Hi! > > > U-Boot 2014.07-rc1-00079-g2072e72-dirty (May 16 2014 - 15:54:55) > > > > > > CPU : Altera SOCFPGA Platform > > > BOARD : Altera SOCFPGA Cyclone5 Board > > > DRAM: 1 GiB > > > WARNING: Caches not enabled > > > Using default environment > > > > > > In: serial > > > Out: serial > > > Err: serial > > > Net: No ethernet found. > > > > Do you have any hints how to get ethernet to work? > > > > I yet to upstream the ethernet part yet. > I plan to do that once I upstreamed all the minimum SPL code to run on > dev kit.
I tried to get it to work, but did not succeed so far. First, designware.c patches are for version before rewrite -- so I reverted to that version. For some reason, it detects phy at all possible places -- seems like the controller is not listening in the address space? Then, it seems ethernet address reading depends on i2c, so I added that, and that in turn depends on clock framework. This is what my current diff. If you have any ideas, let me know. Best regards, Pavel diff --git a/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h b/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h index f564046..c8e925a 100644 --- a/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h +++ b/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h @@ -14,5 +14,8 @@ #define SOCFPGA_CLKMGR_ADDRESS 0xffd04000 #define SOCFPGA_RSTMGR_ADDRESS 0xffd05000 #define SOCFPGA_SYSMGR_ADDRESS 0xffd08000 +#define SOCFPGA_EMAC0_ADDRESS 0xff700000 +#define SOCFPGA_EMAC1_ADDRESS 0xff702000 + #endif /* _SOCFPGA_BASE_ADDRS_H_ */ diff --git a/board/altera/socfpga/socfpga_cyclone5.c b/board/altera/socfpga/socfpga_cyclone5.c index 33946b6..fd68aa9 100644 --- a/board/altera/socfpga/socfpga_cyclone5.c +++ b/board/altera/socfpga/socfpga_cyclone5.c @@ -7,11 +7,39 @@ #include <common.h> #include <asm/arch/reset_manager.h> #include <asm/io.h> +#ifndef CONFIG_SPL_BUILD +#include <phy.h> +#include <micrel.h> +#include <miiphy.h> +#include <netdev.h> +#include "../../../drivers/net/designware.h" +#endif #include <netdev.h> DECLARE_GLOBAL_DATA_PTR; +static const struct socfpga_reset_manager *reset_manager_base = + (void *)SOCFPGA_RSTMGR_ADDRESS; + +#define RSTMGR_PERMODRST_EMAC0_LSB 0 +#define RSTMGR_PERMODRST_EMAC1_LSB 1 + +#define CONFIG_SYSMGR_EMAC_CTRL (SOCFPGA_SYSMGR_ADDRESS + 0x60) + +/* Enumeration: sysmgr::emacgrp::ctrl::physel::enum */ +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB 0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB 2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 + +/* EMAC controller and PHY used */ +#define CONFIG_EMAC_BASE CONFIG_EMAC1_BASE +#define CONFIG_EPHY_PHY_ADDR CONFIG_EPHY1_PHY_ADDR +#define CONFIG_PHY_INTERFACE_MODE SOCFPGA_PHYSEL_ENUM_RGMII + #if defined(CONFIG_DISPLAY_CPUINFO) /* * Print CPU information @@ -64,8 +92,152 @@ int overwrite_console(void) /* * DesignWare Ethernet initialization */ + +int designware_board_phy_init(struct eth_device *dev, int phy_addr, + int (*mii_write)(struct eth_device *, u8, u8, u16), + int (*dw_reset_phy)(struct eth_device *)) +{ + struct dw_eth_dev *priv = dev->priv; + struct phy_device *phydev; + struct mii_dev *bus; + + printf("Back to board file\n"); + + if ((*dw_reset_phy)(dev) < 0) + return -1; + + bus = mdio_get_current_dev(); + printf("Board file: bus %lx\n", bus); + + /* +struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask, +phy_interface_t interface) + */ + + phydev = phy_connect(bus, phy_addr, dev, + priv->interface); + + printf("Board file: bus %lx\n", phydev); + /* Micrel PHY is connected to EMAC1 */ + if (strcasecmp(phydev->drv->name, "Micrel ksz9021") == 0 && + ((phydev->drv->uid & phydev->drv->mask) == + (phydev->phy_id & phydev->drv->mask))) { + + printf("Configuring PHY skew timing for %s\n", + phydev->drv->name); + + /* min rx data delay */ + if (ksz9021_phy_extended_write(phydev, + MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, + getenv_ulong(CONFIG_KSZ9021_DATA_SKEW_ENV, 16, + CONFIG_KSZ9021_DATA_SKEW_VAL)) < 0) + return -1; + /* min tx data delay */ + if (ksz9021_phy_extended_write(phydev, + MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, + getenv_ulong(CONFIG_KSZ9021_DATA_SKEW_ENV, 16, + CONFIG_KSZ9021_DATA_SKEW_VAL)) < 0) + return -1; + /* max rx/tx clock delay, min rx/tx control */ + if (ksz9021_phy_extended_write(phydev, + MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, + getenv_ulong(CONFIG_KSZ9021_CLK_SKEW_ENV, 16, + CONFIG_KSZ9021_CLK_SKEW_VAL)) < 0) + return -1; + + if (phydev->drv->config) + phydev->drv->config(phydev); + } + return 0; +} + +/* Change the reset state for EMAC0 */ +void emac0_reset_enable(uint state) +{ + if (state) + setbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC0_LSB)); + else + clrbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC0_LSB)); +} + +/* Change the reset state for EMAC1 */ +void emac1_reset_enable(uint state) +{ + if (state) + setbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC1_LSB)); + else + clrbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC1_LSB)); +} + + /* We know all the init functions have been run now */ int board_eth_init(bd_t *bis) { - return 0; + printf("Board_eth_init\n"); +#if !defined(CONFIG_SOCFPGA_VIRTUAL_TARGET) && \ +!defined(CONFIG_SPL_BUILD) + + /* Initialize EMAC */ + + /* + * Putting the EMAC controller to reset when configuring the PHY + * interface select at System Manager + */ + printf("enabling resets...\n"); + emac0_reset_enable(1); + emac1_reset_enable(1); + + /* Clearing emac0 PHY interface select to 0 */ + clrbits_le32(CONFIG_SYSMGR_EMAC_CTRL, + (SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << +#if (CONFIG_EMAC_BASE == CONFIG_EMAC0_BASE) + SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB)); +#elif (CONFIG_EMAC_BASE == CONFIG_EMAC1_BASE) + SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB)); +#endif + + /* configure to PHY interface select choosed */ + setbits_le32(CONFIG_SYSMGR_EMAC_CTRL, +#if (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_GMII) + (SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII << +#elif (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_MII) + (SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII << +#elif (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_RGMII) + (SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII << +#elif (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_RMII) + (SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII << +#endif +#if (CONFIG_EMAC_BASE == CONFIG_EMAC0_BASE) + SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB)); + printf("enabling emac0...\n"); + /* Release the EMAC controller from reset */ + emac0_reset_enable(0); +#elif (CONFIG_EMAC_BASE == CONFIG_EMAC1_BASE) + SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB)); + printf("enabling emac1...\n"); + /* Release the EMAC controller from reset */ + emac1_reset_enable(0); +#endif + + /* initialize and register the emac */ + int rval = designware_initialize(0, CONFIG_EMAC_BASE, + CONFIG_EPHY_PHY_ADDR, +#if (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_GMII) + PHY_INTERFACE_MODE_GMII); +#elif (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_MII) + PHY_INTERFACE_MODE_MII); +#elif (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_RGMII) + PHY_INTERFACE_MODE_RGMII); +#elif (CONFIG_PHY_INTERFACE_MODE == SOCFPGA_PHYSEL_ENUM_RMII) + PHY_INTERFACE_MODE_RMII); +#endif + printf("board_eth_init %d\n", rval); + return rval; +#else + return 0; +#endif } diff --git a/board/bf609-ezkit/bf609-ezkit.c b/board/bf609-ezkit/bf609-ezkit.c index 43a4330..cfc64fe 100644 --- a/board/bf609-ezkit/bf609-ezkit.c +++ b/board/bf609-ezkit/bf609-ezkit.c @@ -41,12 +41,12 @@ int board_eth_init(bd_t *bis) if (CONFIG_DW_PORTS & 1) { static const unsigned short pins[] = P_RMII0; if (!peripheral_request_list(pins, "emac0")) - ret += designware_initialize(EMAC0_MACCFG, 0); + ret += designware_initialize(0, EMAC0_MACCFG, 1, 0); } if (CONFIG_DW_PORTS & 2) { static const unsigned short pins[] = P_RMII1; if (!peripheral_request_list(pins, "emac1")) - ret += designware_initialize(EMAC1_MACCFG, 0); + ret += designware_initialize(1, EMAC1_MACCFG, 1, 0); } return ret; diff --git a/board/spear/spear300/spear300.c b/board/spear/spear300/spear300.c index 6b6bd9f..e25aba2 100644 --- a/board/spear/spear300/spear300.c +++ b/board/spear/spear300/spear300.c @@ -53,7 +53,8 @@ int board_eth_init(bd_t *bis) #if defined(CONFIG_DESIGNWARE_ETH) u32 interface = PHY_INTERFACE_MODE_MII; - if (designware_initialize(CONFIG_SPEAR_ETHBASE, interface) >= 0) + if (designware_initialize(0, CONFIG_SPEAR_ETHBASE, CONFIG_DW0_PHY, + interface) >= 0) ret++; #endif return ret; diff --git a/board/spear/spear310/spear310.c b/board/spear/spear310/spear310.c index a4c6a8e..70f9aa1 100644 --- a/board/spear/spear310/spear310.c +++ b/board/spear/spear310/spear310.c @@ -54,7 +54,8 @@ int board_eth_init(bd_t *bis) #if defined(CONFIG_DESIGNWARE_ETH) u32 interface = PHY_INTERFACE_MODE_MII; - if (designware_initialize(CONFIG_SPEAR_ETHBASE, interface) >= 0) + if (designware_initialize(0, CONFIG_SPEAR_ETHBASE, CONFIG_DW0_PHY, + interface) >= 0) ret++; #endif #if defined(CONFIG_MACB) diff --git a/board/spear/spear320/spear320.c b/board/spear/spear320/spear320.c index ab732a7..f6b1fdd 100644 --- a/board/spear/spear320/spear320.c +++ b/board/spear/spear320/spear320.c @@ -65,7 +65,8 @@ int board_eth_init(bd_t *bis) #if defined(CONFIG_DESIGNWARE_ETH) u32 interface = PHY_INTERFACE_MODE_MII; - if (designware_initialize(CONFIG_SPEAR_ETHBASE, interface) >= 0) + if (designware_initialize(0, CONFIG_SPEAR_ETHBASE, CONFIG_DW0_PHY, + interface) >= 0) ret++; #endif #if defined(CONFIG_MACB) diff --git a/board/spear/spear600/spear600.c b/board/spear/spear600/spear600.c index 8472002..e996a0e 100644 --- a/board/spear/spear600/spear600.c +++ b/board/spear/spear600/spear600.c @@ -51,7 +51,8 @@ int board_eth_init(bd_t *bis) #if defined(CONFIG_DW_AUTONEG) interface = PHY_INTERFACE_MODE_GMII; #endif - if (designware_initialize(CONFIG_SPEAR_ETHBASE, interface) >= 0) + if (designware_initialize(0, CONFIG_SPEAR_ETHBASE, CONFIG_DW0_PHY, + interface) >= 0) ret++; #endif return ret; diff --git a/board/spear/x600/x600.c b/board/spear/x600/x600.c index b8edfcd..044d204 100644 --- a/board/spear/x600/x600.c +++ b/board/spear/x600/x600.c @@ -67,32 +67,31 @@ void board_nand_init(void) fsmc_nand_init(nand); } -int board_phy_config(struct phy_device *phydev) +int designware_board_phy_init(struct eth_device *dev, int phy_addr, + int (*mii_write)(struct eth_device *, u8, u8, u16), + int dw_reset_phy(struct eth_device *)) { /* Extended PHY control 1, select GMII */ - phy_write(phydev, MDIO_DEVAD_NONE, 23, 0x0020); + mii_write(dev, phy_addr, 23, 0x0020); /* Software reset necessary after GMII mode selction */ - phy_reset(phydev); + dw_reset_phy(dev); /* Enable extended page register access */ - phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0001); + mii_write(dev, phy_addr, 31, 0x0001); /* 17e: Enhanced LED behavior, needs to be written twice */ - phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x09ff); - phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x09ff); + mii_write(dev, phy_addr, 17, 0x09ff); + mii_write(dev, phy_addr, 17, 0x09ff); /* 16e: Enhanced LED method select */ - phy_write(phydev, MDIO_DEVAD_NONE, 16, 0xe0ea); + mii_write(dev, phy_addr, 16, 0xe0ea); /* Disable extended page register access */ - phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0000); + mii_write(dev, phy_addr, 31, 0x0000); /* Enable clock output pin */ - phy_write(phydev, MDIO_DEVAD_NONE, 18, 0x0049); - - if (phydev->drv->config) - phydev->drv->config(phydev); + mii_write(dev, phy_addr, 18, 0x0049); return 0; } @@ -101,7 +100,7 @@ int board_eth_init(bd_t *bis) { int ret = 0; - if (designware_initialize(CONFIG_SPEAR_ETHBASE, + if (designware_initialize(0, CONFIG_SPEAR_ETHBASE, CONFIG_PHY_ADDR, PHY_INTERFACE_MODE_GMII) >= 0) ret++; diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 78751b2..965b033 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -17,75 +17,7 @@ #include <asm/io.h> #include "designware.h" -#if !defined(CONFIG_PHYLIB) -# error "DesignWare Ether MAC requires PHYLIB - missing CONFIG_PHYLIB" -#endif - -static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct eth_mac_regs *mac_p = bus->priv; - ulong start; - u16 miiaddr; - int timeout = CONFIG_MDIO_TIMEOUT; - - miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | - ((reg << MIIREGSHIFT) & MII_REGMSK); - - writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); - - start = get_timer(0); - while (get_timer(start) < timeout) { - if (!(readl(&mac_p->miiaddr) & MII_BUSY)) - return readl(&mac_p->miidata); - udelay(10); - }; - - return -1; -} - -static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 val) -{ - struct eth_mac_regs *mac_p = bus->priv; - ulong start; - u16 miiaddr; - int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; - - writel(val, &mac_p->miidata); - miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | - ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; - - writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); - - start = get_timer(0); - while (get_timer(start) < timeout) { - if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { - ret = 0; - break; - } - udelay(10); - }; - - return ret; -} - -static int dw_mdio_init(char *name, struct eth_mac_regs *mac_regs_p) -{ - struct mii_dev *bus = mdio_alloc(); - - if (!bus) { - printf("Failed to allocate MDIO bus\n"); - return -1; - } - - bus->read = dw_mdio_read; - bus->write = dw_mdio_write; - sprintf(bus->name, name); - - bus->priv = (void *)mac_regs_p; - - return mdio_register(bus); -} +static int configure_phy(struct eth_device *dev); static void tx_descs_init(struct eth_device *dev) { @@ -170,59 +102,53 @@ static void rx_descs_init(struct eth_device *dev) priv->rx_currdescnum = 0; } -static int dw_write_hwaddr(struct eth_device *dev) +static void descs_init(struct eth_device *dev) { - struct dw_eth_dev *priv = dev->priv; - struct eth_mac_regs *mac_p = priv->mac_regs_p; - u32 macid_lo, macid_hi; - u8 *mac_id = &dev->enetaddr[0]; - - macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) + - (mac_id[3] << 24); - macid_hi = mac_id[4] + (mac_id[5] << 8); - - writel(macid_hi, &mac_p->macaddr0hi); - writel(macid_lo, &mac_p->macaddr0lo); - - return 0; + tx_descs_init(dev); + rx_descs_init(dev); } -static void dw_adjust_link(struct eth_mac_regs *mac_p, - struct phy_device *phydev) +static int mac_reset(struct eth_device *dev) { - u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN; + struct dw_eth_dev *priv = dev->priv; + struct eth_mac_regs *mac_p = priv->mac_regs_p; + struct eth_dma_regs *dma_p = priv->dma_regs_p; - if (!phydev->link) { - printf("%s: No link.\n", phydev->dev->name); - return; - } + ulong start; + int timeout = CONFIG_MACRESET_TIMEOUT; - if (phydev->speed != 1000) - conf |= MII_PORTSELECT; + writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode); - if (phydev->speed == 100) - conf |= FES_100; + if (priv->interface != PHY_INTERFACE_MODE_RGMII) + writel(MII_PORTSELECT, &mac_p->conf); - if (phydev->duplex) - conf |= FULLDPLXMODE; + start = get_timer(0); + while (get_timer(start) < timeout) { + if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) + return 0; - writel(conf, &mac_p->conf); + /* Try again after 10usec */ + udelay(10); + }; - printf("Speed: %d, %s duplex%s\n", phydev->speed, - (phydev->duplex) ? "full" : "half", - (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); + return -1; } -static void dw_eth_halt(struct eth_device *dev) +static int dw_write_hwaddr(struct eth_device *dev) { struct dw_eth_dev *priv = dev->priv; struct eth_mac_regs *mac_p = priv->mac_regs_p; - struct eth_dma_regs *dma_p = priv->dma_regs_p; + u32 macid_lo, macid_hi; + u8 *mac_id = &dev->enetaddr[0]; - writel(readl(&mac_p->conf) & ~(RXENABLE | TXENABLE), &mac_p->conf); - writel(readl(&dma_p->opmode) & ~(RXSTART | TXSTART), &dma_p->opmode); + macid_lo = mac_id[0] + (mac_id[1] << 8) + \ + (mac_id[2] << 16) + (mac_id[3] << 24); + macid_hi = mac_id[4] + (mac_id[5] << 8); - phy_shutdown(priv->phydev); + writel(macid_hi, &mac_p->macaddr0hi); + writel(macid_lo, &mac_p->macaddr0lo); + + return 0; } static int dw_eth_init(struct eth_device *dev, bd_t *bis) @@ -230,43 +156,60 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis) struct dw_eth_dev *priv = dev->priv; struct eth_mac_regs *mac_p = priv->mac_regs_p; struct eth_dma_regs *dma_p = priv->dma_regs_p; - unsigned int start; + u32 conf; - writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode); + if (priv->phy_configured != 1) { + int ret = configure_phy(dev); + if (ret < 0) { + printf("failed to configure phy: %d\n", ret); + return ret; + } + } - start = get_timer(0); - while (readl(&dma_p->busmode) & DMAMAC_SRST) { - if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT) - return -1; + /* Print link status only once */ + if (!priv->link_printed) { + printf("ENET Speed is %d Mbps - %s duplex connection\n", + priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); + priv->link_printed = 1; + } - mdelay(100); - }; + /* Reset ethernet hardware */ + if (mac_reset(dev) < 0) + return -1; - /* Soft reset above clears HW address registers. - * So we have to set it here once again */ + /* Resore the HW MAC address as it has been lost during MAC reset */ dw_write_hwaddr(dev); - rx_descs_init(dev); - tx_descs_init(dev); + writel(FIXEDBURST | PRIORXTX_41 | BURST_16, + &dma_p->busmode); - writel(FIXEDBURST | PRIORXTX_41 | BURST_16, &dma_p->busmode); + writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD | + TXSECONDFRAME, &dma_p->opmode); - writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD, - &dma_p->opmode); + conf = FRAMEBURSTENABLE | DISABLERXOWN; - writel(readl(&dma_p->opmode) | RXSTART | TXSTART, &dma_p->opmode); + if (priv->speed != 1000) + conf |= MII_PORTSELECT; - /* Start up the PHY */ - if (phy_startup(priv->phydev)) { - printf("Could not initialize PHY %s\n", - priv->phydev->dev->name); - return -1; + if ((priv->interface != PHY_INTERFACE_MODE_MII) && + (priv->interface != PHY_INTERFACE_MODE_GMII)) { + + if (priv->speed == 100) + conf |= FES_100; } - dw_adjust_link(mac_p, priv->phydev); + if (priv->duplex == FULL) + conf |= FULLDPLXMODE; - if (!priv->phydev->link) - return -1; + writel(conf, &mac_p->conf); + + descs_init(dev); + + /* + * Start/Enable xfer at dma as well as mac level + */ + writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); + writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf); @@ -376,36 +319,271 @@ static int dw_eth_recv(struct eth_device *dev) return length; } -static int dw_phy_init(struct eth_device *dev) +static void dw_eth_halt(struct eth_device *dev) { struct dw_eth_dev *priv = dev->priv; - struct phy_device *phydev; - int mask = 0xffffffff; -#ifdef CONFIG_PHY_ADDR - mask = 1 << CONFIG_PHY_ADDR; + mac_reset(dev); + priv->tx_currdescnum = priv->rx_currdescnum = 0; +} + +static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) +{ + struct dw_eth_dev *priv = dev->priv; + struct eth_mac_regs *mac_p = priv->mac_regs_p; + ulong start; + u32 miiaddr; + int timeout = CONFIG_MDIO_TIMEOUT; + + miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ + ((reg << MIIREGSHIFT) & MII_REGMSK); + + writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); + + start = get_timer(0); + while (get_timer(start) < timeout) { + if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { + *val = readl(&mac_p->miidata); + return 0; + } + + /* Try again after 10usec */ + udelay(10); + }; + + return -1; +} + +static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) +{ + struct dw_eth_dev *priv = dev->priv; + struct eth_mac_regs *mac_p = priv->mac_regs_p; + ulong start; + u32 miiaddr; + int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; + u16 value; + + printf("eth_mdio_write %lx\n", &mac_p->miidata); + + writel(val, &mac_p->miidata); + miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ + ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; + + writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); + + start = get_timer(0); + while (get_timer(start) < timeout) { + if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { + ret = 0; + break; + } + + /* Try again after 10usec */ + udelay(10); + }; + + /* Needed as a fix for ST-Phy */ + eth_mdio_read(dev, addr, reg, &value); + + return ret; +} + +#if defined(CONFIG_DW_SEARCH_PHY) +static int find_phy(struct eth_device *dev) +{ + int phy_addr = 1; + u16 ctrl, oldctrl; + + do { + printf("Searching at %d\n", phy_addr); + eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); + oldctrl = ctrl & BMCR_ANENABLE; + + ctrl ^= BMCR_ANENABLE; + eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); + eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); + ctrl &= BMCR_ANENABLE; + + if (ctrl == oldctrl) { + phy_addr++; + } else { + ctrl ^= BMCR_ANENABLE; + eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); + printf("Found at %d\n", phy_addr); + + return phy_addr; + } + } while (phy_addr < 32); + + return -1; +} +#endif + +static int dw_reset_phy(struct eth_device *dev) +{ + struct dw_eth_dev *priv = dev->priv; + u16 ctrl; + ulong start; + int timeout = CONFIG_PHYRESET_TIMEOUT; + u32 phy_addr = priv->address; + + eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET); + + start = get_timer(0); + while (get_timer(start) < timeout) { + eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); + if (!(ctrl & BMCR_RESET)) + break; + + /* Try again after 10usec */ + udelay(10); + }; + + if (get_timer(start) >= CONFIG_PHYRESET_TIMEOUT) { + printf("timed out waiting for phy reset %x\n", ctrl); + return -1; + } + + // phydev->supported &= PHY_GBIT_FEATURES; +#ifdef CONFIG_PHY_RESET_DELAY + udelay(CONFIG_PHY_RESET_DELAY); +#endif + return 0; +} + +/* + * Add weak default function for board specific PHY configuration + */ +int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr, + int (*mii_write)(struct eth_device *, u8, u8, u16), + int dw_reset_phy(struct eth_device *)) +{ + return 0; +} + +static int configure_phy(struct eth_device *dev) +{ + struct dw_eth_dev *priv = dev->priv; + int phy_addr; + u16 bmcr; +#if defined(CONFIG_DW_AUTONEG) + u16 bmsr; + u32 timeout; + ulong start; #endif - phydev = phy_find_by_mask(priv->bus, mask, priv->interface); - if (!phydev) + printf("configure_phy\n"); + +#if defined(CONFIG_DW_SEARCH_PHY) + printf("finding phy\n"); + phy_addr = find_phy(dev); + if (phy_addr >= 0) + priv->address = phy_addr; + else + return -1; +#else + phy_addr = priv->address; +#endif + + /* + * Some boards need board specific PHY initialization. This is + * after the main driver init code but before the auto negotiation + * is run. + */ + if (designware_board_phy_init(dev, phy_addr, + eth_mdio_write, dw_reset_phy) < 0) + return -1; + +#if 0 + if (dw_reset_phy(dev) < 0) return -1; +#endif - phy_connect_dev(phydev, dev); +#if defined(CONFIG_DW_AUTONEG) + /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */ + eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1); - phydev->supported &= PHY_GBIT_FEATURES; - phydev->advertising = phydev->supported; + bmcr = BMCR_ANENABLE | BMCR_ANRESTART; +#else + bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; - priv->phydev = phydev; - phy_config(phydev); +#if defined(CONFIG_DW_SPEED10M) + bmcr &= ~BMCR_SPEED100; +#endif +#if defined(CONFIG_DW_DUPLEXHALF) + bmcr &= ~BMCR_FULLDPLX; +#endif +#endif + if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) + return -1; - return 1; + /* Read the phy status register and populate priv structure */ +#if defined(CONFIG_DW_AUTONEG) + timeout = CONFIG_AUTONEG_TIMEOUT; + start = get_timer(0); + puts("Waiting for PHY auto negotiation to complete"); + while (get_timer(start) < timeout) { + eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); + if (bmsr & BMSR_ANEGCOMPLETE) { + priv->phy_configured = 1; + break; + } + + /* Print dot all 1s to show progress */ + if ((get_timer(start) % 1000) == 0) + putc('.'); + + /* Try again after 1msec */ + udelay(1000); + }; + + if (!(bmsr & BMSR_ANEGCOMPLETE)) + puts(" TIMEOUT!\n"); + else + puts(" done\n"); +#else + priv->phy_configured = 1; +#endif + +#ifndef CONFIG_MII +#error Need config_phy +#endif + priv->speed = miiphy_speed(dev->name, phy_addr); + priv->duplex = miiphy_duplex(dev->name, phy_addr); + + return 0; } -int designware_initialize(ulong base_addr, u32 interface) +#if defined(CONFIG_MII) +static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) +{ + struct eth_device *dev; + + dev = eth_get_dev_by_name(devname); + if (dev) + eth_mdio_read(dev, addr, reg, val); + + return 0; +} + +static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) +{ + struct eth_device *dev; + + dev = eth_get_dev_by_name(devname); + if (dev) + eth_mdio_write(dev, addr, reg, val); + + return 0; +} +#endif + +int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface) { struct eth_device *dev; struct dw_eth_dev *priv; + printf("dw_initalize\n"); dev = (struct eth_device *) malloc(sizeof(struct eth_device)); if (!dev) return -ENOMEM; @@ -423,14 +601,20 @@ int designware_initialize(ulong base_addr, u32 interface) memset(dev, 0, sizeof(struct eth_device)); memset(priv, 0, sizeof(struct dw_eth_dev)); - sprintf(dev->name, "dwmac.%lx", base_addr); + sprintf(dev->name, "mii%d", id); dev->iobase = (int)base_addr; dev->priv = priv; + printf("Get address\n"); + eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]); + priv->dev = dev; priv->mac_regs_p = (struct eth_mac_regs *)base_addr; priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + DW_DMA_BASE_OFFSET); + priv->address = phy_addr; + priv->phy_configured = 0; + priv->interface = interface; dev->init = dw_eth_init; dev->send = dw_eth_send; @@ -438,12 +622,13 @@ int designware_initialize(ulong base_addr, u32 interface) dev->halt = dw_eth_halt; dev->write_hwaddr = dw_write_hwaddr; + printf("Get eth register\n"); eth_register(dev); - priv->interface = interface; +#if defined(CONFIG_MII) + printf("Get eth miiphy_register\n"); - dw_mdio_init(dev->name, priv->mac_regs_p); - priv->bus = miiphy_get_dev_by_name(dev->name); - - return dw_phy_init(dev); + miiphy_register(dev->name, dw_mii_read, dw_mii_write); +#endif + return 1; } diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 382b0c7..60b1103 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -16,6 +16,8 @@ #define CONFIG_MACRESET_TIMEOUT (3 * CONFIG_SYS_HZ) #define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ) +#define CONFIG_PHYRESET_TIMEOUT (3 * CONFIG_SYS_HZ) +#define CONFIG_AUTONEG_TIMEOUT (5 * CONFIG_SYS_HZ) struct eth_mac_regs { u32 conf; /* 0x00 */ @@ -215,9 +217,14 @@ struct dmamacdescr { #endif struct dw_eth_dev { + u32 address; u32 interface; + u32 speed; + u32 duplex; u32 tx_currdescnum; u32 rx_currdescnum; + u32 phy_configured; + u32 link_printed; struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM]; struct dmamacdescr rx_mac_descrtable[CONFIG_RX_DESCR_NUM]; @@ -229,8 +236,15 @@ struct dw_eth_dev { struct eth_dma_regs *dma_regs_p; struct eth_device *dev; - struct phy_device *phydev; - struct mii_dev *bus; }; +/* Speed specific definitions */ +#define SPEED_10M 1 +#define SPEED_100M 2 +#define SPEED_1000M 3 + +/* Duplex mode specific definitions */ +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + #endif diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 5d7e3be..506efb2 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -53,6 +53,8 @@ static struct phy_driver KS8721_driver = { static int ksz90xx_startup(struct phy_device *phydev) { unsigned phy_ctl; + + printf("ksz90xx_startup\n"); genphy_update_link(phydev); phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL); @@ -215,6 +217,7 @@ static struct phy_driver ksz9031_driver = { int phy_micrel_init(void) { + printf("phy_micrel_init\n"); phy_register(&KSZ804_driver); #ifdef CONFIG_PHY_MICREL_KSZ9021 phy_register(&ksz9021_driver); diff --git a/include/configs/bf609-ezkit.h b/include/configs/bf609-ezkit.h index 12192ff..1a43e1b 100644 --- a/include/configs/bf609-ezkit.h +++ b/include/configs/bf609-ezkit.h @@ -72,13 +72,12 @@ #define CONFIG_NET_MULTI #define CONFIG_HOSTNAME "bf609-ezkit" #define CONFIG_DESIGNWARE_ETH -#define CONFIG_PHY_ADDR 1 #define CONFIG_DW_PORTS 1 +#define CONFIG_DW_AUTONEG #define CONFIG_DW_ALTDESCRIPTOR #define CONFIG_CMD_NET #define CONFIG_CMD_MII #define CONFIG_MII -#define CONFIG_PHYLIB /* i2c Settings */ #define CONFIG_BFIN_TWI_I2C diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h index 56f993a..ded6cb6 100644 --- a/include/configs/socfpga_common.h +++ b/include/configs/socfpga_common.h @@ -206,6 +206,46 @@ #define CONFIG_ENV_IS_NOWHERE /* + * network support + */ +#ifndef CONFIG_SOCFPGA_VIRTUAL_TARGET +#define CONFIG_DESIGNWARE_ETH 1 +#endif + +#ifdef CONFIG_DESIGNWARE_ETH +#define CONFIG_EMAC0_BASE SOCFPGA_EMAC0_ADDRESS +#define CONFIG_EMAC1_BASE SOCFPGA_EMAC1_ADDRESS +/* console support for network */ +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_MII +#define CONFIG_CMD_NET +#define CONFIG_CMD_PING +/* designware */ +#define CONFIG_NET_MULTI +#define CONFIG_DW_ALTDESCRIPTOR +#define CONFIG_DW_SEARCH_PHY +#define CONFIG_MII +#define CONFIG_PHY_GIGE +#define CONFIG_DW_AUTONEG +#define CONFIG_AUTONEG_TIMEOUT (15 * CONFIG_SYS_HZ) +#define CONFIG_PHYLIB +#define CONFIG_PHY_MICREL +#define CONFIG_PHY_MICREL_KSZ9021 +/* phy */ +#define CONFIG_EPHY0_PHY_ADDR 0 +#define CONFIG_EPHY1_PHY_ADDR 4 +#define CONFIG_KSZ9021_CLK_SKEW_ENV "micrel-ksz9021-clk-skew" +#define CONFIG_KSZ9021_CLK_SKEW_VAL 0xf0f0 +#define CONFIG_KSZ9021_DATA_SKEW_ENV "micrel-ksz9021-data-skew" +#define CONFIG_KSZ9021_DATA_SKEW_VAL 0x0 +/* Type of PHY available */ +#define SOCFPGA_PHYSEL_ENUM_GMII 0x0 +#define SOCFPGA_PHYSEL_ENUM_MII 0x1 +#define SOCFPGA_PHYSEL_ENUM_RGMII 0x2 +#define SOCFPGA_PHYSEL_ENUM_RMII 0x3 +#endif /* CONFIG_DESIGNWARE_ETH */ + +/* * SPL "Second Program Loader" aka Initial Software */ diff --git a/include/configs/spear-common.h b/include/configs/spear-common.h index c0eba37..55f100a 100644 --- a/include/configs/spear-common.h +++ b/include/configs/spear-common.h @@ -17,9 +17,11 @@ /* Ethernet driver configuration */ #define CONFIG_MII #define CONFIG_DESIGNWARE_ETH +#define CONFIG_DW_SEARCH_PHY +#define CONFIG_DW0_PHY 1 #define CONFIG_NET_MULTI -#define CONFIG_PHYLIB #define CONFIG_PHY_RESET_DELAY 10000 /* in usec */ +#define CONFIG_DW_AUTONEG #define CONFIG_PHY_GIGE /* Include GbE speed/duplex detection */ /* USBD driver configuration */ diff --git a/include/configs/spear6xx_evb.h b/include/configs/spear6xx_evb.h index 28dddcc..7f4dc58 100644 --- a/include/configs/spear6xx_evb.h +++ b/include/configs/spear6xx_evb.h @@ -37,9 +37,6 @@ #define CONFIG_SYS_FSMC_NAND_8BIT #define CONFIG_SYS_NAND_BASE 0xD2000000 -/* Ethernet PHY configuration */ -#define CONFIG_PHY_NATSEMI - /* Environment Settings */ #define CONFIG_EXTRA_ENV_SETTINGS CONFIG_EXTRA_ENV_USBTTY diff --git a/include/netdev.h b/include/netdev.h index e211f18..72a0503 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -36,7 +36,7 @@ int calxedaxgmac_initialize(u32 id, ulong base_addr); int cs8900_initialize(u8 dev_num, int base_addr); int davinci_emac_initialize(void); int dc21x4x_initialize(bd_t *bis); -int designware_initialize(ulong base_addr, u32 interface); +int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface); int dm9000_initialize(bd_t *bis); int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot