[U-Boot-Users] [PATCH][resubmit] AX88180: new gigabit network driver

Resubmit the driver for the ASIX AX88180 gigabit ethernet chip.
Signed-off-by: Louis Su louis@asix.com.tw --- drivers/net/Makefile | 1 + drivers/net/ax88180.c | 842 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ax88180.h | 415 ++++++++++++++++++++++++ 3 files changed, 1258 insertions(+), 0 deletions(-) create mode 100644 drivers/net/ax88180.c create mode 100644 drivers/net/ax88180.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 84be288..3a574e0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnet.a
COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o +COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c new file mode 100644 index 0000000..5579ef0 --- /dev/null +++ b/drivers/net/ax88180.c @@ -0,0 +1,842 @@ +/* ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */ +/* + This program is free software; you can distribute it and/or modify + it under the terms of the GNU General Public License (Version 2) as + published by the Free Software Foundation. + This program is distributed in the hope it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + USA. +*/ + +/* + ======================================================================== + ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver + + The AX88180 Ethernet controller is a high performance and highly + integrated local CPU bus Ethernet controller with embedded 40K bytes + SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any + embedded systems. + The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet + controller that supports both MII and RGMII interfaces and is + compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards. + + Please visit ASIX's web site (http://www.asix.com.tw) for more + details. + + Module Name : ax88180.c + Date : 2008-07-01 + History + 09/06/2006 : New release for AX88180 US2 chip. + 07/01/2008 : Fix up the coding style and using functions + instead of most macros + ======================================================================== +*/ +#include <common.h> +#include <command.h> +#include <net.h> + +#include "ax88180.h" + +#ifdef CONFIG_DRIVER_AX88180 + +/* +=========================================================================== +<<<<<< Local SubProgram Declaration >>>>>> +=========================================================================== +*/ +static void ax88180_rx_handler (void); +static int ax88180_PHY_initial (void); +static void ax88180_meida_config (void); +static unsigned long get_CicadaPHY_meida_mode (void); +static unsigned long get_MarvellPHY_meida_mode (void); +static unsigned short ax88180_mdio_read (unsigned long phyaddr, + unsigned long regaddr); +static void ax88180_mdio_write (unsigned long phyaddr, + unsigned long regaddr, + unsigned short regdata); + +/* +=========================================================================== +<<<<<< Declare Macro/Structure Definition >>>>>> +=========================================================================== +*/ +typedef enum _AX88180_LINK_STATE { + INS_LINK_DOWN, + INS_LINK_UP, + INS_LINK_UNKNOWN +} AX88180_LINK_STATE; + +typedef struct _AX88180_PRIVATE { + unsigned long PhyAddr; + unsigned long PhyID0; + unsigned long FirstTxDesc; + unsigned long NextTxDesc; + unsigned long rxbuf_overflow_count; + AX88180_LINK_STATE LinkState; +} AX88180_PRIVATE; + +AX88180_PRIVATE axlocal; + +#if (DEBUG_FLAGS & DEBUG_MSG) +static inline void ax88180_disp_all_reg (void) +{ + unsigned long tmpval; + int i; + PRINTK (DEBUG_MSG, "ax88180: AX88180 MAC Registers:\n"); + for (i = 0xFC00; i <= 0xFCFF; i += 4) { + READ_MACREG (i, tmpval); + PRINTK (DEBUG_MSG, "0x%04x=0x%08lx ", i, tmpval); + if ((i & 0xF) == 0xC) + PRINTK (DEBUG_MSG, "\n"); + } + PRINTK (DEBUG_MSG, "\n"); +} + +static inline void ax88180_disp_phy_reg (void) +{ + unsigned long tmpval; + tmpval = ax88180_mdio_read (axlocal.PhyAddr, BMCR); + PRINTK (DEBUG_MSG, "BMCR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, BMSR); + PRINTK (DEBUG_MSG, "BMSR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR0); + PRINTK (DEBUG_MSG, "PHYIDR0=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR1); + PRINTK (DEBUG_MSG, "PHYIDR1=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, ANAR); + PRINTK (DEBUG_MSG, "ANAR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, ANLPAR); + PRINTK (DEBUG_MSG, "ANLPAR=0x%04x \n", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, ANER); + PRINTK (DEBUG_MSG, "ANER=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, AUX_1000_CTRL); + PRINTK (DEBUG_MSG, "1G_CTRL=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, AUX_1000_STATUS); + PRINTK (DEBUG_MSG, "1G_STATUS=0x%04x \n", (unsigned int)tmpval); + if (axlocal.PhyID0 == MARVELL_88E1111_PHYIDR0) { + tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_SSR); + PRINTK (DEBUG_MSG, "M88_SSR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_IER); + PRINTK (DEBUG_MSG, "M88_IER=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_ISR); + PRINTK (DEBUG_MSG, "M88_ISR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_EXT_SCR); + PRINTK (DEBUG_MSG, "M88_EXT_SCR=0x%04x ", + (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_EXT_SSR); + PRINTK (DEBUG_MSG, "M88_EXT_SSR=0x%04x \n", + (unsigned int)tmpval); + } else if (axlocal.PhyID0 == CICADA_CIS8201_PHYIDR0) { + tmpval = ax88180_mdio_read (axlocal.PhyAddr, CIS_IMR); + PRINTK (DEBUG_MSG, "CIS_IMR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, CIS_ISR); + PRINTK (DEBUG_MSG, "CIS_ISR=0x%04x ", (unsigned int)tmpval); + tmpval = ax88180_mdio_read (axlocal.PhyAddr, + CIS_AUX_CTRL_STATUS); + PRINTK (DEBUG_MSG, "CIS_AUX=0x%04x \n", + (unsigned int)tmpval); + } + READ_MACREG (RXCFG, tmpval); + PRINTK (DEBUG_MSG, "RXCFG=0x%08lx ", tmpval); + READ_MACREG (MACCFG0, tmpval); + PRINTK (DEBUG_MSG, "MACCFG0=0x%08lx ", tmpval); + READ_MACREG (MACCFG1, tmpval); + PRINTK (DEBUG_MSG, "MACCFG1=0x%08lx ", tmpval); + READ_MACREG (MACCFG2, tmpval); + PRINTK (DEBUG_MSG, "MACCFG2=0x%08lx \n\n", tmpval); +} +#else +static inline void ax88180_disp_all_reg (void) {} +static inline void ax88180_disp_phy_reg (void) {} +#endif + +/* +=========================================================================== +<<<<<< Local SubProgram Bodies >>>>>> +=========================================================================== +*/ +static int +ax88180_mdio_check_complete (void) +{ + int us_cnt = 10000; + unsigned long tmpval; + + /* MDIO read/write should not take more than 10 ms */ + while (--us_cnt) { + READ_MACREG (MDIOCTRL, tmpval); + if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0)) + break; + } + + return us_cnt; +} + +static unsigned short +ax88180_mdio_read (unsigned long phyaddr, unsigned long regaddr) +{ + unsigned long tmpval = 0; + + WRITE_MACREG (MDIOCTRL, READ_PHY | (regaddr << 8) | phyaddr); + + if (ax88180_mdio_check_complete ()) + READ_MACREG (MDIODP, tmpval); + else + printf("Failed to read PHY register!\n"); + return (unsigned short)(tmpval & 0xFFFF); +} + +static void +ax88180_mdio_write (unsigned long phyaddr, unsigned long regaddr, + unsigned short regdata) +{ + WRITE_MACREG (MDIODP, regdata); + WRITE_MACREG (MDIOCTRL, WRITE_PHY | (regaddr << 8) | phyaddr); + + if(!ax88180_mdio_check_complete ()) + printf("Failed to write PHY register!\n"); +} + +static int ax88180_phy_reset (void) +{ + unsigned short delay_cnt = 500; + + ax88180_mdio_write (axlocal.PhyAddr, BMCR, PHY_RESET | AUTONEG_EN); + + /* Wait for the reset to complete, or time out (500 ms) */ + while (ax88180_mdio_read (axlocal.PhyAddr, BMCR) & PHY_RESET) { + udelay (1000); + if (--delay_cnt == 0) { + printf("Failed to reset PHY!\n"); + return -1; + } + } + + return 0; +} + +static void ax88180_mac_reset (void) +{ + unsigned long tmpval; + + WRITE_MACREG (MISC, MISC_RESET_MAC); + READ_MACREG (MISC, tmpval); + WRITE_MACREG (MISC, MISC_NORMAL); + WRITE_MACREG (RXINDICATOR, DEFAULT_RXINDICATOR); + WRITE_MACREG (TXCMD, DEFAULT_TXCMD); + WRITE_MACREG (TXBS, DEFAULT_TXBS); + WRITE_MACREG (TXDES0, DEFAULT_TXDES0); + WRITE_MACREG (TXDES1, DEFAULT_TXDES1); + WRITE_MACREG (TXDES2, DEFAULT_TXDES2); + WRITE_MACREG (TXDES3, DEFAULT_TXDES3); + WRITE_MACREG (TXCFG, DEFAULT_TXCFG); + WRITE_MACREG (MACCFG2, DEFAULT_MACCFG2); + WRITE_MACREG (MACCFG3, DEFAULT_MACCFG3); + WRITE_MACREG (TXLEN, DEFAULT_TXLEN); + WRITE_MACREG (RXBTHD0, DEFAULT_RXBTHD0); + WRITE_MACREG (RXBTHD1, DEFAULT_RXBTHD1); + WRITE_MACREG (RXFULTHD, DEFAULT_RXFULTHD); + WRITE_MACREG (DOGTHD0, DEFAULT_DOGTHD0); + WRITE_MACREG (DOGTHD1, DEFAULT_DOGTHD1); +} + +static int ax88180_poll_tx_complete (void) +{ + unsigned long tmp_data, txbs_txdp; + int TimeOutCnt = 10000; + + txbs_txdp = 1 << axlocal.NextTxDesc; + + while (TimeOutCnt--) { + + READ_MACREG (TXBS, tmp_data); + if ((tmp_data & txbs_txdp) == 0) + break; + + udelay (100); + } + + if (TimeOutCnt) + return 0; + else + return -TimeOutCnt; +} + +static void ax88180_rx_handler (void) +{ + unsigned char *rxdata; + unsigned long tmp_data; + unsigned long rx_packet_len; + unsigned int data_size; + unsigned int dword_count, byte_count; + unsigned long rxcurt_ptr, rxbound_ptr, next_ptr; + int i; + int j; + + READ_MACREG (RXCURT, rxcurt_ptr); + READ_MACREG (RXBOUND, rxbound_ptr); + next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK; + + PRINTK (RX_MSG, "ax88180: RX original RXBOUND=0x%08lx," + " RXCURT=0x%08lx\n", rxbound_ptr, rxcurt_ptr); + + while (next_ptr != rxcurt_ptr) { + WRITE_MACREG (RXINDICATOR, RX_START_READ); + READ_RXBUF (rx_packet_len); + if ((rx_packet_len == 0) || (rx_packet_len > MAX_RX_SIZE)) { + WRITE_MACREG (RXINDICATOR, RX_STOP_READ); + ax88180_mac_reset (); + printf ("ax88180: Invalid Rx packet length!" + " (len=0x%08lx)\n", rx_packet_len); + + printf ("ax88180: RX RXBOUND=0x%08lx," + "RXCURT=0x%08lx\n", rxbound_ptr, rxcurt_ptr); + return; + } + data_size = (unsigned int)rx_packet_len; + rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1; + rxbound_ptr &= RX_PAGE_NUM_MASK; + + rxdata = (unsigned char *)NetRxPackets[0]; + +#if defined (CONFIG_DRIVER_AX88180_16BIT) + dword_count = data_size >> 1; + byte_count = data_size & 0x1; +#else + dword_count = data_size >> 2; + byte_count = data_size & 0x3; +#endif + for (i = 0; i < dword_count; i++) { + READ_RXBUF (tmp_data); +#if defined (CONFIG_DRIVER_AX88180_16BIT) + *((unsigned short *)rxdata + i) = tmp_data; +#else + *((unsigned long *)rxdata + i) = tmp_data; +#endif + } + if (byte_count != 0) { + READ_RXBUF (tmp_data); + for (j = 0; j < byte_count; j++) { + *(rxdata + (dword_count * 4) + j) = + (unsigned char)(tmp_data >> (j * 8)); + } + } + + WRITE_MACREG (RXINDICATOR, RX_STOP_READ); + + /* Pass the packet up to the protocol layers. */ + NetReceive (NetRxPackets[0], data_size); + + WRITE_MACREG (RXBOUND, rxbound_ptr); + + READ_MACREG (RXCURT, rxcurt_ptr); + READ_MACREG (RXBOUND, rxbound_ptr); + next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK; + + PRINTK (RX_MSG, "ax88180: RX updated RXBOUND=0x%08lx," + "RXCURT=0x%08lx\n", rxbound_ptr, rxcurt_ptr); + } + + if (axlocal.rxbuf_overflow_count > 0) + axlocal.rxbuf_overflow_count--; + + return; +} + +static int ax88180_PHY_initial (void) +{ + unsigned long tmp_regval; + int i; + int ret; + + /* Check avaliable PHY chipset */ + axlocal.PhyAddr = MARVELL_88E1111_PHYADDR; + axlocal.PhyID0 = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR0); + + if (axlocal.PhyID0 == MARVELL_88E1111_PHYIDR0) { + PRINTK (DEBUG_MSG, "ax88180: Found Marvell 88E1111 PHY." + " (PHY Addr=0x%lx)\n", axlocal.PhyAddr); + tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, M88_EXT_SSR); + if ((tmp_regval & HWCFG_MODE_MASK) == RGMII_COPPER_MODE) { + ax88180_mdio_write (axlocal.PhyAddr, M88_EXT_SCR, + DEFAULT_EXT_SCR); + if ((ret = ax88180_phy_reset ()) < 0) + return ret; + ax88180_mdio_write (axlocal.PhyAddr, M88_IER, + LINK_CHANGE_INT); + } + } else { + axlocal.PhyAddr = CICADA_CIS8201_PHYADDR; + axlocal.PhyID0 = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR0); + if (axlocal.PhyID0 == CICADA_CIS8201_PHYIDR0) { + PRINTK (DEBUG_MSG, "ax88180: Found CICADA CIS8201 PHY" + " chipset. (PHY Addr=0x%lx)\n", + axlocal.PhyAddr); + ax88180_mdio_write (axlocal.PhyAddr, CIS_IMR, + (CIS_INT_ENABLE | LINK_CHANGE_INT)); + + /* + Set CIS_SMI_PRIORITY bit before force the media mode + */ + tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, + CIS_AUX_CTRL_STATUS); + tmp_regval &= ~CIS_SMI_PRIORITY; + ax88180_mdio_write (axlocal.PhyAddr, + CIS_AUX_CTRL_STATUS, tmp_regval); + } else { + printf ("ax88180: Unknown PHY chipset!!\n"); + return -1; + } + } + + /* Waiting for auto-negotiation complete. */ + /* This may take up to 5 seconds */ + PRINTK (DEBUG_MSG, + "ax88180: Waiting for auto-negotiation completion......\n"); + for (i = 0; i < 5000; i++) { + tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, BMSR); + if (tmp_regval & AUTONEG_COMPLETE) { + break; + } + udelay (1000); + } + + return 0; +} + +static void ax88180_meida_config (void) +{ + unsigned long bmcr_val, bmsr_val; + unsigned long rxcfg_val, maccfg0_val, maccfg1_val; + unsigned long RealMediaMode; + int i; + + /* Waiting 200 msecs for PHY link stable */ + for (i = 0; i < 200; i++) { + bmsr_val = ax88180_mdio_read (axlocal.PhyAddr, BMSR); + if (bmsr_val & LINKOK) { + break; + } + udelay (1000); + } + + bmsr_val = ax88180_mdio_read (axlocal.PhyAddr, BMSR); + PRINTK (DEBUG_MSG, "ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val); + + if (bmsr_val & LINKOK) { + bmcr_val = ax88180_mdio_read (axlocal.PhyAddr, BMCR); + if (bmcr_val & AUTONEG_EN) { + /* Waiting for Auto-negotiation completion */ + /* This may take up to 5 seconds */ + PRINTK (DEBUG_MSG, "ax88180: Auto-negotiation is " + "enabled. Waiting for NWay completion..\n"); + for (i = 0; i < 5000; i++) { + bmsr_val = ax88180_mdio_read (axlocal.PhyAddr, + BMSR); + if (bmsr_val & AUTONEG_COMPLETE) { + break; + } + udelay (1000); + } + } else + PRINTK (DEBUG_MSG, + "ax88180: Auto-negotiation is disabled.\n"); + + PRINTK (DEBUG_MSG, "ax88180: BMCR=0x%04x, BMSR=0x%04x\n", + (unsigned int)bmcr_val, (unsigned int)bmsr_val); + + /* Get real media mode here */ + if (axlocal.PhyID0 == MARVELL_88E1111_PHYIDR0) { + RealMediaMode = get_MarvellPHY_meida_mode (); + } else if (axlocal.PhyID0 == CICADA_CIS8201_PHYIDR0) { + RealMediaMode = get_CicadaPHY_meida_mode (); + } else { + RealMediaMode = MEDIA_1000FULL; + } + + switch (RealMediaMode) { + default: + case MEDIA_1000FULL: + PRINTK (DEBUG_MSG, + "ax88180: 1000Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; + maccfg1_val = GIGA_MODE_EN | RXFLOW_EN | + FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_1000HALF: + PRINTK (DEBUG_MSG, + "ax88180: 1000Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1; + break; + + case MEDIA_100FULL: + PRINTK (DEBUG_MSG, + "ax88180: 100Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = SPEED100 | TXFLOW_ENABLE + | DEFAULT_MACCFG0; + maccfg1_val = RXFLOW_EN | FULLDUPLEX + | DEFAULT_MACCFG1; + break; + + case MEDIA_100HALF: + PRINTK (DEBUG_MSG, + "ax88180: 100Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = SPEED100 | DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + break; + + case MEDIA_10FULL: + PRINTK (DEBUG_MSG, + "ax88180: 10Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; + maccfg1_val = RXFLOW_EN | FULLDUPLEX + | DEFAULT_MACCFG1; + break; + + case MEDIA_10HALF: + PRINTK (DEBUG_MSG, + "ax88180: 10Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + break; + } + + axlocal.LinkState = INS_LINK_UP; + } else { + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + + axlocal.LinkState = INS_LINK_DOWN; + } + + WRITE_MACREG (RXCFG, rxcfg_val); + WRITE_MACREG (MACCFG0, maccfg0_val); + WRITE_MACREG (MACCFG1, maccfg1_val); + + return; +} + +static unsigned long +get_MarvellPHY_meida_mode (void) +{ + unsigned long m88_ssr; + unsigned long MediaMode; + + m88_ssr = ax88180_mdio_read (axlocal.PhyAddr, M88_SSR); + switch (m88_ssr & SSR_MEDIA_MASK) { + default: + case SSR_1000FULL: + MediaMode = MEDIA_1000FULL; + break; + case SSR_1000HALF: + MediaMode = MEDIA_1000HALF; + break; + case SSR_100FULL: + MediaMode = MEDIA_100FULL; + break; + case SSR_100HALF: + MediaMode = MEDIA_100HALF; + break; + case SSR_10FULL: + MediaMode = MEDIA_10FULL; + break; + case SSR_10HALF: + MediaMode = MEDIA_10HALF; + break; + } + + return MediaMode; +} + +static unsigned long +get_CicadaPHY_meida_mode (void) +{ + unsigned long tmp_regval; + unsigned long MediaMode; + + tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, + CIS_AUX_CTRL_STATUS); + switch (tmp_regval & CIS_MEDIA_MASK) { + default: + case CIS_1000FULL: + MediaMode = MEDIA_1000FULL; + break; + case CIS_1000HALF: + MediaMode = MEDIA_1000HALF; + break; + case CIS_100FULL: + MediaMode = MEDIA_100FULL; + break; + case CIS_100HALF: + MediaMode = MEDIA_100HALF; + break; + case CIS_10FULL: + MediaMode = MEDIA_10FULL; + break; + case CIS_10HALF: + MediaMode = MEDIA_10HALF; + break; + } + + return MediaMode; +} + +/* +=========================================================================== +<<<<<< Exported SubProgram Bodies >>>>>> +=========================================================================== +*/ +void eth_halt (void) +{ + /* Disable AX88180 TX/RX functions */ + WRITE_MACREG (CMD, WAKEMOD); +} + +int eth_init (bd_t *bd) +{ + unsigned long tmp_regval; + unsigned long macid0_val, macid1_val, macid2_val; + int ret, i; + +#if defined (CONFIG_DRIVER_AX88180_16BIT) + *((volatile unsigned short *)(AX88180_BASE + 6)) = (START_BASE >> 8); + *((volatile unsigned short *)AX88180_BASE ) = 1; +#endif + memset (&axlocal, 0, sizeof (AX88180_PRIVATE)); + + ax88180_mac_reset (); + + /* Disable AX88180 interrupt */ + WRITE_MACREG (IMR, CLEAR_IMR); + + /* Disable AX88180 TX/RX functions */ + WRITE_MACREG (CMD, WAKEMOD); + + axlocal.LinkState = INS_LINK_UNKNOWN; + + /* Initial PHY registers */ + if ((ret = ax88180_PHY_initial ()) < 0) + return ret; + ax88180_meida_config (); + + /* Reload MAC address from EEPROM */ + WRITE_MACREG (PROMCTRL, RELOAD_EEPROM); + + /* Waiting for reload eeprom completion */ + for (i = 0; i < 500; i++) { + READ_MACREG (PROMCTRL, tmp_regval); + if ((tmp_regval & RELOAD_EEPROM) == 0) + break; + udelay (1000); + } + + /* Get MAC addresses */ + READ_MACREG (MACID0, macid0_val); + READ_MACREG (MACID1, macid1_val); + READ_MACREG (MACID2, macid2_val); + + bd->bi_enetaddr[0] = (unsigned char)macid0_val; + bd->bi_enetaddr[1] = (unsigned char)(macid0_val >> 8); + bd->bi_enetaddr[2] = (unsigned char)macid1_val; + bd->bi_enetaddr[3] = (unsigned char)(macid1_val >> 8); + bd->bi_enetaddr[4] = (unsigned char)macid2_val; + bd->bi_enetaddr[5] = (unsigned char)(macid2_val >> 8); + + if (((macid0_val | macid1_val | macid2_val) == 0) || + (bd->bi_enetaddr[0] & 0x01)) { + /* try to get MAC address from environment */ + u8 i; + char *s, *e; + unsigned short tmp16; + + s = getenv ("ethaddr"); + for (i = 0; i < 6; ++i) { + bd->bi_enetaddr[i] = s ? + simple_strtoul (s, &e, 16) : 0; + if (s) + s = (*e) ? e + 1 : e; + } + + tmp16 = bd->bi_enetaddr[1]; + macid0_val = (tmp16 << 8) | bd->bi_enetaddr[0]; + tmp16 = bd->bi_enetaddr[3]; + macid1_val = (tmp16 << 8) | bd->bi_enetaddr[2]; + tmp16 = bd->bi_enetaddr[5]; + macid2_val = (tmp16 << 8) | bd->bi_enetaddr[4]; + + WRITE_MACREG (MACID0, macid0_val); + WRITE_MACREG (MACID1, macid1_val); + WRITE_MACREG (MACID2, macid2_val); + } + + WRITE_MACREG (RXFILTER, DEFAULT_RXFILTER); + + /* Initial variables here */ + axlocal.FirstTxDesc = TXDP0; + axlocal.NextTxDesc = TXDP0; + axlocal.rxbuf_overflow_count = 0; + + ax88180_disp_all_reg (); + + /* Check if there is any invalid interrupt status. If yes, clear it. */ + READ_MACREG (ISR, tmp_regval); + PRINTK (DEBUG_MSG, "ax88180: The interrupt status = 0x%08lx\n", + tmp_regval); + if (tmp_regval) + WRITE_MACREG (ISR, tmp_regval); + + /* Start AX88180 TX/RX functions */ + WRITE_MACREG (CMD, RXEN | TXEN | WAKEMOD); + + return 0; +} + +/* Get a data block via Ethernet */ +int eth_rx (void) +{ + unsigned long ISR_Status; + unsigned long rxcurt_ptr, rxbound_ptr; + unsigned long tmp_regval; + + /* Read and check interrupt status here...... */ + READ_MACREG (ISR, ISR_Status); + + while (ISR_Status) { + /* Clear the interrupt status */ + WRITE_MACREG (ISR, ISR_Status); + + PRINTK (INT_MSG, + "\nax88180: The interrupt status = 0x%08lx\n", + ISR_Status); + + if (ISR_Status & ISR_PHY) { + /* Read ISR register once to clear PHY interrupt bit */ + tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, + M88_ISR); + ax88180_meida_config (); + ax88180_disp_phy_reg (); + } + + if (ISR_Status & ISR_RXBUFFOVR) { + axlocal.rxbuf_overflow_count++; + READ_MACREG (RXCURT, rxcurt_ptr); + READ_MACREG (RXBOUND, rxbound_ptr); + PRINTK (INT_MSG, "ax88180: RX Buffer overflow! " + "count=%d, RXBOUND=0x%08lx, RXCURT=0x%08lx\n", + (int)axlocal.rxbuf_overflow_count, rxbound_ptr, + rxcurt_ptr); + + if (axlocal.rxbuf_overflow_count > 10) { + ax88180_mac_reset (); + axlocal.FirstTxDesc = TXDP0; + axlocal.NextTxDesc = TXDP0; + axlocal.rxbuf_overflow_count = 0; + } + } + + if (ISR_Status & ISR_RX) { + ax88180_rx_handler (); + } + + /* Read and check interrupt status here...... */ + READ_MACREG (ISR, ISR_Status); + } + + return 0; +} + +/* Send a data block via Ethernet. */ +int eth_send (volatile void *packet, int length) +{ + volatile unsigned char *txdata; + unsigned long TXDES_addr; + unsigned long txcmd_txdp, txbs_txdp; + unsigned long tmp_data; + int i; + + if (axlocal.LinkState != INS_LINK_UP) { + return 0; + } + + txdata = (volatile unsigned char *)packet; + + axlocal.FirstTxDesc = axlocal.NextTxDesc; + txbs_txdp = 1 << axlocal.FirstTxDesc; + + READ_MACREG (TXBS, tmp_data); + READ_MACREG (TXBS, tmp_data); + PRINTK (TX_MSG, "ax88180: Checking available TXDP (TXBS=0x%08lx)\n", + tmp_data); + + /* check the available transmit descriptor */ + if (tmp_data & txbs_txdp) { + /* we should never get here. */ + /* we are running out of resource */ + return 0; + } + + PRINTK (TX_MSG, "ax88180: TXDP%d is available, i=%d\n", + (int)axlocal.FirstTxDesc, i); + + txcmd_txdp = axlocal.FirstTxDesc << 13; + TXDES_addr = TXDES0 + (axlocal.FirstTxDesc << 2); + + WRITE_MACREG (TXCMD, txcmd_txdp | length | TX_START_WRITE); + +#if defined (CONFIG_DRIVER_AX88180_16BIT) + for (i = 0; i < length; i += 2) { + tmp_data = + (unsigned short)*(txdata + i) + + (unsigned short)(*(txdata + i + 1) << 8); + WRITE_TXBUF (tmp_data); + } +#else + for (i = 0; i < length; i += 4) { + tmp_data = + (unsigned long)*(txdata + i) + + (unsigned long)(*(txdata + i + 1) << 8) + + (unsigned long)(*(txdata + i + 2) << 16) + + (unsigned long)(*(txdata + i + 3) << 24); + WRITE_TXBUF (tmp_data); + } +#endif + + WRITE_MACREG (TXCMD, txcmd_txdp | length); + WRITE_MACREG (TXBS, txbs_txdp); + WRITE_MACREG (TXDES_addr, TXDPx_ENABLE | length); + + axlocal.NextTxDesc = (axlocal.NextTxDesc + 1) & TXDP_MASK; + + /* + Check the available transmit descriptor, if we had exhausted all + transmit descriptor ,then we have to wait for at least one free + descriptor + */ + txbs_txdp = 1 << axlocal.NextTxDesc; + READ_MACREG (TXBS, tmp_data); + if (tmp_data & txbs_txdp) { + if (ax88180_poll_tx_complete () < 0) { + ax88180_mac_reset (); + axlocal.FirstTxDesc = TXDP0; + axlocal.NextTxDesc = TXDP0; + printf ("ax88180: Transmit time out occurred!\n"); + } + } + + return 0; +} +#endif /* CONFIG_DRIVER_AX88180 */ + diff --git a/drivers/net/ax88180.h b/drivers/net/ax88180.h new file mode 100644 index 0000000..ae4b1b3 --- /dev/null +++ b/drivers/net/ax88180.h @@ -0,0 +1,415 @@ +/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */ +/* + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + */ + +#include <asm/types.h> +#include <config.h> + +#ifdef CONFIG_DRIVER_AX88180 + +#define ENABLE_JUMBO 1 +#define DISABLE_JUMBO 0 + +#define ENABLE_BURST 1 +#define DISABLE_BURST 0 + +#define NORMAL_RX_MODE 0 +#define RX_LOOPBACK_MODE 1 +#define RX_INIFINIT_LOOP_MODE 2 +#define TX_INIFINIT_LOOP_MODE 3 + +#define DEFAULT_ETH_MTU 1500 + +/* Jumbo packet size 4086 bytes included 4 bytes CRC*/ +#define MAX_JUMBO_MTU 4072 + +/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */ +#define MAX_TX_JUMBO_SIZE 4086 + +/* Max Rx Jumbo size is 15K Bytes */ +#define MAX_RX_SIZE 0x3C00 + +#define MARVELL_88E1111_PHYADDR 0x18 +#define MARVELL_88E1111_PHYIDR0 0x0141 + +#define CICADA_CIS8201_PHYADDR 0x01 +#define CICADA_CIS8201_PHYIDR0 0x000F + +#define MEDIA_AUTO 0 +#define MEDIA_1000FULL 1 +#define MEDIA_1000HALF 2 +#define MEDIA_100FULL 3 +#define MEDIA_100HALF 4 +#define MEDIA_10FULL 5 +#define MEDIA_10HALF 6 + +#define AUTO_MEDIA 0 +#define FORCE_MEDIA 1 + +#define TXDP_MASK 3 +#define TXDP0 0 +#define TXDP1 1 +#define TXDP2 2 +#define TXDP3 3 + +#define CMD_MAP_SIZE 0x100 + +#if defined (CONFIG_DRIVER_AX88180_16BIT) + #define AX88180_MEMORY_SIZE 0x00004000 + #define START_BASE 0x1000 + + #define RX_BUF_SIZE 0x1000 + #define TX_BUF_SIZE 0x0F00 + + #define TX_BASE START_BASE + #define CMD_BASE (TX_BASE + TX_BUF_SIZE) + #define RX_BASE (CMD_BASE + CMD_MAP_SIZE) +#else + #define AX88180_MEMORY_SIZE 0x00010000 + + #define RX_BUF_SIZE 0x8000 + #define TX_BUF_SIZE 0x7C00 + + #define RX_BASE 0x0000 + #define TX_BASE (RX_BASE + RX_BUF_SIZE) + #define CMD_BASE (TX_BASE + TX_BUF_SIZE) +#endif + +/* AX88180 Memory Mapping Definition */ +#define RXBUFFER_START RX_BASE + #define RX_PACKET_LEN_OFFSET 0 + #define RX_PAGE_NUM_MASK 0x7FF //RX pages 0~7FFh +#define TXBUFFER_START TX_BASE + +/* AX88180 MAC Register Definition */ +#define CMD (CMD_BASE + 0x0000) + #define WAKEMOD 0x00000001 + #define TXEN 0x00000100 + #define RXEN 0x00000200 + #define DEFAULT_CMD WAKEMOD +#define IMR (CMD_BASE + 0x0004) + #define IMR_RXBUFFOVR 0x00000001 + #define IMR_WATCHDOG 0x00000002 + #define IMR_TX 0x00000008 + #define IMR_RX 0x00000010 + #define IMR_PHY 0x00000020 + #define CLEAR_IMR 0x00000000 + #define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\ + IMR_RXBUFFOVR | IMR_WATCHDOG) +#define ISR (CMD_BASE + 0x0008) + #define ISR_RXBUFFOVR 0x00000001 + #define ISR_WATCHDOG 0x00000002 + #define ISR_TX 0x00000008 + #define ISR_RX 0x00000010 + #define ISR_PHY 0x00000020 +#define TXCFG (CMD_BASE + 0x0010) + #define AUTOPAD_CRC 0x00000050 + #define DEFAULT_TXCFG AUTOPAD_CRC +#define TXCMD (CMD_BASE + 0x0014) + #define TXCMD_TXDP_MASK 0x00006000 + #define TXCMD_TXDP0 0x00000000 + #define TXCMD_TXDP1 0x00002000 + #define TXCMD_TXDP2 0x00004000 + #define TXCMD_TXDP3 0x00006000 + #define TX_START_WRITE 0x00008000 + #define TX_STOP_WRITE 0x00000000 + #define DEFAULT_TXCMD 0x00000000 +#define TXBS (CMD_BASE + 0x0018) + #define TXDP0_USED 0x00000001 + #define TXDP1_USED 0x00000002 + #define TXDP2_USED 0x00000004 + #define TXDP3_USED 0x00000008 + #define DEFAULT_TXBS 0x00000000 +#define TXDES0 (CMD_BASE + 0x0020) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES0 0x00000000 +#define TXDES1 (CMD_BASE + 0x0024) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES1 0x00000000 +#define TXDES2 (CMD_BASE + 0x0028) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES2 0x00000000 +#define TXDES3 (CMD_BASE + 0x002C) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES3 0x00000000 +#define RXCFG (CMD_BASE + 0x0030) + #define RXBUFF_PROTECT 0x00000001 + #define RXTCPCRC_CHECK 0x00000010 + #define RXFLOW_ENABLE 0x00000100 + #define DEFAULT_RXCFG RXBUFF_PROTECT +#define RXCURT (CMD_BASE + 0x0034) + #define DEFAULT_RXCURT 0x00000000 +#define RXBOUND (CMD_BASE + 0x0038) + #define DEFAULT_RXBOUND 0x7FF //RX pages 0~7FFh +#define MACCFG0 (CMD_BASE + 0x0040) + #define MACCFG0_BIT3_0 0x00000007 + #define IPGT_VAL 0x00000150 + #define TXFLOW_ENABLE 0x00001000 + #define SPEED100 0x00008000 + #define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0) +#define MACCFG1 (CMD_BASE + 0x0044) + #define RGMII_EN 0x00000002 + #define RXFLOW_EN 0x00000020 + #define FULLDUPLEX 0x00000040 + #define MAX_JUMBO_LEN_MASK 0x00000780 + #define RXJUMBO_EN 0x00000800 + #define GIGA_MODE_EN 0x00001000 + #define RXCRC_CHECK 0x00002000 + #define RXPAUSE_DA_CHECK 0x00004000 + + #define JUMBO_LEN_4K 0x00000200 + #define JUMBO_LEN_15K 0x00000780 + #define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK |\ + RGMII_EN) + #define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK) +#define MACCFG2 (CMD_BASE + 0x0048) + #define MACCFG2_BIT15_8 0x00000100 + #define JAM_LIMIT_MASK 0x000000FC + #define DEFAULT_JAM_LIMIT 0x00000064 + #define DEFAULT_MACCFG2 MACCFG2_BIT15_8 +#define MACCFG3 (CMD_BASE + 0x004C) + #define IPGR2_VAL 0x0000000E + #define IPGR1_VAL 0x00000600 + #define NOABORT 0x00008000 + #define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL) +#define TXPAUT (CMD_BASE + 0x0054) + #define DEFAULT_TXPAUT 0x001FE000 +#define RXBTHD0 (CMD_BASE + 0x0058) + #define DEFAULT_RXBTHD0 0x00000300 +#define RXBTHD1 (CMD_BASE + 0x005C) + #define DEFAULT_RXBTHD1 0x00000600 +#define RXFULTHD (CMD_BASE + 0x0060) + #define DEFAULT_RXFULTHD 0x00000100 +#define MISC (CMD_BASE + 0x0068) + /* Normal operation mode */ + #define MISC_NORMAL 0x00000003 + /* Clear bit 0 to reset MAC */ + #define MISC_RESET_MAC 0x00000002 + /* Clear bit 1 to reset PHY */ + #define MISC_RESET_PHY 0x00000001 + /* Clear bit 0 and 1 to reset MAC and PHY */ + #define MISC_RESET_MAC_PHY 0x00000000 + #define DEFAULT_MISC MISC_NORMAL +#define MACID0 (CMD_BASE + 0x0070) +#define MACID1 (CMD_BASE + 0x0074) +#define MACID2 (CMD_BASE + 0x0078) +#define TXLEN (CMD_BASE + 0x007C) + #define DEFAULT_TXLEN 0x000005FC +#define RXFILTER (CMD_BASE + 0x0080) + #define RX_RXANY 0x00000001 + #define RX_MULTICAST 0x00000002 + #define RX_UNICAST 0x00000004 + #define RX_BROADCAST 0x00000008 + #define RX_MULTI_HASH 0x00000010 + #define DISABLE_RXFILTER 0x00000000 + #define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST) +#define MDIOCTRL (CMD_BASE + 0x0084) + #define PHY_ADDR_MASK 0x0000001F + #define REG_ADDR_MASK 0x00001F00 + #define READ_PHY 0x00004000 + #define WRITE_PHY 0x00008000 +#define MDIODP (CMD_BASE + 0x0088) +#define GPIOCTRL (CMD_BASE + 0x008C) +#define RXINDICATOR (CMD_BASE + 0x0090) + #define RX_START_READ 0x00000001 + #define RX_STOP_READ 0x00000000 + #define DEFAULT_RXINDICATOR RX_STOP_READ +#define TXST (CMD_BASE + 0x0094) +#define MDCCLKPAT (CMD_BASE + 0x00A0) +#define RXIPCRCCNT (CMD_BASE + 0x00A4) +#define RXCRCCNT (CMD_BASE + 0x00A8) +#define TXFAILCNT (CMD_BASE + 0x00AC) +#define PROMDP (CMD_BASE + 0x00B0) +#define PROMCTRL (CMD_BASE + 0x00B4) + #define RELOAD_EEPROM 0x00000200 +#define MAXRXLEN (CMD_BASE + 0x00B8) +#define HASHTAB0 (CMD_BASE + 0x00C0) +#define HASHTAB1 (CMD_BASE + 0x00C4) +#define HASHTAB2 (CMD_BASE + 0x00C8) +#define HASHTAB3 (CMD_BASE + 0x00CC) +#define DOGTHD0 (CMD_BASE + 0x00E0) + #define DEFAULT_DOGTHD0 0x0000FFFF +#define DOGTHD1 (CMD_BASE + 0x00E4) + #define START_WATCHDOG_TIMER 0x00008000 + #define DEFAULT_DOGTHD1 0x00000FFF +#define SOFTRST (CMD_BASE + 0x00EC) + #define SOFTRST_NORMAL 0x00000003 + #define SOFTRST_RESET_MAC 0x00000002 + +/* External PHY Register Definition */ +#define BMCR 0x0000 + #define LINE_SPEED_MSB 0x0040 + #define DUPLEX_MODE 0x0100 + #define RESTART_AUTONEG 0x0200 + #define POWER_DOWN 0x0800 + #define AUTONEG_EN 0x1000 + #define LINE_SPEED_LSB 0x2000 + #define PHY_RESET 0x8000 + + #define MEDIAMODE_MASK (LINE_SPEED_MSB | LINE_SPEED_LSB |\ + DUPLEX_MODE) + #define BMCR_SPEED_1000 LINE_SPEED_MSB + #define BMCR_SPEED_100 LINE_SPEED_LSB + #define BMCR_SPEED_10 0x0000 + + #define BMCR_1000FULL (BMCR_SPEED_1000 | DUPLEX_MODE) + #define BMCR_100FULL (BMCR_SPEED_100 | DUPLEX_MODE) + #define BMCR_100HALF BMCR_SPEED_100 + #define BMCR_10FULL DUPLEX_MODE + #define BMCR_10HALF 0x0000 +#define BMSR 0x0001 + #define LINKOK 0x0004 + #define AUTONEG_ENABLE_STS 0x0008 + #define AUTONEG_COMPLETE 0x0020 +#define PHYIDR0 0x0002 +#define PHYIDR1 0x0003 +#define ANAR 0x0004 + #define ANAR_PAUSE 0x0400 + #define ANAR_100FULL 0x0100 + #define ANAR_100HALF 0x0080 + #define ANAR_10FULL 0x0040 + #define ANAR_10HALF 0x0020 + #define ANAR_8023BIT 0x0001 +#define ANLPAR 0x0005 +#define ANER 0x0006 +#define AUX_1000_CTRL 0x0009 + #define ENABLE_1000HALF 0x0100 + #define ENABLE_1000FULL 0x0200 + #define DEFAULT_AUX_1000_CTRL (ENABLE_1000HALF | ENABLE_1000FULL) +#define AUX_1000_STATUS 0x000A + #define LP_1000HALF 0x0400 + #define LP_1000FULL 0x0800 + +/* Marvell 88E1111 Gigabit PHY Register Definition */ +#define M88_SSR 0x0011 + #define SSR_SPEED_MASK 0xC000 + #define SSR_SPEED_1000 0x8000 + #define SSR_SPEED_100 0x4000 + #define SSR_SPEED_10 0x0000 + #define SSR_DUPLEX 0x2000 + #define SSR_MEDIA_RESOLVED_OK 0x0800 + + #define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX) + #define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX) + #define SSR_1000HALF SSR_SPEED_1000 + #define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX) + #define SSR_100HALF SSR_SPEED_100 + #define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX) + #define SSR_10HALF SSR_SPEED_10 +#define M88_IER 0x0012 + #define LINK_CHANGE_INT 0x0400 +#define M88_ISR 0x0013 + #define LINK_CHANGE_STATUS 0x0400 +#define M88_EXT_SCR 0x0014 + #define RGMII_RXCLK_DELAY 0x0080 + #define RGMII_TXCLK_DELAY 0x0002 + #define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY) +#define M88_EXT_SSR 0x001B + #define HWCFG_MODE_MASK 0x000F + #define RGMII_COPPER_MODE 0x000B + +/* CICADA CIS8201 Gigabit PHY Register Definition */ +#define CIS_IMR 0x0019 + #define CIS_INT_ENABLE 0x8000 + #define CIS_LINK_CHANGE_INT 0x2000 +#define CIS_ISR 0x001A + #define CIS_INT_PENDING 0x8000 + #define CIS_LINK_CHANGE_STATUS 0x2000 +#define CIS_AUX_CTRL_STATUS 0x001C + #define CIS_AUTONEG_COMPLETE 0x8000 + #define CIS_SPEED_MASK 0x0018 + #define CIS_SPEED_1000 0x0010 + #define CIS_SPEED_100 0x0008 + #define CIS_SPEED_10 0x0000 + #define CIS_DUPLEX 0x0020 + + #define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX) + #define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX) + #define CIS_1000HALF CIS_SPEED_1000 + #define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX) + #define CIS_100HALF CIS_SPEED_100 + #define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX) + #define CIS_10HALF CIS_SPEED_10 + #define CIS_SMI_PRIORITY 0x0004 + +/* Debug Message Display Level Definition */ +#define TX_MSG 0x0001 +#define RX_MSG 0x0002 +#define INT_MSG 0x0004 +#define DEBUG_MSG 0x0008 +#define NO_MSG 0x0000 +#define DEBUG_FLAGS (NO_MSG) + +#define PRINTK(flag, args...) if (flag & DEBUG_FLAGS) printf (args) + +/* + Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer +*/ +#if defined (CONFIG_DRIVER_AX88180_16BIT) +#define READ_RXBUF(data) \ + do { \ + data = *(volatile unsigned short *) \ + (AX88180_BASE + RXBUFFER_START); \ + } while (0) + +#define WRITE_TXBUF(data) \ + do { \ + *(volatile unsigned short *)(AX88180_BASE + TXBUFFER_START) \ + = data; \ + } while (0) + +#define READ_MACREG(regaddr, regdata) \ + do { \ + regdata = *(volatile unsigned short *) \ + (AX88180_BASE + regaddr); \ + } while (0) + +#define WRITE_MACREG(regaddr, regdata) \ + do { \ + *(volatile unsigned short*)(AX88180_BASE + regaddr) \ + = regdata; \ + } while (0) +#else +#define READ_RXBUF(data) \ + do { \ + data = *(volatile unsigned long *) \ + (AX88180_BASE + RXBUFFER_START); \ + } while (0) + +#define WRITE_TXBUF(data) \ + do { \ + *(volatile unsigned long *)(AX88180_BASE + TXBUFFER_START) \ + = data; \ + } while (0) + +#define READ_MACREG(regaddr, regdata) \ + do { \ + regdata = *(volatile unsigned long*)(AX88180_BASE + regaddr); \ + } while (0) + +#define WRITE_MACREG(regaddr, regdata) \ + do { \ + *(volatile unsigned long*)(AX88180_BASE + regaddr) \ + = regdata; \ + } while (0) +#endif /* end of CONFIG_DRIVER_AX88180_16BIT */ + +#endif /*end of CONFIG_DRIVER_AX88180 */

