diff options
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/Makefile | 5 | ||||
| -rw-r--r-- | drivers/net/bfin_mac.c | 357 | ||||
| -rw-r--r-- | drivers/net/bfin_mac.h | 31 | ||||
| -rw-r--r-- | drivers/net/dnet.c | 395 | ||||
| -rw-r--r-- | drivers/net/dnet.h | 166 | ||||
| -rw-r--r-- | drivers/net/e1000.c | 1 | ||||
| -rw-r--r-- | drivers/net/macb.c | 31 | ||||
| -rw-r--r-- | drivers/net/mcfmii.c | 25 | ||||
| -rw-r--r-- | drivers/net/mpc5xxx_fec.c | 28 | ||||
| -rw-r--r-- | drivers/net/sh_eth.c | 355 | ||||
| -rw-r--r-- | drivers/net/sh_eth.h | 12 | ||||
| -rw-r--r-- | drivers/net/smc911x.c | 79 | ||||
| -rw-r--r-- | drivers/net/tsec.c | 5 |
13 files changed, 1074 insertions, 416 deletions
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 631336ab4..a360a5065 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,12 +26,14 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnet.a COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o +COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.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 COBJS-$(CONFIG_TULIP) += dc2114x.o COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o +COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o @@ -54,11 +56,11 @@ COBJS-$(CONFIG_NS8382X) += ns8382x.o COBJS-$(CONFIG_DRIVER_NS9750_ETHERNET) += ns9750_eth.o COBJS-$(CONFIG_PCNET) += pcnet.o COBJS-$(CONFIG_PLB2800_ETHER) += plb2800_eth.o -COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o COBJS-$(CONFIG_DRIVER_RTL8019) += rtl8019.o COBJS-$(CONFIG_RTL8139) += rtl8139.o COBJS-$(CONFIG_RTL8169) += rtl8169.o COBJS-$(CONFIG_DRIVER_S3C4510_ETH) += s3c4510b_eth.o +COBJS-$(CONFIG_SH_ETHER) += sh_eth.o COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o COBJS-$(CONFIG_DRIVER_SMC911X) += smc911x.o COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o @@ -68,7 +70,6 @@ COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o -COBJS-$(CONFIG_SH_ETHER) += sh_eth.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 504fd100a..23f934aee 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -12,6 +12,8 @@ #include <netdev.h> #include <command.h> #include <malloc.h> +#include <miiphy.h> +#include <linux/mii.h> #include <asm/blackfin.h> #include <asm/mach-common/bits/dma.h> @@ -20,16 +22,15 @@ #include "bfin_mac.h" -#ifdef CONFIG_POST -#include <post.h> +#ifndef CONFIG_PHY_ADDR +# define CONFIG_PHY_ADDR 1 +#endif +#ifndef CONFIG_PHY_CLOCK_FREQ +# define CONFIG_PHY_CLOCK_FREQ 2500000 #endif -#undef DEBUG_ETHERNET - -#ifdef DEBUG_ETHERNET -#define DEBUGF(fmt, args...) printf(fmt, ##args) -#else -#define DEBUGF(fmt, args...) +#ifdef CONFIG_POST +#include <post.h> #endif #define RXBUF_BASE_ADDR 0xFF900000 @@ -38,42 +39,61 @@ #define TOUT_LOOP 1000000 -ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT]; -ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX]; +static ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT]; +static ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX]; static u16 txIdx; /* index of the current RX buffer */ static u16 rxIdx; /* index of the current TX buffer */ -u16 PHYregs[NO_PHY_REGS]; /* u16 PHYADDR; */ - /* DMAx_CONFIG values at DMA Restart */ -const ADI_DMA_CONFIG_REG rxdmacfg = { - .b_DMA_EN = 1, /* enabled */ - .b_WNR = 1, /* write to memory */ - .b_WDSIZE = 2, /* wordsize is 32 bits */ - .b_DMA2D = 0, - .b_RESTART = 0, - .b_DI_SEL = 0, - .b_DI_EN = 0, /* no interrupt */ - .b_NDSIZE = 5, /* 5 half words is desc size */ - .b_FLOW = 7 /* large desc flow */ +static const union { + u16 data; + ADI_DMA_CONFIG_REG reg; +} txdmacfg = { + .reg = { + .b_DMA_EN = 1, /* enabled */ + .b_WNR = 0, /* read from memory */ + .b_WDSIZE = 2, /* wordsize is 32 bits */ + .b_DMA2D = 0, + .b_RESTART = 0, + .b_DI_SEL = 0, + .b_DI_EN = 0, /* no interrupt */ + .b_NDSIZE = 5, /* 5 half words is desc size */ + .b_FLOW = 7 /* large desc flow */ + }, }; -const ADI_DMA_CONFIG_REG txdmacfg = { - .b_DMA_EN = 1, /* enabled */ - .b_WNR = 0, /* read from memory */ - .b_WDSIZE = 2, /* wordsize is 32 bits */ - .b_DMA2D = 0, - .b_RESTART = 0, - .b_DI_SEL = 0, - .b_DI_EN = 0, /* no interrupt */ - .b_NDSIZE = 5, /* 5 half words is desc size */ - .b_FLOW = 7 /* large desc flow */ -}; +static int bfin_miiphy_wait(void) +{ + /* poll the STABUSY bit */ + while (bfin_read_EMAC_STAADD() & STABUSY) + continue; + return 0; +} + +static int bfin_miiphy_read(char *devname, uchar addr, uchar reg, ushort *val) +{ + if (bfin_miiphy_wait()) + return 1; + bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY); + if (bfin_miiphy_wait()) + return 1; + *val = bfin_read_EMAC_STADAT(); + return 0; +} + +static int bfin_miiphy_write(char *devname, uchar addr, uchar reg, ushort val) +{ + if (bfin_miiphy_wait()) + return 1; + bfin_write_EMAC_STADAT(val); + bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY); + return 0; +} int bfin_EMAC_initialize(bd_t *bis) { struct eth_device *dev; - dev = (struct eth_device *)malloc(sizeof(*dev)); + dev = malloc(sizeof(*dev)); if (dev == NULL) hang(); @@ -89,6 +109,10 @@ int bfin_EMAC_initialize(bd_t *bis) eth_register(dev); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + miiphy_register(dev->name, bfin_miiphy_read, bfin_miiphy_write); +#endif + return 0; } @@ -119,8 +143,8 @@ static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, txbuf[txIdx]->FrmData->NoBytes = length; memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length); txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData; - *pDMA2_NEXT_DESC_PTR = &txbuf[txIdx]->Dma[0]; - *pDMA2_CONFIG = *(u16 *) (void *)(&txdmacfg); + *pDMA2_NEXT_DESC_PTR = txbuf[txIdx]->Dma; + *pDMA2_CONFIG = txdmacfg.data; *pEMAC_OPMODE |= TE; for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) { @@ -136,7 +160,7 @@ static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, else txIdx++; out: - DEBUGF("BFIN EMAC send: length = %d\n", length); + debug("BFIN EMAC send: length = %d\n", length); return result; } @@ -182,51 +206,141 @@ static int bfin_EMAC_recv(struct eth_device *dev) * *************************************************************/ +/* MDC = SCLK / MDC_freq / 2 - 1 */ +#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1) + +static int bfin_miiphy_init(struct eth_device *dev, int *opmode) +{ + u16 phydat; + size_t count; + + /* Enable PHY output */ + *pVR_CTL |= CLKBUFOE; + + /* Set all the pins to peripheral mode */ +#ifdef CONFIG_RMII + /* grab RMII pins */ +# if defined(__ADSPBF51x__) + *pPORTF_MUX = (*pPORTF_MUX & \ + ~(PORT_x_MUX_3_MASK | PORT_x_MUX_4_MASK | PORT_x_MUX_5_MASK)) | \ + PORT_x_MUX_3_FUNC_1 | PORT_x_MUX_4_FUNC_1 | PORT_x_MUX_5_FUNC_1; + *pPORTF_FER |= PF8 | PF9 | PF10 | PF11 | PF12 | PF13 | PF14 | PF15; + *pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_1; + *pPORTG_FER |= PG0 | PG1 | PG2; +# elif defined(__ADSPBF52x__) + *pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_6_MASK) | PORT_x_MUX_6_FUNC_2; + *pPORTG_FER |= PG14 | PG15; + *pPORTH_MUX = (*pPORTH_MUX & ~(PORT_x_MUX_0_MASK | PORT_x_MUX_1_MASK)) | \ + PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2; + *pPORTH_FER |= PH0 | PH1 | PH2 | PH3 | PH4 | PH5 | PH6 | PH7 | PH8; +# else + *pPORTH_FER |= PH0 | PH1 | PH4 | PH5 | PH6 | PH8 | PH9 | PH14 | PH15; +# endif +#else + /* grab MII & RMII pins */ +# if defined(__ADSPBF51x__) + *pPORTF_MUX = (*pPORTF_MUX & \ + ~(PORT_x_MUX_0_MASK | PORT_x_MUX_1_MASK | PORT_x_MUX_3_MASK | PORT_x_MUX_4_MASK | PORT_x_MUX_5_MASK)) | \ + PORT_x_MUX_0_FUNC_1 | PORT_x_MUX_1_FUNC_1 | PORT_x_MUX_3_FUNC_1 | PORT_x_MUX_4_FUNC_1 | PORT_x_MUX_5_FUNC_1; + *pPORTF_FER |= PF0 | PF1 | PF2 | PF3 | PF4 | PF5 | PF6 | PF8 | PF9 | PF10 | PF11 | PF12 | PF13 | PF14 | PF15; + *pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_1; + *pPORTG_FER |= PG0 | PG1 | PG2; +# elif defined(__ADSPBF52x__) + *pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_6_MASK) | PORT_x_MUX_6_FUNC_2; + *pPORTG_FER |= PG14 | PG15; + *pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2 | PORT_x_MUX_2_FUNC_2; + *pPORTH_FER = -1; /* all pins */ +# else + *pPORTH_FER = -1; /* all pins */ +# endif +#endif + + /* Odd word alignment for Receive Frame DMA word */ + /* Configure checksum support and rcve frame word alignment */ + bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ))); + + /* turn on auto-negotiation and wait for link to come up */ + bfin_miiphy_write(dev->name, CONFIG_PHY_ADDR, MII_BMCR, BMCR_ANENABLE); + count = 0; + while (1) { + ++count; + if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_BMSR, &phydat)) + return -1; + if (phydat & BMSR_LSTATUS) + break; + if (count > 30000) { + printf("%s: link down, check cable\n", dev->name); + return -1; + } + udelay(100); + } + + /* see what kind of link we have */ + if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_LPA, &phydat)) + return -1; + if (phydat & LPA_DUPLEX) + *opmode = FDMODE; + else + *opmode = 0; + + bfin_write_EMAC_MMC_CTL(RSTC | CROLL); + + /* Initialize the TX DMA channel registers */ + *pDMA2_X_COUNT = 0; + *pDMA2_X_MODIFY = 4; + *pDMA2_Y_COUNT = 0; + *pDMA2_Y_MODIFY = 0; + + /* Initialize the RX DMA channel registers */ + *pDMA1_X_COUNT = 0; + *pDMA1_X_MODIFY = 4; + *pDMA1_Y_COUNT = 0; + *pDMA1_Y_MODIFY = 0; + + return 0; +} + static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) { u32 opmode; int dat; int i; - DEBUGF("Eth_init: ......\n"); + debug("Eth_init: ......\n"); txIdx = 0; rxIdx = 0; -/* Initialize System Register */ - if (SetupSystemRegs(&dat) < 0) + /* Initialize System Register */ + if (bfin_miiphy_init(dev, &dat) < 0) return -1; -/* Initialize EMAC address */ + /* Initialize EMAC address */ bfin_EMAC_setup_addr(bd); -/* Initialize TX and RX buffer */ + /* Initialize TX and RX buffer */ for (i = 0; i < PKTBUFSRX; i++) { rxbuf[i] = SetupRxBuffer(i); if (i > 0) { - rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = - &(rxbuf[i]->Dma[0]); + rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = rxbuf[i]->Dma; if (i == (PKTBUFSRX - 1)) - rxbuf[i]->Dma[1].NEXT_DESC_PTR = - &(rxbuf[0]->Dma[0]); + rxbuf[i]->Dma[1].NEXT_DESC_PTR = rxbuf[0]->Dma; } } for (i = 0; i < TX_BUF_CNT; i++) { txbuf[i] = SetupTxBuffer(i); if (i > 0) { - txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = - &(txbuf[i]->Dma[0]); + txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = txbuf[i]->Dma; if (i == (TX_BUF_CNT - 1)) - txbuf[i]->Dma[1].NEXT_DESC_PTR = - &(txbuf[0]->Dma[0]); + txbuf[i]->Dma[1].NEXT_DESC_PTR = txbuf[0]->Dma; } } /* Set RX DMA */ - *pDMA1_NEXT_DESC_PTR = &rxbuf[0]->Dma[0]; - *pDMA1_CONFIG = *((u16 *) (void *)&rxbuf[0]->Dma[0].CONFIG); + *pDMA1_NEXT_DESC_PTR = rxbuf[0]->Dma; + *pDMA1_CONFIG = rxbuf[0]->Dma[0].CONFIG_DATA; /* Wait MII done */ - PollMdcDone(); + bfin_miiphy_wait(); /* We enable only RX here */ /* ASTP : Enable Automatic Pad Stripping @@ -240,7 +354,7 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) else opmode = ASTP | PSF; opmode |= RE; -#ifdef CONFIG_BFIN_MAC_RMII +#ifdef CONFIG_RMII opmode |= TE | RMII; #endif /* Turn on the EMAC */ @@ -250,7 +364,7 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) static void bfin_EMAC_halt(struct eth_device *dev) { - DEBUGF("Eth_halt: ......\n"); + debug("Eth_halt: ......\n"); /* Turn off the EMAC */ *pEMAC_OPMODE = 0x00000000; /* Turn off the EMAC RX DMA */ @@ -271,125 +385,6 @@ void bfin_EMAC_setup_addr(bd_t *bd) bd->bi_enetaddr[5] << 8; } -static void PollMdcDone(void) -{ - /* poll the STABUSY bit */ - while (*pEMAC_STAADD & STABUSY) ; -} - -static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data) -{ - PollMdcDone(); - - *pEMAC_STADAT = Data; - - *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | - STAOP | STAIE | STABUSY; -} - -/********************************************************************************* - * Read an off-chip register in a PHY through the MDC/MDIO port * - *********************************************************************************/ -static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr) -{ - u16 Data; - - PollMdcDone(); - - *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | - STAIE | STABUSY; - - PollMdcDone(); - - Data = (u16) * pEMAC_STADAT; - - PHYregs[RegAddr] = Data; /* save shadow copy */ - - return Data; -} - -#if 0 /* dead code ? */ -static void SoftResetPHY(void) -{ - u16 phydat; - /* set the reset bit */ - WrPHYReg(PHYADDR, PHY_MODECTL, PHY_RESET); - /* and clear it again */ - WrPHYReg(PHYADDR, PHY_MODECTL, 0x0000); - do { - /* poll until reset is complete */ - phydat = RdPHYReg(PHYADDR, PHY_MODECTL); - } while ((phydat & PHY_RESET) != 0); -} -#endif - -static int SetupSystemRegs(int *opmode) -{ - u16 sysctl, phydat; - int count = 0; - /* Enable PHY output */ - *pVR_CTL |= CLKBUFOE; - /* Set all the pins to peripheral mode */ - -#ifndef CONFIG_BFIN_MAC_RMII - *pPORTH_FER = 0xFFFF; -#ifdef __ADSPBF52x__ - *pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2 | PORT_x_MUX_2_FUNC_2; -#endif -#else -#if defined(__ADSPBF536__) || defined(__ADSPBF537__) - *pPORTH_FER = 0xC373; -#endif -#ifdef __ADSPBF52x__ - *pPORTH_FER = 0x01FF; - *pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2; -#endif -#endif - /* MDC = 2.5 MHz */ - sysctl = SET_MDCDIV(24); - /* Odd word alignment for Receive Frame DMA word */ - /* Configure checksum support and rcve frame word alignment */ - sysctl |= RXDWA | RXCKS; - *pEMAC_SYSCTL = sysctl; - /* auto negotiation on */ - /* full duplex */ - /* 100 Mbps */ - phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; - WrPHYReg(PHYADDR, PHY_MODECTL, phydat); - do { - udelay(1000); - phydat = RdPHYReg(PHYADDR, PHY_MODESTAT); - if (count > 3000) { - printf - ("Link is down, please check your network connection\n"); - return -1; - } - count++; - } while (!(phydat & 0x0004)); - - phydat = RdPHYReg(PHYADDR, PHY_ANLPAR); - - if ((phydat & 0x0100) || (phydat & 0x0040)) - *opmode = FDMODE; - else - *opmode = 0; - - *pEMAC_MMC_CTL = RSTC | CROLL; - - /* Initialize the TX DMA channel registers */ - *pDMA2_X_COUNT = 0; - *pDMA2_X_MODIFY = 4; - *pDMA2_Y_COUNT = 0; - *pDMA2_Y_MODIFY = 0; - - /* Initialize the RX DMA channel registers */ - *pDMA1_X_COUNT = 0; - *pDMA1_X_MODIFY = 4; - *pDMA1_Y_COUNT = 0; - *pDMA1_Y_MODIFY = 0; - return 0; -} - ADI_ETHER_BUFFER *SetupRxBuffer(int no) { ADI_ETHER_FRAME_BUFFER *frmbuf; @@ -397,10 +392,8 @@ ADI_ETHER_BUFFER *SetupRxBuffer(int no) int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ int total_size = nobytes_buffer + RECV_BUFSIZE; - buf = (ADI_ETHER_BUFFER *) (RXBUF_BASE_ADDR + no * total_size); - frmbuf = - (ADI_ETHER_FRAME_BUFFER *) (RXBUF_BASE_ADDR + no * total_size + - nobytes_buffer); + buf = (void *) (RXBUF_BASE_ADDR + no * total_size); + frmbuf = (void *) (RXBUF_BASE_ADDR + no * total_size + nobytes_buffer); memset(buf, 0x00, nobytes_buffer); buf->FrmData = frmbuf; @@ -416,7 +409,7 @@ ADI_ETHER_BUFFER *SetupRxBuffer(int no) buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ /* set up second desc to point to status word */ - buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]); + buf->Dma[1].NEXT_DESC_PTR = buf->Dma; buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum; buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ @@ -435,10 +428,8 @@ ADI_ETHER_BUFFER *SetupTxBuffer(int no) int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ int total_size = nobytes_buffer + RECV_BUFSIZE; - buf = (ADI_ETHER_BUFFER *) (TXBUF_BASE_ADDR + no * total_size); - frmbuf = - (ADI_ETHER_FRAME_BUFFER *) (TXBUF_BASE_ADDR + no * total_size + - nobytes_buffer); + buf = (void *) (TXBUF_BASE_ADDR + no * total_size); + frmbuf = (void *) (TXBUF_BASE_ADDR + no * total_size + nobytes_buffer); memset(buf, 0x00, nobytes_buffer); buf->FrmData = frmbuf; diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index c8a94d0c9..084f53334 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -9,29 +9,8 @@ #ifndef __BFIN_MAC_H__ #define __BFIN_MAC_H__ -#define PHYADDR 0x01 -#define NO_PHY_REGS 0x20 - -#define DEFAULT_PHY_PHYID1 0x0007 -#define DEFAULT_PHY_PHYID2 0xC0A3 -#define PHY_MODECTL 0x00 -#define PHY_MODESTAT 0x01 -#define PHY_PHYID1 0x02 -#define PHY_PHYID2 0x03 -#define PHY_ANAR 0x04 -#define PHY_ANLPAR 0x05 -#define PHY_ANER 0x06 - -#define PHY_RESET 0x8000 -#define PHY_ANEG_EN 0x1000 -#define PHY_DUPLEX 0x0100 -#define PHY_SPD_SET 0x2000 - #define RECV_BUFSIZE (0x614) -typedef volatile u32 reg32; -typedef volatile u16 reg16; - typedef struct ADI_DMA_CONFIG_REG { u16 b_DMA_EN:1; /* 0 Enabled */ u16 b_WNR:1; /* 1 Direction */ @@ -56,7 +35,10 @@ typedef struct adi_ether_frame_buffer { typedef struct dma_descriptor { struct dma_descriptor *NEXT_DESC_PTR; u32 START_ADDR; - ADI_DMA_CONFIG_REG CONFIG; + union { + u16 CONFIG_DATA; + ADI_DMA_CONFIG_REG CONFIG; + }; } DMA_DESCRIPTOR; /* 10 bytes/struct in 12 bytes */ @@ -79,11 +61,6 @@ static void bfin_EMAC_halt(struct eth_device *dev); static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, int length); static int bfin_EMAC_recv(struct eth_device *dev); -static void PollMdcDone(void); -static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data); -static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr); -static int SetupSystemRegs(int *opmode); - static void bfin_EMAC_setup_addr(bd_t *bd); #endif diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c new file mode 100644 index 000000000..bfe87faa2 --- /dev/null +++ b/drivers/net/dnet.c @@ -0,0 +1,395 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> + +#ifndef CONFIG_DNET_AUTONEG_TIMEOUT +#define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ +#endif + +#include <net.h> +#include <malloc.h> +#include <linux/mii.h> + +#include <miiphy.h> +#include <asm/io.h> + +#include "dnet.h" + +struct dnet_device { + struct dnet_registers *regs; + const struct device *dev; + struct eth_device netdev; + unsigned short phy_addr; +}; + +/* get struct dnet_device from given struct netdev */ +#define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) + +/* function for reading internal MAC register */ +u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) +{ + u16 data_read; + + /* issue a read */ + writel(reg, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before reading the data */ + udelay(1); + + /* read data read from the MAC register */ + data_read = readl(&dnet->regs->MACREG_DATA); + + /* all done */ + return data_read; +} + +/* function for writing internal MAC register */ +void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) +{ + /* load data to write */ + writel(val, &dnet->regs->MACREG_DATA); + + /* issue a write */ + writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before exiting */ + udelay(1); +} + +static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) +{ + u16 tmp; + + debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* prepare for a write operation */ + tmp = (1 << 13); + + /* only 5 bits allowed for register offset */ + reg &= 0x1f; + + /* prepare reg_value for a write */ + tmp |= (dnet->phy_addr << 8); + tmp |= reg; + + /* write data to write first */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; +} + +static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) +{ + u16 value; + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* only 5 bits allowed for register offset*/ + reg &= 0x1f; + + /* prepare reg_value for a read */ + value = (dnet->phy_addr << 8); + value |= reg; + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); + + /* wait for end of transfer */ + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); + + debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + return value; +} + +static int dnet_send(struct eth_device *netdev, volatile void *packet, + int length) +{ + struct dnet_device *dnet = to_dnet(netdev); + int i, len, wrsz; + unsigned int *bufp; + unsigned int tx_cmd; + + debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); + + /* frame size (words) */ + len = (length + 3) >> 2; + + bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); + wrsz = (u32)length + 3; + wrsz += ((u32)packet) & 0x3; + wrsz >>= 2; + tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; + + /* check if there is enough room for the current frame */ + if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { + for (i = 0; i < wrsz; i++) + writel(*bufp++, &dnet->regs->TX_DATA_FIFO); + /* + * inform MAC that a packet's written and ready + * to be shipped out + */ + writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); + } else { + printf(DRIVERNAME "No free space (actual %d, required %d " + "(words))\n", DNET_FIFO_SIZE - + readl(&dnet->regs->TX_FIFO_WCNT), wrsz); + } + + /* No one cares anyway */ + return 0; +} + + +static int dnet_recv(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + unsigned int *data_ptr; + int pkt_len, poll, i; + u32 cmd_word; + + debug("Waiting for pkt (polling)\n"); + poll = 50; + while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { + udelay(10); /* wait 10 usec */ + if (--poll == 0) + return 0; /* no pkt available */ + } + + cmd_word = readl(&dnet->regs->RX_LEN_FIFO); + pkt_len = cmd_word & 0xFFFF; + + debug("Got pkt with size %d bytes\n", pkt_len); + + if (cmd_word & 0xDF180000) + printf("%s packet receive error %x\n", __func__, cmd_word); + + data_ptr = (unsigned int *) NetRxPackets[0]; + + for (i = 0; i < (pkt_len + 3) >> 2; i++) + *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); + + NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ + + return 0; +} + +static void dnet_set_hwaddr(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + u16 tmp; + + tmp = cpu_to_be16(*((u16 *)netdev->enetaddr)); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 2))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 4))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); +} + +static void dnet_phy_reset(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + int i; + u16 status, adv; + + adv = ADVERTISE_CSMA | ADVERTISE_ALL; + dnet_mdio_write(dnet, MII_ADVERTISE, adv); + printf("%s: Starting autonegotiation...\n", netdev->name); + dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE + | BMCR_ANRESTART)); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_ANEGCOMPLETE) + break; + udelay(100); + } + + if (status & BMSR_ANEGCOMPLETE) + printf("%s: Autonegotiation complete\n", netdev->name); + else + printf("%s: Autonegotiation timed out (status=0x%04x)\n", + netdev->name, status); +} + +static int dnet_phy_init(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + u16 phy_id, status, adv, lpa; + int media, speed, duplex; + int i; + u32 ctl_reg; + + /* Find a PHY */ + for (i = 0; i < 32; i++) { + dnet->phy_addr = i; + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id != 0xffff) { + /* ok we found it */ + printf("Found PHY at address %d PHYID (%04x:%04x)\n", + i, phy_id, + dnet_mdio_read(dnet, MII_PHYSID2)); + break; + } + } + + /* Check if the PHY is up to snuff... */ + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id == 0xffff) { + printf("%s: No PHY present\n", netdev->name); + return -1; + } + + status = dnet_mdio_read(dnet, MII_BMSR); + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + dnet_phy_reset(dnet); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_LSTATUS) + break; + udelay(100); + } + } + + if (!(status & BMSR_LSTATUS)) { + printf("%s: link down (status: 0x%04x)\n", + netdev->name, status); + return -1; + } else { + adv = dnet_mdio_read(dnet, MII_ADVERTISE); + lpa = dnet_mdio_read(dnet, MII_LPA); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + /* 1000BaseT ethernet is not supported */ + printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", + netdev->name, + speed ? "100" : "10", + duplex ? "full" : "half", + lpa); + + ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + if (duplex) + ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); + else + ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); + + return 0; + } +} + +static int dnet_init(struct eth_device *netdev, bd_t *bd) +{ + struct dnet_device *dnet = to_dnet(netdev); + u32 config; + + /* + * dnet_halt should have been called at some point before now, + * so we'll assume the controller is idle. + */ + + /* set hardware address */ + dnet_set_hwaddr(netdev); + + if (dnet_phy_init(dnet) < 0) + return -1; + + /* flush rx/tx fifos */ + writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, + &dnet->regs->SYS_CTL); + udelay(1000); + writel(0, &dnet->regs->SYS_CTL); + + config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | + DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | + DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | + DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); + + /* Enable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, + DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); + + return 0; +} + +static void dnet_halt(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + + /* Disable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); +} + +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) +{ + struct dnet_device *dnet; + struct eth_device *netdev; + unsigned int dev_capa; + + dnet = malloc(sizeof(struct dnet_device)); + if (!dnet) { + printf("Error: Failed to allocate memory for DNET%d\n", id); + return -1; + } + memset(dnet, 0, sizeof(struct dnet_device)); + + netdev = &dnet->netdev; + + dnet->regs = (struct dnet_registers *)regs; + dnet->phy_addr = phy_addr; + + sprintf(netdev->name, "dnet%d", id); + netdev->init = dnet_init; + netdev->halt = dnet_halt; + netdev->send = dnet_send; + netdev->recv = dnet_recv; + + dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; + debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, + (dev_capa & DNET_HAS_MDIO) ? "" : "no ", + (dev_capa & DNET_HAS_IRQ) ? "" : "no ", + (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", + (dev_capa & DNET_HAS_DMA) ? "" : "no "); + + eth_register(netdev); + + return 0; +} diff --git a/drivers/net/dnet.h b/drivers/net/dnet.h new file mode 100644 index 000000000..fdb4fd2d3 --- /dev/null +++ b/drivers/net/dnet.h @@ -0,0 +1,166 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_DNET_H__ +#define __DRIVERS_DNET_H__ + +#define DRIVERNAME "dnet" + +struct dnet_registers { + /* ALL DNET FIFO REGISTERS */ + u32 RX_LEN_FIFO; + u32 RX_DATA_FIFO; + u32 TX_LEN_FIFO; + u32 TX_DATA_FIFO; + u32 pad1[0x3c]; + /* ALL DNET CONTROL/STATUS REGISTERS */ + u32 VERCAPS; + u32 INTR_SRC; + u32 INTR_ENB; + u32 RX_STATUS; + u32 TX_STATUS; + u32 RX_FRAMES_CNT; + u32 TX_FRAMES_CNT; + u32 RX_FIFO_TH; + u32 TX_FIFO_TH; + u32 SYS_CTL; + u32 PAUSE_TMR; + u32 RX_FIFO_WCNT; + u32 TX_FIFO_WCNT; + u32 pad2[0x33]; + /* ALL DNET MAC REGISTERS */ + u32 MACREG_DATA; /* Mac-Reg Data */ + u32 MACREG_ADDR; /* Mac-Reg Addr */ + u32 pad3[0x3e]; + /* ALL DNET RX STATISTICS COUNTERS */ + u32 RX_PKT_IGNR_CNT; + u32 RX_LEN_CHK_ERR_CNT; + u32 RX_LNG_FRM_CNT; + u32 RX_SHRT_FRM_CNT; + u32 RX_IPG_VIOL_CNT; + u32 RX_CRC_ERR_CNT; + u32 RX_OK_PKT_CNT; + u32 RX_CTL_FRM_CNT; + u32 RX_PAUSE_FRM_CNT; + u32 RX_MULTICAST_CNT; + u32 RX_BROADCAST_CNT; + u32 RX_VLAN_TAG_CNT; + u32 RX_PRE_SHRINK_CNT; + u32 RX_DRIB_NIB_CNT; + u32 RX_UNSUP_OPCD_CNT; + u32 RX_BYTE_CNT; + u32 pad4[0x30]; + /* DNET TX STATISTICS COUNTERS */ + u32 TX_UNICAST_CNT; + u32 TX_PAUSE_FRM_CNT; + u32 TX_MULTICAST_CNT; + u32 TX_BRDCAST_CNT; + u32 TX_VLAN_TAG_CNT; + u32 TX_BAD_FCS_CNT; + u32 TX_JUMBO_CNT; + u32 TX_BYTE_CNT; +}; + +/* SOME INTERNAL MAC-CORE REGISTER */ +#define DNET_INTERNAL_MODE_REG 0x0 +#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2 +#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4 +#define DNET_INTERNAL_IGP_REG 0x8 +#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa +#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc +#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe +#define DNET_INTERNAL_TX_RX_STS_REG 0x12 +#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14 +#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16 + +#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14) + +#define DNET_INTERNAL_WRITE (1 << 31) + +/* MAC-CORE REGISTER FIELDS */ + +/* MAC-CORE MODE REGISTER FIELDS */ +#define DNET_INTERNAL_MODE_GBITEN (1 << 0) +#define DNET_INTERNAL_MODE_FCEN (1 << 1) +#define DNET_INTERNAL_MODE_RXEN (1 << 2) +#define DNET_INTERNAL_MODE_TXEN (1 << 3) + +/* MAC-CORE RXTX CONTROL REGISTER FIELDS */ +#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8) +#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7) +#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4) +#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3) +#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2) +#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1) +#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0) +#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6) +#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5) + +/* SYSTEM CONTROL REGISTER FIELDS */ +#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0) +#define DNET_SYS_CTL_SENDPAUSE (1 << 2) +#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3) +#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4) + +/* TX STATUS REGISTER FIELDS */ +#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2) +#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1) + +/* INTERRUPT SOURCE REGISTER FIELDS */ +#define DNET_INTR_SRC_TX_PKTSENT (1 << 0) +#define DNET_INTR_SRC_TX_FIFOAF (1 << 1) +#define DNET_INTR_SRC_TX_FIFOAE (1 << 2) +#define DNET_INTR_SRC_TX_DISCFRM (1 << 3) +#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4) +#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8) +#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9) +#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10) +#define DNET_INTR_SRC_TX_SUMMARY (1 << 16) +#define DNET_INTR_SRC_RX_SUMMARY (1 << 17) +#define DNET_INTR_SRC_PHY (1 << 19) + +/* INTERRUPT ENABLE REGISTER FIELDS */ +#define DNET_INTR_ENB_TX_PKTSENT (1 << 0) +#define DNET_INTR_ENB_TX_FIFOAF (1 << 1) +#define DNET_INTR_ENB_TX_FIFOAE (1 << 2) +#define DNET_INTR_ENB_TX_DISCFRM (1 << 3) +#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4) +#define DNET_INTR_ENB_RX_PKTRDY (1 << 8) +#define DNET_INTR_ENB_RX_FIFOAF (1 << 9) +#define DNET_INTR_ENB_RX_FIFOERR (1 << 10) +#define DNET_INTR_ENB_RX_ERROR (1 << 11) +#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12) +#define DNET_INTR_ENB_RX_FIFOAE (1 << 13) +#define DNET_INTR_ENB_TX_SUMMARY (1 << 16) +#define DNET_INTR_ENB_RX_SUMMARY (1 << 17) +#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18) + +/* + * Capabilities. Used by the driver to know the capabilities that + * the ethernet controller inside the FPGA have. + */ + +#define DNET_HAS_MDIO (1 << 0) +#define DNET_HAS_IRQ (1 << 1) +#define DNET_HAS_GIGABIT (1 << 2) +#define DNET_HAS_DMA (1 << 3) + +#define DNET_HAS_MII (1 << 4) /* or GMII */ +#define DNET_HAS_RMII (1 << 5) /* or RGMII */ + +#define DNET_CAPS_MASK 0xFFFF + +#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */ +#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */ +#define DNET_FIFO_TX_DATA_AE_TH (384) + +#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */ + +#endif diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 2dcaa2c91..a52749d78 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -82,6 +82,7 @@ static struct pci_device_id supported[] = { {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541GI_LF}, + {} }; /* Function forward declarations */ diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 98e8c73ca..af0409bd2 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -317,6 +317,30 @@ static void macb_phy_reset(struct macb_device *macb) netdev->name, status); } +#ifdef CONFIG_MACB_SEARCH_PHY +static int macb_phy_find(struct macb_device *macb) +{ + int i; + u16 phy_id; + + /* Search for PHY... */ + for (i = 0; i < 32; i++) { + macb->phy_addr = i; + phy_id = macb_mdio_read(macb, MII_PHYSID1); + if (phy_id != 0xffff) { + printf("%s: PHY present at %d\n", macb->netdev.name, i); + return 1; + } + } + + /* PHY isn't up to snuff */ + printf("%s: PHY not found", macb->netdev.name); + + return 0; +} +#endif /* CONFIG_MACB_SEARCH_PHY */ + + static int macb_phy_init(struct macb_device *macb) { struct eth_device *netdev = &macb->netdev; @@ -325,6 +349,13 @@ static int macb_phy_init(struct macb_device *macb) int media, speed, duplex; int i; +#ifdef CONFIG_MACB_SEARCH_PHY + /* Auto-detect phy_addr */ + if (!macb_phy_find(macb)) { + return 0; + } +#endif /* CONFIG_MACB_SEARCH_PHY */ + /* Check if the PHY is up to snuff... */ phy_id = macb_mdio_read(macb, MII_PHYSID1); if (phy_id == 0xffff) { diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index 2b733c66e..4f1c0a012 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -226,7 +226,8 @@ void __mii_init(void) volatile FEC_T *fecp; struct eth_device *dev; int miispd = 0, i = 0; - u16 autoneg = 0; + u16 status = 0; + u16 linkgood = 0; /* retrieve from register structure */ dev = eth_get_dev(); @@ -250,22 +251,32 @@ void __mii_init(void) info->phy_addr = mii_discover_phy(dev); -#define AUTONEGLINK (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS) while (i < MCFFEC_TOUT_LOOP) { - autoneg = 0; - miiphy_read(dev->name, info->phy_addr, PHY_BMSR, &autoneg); + status = 0; i++; + /* Read PHY control register */ + miiphy_read(dev->name, info->phy_addr, PHY_BMCR, &status); - if ((autoneg & AUTONEGLINK) == AUTONEGLINK) + /* If phy set to autonegotiate, wait for autonegotiation done, + * if phy is not autonegotiating, just wait for link up. + */ + if ((status & PHY_BMCR_AUTON) == PHY_BMCR_AUTON) { + linkgood = (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS); + } else { + linkgood = PHY_BMSR_LS; + } + /* Read PHY status register */ + miiphy_read(dev->name, info->phy_addr, PHY_BMSR, &status); + if ((status & linkgood) == linkgood) break; udelay(500); } if (i >= MCFFEC_TOUT_LOOP) { - printf("Auto Negotiation not complete\n"); + printf("Link UP timeout\n"); } - /* adapt to the half/full speed settings */ + /* adapt to the duplex and speed settings of the phy */ info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16; info->dup_spd |= miiphy_speed(dev->name, info->phy_addr); } diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c index f8618b172..2bf901e13 100644 --- a/drivers/net/mpc5xxx_fec.c +++ b/drivers/net/mpc5xxx_fec.c @@ -19,9 +19,6 @@ DECLARE_GLOBAL_DATA_PTR; /* #define DEBUG 0x28 */ -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_MPC5xxx_FEC) - #if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) #error "CONFIG_MII has to be defined!" #endif @@ -891,28 +888,11 @@ int mpc5xxx_fec_initialize(bd_t * bis) fec->eth = (ethernet_regs *)MPC5XXX_FEC; fec->tbdBase = (FEC_TBD *)FEC_BD_BASE; fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD)); -#if defined(CONFIG_CANMB) || \ - defined(CONFIG_CM5200) || \ - defined(CONFIG_HMI1001) || \ - defined(CONFIG_ICECUBE) || \ - defined(CONFIG_INKA4X0) || \ - defined(CONFIG_JUPITER) || \ - defined(CONFIG_MCC200) || \ - defined(CONFIG_MOTIONPRO) || \ - defined(CONFIG_MUCMC52) || \ - defined(CONFIG_O2DNT) || \ - defined(CONFIG_PM520) || \ - defined(CONFIG_TOP5200) || \ - defined(CONFIG_TQM5200) || \ - defined(CONFIG_UC101) || \ - defined(CONFIG_V38B) || \ - defined(CONFIG_MUNICES) -# ifndef CONFIG_FEC_10MBIT +#if defined(CONFIG_MPC5xxx_FEC_MII100) fec->xcv_type = MII100; -# else +#elif defined(CONFIG_MPC5xxx_FEC_MII10) fec->xcv_type = MII10; -# endif -#elif defined(CONFIG_TOTAL5200) +#elif defined(CONFIG_MPC5xxx_FEC_SEVENWIRE) fec->xcv_type = SEVENWIRE; #else #error fec->xcv_type not initialized. @@ -1064,5 +1044,3 @@ static uint32 local_crc32(char *string, unsigned int crc_value, int len) /**/ return crc; } #endif /* DEBUG */ - -#endif /* CONFIG_MPC5xxx_FEC */ diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 9e3cf98b3..ebe858894 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -24,6 +24,7 @@ #include <common.h> #include <malloc.h> #include <net.h> +#include <netdev.h> #include <asm/errno.h> #include <asm/io.h> @@ -36,12 +37,7 @@ # error "Please define CONFIG_SH_ETHER_PHY_ADDR" #endif -extern int eth_init(bd_t *bd); -extern void eth_halt(void); -extern int eth_rx(void); -extern int eth_send(volatile void *packet, int length); - -static struct dev_info_s *dev; +#define SH_ETH_PHY_DELAY 50000 /* * Bits are written to the PHY serially using the @@ -89,7 +85,7 @@ static void sh_eth_mii_ind_bus_release(int port) udelay(1); } -static int sh_eth_mii_read_phy_bits(int port, u32 * val, int len) +static void sh_eth_mii_read_phy_bits(int port, u32 *val, int len) { int i; u32 pir; @@ -106,8 +102,6 @@ static int sh_eth_mii_read_phy_bits(int port, u32 * val, int len) outl(0, PIR(port)); udelay(1); } - - return 0; } #define PHY_INIT 0xFFFFFFFF @@ -183,26 +177,23 @@ static void sh_eth_mii_write_phy_reg(int port, u8 phy_addr, int reg, u16 val) sh_eth_mii_ind_bus_release(port); } -void eth_halt(void) -{ -} - -int eth_send(volatile void *packet, int len) +int sh_eth_send(struct eth_device *dev, volatile void *packet, int len) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; - int timeout; - int rc = 0; + struct sh_eth_dev *eth = dev->priv; + int port = eth->port, ret = 0, timeout; + struct sh_eth_info *port_info = ð->port_info[port]; if (!packet || len > 0xffff) { - printf("eth_send: Invalid argument\n"); - return -EINVAL; + printf(SHETHER_NAME ": %s: Invalid argument\n", __func__); + ret = -EINVAL; + goto err; } /* packet must be a 4 byte boundary */ if ((int)packet & (4 - 1)) { - printf("eth_send: packet not 4 byte alligned\n"); - return -EFAULT; + printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n", __func__); + ret = -EFAULT; + goto err; } /* Update tx descriptor */ @@ -224,24 +215,25 @@ int eth_send(volatile void *packet, int len) udelay(100); if (timeout < 0) { - printf("eth_send: transmit timeout\n"); - rc = -1; + printf(SHETHER_NAME ": transmit timeout\n"); + ret = -ETIMEDOUT; goto err; } -err: port_info->tx_desc_cur++; if (port_info->tx_desc_cur >= port_info->tx_desc_base + NUM_TX_DESC) port_info->tx_desc_cur = port_info->tx_desc_base; - return rc; + return ret; +err: + return ret; } -int eth_rx(void) +int sh_eth_recv(struct eth_device *dev) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; - int len = 0; + struct sh_eth_dev *eth = dev->priv; + int port = eth->port, len = 0; + struct sh_eth_info *port_info = ð->port_info[port]; volatile u8 *packet; /* Check if the rx descriptor is ready */ @@ -275,10 +267,10 @@ int eth_rx(void) } #define EDMR_INIT_CNT 1000 -static int sh_eth_reset(struct dev_info_s *dev) +static int sh_eth_reset(struct sh_eth_dev *eth) { - int port = dev->port; - int i; + int port = eth->port; + int ret = 0, i; /* Start e-dmac transmitter and receiver */ outl(EDSR_ENALL, EDSR(port)); @@ -292,33 +284,36 @@ static int sh_eth_reset(struct dev_info_s *dev) } if (i == EDMR_INIT_CNT) { - printf("Error: Software reset timeout\n"); - return -1; + printf(SHETHER_NAME ": Software reset timeout\n"); + ret = -EIO; } - return 0; + + return ret; } -static int sh_eth_tx_desc_init(struct dev_info_s *dev) +static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; + int port = eth->port, i, ret = 0; u32 tmp_addr; + struct sh_eth_info *port_info = ð->port_info[port]; struct tx_desc_s *cur_tx_desc; - int i; - /* Allocate tx descriptors. They must be TX_DESC_SIZE bytes - aligned */ - if (!(port_info->tx_desc_malloc = malloc(NUM_TX_DESC * + /* + * Allocate tx descriptors. They must be TX_DESC_SIZE bytes aligned + */ + port_info->tx_desc_malloc = malloc(NUM_TX_DESC * sizeof(struct tx_desc_s) + - TX_DESC_SIZE - 1))) { - printf("Error: malloc failed\n"); - return -ENOMEM; + TX_DESC_SIZE - 1); + if (!port_info->tx_desc_malloc) { + printf(SHETHER_NAME ": malloc failed\n"); + ret = -ENOMEM; + goto err; } + tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) & ~(TX_DESC_SIZE - 1)); /* Make sure we use a P2 address (non-cacheable) */ port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr); - port_info->tx_desc_cur = port_info->tx_desc_base; /* Initialize all descriptors */ @@ -340,26 +335,30 @@ static int sh_eth_tx_desc_init(struct dev_info_s *dev) outl(ADDR_TO_PHY(cur_tx_desc), TDFXR(port)); outl(0x01, TDFFR(port));/* Last discriptor bit */ - return 0; +err: + return ret; } -static int sh_eth_rx_desc_init(struct dev_info_s *dev) +static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; - u32 tmp_addr; + int port = eth->port, i , ret = 0; + struct sh_eth_info *port_info = ð->port_info[port]; struct rx_desc_s *cur_rx_desc; + u32 tmp_addr; u8 *rx_buf; - int i; - /* Allocate rx descriptors. They must be RX_DESC_SIZE bytes - aligned */ - if (!(port_info->rx_desc_malloc = malloc(NUM_RX_DESC * + /* + * Allocate rx descriptors. They must be RX_DESC_SIZE bytes aligned + */ + port_info->rx_desc_malloc = malloc(NUM_RX_DESC * sizeof(struct rx_desc_s) + - RX_DESC_SIZE - 1))) { - printf("Error: malloc failed\n"); - return -ENOMEM; + RX_DESC_SIZE - 1); + if (!port_info->rx_desc_malloc) { + printf(SHETHER_NAME ": malloc failed\n"); + ret = -ENOMEM; + goto err; } + tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) & ~(RX_DESC_SIZE - 1)); /* Make sure we use a P2 address (non-cacheable) */ @@ -367,15 +366,17 @@ static int sh_eth_rx_desc_init(struct dev_info_s *dev) port_info->rx_desc_cur = port_info->rx_desc_base; - /* Allocate rx data buffers. They must be 32 bytes aligned and in - P2 area */ - if (!(port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE + - 31))) { - printf("Error: malloc failed\n"); - free(port_info->rx_desc_malloc); - port_info->rx_desc_malloc = NULL; - return -ENOMEM; + /* + * Allocate rx data buffers. They must be 32 bytes aligned and in + * P2 area + */ + port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE + 31); + if (!port_info->rx_buf_malloc) { + printf(SHETHER_NAME ": malloc failed\n"); + ret = -ENOMEM; + goto err_buf_malloc; } + tmp_addr = (u32)(((int)port_info->rx_buf_malloc + (32 - 1)) & ~(32 - 1)); port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr); @@ -399,18 +400,31 @@ static int sh_eth_rx_desc_init(struct dev_info_s *dev) outl(ADDR_TO_PHY(cur_rx_desc), RDFXR(port)); outl(RDFFR_RDLF, RDFFR(port)); - return 0; + return ret; + +err_buf_malloc: + free(port_info->rx_desc_malloc); + port_info->rx_desc_malloc = NULL; + +err: + return ret; } -static void sh_eth_desc_free(struct dev_info_s *dev) +static void sh_eth_tx_desc_free(struct sh_eth_dev *eth) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; + int port = eth->port; + struct sh_eth_info *port_info = ð->port_info[port]; if (port_info->tx_desc_malloc) { free(port_info->tx_desc_malloc); port_info->tx_desc_malloc = NULL; } +} + +static void sh_eth_rx_desc_free(struct sh_eth_dev *eth) +{ + int port = eth->port; + struct sh_eth_info *port_info = ð->port_info[port]; if (port_info->rx_desc_malloc) { free(port_info->rx_desc_malloc); @@ -423,36 +437,48 @@ static void sh_eth_desc_free(struct dev_info_s *dev) } } -static int sh_eth_desc_init(struct dev_info_s *dev) +static int sh_eth_desc_init(struct sh_eth_dev *eth) { - int rc; + int ret = 0; - if ((rc = sh_eth_tx_desc_init(dev)) || (rc = sh_eth_rx_desc_init(dev))) { - sh_eth_desc_free(dev); - return rc; - } + ret = sh_eth_tx_desc_init(eth); + if (ret) + goto err_tx_init; - return 0; + ret = sh_eth_rx_desc_init(eth); + if (ret) + goto err_rx_init; + + return ret; +err_rx_init: + sh_eth_tx_desc_free(eth); + +err_tx_init: + return ret; } -static int sh_eth_phy_config(struct dev_info_s *dev) +static int sh_eth_phy_config(struct sh_eth_dev *eth) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; - int timeout; + int port = eth->port, timeout, ret = 0; + struct sh_eth_info *port_info = ð->port_info[port]; u32 val; + /* Reset phy */ - sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_CTRL, PHY_C_RESET); + sh_eth_mii_write_phy_reg + (port, port_info->phy_addr, PHY_CTRL, PHY_C_RESET); timeout = 10; while (timeout--) { - val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, PHY_CTRL); + val = sh_eth_mii_read_phy_reg(port, + port_info->phy_addr, PHY_CTRL); if (!(val & PHY_C_RESET)) break; - udelay(50000); + udelay(SH_ETH_PHY_DELAY); } + if (timeout < 0) { - printf("%s phy reset timeout\n", __func__); - return -1; + printf(SHETHER_NAME ": phy reset timeout\n"); + ret = -EIO; + goto err_tout; } /* Advertise 100/10 baseT full/half duplex */ @@ -467,23 +493,27 @@ static int sh_eth_phy_config(struct dev_info_s *dev) val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1); if (val & PHY_S_ANEGC) break; - udelay(50000); + + udelay(SH_ETH_PHY_DELAY); } + if (timeout < 0) { - printf("sh_eth_phy_config() phy auto-negotiation failed\n"); - return -1; + printf(SHETHER_NAME ": phy auto-negotiation failed\n"); + ret = -ETIMEDOUT; + goto err_tout; } - return 0; + return ret; + +err_tout: + return ret; } -static int sh_eth_config(struct dev_info_s *dev, bd_t * bd) +static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) { - int port = dev->port; - struct port_info_s *port_info = &dev->port_info[port]; - u32 val; - u32 phy_status; - int rc; + int port = eth->port, ret = 0; + u32 val, phy_status; + struct sh_eth_info *port_info = ð->port_info[port]; /* Configure e-dmac registers */ outl((inl(EDMR(port)) & ~EMDR_DESC_R) | EDMR_EL, EDMR(port)); @@ -513,20 +543,20 @@ static int sh_eth_config(struct dev_info_s *dev, bd_t * bd) outl(TPAUSER_TPAUSE, TPAUSER(port)); /* Configure phy */ - if ((rc = sh_eth_phy_config(dev))) - return rc; - + ret = sh_eth_phy_config(eth); + if (ret) { + printf(SHETHER_NAME ":i phy config timeout\n"); + goto err_phy_cfg; + } /* Read phy status to finish configuring the e-mac */ - phy_status = sh_eth_mii_read_phy_reg(dev->port, - dev->port_info[dev->port].phy_addr, - 1); + phy_status = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1); /* Set the transfer speed */ if (phy_status & (PHY_S_100X_F|PHY_S_100X_H)) { - printf("100Base/"); + printf(SHETHER_NAME ": 100Base/"); outl(GECMR_100B, GECMR(port)); } else { - printf("10Base/"); + printf(SHETHER_NAME ": 10Base/"); outl(GECMR_10B, GECMR(port)); } @@ -538,27 +568,34 @@ static int sh_eth_config(struct dev_info_s *dev, bd_t * bd) printf("Half\n"); outl((ECMR_CHG_DM|ECMR_RE|ECMR_TE), ECMR(port)); } - return 0; + + return ret; + +err_phy_cfg: + return ret; } -static int sh_eth_start(struct dev_info_s *dev) +static void sh_eth_start(struct sh_eth_dev *eth) { /* * Enable the e-dmac receiver only. The transmitter will be enabled when * we have something to transmit */ - outl(EDRRR_R, EDRRR(dev->port)); + outl(EDRRR_R, EDRRR(eth->port)); +} - return 0; +static void sh_eth_stop(struct sh_eth_dev *eth) +{ + outl(~EDRRR_R, EDRRR(eth->port)); } static int sh_eth_get_mac(bd_t *bd) { char *s, *e; - int i; s = getenv("ethaddr"); if (s != NULL) { + int i; for (i = 0; i < 6; ++i) { bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0; if (s) @@ -570,34 +607,92 @@ static int sh_eth_get_mac(bd_t *bd) return 0; } -int eth_init(bd_t *bd) +int sh_eth_init(struct eth_device *dev, bd_t *bd) { - int rc; - /* Allocate main device information structure */ - if (!(dev = malloc(sizeof(*dev)))) { - printf("eth_init: malloc failed\n"); - return -ENOMEM; - } + int ret = 0; + struct sh_eth_dev *eth = dev->priv; - memset(dev, 0, sizeof(*dev)); + ret = sh_eth_reset(eth); + if (ret) + goto err; - dev->port = CONFIG_SH_ETHER_USE_PORT; - dev->port_info[dev->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; + ret = sh_eth_desc_init(eth); + if (ret) + goto err; - sh_eth_get_mac(bd); + ret = sh_eth_config(eth, bd); + if (ret) + goto err_config; + + sh_eth_start(eth); + + return ret; - if ((rc = sh_eth_reset(dev)) || (rc = sh_eth_desc_init(dev))) +err_config: + sh_eth_tx_desc_free(eth); + sh_eth_rx_desc_free(eth); + +err: + return ret; +} + +void sh_eth_halt(struct eth_device *dev) +{ + struct sh_eth_dev *eth = dev->priv; + + sh_eth_reset(eth); + sh_eth_stop(eth); +} + +int sh_eth_initialize(bd_t *bd) +{ + int ret = 0; + struct sh_eth_dev *eth = NULL; + struct eth_device *dev = NULL; + + eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev)); + if (!eth) { + printf(SHETHER_NAME ": %s: malloc failed\n", __func__); + ret = -ENOMEM; + goto err; + } + + dev = (struct eth_device *)malloc(sizeof(struct eth_device)); + if (!dev) { + printf(SHETHER_NAME ": %s: malloc failed\n", __func__); + ret = -ENOMEM; goto err; + } + memset(dev, 0, sizeof(struct eth_device)); + memset(eth, 0, sizeof(struct sh_eth_dev)); - if ((rc = sh_eth_config(dev, bd)) || (rc = sh_eth_start(dev))) - goto err_desc; + eth->port = CONFIG_SH_ETHER_USE_PORT; + eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; - return 0; + dev->priv = (void *)eth; + dev->iobase = 0; + dev->init = sh_eth_init; + dev->halt = sh_eth_halt; + dev->send = sh_eth_send; + dev->recv = sh_eth_recv; + eth->port_info[eth->port].dev = dev; + + sprintf(dev->name, SHETHER_NAME); + + /* Register Device to EtherNet subsystem */ + eth_register(dev); + + sh_eth_get_mac(bd); + + return ret; -err_desc: - sh_eth_desc_free(dev); err: - free(dev); - printf("eth_init: Failed\n"); - return rc; + if (dev) + free(dev); + + if (eth) + free(eth); + + printf(SHETHER_NAME ": Failed\n"); + return ret; } diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 9cf0ea0b9..e153849e3 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -20,6 +20,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <netdev.h> #include <asm/types.h> #define SHETHER_NAME "sh_eth" @@ -48,7 +49,7 @@ #define TX_DESC_PADDING 4 #define TX_DESC_SIZE (12 + TX_DESC_PADDING) -/* Tx descriptor. We always use 4 bytes of padding */ +/* Tx descriptor. We always use 3 bytes of padding */ struct tx_desc_s { volatile u32 td0; u32 td1; @@ -72,7 +73,7 @@ struct rx_desc_s { u32 padding; }; -struct port_info_s { +struct sh_eth_info { struct tx_desc_s *tx_desc_malloc; struct tx_desc_s *tx_desc_base; struct tx_desc_s *tx_desc_cur; @@ -83,11 +84,12 @@ struct port_info_s { u8 *rx_buf_base; u8 mac_addr[6]; u8 phy_addr; + struct eth_device *dev; }; -struct dev_info_s { +struct sh_eth_dev { int port; - struct port_info_s port_info[MAX_PORT_NUM]; + struct sh_eth_info port_info[MAX_PORT_NUM]; }; /* Register Address */ @@ -166,7 +168,7 @@ enum DMAC_T_BIT { /* GECMR */ enum GECMR_BIT { - GECMR_1000B = 0x01, GECMR_100B = 0x40, GECMR_10B = 0x00, + GECMR_1000B = 0x01, GECMR_100B = 0x04, GECMR_10B = 0x00, }; /* EDRRR*/ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 648c94cbb..9cc4fce00 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -34,21 +34,24 @@ #endif #if defined (CONFIG_DRIVER_SMC911X_32_BIT) -static inline u32 reg_read(u32 addr) +static inline u32 __smc911x_reg_read(u32 addr) { return *(volatile u32*)addr; } -static inline void reg_write(u32 addr, u32 val) +u32 smc911x_reg_read(u32 addr) __attribute__((weak, alias("__smc911x_reg_read"))); + +static inline void __smc911x_reg_write(u32 addr, u32 val) { *(volatile u32*)addr = val; } +void smc911x_reg_write(u32 addr, u32 val) __attribute__((weak, alias("__smc911x_reg_write"))); #elif defined (CONFIG_DRIVER_SMC911X_16_BIT) -static inline u32 reg_read(u32 addr) +static inline u32 smc911x_reg_read(u32 addr) { volatile u16 *addr_16 = (u16 *)addr; return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16)); } -static inline void reg_write(u32 addr, u32 val) +static inline void smc911x_reg_write(u32 addr, u32 val) { *(volatile u16*)addr = (u16)val; *(volatile u16*)(addr + 2) = (u16)(val >> 16); @@ -58,9 +61,9 @@ static inline void reg_write(u32 addr, u32 val) #endif /* CONFIG_DRIVER_SMC911X_16_BIT */ u32 pkt_data_pull(u32 addr) \ - __attribute__ ((weak, alias ("reg_read"))); + __attribute__ ((weak, alias ("smc911x_reg_read"))); void pkt_data_push(u32 addr, u32 val) \ - __attribute__ ((weak, alias ("reg_write"))); + __attribute__ ((weak, alias ("smc911x_reg_write"))); #define mdelay(n) udelay((n)*1000) @@ -381,6 +384,7 @@ void pkt_data_push(u32 addr, u32 val) \ #define CHIP_9116 0x116 #define CHIP_9117 0x117 #define CHIP_9118 0x118 +#define CHIP_9211 0x9211 #define CHIP_9215 0x115a #define CHIP_9216 0x116a #define CHIP_9217 0x117a @@ -396,6 +400,7 @@ static const struct chip_id chip_ids[] = { { CHIP_9116, "LAN9116" }, { CHIP_9117, "LAN9117" }, { CHIP_9118, "LAN9118" }, + { CHIP_9211, "LAN9211" }, { CHIP_9215, "LAN9215" }, { CHIP_9216, "LAN9216" }, { CHIP_9217, "LAN9217" }, @@ -407,22 +412,22 @@ static const struct chip_id chip_ids[] = { u32 smc911x_get_mac_csr(u8 reg) { - while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); - while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - return reg_read(MAC_CSR_DATA); + return smc911x_reg_read(MAC_CSR_DATA); } void smc911x_set_mac_csr(u8 reg, u32 data) { - while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - reg_write(MAC_CSR_DATA, data); - reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); - while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + smc911x_reg_write(MAC_CSR_DATA, data); + smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; } @@ -496,10 +501,10 @@ static int smc911x_phy_reset(void) { u32 reg; - reg = reg_read(PMT_CTRL); + reg = smc911x_reg_read(PMT_CTRL); reg &= ~0xfffff030; reg |= PMT_CTRL_PHY_RST; - reg_write(PMT_CTRL, reg); + smc911x_reg_write(PMT_CTRL, reg); mdelay(100); @@ -541,13 +546,13 @@ static void smc911x_reset(void) int timeout; /* Take out of PM setting first */ - if (reg_read(PMT_CTRL) & PMT_CTRL_READY) { + if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) { /* Write to the bytetest will take out of powerdown */ - reg_write(BYTE_TEST, 0x0); + smc911x_reg_write(BYTE_TEST, 0x0); timeout = 10; - while (timeout-- && !(reg_read(PMT_CTRL) & PMT_CTRL_READY)) + while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY)) udelay(10); if (!timeout) { printf(DRIVERNAME @@ -557,12 +562,12 @@ static void smc911x_reset(void) } /* Disable interrupts */ - reg_write(INT_EN, 0); + smc911x_reg_write(INT_EN, 0); - reg_write(HW_CFG, HW_CFG_SRST); + smc911x_reg_write(HW_CFG, HW_CFG_SRST); timeout = 1000; - while (timeout-- && reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) + while (timeout-- && smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) udelay(10); if (!timeout) { @@ -572,23 +577,23 @@ static void smc911x_reset(void) /* Reset the FIFO level and flow control settings */ smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN); - reg_write(AFC_CFG, 0x0050287F); + smc911x_reg_write(AFC_CFG, 0x0050287F); /* Set to LED outputs */ - reg_write(GPIO_CFG, 0x70070000); + smc911x_reg_write(GPIO_CFG, 0x70070000); } static void smc911x_enable(void) { /* Enable TX */ - reg_write(HW_CFG, 8 << 16 | HW_CFG_SF); + smc911x_reg_write(HW_CFG, 8 << 16 | HW_CFG_SF); - reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000); + smc911x_reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000); - reg_write(TX_CFG, TX_CFG_TX_ON); + smc911x_reg_write(TX_CFG, TX_CFG_TX_ON); /* no padding to start of packets */ - reg_write(RX_CFG, 0); + smc911x_reg_write(RX_CFG, 0); smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); @@ -600,13 +605,13 @@ int eth_init(bd_t *bd) printf(DRIVERNAME ": initializing\n"); - val = reg_read(BYTE_TEST); + val = smc911x_reg_read(BYTE_TEST); if (val != 0x87654321) { printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val); goto err_out; } - val = reg_read(ID_REV) >> 16; + val = smc911x_reg_read(ID_REV) >> 16; for (i = 0; chip_ids[i].id != 0; i++) { if (chip_ids[i].id == val) break; } @@ -640,8 +645,8 @@ int eth_send(volatile void *packet, int length) u32 tmplen; u32 status; - reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); - reg_write(TX_DATA_FIFO, length); + smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); + smc911x_reg_write(TX_DATA_FIFO, length); tmplen = (length + 3) / 4; @@ -649,12 +654,12 @@ int eth_send(volatile void *packet, int length) pkt_data_push(TX_DATA_FIFO, *data++); /* wait for transmission */ - while (!((reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); + while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); /* get status. Ignore 'no carrier' error, it has no meaning for * full duplex operation */ - status = reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | + status = smc911x_reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN); if (!status) @@ -681,11 +686,11 @@ int eth_rx(void) u32 pktlen, tmplen; u32 status; - if ((reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { - status = reg_read(RX_STATUS_FIFO); + if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { + status = smc911x_reg_read(RX_STATUS_FIFO); pktlen = (status & RX_STS_PKT_LEN) >> 16; - reg_write(RX_CFG, 0); + smc911x_reg_write(RX_CFG, 0); tmplen = (pktlen + 2+ 3) / 4; while (tmplen--) diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index fbc9a6dd0..9edba6a7b 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -158,6 +158,7 @@ int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info) /* Reset the MAC */ priv->regs->maccfg1 |= MACCFG1_SOFT_RESET; + udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ @@ -1141,6 +1142,9 @@ struct phy_info phy_info_M88E1118 = { {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, {0x16, 0x0002, NULL}, /* Change Page Number */ {0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */ + {0x16, 0x0003, NULL}, /* Change Page Number */ + {0x10, 0x021e, NULL}, /* Adjust LED control */ + {0x16, 0x0000, NULL}, /* Change Page Number */ {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, @@ -1152,6 +1156,7 @@ struct phy_info phy_info_M88E1118 = { /* Status is read once to clear old link state */ {MIIM_STATUS, miim_read, NULL}, /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, /* Read the status */ {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, |