⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ax88796b.c

📁 AX88796B的linux 2.4驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	}
	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 + -