From e1957ef02c0d949c27f7386e5fa509a57e033d5a Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Mon, 9 Nov 2009 13:09:45 -0600 Subject: tsec: Make functions/data static when possible This is generally good practice and saves ~150 bytes. Signed-off-by: Peter Tyser Signed-off-by: Ben Warren --- include/tsec.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/tsec.h b/include/tsec.h index f56723a1535..29e4c56d6cb 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -644,7 +644,6 @@ struct tsec_info_struct { u32 flags; }; -int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info); int tsec_standard_init(bd_t *bis); int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsec_info, int num); -- cgit v1.3.1 From 8abb8dcc8d6f2a9e31551a6fa41de97bd1f15350 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Mon, 9 Nov 2009 13:09:47 -0600 Subject: tsec: Add support for using the BCM5482 PHY in fiber mode The BCM5482 PHY supports both copper and fiber as an ethernet medium. By enabling its copper/fiber mode auto-detection feature it can dynamically determine if it should be configured for copper or fiber. Signed-off-by: Peter Tyser Signed-off-by: Ben Warren --- drivers/net/tsec.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++-- include/tsec.h | 13 +++++++ 2 files changed, 119 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 6a444186880..7600e40de90 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -530,8 +530,105 @@ static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv) } return 0; +} +/* + * Find out if PHY is in copper or serdes mode by looking at Expansion Reg + * 0x42 - "Operating Mode Status Register" + */ +static int BCM8482_is_serdes(struct tsec_private *priv) +{ + u16 val; + int serdes = 0; + + write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); + + switch (val & 0x1f) { + case 0x0d: /* RGMII-to-100Base-FX */ + case 0x0e: /* RGMII-to-SGMII */ + case 0x0f: /* RGMII-to-SerDes */ + case 0x12: /* SGMII-to-SerDes */ + case 0x13: /* SGMII-to-100Base-FX */ + case 0x16: /* SerDes-to-Serdes */ + serdes = 1; + break; + case 0x6: /* RGMII-to-Copper */ + case 0x14: /* SGMII-to-Copper */ + case 0x17: /* SerDes-to-Copper */ + break; + default: + printf("ERROR, invalid PHY mode (0x%x\n)", val); + break; + } + + return serdes; } + +/* + * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating + * Mode Status Register" + */ +uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv) +{ + u16 val; + int i = 0; + + /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ + while (1) { + write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); + + if (val & 0x8000) + break; + + if (i++ > 1000) { + priv->link = 0; + return 1; + } + + udelay(1000); /* 1 ms */ + } + + priv->link = 1; + switch ((val >> 13) & 0x3) { + case (0x00): + priv->speed = 10; + break; + case (0x01): + priv->speed = 100; + break; + case (0x02): + priv->speed = 1000; + break; + } + + priv->duplexity = (val & 0x1000) == 0x1000; + + return 0; +} + +/* + * Figure out if BCM5482 is in serdes or copper mode and determine link + * configuration accordingly + */ +static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv) +{ + if (BCM8482_is_serdes(priv)) { + mii_parse_BCM5482_serdes_sr(priv); + } else { + /* Wait for auto-negotiation to complete or fail */ + mii_parse_sr(mii_reg, priv); + + /* Parse BCM54xx copper aux status register */ + mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS); + mii_parse_BCM54xx_sr(mii_reg, priv); + } + + return 0; +} + /* Parse the 88E1011's status register for speed and duplex * information */ @@ -1091,15 +1188,20 @@ static struct phy_info phy_info_BCM5482S = { /* Read Misc Control register and or in Ethernet@Wirespeed */ {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + /* Initial config/enable of secondary SerDes interface */ + {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL}, + /* Write intial value to secondary SerDes Contol */ + {MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL}, + {MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL}, + /* Enable copper/fiber auto-detect */ + {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)}, {miim_end,} }, (struct phy_cmd[]) { /* startup */ /* 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_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, + /* Determine copper/fiber, auto-negotiate, and read the result */ + {MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr}, {miim_end,} }, (struct phy_cmd[]) { /* shutdown */ diff --git a/include/tsec.h b/include/tsec.h index 29e4c56d6cb..b2e37d4323b 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -153,6 +153,19 @@ #define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700 #define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8 +#define MIIM_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ +#define MIIM_BCM54XX_SHD_WRITE 0x8000 +#define MIIM_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) +#define MIIM_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) +#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data) \ + (MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \ + MIIM_BCM54XX_SHD_DATA(data)) + +#define MIIM_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ +#define MIIM_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ +#define MIIM_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ + /* Cicada Auxiliary Control/Status Register */ #define MIIM_CIS8201_AUX_CONSTAT 0x1c #define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004 -- cgit v1.3.1 From 5f6b1442218fcb6a3ef0d2be05d84119cebfe0ae Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Mon, 9 Nov 2009 13:09:48 -0600 Subject: tsec: Add TSEC_FIBER flag The TSEC_FIBER flag should be set when a PHY is operating with an external fiber interface. Currently it is only used to notify a user that the PHY is operating in fiber mode. A short description was also added to the other TSEC flag defines so that it is clear how they differ from one another. Signed-off-by: Peter Tyser Signed-off-by: Ben Warren --- drivers/net/tsec.c | 6 ++++-- include/tsec.h | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 7600e40de90..fd49eff183d 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -617,6 +617,7 @@ static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv) { if (BCM8482_is_serdes(priv)) { mii_parse_BCM5482_serdes_sr(priv); + priv->flags |= TSEC_FIBER; } else { /* Wait for auto-negotiation to complete or fail */ mii_parse_sr(mii_reg, priv); @@ -940,8 +941,9 @@ static void adjust_link(struct eth_device *dev) break; } - printf("Speed: %d, %s duplex\n", priv->speed, - (priv->duplexity) ? "full" : "half"); + printf("Speed: %d, %s duplex%s\n", priv->speed, + (priv->duplexity) ? "full" : "half", + (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); } else { printf("%s: No link.\n", dev->name); diff --git a/include/tsec.h b/include/tsec.h index b2e37d4323b..1e903659eba 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -584,9 +584,9 @@ typedef struct tsec /* This flag currently only has * meaning if we're using the eTSEC */ -#define TSEC_REDUCED (1 << 1) - -#define TSEC_SGMII (1 << 2) +#define TSEC_REDUCED (1 << 1) /* MAC-PHY interface uses RGMII */ +#define TSEC_SGMII (1 << 2) /* MAC-PHY interface uses SGMII */ +#define TSEC_FIBER (1 << 3) /* PHY uses fiber, eg 1000 Base-X */ struct tsec_private { volatile tsec_t *regs; -- cgit v1.3.1 From d7e354374c8eb0a5d8b8226b881c5ee276c77a60 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 18 Dec 2009 13:33:07 +0000 Subject: TI: DaVinci: Updating EMAC driver for DM365, DM646x and DA8XX The EMAC IP on DM365, DM646x and DA830 is slightly different from that on DM644x. This change updates the DaVinci EMAC driver so that EMAC becomes operational on SOCs with EMAC v2. Signed-off-by: Nick Thompson Signed-off-by: Ben Warren --- drivers/net/davinci_emac.c | 266 ++++++++++++++++++++----------- include/asm-arm/arch-davinci/emac_defs.h | 59 ++++++- 2 files changed, 226 insertions(+), 99 deletions(-) (limited to 'include') diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index fa8cee4d2ef..02bbb8c0aff 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -42,10 +42,17 @@ #include #include #include +#include unsigned int emac_dbg = 0; #define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) +#ifdef DAVINCI_EMAC_GIG_ENABLE +#define emac_gigabit_enable() davinci_eth_gigabit_enable() +#else +#define emac_gigabit_enable() /* no gigabit to enable */ +#endif + static void davinci_eth_mdio_enable(void); static int gen_init_phy(int phy_addr); @@ -99,12 +106,14 @@ static void davinci_eth_mdio_enable(void) clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; - adap_mdio->CONTROL = (clkdiv & 0xff) | - MDIO_CONTROL_ENABLE | - MDIO_CONTROL_FAULT | - MDIO_CONTROL_FAULT_ENABLE; + writel((clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE, + &adap_mdio->CONTROL); - while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} + while (readl(&adap_mdio->CONTROL) & MDIO_CONTROL_IDLE) + ; } /* @@ -119,7 +128,8 @@ static int davinci_eth_phy_detect(void) active_phy_addr = 0xff; - if ((phy_act_state = adap_mdio->ALIVE) == 0) + phy_act_state = readl(&adap_mdio->ALIVE) & EMAC_MDIO_PHY_MASK; + if (phy_act_state == 0) return(0); /* No active PHYs */ debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); @@ -144,15 +154,18 @@ int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) { int tmp; - while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) + ; - adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_READ | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16); + writel(MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16), + &adap_mdio->USERACCESS0); /* Wait for command to complete */ - while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} + while ((tmp = readl(&adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO) + ; if (tmp & MDIO_USERACCESS0_ACK) { *data = tmp & 0xffff; @@ -167,16 +180,19 @@ int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) { - while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) + ; - adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_WRITE | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16) | - (data & 0xffff); + writel(MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff), + &adap_mdio->USERACCESS0); /* Wait for command to complete */ - while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) + ; return(1); } @@ -245,9 +261,24 @@ static int davinci_mii_phy_write(char *devname, unsigned char addr, unsigned cha { return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1); } - #endif +static void __attribute__((unused)) davinci_eth_gigabit_enable(void) +{ + u_int16_t data; + + if (davinci_eth_phy_read(EMAC_MDIO_PHY_NUM, 0, &data)) { + if (data & (1 << 6)) { /* speed selection MSB */ + /* + * Check if link detected is giga-bit + * If Gigabit mode detected, enable gigbit in MAC + */ + writel(EMAC_MACCONTROL_GIGFORCE | + EMAC_MACCONTROL_GIGABIT_ENABLE, + &adap_emac->MACCONTROL); + } + } +} /* Eth device open */ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) @@ -255,64 +286,73 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) dv_reg_p addr; u_int32_t clkdiv, cnt; volatile emac_desc *rx_desc; + unsigned long mac_hi; + unsigned long mac_lo; debug_emac("+ emac_open\n"); /* Reset EMAC module and disable interrupts in wrapper */ - adap_emac->SOFTRESET = 1; - while (adap_emac->SOFTRESET != 0) {;} - adap_ewrap->EWCTL = 0; + writel(1, &adap_emac->SOFTRESET); + while (readl(&adap_emac->SOFTRESET) != 0) + ; +#if defined(DAVINCI_EMAC_VERSION2) + writel(1, &adap_ewrap->softrst); + while (readl(&adap_ewrap->softrst) != 0) + ; +#else + writel(0, &adap_ewrap->EWCTL); for (cnt = 0; cnt < 5; cnt++) { - clkdiv = adap_ewrap->EWCTL; + clkdiv = readl(&adap_ewrap->EWCTL); } +#endif rx_desc = emac_rx_desc; - adap_emac->TXCONTROL = 0x01; - adap_emac->RXCONTROL = 0x01; + writel(1, &adap_emac->TXCONTROL); + writel(1, &adap_emac->RXCONTROL); /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ /* Using channel 0 only - other channels are disabled */ - adap_emac->MACINDEX = 0; - adap_emac->MACADDRHI = - (davinci_eth_mac_addr[3] << 24) | - (davinci_eth_mac_addr[2] << 16) | - (davinci_eth_mac_addr[1] << 8) | - (davinci_eth_mac_addr[0]); - adap_emac->MACADDRLO = - (davinci_eth_mac_addr[5] << 8) | - (davinci_eth_mac_addr[4]); - - adap_emac->MACHASH1 = 0; - adap_emac->MACHASH2 = 0; + writel(0, &adap_emac->MACINDEX); + mac_hi = (davinci_eth_mac_addr[3] << 24) | + (davinci_eth_mac_addr[2] << 16) | + (davinci_eth_mac_addr[1] << 8) | + (davinci_eth_mac_addr[0]); + mac_lo = (davinci_eth_mac_addr[5] << 8) | + (davinci_eth_mac_addr[4]); + + writel(mac_hi, &adap_emac->MACADDRHI); +#if defined(DAVINCI_EMAC_VERSION2) + writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH, + &adap_emac->MACADDRLO); +#else + writel(mac_lo, &adap_emac->MACADDRLO); +#endif + + writel(0, &adap_emac->MACHASH1); + writel(0, &adap_emac->MACHASH2); /* Set source MAC address - REQUIRED */ - adap_emac->MACSRCADDRHI = - (davinci_eth_mac_addr[3] << 24) | - (davinci_eth_mac_addr[2] << 16) | - (davinci_eth_mac_addr[1] << 8) | - (davinci_eth_mac_addr[0]); - adap_emac->MACSRCADDRLO = - (davinci_eth_mac_addr[4] << 8) | - (davinci_eth_mac_addr[5]); + writel(mac_hi, &adap_emac->MACSRCADDRHI); + writel(mac_lo, &adap_emac->MACSRCADDRLO); /* Set DMA 8 TX / 8 RX Head pointers to 0 */ addr = &adap_emac->TX0HDP; for(cnt = 0; cnt < 16; cnt++) - *addr++ = 0; + writel(0, addr++); addr = &adap_emac->RX0HDP; for(cnt = 0; cnt < 16; cnt++) - *addr++ = 0; + writel(0, addr++); /* Clear Statistics (do this before setting MacControl register) */ addr = &adap_emac->RXGOODFRAMES; for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) - *addr++ = 0; + writel(0, addr++); /* No multicast addressing */ - adap_emac->MACHASH1 = 0; - adap_emac->MACHASH2 = 0; + writel(0, &adap_emac->MACHASH1); + writel(0, &adap_emac->MACHASH2); /* Create RX queue and set receive process in place */ emac_rx_active_head = emac_rx_desc; @@ -324,34 +364,52 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) rx_desc++; } - /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ + /* Finalize the rx desc list */ rx_desc--; rx_desc->next = 0; emac_rx_active_tail = rx_desc; emac_rx_queue_active = 1; /* Enable TX/RX */ - adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; - adap_emac->RXBUFFEROFFSET = 0; + writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN); + writel(0, &adap_emac->RXBUFFEROFFSET); - /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ - adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; + /* + * No fancy configs - Use this for promiscous debug + * - EMAC_RXMBPENABLE_RXCAFEN_ENABLE + */ + writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE); /* Enable ch 0 only */ - adap_emac->RXUNICASTSET = 0x01; + writel(1, &adap_emac->RXUNICASTSET); /* Enable MII interface and Full duplex mode */ - adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE); +#ifdef CONFIG_SOC_DA8XX + writel((EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE | + EMAC_MACCONTROL_RMIISPEED_100), + &adap_emac->MACCONTROL); +#else + writel((EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE), + &adap_emac->MACCONTROL); +#endif /* Init MDIO & get link state */ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; - adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); + writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT, + &adap_mdio->CONTROL); + + /* We need to wait for MDIO to start */ + udelay(1000); if (!phy.get_link_speed(active_phy_addr)) return(0); + emac_gigabit_enable(); + /* Start receive process */ - adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; + writel((u_int32_t)emac_rx_desc, &adap_emac->RX0HDP); debug_emac("- emac_open\n"); @@ -368,34 +426,42 @@ static void davinci_eth_ch_teardown(int ch) if (ch == EMAC_CH_TX) { /* Init TX channel teardown */ - adap_emac->TXTEARDOWN = 1; - for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { - /* Wait here for Tx teardown completion interrupt to occur - * Note: A task delay can be called here to pend rather than - * occupying CPU cycles - anyway it has been found that teardown - * takes very few cpu cycles and does not affect functionality */ - dly--; - udelay(1); - if (dly == 0) + writel(1, &adap_emac->TXTEARDOWN); + do { + /* + * Wait here for Tx teardown completion interrupt to + * occur. Note: A task delay can be called here to pend + * rather than occupying CPU cycles - anyway it has + * been found that teardown takes very few cpu cycles + * and does not affect functionality + */ + dly--; + udelay(1); + if (dly == 0) break; - } - adap_emac->TX0CP = cnt; - adap_emac->TX0HDP = 0; + cnt = readl(&adap_emac->TX0CP); + } while (cnt != 0xfffffffc); + writel(cnt, &adap_emac->TX0CP); + writel(0, &adap_emac->TX0HDP); } else { /* Init RX channel teardown */ - adap_emac->RXTEARDOWN = 1; - for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { - /* Wait here for Rx teardown completion interrupt to occur - * Note: A task delay can be called here to pend rather than - * occupying CPU cycles - anyway it has been found that teardown - * takes very few cpu cycles and does not affect functionality */ - dly--; - udelay(1); - if (dly == 0) + writel(1, &adap_emac->RXTEARDOWN); + do { + /* + * Wait here for Rx teardown completion interrupt to + * occur. Note: A task delay can be called here to pend + * rather than occupying CPU cycles - anyway it has + * been found that teardown takes very few cpu cycles + * and does not affect functionality + */ + dly--; + udelay(1); + if (dly == 0) break; - } - adap_emac->RX0CP = cnt; - adap_emac->RX0HDP = 0; + cnt = readl(&adap_emac->RX0CP); + } while (cnt != 0xfffffffc); + writel(cnt, &adap_emac->RX0CP); + writel(0, &adap_emac->RX0HDP); } debug_emac("- emac_ch_teardown\n"); @@ -410,8 +476,12 @@ static void davinci_eth_close(struct eth_device *dev) davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ /* Reset EMAC module and disable interrupts in wrapper */ - adap_emac->SOFTRESET = 1; - adap_ewrap->EWCTL = 0; + writel(1, &adap_emac->SOFTRESET); +#if defined(DAVINCI_EMAC_VERSION2) + writel(1, &adap_ewrap->softrst); +#else + writel(0, &adap_ewrap->EWCTL); +#endif debug_emac("- emac_close\n"); } @@ -435,6 +505,8 @@ static int davinci_eth_send_packet (struct eth_device *dev, return (ret_status); } + emac_gigabit_enable(); + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { length = EMAC_MIN_ETHERNET_PKT_SIZE; @@ -449,7 +521,7 @@ static int davinci_eth_send_packet (struct eth_device *dev, EMAC_CPPI_OWNERSHIP_BIT | EMAC_CPPI_EOP_BIT); /* Send the packet */ - adap_emac->TX0HDP = (unsigned int) emac_tx_desc; + writel((unsigned long)emac_tx_desc, &adap_emac->TX0HDP); /* Wait for packet to complete or link down */ while (1) { @@ -457,7 +529,10 @@ static int davinci_eth_send_packet (struct eth_device *dev, davinci_eth_ch_teardown (EMAC_CH_TX); return (ret_status); } - if (adap_emac->TXINTSTATRAW & 0x01) { + + emac_gigabit_enable(); + + if (readl(&adap_emac->TXINTSTATRAW) & 0x01) { ret_status = length; break; } @@ -490,15 +565,15 @@ static int davinci_eth_rcv_packet (struct eth_device *dev) } /* Ack received packet descriptor */ - adap_emac->RX0CP = (unsigned int) rx_curr_desc; + writel((unsigned long)rx_curr_desc, &adap_emac->RX0CP); curr_desc = rx_curr_desc; emac_rx_active_head = (volatile emac_desc *) rx_curr_desc->next; if (status & EMAC_CPPI_EOQ_BIT) { if (emac_rx_active_head) { - adap_emac->RX0HDP = - (unsigned int) emac_rx_active_head; + writel((unsigned long)emac_rx_active_head, + &adap_emac->RX0HDP); } else { emac_rx_queue_active = 0; printf ("INFO:emac_rcv_packet: RX Queue not active\n"); @@ -515,8 +590,8 @@ static int davinci_eth_rcv_packet (struct eth_device *dev) emac_rx_active_head = curr_desc; emac_rx_active_tail = curr_desc; if (emac_rx_queue_active != 0) { - adap_emac->RX0HDP = - (unsigned int) emac_rx_active_head; + writel((unsigned long)emac_rx_active_head, + &adap_emac->RX0HDP); printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); emac_rx_queue_active = 1; } @@ -526,7 +601,8 @@ static int davinci_eth_rcv_packet (struct eth_device *dev) tail_desc->next = (unsigned int) curr_desc; status = tail_desc->pkt_flag_len; if (status & EMAC_CPPI_EOQ_BIT) { - adap_emac->RX0HDP = (unsigned int) curr_desc; + writel((unsigned long)curr_desc, + &adap_emac->RX0HDP); status &= ~EMAC_CPPI_EOQ_BIT; tail_desc->pkt_flag_len = status; } @@ -566,7 +642,7 @@ int davinci_emac_initialize(void) davinci_eth_mdio_enable(); for (i = 0; i < 256; i++) { - if (adap_mdio->ALIVE) + if (readl(&adap_mdio->ALIVE)) break; udelay(10); } diff --git a/include/asm-arm/arch-davinci/emac_defs.h b/include/asm-arm/arch-davinci/emac_defs.h index 96bc80e4769..e313263ffb0 100644 --- a/include/asm-arm/arch-davinci/emac_defs.h +++ b/include/asm-arm/arch-davinci/emac_defs.h @@ -43,6 +43,13 @@ #define EMAC_WRAPPER_BASE_ADDR (0x01d0a000) #define EMAC_WRAPPER_RAM_ADDR (0x01d08000) #define EMAC_MDIO_BASE_ADDR (0x01d0b000) +#define DAVINCI_EMAC_VERSION2 +#elif defined(CONFIG_SOC_DA8XX) +#define EMAC_BASE_ADDR DAVINCI_EMAC_CNTRL_REGS_BASE +#define EMAC_WRAPPER_BASE_ADDR DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE +#define EMAC_WRAPPER_RAM_ADDR DAVINCI_EMAC_WRAPPER_RAM_BASE +#define EMAC_MDIO_BASE_ADDR DAVINCI_MDIO_CNTRL_REGS_BASE +#define DAVINCI_EMAC_VERSION2 #else #define EMAC_BASE_ADDR (0x01c80000) #define EMAC_WRAPPER_BASE_ADDR (0x01c81000) @@ -50,6 +57,11 @@ #define EMAC_MDIO_BASE_ADDR (0x01c84000) #endif +#ifdef CONFIG_SOC_DM646X +#define DAVINCI_EMAC_VERSION2 +#define DAVINCI_EMAC_GIG_ENABLE +#endif + #ifdef CONFIG_SOC_DM646X /* MDIO module input frequency */ #define EMAC_MDIO_BUS_FREQ 76500000 @@ -60,6 +72,11 @@ #define EMAC_MDIO_BUS_FREQ 121500000 /* MDIO clock output frequency */ #define EMAC_MDIO_CLOCK_FREQ 2200000 /* 2.2 MHz */ +#elif defined(CONFIG_SOC_DA8XX) +/* MDIO module input frequency */ +#define EMAC_MDIO_BUS_FREQ clk_get(DAVINCI_MDIO_CLKID) +/* MDIO clock output frequency */ +#define EMAC_MDIO_CLOCK_FREQ 2000000 /* 2.0 MHz */ #else /* MDIO module input frequency */ #define EMAC_MDIO_BUS_FREQ 99000000 /* PLL/6 - 99 MHz */ @@ -128,6 +145,10 @@ typedef volatile struct _emac_desc #define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1) #define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7) #define EMAC_MACCONTROL_GIGFORCE (1 << 17) +#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15) + +#define EMAC_MAC_ADDR_MATCH (1 << 19) +#define EMAC_MAC_ADDR_IS_VALID (1 << 20) #define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000) #define EMAC_RXMBPENABLE_RXBROADEN (0x2000) @@ -283,10 +304,40 @@ typedef struct { /* EMAC Wrapper Registers Structure */ typedef struct { -#if defined(CONFIG_SOC_DM646X) || defined(CONFIG_SOC_DM365) - dv_reg IDVER; - dv_reg SOFTRST; - dv_reg EMCTRL; +#ifdef DAVINCI_EMAC_VERSION2 + dv_reg idver; + dv_reg softrst; + dv_reg emctrl; + dv_reg c0rxthreshen; + dv_reg c0rxen; + dv_reg c0txen; + dv_reg c0miscen; + dv_reg c1rxthreshen; + dv_reg c1rxen; + dv_reg c1txen; + dv_reg c1miscen; + dv_reg c2rxthreshen; + dv_reg c2rxen; + dv_reg c2txen; + dv_reg c2miscen; + dv_reg c0rxthreshstat; + dv_reg c0rxstat; + dv_reg c0txstat; + dv_reg c0miscstat; + dv_reg c1rxthreshstat; + dv_reg c1rxstat; + dv_reg c1txstat; + dv_reg c1miscstat; + dv_reg c2rxthreshstat; + dv_reg c2rxstat; + dv_reg c2txstat; + dv_reg c2miscstat; + dv_reg c0rximax; + dv_reg c0tximax; + dv_reg c1rximax; + dv_reg c1tximax; + dv_reg c2rximax; + dv_reg c2tximax; #else u_int8_t RSVD0[4100]; dv_reg EWCTL; -- cgit v1.3.1 From 582c55a0274f38e6e7e35b95e7ab81d3e912f700 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 20 Jan 2010 09:04:28 +0100 Subject: 83xx, uec: split enet_interface in two variables There's no sensible reason to unite speed and interface type into one variable. So split this variable enet_interface into two vars: enet_interface_type, which hold the interface type and speed. Also: add the possibility for switching between 10 and 100 MBit interfaces on the fly, when running in FAST_ETH mode. Signed-off-by: Heiko Schocher Signed-off-by: Ben Warren --- board/freescale/mpc8360emds/mpc8360emds.c | 3 +- drivers/qe/uec.c | 122 +++++++++++++++++------------- drivers/qe/uec.h | 34 ++++----- drivers/qe/uec_phy.c | 84 ++++++++++---------- include/configs/MPC8323ERDB.h | 6 +- include/configs/MPC832XEMDS.h | 6 +- include/configs/MPC8360EMDS.h | 6 +- include/configs/MPC8360ERDK.h | 6 +- include/configs/MPC8568MDS.h | 6 +- include/configs/MPC8569MDS.h | 30 +++++--- include/configs/kmeter1.h | 3 +- 11 files changed, 175 insertions(+), 131 deletions(-) (limited to 'include') diff --git a/board/freescale/mpc8360emds/mpc8360emds.c b/board/freescale/mpc8360emds/mpc8360emds.c index d4ba043b283..4f557329f48 100644 --- a/board/freescale/mpc8360emds/mpc8360emds.c +++ b/board/freescale/mpc8360emds/mpc8360emds.c @@ -159,7 +159,8 @@ int board_eth_init(bd_t *bd) int i; for (i = 0; i < ARRAY_SIZE(uec_info); i++) - uec_info[i].enet_interface = ENET_1000_RGMII_RXID; + uec_info[i].enet_interface_type = RGMII_RXID; + uec_info[i].speed = 1000; } return uec_eth_init(bd, uec_info, ARRAY_SIZE(uec_info)); } diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index db95adaeef9..27dc5009c80 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -323,9 +323,10 @@ static int uec_set_mac_duplex(uec_private_t *uec, int duplex) return 0; } -static int uec_set_mac_if_mode(uec_private_t *uec, enet_interface_e if_mode) +static int uec_set_mac_if_mode(uec_private_t *uec, + enet_interface_type_e if_mode, int speed) { - enet_interface_e enet_if_mode; + enet_interface_type_e enet_if_mode; uec_info_t *uec_info; uec_t *uec_regs; u32 upsmr; @@ -346,52 +347,68 @@ static int uec_set_mac_if_mode(uec_private_t *uec, enet_interface_e if_mode) upsmr = in_be32(&uec->uccf->uf_regs->upsmr); upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM); - switch (enet_if_mode) { - case ENET_100_MII: - case ENET_10_MII: + switch (speed) { + case 10: maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + switch (enet_if_mode) { + case MII: + break; + case RGMII: + upsmr |= (UPSMR_RPM | UPSMR_R10M); + break; + case RMII: + upsmr |= (UPSMR_R10M | UPSMR_RMM); + break; + default: + return -EINVAL; + break; + } break; - case ENET_1000_GMII: - maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; - break; - case ENET_1000_TBI: - maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; - upsmr |= UPSMR_TBIM; - break; - case ENET_1000_RTBI: - maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; - upsmr |= (UPSMR_RPM | UPSMR_TBIM); - break; - case ENET_1000_RGMII_RXID: - case ENET_1000_RGMII_ID: - case ENET_1000_RGMII: - maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; - upsmr |= UPSMR_RPM; - break; - case ENET_100_RGMII: - maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - upsmr |= UPSMR_RPM; - break; - case ENET_10_RGMII: - maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - upsmr |= (UPSMR_RPM | UPSMR_R10M); - break; - case ENET_100_RMII: - maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - upsmr |= UPSMR_RMM; - break; - case ENET_10_RMII: + case 100: maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - upsmr |= (UPSMR_R10M | UPSMR_RMM); + switch (enet_if_mode) { + case MII: + break; + case RGMII: + upsmr |= UPSMR_RPM; + break; + case RMII: + upsmr |= UPSMR_RMM; + break; + default: + return -EINVAL; + break; + } break; - case ENET_1000_SGMII: + case 1000: maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; - upsmr |= UPSMR_SGMM; + switch (enet_if_mode) { + case GMII: + break; + case TBI: + upsmr |= UPSMR_TBIM; + break; + case RTBI: + upsmr |= (UPSMR_RPM | UPSMR_TBIM); + break; + case RGMII_RXID: + case RGMII_ID: + case RGMII: + upsmr |= UPSMR_RPM; + break; + case SGMII: + upsmr |= UPSMR_SGMM; + break; + default: + return -EINVAL; + break; + } break; default: return -EINVAL; break; } + out_be32(&uec_regs->maccfg2, maccfg2); out_be32(&uec->uccf->uf_regs->upsmr, upsmr); @@ -504,7 +521,7 @@ static void adjust_link(struct eth_device *dev) struct uec_mii_info *mii_info = uec->mii_info; extern void change_phy_interface_mode(struct eth_device *dev, - enet_interface_e mode); + enet_interface_type_e mode, int speed); uec_regs = uec->uec_regs; if (mii_info->link) { @@ -522,25 +539,19 @@ static void adjust_link(struct eth_device *dev) } if (mii_info->speed != uec->oldspeed) { + enet_interface_type_e mode = \ + uec->uec_info->enet_interface_type; if (uec->uec_info->uf_info.eth_type == GIGA_ETH) { switch (mii_info->speed) { case 1000: break; case 100: printf ("switching to rgmii 100\n"); - /* change phy to rgmii 100 */ - change_phy_interface_mode(dev, - ENET_100_RGMII); - /* change the MAC interface mode */ - uec_set_mac_if_mode(uec,ENET_100_RGMII); + mode = RGMII; break; case 10: printf ("switching to rgmii 10\n"); - /* change phy to rgmii 10 */ - change_phy_interface_mode(dev, - ENET_10_RGMII); - /* change the MAC interface mode */ - uec_set_mac_if_mode(uec,ENET_10_RGMII); + mode = RGMII; break; default: printf("%s: Ack,Speed(%d)is illegal\n", @@ -549,6 +560,11 @@ static void adjust_link(struct eth_device *dev) } } + /* change phy */ + change_phy_interface_mode(dev, mode, mii_info->speed); + /* change the MAC interface mode */ + uec_set_mac_if_mode(uec, mode, mii_info->speed); + printf("%s: Speed %dBT\n", dev->name, mii_info->speed); uec->oldspeed = mii_info->speed; } @@ -980,7 +996,6 @@ static int uec_startup(uec_private_t *uec) int num_threads_tx; int num_threads_rx; u32 utbipar; - enet_interface_e enet_interface; u32 length; u32 align; qe_bd_t *bd; @@ -1060,7 +1075,7 @@ static int uec_startup(uec_private_t *uec) out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE); /* Setup MAC interface mode */ - uec_set_mac_if_mode(uec, uec_info->enet_interface); + uec_set_mac_if_mode(uec, uec_info->enet_interface_type, uec_info->speed); /* Setup MII management base */ #ifndef CONFIG_eTSEC_MDIO_BUS @@ -1075,7 +1090,6 @@ static int uec_startup(uec_private_t *uec) /* Setup UTBIPAR */ utbipar = in_be32(&uec_regs->utbipar); utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; - enet_interface = uec->uec_info->enet_interface; /* Initialize UTBIPAR address to CONFIG_UTBIPAR_INIT_TBIPA for ALL UEC. * This frees up the remaining SMI addresses for use. @@ -1084,7 +1098,8 @@ static int uec_startup(uec_private_t *uec) out_be32(&uec_regs->utbipar, utbipar); /* Configure the TBI for SGMII operation */ - if (uec->uec_info->enet_interface == ENET_1000_SGMII) { + if ((uec->uec_info->enet_interface_type == SGMII) && + (uec->uec_info->speed == 1000)) { uec_write_phy_reg(uec->dev, uec_regs->utbipar, ENET_TBI_MII_ANA, TBIANA_SETTINGS); @@ -1215,6 +1230,7 @@ static int uec_init(struct eth_device* dev, bd_t *bd) if (err || i <= 0) printf("warning: %s: timeout on PHY link\n", dev->name); + adjust_link(dev); uec->the_first_run = 1; } diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h index febfbcef532..2a9e2dcd9c2 100644 --- a/drivers/qe/uec.h +++ b/drivers/qe/uec.h @@ -662,22 +662,18 @@ typedef enum uec_num_of_threads { /* UEC ethernet interface type */ -typedef enum enet_interface { - ENET_10_MII, - ENET_10_RMII, - ENET_10_RGMII, - ENET_100_MII, - ENET_100_RMII, - ENET_100_RGMII, - ENET_1000_GMII, - ENET_1000_RGMII, - ENET_1000_RGMII_ID, - ENET_1000_RGMII_RXID, - ENET_1000_RGMII_TXID, - ENET_1000_TBI, - ENET_1000_RTBI, - ENET_1000_SGMII -} enet_interface_e; +typedef enum enet_interface_type { + MII, + RMII, + RGMII, + GMII, + RGMII_ID, + RGMII_RXID, + RGMII_TXID, + TBI, + RTBI, + SGMII +} enet_interface_type_e; /* UEC initialization info struct */ @@ -696,7 +692,8 @@ typedef enum enet_interface { .tx_bd_ring_len = 16, \ .rx_bd_ring_len = 16, \ .phy_address = CONFIG_SYS_UEC##num##_PHY_ADDR, \ - .enet_interface = CONFIG_SYS_UEC##num##_INTERFACE_MODE, \ + .enet_interface_type = CONFIG_SYS_UEC##num##_INTERFACE_TYPE, \ + .speed = CONFIG_SYS_UEC##num##_INTERFACE_SPEED, \ } typedef struct uec_info { @@ -708,7 +705,8 @@ typedef struct uec_info { u16 rx_bd_ring_len; u16 tx_bd_ring_len; u8 phy_address; - enet_interface_e enet_interface; + enet_interface_type_e enet_interface_type; + int speed; } uec_info_t; /* UEC driver initialized info diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index 97151839428..c4214d9a0ae 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -401,7 +401,8 @@ static int bcm_init(struct uec_mii_info *mii_info) gbit_config_aneg(mii_info); - if (uec->uec_info->enet_interface == ENET_1000_RGMII_RXID) { + if ((uec->uec_info->enet_interface_type == RGMII_RXID) && + (uec->uec_info->speed == 1000)) { u16 val; int cnt = 50; @@ -429,20 +430,22 @@ static int marvell_init(struct uec_mii_info *mii_info) { struct eth_device *edev = mii_info->dev; uec_private_t *uec = edev->priv; - enum enet_interface iface = uec->uec_info->enet_interface; + enum enet_interface_type iface = uec->uec_info->enet_interface_type; + int speed = uec->uec_info->speed; - if (iface == ENET_1000_RGMII_ID || - iface == ENET_1000_RGMII_RXID || - iface == ENET_1000_RGMII_TXID) { + if ((speed == 1000) && + (iface == RGMII_ID || + iface == RGMII_RXID || + iface == RGMII_TXID)) { int temp; temp = phy_read(mii_info, MII_M1111_PHY_EXT_CR); - if (iface == ENET_1000_RGMII_ID) { + if (iface == RGMII_ID) { temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY; - } else if (iface == ENET_1000_RGMII_RXID) { + } else if (iface == RGMII_RXID) { temp &= ~MII_M1111_TX_DELAY; temp |= MII_M1111_RX_DELAY; - } else if (iface == ENET_1000_RGMII_TXID) { + } else if (iface == RGMII_TXID) { temp &= ~MII_M1111_RX_DELAY; temp |= MII_M1111_TX_DELAY; } @@ -795,7 +798,9 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) } void marvell_phy_interface_mode (struct eth_device *dev, - enet_interface_e mode) + enet_interface_type_e type, + int speed + ) { uec_private_t *uec = (uec_private_t *) dev->priv; struct uec_mii_info *mii_info; @@ -807,33 +812,35 @@ void marvell_phy_interface_mode (struct eth_device *dev, } mii_info = uec->mii_info; - if (mode == ENET_100_RGMII) { - phy_write (mii_info, 0x00, 0x9140); - phy_write (mii_info, 0x1d, 0x001f); - phy_write (mii_info, 0x1e, 0x200c); - phy_write (mii_info, 0x1d, 0x0005); - phy_write (mii_info, 0x1e, 0x0000); - phy_write (mii_info, 0x1e, 0x0100); - phy_write (mii_info, 0x09, 0x0e00); - phy_write (mii_info, 0x04, 0x01e1); - phy_write (mii_info, 0x00, 0x9140); - phy_write (mii_info, 0x00, 0x1000); - udelay (100000); - phy_write (mii_info, 0x00, 0x2900); - phy_write (mii_info, 0x14, 0x0cd2); - phy_write (mii_info, 0x00, 0xa100); - phy_write (mii_info, 0x09, 0x0000); - phy_write (mii_info, 0x1b, 0x800b); - phy_write (mii_info, 0x04, 0x05e1); - phy_write (mii_info, 0x00, 0xa100); - phy_write (mii_info, 0x00, 0x2100); - udelay (1000000); - } else if (mode == ENET_10_RGMII) { - phy_write (mii_info, 0x14, 0x8e40); - phy_write (mii_info, 0x1b, 0x800b); - phy_write (mii_info, 0x14, 0x0c82); - phy_write (mii_info, 0x00, 0x8100); - udelay (1000000); + if (type == RGMII) { + if (speed == 100) { + phy_write (mii_info, 0x00, 0x9140); + phy_write (mii_info, 0x1d, 0x001f); + phy_write (mii_info, 0x1e, 0x200c); + phy_write (mii_info, 0x1d, 0x0005); + phy_write (mii_info, 0x1e, 0x0000); + phy_write (mii_info, 0x1e, 0x0100); + phy_write (mii_info, 0x09, 0x0e00); + phy_write (mii_info, 0x04, 0x01e1); + phy_write (mii_info, 0x00, 0x9140); + phy_write (mii_info, 0x00, 0x1000); + udelay (100000); + phy_write (mii_info, 0x00, 0x2900); + phy_write (mii_info, 0x14, 0x0cd2); + phy_write (mii_info, 0x00, 0xa100); + phy_write (mii_info, 0x09, 0x0000); + phy_write (mii_info, 0x1b, 0x800b); + phy_write (mii_info, 0x04, 0x05e1); + phy_write (mii_info, 0x00, 0xa100); + phy_write (mii_info, 0x00, 0x2100); + udelay (1000000); + } else if (speed == 10) { + phy_write (mii_info, 0x14, 0x8e40); + phy_write (mii_info, 0x1b, 0x800b); + phy_write (mii_info, 0x14, 0x0c82); + phy_write (mii_info, 0x00, 0x8100); + udelay (1000000); + } } /* handle 88e1111 rev.B2 erratum 5.6 */ @@ -844,9 +851,10 @@ void marvell_phy_interface_mode (struct eth_device *dev, /* now the B2 will correctly report autoneg completion status */ } -void change_phy_interface_mode (struct eth_device *dev, enet_interface_e mode) +void change_phy_interface_mode (struct eth_device *dev, + enet_interface_type_e type, int speed) { #ifdef CONFIG_PHY_MODE_NEED_CHANGE - marvell_phy_interface_mode (dev, mode); + marvell_phy_interface_mode (dev, type, speed); #endif } diff --git a/include/configs/MPC8323ERDB.h b/include/configs/MPC8323ERDB.h index 356586c4280..8e6f7ce4535 100644 --- a/include/configs/MPC8323ERDB.h +++ b/include/configs/MPC8323ERDB.h @@ -347,7 +347,8 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK10 #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 4 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_100_MII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif #define CONFIG_UEC_ETH2 /* ETH4 */ @@ -358,7 +359,8 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK3 #define CONFIG_SYS_UEC2_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 0 -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_100_MII +#define CONFIG_SYS_UEC2_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 100 #endif /* diff --git a/include/configs/MPC832XEMDS.h b/include/configs/MPC832XEMDS.h index f17f9c7c376..1adac649e30 100644 --- a/include/configs/MPC832XEMDS.h +++ b/include/configs/MPC832XEMDS.h @@ -362,7 +362,8 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK10 #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 3 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_100_MII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif #define CONFIG_UEC_ETH2 /* ETH4 */ @@ -373,7 +374,8 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK8 #define CONFIG_SYS_UEC2_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 4 -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_100_MII +#define CONFIG_SYS_UEC2_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 100 #endif /* diff --git a/include/configs/MPC8360EMDS.h b/include/configs/MPC8360EMDS.h index 852015512c0..6fa7287c83d 100644 --- a/include/configs/MPC8360EMDS.h +++ b/include/configs/MPC8360EMDS.h @@ -400,7 +400,8 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK9 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 0 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #endif #define CONFIG_UEC_ETH2 /* GETH2 */ @@ -411,7 +412,8 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK4 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 1 -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #endif /* diff --git a/include/configs/MPC8360ERDK.h b/include/configs/MPC8360ERDK.h index 1d1f94f3f9a..c6f14093027 100644 --- a/include/configs/MPC8360ERDK.h +++ b/include/configs/MPC8360ERDK.h @@ -318,7 +318,8 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK9 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 2 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_1000_RGMII_RXID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_RXID +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #endif #define CONFIG_UEC_ETH2 /* GETH2 */ @@ -329,7 +330,8 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK4 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 4 -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_1000_RGMII_RXID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_RXID +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #endif /* diff --git a/include/configs/MPC8568MDS.h b/include/configs/MPC8568MDS.h index 128a7e13f80..6973538a8c9 100644 --- a/include/configs/MPC8568MDS.h +++ b/include/configs/MPC8568MDS.h @@ -333,7 +333,8 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC1_TX_CLK QE_CLK16 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 7 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #endif #define CONFIG_UEC_ETH2 /* GETH2 */ @@ -344,7 +345,8 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC2_TX_CLK QE_CLK16 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 1 -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #endif #endif /* CONFIG_QE */ diff --git a/include/configs/MPC8569MDS.h b/include/configs/MPC8569MDS.h index ae2fc19f4b5..4f4bcbeda85 100644 --- a/include/configs/MPC8569MDS.h +++ b/include/configs/MPC8569MDS.h @@ -326,12 +326,14 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC1_TX_CLK QE_CLK12 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 7 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC1_TX_CLK QE_CLK16 /* CLK16 for RMII */ #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 8 /* 0x8 for RMII */ -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_100_RMII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH1 */ @@ -345,12 +347,14 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC2_TX_CLK QE_CLK17 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 1 -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC2_TX_CLK QE_CLK16 /* CLK 16 for RMII */ #define CONFIG_SYS_UEC2_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 0x9 /* 0x9 for RMII */ -#define CONFIG_SYS_UEC2_INTERFACE_MODE ENET_100_RMII +#define CONFIG_SYS_UEC2_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC2_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH2 */ @@ -364,12 +368,14 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC3_TX_CLK QE_CLK12 #define CONFIG_SYS_UEC3_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC3_PHY_ADDR 2 -#define CONFIG_SYS_UEC3_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC3_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC3_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC3_TX_CLK QE_CLK16 /* CLK_16 for RMII */ #define CONFIG_SYS_UEC3_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC3_PHY_ADDR 0xA /* 0xA for RMII */ -#define CONFIG_SYS_UEC3_INTERFACE_MODE ENET_100_RMII +#define CONFIG_SYS_UEC3_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC3_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH3 */ @@ -383,12 +389,14 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC4_TX_CLK QE_CLK17 #define CONFIG_SYS_UEC4_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC4_PHY_ADDR 3 -#define CONFIG_SYS_UEC4_INTERFACE_MODE ENET_1000_RGMII_ID +#define CONFIG_SYS_UEC4_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC4_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC4_TX_CLK QE_CLK16 /* CLK16 for RMII */ #define CONFIG_SYS_UEC4_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC4_PHY_ADDR 0xB /* 0xB for RMII */ -#define CONFIG_SYS_UEC4_INTERFACE_MODE ENET_100_RMII +#define CONFIG_SYS_UEC4_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC4_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH4 */ @@ -401,7 +409,8 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC6_TX_CLK QE_CLK_NONE #define CONFIG_SYS_UEC6_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC6_PHY_ADDR 4 -#define CONFIG_SYS_UEC6_INTERFACE_MODE ENET_1000_SGMII +#define CONFIG_SYS_UEC6_INTERFACE_TYPE SGMII +#define CONFIG_SYS_UEC6_INTERFACE_SPEED 1000 #endif /* CONFIG_UEC_ETH6 */ #undef CONFIG_UEC_ETH8 /* GETH8 */ @@ -413,7 +422,8 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC8_TX_CLK QE_CLK_NONE #define CONFIG_SYS_UEC8_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC8_PHY_ADDR 6 -#define CONFIG_SYS_UEC8_INTERFACE_MODE ENET_1000_SGMII +#define CONFIG_SYS_UEC8_INTERFACE_TYPE SGMII +#define CONFIG_SYS_UEC8_INTERFACE_SPEED 1000 #endif /* CONFIG_UEC_ETH8 */ #endif /* CONFIG_QE */ diff --git a/include/configs/kmeter1.h b/include/configs/kmeter1.h index 0327b971b54..d27b75b6471 100644 --- a/include/configs/kmeter1.h +++ b/include/configs/kmeter1.h @@ -295,7 +295,8 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK17 #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 0 -#define CONFIG_SYS_UEC1_INTERFACE_MODE ENET_100_RMII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif /* -- cgit v1.3.1 From 594d57d0ccce649d6ccd881b8d9c5ea8d0c307ef Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Sun, 31 Jan 2010 17:39:49 +0100 Subject: Add EP93xx ethernet driver Added ethernet driver for EP93xx SoCs Signed-off-by: Matthias Kaehlcke Signed-off-by: Ben Warren --- drivers/net/Makefile | 1 + drivers/net/ep93xx_eth.c | 653 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ep93xx_eth.h | 144 +++++++++++ include/common.h | 5 + include/netdev.h | 1 + 5 files changed, 804 insertions(+) create mode 100644 drivers/net/ep93xx_eth.c create mode 100644 drivers/net/ep93xx_eth.h (limited to 'include') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 904727e1bfe..dc3107c0032 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -37,6 +37,7 @@ COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o +COBJS-$(CONFIG_EP93XX) += ep93xx_eth.o COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_FTMAC100) += ftmac100.o diff --git a/drivers/net/ep93xx_eth.c b/drivers/net/ep93xx_eth.c new file mode 100644 index 00000000000..4e39948d2fa --- /dev/null +++ b/drivers/net/ep93xx_eth.c @@ -0,0 +1,653 @@ +/* + * Cirrus Logic EP93xx ethernet MAC / MII driver. + * + * Copyright (C) 2010, 2009 + * Matthias Kaehlcke + * + * Copyright (C) 2004, 2005 + * Cory T. Tusar, Videon Central, Inc., + * + * Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver, + * which is + * + * (C) Copyright 2002 2003 + * Adam Bezanson, Network Audio Technologies, Inc. + * + * + * See file CREDITS for list of people who contributed to this project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ep93xx_eth.h" + +#define GET_PRIV(eth_dev) ((struct ep93xx_priv *)(eth_dev)->priv) +#define GET_REGS(eth_dev) (GET_PRIV(eth_dev)->regs) + +/* ep93xx_miiphy ops forward declarations */ +static int ep93xx_miiphy_read(char * const dev, unsigned char const addr, + unsigned char const reg, unsigned short * const value); +static int ep93xx_miiphy_write(char * const dev, unsigned char const addr, + unsigned char const reg, unsigned short const value); + +#if defined(EP93XX_MAC_DEBUG) +/** + * Dump ep93xx_mac values to the terminal. + */ +static void dump_dev(struct eth_device *dev) +{ + struct ep93xx_priv *priv = GET_PRIV(dev); + int i; + + printf("\ndump_dev()\n"); + printf(" rx_dq.base %p\n", priv->rx_dq.base); + printf(" rx_dq.current %p\n", priv->rx_dq.current); + printf(" rx_dq.end %p\n", priv->rx_dq.end); + printf(" rx_sq.base %p\n", priv->rx_sq.base); + printf(" rx_sq.current %p\n", priv->rx_sq.current); + printf(" rx_sq.end %p\n", priv->rx_sq.end); + + for (i = 0; i < NUMRXDESC; i++) + printf(" rx_buffer[%2.d] %p\n", i, NetRxPackets[i]); + + printf(" tx_dq.base %p\n", priv->tx_dq.base); + printf(" tx_dq.current %p\n", priv->tx_dq.current); + printf(" tx_dq.end %p\n", priv->tx_dq.end); + printf(" tx_sq.base %p\n", priv->tx_sq.base); + printf(" tx_sq.current %p\n", priv->tx_sq.current); + printf(" tx_sq.end %p\n", priv->tx_sq.end); +} + +/** + * Dump all RX status queue entries to the terminal. + */ +static void dump_rx_status_queue(struct eth_device *dev) +{ + struct ep93xx_priv *priv = GET_PRIV(dev); + int i; + + printf("\ndump_rx_status_queue()\n"); + printf(" descriptor address word1 word2\n"); + for (i = 0; i < NUMRXDESC; i++) { + printf(" [ %p ] %08X %08X\n", + priv->rx_sq.base + i, + (priv->rx_sq.base + i)->word1, + (priv->rx_sq.base + i)->word2); + } +} + +/** + * Dump all RX descriptor queue entries to the terminal. + */ +static void dump_rx_descriptor_queue(struct eth_device *dev) +{ + struct ep93xx_priv *priv = GET_PRIV(dev); + int i; + + printf("\ndump_rx_descriptor_queue()\n"); + printf(" descriptor address word1 word2\n"); + for (i = 0; i < NUMRXDESC; i++) { + printf(" [ %p ] %08X %08X\n", + priv->rx_dq.base + i, + (priv->rx_dq.base + i)->word1, + (priv->rx_dq.base + i)->word2); + } +} + +/** + * Dump all TX descriptor queue entries to the terminal. + */ +static void dump_tx_descriptor_queue(struct eth_device *dev) +{ + struct ep93xx_priv *priv = GET_PRIV(dev); + int i; + + printf("\ndump_tx_descriptor_queue()\n"); + printf(" descriptor address word1 word2\n"); + for (i = 0; i < NUMTXDESC; i++) { + printf(" [ %p ] %08X %08X\n", + priv->tx_dq.base + i, + (priv->tx_dq.base + i)->word1, + (priv->tx_dq.base + i)->word2); + } +} + +/** + * Dump all TX status queue entries to the terminal. + */ +static void dump_tx_status_queue(struct eth_device *dev) +{ + struct ep93xx_priv *priv = GET_PRIV(dev); + int i; + + printf("\ndump_tx_status_queue()\n"); + printf(" descriptor address word1\n"); + for (i = 0; i < NUMTXDESC; i++) { + printf(" [ %p ] %08X\n", + priv->rx_sq.base + i, + (priv->rx_sq.base + i)->word1); + } +} +#else +#define dump_dev(x) +#define dump_rx_descriptor_queue(x) +#define dump_rx_status_queue(x) +#define dump_tx_descriptor_queue(x) +#define dump_tx_status_queue(x) +#endif /* defined(EP93XX_MAC_DEBUG) */ + +/** + * Reset the EP93xx MAC by twiddling the soft reset bit and spinning until + * it's cleared. + */ +static void ep93xx_mac_reset(struct eth_device *dev) +{ + struct mac_regs *mac = GET_REGS(dev); + uint32_t value; + + debug("+ep93xx_mac_reset"); + + value = readl(&mac->selfctl); + value |= SELFCTL_RESET; + writel(value, &mac->selfctl); + + while (readl(&mac->selfctl) & SELFCTL_RESET) + ; /* noop */ + + debug("-ep93xx_mac_reset"); +} + +/* Eth device open */ +static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd) +{ + struct ep93xx_priv *priv = GET_PRIV(dev); + struct mac_regs *mac = GET_REGS(dev); + uchar *mac_addr = dev->enetaddr; + int i; + + debug("+ep93xx_eth_open"); + + /* Reset the MAC */ + ep93xx_mac_reset(dev); + + /* Reset the descriptor queues' current and end address values */ + priv->tx_dq.current = priv->tx_dq.base; + priv->tx_dq.end = (priv->tx_dq.base + NUMTXDESC); + + priv->tx_sq.current = priv->tx_sq.base; + priv->tx_sq.end = (priv->tx_sq.base + NUMTXDESC); + + priv->rx_dq.current = priv->rx_dq.base; + priv->rx_dq.end = (priv->rx_dq.base + NUMRXDESC); + + priv->rx_sq.current = priv->rx_sq.base; + priv->rx_sq.end = (priv->rx_sq.base + NUMRXDESC); + + /* + * Set the transmit descriptor and status queues' base address, + * current address, and length registers. Set the maximum frame + * length and threshold. Enable the transmit descriptor processor. + */ + writel((uint32_t)priv->tx_dq.base, &mac->txdq.badd); + writel((uint32_t)priv->tx_dq.base, &mac->txdq.curadd); + writel(sizeof(struct tx_descriptor) * NUMTXDESC, &mac->txdq.blen); + + writel((uint32_t)priv->tx_sq.base, &mac->txstsq.badd); + writel((uint32_t)priv->tx_sq.base, &mac->txstsq.curadd); + writel(sizeof(struct tx_status) * NUMTXDESC, &mac->txstsq.blen); + + writel(0x00040000, &mac->txdthrshld); + writel(0x00040000, &mac->txststhrshld); + + writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), &mac->maxfrmlen); + writel(BMCTL_TXEN, &mac->bmctl); + + /* + * Set the receive descriptor and status queues' base address, + * current address, and length registers. Enable the receive + * descriptor processor. + */ + writel((uint32_t)priv->rx_dq.base, &mac->rxdq.badd); + writel((uint32_t)priv->rx_dq.base, &mac->rxdq.curadd); + writel(sizeof(struct rx_descriptor) * NUMRXDESC, &mac->rxdq.blen); + + writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.badd); + writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.curadd); + writel(sizeof(struct rx_status) * NUMRXDESC, &mac->rxstsq.blen); + + writel(0x00040000, &mac->rxdthrshld); + + writel(BMCTL_RXEN, &mac->bmctl); + + writel(0x00040000, &mac->rxststhrshld); + + /* Wait until the receive descriptor processor is active */ + while (!(readl(&mac->bmsts) & BMSTS_RXACT)) + ; /* noop */ + + /* + * Initialize the RX descriptor queue. Clear the TX descriptor queue. + * Clear the RX and TX status queues. Enqueue the RX descriptor and + * status entries to the MAC. + */ + for (i = 0; i < NUMRXDESC; i++) { + /* set buffer address */ + (priv->rx_dq.base + i)->word1 = (uint32_t)NetRxPackets[i]; + + /* set buffer length, clear buffer index and NSOF */ + (priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN; + } + + memset(priv->tx_dq.base, 0, + (sizeof(struct tx_descriptor) * NUMTXDESC)); + memset(priv->rx_sq.base, 0, + (sizeof(struct rx_status) * NUMRXDESC)); + memset(priv->tx_sq.base, 0, + (sizeof(struct tx_status) * NUMTXDESC)); + + writel(NUMRXDESC, &mac->rxdqenq); + writel(NUMRXDESC, &mac->rxstsqenq); + + /* Set the primary MAC address */ + writel(AFP_IAPRIMARY, &mac->afp); + writel(mac_addr[0] | (mac_addr[1] << 8) | + (mac_addr[2] << 16) | (mac_addr[3] << 24), + &mac->indad); + writel(mac_addr[4] | (mac_addr[5] << 8), &mac->indad_upper); + + /* Turn on RX and TX */ + writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON | + RXCTL_RCRCA | RXCTL_MA, &mac->rxctl); + writel(TXCTL_STXON, &mac->txctl); + + /* Dump data structures if we're debugging */ + dump_dev(dev); + dump_rx_descriptor_queue(dev); + dump_rx_status_queue(dev); + dump_tx_descriptor_queue(dev); + dump_tx_status_queue(dev); + + debug("-ep93xx_eth_open"); + + return 1; +} + +/** + * Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL + * registers. + */ +static void ep93xx_eth_close(struct eth_device *dev) +{ + struct mac_regs *mac = GET_REGS(dev); + + debug("+ep93xx_eth_close"); + + writel(0x00000000, &mac->rxctl); + writel(0x00000000, &mac->txctl); + + debug("-ep93xx_eth_close"); +} + +/** + * Copy a frame of data from the MAC into the protocol layer for further + * processing. + */ +static int ep93xx_eth_rcv_packet(struct eth_device *dev) +{ + struct mac_regs *mac = GET_REGS(dev); + struct ep93xx_priv *priv = GET_PRIV(dev); + int len = -1; + + debug("+ep93xx_eth_rcv_packet"); + + if (RX_STATUS_RFP(priv->rx_sq.current)) { + if (RX_STATUS_RWE(priv->rx_sq.current)) { + /* + * We have a good frame. Extract the frame's length + * from the current rx_status_queue entry, and copy + * the frame's data into NetRxPackets[] of the + * protocol stack. We track the total number of + * bytes in the frame (nbytes_frame) which will be + * used when we pass the data off to the protocol + * layer via NetReceive(). + */ + len = RX_STATUS_FRAME_LEN(priv->rx_sq.current); + + NetReceive((uchar *)priv->rx_dq.current->word1, len); + + debug("reporting %d bytes...\n", len); + } else { + /* Do we have an erroneous packet? */ + error("packet rx error, status %08X %08X", + priv->rx_sq.current->word1, + priv->rx_sq.current->word2); + dump_rx_descriptor_queue(dev); + dump_rx_status_queue(dev); + } + + /* + * Clear the associated status queue entry, and + * increment our current pointers to the next RX + * descriptor and status queue entries (making sure + * we wrap properly). + */ + memset((void *)priv->rx_sq.current, 0, + sizeof(struct rx_status)); + + priv->rx_sq.current++; + if (priv->rx_sq.current >= priv->rx_sq.end) + priv->rx_sq.current = priv->rx_sq.base; + + priv->rx_dq.current++; + if (priv->rx_dq.current >= priv->rx_dq.end) + priv->rx_dq.current = priv->rx_dq.base; + + /* + * Finally, return the RX descriptor and status entries + * back to the MAC engine, and loop again, checking for + * more descriptors to process. + */ + writel(1, &mac->rxdqenq); + writel(1, &mac->rxstsqenq); + } else { + len = 0; + } + + debug("-ep93xx_eth_rcv_packet %d", len); + return len; +} + +/** + * Send a block of data via ethernet. + */ +static int ep93xx_eth_send_packet(struct eth_device *dev, + volatile void * const packet, int const length) +{ + struct mac_regs *mac = GET_REGS(dev); + struct ep93xx_priv *priv = GET_PRIV(dev); + int ret = -1; + + debug("+ep93xx_eth_send_packet"); + + /* Parameter check */ + BUG_ON(packet == NULL); + + /* + * Initialize the TX descriptor queue with the new packet's info. + * Clear the associated status queue entry. Enqueue the packet + * to the MAC for transmission. + */ + + /* set buffer address */ + priv->tx_dq.current->word1 = (uint32_t)packet; + + /* set buffer length and EOF bit */ + priv->tx_dq.current->word2 = length | TX_DESC_EOF; + + /* clear tx status */ + priv->tx_sq.current->word1 = 0; + + /* enqueue the TX descriptor */ + writel(1, &mac->txdqenq); + + /* wait for the frame to become processed */ + while (!TX_STATUS_TXFP(priv->tx_sq.current)) + ; /* noop */ + + if (!TX_STATUS_TXWE(priv->tx_sq.current)) { + error("packet tx error, status %08X", + priv->tx_sq.current->word1); + dump_tx_descriptor_queue(dev); + dump_tx_status_queue(dev); + + /* TODO: Add better error handling? */ + goto eth_send_out; + } + + ret = 0; + /* Fall through */ + +eth_send_out: + debug("-ep93xx_eth_send_packet %d", ret); + return ret; +} + +#if defined(CONFIG_MII) +int ep93xx_miiphy_initialize(bd_t * const bd) +{ + miiphy_register("ep93xx_eth0", ep93xx_miiphy_read, ep93xx_miiphy_write); + return 0; +} +#endif + +/** + * Initialize the EP93xx MAC. The MAC hardware is reset. Buffers are + * allocated, if necessary, for the TX and RX descriptor and status queues, + * as well as for received packets. The EP93XX MAC hardware is initialized. + * Transmit and receive operations are enabled. + */ +int ep93xx_eth_initialize(u8 dev_num, int base_addr) +{ + int ret = -1; + struct eth_device *dev; + struct ep93xx_priv *priv; + + debug("+ep93xx_eth_initialize"); + + priv = malloc(sizeof(*priv)); + if (!priv) { + error("malloc() failed"); + goto eth_init_failed_0; + } + memset(priv, 0, sizeof(*priv)); + + priv->regs = (struct mac_regs *)base_addr; + + priv->tx_dq.base = calloc(NUMTXDESC, + sizeof(struct tx_descriptor)); + if (priv->tx_dq.base == NULL) { + error("calloc() failed"); + goto eth_init_failed_1; + } + + priv->tx_sq.base = calloc(NUMTXDESC, + sizeof(struct tx_status)); + if (priv->tx_sq.base == NULL) { + error("calloc() failed"); + goto eth_init_failed_2; + } + + priv->rx_dq.base = calloc(NUMRXDESC, + sizeof(struct rx_descriptor)); + if (priv->rx_dq.base == NULL) { + error("calloc() failed"); + goto eth_init_failed_3; + } + + priv->rx_sq.base = calloc(NUMRXDESC, + sizeof(struct rx_status)); + if (priv->rx_sq.base == NULL) { + error("calloc() failed"); + goto eth_init_failed_4; + } + + dev = malloc(sizeof *dev); + if (dev == NULL) { + error("malloc() failed"); + goto eth_init_failed_5; + } + memset(dev, 0, sizeof *dev); + + dev->iobase = base_addr; + dev->priv = priv; + dev->init = ep93xx_eth_open; + dev->halt = ep93xx_eth_close; + dev->send = ep93xx_eth_send_packet; + dev->recv = ep93xx_eth_rcv_packet; + + sprintf(dev->name, "ep93xx_eth-%hu", dev_num); + + eth_register(dev); + + /* Done! */ + ret = 1; + goto eth_init_done; + +eth_init_failed_5: + free(priv->rx_sq.base); + /* Fall through */ + +eth_init_failed_4: + free(priv->rx_dq.base); + /* Fall through */ + +eth_init_failed_3: + free(priv->tx_sq.base); + /* Fall through */ + +eth_init_failed_2: + free(priv->tx_dq.base); + /* Fall through */ + +eth_init_failed_1: + free(priv); + /* Fall through */ + +eth_init_failed_0: + /* Fall through */ + +eth_init_done: + debug("-ep93xx_eth_initialize %d", ret); + return ret; +} + +#if defined(CONFIG_MII) + +/** + * Maximum MII address we support + */ +#define MII_ADDRESS_MAX 31 + +/** + * Maximum MII register address we support + */ +#define MII_REGISTER_MAX 31 + +/** + * Read a 16-bit value from an MII register. + */ +static int ep93xx_miiphy_read(char * const dev, unsigned char const addr, + unsigned char const reg, unsigned short * const value) +{ + struct mac_regs *mac = (struct mac_regs *)MAC_BASE; + int ret = -1; + uint32_t self_ctl; + + debug("+ep93xx_miiphy_read"); + + /* Parameter checks */ + BUG_ON(dev == NULL); + BUG_ON(addr > MII_ADDRESS_MAX); + BUG_ON(reg > MII_REGISTER_MAX); + BUG_ON(value == NULL); + + /* + * Save the current SelfCTL register value. Set MAC to suppress + * preamble bits. Wait for any previous MII command to complete + * before issuing the new command. + */ + self_ctl = readl(&mac->selfctl); +#if defined(CONFIG_MII_SUPPRESS_PREAMBLE) + writel(self_ctl & ~(1 << 8), &mac->selfctl); +#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */ + + while (readl(&mac->miists) & MIISTS_BUSY) + ; /* noop */ + + /* + * Issue the MII 'read' command. Wait for the command to complete. + * Read the MII data value. + */ + writel(MIICMD_OPCODE_READ | ((uint32_t)addr << 5) | (uint32_t)reg, + &mac->miicmd); + while (readl(&mac->miists) & MIISTS_BUSY) + ; /* noop */ + + *value = (unsigned short)readl(&mac->miidata); + + /* Restore the saved SelfCTL value and return. */ + writel(self_ctl, &mac->selfctl); + + ret = 0; + /* Fall through */ + + debug("-ep93xx_miiphy_read"); + return ret; +} + +/** + * Write a 16-bit value to an MII register. + */ +static int ep93xx_miiphy_write(char * const dev, unsigned char const addr, + unsigned char const reg, unsigned short const value) +{ + struct mac_regs *mac = (struct mac_regs *)MAC_BASE; + int ret = -1; + uint32_t self_ctl; + + debug("+ep93xx_miiphy_write"); + + /* Parameter checks */ + BUG_ON(dev == NULL); + BUG_ON(addr > MII_ADDRESS_MAX); + BUG_ON(reg > MII_REGISTER_MAX); + + /* + * Save the current SelfCTL register value. Set MAC to suppress + * preamble bits. Wait for any previous MII command to complete + * before issuing the new command. + */ + self_ctl = readl(&mac->selfctl); +#if defined(CONFIG_MII_SUPPRESS_PREAMBLE) + writel(self_ctl & ~(1 << 8), &mac->selfctl); +#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */ + + while (readl(&mac->miists) & MIISTS_BUSY) + ; /* noop */ + + /* Issue the MII 'write' command. Wait for the command to complete. */ + writel((uint32_t)value, &mac->miidata); + writel(MIICMD_OPCODE_WRITE | ((uint32_t)addr << 5) | (uint32_t)reg, + &mac->miicmd); + while (readl(&mac->miists) & MIISTS_BUSY) + ; /* noop */ + + /* Restore the saved SelfCTL value and return. */ + writel(self_ctl, &mac->selfctl); + + ret = 0; + /* Fall through */ + + debug("-ep93xx_miiphy_write"); + return ret; +} +#endif /* defined(CONFIG_MII) */ diff --git a/drivers/net/ep93xx_eth.h b/drivers/net/ep93xx_eth.h new file mode 100644 index 00000000000..4654b2f0c84 --- /dev/null +++ b/drivers/net/ep93xx_eth.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2004, 2005 + * Cory T. Tusar, Videon Central, Inc., + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 _EP93XX_ETH_H +#define _EP93XX_ETH_H + +#include + +/** + * #define this to dump device status and queue info during initialization and + * following errors. + */ +#undef EP93XX_MAC_DEBUG + +/** + * Number of descriptor and status entries in our RX queues. + * It must be power of 2 ! + */ +#define NUMRXDESC PKTBUFSRX + +/** + * Number of descriptor and status entries in our TX queues. + */ +#define NUMTXDESC 1 + +/** + * 944 = (1024 - 64) - 16, Fifo size - Minframesize - 16 (Chip FACT) + */ +#define TXSTARTMAX 944 + +/** + * Receive descriptor queue entry + */ +struct rx_descriptor { + uint32_t word1; + uint32_t word2; +}; + +/** + * Receive status queue entry + */ +struct rx_status { + uint32_t word1; + uint32_t word2; +}; + +#define RX_STATUS_RWE(rx_status) ((rx_status->word1 >> 30) & 0x01) +#define RX_STATUS_RFP(rx_status) ((rx_status->word1 >> 31) & 0x01) +#define RX_STATUS_FRAME_LEN(rx_status) (rx_status->word2 & 0xFFFF) + +/** + * Transmit descriptor queue entry + */ +struct tx_descriptor { + uint32_t word1; + uint32_t word2; +}; + +#define TX_DESC_EOF (1 << 31) + +/** + * Transmit status queue entry + */ +struct tx_status { + uint32_t word1; +}; + +#define TX_STATUS_TXWE(tx_status) (((tx_status)->word1 >> 30) & 0x01) +#define TX_STATUS_TXFP(tx_status) (((tx_status)->word1 >> 31) & 0x01) + +/** + * Transmit descriptor queue + */ +struct tx_descriptor_queue { + struct tx_descriptor *base; + struct tx_descriptor *current; + struct tx_descriptor *end; +}; + +/** + * Transmit status queue + */ +struct tx_status_queue { + struct tx_status *base; + volatile struct tx_status *current; + struct tx_status *end; +}; + +/** + * Receive descriptor queue + */ +struct rx_descriptor_queue { + struct rx_descriptor *base; + struct rx_descriptor *current; + struct rx_descriptor *end; +}; + +/** + * Receive status queue + */ +struct rx_status_queue { + struct rx_status *base; + volatile struct rx_status *current; + struct rx_status *end; +}; + +/** + * EP93xx MAC private data structure + */ +struct ep93xx_priv { + struct rx_descriptor_queue rx_dq; + struct rx_status_queue rx_sq; + void *rx_buffer[NUMRXDESC]; + + struct tx_descriptor_queue tx_dq; + struct tx_status_queue tx_sq; + + struct mac_regs *regs; +}; + +#endif diff --git a/include/common.h b/include/common.h index 81f2b59dea1..0ae5abc6ce3 100644 --- a/include/common.h +++ b/include/common.h @@ -123,6 +123,11 @@ typedef volatile unsigned char vu_char; #define debugX(level,fmt,args...) #endif /* DEBUG */ +#define error(fmt, args...) do { \ + printf("ERROR: " fmt "\nat %s:%d/%s()\n", \ + ##args, __FILE__, __LINE__, __func__); \ +} while (0) + #ifndef BUG #define BUG() do { \ printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \ diff --git a/include/netdev.h b/include/netdev.h index a9d5ec98319..1e0484fa410 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -49,6 +49,7 @@ int davinci_emac_initialize(void); int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); int eepro100_initialize(bd_t *bis); +int ep93xx_eth_initialize(u8 dev_num, int base_addr); int eth_3com_initialize (bd_t * bis); int fec_initialize (bd_t *bis); int fecmxc_initialize (bd_t *bis); -- cgit v1.3.1 From c041e9d212162f6c85cd3b6a40ad6ba9d9292451 Mon Sep 17 00:00:00 2001 From: Jens Scharsig Date: Sat, 23 Jan 2010 12:03:45 +0100 Subject: new at91_emac network driver (NET_MULTI api) * add's at91_emac (AT91RM9200) network driver (NET_MULTI api) * enable driver with CONFIG_DRIVER_AT91EMAC * generic PHY initialization * modify AT91RM9200 boards to use NET_MULTI driver * the drivers has been tested with LXT971 Phy and DM9161 Phy at MII and RMII interface Signed-off-by: Jens Scharsig Signed-off-by: Ben Warren --- README | 10 + board/atmel/at91rm9200dk/at91rm9200dk.c | 15 + board/atmel/at91rm9200ek/at91rm9200ek.c | 14 + board/cmc_pu2/cmc_pu2.c | 13 + board/csb637/csb637.c | 13 + board/eukrea/cpuat91/cpuat91.c | 14 + board/kb9202/kb9202.c | 13 + board/m501sk/m501sk.c | 14 + board/mp2usb/mp2usb.c | 13 + cpu/arm920t/at91rm9200/bcm5221.c | 4 +- cpu/arm920t/at91rm9200/dm9161.c | 3 +- drivers/net/Makefile | 1 + drivers/net/at91_emac.c | 498 ++++++++++++++++++++++++++++++++ include/asm-arm/arch-at91/at91_emac.h | 145 ++++++++++ include/configs/at91rm9200dk.h | 9 +- include/configs/at91rm9200ek.h | 8 +- include/configs/cmc_pu2.h | 8 +- include/configs/cpuat91.h | 8 +- include/configs/csb637.h | 8 +- include/configs/kb9202.h | 8 +- include/configs/m501sk.h | 9 +- include/configs/mp2usb.h | 8 +- include/netdev.h | 1 + 23 files changed, 825 insertions(+), 12 deletions(-) create mode 100644 drivers/net/at91_emac.c create mode 100644 include/asm-arm/arch-at91/at91_emac.h (limited to 'include') diff --git a/README b/README index 263bb05076b..1158e24de77 100644 --- a/README +++ b/README @@ -822,6 +822,16 @@ The following options need to be configured: - NETWORK Support (other): + CONFIG_DRIVER_AT91EMAC + Support for AT91RM9200 EMAC. + + CONFIG_RMII + Define this to use reduced MII inteface + + CONFIG_DRIVER_AT91EMAC_QUIET + If this defined, the driver is quiet. + The driver doen't show link status messages. + CONFIG_DRIVER_LAN91C96 Support for SMSC's LAN91C96 chips. diff --git a/board/atmel/at91rm9200dk/at91rm9200dk.c b/board/atmel/at91rm9200dk/at91rm9200dk.c index c761dd7467d..49b5fe3203d 100644 --- a/board/atmel/at91rm9200dk/at91rm9200dk.c +++ b/board/atmel/at91rm9200dk/at91rm9200dk.c @@ -23,9 +23,15 @@ */ #include +#include +#include #include +#include + +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -95,6 +101,15 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) #endif #endif /* CONFIG_DRIVER_ETHER */ +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif + /* * Disk On Chip (NAND) Millenium initialization. * The NAND lives in the CS2* space diff --git a/board/atmel/at91rm9200ek/at91rm9200ek.c b/board/atmel/at91rm9200ek/at91rm9200ek.c index ea684e949d0..570a09a0741 100644 --- a/board/atmel/at91rm9200ek/at91rm9200ek.c +++ b/board/atmel/at91rm9200ek/at91rm9200ek.c @@ -23,9 +23,14 @@ */ #include +#include +#include #include +#include +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -84,3 +89,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) p_phyops->AutoNegotiate = dm9161_AutoNegotiate; } #endif + +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif diff --git a/board/cmc_pu2/cmc_pu2.c b/board/cmc_pu2/cmc_pu2.c index 3ad756de1c8..0ac851c97f3 100644 --- a/board/cmc_pu2/cmc_pu2.c +++ b/board/cmc_pu2/cmc_pu2.c @@ -30,8 +30,12 @@ #include #include #include +#include +#include +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -177,3 +181,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) #endif #endif /* CONFIG_DRIVER_ETHER */ + +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif diff --git a/board/csb637/csb637.c b/board/csb637/csb637.c index fbc3c87c5da..d7fdcc4f739 100644 --- a/board/csb637/csb637.c +++ b/board/csb637/csb637.c @@ -23,8 +23,12 @@ #include #include +#include +#include +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -79,3 +83,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) #endif #endif /* CONFIG_DRIVER_ETHER */ + +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif diff --git a/board/eukrea/cpuat91/cpuat91.c b/board/eukrea/cpuat91/cpuat91.c index 1a700b649cc..0017962d420 100644 --- a/board/eukrea/cpuat91/cpuat91.c +++ b/board/eukrea/cpuat91/cpuat91.c @@ -26,9 +26,14 @@ */ #include +#include #include +#include + +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -79,3 +84,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) #endif /* CONFIG_CMD_NET */ #endif /* CONFIG_DRIVER_ETHER */ +#ifdef CONFIG_DRIVER_AT91EMAC + +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif diff --git a/board/kb9202/kb9202.c b/board/kb9202/kb9202.c index 59ed8ff6042..3164cc5ac44 100644 --- a/board/kb9202/kb9202.c +++ b/board/kb9202/kb9202.c @@ -28,8 +28,12 @@ #include #include +#include +#include +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -92,3 +96,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) #endif #endif /* CONFIG_DRIVER_ETHER */ + +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif diff --git a/board/m501sk/m501sk.c b/board/m501sk/m501sk.c index 1e6a6056722..c9957684b18 100644 --- a/board/m501sk/m501sk.c +++ b/board/m501sk/m501sk.c @@ -24,8 +24,13 @@ */ #include +#include +#include +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif + #include "m501sk.h" #include "net.h" @@ -186,4 +191,13 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) } #endif /* CONFIG_CMD_NET */ #endif /* CONFIG_DRIVER_ETHER */ + +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif #endif /* CONFIG_M501SK */ diff --git a/board/mp2usb/mp2usb.c b/board/mp2usb/mp2usb.c index dcda699dc87..e5eba6bbc09 100644 --- a/board/mp2usb/mp2usb.c +++ b/board/mp2usb/mp2usb.c @@ -27,8 +27,12 @@ #include #include +#include +#include +#if defined(CONFIG_DRIVER_ETHER) #include #include +#endif #include DECLARE_GLOBAL_DATA_PTR; @@ -83,3 +87,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops) #endif #endif /* CONFIG_DRIVER_ETHER */ + +#ifdef CONFIG_DRIVER_AT91EMAC +int board_eth_init(bd_t *bis) +{ + int rc = 0; + rc = at91emac_register(bis, 0); + return rc; +} +#endif diff --git a/cpu/arm920t/at91rm9200/bcm5221.c b/cpu/arm920t/at91rm9200/bcm5221.c index b52c615864c..8de3cba7381 100644 --- a/cpu/arm920t/at91rm9200/bcm5221.c +++ b/cpu/arm920t/at91rm9200/bcm5221.c @@ -28,10 +28,10 @@ #include #include -#include - #ifdef CONFIG_DRIVER_ETHER +#include + #if defined(CONFIG_CMD_NET) /* diff --git a/cpu/arm920t/at91rm9200/dm9161.c b/cpu/arm920t/at91rm9200/dm9161.c index 1beb6e8ba11..6d4384f41a0 100644 --- a/cpu/arm920t/at91rm9200/dm9161.c +++ b/cpu/arm920t/at91rm9200/dm9161.c @@ -23,9 +23,8 @@ #include #include -#include - #ifdef CONFIG_DRIVER_ETHER +#include #if defined(CONFIG_CMD_NET) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index dc3107c0032..1ec0ba13a6d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libnet.a COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o +COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o diff --git a/drivers/net/at91_emac.c b/drivers/net/at91_emac.c new file mode 100644 index 00000000000..239956998da --- /dev/null +++ b/drivers/net/at91_emac.c @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2009 BuS Elektronik GmbH & Co. KG + * Jens Scharsig (esw@bus-elektronik.de) + * + * (C) Copyright 2003 + * Author : Hamid Ikdoumi (Atmel) + + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 +#include +#ifndef CONFIG_AT91_LEGACY +#include +#include +#include +#include +#else +/* remove next 5 lines, if all RM9200 boards convert to at91 arch */ +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include + +#undef MII_DEBUG +#undef ET_DEBUG + +#if (CONFIG_SYS_RX_ETH_BUFFER > 1024) +#error AT91 EMAC supports max 1024 RX buffers. \ + Please decrease the CONFIG_SYS_RX_ETH_BUFFER value +#endif + +/* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */ +#if (AT91C_MASTER_CLOCK > 80000000) + #define HCLK_DIV AT91_EMAC_CFG_MCLK_64 +#elif (AT91C_MASTER_CLOCK > 40000000) + #define HCLK_DIV AT91_EMAC_CFG_MCLK_32 +#elif (AT91C_MASTER_CLOCK > 20000000) + #define HCLK_DIV AT91_EMAC_CFG_MCLK_16 +#else + #define HCLK_DIV AT91_EMAC_CFG_MCLK_8 +#endif + +#ifdef ET_DEBUG +#define DEBUG_AT91EMAC(...) printf(__VA_ARGS__); +#else +#define DEBUG_AT91EMAC(...) +#endif + +#ifdef MII_DEBUG +#define DEBUG_AT91PHY(...) printf(__VA_ARGS__); +#else +#define DEBUG_AT91PHY(...) +#endif + +#ifndef CONFIG_DRIVER_AT91EMAC_QUIET +#define VERBOSEP(...) printf(__VA_ARGS__); +#else +#define VERBOSEP(...) +#endif + +#define RBF_ADDR 0xfffffffc +#define RBF_OWNER (1<<0) +#define RBF_WRAP (1<<1) +#define RBF_BROADCAST (1<<31) +#define RBF_MULTICAST (1<<30) +#define RBF_UNICAST (1<<29) +#define RBF_EXTERNAL (1<<28) +#define RBF_UNKOWN (1<<27) +#define RBF_SIZE 0x07ff +#define RBF_LOCAL4 (1<<26) +#define RBF_LOCAL3 (1<<25) +#define RBF_LOCAL2 (1<<24) +#define RBF_LOCAL1 (1<<23) + +#define RBF_FRAMEMAX CONFIG_SYS_RX_ETH_BUFFER +#define RBF_FRAMELEN 0x600 + +typedef struct { + unsigned long addr, size; +} rbf_t; + +typedef struct { + rbf_t rbfdt[RBF_FRAMEMAX]; + unsigned long rbindex; +} emac_device; + +void at91emac_EnableMDIO(at91_emac_t *at91mac) +{ + /* Mac CTRL reg set for MDIO enable */ + writel(readl(&at91mac->ctl) | AT91_EMAC_CTL_MPE, &at91mac->ctl); +} + +void at91emac_DisableMDIO(at91_emac_t *at91mac) +{ + /* Mac CTRL reg set for MDIO disable */ + writel(readl(&at91mac->ctl) & ~AT91_EMAC_CTL_MPE, &at91mac->ctl); +} + +int at91emac_read(at91_emac_t *at91mac, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + at91emac_EnableMDIO(at91mac); + + writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_R | + AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 | + AT91_EMAC_MAN_PHYA(addr), + &at91mac->man); + udelay(10000); + *value = readl(&at91mac->man) & AT91_EMAC_MAN_DATA_MASK; + + at91emac_DisableMDIO(at91mac); + + DEBUG_AT91PHY("AT91PHY read %x REG(%d)=%x\n", at91mac, reg, *value) + + return 0; +} + +int at91emac_write(at91_emac_t *at91mac, unsigned char addr, + unsigned char reg, unsigned short value) +{ + DEBUG_AT91PHY("AT91PHY write %x REG(%d)=%x\n", at91mac, reg, &value) + + at91emac_EnableMDIO(at91mac); + + writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_W | + AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 | + AT91_EMAC_MAN_PHYA(addr) | (value & AT91_EMAC_MAN_DATA_MASK), + &at91mac->man); + udelay(10000); + + at91emac_DisableMDIO(at91mac); + return 0; +} + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + +at91_emac_t *get_emacbase_by_name(char *devname) +{ + struct eth_device *netdev; + + netdev = eth_get_dev_by_name(devname); + return (at91_emac_t *) netdev->iobase; +} + +int at91emac_mii_read(char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + at91_emac_t *emac; + + emac = get_emacbase_by_name(devname); + at91emac_read(emac , addr, reg, value); + return 0; +} + + +int at91emac_mii_write(char *devname, unsigned char addr, + unsigned char reg, unsigned short value) +{ + at91_emac_t *emac; + + emac = get_emacbase_by_name(devname); + at91emac_write(emac, addr, reg, value); + return 0; +} + +#endif + +static int at91emac_phy_reset(struct eth_device *netdev) +{ + int i; + u16 status, adv; + at91_emac_t *emac; + + emac = (at91_emac_t *) netdev->iobase; + + adv = ADVERTISE_CSMA | ADVERTISE_ALL; + at91emac_write(emac, 0, MII_ADVERTISE, adv); + VERBOSEP("%s: Starting autonegotiation...\n", netdev->name); + at91emac_write(emac, 0, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); + + for (i = 0; i < 100000 / 100; i++) { + at91emac_read(emac, 0, MII_BMSR, &status); + if (status & BMSR_ANEGCOMPLETE) + break; + udelay(100); + } + + if (status & BMSR_ANEGCOMPLETE) { + VERBOSEP("%s: Autonegotiation complete\n", netdev->name); + } else { + printf("%s: Autonegotiation timed out (status=0x%04x)\n", + netdev->name, status); + return 1; + } + return 0; +} + +static int at91emac_phy_init(struct eth_device *netdev) +{ + u16 phy_id, status, adv, lpa; + int media, speed, duplex; + int i; + at91_emac_t *emac; + + emac = (at91_emac_t *) netdev->iobase; + + /* Check if the PHY is up to snuff... */ + at91emac_read(emac, 0, MII_PHYSID1, &phy_id); + if (phy_id == 0xffff) { + printf("%s: No PHY present\n", netdev->name); + return 1; + } + + at91emac_read(emac, 0, MII_BMSR, &status); + + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + if (at91emac_phy_reset(netdev)) + return 2; + + for (i = 0; i < 100000 / 100; i++) { + at91emac_read(emac, 0, MII_BMSR, &status); + if (status & BMSR_LSTATUS) + break; + udelay(100); + } + } + if (!(status & BMSR_LSTATUS)) { + VERBOSEP("%s: link down\n", netdev->name); + return 3; + } else { + at91emac_read(emac, 0, MII_ADVERTISE, &adv); + at91emac_read(emac, 0, MII_LPA, &lpa); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + VERBOSEP("%s: link up, %sMbps %s-duplex\n", + netdev->name, + speed ? "100" : "10", + duplex ? "full" : "half"); + } + return 0; +} + +int at91emac_UpdateLinkSpeed(at91_emac_t *emac) +{ + unsigned short stat1; + + at91emac_read(emac, 0, MII_BMSR, &stat1); + + if (!(stat1 & BMSR_LSTATUS)) /* link status up? */ + return 1; + + if (stat1 & BMSR_100FULL) { + /*set Emac for 100BaseTX and Full Duplex */ + writel(readl(&emac->cfg) | + AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD, + &emac->cfg); + return 0; + } + + if (stat1 & BMSR_10FULL) { + /*set MII for 10BaseT and Full Duplex */ + writel((readl(&emac->cfg) & + ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD) + ) | AT91_EMAC_CFG_FD, + &emac->cfg); + return 0; + } + + if (stat1 & BMSR_100HALF) { + /*set MII for 100BaseTX and Half Duplex */ + writel((readl(&emac->cfg) & + ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD) + ) | AT91_EMAC_CFG_SPD, + &emac->cfg); + return 0; + } + + if (stat1 & BMSR_10HALF) { + /*set MII for 10BaseT and Half Duplex */ + writel((readl(&emac->cfg) & + ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)), + &emac->cfg); + return 0; + } + return 1; +} + +static int at91emac_init(struct eth_device *netdev, bd_t *bd) +{ + int i; + u32 value; + emac_device *dev; + at91_emac_t *emac; + at91_pio_t *pio = (at91_pio_t *) AT91_PIO_BASE; + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + emac = (at91_emac_t *) netdev->iobase; + dev = (emac_device *) netdev->priv; + + /* PIO Disable Register */ + value = AT91_PMX_AA_EMDIO | AT91_PMX_AA_EMDC | + AT91_PMX_AA_ERXER | AT91_PMX_AA_ERX1 | + AT91_PMX_AA_ERX0 | AT91_PMX_AA_ECRS | + AT91_PMX_AA_ETX1 | AT91_PMX_AA_ETX0 | + AT91_PMX_AA_ETXEN | AT91_PMX_AA_EREFCK; + + writel(value, &pio->pioa.pdr); + writel(value, &pio->pioa.asr); + +#ifdef CONFIG_RMII + value = AT91_PMX_BA_ERXCK; +#else + value = AT91_PMX_BA_ERXCK | AT91_PMX_BA_ECOL | + AT91_PMX_BA_ERXDV | AT91_PMX_BA_ERX3 | + AT91_PMX_BA_ERX2 | AT91_PMX_BA_ETXER | + AT91_PMX_BA_ETX3 | AT91_PMX_BA_ETX2; +#endif + writel(value, &pio->piob.pdr); + writel(value, &pio->piob.bsr); + + writel(1 << AT91_ID_EMAC, &pmc->pcer); + writel(readl(&emac->ctl) | AT91_EMAC_CTL_CSR, &emac->ctl); + + DEBUG_AT91EMAC("init MAC-ADDR %x%x \n", + cpu_to_le16(*((u16 *)(netdev->enetaddr + 4))), + cpu_to_le32(*((u32 *)netdev->enetaddr))); + writel(cpu_to_le32(*((u32 *)netdev->enetaddr)), &emac->sa2l); + writel(cpu_to_le16(*((u16 *)(netdev->enetaddr + 4))), &emac->sa2h); + DEBUG_AT91EMAC("init MAC-ADDR %x%x \n", + readl(&emac->sa2h), readl(&emac->sa2l)); + + /* Init Ethernet buffers */ + for (i = 0; i < RBF_FRAMEMAX; i++) { + dev->rbfdt[i].addr = (unsigned long) NetRxPackets[i]; + dev->rbfdt[i].size = 0; + } + dev->rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP; + dev->rbindex = 0; + writel((u32) &(dev->rbfdt[0]), &emac->rbqp); + + writel(readl(&emac->rsr) & + ~(AT91_EMAC_RSR_OVR | AT91_EMAC_RSR_REC | AT91_EMAC_RSR_BNA), + &emac->rsr); + + value = AT91_EMAC_CFG_CAF | AT91_EMAC_CFG_NBC | + HCLK_DIV; +#ifdef CONFIG_RMII + value |= AT91C_EMAC_RMII; +#endif + writel(value, &emac->cfg); + + writel(readl(&emac->ctl) | AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE, + &emac->ctl); + + if (!at91emac_phy_init(netdev)) { + at91emac_UpdateLinkSpeed(emac); + return 0; + } + return 1; +} + +static void at91emac_halt(struct eth_device *netdev) +{ + at91_emac_t *emac; + + emac = (at91_emac_t *) netdev->iobase; + writel(readl(&emac->ctl) & ~(AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE), + &emac->ctl); + DEBUG_AT91EMAC("halt MAC\n"); +} + +static int at91emac_send(struct eth_device *netdev, volatile void *packet, + int length) +{ + at91_emac_t *emac; + + emac = (at91_emac_t *) netdev->iobase; + + while (!(readl(&emac->tsr) & AT91_EMAC_TSR_BNQ)) + ; + writel((u32) packet, &emac->tar); + writel(AT91_EMAC_TCR_LEN(length), &emac->tcr); + while (AT91_EMAC_TCR_LEN(readl(&emac->tcr))) + ; + DEBUG_AT91EMAC("Send %d \n", length); + writel(readl(&emac->tsr) | AT91_EMAC_TSR_COMP, &emac->tsr); + return 0; +} + +static int at91emac_recv(struct eth_device *netdev) +{ + emac_device *dev; + at91_emac_t *emac; + rbf_t *rbfp; + int size; + + emac = (at91_emac_t *) netdev->iobase; + dev = (emac_device *) netdev->priv; + + rbfp = &dev->rbfdt[dev->rbindex]; + while (rbfp->addr & RBF_OWNER) { + size = rbfp->size & RBF_SIZE; + NetReceive(NetRxPackets[dev->rbindex], size); + + DEBUG_AT91EMAC("Recv[%d]: %d bytes @ %x \n", + dev->rbindex, size, rbfp->addr); + + rbfp->addr &= ~RBF_OWNER; + rbfp->size = 0; + if (dev->rbindex < (RBF_FRAMEMAX-1)) + dev->rbindex++; + else + dev->rbindex = 0; + + rbfp = &(dev->rbfdt[dev->rbindex]); + if (!(rbfp->addr & RBF_OWNER)) + writel(readl(&emac->rsr) | AT91_EMAC_RSR_REC, + &emac->rsr); + } + + if (readl(&emac->isr) & AT91_EMAC_IxR_RBNA) { + /* EMAC silicon bug 41.3.1 workaround 1 */ + writel(readl(&emac->ctl) & ~AT91_EMAC_CTL_RE, &emac->ctl); + writel(readl(&emac->ctl) | AT91_EMAC_CTL_RE, &emac->ctl); + dev->rbindex = 0; + printf("%s: reset receiver (EMAC dead lock bug)\n", + netdev->name); + } + return 0; +} + +int at91emac_register(bd_t *bis, unsigned long iobase) +{ + emac_device *emac; + emac_device *emacfix; + struct eth_device *dev; + + if (iobase == 0) + iobase = AT91_EMAC_BASE; + emac = malloc(sizeof(*emac)+512); + if (emac == NULL) + return 1; + dev = malloc(sizeof(*dev)); + if (dev == NULL) { + free(emac); + return 1; + } + /* alignment as per Errata (64 bytes) is insufficient! */ + emacfix = (emac_device *) (((unsigned long) emac + 0x1ff) & 0xFFFFFE00); + memset(emacfix, 0, sizeof(emac_device)); + + memset(dev, 0, sizeof(*dev)); +#ifndef CONFIG_RMII + sprintf(dev->name, "AT91 EMAC"); +#else + sprintf(dev->name, "AT91 EMAC RMII"); +#endif + dev->iobase = iobase; + dev->priv = emacfix; + dev->init = at91emac_init; + dev->halt = at91emac_halt; + dev->send = at91emac_send; + dev->recv = at91emac_recv; + + eth_register(dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + miiphy_register(dev->name, at91emac_mii_read, at91emac_mii_write); +#endif + return 1; +} diff --git a/include/asm-arm/arch-at91/at91_emac.h b/include/asm-arm/arch-at91/at91_emac.h new file mode 100644 index 00000000000..4b96f048bb5 --- /dev/null +++ b/include/asm-arm/arch-at91/at91_emac.h @@ -0,0 +1,145 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Copyright (C) 2009 Jens Scharsig (js_at_ng@scharsoft.de) + * + * based on AT91RM9200 datasheet revision I (36. Ethernet MAC (EMAC)) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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 AT91_H +#define AT91_H + +typedef struct at91_emac { + u32 ctl; + u32 cfg; + u32 sr; + u32 tar; + u32 tcr; + u32 tsr; + u32 rbqp; + u32 reserved0; + u32 rsr; + u32 isr; + u32 ier; + u32 idr; + u32 imr; + u32 man; + u32 reserved1[2]; + u32 fra; + u32 scol; + u32 mocl; + u32 ok; + u32 seqe; + u32 ale; + u32 dte; + u32 lcol; + u32 ecol; + u32 cse; + u32 tue; + u32 cde; + u32 elr; + u32 rjb; + u32 usf; + u32 sqee; + u32 drfc; + u32 reserved2[3]; + u32 hsh; + u32 hsl; + u32 sh1l; + u32 sa1h; + u32 sa2l; + u32 sa2h; + u32 sa3l; + u32 sa3h; + u32 sa4l; + u32 sa4h; +} at91_emac_t; + +#define AT91_EMAC_CTL_LB 0x0001 +#define AT91_EMAC_CTL_LBL 0x0002 +#define AT91_EMAC_CTL_RE 0x0004 +#define AT91_EMAC_CTL_TE 0x0008 +#define AT91_EMAC_CTL_MPE 0x0010 +#define AT91_EMAC_CTL_CSR 0x0020 +#define AT91_EMAC_CTL_ISR 0x0040 +#define AT91_EMAC_CTL_WES 0x0080 +#define AT91_EMAC_CTL_BP 0x1000 + +#define AT91_EMAC_CFG_SPD 0x0001 +#define AT91_EMAC_CFG_FD 0x0002 +#define AT91_EMAC_CFG_BR 0x0004 +#define AT91_EMAC_CFG_CAF 0x0010 +#define AT91_EMAC_CFG_NBC 0x0020 +#define AT91_EMAC_CFG_MTI 0x0040 +#define AT91_EMAC_CFG_UNI 0x0080 +#define AT91_EMAC_CFG_BIG 0x0100 +#define AT91_EMAC_CFG_EAE 0x0200 +#define AT91_EMAC_CFG_CLK_MASK 0xFFFFF3FF +#define AT91_EMAC_CFG_MCLK_8 0x0000 +#define AT91_EMAC_CFG_MCLK_16 0x0400 +#define AT91_EMAC_CFG_MCLK_32 0x0800 +#define AT91_EMAC_CFG_MCLK_64 0x0C00 +#define AT91_EMAC_CFG_RTY 0x1000 +#define AT91_EMAC_CFG_RMII 0x2000 + +#define AT91_EMAC_SR_LINK 0x0001 +#define AT91_EMAC_SR_MDIO 0x0002 +#define AT91_EMAC_SR_IDLE 0x0004 + +#define AT91_EMAC_TCR_LEN(x) (x & 0x7FF) +#define AT91_EMAC_TCR_NCRC 0x8000 + +#define AT91_EMAC_TSR_OVR 0x0001 +#define AT91_EMAC_TSR_COL 0x0002 +#define AT91_EMAC_TSR_RLE 0x0004 +#define AT91_EMAC_TSR_TXIDLE 0x0008 +#define AT91_EMAC_TSR_BNQ 0x0010 +#define AT91_EMAC_TSR_COMP 0x0020 +#define AT91_EMAC_TSR_UND 0x0040 + +#define AT91_EMAC_RSR_BNA 0x0001 +#define AT91_EMAC_RSR_REC 0x0002 +#define AT91_EMAC_RSR_OVR 0x0004 + +/* ISR, IER, IDR, IMR use the same bits */ +#define AT91_EMAC_IxR_DONE 0x0001 +#define AT91_EMAC_IxR_RCOM 0x0002 +#define AT91_EMAC_IxR_RBNA 0x0004 +#define AT91_EMAC_IxR_TOVR 0x0008 +#define AT91_EMAC_IxR_TUND 0x0010 +#define AT91_EMAC_IxR_RTRY 0x0020 +#define AT91_EMAC_IxR_TBRE 0x0040 +#define AT91_EMAC_IxR_TCOM 0x0080 +#define AT91_EMAC_IxR_TIDLE 0x0100 +#define AT91_EMAC_IxR_LINK 0x0200 +#define AT91_EMAC_IxR_ROVR 0x0400 +#define AT91_EMAC_IxR_HRESP 0x0800 + +#define AT91_EMAC_MAN_DATA_MASK 0xFFFF +#define AT91_EMAC_MAN_CODE_802_3 0x00020000 +#define AT91_EMAC_MAN_REGA(reg) ((reg & 0x1F) << 18) +#define AT91_EMAC_MAN_PHYA(phy) ((phy & 0x1F) << 23) +#define AT91_EMAC_MAN_RW_R 0x20000000 +#define AT91_EMAC_MAN_RW_W 0x10000000 +#define AT91_EMAC_MAN_HIGH 0x40000000 +#define AT91_EMAC_MAN_LOW 0x80000000 + +#endif diff --git a/include/configs/at91rm9200dk.h b/include/configs/at91rm9200dk.h index 590c69a19cc..5de70cb4d85 100644 --- a/include/configs/at91rm9200dk.h +++ b/include/configs/at91rm9200dk.h @@ -122,7 +122,14 @@ #define CONFIG_SYS_MEMTEST_START PHYS_SDRAM #define CONFIG_SYS_MEMTEST_END CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif + #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_AT91C_USE_RMII diff --git a/include/configs/at91rm9200ek.h b/include/configs/at91rm9200ek.h index b4f075ebc58..47508551f15 100644 --- a/include/configs/at91rm9200ek.h +++ b/include/configs/at91rm9200ek.h @@ -145,7 +145,13 @@ /* * Network Driver Setting */ -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_AT91C_USE_RMII diff --git a/include/configs/cmc_pu2.h b/include/configs/cmc_pu2.h index be478b24e41..00d0cec4fdc 100644 --- a/include/configs/cmc_pu2.h +++ b/include/configs/cmc_pu2.h @@ -152,7 +152,13 @@ #define CONFIG_SYS_MEMTEST_START PHYS_SDRAM #define CONFIG_SYS_MEMTEST_END CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_AT91C_USE_RMII diff --git a/include/configs/cpuat91.h b/include/configs/cpuat91.h index 8746f702da7..e872fe9abd1 100644 --- a/include/configs/cpuat91.h +++ b/include/configs/cpuat91.h @@ -128,7 +128,13 @@ #define CONFIG_SYS_MEMTEST_END \ (CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 512 * 1024) -#define CONFIG_DRIVER_ETHER 1 +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_AT91C_USE_RMII 1 #define CONFIG_PHY_ADDRESS (1 << 5) diff --git a/include/configs/csb637.h b/include/configs/csb637.h index f4fd808e46e..689e7f0030f 100644 --- a/include/configs/csb637.h +++ b/include/configs/csb637.h @@ -126,7 +126,13 @@ #define CONFIG_SYS_ALT_MEMTEST 1 #define CONFIG_SYS_MEMTEST_SCRATCH CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 4 -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #undef CONFIG_AT91C_USE_RMII diff --git a/include/configs/kb9202.h b/include/configs/kb9202.h index 7dd81e69cb9..3fe88feec21 100644 --- a/include/configs/kb9202.h +++ b/include/configs/kb9202.h @@ -115,7 +115,13 @@ #define CONFIG_SYS_MEMTEST_START PHYS_SDRAM #define CONFIG_SYS_MEMTEST_END CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - (512*1024) -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_SYS_FLASH_BASE 0x10000000 diff --git a/include/configs/m501sk.h b/include/configs/m501sk.h index 5c066426cf7..a28fd27d428 100644 --- a/include/configs/m501sk.h +++ b/include/configs/m501sk.h @@ -34,6 +34,7 @@ #define AT91C_MASTER_CLOCK 59904000 #define AT91_SLOW_CLOCK 32768 /* slow clock */ +#define CONFIG_AT91RM9200 1 /* It's an Atmel AT91RM9200 SoC */ #define CONFIG_AT91RM9200DK 1 /* on an AT91RM9200DK Board */ #undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */ #define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */ @@ -166,7 +167,13 @@ /* CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 */ #define CONFIG_SYS_MEMTEST_END 0x00100000 -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #define CONFIG_AT91C_USE_RMII diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h index 0c2ee6057ee..31eb1b666c7 100644 --- a/include/configs/mp2usb.h +++ b/include/configs/mp2usb.h @@ -181,7 +181,13 @@ #define CONFIG_SYS_MEMTEST_START PHYS_SDRAM #define CONFIG_SYS_MEMTEST_END CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 -#define CONFIG_DRIVER_ETHER +#define CONFIG_NET_MULTI 1 +#ifdef CONFIG_NET_MULTI +#define CONFIG_DRIVER_AT91EMAC 1 +#define CONFIG_SYS_RX_ETH_BUFFER 8 +#else +#define CONFIG_DRIVER_ETHER 1 +#endif #define CONFIG_NET_RETRY_COUNT 20 #undef CONFIG_AT91C_USE_RMII diff --git a/include/netdev.h b/include/netdev.h index 1e0484fa410..1dd80f05937 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -42,6 +42,7 @@ int cpu_eth_init(bd_t *bis); /* Driver initialization prototypes */ int au1x00_enet_initialize(bd_t*); +int at91emac_register(bd_t *bis, unsigned long iobase); int bfin_EMAC_initialize(bd_t *bis); int cs8900_initialize(u8 dev_num, int base_addr); int dc21x4x_initialize(bd_t *bis); -- cgit v1.3.1