Louis,
This submission has several style issues. I suggest you read this: http://www.denx.de/wiki/UBoot/CodingStyle
Louis wrote:
Resubmit the driver for the ASIX AX88180 gigabit ethernet chip.
Signed-off-by: Louis Su louis@asix.com.tw
drivers/net/Makefile | 1 + drivers/net/ax88180.c | 842 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ax88180.h | 415 ++++++++++++++++++++++++ 3 files changed, 1258 insertions(+), 0 deletions(-) create mode 100644 drivers/net/ax88180.c create mode 100644 drivers/net/ax88180.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 84be288..3a574e0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnet.a
COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o +COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c new file mode 100644 index 0000000..5579ef0 --- /dev/null +++ b/drivers/net/ax88180.c @@ -0,0 +1,842 @@ +/* ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */ +/*
Multi-line comments are done like:
/* * Comment */
- This program is free software; you can distribute it and/or modify
- it under the terms of the GNU General Public License (Version 2) as
- published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- USA.
+*/
+/*
========================================================================
- ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
- The AX88180 Ethernet controller is a high performance and highly
- integrated local CPU bus Ethernet controller with embedded 40K bytes
- SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
- embedded systems.
- The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
- controller that supports both MII and RGMII interfaces and is
- compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
- Please visit ASIX's web site (http://www.asix.com.tw) for more
- details.
- Module Name : ax88180.c
- Date : 2008-07-01
- History
- 09/06/2006 : New release for AX88180 US2 chip.
- 07/01/2008 : Fix up the coding style and using functions
- instead of most macros
======================================================================== +*/ +#include <common.h> +#include <command.h> +#include <net.h>
+#include "ax88180.h"
+#ifdef CONFIG_DRIVER_AX88180
This is unnecessary. You're already compiling conditionally in Makefile
+/* +===========================================================================
+<<<<<< Local SubProgram Declaration >>>>>> +===========================================================================
+*/ +static void ax88180_rx_handler (void); +static int ax88180_PHY_initial (void); +static void ax88180_meida_config (void); +static unsigned long get_CicadaPHY_meida_mode (void); +static unsigned long get_MarvellPHY_meida_mode (void); +static unsigned short ax88180_mdio_read (unsigned long phyaddr,
unsigned long regaddr);
Indentation with TABs, 8 characters wide.
+static void ax88180_mdio_write (unsigned long phyaddr,
unsigned long regaddr,
unsigned short regdata);
+/* +===========================================================================
+<<<<<< Declare Macro/Structure Definition >>>>>> +===========================================================================
+*/ +typedef enum _AX88180_LINK_STATE {
- INS_LINK_DOWN,
- INS_LINK_UP,
- INS_LINK_UNKNOWN
+} AX88180_LINK_STATE;
Again, serious indentation problems. I won't mention it again.
+typedef struct _AX88180_PRIVATE {
- unsigned long PhyAddr;
- unsigned long PhyID0;
- unsigned long FirstTxDesc;
- unsigned long NextTxDesc;
- unsigned long rxbuf_overflow_count;
- AX88180_LINK_STATE LinkState;
+} AX88180_PRIVATE;
+AX88180_PRIVATE axlocal;
+#if (DEBUG_FLAGS & DEBUG_MSG) +static inline void ax88180_disp_all_reg (void) +{
- unsigned long tmpval;
- int i;
- PRINTK (DEBUG_MSG, "ax88180: AX88180 MAC Registers:\n");
We don't need yet another way to print debug information. Please use debug() or printf() only.
- for (i = 0xFC00; i <= 0xFCFF; i += 4) {
- READ_MACREG (i, tmpval);
- PRINTK (DEBUG_MSG, "0x%04x=0x%08lx ", i, tmpval);
- if ((i & 0xF) == 0xC)
This is a silly obfuscated way of saying 'if (i%12 == 0)'
- PRINTK (DEBUG_MSG, "\n");
- }
- PRINTK (DEBUG_MSG, "\n");
+}
+static inline void ax88180_disp_phy_reg (void) +{
- unsigned long tmpval;
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, BMCR);
- PRINTK (DEBUG_MSG, "BMCR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, BMSR);
- PRINTK (DEBUG_MSG, "BMSR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR0);
- PRINTK (DEBUG_MSG, "PHYIDR0=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR1);
- PRINTK (DEBUG_MSG, "PHYIDR1=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, ANAR);
- PRINTK (DEBUG_MSG, "ANAR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, ANLPAR);
- PRINTK (DEBUG_MSG, "ANLPAR=0x%04x \n", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, ANER);
- PRINTK (DEBUG_MSG, "ANER=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, AUX_1000_CTRL);
- PRINTK (DEBUG_MSG, "1G_CTRL=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, AUX_1000_STATUS);
- PRINTK (DEBUG_MSG, "1G_STATUS=0x%04x \n", (unsigned int)tmpval);
- if (axlocal.PhyID0 == MARVELL_88E1111_PHYIDR0) {
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_SSR);
- PRINTK (DEBUG_MSG, "M88_SSR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_IER);
- PRINTK (DEBUG_MSG, "M88_IER=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_ISR);
- PRINTK (DEBUG_MSG, "M88_ISR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_EXT_SCR);
- PRINTK (DEBUG_MSG, "M88_EXT_SCR=0x%04x ",
- (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, M88_EXT_SSR);
- PRINTK (DEBUG_MSG, "M88_EXT_SSR=0x%04x \n",
- (unsigned int)tmpval);
- } else if (axlocal.PhyID0 == CICADA_CIS8201_PHYIDR0) {
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, CIS_IMR);
- PRINTK (DEBUG_MSG, "CIS_IMR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr, CIS_ISR);
- PRINTK (DEBUG_MSG, "CIS_ISR=0x%04x ", (unsigned int)tmpval);
- tmpval = ax88180_mdio_read (axlocal.PhyAddr,
- CIS_AUX_CTRL_STATUS);
- PRINTK (DEBUG_MSG, "CIS_AUX=0x%04x \n",
- (unsigned int)tmpval);
- }
- READ_MACREG (RXCFG, tmpval);
- PRINTK (DEBUG_MSG, "RXCFG=0x%08lx ", tmpval);
- READ_MACREG (MACCFG0, tmpval);
- PRINTK (DEBUG_MSG, "MACCFG0=0x%08lx ", tmpval);
- READ_MACREG (MACCFG1, tmpval);
- PRINTK (DEBUG_MSG, "MACCFG1=0x%08lx ", tmpval);
- READ_MACREG (MACCFG2, tmpval);
- PRINTK (DEBUG_MSG, "MACCFG2=0x%08lx \n\n", tmpval);
+} +#else +static inline void ax88180_disp_all_reg (void) {} +static inline void ax88180_disp_phy_reg (void) {} +#endif
+/* +===========================================================================
+<<<<<< Local SubProgram Bodies >>>>>> +===========================================================================
+*/ +static int +ax88180_mdio_check_complete (void) +{
- int us_cnt = 10000;
- unsigned long tmpval;
- /* MDIO read/write should not take more than 10 ms */
- while (--us_cnt) {
- READ_MACREG (MDIOCTRL, tmpval);
- if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
- break;
- }
- return us_cnt;
+}
+static unsigned short +ax88180_mdio_read (unsigned long phyaddr, unsigned long regaddr) +{
- unsigned long tmpval = 0;
- WRITE_MACREG (MDIOCTRL, READ_PHY | (regaddr << 8) | phyaddr);
- if (ax88180_mdio_check_complete ())
- READ_MACREG (MDIODP, tmpval);
- else
- printf("Failed to read PHY register!\n");
- return (unsigned short)(tmpval & 0xFFFF);
+}
+static void +ax88180_mdio_write (unsigned long phyaddr, unsigned long regaddr,
- unsigned short regdata)
+{
- WRITE_MACREG (MDIODP, regdata);
- WRITE_MACREG (MDIOCTRL, WRITE_PHY | (regaddr << 8) | phyaddr);
- if(!ax88180_mdio_check_complete ())
- printf("Failed to write PHY register!\n");
+}
+static int ax88180_phy_reset (void) +{
- unsigned short delay_cnt = 500;
- ax88180_mdio_write (axlocal.PhyAddr, BMCR, PHY_RESET | AUTONEG_EN);
- /* Wait for the reset to complete, or time out (500 ms) */
- while (ax88180_mdio_read (axlocal.PhyAddr, BMCR) & PHY_RESET) {
- udelay (1000);
- if (--delay_cnt == 0) {
- printf("Failed to reset PHY!\n");
- return -1;
- }
- }
- return 0;
+}
+static void ax88180_mac_reset (void) +{
- unsigned long tmpval;
- WRITE_MACREG (MISC, MISC_RESET_MAC);
- READ_MACREG (MISC, tmpval);
- WRITE_MACREG (MISC, MISC_NORMAL);
- WRITE_MACREG (RXINDICATOR, DEFAULT_RXINDICATOR);
- WRITE_MACREG (TXCMD, DEFAULT_TXCMD);
- WRITE_MACREG (TXBS, DEFAULT_TXBS);
- WRITE_MACREG (TXDES0, DEFAULT_TXDES0);
- WRITE_MACREG (TXDES1, DEFAULT_TXDES1);
- WRITE_MACREG (TXDES2, DEFAULT_TXDES2);
- WRITE_MACREG (TXDES3, DEFAULT_TXDES3);
- WRITE_MACREG (TXCFG, DEFAULT_TXCFG);
- WRITE_MACREG (MACCFG2, DEFAULT_MACCFG2);
- WRITE_MACREG (MACCFG3, DEFAULT_MACCFG3);
- WRITE_MACREG (TXLEN, DEFAULT_TXLEN);
- WRITE_MACREG (RXBTHD0, DEFAULT_RXBTHD0);
- WRITE_MACREG (RXBTHD1, DEFAULT_RXBTHD1);
- WRITE_MACREG (RXFULTHD, DEFAULT_RXFULTHD);
- WRITE_MACREG (DOGTHD0, DEFAULT_DOGTHD0);
- WRITE_MACREG (DOGTHD1, DEFAULT_DOGTHD1);
+}
+static int ax88180_poll_tx_complete (void) +{
- unsigned long tmp_data, txbs_txdp;
- int TimeOutCnt = 10000;
- txbs_txdp = 1 << axlocal.NextTxDesc;
- while (TimeOutCnt--) {
- READ_MACREG (TXBS, tmp_data);
- if ((tmp_data & txbs_txdp) == 0)
- break;
- udelay (100);
- }
- if (TimeOutCnt)
- return 0;
- else
- return -TimeOutCnt;
+}
+static void ax88180_rx_handler (void) +{
- unsigned char *rxdata;
- unsigned long tmp_data;
- unsigned long rx_packet_len;
- unsigned int data_size;
- unsigned int dword_count, byte_count;
- unsigned long rxcurt_ptr, rxbound_ptr, next_ptr;
- int i;
- int j;
- READ_MACREG (RXCURT, rxcurt_ptr);
- READ_MACREG (RXBOUND, rxbound_ptr);
- next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
- PRINTK (RX_MSG, "ax88180: RX original RXBOUND=0x%08lx,"
- " RXCURT=0x%08lx\n", rxbound_ptr, rxcurt_ptr);
- while (next_ptr != rxcurt_ptr) {
- WRITE_MACREG (RXINDICATOR, RX_START_READ);
- READ_RXBUF (rx_packet_len);
- if ((rx_packet_len == 0) || (rx_packet_len > MAX_RX_SIZE)) {
- WRITE_MACREG (RXINDICATOR, RX_STOP_READ);
- ax88180_mac_reset ();
- printf ("ax88180: Invalid Rx packet length!"
- " (len=0x%08lx)\n", rx_packet_len);
- printf ("ax88180: RX RXBOUND=0x%08lx,"
- "RXCURT=0x%08lx\n", rxbound_ptr, rxcurt_ptr);
- return;
- }
- data_size = (unsigned int)rx_packet_len;
- rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
- rxbound_ptr &= RX_PAGE_NUM_MASK;
- rxdata = (unsigned char *)NetRxPackets[0];
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
- dword_count = data_size >> 1;
- byte_count = data_size & 0x1;
+#else
- dword_count = data_size >> 2;
- byte_count = data_size & 0x3;
+#endif
- for (i = 0; i < dword_count; i++) {
- READ_RXBUF (tmp_data);
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
- *((unsigned short *)rxdata + i) = tmp_data;
+#else
- *((unsigned long *)rxdata + i) = tmp_data;
+#endif
- }
- if (byte_count != 0) {
- READ_RXBUF (tmp_data);
- for (j = 0; j < byte_count; j++) {
- *(rxdata + (dword_count * 4) + j) =
(unsigned char)(tmp_data >> (j * 8));
- }
- }
- WRITE_MACREG (RXINDICATOR, RX_STOP_READ);
- /* Pass the packet up to the protocol layers. */
- NetReceive (NetRxPackets[0], data_size);
- WRITE_MACREG (RXBOUND, rxbound_ptr);
- READ_MACREG (RXCURT, rxcurt_ptr);
- READ_MACREG (RXBOUND, rxbound_ptr);
- next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
- PRINTK (RX_MSG, "ax88180: RX updated RXBOUND=0x%08lx,"
- "RXCURT=0x%08lx\n", rxbound_ptr, rxcurt_ptr);
- }
- if (axlocal.rxbuf_overflow_count > 0)
- axlocal.rxbuf_overflow_count--;
- return;
+}
+static int ax88180_PHY_initial (void) +{
- unsigned long tmp_regval;
- int i;
- int ret;
- /* Check avaliable PHY chipset */
- axlocal.PhyAddr = MARVELL_88E1111_PHYADDR;
- axlocal.PhyID0 = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR0);
- if (axlocal.PhyID0 == MARVELL_88E1111_PHYIDR0) {
- PRINTK (DEBUG_MSG, "ax88180: Found Marvell 88E1111 PHY."
- " (PHY Addr=0x%lx)\n", axlocal.PhyAddr);
- tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, M88_EXT_SSR);
- if ((tmp_regval & HWCFG_MODE_MASK) == RGMII_COPPER_MODE) {
- ax88180_mdio_write (axlocal.PhyAddr, M88_EXT_SCR,
- DEFAULT_EXT_SCR);
- if ((ret = ax88180_phy_reset ()) < 0)
- return ret;
- ax88180_mdio_write (axlocal.PhyAddr, M88_IER,
- LINK_CHANGE_INT);
- }
- } else {
- axlocal.PhyAddr = CICADA_CIS8201_PHYADDR;
- axlocal.PhyID0 = ax88180_mdio_read (axlocal.PhyAddr, PHYIDR0);
- if (axlocal.PhyID0 == CICADA_CIS8201_PHYIDR0) {
- PRINTK (DEBUG_MSG, "ax88180: Found CICADA CIS8201 PHY"
- " chipset. (PHY Addr=0x%lx)\n",
- axlocal.PhyAddr);
- ax88180_mdio_write (axlocal.PhyAddr, CIS_IMR,
- (CIS_INT_ENABLE | LINK_CHANGE_INT));
- /*
Set CIS_SMI_PRIORITY bit before force the media mode
- */
- tmp_regval = ax88180_mdio_read (axlocal.PhyAddr,
CIS_AUX_CTRL_STATUS);
- tmp_regval &= ~CIS_SMI_PRIORITY;
- ax88180_mdio_write (axlocal.PhyAddr,
- CIS_AUX_CTRL_STATUS, tmp_regval);
- } else {
- printf ("ax88180: Unknown PHY chipset!!\n");
- return -1;
- }
- }
- /* Waiting for auto-negotiation complete. */
- /* This may take up to 5 seconds */
- PRINTK (DEBUG_MSG,
- "ax88180: Waiting for auto-negotiation completion......\n");
- for (i = 0; i < 5000; i++) {
- tmp_regval = ax88180_mdio_read (axlocal.PhyAddr, BMSR);
- if (tmp_regval & AUTONEG_COMPLETE) {
- break;
- }
- udelay (1000);
- }
- return 0;
+}
+static void ax88180_meida_config (void)
I think you mean to call this 'media_config'. Several function names are misspelled this way.
+{
- unsigned long bmcr_val, bmsr_val;
- unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
- unsigned long RealMediaMode;
- int i;
- /* Waiting 200 msecs for PHY link stable */
- for (i = 0; i < 200; i++) {
- bmsr_val = ax88180_mdio_read (axlocal.PhyAddr, BMSR);
- if (bmsr_val & LINKOK) {
- break;
- }
- udelay (1000);
- }
- bmsr_val = ax88180_mdio_read (axlocal.PhyAddr, BMSR);
- PRINTK (DEBUG_MSG, "ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
- if (bmsr_val & LINKOK) {
- bmcr_val = ax88180_mdio_read (axlocal.PhyAddr, BMCR);
- if (bmcr_val & AUTONEG_EN) {
- /* Waiting for Auto-negotiation completion */
- /* This may take up to 5 seconds */
- PRINTK (DEBUG_MSG, "ax88180: Auto-negotiation is "
- "enabled. Waiting for NWay completion..\n");
- for (i = 0; i < 5000; i++) {
- bmsr_val = ax88180_mdio_read (axlocal.PhyAddr,
BMSR);
- if (bmsr_val & AUTONEG_COMPLETE) {
break;
- }
- udelay (1000);
- }
- } else
- PRINTK (DEBUG_MSG,
- "ax88180: Auto-negotiation is disabled.\n");
- PRINTK (DEBUG_MSG, "ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
- (unsigned int)bmcr_val, (unsigned int)bmsr_val);
- /* Get real media mode here */
- if (axlocal.PhyID0 == MARVELL_88E1111_PHYIDR0) {
- RealMediaMode = get_MarvellPHY_meida_mode ();
- } else if (axlocal.PhyID0 == CICADA_CIS8201_PHYIDR0) {
- RealMediaMode = get_CicadaPHY_meida_mode ();
- } else {
- RealMediaMode = MEDIA_1000FULL;
- }
- switch (RealMediaMode) {
- default:
- case MEDIA_1000FULL:
- PRINTK (DEBUG_MSG,
- "ax88180: 1000Mbps Full-duplex mode.\n");
- rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
- maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
- maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
FULLDUPLEX | DEFAULT_MACCFG1;
- break;
- case MEDIA_1000HALF:
- PRINTK (DEBUG_MSG,
- "ax88180: 1000Mbps Half-duplex mode.\n");
- rxcfg_val = DEFAULT_RXCFG;
- maccfg0_val = DEFAULT_MACCFG0;
- maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
- break;
- case MEDIA_100FULL:
- PRINTK (DEBUG_MSG,
- "ax88180: 100Mbps Full-duplex mode.\n");
- rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
- maccfg0_val = SPEED100 | TXFLOW_ENABLE
| DEFAULT_MACCFG0;
- maccfg1_val = RXFLOW_EN | FULLDUPLEX
| DEFAULT_MACCFG1;
- break;
- case MEDIA_100HALF:
- PRINTK (DEBUG_MSG,
- "ax88180: 100Mbps Half-duplex mode.\n");
- rxcfg_val = DEFAULT_RXCFG;
- maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
- maccfg1_val = DEFAULT_MACCFG1;
- break;
- case MEDIA_10FULL:
- PRINTK (DEBUG_MSG,
- "ax88180: 10Mbps Full-duplex mode.\n");
- rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
- maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
- maccfg1_val = RXFLOW_EN | FULLDUPLEX
| DEFAULT_MACCFG1;
- break;
- case MEDIA_10HALF:
- PRINTK (DEBUG_MSG,
- "ax88180: 10Mbps Half-duplex mode.\n");
- rxcfg_val = DEFAULT_RXCFG;
- maccfg0_val = DEFAULT_MACCFG0;
- maccfg1_val = DEFAULT_MACCFG1;
- break;
- }
- axlocal.LinkState = INS_LINK_UP;
- } else {
- rxcfg_val = DEFAULT_RXCFG;
- maccfg0_val = DEFAULT_MACCFG0;
- maccfg1_val = DEFAULT_MACCFG1;
- axlocal.LinkState = INS_LINK_DOWN;
- }
- WRITE_MACREG (RXCFG, rxcfg_val);
- WRITE_MACREG (MACCFG0, maccfg0_val);
- WRITE_MACREG (MACCFG1, maccfg1_val);
- return;
+}
+static unsigned long +get_MarvellPHY_meida_mode (void) +{
- unsigned long m88_ssr;
- unsigned long MediaMode;
- m88_ssr = ax88180_mdio_read (axlocal.PhyAddr, M88_SSR);
- switch (m88_ssr & SSR_MEDIA_MASK) {
- default:
- case SSR_1000FULL:
- MediaMode = MEDIA_1000FULL;
- break;
- case SSR_1000HALF:
- MediaMode = MEDIA_1000HALF;
- break;
- case SSR_100FULL:
- MediaMode = MEDIA_100FULL;
- break;
- case SSR_100HALF:
- MediaMode = MEDIA_100HALF;
- break;
- case SSR_10FULL:
- MediaMode = MEDIA_10FULL;
- break;
- case SSR_10HALF:
- MediaMode = MEDIA_10HALF;
- break;
- }
- return MediaMode;
+}
+static unsigned long +get_CicadaPHY_meida_mode (void) +{
- unsigned long tmp_regval;
- unsigned long MediaMode;
- tmp_regval = ax88180_mdio_read (axlocal.PhyAddr,
- CIS_AUX_CTRL_STATUS);
- switch (tmp_regval & CIS_MEDIA_MASK) {
- default:
Please don't put default first. I'm sure it compiles correctly, but looks awkward.
- case CIS_1000FULL:
- MediaMode = MEDIA_1000FULL;
- break;
- case CIS_1000HALF:
- MediaMode = MEDIA_1000HALF;
- break;
- case CIS_100FULL:
- MediaMode = MEDIA_100FULL;
- break;
- case CIS_100HALF:
- MediaMode = MEDIA_100HALF;
- break;
- case CIS_10FULL:
- MediaMode = MEDIA_10FULL;
- break;
- case CIS_10HALF:
- MediaMode = MEDIA_10HALF;
- break;
- }
- return MediaMode;
+}
+/* +===========================================================================
+<<<<<< Exported SubProgram Bodies >>>>>> +===========================================================================
Please don't do things this way. Only one function should be exported globally, something like: int ax88180_initialize(bd_t *bis)
This function should fill in a 'struct eth_device' with init(), halt(), send() and recv() function pointers, and register the struct. There are many examples in the source tree of drivers that do this properly.
+*/ +void eth_halt (void) +{
- /* Disable AX88180 TX/RX functions */
- WRITE_MACREG (CMD, WAKEMOD);
+}
+int eth_init (bd_t *bd) +{
- unsigned long tmp_regval;
- unsigned long macid0_val, macid1_val, macid2_val;
- int ret, i;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
- *((volatile unsigned short *)(AX88180_BASE + 6)) = (START_BASE >> 8);
- *((volatile unsigned short *)AX88180_BASE ) = 1;
+#endif
- memset (&axlocal, 0, sizeof (AX88180_PRIVATE));
- ax88180_mac_reset ();
- /* Disable AX88180 interrupt */
- WRITE_MACREG (IMR, CLEAR_IMR);
- /* Disable AX88180 TX/RX functions */
- WRITE_MACREG (CMD, WAKEMOD);
- axlocal.LinkState = INS_LINK_UNKNOWN;
- /* Initial PHY registers */
- if ((ret = ax88180_PHY_initial ()) < 0)
- return ret;
- ax88180_meida_config ();
- /* Reload MAC address from EEPROM */
- WRITE_MACREG (PROMCTRL, RELOAD_EEPROM);
- /* Waiting for reload eeprom completion */
- for (i = 0; i < 500; i++) {
- READ_MACREG (PROMCTRL, tmp_regval);
- if ((tmp_regval & RELOAD_EEPROM) == 0)
- break;
- udelay (1000);
- }
- /* Get MAC addresses */
- READ_MACREG (MACID0, macid0_val);
- READ_MACREG (MACID1, macid1_val);
- READ_MACREG (MACID2, macid2_val);
- bd->bi_enetaddr[0] = (unsigned char)macid0_val;
- bd->bi_enetaddr[1] = (unsigned char)(macid0_val >> 8);
- bd->bi_enetaddr[2] = (unsigned char)macid1_val;
- bd->bi_enetaddr[3] = (unsigned char)(macid1_val >> 8);
- bd->bi_enetaddr[4] = (unsigned char)macid2_val;
- bd->bi_enetaddr[5] = (unsigned char)(macid2_val >> 8);
- if (((macid0_val | macid1_val | macid2_val) == 0) ||
- (bd->bi_enetaddr[0] & 0x01)) {
- /* try to get MAC address from environment */
- u8 i;
- char *s, *e;
- unsigned short tmp16;
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ?
- simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- tmp16 = bd->bi_enetaddr[1];
- macid0_val = (tmp16 << 8) | bd->bi_enetaddr[0];
- tmp16 = bd->bi_enetaddr[3];
- macid1_val = (tmp16 << 8) | bd->bi_enetaddr[2];
- tmp16 = bd->bi_enetaddr[5];
- macid2_val = (tmp16 << 8) | bd->bi_enetaddr[4];
- WRITE_MACREG (MACID0, macid0_val);
- WRITE_MACREG (MACID1, macid1_val);
- WRITE_MACREG (MACID2, macid2_val);
- }
- WRITE_MACREG (RXFILTER, DEFAULT_RXFILTER);
- /* Initial variables here */
- axlocal.FirstTxDesc = TXDP0;
- axlocal.NextTxDesc = TXDP0;
- axlocal.rxbuf_overflow_count = 0;
- ax88180_disp_all_reg ();
- /* Check if there is any invalid interrupt status. If yes, clear it. */
- READ_MACREG (ISR, tmp_regval);
- PRINTK (DEBUG_MSG, "ax88180: The interrupt status = 0x%08lx\n",
tmp_regval);
- if (tmp_regval)
- WRITE_MACREG (ISR, tmp_regval);
- /* Start AX88180 TX/RX functions */
- WRITE_MACREG (CMD, RXEN | TXEN | WAKEMOD);
- return 0;
+}
+/* Get a data block via Ethernet */ +int eth_rx (void) +{
- unsigned long ISR_Status;
- unsigned long rxcurt_ptr, rxbound_ptr;
- unsigned long tmp_regval;
- /* Read and check interrupt status here...... */
- READ_MACREG (ISR, ISR_Status);
- while (ISR_Status) {
- /* Clear the interrupt status */
- WRITE_MACREG (ISR, ISR_Status);
- PRINTK (INT_MSG,
"\nax88180: The interrupt status = 0x%08lx\n",
ISR_Status);
- if (ISR_Status & ISR_PHY) {
- /* Read ISR register once to clear PHY interrupt bit */
- tmp_regval = ax88180_mdio_read (axlocal.PhyAddr,
M88_ISR);
- ax88180_meida_config ();
- ax88180_disp_phy_reg ();
- }
- if (ISR_Status & ISR_RXBUFFOVR) {
- axlocal.rxbuf_overflow_count++;
- READ_MACREG (RXCURT, rxcurt_ptr);
- READ_MACREG (RXBOUND, rxbound_ptr);
- PRINTK (INT_MSG, "ax88180: RX Buffer overflow! "
- "count=%d, RXBOUND=0x%08lx, RXCURT=0x%08lx\n",
- (int)axlocal.rxbuf_overflow_count, rxbound_ptr,
- rxcurt_ptr);
- if (axlocal.rxbuf_overflow_count > 10) {
- ax88180_mac_reset ();
- axlocal.FirstTxDesc = TXDP0;
- axlocal.NextTxDesc = TXDP0;
- axlocal.rxbuf_overflow_count = 0;
- }
- }
- if (ISR_Status & ISR_RX) {
- ax88180_rx_handler ();
- }
- /* Read and check interrupt status here...... */
- READ_MACREG (ISR, ISR_Status);
- }
- return 0;
+}
+/* Send a data block via Ethernet. */ +int eth_send (volatile void *packet, int length) +{
- volatile unsigned char *txdata;
- unsigned long TXDES_addr;
- unsigned long txcmd_txdp, txbs_txdp;
- unsigned long tmp_data;
- int i;
- if (axlocal.LinkState != INS_LINK_UP) {
- return 0;
- }
- txdata = (volatile unsigned char *)packet;
- axlocal.FirstTxDesc = axlocal.NextTxDesc;
- txbs_txdp = 1 << axlocal.FirstTxDesc;
- READ_MACREG (TXBS, tmp_data);
- READ_MACREG (TXBS, tmp_data);
- PRINTK (TX_MSG, "ax88180: Checking available TXDP (TXBS=0x%08lx)\n",
- tmp_data);
- /* check the available transmit descriptor */
- if (tmp_data & txbs_txdp) {
- /* we should never get here. */
- /* we are running out of resource */
- return 0;
- }
- PRINTK (TX_MSG, "ax88180: TXDP%d is available, i=%d\n",
(int)axlocal.FirstTxDesc, i);
- txcmd_txdp = axlocal.FirstTxDesc << 13;
- TXDES_addr = TXDES0 + (axlocal.FirstTxDesc << 2);
- WRITE_MACREG (TXCMD, txcmd_txdp | length | TX_START_WRITE);
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
- for (i = 0; i < length; i += 2) {
- tmp_data =
(unsigned short)*(txdata + i) +
(unsigned short)(*(txdata + i + 1) << 8);
- WRITE_TXBUF (tmp_data);
- }
+#else
- for (i = 0; i < length; i += 4) {
- tmp_data =
(unsigned long)*(txdata + i) +
(unsigned long)(*(txdata + i + 1) << 8) +
(unsigned long)(*(txdata + i + 2) << 16) +
(unsigned long)(*(txdata + i + 3) << 24);
- WRITE_TXBUF (tmp_data);
- }
+#endif
- WRITE_MACREG (TXCMD, txcmd_txdp | length);
- WRITE_MACREG (TXBS, txbs_txdp);
- WRITE_MACREG (TXDES_addr, TXDPx_ENABLE | length);
- axlocal.NextTxDesc = (axlocal.NextTxDesc + 1) & TXDP_MASK;
- /*
- Check the available transmit descriptor, if we had exhausted all
- transmit descriptor ,then we have to wait for at least one free
- descriptor
- */
- txbs_txdp = 1 << axlocal.NextTxDesc;
- READ_MACREG (TXBS, tmp_data);
- if (tmp_data & txbs_txdp) {
- if (ax88180_poll_tx_complete () < 0) {
- ax88180_mac_reset ();
- axlocal.FirstTxDesc = TXDP0;
- axlocal.NextTxDesc = TXDP0;
- printf ("ax88180: Transmit time out occurred!\n");
- }
- }
- return 0;
+} +#endif /* CONFIG_DRIVER_AX88180 */
diff --git a/drivers/net/ax88180.h b/drivers/net/ax88180.h new file mode 100644 index 0000000..ae4b1b3 --- /dev/null +++ b/drivers/net/ax88180.h @@ -0,0 +1,415 @@ +/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */ +/*
- This program is free software; you can distribute it and/or
modify it
- under the terms of the GNU General Public License (Version 2) as
- published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but
WITHOUT
- ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License
- for more details.
- You should have received a copy of the GNU General Public License
along
- with this program; if not, write to the Free Software Foundation,
Inc.,
- 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
+#include <asm/types.h> +#include <config.h>
+#ifdef CONFIG_DRIVER_AX88180
Unnecessary #ifdef. You should have a #ifdef guard around this file, though, as with all header files.
+#define ENABLE_JUMBO 1 +#define DISABLE_JUMBO 0
+#define ENABLE_BURST 1 +#define DISABLE_BURST 0
+#define NORMAL_RX_MODE 0 +#define RX_LOOPBACK_MODE 1 +#define RX_INIFINIT_LOOP_MODE 2 +#define TX_INIFINIT_LOOP_MODE 3
s/INIFINIT/INFINITE/
+#define DEFAULT_ETH_MTU 1500
+/* Jumbo packet size 4086 bytes included 4 bytes CRC*/ +#define MAX_JUMBO_MTU 4072
+/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */ +#define MAX_TX_JUMBO_SIZE 4086
+/* Max Rx Jumbo size is 15K Bytes */ +#define MAX_RX_SIZE 0x3C00
<snip>
+/* Debug Message Display Level Definition */ +#define TX_MSG 0x0001 +#define RX_MSG 0x0002 +#define INT_MSG 0x0004 +#define DEBUG_MSG 0x0008 +#define NO_MSG 0x0000 +#define DEBUG_FLAGS (NO_MSG)
+#define PRINTK(flag, args...) if (flag & DEBUG_FLAGS) printf (args)
As I mentioned earlier, please get rid of this and use debug() instead.
+/*
- Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer
+*/ +#if defined (CONFIG_DRIVER_AX88180_16BIT) +#define READ_RXBUF(data) \
- do { \
- data = *(volatile unsigned short *) \
- (AX88180_BASE + RXBUFFER_START); \
- } while (0)
This macro is evil. There's no reason why you need to pass the return varible when the following will do:
#define Read_Rx_buf(addr) *(volatile unsigned short *)(AX88180_base + (addr))
val = Read_Rx_buf(RXBUFFER_START);
Also, please don't use ALL_CAPS names.
+#define WRITE_TXBUF(data) \
- do { \
- *(volatile unsigned short *)(AX88180_BASE + TXBUFFER_START) \
- = data; \
- } while (0)
In this case, the do{...}while(0) is unnecessary. Just make the assignment.
+#define READ_MACREG(regaddr, regdata) \
- do { \
- regdata = *(volatile unsigned short *) \
- (AX88180_BASE + regaddr); \
- } while (0)
Here, regdata shouldn't be in the macro. I think you get the idea...
+#define WRITE_MACREG(regaddr, regdata) \
- do { \
- *(volatile unsigned short*)(AX88180_BASE + regaddr) \
- = regdata; \
- } while (0)
+#else +#define READ_RXBUF(data) \
- do { \
- data = *(volatile unsigned long *) \
- (AX88180_BASE + RXBUFFER_START); \
- } while (0)
I know you wrote your macros this way because you want to support different bus widths, but there are cleaner ways of doing it.
+#define WRITE_TXBUF(data) \
- do { \
- *(volatile unsigned long *)(AX88180_BASE + TXBUFFER_START) \
- = data; \
- } while (0)
+#define READ_MACREG(regaddr, regdata) \
- do { \
- regdata = *(volatile unsigned long*)(AX88180_BASE + regaddr); \
- } while (0)
+#define WRITE_MACREG(regaddr, regdata) \
- do { \
- *(volatile unsigned long*)(AX88180_BASE + regaddr) \
- = regdata; \
- } while (0)
+#endif /* end of CONFIG_DRIVER_AX88180_16BIT */
+#endif /*end of CONFIG_DRIVER_AX88180 */
Please clean up the issues and re-submit.
regards, Ben

On Wed, Jul 2, 2008 at 12:07 AM, Ben Warren bwarren@qstreams.com wrote: <snip>
+#define WRITE_TXBUF(data) \
- do { \
- *(volatile unsigned short *)(AX88180_BASE + TXBUFFER_START) \
- = data; \
- } while (0)
In this case, the do{...}while(0) is unnecessary. Just make the assignment.
Sorry, I was wrong in this case - do{...}while(0) is correct. Please consider replacing all of these macros with static inline functions though. Much easier for everybody that way.
regards, Ben

Dear Ben,
Thanks for your suggestion; I will correct the driver as soon as possible. And I make a mistake in sending the mail through outlook express, hence making indentation problems.
----- Original Message ----- From: "Ben Warren" biggerbadderben@gmail.com To: "Ben Warren" bwarren@qstreams.com Cc: "Louis" louis@asix.com.tw; u-boot-users@lists.sourceforge.net; "[???]"" donald@asix.com.tw; ""ASIX Donald@sc8-sf-spam2-b.sourceforge.net" =?windows-1252?Q?=22ASIX_Donald?=@sc8-sf-spam2-b.sourceforge.net Sent: Wednesday, July 02, 2008 3:49 PM Subject: Re: [U-Boot-Users] [PATCH][resubmit] AX88180: new gigabit network driver
On Wed, Jul 2, 2008 at 12:07 AM, Ben Warren bwarren@qstreams.com wrote:
<snip>
+#define WRITE_TXBUF(data) \
- do { \
- *(volatile unsigned short *)(AX88180_BASE + TXBUFFER_START) \
- = data; \
- } while (0)
In this case, the do{...}while(0) is unnecessary. Just make the assignment.
Sorry, I was wrong in this case - do{...}while(0) is correct. Please consider replacing all of these macros with static inline functions though. Much easier for everybody that way.
regards, Ben

Louis wrote:
Dear Ben,
Thanks for your suggestion; I will correct the driver as soon as possible. And I make a mistake in sending the mail through outlook express, hence making indentation problems.
Great! Thanks Louis. For sending patches, I highly recommend using git-send-email instead of your mail client. While it's possible to get most clients to send properly formatted patches, it often takes a lot of trial and error, while git-send-email always works (AFAIK). Also, please consider running 'Lindent -pcs' on the code before sending. This page is very useful:
http://www.denx.de/wiki/UBoot/CodingStyle
regards, Ben

Dear Ben,
Please review the resubmitted patch; This patch fix up following issues:
1. coding style 2. eliminate macros 3. use debug instead of PRINTK
Thanks, Louis

Signed-off-by: Louis Su louis@asix.com.tw --- drivers/net/Makefile | 1 + drivers/net/ax88180.c | 727 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ax88180.h | 412 ++++++++++++++++++++++++++++ 3 files changed, 1140 insertions(+), 0 deletions(-) create mode 100644 drivers/net/ax88180.c create mode 100644 drivers/net/ax88180.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 84be288..3a574e0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnet.a
COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o +COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c new file mode 100644 index 0000000..1457355 --- /dev/null +++ b/drivers/net/ax88180.c @@ -0,0 +1,727 @@ +/* + * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver + * + * This program is free software; you can distribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + * USA. + */ + +/* + * ======================================================================== + * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver + * + * The AX88180 Ethernet controller is a high performance and highly + * integrated local CPU bus Ethernet controller with embedded 40K bytes + * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any + * embedded systems. + * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet + * controller that supports both MII and RGMII interfaces and is + * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards. + * + * Please visit ASIX's web site (http://www.asix.com.tw) for more + * details. + * + * Module Name : ax88180.c + * Date : 2008-07-07 + * History + * 09/06/2006 : New release for AX88180 US2 chip. + * 07/07/2008 : Fix up the coding style and using inline functions + * instead of macros + * ======================================================================== + */ +#include <common.h> +#include <command.h> +#include <net.h> +#include <malloc.h> +#include "ax88180.h" + +/* + * =========================================================================== + * Local SubProgram Declaration + * =========================================================================== + */ +static void ax88180_rx_handler (struct eth_device *dev); +static int ax88180_phy_initial (struct eth_device *dev); +static void ax88180_meidia_config (struct eth_device *dev); +static unsigned long get_CicadaPHY_meida_mode (struct eth_device *dev); +static unsigned long get_MarvellPHY_meida_mode (struct eth_device *dev); +static unsigned short ax88180_mdio_read (struct eth_device *dev, + unsigned long regaddr); +static void ax88180_mdio_write (struct eth_device *dev, + unsigned long regaddr, unsigned short regdata); + +/* + * =========================================================================== + * Local SubProgram Bodies + * =========================================================================== + */ +static int ax88180_mdio_check_complete (struct eth_device *dev) +{ + int us_cnt = 10000; + unsigned short tmpval; + + /* MDIO read/write should not take more than 10 ms */ + while (--us_cnt) { + tmpval = INW (dev, MDIOCTRL); + if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0)) + break; + } + + return us_cnt; +} + +static unsigned short +ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long tmpval = 0; + + OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL); + + if (ax88180_mdio_check_complete (dev)) + tmpval = INW (dev, MDIODP); + else + printf ("Failed to read PHY register!\n"); + + return (unsigned short)(tmpval & 0xFFFF); +} + +static void +ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr, + unsigned short regdata) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + + OUTW (dev, regdata, MDIODP); + + OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL); + + if (!ax88180_mdio_check_complete (dev)) + printf ("Failed to write PHY register!\n"); +} + +static int ax88180_phy_reset (struct eth_device *dev) +{ + unsigned short delay_cnt = 500; + + ax88180_mdio_write (dev, BMCR, (PHY_RESET | AUTONEG_EN)); + + /* Wait for the reset to complete, or time out (500 ms) */ + while (ax88180_mdio_read (dev, BMCR) & PHY_RESET) { + udelay (1000); + if (--delay_cnt == 0) { + printf ("Failed to reset PHY!\n"); + return -1; + } + } + + return 0; +} + +static void ax88180_mac_reset (struct eth_device *dev) +{ + unsigned long tmpval; + unsigned char i; + + struct { + unsigned short offset, value; + } program_seq[] = { + { + MISC, MISC_NORMAL}, { + RXINDICATOR, DEFAULT_RXINDICATOR}, { + TXCMD, DEFAULT_TXCMD}, { + TXBS, DEFAULT_TXBS}, { + TXDES0, DEFAULT_TXDES0}, { + TXDES1, DEFAULT_TXDES1}, { + TXDES2, DEFAULT_TXDES2}, { + TXDES3, DEFAULT_TXDES3}, { + TXCFG, DEFAULT_TXCFG}, { + MACCFG2, DEFAULT_MACCFG2}, { + MACCFG3, DEFAULT_MACCFG3}, { + TXLEN, DEFAULT_TXLEN}, { + RXBTHD0, DEFAULT_RXBTHD0}, { + RXBTHD1, DEFAULT_RXBTHD1}, { + RXFULTHD, DEFAULT_RXFULTHD}, { + DOGTHD0, DEFAULT_DOGTHD0}, { + DOGTHD1, DEFAULT_DOGTHD1},}; + + OUTW (dev, MISC_RESET_MAC, MISC); + tmpval = INW (dev, MISC); + + for (i = 0; i < (sizeof (program_seq) / sizeof (program_seq[0])); i++) + OUTW (dev, program_seq[i].value, program_seq[i].offset); +} + +static int ax88180_poll_tx_complete (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long tmpval, txbs_txdp; + int TimeOutCnt = 10000; + + txbs_txdp = 1 << priv->NextTxDesc; + + while (TimeOutCnt--) { + + tmpval = INW (dev, TXBS); + + if ((tmpval & txbs_txdp) == 0) + break; + + udelay (100); + } + + if (TimeOutCnt) + return 0; + else + return -TimeOutCnt; +} + +static void ax88180_rx_handler (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long data_size; + unsigned short rxcurt_ptr, rxbound_ptr, next_ptr; + int i; +#if defined (CONFIG_DRIVER_AX88180_16BIT) + unsigned short *rxdata = (unsigned short *)NetRxPackets[0]; +#else + unsigned long *rxdata = (unsigned long *)NetRxPackets[0]; +#endif + unsigned short count; + + rxcurt_ptr = INW (dev, RXCURT); + rxbound_ptr = INW (dev, RXBOUND); + next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK; + + debug ("ax88180: RX original RXBOUND=0x%04x," + " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr); + + while (next_ptr != rxcurt_ptr) { + + OUTW (dev, RX_START_READ, RXINDICATOR); + + data_size = READ_RXBUF (dev) & 0xFFFF; + + if ((data_size == 0) || (data_size > MAX_RX_SIZE)) { + + OUTW (dev, RX_STOP_READ, RXINDICATOR); + + ax88180_mac_reset (dev); + printf ("ax88180: Invalid Rx packet length!" + " (len=0x%04lx)\n", data_size); + + debug ("ax88180: RX RXBOUND=0x%04x," + "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr); + return; + } + + rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1; + rxbound_ptr &= RX_PAGE_NUM_MASK; + + /* Comput access times */ + count = (data_size + priv->PadSize) >> priv->BusWidth; + + for (i = 0; i < count; i++) { + *(rxdata + i) = READ_RXBUF (dev); + } + + OUTW (dev, RX_STOP_READ, RXINDICATOR); + + /* Pass the packet up to the protocol layers. */ + NetReceive (NetRxPackets[0], data_size); + + OUTW (dev, rxbound_ptr, RXBOUND); + + rxcurt_ptr = INW (dev, RXCURT); + rxbound_ptr = INW (dev, RXBOUND); + next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK; + + debug ("ax88180: RX updated RXBOUND=0x%04x," + "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr); + } + + return; +} + +static int ax88180_phy_initial (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long tmp_regval; + + /* Check avaliable PHY chipset */ + priv->PhyAddr = MARVELL_88E1111_PHYADDR; + priv->PhyID0 = ax88180_mdio_read (dev, PHYIDR0); + + if (priv->PhyID0 == MARVELL_88E1111_PHYIDR0) { + + debug ("ax88180: Found Marvell 88E1111 PHY." + " (PHY Addr=0x%x)\n", priv->PhyAddr); + + tmp_regval = ax88180_mdio_read (dev, M88_EXT_SSR); + if ((tmp_regval & HWCFG_MODE_MASK) == RGMII_COPPER_MODE) { + + ax88180_mdio_write (dev, M88_EXT_SCR, DEFAULT_EXT_SCR); + if (ax88180_phy_reset (dev) < 0) + return 0; + ax88180_mdio_write (dev, M88_IER, LINK_CHANGE_INT); + } + } else { + + priv->PhyAddr = CICADA_CIS8201_PHYADDR; + priv->PhyID0 = ax88180_mdio_read (dev, PHYIDR0); + + if (priv->PhyID0 == CICADA_CIS8201_PHYIDR0) { + + debug ("ax88180: Found CICADA CIS8201 PHY" + " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr); + ax88180_mdio_write (dev, CIS_IMR, + (CIS_INT_ENABLE | LINK_CHANGE_INT)); + + /* Set CIS_SMI_PRIORITY bit before force the media mode */ + tmp_regval = + ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS); + tmp_regval &= ~CIS_SMI_PRIORITY; + ax88180_mdio_write (dev, CIS_AUX_CTRL_STATUS, + tmp_regval); + } else { + printf ("ax88180: Unknown PHY chipset!!\n"); + return 0; + } + } + + return 1; +} + +static void ax88180_meidia_config (struct eth_device *dev) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned long bmcr_val, bmsr_val; + unsigned long rxcfg_val, maccfg0_val, maccfg1_val; + unsigned long RealMediaMode; + int i; + + /* Waiting 2 seconds for PHY link stable */ + for (i = 0; i < 20000; i++) { + bmsr_val = ax88180_mdio_read (dev, BMSR); + if (bmsr_val & LINKOK) { + break; + } + udelay (100); + } + + bmsr_val = ax88180_mdio_read (dev, BMSR); + debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val); + + if (bmsr_val & LINKOK) { + bmcr_val = ax88180_mdio_read (dev, BMCR); + + if (bmcr_val & AUTONEG_EN) { + + /* + * Waiting for Auto-negotiation completion, this may + * take up to 5 seconds. + */ + debug ("ax88180: Auto-negotiation is " + "enabled. Waiting for NWay completion..\n"); + for (i = 0; i < 50000; i++) { + bmsr_val = ax88180_mdio_read (dev, BMSR); + if (bmsr_val & AUTONEG_COMPLETE) { + break; + } + udelay (100); + } + } else + debug ("ax88180: Auto-negotiation is disabled.\n"); + + debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n", + (unsigned int)bmcr_val, (unsigned int)bmsr_val); + + /* Get real media mode here */ + if (priv->PhyID0 == MARVELL_88E1111_PHYIDR0) { + RealMediaMode = get_MarvellPHY_meida_mode (dev); + } else if (priv->PhyID0 == CICADA_CIS8201_PHYIDR0) { + RealMediaMode = get_CicadaPHY_meida_mode (dev); + } else { + RealMediaMode = MEDIA_1000FULL; + } + + priv->LinkState = INS_LINK_UP; + + switch (RealMediaMode) { + case MEDIA_1000FULL: + debug ("ax88180: 1000Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; + maccfg1_val = GIGA_MODE_EN | RXFLOW_EN | + FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_1000HALF: + debug ("ax88180: 1000Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1; + break; + + case MEDIA_100FULL: + debug ("ax88180: 100Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = SPEED100 | TXFLOW_ENABLE + | DEFAULT_MACCFG0; + maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_100HALF: + debug ("ax88180: 100Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = SPEED100 | DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + break; + + case MEDIA_10FULL: + debug ("ax88180: 10Mbps Full-duplex mode.\n"); + rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; + maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; + maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1; + break; + + case MEDIA_10HALF: + debug ("ax88180: 10Mbps Half-duplex mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + break; + default: + debug ("ax88180: Unknow media mode.\n"); + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + + priv->LinkState = INS_LINK_DOWN; + break; + } + + } else { + rxcfg_val = DEFAULT_RXCFG; + maccfg0_val = DEFAULT_MACCFG0; + maccfg1_val = DEFAULT_MACCFG1; + + priv->LinkState = INS_LINK_DOWN; + } + + OUTW (dev, rxcfg_val, RXCFG); + OUTW (dev, maccfg0_val, MACCFG0); + OUTW (dev, maccfg1_val, MACCFG1); + + return; +} + +static unsigned long get_MarvellPHY_meida_mode (struct eth_device *dev) +{ + unsigned long m88_ssr; + unsigned long MediaMode; + + m88_ssr = ax88180_mdio_read (dev, M88_SSR); + switch (m88_ssr & SSR_MEDIA_MASK) { + case SSR_1000FULL: + MediaMode = MEDIA_1000FULL; + break; + case SSR_1000HALF: + MediaMode = MEDIA_1000HALF; + break; + case SSR_100FULL: + MediaMode = MEDIA_100FULL; + break; + case SSR_100HALF: + MediaMode = MEDIA_100HALF; + break; + case SSR_10FULL: + MediaMode = MEDIA_10FULL; + break; + case SSR_10HALF: + MediaMode = MEDIA_10HALF; + break; + default: + MediaMode = MEDIA_UNKNOWN; + break; + } + + return MediaMode; +} + +static unsigned long get_CicadaPHY_meida_mode (struct eth_device *dev) +{ + unsigned long tmp_regval; + unsigned long MediaMode; + + tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS); + switch (tmp_regval & CIS_MEDIA_MASK) { + case CIS_1000FULL: + MediaMode = MEDIA_1000FULL; + break; + case CIS_1000HALF: + MediaMode = MEDIA_1000HALF; + break; + case CIS_100FULL: + MediaMode = MEDIA_100FULL; + break; + case CIS_100HALF: + MediaMode = MEDIA_100HALF; + break; + case CIS_10FULL: + MediaMode = MEDIA_10FULL; + break; + case CIS_10HALF: + MediaMode = MEDIA_10HALF; + break; + default: + MediaMode = MEDIA_UNKNOWN; + break; + } + + return MediaMode; +} + +static void ax88180_halt (struct eth_device *dev) +{ + /* Disable AX88180 TX/RX functions */ + OUTW (dev, WAKEMOD, CMD); +} + +static int ax88180_init (struct eth_device *dev, bd_t * bd) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned short tmp_regval; + + ax88180_mac_reset (dev); + + /* Disable interrupt */ + OUTW (dev, CLEAR_IMR, IMR); + + /* Disable AX88180 TX/RX functions */ + OUTW (dev, WAKEMOD, CMD); + + /* Fill the MAC address */ + tmp_regval = + dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8); + OUTW (dev, tmp_regval, MACID0); + + tmp_regval = + dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8); + OUTW (dev, tmp_regval, MACID1); + + tmp_regval = + dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8); + OUTW (dev, tmp_regval, MACID2); + + ax88180_meidia_config (dev); + + OUTW (dev, DEFAULT_RXFILTER, RXFILTER); + + /* Initial variables here */ + priv->FirstTxDesc = TXDP0; + priv->NextTxDesc = TXDP0; + + /* Check if there is any invalid interrupt status and clear it. */ + OUTW (dev, INW (dev, ISR), ISR); + + /* Start AX88180 TX/RX functions */ + OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD); + + return 0; +} + +/* Get a data block via Ethernet */ +static int ax88180_recv (struct eth_device *dev) +{ + unsigned short ISR_Status; + unsigned short tmp_regval; + + /* Read and check interrupt status here. */ + ISR_Status = INW (dev, ISR); + + while (ISR_Status) { + /* Clear the interrupt status */ + OUTW (dev, ISR_Status, ISR); + + debug ("\nax88180: The interrupt status = 0x%04x\n", + ISR_Status); + + if (ISR_Status & ISR_PHY) { + /* Read ISR register once to clear PHY interrupt bit */ + tmp_regval = ax88180_mdio_read (dev, M88_ISR); + ax88180_meidia_config (dev); + } + + if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) { + ax88180_rx_handler (dev); + } + + /* Read and check interrupt status again */ + ISR_Status = INW (dev, ISR); + } + + return 0; +} + +/* Send a data block via Ethernet. */ +static int +ax88180_send (struct eth_device *dev, volatile void *packet, int length) +{ + struct ax88180_private *priv = (struct ax88180_private *)dev->priv; + unsigned short TXDES_addr; + unsigned short txcmd_txdp, txbs_txdp; + unsigned short tmp_data; + int i; +#if defined (CONFIG_DRIVER_AX88180_16BIT) + volatile unsigned short *txdata = (volatile unsigned short *)packet; +#else + volatile unsigned long *txdata = (volatile unsigned long *)packet; +#endif + unsigned short count; + + if (priv->LinkState != INS_LINK_UP) { + return 0; + } + + priv->FirstTxDesc = priv->NextTxDesc; + txbs_txdp = 1 << priv->FirstTxDesc; + + debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc); + + txcmd_txdp = priv->FirstTxDesc << 13; + TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2); + + OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD); + + /* Comput access times */ + count = (length + priv->PadSize) >> priv->BusWidth; + + for (i = 0; i < count; i++) { + WRITE_TXBUF (dev, *(txdata + i)); + } + + OUTW (dev, txcmd_txdp | length, TXCMD); + OUTW (dev, txbs_txdp, TXBS); + OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr); + + priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK; + + /* + * Check the available transmit descriptor, if we had exhausted all + * transmit descriptor ,then we have to wait for at least one free + * descriptor + */ + txbs_txdp = 1 << priv->NextTxDesc; + tmp_data = INW (dev, TXBS); + + if (tmp_data & txbs_txdp) { + if (ax88180_poll_tx_complete (dev) < 0) { + ax88180_mac_reset (dev); + priv->FirstTxDesc = TXDP0; + priv->NextTxDesc = TXDP0; + printf ("ax88180: Transmit time out occurred!\n"); + } + } + + return 0; +} + +static void ax88180_read_mac_addr (struct eth_device *dev) +{ + unsigned short macid0_val, macid1_val, macid2_val; + unsigned short tmp_regval; + unsigned short i; + + /* Reload MAC address from EEPROM */ + OUTW (dev, RELOAD_EEPROM, PROMCTRL); + + /* Waiting for reload eeprom completion */ + for (i = 0; i < 500; i++) { + tmp_regval = INW (dev, PROMCTRL); + if ((tmp_regval & RELOAD_EEPROM) == 0) + break; + udelay (1000); + } + + /* Get MAC addresses */ + macid0_val = INW (dev, MACID0); + macid1_val = INW (dev, MACID1); + macid2_val = INW (dev, MACID2); + + if (((macid0_val | macid1_val | macid2_val) != 0) && + ((macid0_val & 0x01) == 0)) { + dev->enetaddr[0] = (unsigned char)macid0_val; + dev->enetaddr[1] = (unsigned char)(macid0_val >> 8); + dev->enetaddr[2] = (unsigned char)macid1_val; + dev->enetaddr[3] = (unsigned char)(macid1_val >> 8); + dev->enetaddr[4] = (unsigned char)macid2_val; + dev->enetaddr[5] = (unsigned char)(macid2_val >> 8); + } +} + +/* +=========================================================================== +<<<<<< Exported SubProgram Bodies >>>>>> +=========================================================================== +*/ +int ax88180_initialize (bd_t * bis) +{ + struct eth_device *dev; + struct ax88180_private *priv; + + dev = (struct eth_device *)malloc (sizeof *dev); + + if (NULL == dev) + return 0; + + memset (dev, 0, sizeof *dev); + + priv = (struct ax88180_private *)malloc (sizeof (*priv)); + + if (NULL == priv) + return 0; + + memset (priv, 0, sizeof *priv); + + sprintf (dev->name, "ax88180"); + dev->iobase = AX88180_BASE; + dev->priv = priv; + dev->init = ax88180_init; + dev->halt = ax88180_halt; + dev->send = ax88180_send; + dev->recv = ax88180_recv; + + priv->BusWidth = BUS_WIDTH_32; + priv->PadSize = 3; +#if defined (CONFIG_DRIVER_AX88180_16BIT) + OUTW (dev, (START_BASE >> 8), BASE); + OUTW (dev, DECODE_EN, DECODE); + + priv->BusWidth = BUS_WIDTH_16; + priv->PadSize = 1; +#endif + + ax88180_mac_reset (dev); + + /* Disable interrupt */ + OUTW (dev, CLEAR_IMR, IMR); + + /* Disable AX88180 TX/RX functions */ + OUTW (dev, WAKEMOD, CMD); + + ax88180_read_mac_addr (dev); + + eth_register (dev); + + return ax88180_phy_initial (dev); + +} diff --git a/drivers/net/ax88180.h b/drivers/net/ax88180.h new file mode 100644 index 0000000..5254e7d --- /dev/null +++ b/drivers/net/ax88180.h @@ -0,0 +1,412 @@ +/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */ +/* + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + */ + +#ifndef _AX88180_H_ +#define _AX88180_H_ + +#include <asm/types.h> +#include <config.h> + +typedef enum _ax88180_link_state { + INS_LINK_DOWN, + INS_LINK_UP, + INS_LINK_UNKNOWN +} ax88180_link_state; + +struct ax88180_private { + unsigned char BusWidth; + unsigned char PadSize; + unsigned short PhyAddr; + unsigned short PhyID0; + unsigned short FirstTxDesc; + unsigned short NextTxDesc; + ax88180_link_state LinkState; +}; + +#define BUS_WIDTH_16 1 +#define BUS_WIDTH_32 2 + +#define ENABLE_JUMBO 1 +#define DISABLE_JUMBO 0 + +#define ENABLE_BURST 1 +#define DISABLE_BURST 0 + +#define NORMAL_RX_MODE 0 +#define RX_LOOPBACK_MODE 1 +#define RX_INIFINIT_LOOP_MODE 2 +#define TX_INIFINIT_LOOP_MODE 3 + +#define DEFAULT_ETH_MTU 1500 + +/* Jumbo packet size 4086 bytes included 4 bytes CRC*/ +#define MAX_JUMBO_MTU 4072 + +/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */ +#define MAX_TX_JUMBO_SIZE 4086 + +/* Max Rx Jumbo size is 15K Bytes */ +#define MAX_RX_SIZE 0x3C00 + +#define MARVELL_88E1111_PHYADDR 0x18 +#define MARVELL_88E1111_PHYIDR0 0x0141 + +#define CICADA_CIS8201_PHYADDR 0x01 +#define CICADA_CIS8201_PHYIDR0 0x000F + +#define MEDIA_AUTO 0 +#define MEDIA_1000FULL 1 +#define MEDIA_1000HALF 2 +#define MEDIA_100FULL 3 +#define MEDIA_100HALF 4 +#define MEDIA_10FULL 5 +#define MEDIA_10HALF 6 +#define MEDIA_UNKNOWN 7 + +#define AUTO_MEDIA 0 +#define FORCE_MEDIA 1 + +#define TXDP_MASK 3 +#define TXDP0 0 +#define TXDP1 1 +#define TXDP2 2 +#define TXDP3 3 + +#define CMD_MAP_SIZE 0x100 + +#if defined (CONFIG_DRIVER_AX88180_16BIT) + #define AX88180_MEMORY_SIZE 0x00004000 + #define START_BASE 0x1000 + + #define RX_BUF_SIZE 0x1000 + #define TX_BUF_SIZE 0x0F00 + + #define TX_BASE START_BASE + #define CMD_BASE (TX_BASE + TX_BUF_SIZE) + #define RX_BASE (CMD_BASE + CMD_MAP_SIZE) +#else + #define AX88180_MEMORY_SIZE 0x00010000 + + #define RX_BUF_SIZE 0x8000 + #define TX_BUF_SIZE 0x7C00 + + #define RX_BASE 0x0000 + #define TX_BASE (RX_BASE + RX_BUF_SIZE) + #define CMD_BASE (TX_BASE + TX_BUF_SIZE) +#endif + +/* AX88180 Memory Mapping Definition */ +#define RXBUFFER_START RX_BASE + #define RX_PACKET_LEN_OFFSET 0 + #define RX_PAGE_NUM_MASK 0x7FF /* RX pages 0~7FFh */ +#define TXBUFFER_START TX_BASE + +/* AX88180 MAC Register Definition */ +#define DECODE (0) + #define DECODE_EN 0x00000001 +#define BASE (6) +#define CMD (CMD_BASE + 0x0000) + #define WAKEMOD 0x00000001 + #define TXEN 0x00000100 + #define RXEN 0x00000200 + #define DEFAULT_CMD WAKEMOD +#define IMR (CMD_BASE + 0x0004) + #define IMR_RXBUFFOVR 0x00000001 + #define IMR_WATCHDOG 0x00000002 + #define IMR_TX 0x00000008 + #define IMR_RX 0x00000010 + #define IMR_PHY 0x00000020 + #define CLEAR_IMR 0x00000000 + #define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\ + IMR_RXBUFFOVR | IMR_WATCHDOG) +#define ISR (CMD_BASE + 0x0008) + #define ISR_RXBUFFOVR 0x00000001 + #define ISR_WATCHDOG 0x00000002 + #define ISR_TX 0x00000008 + #define ISR_RX 0x00000010 + #define ISR_PHY 0x00000020 +#define TXCFG (CMD_BASE + 0x0010) + #define AUTOPAD_CRC 0x00000050 + #define DEFAULT_TXCFG AUTOPAD_CRC +#define TXCMD (CMD_BASE + 0x0014) + #define TXCMD_TXDP_MASK 0x00006000 + #define TXCMD_TXDP0 0x00000000 + #define TXCMD_TXDP1 0x00002000 + #define TXCMD_TXDP2 0x00004000 + #define TXCMD_TXDP3 0x00006000 + #define TX_START_WRITE 0x00008000 + #define TX_STOP_WRITE 0x00000000 + #define DEFAULT_TXCMD 0x00000000 +#define TXBS (CMD_BASE + 0x0018) + #define TXDP0_USED 0x00000001 + #define TXDP1_USED 0x00000002 + #define TXDP2_USED 0x00000004 + #define TXDP3_USED 0x00000008 + #define DEFAULT_TXBS 0x00000000 +#define TXDES0 (CMD_BASE + 0x0020) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES0 0x00000000 +#define TXDES1 (CMD_BASE + 0x0024) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES1 0x00000000 +#define TXDES2 (CMD_BASE + 0x0028) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES2 0x00000000 +#define TXDES3 (CMD_BASE + 0x002C) + #define TXDPx_ENABLE 0x00008000 + #define TXDPx_LEN_MASK 0x00001FFF + #define DEFAULT_TXDES3 0x00000000 +#define RXCFG (CMD_BASE + 0x0030) + #define RXBUFF_PROTECT 0x00000001 + #define RXTCPCRC_CHECK 0x00000010 + #define RXFLOW_ENABLE 0x00000100 + #define DEFAULT_RXCFG RXBUFF_PROTECT +#define RXCURT (CMD_BASE + 0x0034) + #define DEFAULT_RXCURT 0x00000000 +#define RXBOUND (CMD_BASE + 0x0038) + #define DEFAULT_RXBOUND 0x7FF //RX pages 0~7FFh +#define MACCFG0 (CMD_BASE + 0x0040) + #define MACCFG0_BIT3_0 0x00000007 + #define IPGT_VAL 0x00000150 + #define TXFLOW_ENABLE 0x00001000 + #define SPEED100 0x00008000 + #define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0) +#define MACCFG1 (CMD_BASE + 0x0044) + #define RGMII_EN 0x00000002 + #define RXFLOW_EN 0x00000020 + #define FULLDUPLEX 0x00000040 + #define MAX_JUMBO_LEN 0x00000780 + #define RXJUMBO_EN 0x00000800 + #define GIGA_MODE_EN 0x00001000 + #define RXCRC_CHECK 0x00002000 + #define RXPAUSE_DA_CHECK 0x00004000 + + #define JUMBO_LEN_4K 0x00000200 + #define JUMBO_LEN_15K 0x00000780 + #define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK | \ + RGMII_EN) + #define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK) +#define MACCFG2 (CMD_BASE + 0x0048) + #define MACCFG2_BIT15_8 0x00000100 + #define JAM_LIMIT_MASK 0x000000FC + #define DEFAULT_JAM_LIMIT 0x00000064 + #define DEFAULT_MACCFG2 MACCFG2_BIT15_8 +#define MACCFG3 (CMD_BASE + 0x004C) + #define IPGR2_VAL 0x0000000E + #define IPGR1_VAL 0x00000600 + #define NOABORT 0x00008000 + #define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL) +#define TXPAUT (CMD_BASE + 0x0054) + #define DEFAULT_TXPAUT 0x001FE000 +#define RXBTHD0 (CMD_BASE + 0x0058) + #define DEFAULT_RXBTHD0 0x00000300 +#define RXBTHD1 (CMD_BASE + 0x005C) + #define DEFAULT_RXBTHD1 0x00000600 +#define RXFULTHD (CMD_BASE + 0x0060) + #define DEFAULT_RXFULTHD 0x00000100 +#define MISC (CMD_BASE + 0x0068) + /* Normal operation mode */ + #define MISC_NORMAL 0x00000003 + /* Clear bit 0 to reset MAC */ + #define MISC_RESET_MAC 0x00000002 + /* Clear bit 1 to reset PHY */ + #define MISC_RESET_PHY 0x00000001 + /* Clear bit 0 and 1 to reset MAC and PHY */ + #define MISC_RESET_MAC_PHY 0x00000000 + #define DEFAULT_MISC MISC_NORMAL +#define MACID0 (CMD_BASE + 0x0070) +#define MACID1 (CMD_BASE + 0x0074) +#define MACID2 (CMD_BASE + 0x0078) +#define TXLEN (CMD_BASE + 0x007C) + #define DEFAULT_TXLEN 0x000005FC +#define RXFILTER (CMD_BASE + 0x0080) + #define RX_RXANY 0x00000001 + #define RX_MULTICAST 0x00000002 + #define RX_UNICAST 0x00000004 + #define RX_BROADCAST 0x00000008 + #define RX_MULTI_HASH 0x00000010 + #define DISABLE_RXFILTER 0x00000000 + #define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST) +#define MDIOCTRL (CMD_BASE + 0x0084) + #define PHY_ADDR_MASK 0x0000001F + #define REG_ADDR_MASK 0x00001F00 + #define READ_PHY 0x00004000 + #define WRITE_PHY 0x00008000 +#define MDIODP (CMD_BASE + 0x0088) +#define GPIOCTRL (CMD_BASE + 0x008C) +#define RXINDICATOR (CMD_BASE + 0x0090) + #define RX_START_READ 0x00000001 + #define RX_STOP_READ 0x00000000 + #define DEFAULT_RXINDICATOR RX_STOP_READ +#define TXST (CMD_BASE + 0x0094) +#define MDCCLKPAT (CMD_BASE + 0x00A0) +#define RXIPCRCCNT (CMD_BASE + 0x00A4) +#define RXCRCCNT (CMD_BASE + 0x00A8) +#define TXFAILCNT (CMD_BASE + 0x00AC) +#define PROMDP (CMD_BASE + 0x00B0) +#define PROMCTRL (CMD_BASE + 0x00B4) + #define RELOAD_EEPROM 0x00000200 +#define MAXRXLEN (CMD_BASE + 0x00B8) +#define HASHTAB0 (CMD_BASE + 0x00C0) +#define HASHTAB1 (CMD_BASE + 0x00C4) +#define HASHTAB2 (CMD_BASE + 0x00C8) +#define HASHTAB3 (CMD_BASE + 0x00CC) +#define DOGTHD0 (CMD_BASE + 0x00E0) + #define DEFAULT_DOGTHD0 0x0000FFFF +#define DOGTHD1 (CMD_BASE + 0x00E4) + #define START_WATCHDOG_TIMER 0x00008000 + #define DEFAULT_DOGTHD1 0x00000FFF +#define SOFTRST (CMD_BASE + 0x00EC) + #define SOFTRST_NORMAL 0x00000003 + #define SOFTRST_RESET_MAC 0x00000002 + +/* External PHY Register Definition */ +#define BMCR 0x0000 + #define LINE_SPEED_MSB 0x0040 + #define DUPLEX_MODE 0x0100 + #define RESTART_AUTONEG 0x0200 + #define POWER_DOWN 0x0800 + #define AUTONEG_EN 0x1000 + #define LINE_SPEED_LSB 0x2000 + #define PHY_RESET 0x8000 + + #define MEDIAMODE_MASK (LINE_SPEED_MSB | LINE_SPEED_LSB |\ + DUPLEX_MODE) + #define BMCR_SPEED_1000 LINE_SPEED_MSB + #define BMCR_SPEED_100 LINE_SPEED_LSB + #define BMCR_SPEED_10 0x0000 + + #define BMCR_1000FULL (BMCR_SPEED_1000 | DUPLEX_MODE) + #define BMCR_100FULL (BMCR_SPEED_100 | DUPLEX_MODE) + #define BMCR_100HALF BMCR_SPEED_100 + #define BMCR_10FULL DUPLEX_MODE + #define BMCR_10HALF 0x0000 +#define BMSR 0x0001 + #define LINKOK 0x0004 + #define AUTONEG_ENABLE_STS 0x0008 + #define AUTONEG_COMPLETE 0x0020 +#define PHYIDR0 0x0002 +#define PHYIDR1 0x0003 +#define ANAR 0x0004 + #define ANAR_PAUSE 0x0400 + #define ANAR_100FULL 0x0100 + #define ANAR_100HALF 0x0080 + #define ANAR_10FULL 0x0040 + #define ANAR_10HALF 0x0020 + #define ANAR_8023BIT 0x0001 +#define ANLPAR 0x0005 +#define ANER 0x0006 +#define AUX_1000_CTRL 0x0009 + #define ENABLE_1000HALF 0x0100 + #define ENABLE_1000FULL 0x0200 + #define DEFAULT_AUX_1000_CTRL (ENABLE_1000HALF | ENABLE_1000FULL) +#define AUX_1000_STATUS 0x000A + #define LP_1000HALF 0x0400 + #define LP_1000FULL 0x0800 + +/* Marvell 88E1111 Gigabit PHY Register Definition */ +#define M88_SSR 0x0011 + #define SSR_SPEED_MASK 0xC000 + #define SSR_SPEED_1000 0x8000 + #define SSR_SPEED_100 0x4000 + #define SSR_SPEED_10 0x0000 + #define SSR_DUPLEX 0x2000 + #define SSR_MEDIA_RESOLVED_OK 0x0800 + + #define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX) + #define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX) + #define SSR_1000HALF SSR_SPEED_1000 + #define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX) + #define SSR_100HALF SSR_SPEED_100 + #define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX) + #define SSR_10HALF SSR_SPEED_10 +#define M88_IER 0x0012 + #define LINK_CHANGE_INT 0x0400 +#define M88_ISR 0x0013 + #define LINK_CHANGE_STATUS 0x0400 +#define M88_EXT_SCR 0x0014 + #define RGMII_RXCLK_DELAY 0x0080 + #define RGMII_TXCLK_DELAY 0x0002 + #define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY) +#define M88_EXT_SSR 0x001B + #define HWCFG_MODE_MASK 0x000F + #define RGMII_COPPER_MODE 0x000B + +/* CICADA CIS8201 Gigabit PHY Register Definition */ +#define CIS_IMR 0x0019 + #define CIS_INT_ENABLE 0x8000 + #define CIS_LINK_CHANGE_INT 0x2000 +#define CIS_ISR 0x001A + #define CIS_INT_PENDING 0x8000 + #define CIS_LINK_CHANGE_STATUS 0x2000 +#define CIS_AUX_CTRL_STATUS 0x001C + #define CIS_AUTONEG_COMPLETE 0x8000 + #define CIS_SPEED_MASK 0x0018 + #define CIS_SPEED_1000 0x0010 + #define CIS_SPEED_100 0x0008 + #define CIS_SPEED_10 0x0000 + #define CIS_DUPLEX 0x0020 + + #define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX) + #define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX) + #define CIS_1000HALF CIS_SPEED_1000 + #define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX) + #define CIS_100HALF CIS_SPEED_100 + #define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX) + #define CIS_10HALF CIS_SPEED_10 + #define CIS_SMI_PRIORITY 0x0004 + +static inline unsigned short INW (struct eth_device *dev, unsigned long addr) +{ + return le16_to_cpu (*(volatile unsigned short *) (addr + dev->iobase)); +} + +static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr) +{ + *(volatile unsigned short *) ((addr + dev->iobase)) = cpu_to_le16 (command); +} + +/* + Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer +*/ +#if defined (CONFIG_DRIVER_AX88180_16BIT) +static inline unsigned short READ_RXBUF (struct eth_device *dev) +{ + return le16_to_cpu (*(volatile unsigned short *) (RXBUFFER_START + dev->iobase)); +} + +static inline void WRITE_TXBUF (struct eth_device *dev, unsigned short data) +{ + *(volatile unsigned short *) ((TXBUFFER_START + dev->iobase)) = cpu_to_le16 (data); +} +#else +static inline unsigned long READ_RXBUF (struct eth_device *dev) +{ + return le32_to_cpu (*(volatile unsigned long *) (RXBUFFER_START + dev->iobase)); +} + +static inline void WRITE_TXBUF (struct eth_device *dev, unsigned long data) +{ + *(volatile unsigned long *) ((TXBUFFER_START + dev->iobase)) = cpu_to_le32 (data); +} +#endif + +#endif /* _AX88180_H_ */

Dear Ben,
In message 1215572497-5985-2-git-send-email-louis@asix.com.tw Louis Su wrote:
Signed-off-by: Louis Su louis@asix.com.tw
drivers/net/Makefile | 1 + drivers/net/ax88180.c | 727 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ax88180.h | 412 ++++++++++++++++++++++++++++ 3 files changed, 1140 insertions(+), 0 deletions(-) create mode 100644 drivers/net/ax88180.c create mode 100644 drivers/net/ax88180.h
I don't see any responses to this latest version of the driver.
Is there any special reason it was neither added nor rejected?
Best regards,
Wolfgang Denk

Hi Wolfgang,
Wolfgang Denk wrote:
Dear Ben,
In message 1215572497-5985-2-git-send-email-louis@asix.com.tw Louis Su wrote:
Signed-off-by: Louis Su louis@asix.com.tw
drivers/net/Makefile | 1 + drivers/net/ax88180.c | 727 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ax88180.h | 412 ++++++++++++++++++++++++++++ 3 files changed, 1140 insertions(+), 0 deletions(-) create mode 100644 drivers/net/ax88180.c create mode 100644 drivers/net/ax88180.h
I don't see any responses to this latest version of the driver.
Is there any special reason it was neither added nor rejected?
Best regards,
Wolfgang Denk
No specific reasons - I should have sent a response. The only issue I have is that there are no in-tree boards that use it. I wonder if we should make up some dummy configs that include devices such as this, so that at least MAKEALL will find problems.
regards, Ben

Dear Ben Warren,
In message 48C1F669.7060708@gmail.com you wrote:
Is there any special reason it was neither added nor rejected?
...
No specific reasons - I should have sent a response. The only issue I have is that there are no in-tree boards that use it. I wonder if we should make up some dummy configs that include devices such as this, so that at least MAKEALL will find problems.
That's a good ideas. Some "make config_all" ;-)
Best regards,
Wolfgang Denk

Dear Ben,
In message 48C1F669.7060708@gmail.com you wrote:
I don't see any responses to this latest version of the driver.
Is there any special reason it was neither added nor rejected?
...
No specific reasons - I should have sent a response. The only issue I have is that there are no in-tree boards that use it. I wonder if we should make up some dummy configs that include devices such as this, so that at least MAKEALL will find problems.
This driver has still not been added. What exactly are we waiting for?
I think we should at least come up with a decision what shall be done about this patch, and informt he submitter.
Thanks.
Best regards,
Wolfgang Denk

Wolfgang Denk wrote:
Dear Ben,
In message 48C1F669.7060708@gmail.com you wrote:
I don't see any responses to this latest version of the driver.
Is there any special reason it was neither added nor rejected?
...
No specific reasons - I should have sent a response. The only issue I have is that there are no in-tree boards that use it. I wonder if we should make up some dummy configs that include devices such as this, so that at least MAKEALL will find problems.
This driver has still not been added. What exactly are we waiting for?
I think we should at least come up with a decision what shall be done about this patch, and informt he submitter.
Huh, I thought there was a strict policy of no drivers without a supporting board, and that this was communicated to Louis. If this isn't that strict a requirement then I have no objections with this patch.
regards, Ben

On Sunday 12 October 2008, Ben Warren wrote:
Wolfgang Denk wrote:
Dear Ben,
In message 48C1F669.7060708@gmail.com you wrote:
I don't see any responses to this latest version of the driver.
Is there any special reason it was neither added nor rejected?
...
No specific reasons - I should have sent a response. The only issue I have is that there are no in-tree boards that use it. I wonder if we should make up some dummy configs that include devices such as this, so that at least MAKEALL will find problems.
This driver has still not been added. What exactly are we waiting for?
I think we should at least come up with a decision what shall be done about this patch, and informt he submitter.
Huh, I thought there was a strict policy of no drivers without a supporting board, and that this was communicated to Louis. If this isn't that strict a requirement then I have no objections with this patch.
the BF537-STAMP can use it (actually, it'll probably work on most Blackfin boards via the addon card). -mike
participants (6)
-
Ben Warren
-
Ben Warren
-
Louis
-
Louis Su
-
Mike Frysinger
-
Wolfgang Denk