📄 phy.c
字号:
/** * Airgo MIMO wireless driver * * Copyright (c) 2007-2008 Li YanBo <dreamfly281@gmail.com> * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/init.h>#include <linux/etherdevice.h>#include <linux/pci.h>#include <linux/delay.h>#include "agnx.h"#include "debug.h"#include "phy.h"#include "table.h"#include "sta.h"#include "xmit.h"u8 read_from_eeprom(struct agnx_priv *priv, u16 address){ void __iomem *ctl = priv->ctl; struct agnx_eeprom cmd; u32 reg; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = EEPROM_CMD_READ << AGNX_EEPROM_COMMAND_SHIFT; cmd.address = address; /* Verify that the Status bit is clear */ /* Read Command and Address are written to the Serial Interface */ iowrite32(*(__le32 *)&cmd, ctl + AGNX_CIR_SERIALITF); /* Wait for the Status bit to clear again */ eeprom_delay(); /* Read from Data */ reg = ioread32(ctl + AGNX_CIR_SERIALITF); cmd = *(struct agnx_eeprom *)® return cmd.data;}static int card_full_reset(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u32 reg; AGNX_TRACE; reg = agnx_read32(ctl, AGNX_CIR_BLKCTL); agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x80); reg = agnx_read32(ctl, AGNX_CIR_BLKCTL); return 0;}inline void enable_power_saving(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u32 reg; reg = agnx_read32(ctl, AGNX_PM_PMCTL); reg &= ~0x8; agnx_write32(ctl, AGNX_PM_PMCTL, reg);}inline void disable_power_saving(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u32 reg; reg = agnx_read32(ctl, AGNX_PM_PMCTL); reg |= 0x8; agnx_write32(ctl, AGNX_PM_PMCTL, reg);}void disable_receiver(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; AGNX_TRACE; /* FIXME Disable the receiver */ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0); /* Set gain control reset */ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); /* Reset gain control reset */ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);}/* Fixme this shoule be disable RX, above is enable RX */void enable_receiver(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; AGNX_TRACE; /* Set adaptive gain control discovery mode */ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); /* Set gain control reset */ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); /* Clear gain control reset */ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);}static void mac_address_set(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u8 *mac_addr = priv->mac_addr; u32 reg; /* FIXME */ reg = (mac_addr[0] << 24) | (mac_addr[1] << 16) | mac_addr[2] << 8 | mac_addr[3]; iowrite32(reg, ctl + AGNX_RXM_MACHI); reg = (mac_addr[4] << 8) | mac_addr[5]; iowrite32(reg, ctl + AGNX_RXM_MACLO);}static void receiver_bssid_set(struct agnx_priv *priv, u8 *bssid){ void __iomem *ctl = priv->ctl; u32 reg; disable_receiver(priv); /* FIXME */ reg = bssid[0] << 24 | (bssid[1] << 16) | (bssid[2] << 8) | bssid[3]; iowrite32(reg, ctl + AGNX_RXM_BSSIDHI); reg = (bssid[4] << 8) | bssid[5]; iowrite32(reg, ctl + AGNX_RXM_BSSIDLO); /* Enable the receiver */ enable_receiver(priv); /* Clear the TSF *//* agnx_write32(ctl, AGNX_TXM_TSFLO, 0x0); *//* agnx_write32(ctl, AGNX_TXM_TSFHI, 0x0); */ /* Clear the TBTT */ agnx_write32(ctl, AGNX_TXM_TBTTLO, 0x0); agnx_write32(ctl, AGNX_TXM_TBTTHI, 0x0); disable_receiver(priv);} /* receiver_bssid_set */static void band_management_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; void __iomem *data = priv->data; u32 reg; int i; AGNX_TRACE; agnx_write32(ctl, AGNX_BM_TXWADDR, AGNX_PDU_TX_WQ); agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0); memset_io(data + AGNX_PDUPOOL, 0x0, AGNX_PDUPOOL_SIZE); agnx_write32(ctl, AGNX_BM_BMCTL, 0x200); agnx_write32(ctl, AGNX_BM_CIPDUWCNT, 0x40); agnx_write32(ctl, AGNX_BM_SPPDUWCNT, 0x2); agnx_write32(ctl, AGNX_BM_RFPPDUWCNT, 0x0); agnx_write32(ctl, AGNX_BM_RHPPDUWCNT, 0x22); /* FIXME Initialize the Free Pool Linked List */ /* 1. Write the Address of the Next Node ((0x41800 + node*size)/size) to the first word of each node. */ for (i = 0; i < PDU_FREE_CNT; i++) { iowrite32((AGNX_PDU_FREE + (i+1)*PDU_SIZE)/PDU_SIZE, data + AGNX_PDU_FREE + (PDU_SIZE * i)); /* The last node should be set to 0x0 */ if ((i + 1) == PDU_FREE_CNT) memset_io(data + AGNX_PDU_FREE + (PDU_SIZE * i), 0x0, PDU_SIZE); } /* Head is First Pool address (0x41800) / size (0x80) */ agnx_write32(ctl, AGNX_BM_FPLHP, AGNX_PDU_FREE/PDU_SIZE); /* Tail is Last Pool Address (0x47f80) / size (0x80) */ agnx_write32(ctl, AGNX_BM_FPLTP, 0x47f80/PDU_SIZE); /* Count is Number of Nodes in the Pool (0xd0) */ agnx_write32(ctl, AGNX_BM_FPCNT, PDU_FREE_CNT); /* Start all workqueue */ agnx_write32(ctl, AGNX_BM_CIWQCTL, 0x80000); agnx_write32(ctl, AGNX_BM_CPULWCTL, 0x80000); agnx_write32(ctl, AGNX_BM_CPUHWCTL, 0x80000); agnx_write32(ctl, AGNX_BM_CPUTXWCTL, 0x80000); agnx_write32(ctl, AGNX_BM_CPURXWCTL, 0x80000); agnx_write32(ctl, AGNX_BM_SPRXWCTL, 0x80000); agnx_write32(ctl, AGNX_BM_SPTXWCTL, 0x80000); agnx_write32(ctl, AGNX_BM_RFPWCTL, 0x80000); /* Enable the Band Management */ reg = agnx_read32(ctl, AGNX_BM_BMCTL); reg |= 0x1; agnx_write32(ctl, AGNX_BM_BMCTL, reg);} /* band_managment_init */static void system_itf_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u32 reg; AGNX_TRACE; agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x0); agnx_write32(ctl, AGNX_PM_TESTPHY, 0x11e143a); if (priv->revid == 0) { reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE); reg |= 0x11; agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg); } /* ??? What is that means? it should difference for differice type of cards */ agnx_write32(ctl, AGNX_CIR_SERIALITF, 0xfff81006); agnx_write32(ctl, AGNX_SYSITF_GPIOIN, 0x1f0000); agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5); reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN);}static void encryption_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; AGNX_TRACE; agnx_write32(ctl, AGNX_ENCRY_WEPKEY0, 0x0); agnx_write32(ctl, AGNX_ENCRY_WEPKEY1, 0x0); agnx_write32(ctl, AGNX_ENCRY_WEPKEY2, 0x0); agnx_write32(ctl, AGNX_ENCRY_WEPKEY3, 0x0); agnx_write32(ctl, AGNX_ENCRY_CCMRECTL, 0x8);}static void tx_management_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; void __iomem *data = priv->data; u32 reg; AGNX_TRACE; /* Fill out the ComputationalEngineLookupTable * starting at memory #2 offset 0x800 */ tx_engine_lookup_tbl_init(priv); memset_io(data + 0x1000, 0, 0xfe0); /* Enable Transmission Management Functions */ agnx_write32(ctl, AGNX_TXM_ETMF, 0x3ff); /* Write 0x3f to Transmission Template */ agnx_write32(ctl, AGNX_TXM_TXTEMP, 0x3f); if (priv->revid >= 2) agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e140a0b); else agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e190a0b); reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); reg &= 0xff00; reg |= 0xb; agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); reg &= 0xffff00ff; reg |= 0xa00; agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); /* Enable TIFS */ agnx_write32(ctl, AGNX_TXM_CTL, 0x40000); reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); reg &= 0xff00ffff; reg |= 0x510000; agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY); reg &= 0xff00ffff; agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg); reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); reg &= 0x00ffffff; reg |= 0x1c000000; agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY); reg &= 0x00ffffff; reg |= 0x01000000; agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg); /* # Set DIF 0-1,2-3,4-5,6-7 to defaults */ agnx_write32(ctl, AGNX_TXM_DIF01, 0x321d321d); agnx_write32(ctl, AGNX_TXM_DIF23, 0x321d321d); agnx_write32(ctl, AGNX_TXM_DIF45, 0x321d321d); agnx_write32(ctl, AGNX_TXM_DIF67, 0x321d321d); /* Max Ack timeout limit */ agnx_write32(ctl, AGNX_TXM_MAXACKTIM, 0x1e19); /* Max RX Data Timeout count, */ reg = agnx_read32(ctl, AGNX_TXM_MAXRXTIME); reg &= 0xffff0000; reg |= 0xff; agnx_write32(ctl, AGNX_TXM_MAXRXTIME, reg); /* CF poll RX Timeout count */ reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM); reg &= 0xffff; reg |= 0xff0000; agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg); /* Max Timeout Exceeded count, */ reg = agnx_read32(ctl, AGNX_TXM_MAXTIMOUT); reg &= 0xff00ffff; reg |= 0x190000; agnx_write32(ctl, AGNX_TXM_MAXTIMOUT, reg); /* CF ack timeout limit for 11b */ reg = agnx_read32(ctl, AGNX_TXM_CFACKT11B); reg &= 0xff00; reg |= 0x1e; agnx_write32(ctl, AGNX_TXM_CFACKT11B, reg); /* Max CF Poll Timeout Count */ reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM); reg &= 0xffff0000; reg |= 0x19; agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg); /* CF Poll RX Timeout Count */ reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM); reg &= 0xffff0000; reg |= 0x1e; agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg); /* # write default to */ /* 1. Schedule Empty Count */ agnx_write32(ctl, AGNX_TXM_SCHEMPCNT, 0x5); /* 2. CFP Period Count */ agnx_write32(ctl, AGNX_TXM_CFPERCNT, 0x1); /* 3. CFP MDV */ agnx_write32(ctl, AGNX_TXM_CFPMDV, 0x10000); /* Probe Delay */ reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY); reg &= 0xffff0000; reg |= 0x400; agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg); /* Max CCA count Slot */ reg = agnx_read32(ctl, AGNX_TXM_MAXCCACNTSLOT); reg &= 0xffff00ff; reg |= 0x900; agnx_write32(ctl, AGNX_TXM_MAXCCACNTSLOT, reg); /* Slot limit/1 msec Limit */ reg = agnx_read32(ctl, AGNX_TXM_SLOTLIMIT); reg &= 0xff00ffff; reg |= 0x140077; agnx_write32(ctl, AGNX_TXM_SLOTLIMIT, reg); /* # Set CW #(0-7) to default */ agnx_write32(ctl, AGNX_TXM_CW0, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW1, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW2, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW3, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW4, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW5, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW6, 0xff0007); agnx_write32(ctl, AGNX_TXM_CW7, 0xff0007); /* # Set Short/Long limit #(0-7) to default */ agnx_write32(ctl, AGNX_TXM_SLBEALIM0, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM1, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM2, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM3, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM4, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM5, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM6, 0xa000a); agnx_write32(ctl, AGNX_TXM_SLBEALIM7, 0xa000a); reg = agnx_read32(ctl, AGNX_TXM_CTL); reg |= 0x1400; agnx_write32(ctl, AGNX_TXM_CTL, reg); /* Wait for bit 0 in Control Reg to clear */ udelay(80); reg = agnx_read32(ctl, AGNX_TXM_CTL); /* Or 0x18000 to Control reg */ reg = agnx_read32(ctl, AGNX_TXM_CTL); reg |= 0x18000; agnx_write32(ctl, AGNX_TXM_CTL, reg); /* Wait for bit 0 in Control Reg to clear */ udelay(80); reg = agnx_read32(ctl, AGNX_TXM_CTL); /* Set Listen Interval Count to default */ agnx_write32(ctl, AGNX_TXM_LISINTERCNT, 0x1); /* Set DTIM period count to default */ agnx_write32(ctl, AGNX_TXM_DTIMPERICNT, 0x2000);} /* tx_management_init */static void rx_management_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; AGNX_TRACE; /* Initialize the Routing Table */ routing_table_init(priv); if (priv->revid >= 3) { agnx_write32(ctl, 0x2074, 0x1f171710); agnx_write32(ctl, 0x2078, 0x10100d0d); agnx_write32(ctl, 0x207c, 0x11111010); } else agnx_write32(ctl, AGNX_RXM_DELAY11, 0x0); agnx_write32(ctl, AGNX_RXM_REQRATE, 0x8195e00);}static void agnx_timer_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; AGNX_TRACE;/* /\* Write 0x249f00 (tick duration?) to Timer 1 *\/ *//* agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x249f00); *//* /\* Write 0xe2 to Timer 1 Control *\/ *//* agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0xe2); */ /* Write 0x249f00 (tick duration?) to Timer 1 */ agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x0); /* Write 0xe2 to Timer 1 Control */ agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0x0); iowrite32(0xFFFFFFFF, priv->ctl + AGNX_TXM_BEACON_CTL);}static void power_manage_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u32 reg; AGNX_TRACE; agnx_write32(ctl, AGNX_PM_MACMSW, 0x1f); agnx_write32(ctl, AGNX_PM_RFCTL, 0x1f); reg = agnx_read32(ctl, AGNX_PM_PMCTL); reg &= 0xf00f; reg |= 0xa0; agnx_write32(ctl, AGNX_PM_PMCTL, reg); if (priv->revid >= 3) { reg = agnx_read32(ctl, AGNX_PM_SOFTRST); reg |= 0x18; agnx_write32(ctl, AGNX_PM_SOFTRST, reg); }} /* power_manage_init */static void gain_ctlcnt_init(struct agnx_priv *priv){ void __iomem *ctl = priv->ctl; u32 reg; AGNX_TRACE; agnx_write32(ctl, AGNX_GCR_TRACNT5, 0x119); agnx_write32(ctl, AGNX_GCR_TRACNT6, 0x118); agnx_write32(ctl, AGNX_GCR_TRACNT7, 0x117); reg = agnx_read32(ctl, AGNX_PM_PMCTL); reg |= 0x8; agnx_write32(ctl, AGNX_PM_PMCTL, reg); reg = agnx_read32(ctl, AGNX_PM_PMCTL); reg &= ~0x8; agnx_write32(ctl, AGNX_PM_PMCTL, reg); agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0); /* FIXME Write the initial Station Descriptor for the card */ sta_init(priv, LOCAL_STAID); sta_init(priv, BSSID_STAID); /* Enable staion 0 and 1 can do TX */ /* It seemed if we set other bit to 1 the bit 0 will be auto change to 0 */ agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x2 | 0x1);// agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x1);} /* gain_ctlcnt_init */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -