X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmacb.c;h=e62aefcd0d6cadf257dd56807983c5a5b830f9e4;hb=f24e482ae0b856fcf18e8e6956ab3f6b59f3693f;hp=0835fdc306088e097e6b2509f8b0ddb83b1f76ff;hpb=2313d48445e59f063ec9a3b4940fe8252737db76;p=oweals%2Fu-boot.git diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 0835fdc306..e62aefcd0d 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include /* @@ -39,16 +40,34 @@ #include #include #include -#include +#include #include "macb.h" +DECLARE_GLOBAL_DATA_PTR; + #define MACB_RX_BUFFER_SIZE 4096 #define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) #define MACB_TX_RING_SIZE 16 #define MACB_TX_TIMEOUT 1000 #define MACB_AUTONEG_TIMEOUT 5000000 +#ifdef CONFIG_MACB_ZYNQ +/* INCR4 AHB bursts */ +#define MACB_ZYNQ_GEM_DMACR_BLENGTH 0x00000004 +/* Use full configured addressable space (8 Kb) */ +#define MACB_ZYNQ_GEM_DMACR_RXSIZE 0x00000300 +/* Use full configured addressable space (4 Kb) */ +#define MACB_ZYNQ_GEM_DMACR_TXSIZE 0x00000400 +/* Set RXBUF with use of 128 byte */ +#define MACB_ZYNQ_GEM_DMACR_RXBUF 0x00020000 +#define MACB_ZYNQ_GEM_DMACR_INIT \ + (MACB_ZYNQ_GEM_DMACR_BLENGTH | \ + MACB_ZYNQ_GEM_DMACR_RXSIZE | \ + MACB_ZYNQ_GEM_DMACR_TXSIZE | \ + MACB_ZYNQ_GEM_DMACR_RXBUF) +#endif + struct macb_dma_desc { u32 addr; u32 ctrl; @@ -108,6 +127,16 @@ struct macb_device { #endif unsigned short phy_addr; struct mii_dev *bus; +#ifdef CONFIG_PHYLIB + struct phy_device *phydev; +#endif + +#ifdef CONFIG_DM_ETH +#ifdef CONFIG_CLK + unsigned long pclk_rate; +#endif + phy_interface_t phy_interface; +#endif }; #ifndef CONFIG_DM_ETH #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) @@ -199,39 +228,41 @@ void __weak arch_get_mdio_control(const char *name) #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) -int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) +int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg) { + u16 value = 0; #ifdef CONFIG_DM_ETH - struct udevice *dev = eth_get_dev_by_name(devname); + struct udevice *dev = eth_get_dev_by_name(bus->name); struct macb_device *macb = dev_get_priv(dev); #else - struct eth_device *dev = eth_get_dev_by_name(devname); + struct eth_device *dev = eth_get_dev_by_name(bus->name); struct macb_device *macb = to_macb(dev); #endif if (macb->phy_addr != phy_adr) return -1; - arch_get_mdio_control(devname); - *value = macb_mdio_read(macb, reg); + arch_get_mdio_control(bus->name); + value = macb_mdio_read(macb, reg); - return 0; + return value; } -int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) +int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg, + u16 value) { #ifdef CONFIG_DM_ETH - struct udevice *dev = eth_get_dev_by_name(devname); + struct udevice *dev = eth_get_dev_by_name(bus->name); struct macb_device *macb = dev_get_priv(dev); #else - struct eth_device *dev = eth_get_dev_by_name(devname); + struct eth_device *dev = eth_get_dev_by_name(bus->name); struct macb_device *macb = to_macb(dev); #endif if (macb->phy_addr != phy_adr) return -1; - arch_get_mdio_control(devname); + arch_get_mdio_control(bus->name); macb_mdio_write(macb, reg, value); return 0; @@ -243,33 +274,35 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) { if (rx) - invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + - MACB_RX_DMA_DESC_SIZE); + invalidate_dcache_range(macb->rx_ring_dma, + ALIGN(macb->rx_ring_dma + MACB_RX_DMA_DESC_SIZE, + PKTALIGN)); else - invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + - MACB_TX_DMA_DESC_SIZE); + invalidate_dcache_range(macb->tx_ring_dma, + ALIGN(macb->tx_ring_dma + MACB_TX_DMA_DESC_SIZE, + PKTALIGN)); } static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) { if (rx) flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + - MACB_RX_DMA_DESC_SIZE); + ALIGN(MACB_RX_DMA_DESC_SIZE, PKTALIGN)); else flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + - MACB_TX_DMA_DESC_SIZE); + ALIGN(MACB_TX_DMA_DESC_SIZE, PKTALIGN)); } static inline void macb_flush_rx_buffer(struct macb_device *macb) { flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + - MACB_RX_BUFFER_SIZE); + ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN)); } static inline void macb_invalidate_rx_buffer(struct macb_device *macb) { invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + - MACB_RX_BUFFER_SIZE); + ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN)); } #if defined(CONFIG_CMD_NET) @@ -433,8 +466,7 @@ static void macb_phy_reset(struct macb_device *macb, const char *name) name, status); } -#ifdef CONFIG_MACB_SEARCH_PHY -static int macb_phy_find(struct macb_device *macb) +static int macb_phy_find(struct macb_device *macb, const char *name) { int i; u16 phy_id; @@ -444,53 +476,72 @@ static int macb_phy_find(struct macb_device *macb) macb->phy_addr = i; phy_id = macb_mdio_read(macb, MII_PHYSID1); if (phy_id != 0xffff) { - printf("%s: PHY present at %d\n", macb->netdev.name, i); - return 1; + printf("%s: PHY present at %d\n", name, i); + return 0; } } /* PHY isn't up to snuff */ - printf("%s: PHY not found\n", macb->netdev.name); + printf("%s: PHY not found\n", name); - return 0; + return -ENODEV; } -#endif /* CONFIG_MACB_SEARCH_PHY */ +/** + * macb_linkspd_cb - Linkspeed change callback function + * @regs: Base Register of MACB devices + * @speed: Linkspeed + * Returns 0 when operation success and negative errno number + * when operation failed. + */ +int __weak macb_linkspd_cb(void *regs, unsigned int speed) +{ + return 0; +} +#ifdef CONFIG_DM_ETH +static int macb_phy_init(struct udevice *dev, const char *name) +#else static int macb_phy_init(struct macb_device *macb, const char *name) +#endif { -#ifdef CONFIG_PHYLIB - struct phy_device *phydev; +#ifdef CONFIG_DM_ETH + struct macb_device *macb = dev_get_priv(dev); #endif u32 ncfgr; u16 phy_id, status, adv, lpa; int media, speed, duplex; + int ret; int i; arch_get_mdio_control(name); -#ifdef CONFIG_MACB_SEARCH_PHY /* Auto-detect phy_addr */ - if (!macb_phy_find(macb)) - return 0; -#endif /* CONFIG_MACB_SEARCH_PHY */ + ret = macb_phy_find(macb, name); + if (ret) + return ret; /* Check if the PHY is up to snuff... */ phy_id = macb_mdio_read(macb, MII_PHYSID1); if (phy_id == 0xffff) { printf("%s: No PHY present\n", name); - return 0; + return -ENODEV; } #ifdef CONFIG_PHYLIB +#ifdef CONFIG_DM_ETH + macb->phydev = phy_connect(macb->bus, macb->phy_addr, dev, + macb->phy_interface); +#else /* need to consider other phy interface mode */ - phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev, + macb->phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev, PHY_INTERFACE_MODE_RGMII); - if (!phydev) { +#endif + if (!macb->phydev) { printf("phy_connect failed\n"); return -ENODEV; } - phy_config(phydev); + phy_config(macb->phydev); #endif status = macb_mdio_read(macb, MII_BMSR); @@ -509,7 +560,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name) if (!(status & BMSR_LSTATUS)) { printf("%s: link down (status: 0x%04x)\n", name, status); - return 0; + return -ENETDOWN; } /* First check for GMAC and that it is GiB capable */ @@ -533,7 +584,11 @@ static int macb_phy_init(struct macb_device *macb, const char *name) macb_writel(macb, NCFGR, ncfgr); - return 1; + ret = macb_linkspd_cb(macb->regs, _1000BASET); + if (ret) + return ret; + + return 0; } } @@ -552,13 +607,21 @@ static int macb_phy_init(struct macb_device *macb, const char *name) ncfgr = macb_readl(macb, NCFGR); ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); - if (speed) + if (speed) { ncfgr |= MACB_BIT(SPD); + ret = macb_linkspd_cb(macb->regs, _100BASET); + } else { + ret = macb_linkspd_cb(macb->regs, _10BASET); + } + + if (ret) + return ret; + if (duplex) ncfgr |= MACB_BIT(FD); macb_writel(macb, NCFGR, ncfgr); - return 1; + return 0; } static int gmac_init_multi_queues(struct macb_device *macb) @@ -577,7 +640,7 @@ static int gmac_init_multi_queues(struct macb_device *macb) macb->dummy_desc->ctrl = TXBUF_USED; macb->dummy_desc->addr = 0; flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma + - MACB_TX_DUMMY_DMA_DESC_SIZE); + ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN)); for (i = 1; i < num_queues; i++) gem_writel_queue_TBQP(macb, macb->dummy_desc_dma, i - 1); @@ -585,9 +648,17 @@ static int gmac_init_multi_queues(struct macb_device *macb) return 0; } +#ifdef CONFIG_DM_ETH +static int _macb_init(struct udevice *dev, const char *name) +#else static int _macb_init(struct macb_device *macb, const char *name) +#endif { +#ifdef CONFIG_DM_ETH + struct macb_device *macb = dev_get_priv(dev); +#endif unsigned long paddr; + int ret; int i; /* @@ -621,6 +692,10 @@ static int _macb_init(struct macb_device *macb, const char *name) macb->tx_tail = 0; macb->next_rx_tail = 0; +#ifdef CONFIG_MACB_ZYNQ + macb_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT); +#endif + macb_writel(macb, RBQP, macb->rx_ring_dma); macb_writel(macb, TBQP, macb->tx_ring_dma); @@ -634,13 +709,36 @@ static int _macb_init(struct macb_device *macb, const char *name) * When the GMAC IP without GE feature, this bit is used * to select interface between RMII and MII. */ +#ifdef CONFIG_DM_ETH + if ((macb->phy_interface == PHY_INTERFACE_MODE_RMII) || + (macb->phy_interface == PHY_INTERFACE_MODE_RGMII)) + gem_writel(macb, UR, GEM_BIT(RGMII)); + else + gem_writel(macb, UR, 0); +#else #if defined(CONFIG_RGMII) || defined(CONFIG_RMII) gem_writel(macb, UR, GEM_BIT(RGMII)); #else gem_writel(macb, UR, 0); +#endif #endif } else { /* choose RMII or MII mode. This depends on the board */ +#ifdef CONFIG_DM_ETH +#ifdef CONFIG_AT91FAMILY + if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) { + macb_writel(macb, USRIO, + MACB_BIT(RMII) | MACB_BIT(CLKEN)); + } else { + macb_writel(macb, USRIO, MACB_BIT(CLKEN)); + } +#else + if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) + macb_writel(macb, USRIO, 0); + else + macb_writel(macb, USRIO, MACB_BIT(MII)); +#endif +#else #ifdef CONFIG_RMII #ifdef CONFIG_AT91FAMILY macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); @@ -654,10 +752,16 @@ static int _macb_init(struct macb_device *macb, const char *name) macb_writel(macb, USRIO, MACB_BIT(MII)); #endif #endif /* CONFIG_RMII */ +#endif } - if (!macb_phy_init(macb, name)) - return -1; +#ifdef CONFIG_DM_ETH + ret = macb_phy_init(dev, name); +#else + ret = macb_phy_init(macb, name); +#endif + if (ret) + return ret; /* Enable TX and RX */ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); @@ -699,7 +803,11 @@ static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) static u32 macb_mdc_clk_div(int id, struct macb_device *macb) { u32 config; +#if defined(CONFIG_DM_ETH) && defined(CONFIG_CLK) + unsigned long macb_hz = macb->pclk_rate; +#else unsigned long macb_hz = get_macb_pclk_rate(id); +#endif if (macb_hz < 20000000) config = MACB_BF(CLK, MACB_CLK_DIV8); @@ -716,7 +824,12 @@ static u32 macb_mdc_clk_div(int id, struct macb_device *macb) static u32 gem_mdc_clk_div(int id, struct macb_device *macb) { u32 config; + +#if defined(CONFIG_DM_ETH) && defined(CONFIG_CLK) + unsigned long macb_hz = macb->pclk_rate; +#else unsigned long macb_hz = get_macb_pclk_rate(id); +#endif if (macb_hz < 20000000) config = GEM_BF(CLK, GEM_CLK_DIV8); @@ -862,7 +975,17 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) eth_register(netdev); #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) - miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write); + int retval; + struct mii_dev *mdiodev = mdio_alloc(); + if (!mdiodev) + return -ENOMEM; + strncpy(mdiodev->name, netdev->name, MDIO_NAME_LEN); + mdiodev->read = macb_miiphy_read; + mdiodev->write = macb_miiphy_write; + + retval = mdio_register(mdiodev); + if (retval < 0) + return retval; macb->bus = miiphy_get_dev_by_name(netdev->name); #endif return 0; @@ -873,9 +996,7 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) static int macb_start(struct udevice *dev) { - struct macb_device *macb = dev_get_priv(dev); - - return _macb_init(macb, dev->name); + return _macb_init(dev, dev->name); } static int macb_send(struct udevice *dev, void *packet, int length) @@ -928,32 +1049,121 @@ static const struct eth_ops macb_eth_ops = { .write_hwaddr = macb_write_hwaddr, }; +#ifdef CONFIG_CLK +static int macb_enable_clk(struct udevice *dev) +{ + struct macb_device *macb = dev_get_priv(dev); + struct clk clk; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return -EINVAL; + + /* + * Zynq clock driver didn't support for enable or disable + * clock. Hence, clk_enable() didn't apply for Zynq + */ +#ifndef CONFIG_MACB_ZYNQ + ret = clk_enable(&clk); + if (ret) + return ret; +#endif + + clk_rate = clk_get_rate(&clk); + if (!clk_rate) + return -EINVAL; + + macb->pclk_rate = clk_rate; + + return 0; +} +#endif + static int macb_eth_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct macb_device *macb = dev_get_priv(dev); + const char *phy_mode; + __maybe_unused int ret; + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", + NULL); + if (phy_mode) + macb->phy_interface = phy_get_interface_by_name(phy_mode); + if (macb->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } macb->regs = (void *)pdata->iobase; +#ifdef CONFIG_CLK + ret = macb_enable_clk(dev); + if (ret) + return ret; +#endif + _macb_eth_initialize(macb); + #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) - miiphy_register(dev->name, macb_miiphy_read, macb_miiphy_write); + macb->bus = mdio_alloc(); + if (!macb->bus) + return -ENOMEM; + strncpy(macb->bus->name, dev->name, MDIO_NAME_LEN); + macb->bus->read = macb_miiphy_read; + macb->bus->write = macb_miiphy_write; + + ret = mdio_register(macb->bus); + if (ret < 0) + return ret; macb->bus = miiphy_get_dev_by_name(dev->name); #endif return 0; } +static int macb_eth_remove(struct udevice *dev) +{ + struct macb_device *macb = dev_get_priv(dev); + +#ifdef CONFIG_PHYLIB + free(macb->phydev); +#endif + mdio_unregister(macb->bus); + mdio_free(macb->bus); + + return 0; +} + +/** + * macb_late_eth_ofdata_to_platdata + * @dev: udevice struct + * Returns 0 when operation success and negative errno number + * when operation failed. + */ +int __weak macb_late_eth_ofdata_to_platdata(struct udevice *dev) +{ + return 0; +} + static int macb_eth_ofdata_to_platdata(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); - pdata->iobase = dev_get_addr(dev); - return 0; + pdata->iobase = devfdt_get_addr(dev); + + return macb_late_eth_ofdata_to_platdata(dev); } static const struct udevice_id macb_eth_ids[] = { { .compatible = "cdns,macb" }, + { .compatible = "cdns,at91sam9260-macb" }, + { .compatible = "atmel,sama5d2-gem" }, + { .compatible = "atmel,sama5d3-gem" }, + { .compatible = "atmel,sama5d4-gem" }, + { .compatible = "cdns,zynq-gem" }, { } }; @@ -963,6 +1173,7 @@ U_BOOT_DRIVER(eth_macb) = { .of_match = macb_eth_ids, .ofdata_to_platdata = macb_eth_ofdata_to_platdata, .probe = macb_eth_probe, + .remove = macb_eth_remove, .ops = &macb_eth_ops, .priv_auto_alloc_size = sizeof(struct macb_device), .platdata_auto_alloc_size = sizeof(struct eth_pdata),