📄 ax88796b.c
字号:
}
mdio_write (dev, 0x10, MII_ADVERTISE, advertise);
mdio_write (dev, 0x10, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART));
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_init
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_init (struct net_device *dev, int startp)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
int i;
/* Follow National Semi's recommendations for initing the DP83902. */
writeb (E8390_NODMA+E8390_PAGE0+E8390_STOP, ax_base+E8390_CMD); /* 0x21 */
writeb (ax_local->bus_width, ax_base + EN0_DCFG);/* 8-bit or 16-bit */
/* Set AX88796B interrupt active high */
writeb (E8390_NODMA+E8390_PAGE1+E8390_STOP, ax_base + E8390_CMD);
writeb (ENBTCR_INT_ACT_HIGH, ax_base + EN0_BTCR);
writeb (E8390_NODMA+E8390_PAGE0+E8390_STOP, ax_base + E8390_CMD);
/* Clear the remote byte count registers. */
writeb (0x00, ax_base + EN0_RCNTLO);
writeb (0x00, ax_base + EN0_RCNTHI);
/* Set to monitor and loopback mode -- this is vital!. */
writeb (E8390_RXOFF, ax_base + EN0_RXCR); /* 0x20 */
writeb (E8390_TXOFF, ax_base + EN0_TXCR); /* 0x02 */
/* Set the transmit page and receive ring. */
writeb (NESM_START_PG, ax_base + EN0_TPSR);
writeb (NESM_RX_START_PG, ax_base + EN0_STARTPG);
writeb (NESM_RX_START_PG, ax_base + EN0_BOUNDARY);
ax_local->current_page = NESM_RX_START_PG + 1; /* assert boundary+1 */
writeb (NESM_STOP_PG, ax_base + EN0_STOPPG);
ax_local->tx_prev_ctepr = 0;
ax_local->tx_start_page = NESM_START_PG;
ax_local->tx_curr_page = NESM_START_PG;
ax_local->tx_stop_page = NESM_START_PG + TX_PAGES;
/* Clear the pending interrupts and mask. */
writeb (0xFF, ax_base + EN0_ISR);
writeb (0x00, ax_base + EN0_IMR);
/* Copy the station address into the DS8390 registers. */
writeb (E8390_NODMA + E8390_PAGE1 + E8390_STOP, ax_base+E8390_CMD); /* 0x61 */
writeb (NESM_START_PG + TX_PAGES + 1, ax_base + EN1_CURPAG);
for (i = 0; i < 6; i++)
{
writeb (dev->dev_addr[i], ax_base + EN1_PHYS_SHIFT (i));
if (readb (ax_base + EN1_PHYS_SHIFT (i))!=dev->dev_addr[i])
PRINTK (ERROR_MSG, "Hw. address read/write mismap %d\n",i);
}
writeb (E8390_NODMA+E8390_PAGE0+E8390_STOP, ax_base+E8390_CMD);
if (startp)
{
/* Enable AX88796B TQC */
writeb ((readb (ax_base+EN0_MCR) | ENTQC_ENABLE), ax_base+EN0_MCR);
/* Enable AX88796B Transmit Buffer Ring */
writeb (E8390_NODMA+E8390_PAGE3+E8390_STOP, ax_base+E8390_CMD);
writeb (ENTBR_ENABLE, ax_base+EN3_TBR);
writeb (E8390_NODMA+E8390_PAGE0+E8390_STOP, ax_base+E8390_CMD);
ax_local->media_curr = 0xFF;
ax88796_PHY_init (dev);
writeb (0xff, ax_base + EN0_ISR);
writeb (ENISR_ALL, ax_base + EN0_IMR);
writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base+E8390_CMD);
writeb (E8390_TXCONFIG, ax_base + EN0_TXCR); /* xmit on. */
writeb (E8390_RXCONFIG, ax_base + EN0_RXCR); /* rx on, */
do_set_multicast_list (dev); /* (re)load the mcast table */
}
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_trigger_send
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_trigger_send (struct net_device *dev, unsigned int length, int start_page)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
writeb (E8390_NODMA+E8390_PAGE0, ax_base+E8390_CMD);
writeb (length & 0xff, ax_base + EN0_TCNTLO);
writeb (length >> 8, ax_base + EN0_TCNTHI);
writeb (start_page, ax_base + EN0_TPSR);
writeb ((E8390_NODMA|E8390_TRANS|E8390_START), ax_base+E8390_CMD);
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_vlan_rx_add_vid
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void
ax_vlan_rx_add_vid (struct net_device *dev, u16 vid)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
writeb ((u8)vid, ax_base+EN0_VID0);
writeb ((vid >> 9) & 0xF, ax_base+EN0_VID1);
/* Enable AX88796B Vlan filtering */
writeb (readb(ax_base+EN0_MCR) | ENVLAN_ENABLE, ax_base+EN0_MCR);
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_vlan_rx_kill_vid
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void
ax_vlan_rx_kill_vid (struct net_device *dev, u16 vid)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
/* Disable AX88796B Vlan filtering */
writeb (readb (ax_base+EN0_MCR) & ~ENVLAN_ENABLE, ax_base+EN0_MCR);
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_watchdog
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_watchdog (unsigned long arg)
{
struct net_device *dev = (struct net_device *)(arg);
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
u8 status;
u16 bmcr, advertise;
status = readb (ax_base + EN0_SR);
if (ax_local->media_curr != status) {
ax_local->media_curr = status;
if ((status & ENSR_LINK))
{
if (status & ENSR_SPEED_100) {
PRINTK (DRIVER_MSG, "%s Link mode : 100 Mb/s ", dev->name);
} else {
PRINTK (DRIVER_MSG, "%s Link mode : 10 Mb/s ", dev->name);
}
if (status & ENSR_DUPLEX_DULL) {
PRINTK (DRIVER_MSG, "Full Duplex.\n");
} else {
PRINTK (DRIVER_MSG, "Half Duplex.\n");
}
mdelay (200);
netif_carrier_on (dev);
netif_wake_queue (dev);
} else {
netif_stop_queue (dev);
netif_carrier_off (dev);
PRINTK (DRIVER_MSG, "%s Link down.\n", dev->name);
}
}
if (!(status & ENSR_LINK)) {
bmcr = mdio_read (dev, 0x10, MII_BMCR);
advertise = mdio_read (dev, 0x10, MII_ADVERTISE);
/* Power down PHY */
mdio_write (dev, 0x10, MII_BMCR, BMCR_PDOWN);
mdelay (1);
/* Power up PHY */
mdio_write (dev, 0x10, MII_BMCR, bmcr);
mdelay (60);
mdio_write (dev, 0x10, MII_ADVERTISE, advertise);
mdio_write (dev, 0x10, MII_BMCR, bmcr);
}
mod_timer (&ax_local->watchdog, jiffies + AX88796_WATCHDOG_PERIOD);
return ;
}
/*
* ======================================================================
* MII interface support
* ======================================================================
*/
#define MDIO_SHIFT_CLK 0x01
#define MDIO_DATA_WRITE0 0x00
#define MDIO_DATA_WRITE1 0x08
#define MDIO_DATA_READ 0x04
#define MDIO_MASK 0x0f
#define MDIO_ENB_IN 0x02
static void mdio_sync (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
int bits;
for (bits = 0; bits < 32; bits++) {
writeb (MDIO_DATA_WRITE1, ax_base + AX88796_MII_EEPROM);
writeb (MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
}
static void mdio_clear (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
int bits;
for (bits = 0; bits < 16; bits++) {
writeb (MDIO_DATA_WRITE0, ax_base + AX88796_MII_EEPROM);
writeb (MDIO_DATA_WRITE0 | MDIO_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
}
static int mdio_read (struct net_device *dev, int phy_id, int loc)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
int i, retval = 0;
mdio_clear (dev);
mdio_sync (dev);
for (i = 14; i >= 0; i--) {
int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
writeb (dat, ax_base + AX88796_MII_EEPROM);
writeb (dat | MDIO_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
for (i = 19; i > 0; i--) {
writeb (MDIO_ENB_IN, ax_base + AX88796_MII_EEPROM);
retval = (retval << 1) | ((readb (ax_base + AX88796_MII_EEPROM) & MDIO_DATA_READ) != 0);
writeb (MDIO_ENB_IN | MDIO_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
return (retval>>1) & 0xffff;
}
static void mdio_write (struct net_device *dev, int phy_id, int loc, int value)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i;
mdio_clear (dev);
mdio_sync (dev);
for (i = 31; i >= 0; i--) {
int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
writeb (dat, ax_base + AX88796_MII_EEPROM);
writeb (dat | MDIO_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
for (i = 1; i >= 0; i--) {
writeb (MDIO_ENB_IN, ax_base + AX88796_MII_EEPROM);
writeb (MDIO_ENB_IN | MDIO_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
}
#if (CONFIG_AX88796B_EEPROM_READ_WRITE == 1)
/*
* ======================================================================
* EEPROM interface support
* ======================================================================
*/
#define EEPROM_SHIFT_CLK (0x80)
#define EEPROM_DATA_READ1 (0x40)
#define EEPROM_DATA_WRITE0 (0x00)
#define EEPROM_DATA_WRITE1 (0x20)
#define EEPROM_SELECT (0x10)
#define EEPROM_DIR_IN (0x02)
#define EEPROM_READ (0x02)
#define EEPROM_EWEN (0x00)
#define EEPROM_ERASE (0x03)
#define EEPROM_WRITE (0x01)
#define EEPROM_ERALL (0x00)
#define EEPROM_WRAL (0x00)
#define EEPROM_EWDS (0x00)
#define EEPROM_93C46_OPCODE(x) ((x) << 6)
#define EEPROM_93C46_STARTBIT (1 << 8)
static void
eeprom_write_en (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned short cmd = EEPROM_93C46_STARTBIT | EEPROM_93C46_OPCODE(EEPROM_EWEN) | 0x30;
unsigned char tmp;
int i;
// issue a "SB OP Addr" command
for (i = 8; i >= 0 ; i--) {
tmp = (cmd & (1 << i)) == 0 ? EEPROM_DATA_WRITE0 : EEPROM_DATA_WRITE1;
writeb (tmp | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (tmp | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
for (i = 15; i >= 0; i--) {
writeb (EEPROM_DATA_WRITE0 | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_DATA_WRITE0 | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
writeb (0, ax_base + AX88796_MII_EEPROM);
}
static void
eeprom_write_dis (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned short cmd = EEPROM_93C46_STARTBIT | EEPROM_93C46_OPCODE (EEPROM_EWDS);
unsigned char tmp;
int i;
// issue a "SB OP Addr" command
for (i = 8; i >= 0 ; i--) {
tmp = (cmd & (1 << i)) == 0 ? EEPROM_DATA_WRITE0 : EEPROM_DATA_WRITE1;
writeb (tmp | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (tmp | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
for (i = 15; i >= 0; i--) {
writeb (EEPROM_DATA_WRITE0 | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_DATA_WRITE0 | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
writeb (0, ax_base + AX88796_MII_EEPROM);
}
static int
eeprom_write (struct net_device *dev, unsigned char loc, unsigned short nValue)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned short cmd = EEPROM_93C46_STARTBIT | EEPROM_93C46_OPCODE (EEPROM_WRITE) | loc;
unsigned char tmp;
int i;
int ret = 0;
// issue a "SB OP Addr" command
for(i = 8; i >= 0 ; i--) {
tmp = (cmd & (1 << i)) == 0 ? EEPROM_DATA_WRITE0 : EEPROM_DATA_WRITE1;
writeb (tmp | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (tmp | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
// writing the data
for (i = 15; i >= 0; i--) {
tmp = (nValue & (1 << i)) == 0 ? EEPROM_DATA_WRITE0 : EEPROM_DATA_WRITE1;
writeb (tmp | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (tmp | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
//
// check busy
//
// Turn, wait two clocks
writeb (EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_SHIFT_CLK | EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_SHIFT_CLK | EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
// waiting for busy signal
i = 0xFFFF;
while (--i) {
writeb (EEPROM_SELECT | EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_SELECT | EEPROM_DIR_IN | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
tmp = readb (ax_base + AX88796_MII_EEPROM);
if ((tmp & EEPROM_DATA_READ1) == 0)
break;
}
if (i <= 0) {
printk ("Failed on waiting for bus busy\n\r");
ret = -1;
} else {
i = 0xFFFF;
while (--i) {
writeb (EEPROM_SELECT | EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_SELECT | EEPROM_DIR_IN | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
tmp = readb (ax_base + AX88796_MII_EEPROM);
if (tmp & EEPROM_DATA_READ1)
break;
}
if (i <= 0) {
printk ("Failed on waiting for write completion\n\r");
ret = -1;
}
}
writeb (0, ax_base + AX88796_MII_EEPROM);
return ret;
}
static unsigned short
eeprom_read (struct net_device *dev, unsigned char loc)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned short cmd = EEPROM_93C46_STARTBIT | EEPROM_93C46_OPCODE (EEPROM_READ) | loc;
unsigned char tmp;
unsigned short retValue = 0;
int i;
// issue a "SB OP Addr" command
for (i = 8; i >= 0 ; i--) {
tmp = (cmd & (1 << i)) == 0 ? EEPROM_DATA_WRITE0 : EEPROM_DATA_WRITE1;
writeb (tmp | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (tmp | EEPROM_SELECT | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
// Turn
writeb (EEPROM_DIR_IN | EEPROM_SELECT, ax_base + AX88796_MII_EEPROM);
writeb (EEPROM_DIR_IN | EEPROM_SELECT | EEPROM_SHIFT_CLK | EEPROM_DATA_WRITE1, ax_base + AX88796_MII_EEPROM);
// retriving the data
for (i = 15; i >= 0; i--) {
writeb (EEPROM_SELECT | EEPROM_DIR_IN, ax_base + AX88796_MII_EEPROM);
tmp = readb (ax_base + AX88796_MII_EEPROM);
if (tmp & EEPROM_DATA_READ1)
retValue |= (1 << i);
writeb (EEPROM_SELECT | EEPROM_DIR_IN | EEPROM_SHIFT_CLK, ax_base + AX88796_MII_EEPROM);
}
writeb (0, ax_base + AX88796_MII_EEPROM);
return retValue;
}
#endif /* #if (CONFIG_AX88796B_EEPROM_READ_WRITE == 1) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -