diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/gmac_rockchip.c | 1 | ||||
-rw-r--r-- | drivers/net/macb.c | 186 | ||||
-rw-r--r-- | drivers/net/mtk_eth.c | 57 | ||||
-rw-r--r-- | drivers/net/mtk_eth.h | 9 | ||||
-rw-r--r-- | drivers/net/ti/Kconfig | 8 | ||||
-rw-r--r-- | drivers/net/ti/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/ti/am65-cpsw-nuss.c | 190 | ||||
-rw-r--r-- | drivers/net/ti/cpsw_mdio.c | 198 | ||||
-rw-r--r-- | drivers/net/ti/cpsw_mdio.h | 2 |
9 files changed, 367 insertions, 287 deletions
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c index 04008d2b198..c1bae3f68bd 100644 --- a/drivers/net/gmac_rockchip.c +++ b/drivers/net/gmac_rockchip.c @@ -13,7 +13,6 @@ #include <phy.h> #include <syscon.h> #include <asm/global_data.h> -#include <asm/io.h> #include <asm/arch-rockchip/periph.h> #include <asm/arch-rockchip/clock.h> #include <asm/arch-rockchip/hardware.h> diff --git a/drivers/net/macb.c b/drivers/net/macb.c index bfc48dac079..bca014c3cbb 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -128,6 +128,8 @@ struct macb_device { unsigned long dummy_desc_dma; const struct device *dev; + unsigned int duplex; + unsigned int speed; unsigned short phy_addr; struct mii_dev *bus; #ifdef CONFIG_PHYLIB @@ -178,6 +180,12 @@ static int gem_is_gigabit_capable(struct macb_device *macb) return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4(); } +/* Is the port a fixed link */ +static int macb_port_is_fixed_link(struct macb_device *macb) +{ + return macb->phy_addr > PHY_MAX_ADDR; +} + static void macb_mdio_write(struct macb_device *macb, u8 phy_adr, u8 reg, u16 value) { @@ -666,97 +674,109 @@ static int macb_phy_init(struct udevice *dev, const char *name) int i; arch_get_mdio_control(name); - /* Auto-detect phy_addr */ - ret = macb_phy_find(macb, name); - if (ret) - return ret; + /* If port is not fixed -> setup PHY */ + if (!macb_port_is_fixed_link(macb)) { + /* Auto-detect phy_addr */ + ret = macb_phy_find(macb, name); + if (ret) + return ret; - /* Check if the PHY is up to snuff... */ - phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1); - if (phy_id == 0xffff) { - printf("%s: No PHY present\n", name); - return -ENODEV; - } + /* Check if the PHY is up to snuff... */ + phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1); + if (phy_id == 0xffff) { + printf("%s: No PHY present\n", name); + return -ENODEV; + } #ifdef CONFIG_PHYLIB - macb->phydev = phy_connect(macb->bus, macb->phy_addr, dev, - macb->phy_interface); - if (!macb->phydev) { - printf("phy_connect failed\n"); - return -ENODEV; - } + macb->phydev = phy_connect(macb->bus, macb->phy_addr, dev, + macb->phy_interface); + if (!macb->phydev) { + printf("phy_connect failed\n"); + return -ENODEV; + } - phy_config(macb->phydev); + phy_config(macb->phydev); #endif - status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); - if (!(status & BMSR_LSTATUS)) { - /* Try to re-negotiate if we don't have link already. */ - macb_phy_reset(macb, name); - - for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { - status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); - if (status & BMSR_LSTATUS) { - /* - * Delay a bit after the link is established, - * so that the next xfer does not fail - */ - mdelay(10); - break; + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + macb_phy_reset(macb, name); + + for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); + if (status & BMSR_LSTATUS) { + /* + * Delay a bit after the link is established, + * so that the next xfer does not fail + */ + mdelay(10); + break; + } + udelay(100); } - udelay(100); } - } - if (!(status & BMSR_LSTATUS)) { - printf("%s: link down (status: 0x%04x)\n", - name, status); - return -ENETDOWN; - } + if (!(status & BMSR_LSTATUS)) { + printf("%s: link down (status: 0x%04x)\n", + name, status); + return -ENETDOWN; + } - /* First check for GMAC and that it is GiB capable */ - if (gem_is_gigabit_capable(macb)) { - lpa = macb_mdio_read(macb, macb->phy_addr, MII_STAT1000); + /* First check for GMAC and that it is GiB capable */ + if (gem_is_gigabit_capable(macb)) { + lpa = macb_mdio_read(macb, macb->phy_addr, MII_STAT1000); - if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL | - LPA_1000XHALF)) { - duplex = ((lpa & (LPA_1000FULL | LPA_1000XFULL)) ? - 1 : 0); + if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL | + LPA_1000XHALF)) { + duplex = ((lpa & (LPA_1000FULL | LPA_1000XFULL)) ? + 1 : 0); - printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", - name, - duplex ? "full" : "half", - lpa); + printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", + name, + duplex ? "full" : "half", + lpa); - ncfgr = macb_readl(macb, NCFGR); - ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); - ncfgr |= GEM_BIT(GBE); + ncfgr = macb_readl(macb, NCFGR); + ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); + ncfgr |= GEM_BIT(GBE); - if (duplex) - ncfgr |= MACB_BIT(FD); + if (duplex) + ncfgr |= MACB_BIT(FD); - macb_writel(macb, NCFGR, ncfgr); + macb_writel(macb, NCFGR, ncfgr); - ret = macb_linkspd_cb(dev, _1000BASET); - if (ret) - return ret; + ret = macb_linkspd_cb(dev, _1000BASET); + if (ret) + return ret; - return 0; + return 0; + } } - } - /* fall back for EMAC checking */ - adv = macb_mdio_read(macb, macb->phy_addr, MII_ADVERTISE); - lpa = macb_mdio_read(macb, macb->phy_addr, MII_LPA); - media = mii_nway_result(lpa & adv); - speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) - ? 1 : 0); - duplex = (media & ADVERTISE_FULL) ? 1 : 0; - printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", - name, - speed ? "100" : "10", - duplex ? "full" : "half", - lpa); + /* fall back for EMAC checking */ + adv = macb_mdio_read(macb, macb->phy_addr, MII_ADVERTISE); + lpa = macb_mdio_read(macb, macb->phy_addr, MII_LPA); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", + name, + speed ? "100" : "10", + duplex ? "full" : "half", + lpa); + } else { + /* if macb port is a fixed link */ + /* TODO : manage gigabit capable processors */ + speed = macb->speed; + duplex = macb->duplex; + printf("%s: link up, %sMbps %s-duplex\n", + name, + speed ? "100" : "10", + duplex ? "full" : "half"); + } ncfgr = macb_readl(macb, NCFGR); ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); @@ -1276,6 +1296,28 @@ int __weak macb_late_eth_of_to_plat(struct udevice *dev) static int macb_eth_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); + struct macb_device *macb = dev_get_priv(dev); + void *blob = (void *)gd->fdt_blob; + int node = dev_of_offset(dev); + int fl_node, speed_fdt; + + /* fetch 'fixed-link' property */ + fl_node = fdt_subnode_offset(blob, node, "fixed-link"); + if (fl_node >= 0) { + /* set phy_addr to invalid value for fixed link */ + macb->phy_addr = PHY_MAX_ADDR + 1; + macb->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex"); + speed_fdt = fdtdec_get_int(blob, fl_node, "speed", 0); + if (speed_fdt == 100) { + macb->speed = 1; + } else if (speed_fdt == 10) { + macb->speed = 0; + } else { + printf("%s: The given speed %d of ethernet in the DT is not supported\n", + __func__, speed_fdt); + return -EINVAL; + } + } pdata->iobase = (uintptr_t)dev_remap_addr(dev); if (!pdata->iobase) diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 3cfce058451..75e7bcf83b7 100644 --- a/drivers/net/mtk_eth.c +++ b/drivers/net/mtk_eth.c @@ -137,6 +137,7 @@ struct mtk_eth_priv { int force_mode; int speed; int duplex; + int mdc; bool pn_swap; struct phy_device *phydev; @@ -1245,7 +1246,8 @@ static int mtk_phy_start(struct mtk_eth_priv *priv) } if (!priv->force_mode) { - if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || + priv->phy_interface == PHY_INTERFACE_MODE_XGMII) mtk_xphy_link_adjust(priv); else mtk_phy_link_adjust(priv); @@ -1515,7 +1517,7 @@ static void mtk_mac_init(struct mtk_eth_priv *priv) static void mtk_xmac_init(struct mtk_eth_priv *priv) { - u32 sts; + u32 force_link = 0; switch (priv->phy_interface) { case PHY_INTERFACE_MODE_USXGMII: @@ -1530,15 +1532,19 @@ static void mtk_xmac_init(struct mtk_eth_priv *priv) SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id), 0); - if (priv->gmac_id == 1) { + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII && + priv->gmac_id == 1) { mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX, NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL); - } else if (priv->gmac_id == 2) { - sts = mtk_gmac_read(priv, XGMAC_STS(priv->gmac_id)); - sts |= XGMAC_FORCE_LINK; - mtk_gmac_write(priv, XGMAC_STS(priv->gmac_id), sts); } + if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII || + priv->gmac_id == 2) + force_link = XGMAC_FORCE_LINK(priv->gmac_id); + + mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id), + XGMAC_FORCE_LINK(priv->gmac_id), force_link); + /* Force GMAC link down */ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE); } @@ -1607,6 +1613,26 @@ static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0); } +static void mtk_eth_mdc_init(struct mtk_eth_priv *priv) +{ + u32 divider; + + if (priv->mdc == 0) + return; + + divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER); + + /* Configure MDC turbo mode */ + if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) + mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO); + else + mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO); + + /* Configure MDC divider */ + mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG, + FIELD_PREP(PHY_MDC_CFG, divider)); +} + static int mtk_eth_start(struct udevice *dev) { struct mtk_eth_priv *priv = dev_get_priv(dev); @@ -1803,8 +1829,12 @@ static int mtk_eth_probe(struct udevice *dev) noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC, ARCH_DMA_MINALIGN); + /* Set MDC divider */ + mtk_eth_mdc_init(priv); + /* Set MAC mode */ - if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || + priv->phy_interface == PHY_INTERFACE_MODE_XGMII) mtk_xmac_init(priv); else mtk_mac_init(priv); @@ -1881,6 +1911,17 @@ static int mtk_eth_of_to_plat(struct udevice *dev) priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0); + priv->mdc = 0; + subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio"); + if (ofnode_valid(subnode)) { + priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000); + if (priv->mdc > MDC_MAX_FREQ || + priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) { + printf("error: MDIO clock frequency out of range\n"); + return -EINVAL; + } + } + /* Interface mode is required */ pdata->phy_interface = dev_read_phy_mode(dev); priv->phy_interface = pdata->phy_interface; diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h index 491cac56a81..fd31c782c7f 100644 --- a/drivers/net/mtk_eth.h +++ b/drivers/net/mtk_eth.h @@ -180,6 +180,12 @@ enum mkt_eth_capabilities { /* GMAC Registers */ +#define GMAC_PPSC_REG 0x0000 +#define PHY_MDC_CFG GENMASK(29, 24) +#define MDC_TURBO BIT(20) +#define MDC_MAX_FREQ 25000000 +#define MDC_MAX_DIVIDER 63 + #define GMAC_PIAC_REG 0x0004 #define PHY_ACS_ST BIT(31) #define MDIO_REG_ADDR_S 25 @@ -197,6 +203,7 @@ enum mkt_eth_capabilities { #define P1_XGMAC_FORCE_LINK BIT(15) #define GMAC_MAC_MISC_REG 0x0010 +#define MISC_MDC_TURBO BIT(4) #define GMAC_GSW_CFG_REG 0x0080 #define GSWTX_IPG_M 0xF0000 @@ -261,7 +268,7 @@ enum mkt_eth_capabilities { /* XGMAC Status Registers */ #define XGMAC_STS(x) (((x) == 2) ? 0x001C : 0x000C) -#define XGMAC_FORCE_LINK BIT(15) +#define XGMAC_FORCE_LINK(x) (((x) == 1) ? BIT(31) : BIT(15)) /* XGMAC Registers */ #define XGMAC_PORT_MCR(x) (0x2000 + (((x) - 1) * 0x1000)) diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index c75f4186285..72eccc99e5f 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -45,7 +45,15 @@ config TI_AM65_CPSW_NUSS imply MISC_INIT_R imply MISC imply SYSCON + imply MDIO_TI_CPSW select PHYLIB help This driver supports TI K3 MCU CPSW Nuss Ethernet controller in Texas Instruments K3 AM65x SoCs. + +config MDIO_TI_CPSW + bool "TI CPSW MDIO interface support" + depends on DM_MDIO + help + This driver supports the TI CPSW MDIO interface found in various + TI SoCs. diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile index 0ce0cf2828a..30c4c4b6d5a 100644 --- a/drivers/net/ti/Makefile +++ b/drivers/net/ti/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o -obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o cpsw_mdio.o +obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o +obj-$(CONFIG_MDIO_TI_CPSW) += cpsw_mdio.o diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 6da018c0f9d..d68ed671836 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -31,8 +31,6 @@ #include <linux/printk.h> #include <linux/soc/ti/ti-udma.h> -#include "cpsw_mdio.h" - #define AM65_CPSW_CPSWNU_MAX_PORTS 9 #define AM65_CPSW_SS_BASE 0x0 @@ -113,7 +111,6 @@ struct am65_cpsw_common { struct udevice *dev; fdt_addr_t ss_base; fdt_addr_t cpsw_base; - fdt_addr_t mdio_base; fdt_addr_t ale_base; struct clk fclk; @@ -122,13 +119,8 @@ struct am65_cpsw_common { u32 port_num; struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS]; - struct mii_dev *bus; u32 bus_freq; - struct gpio_desc mdio_gpio_reset; - u32 reset_delay_us; - u32 reset_post_delay_us; - struct dma dma_tx; struct dma dma_rx; u32 rx_next; @@ -140,13 +132,7 @@ struct am65_cpsw_priv { struct udevice *dev; struct am65_cpsw_common *cpsw_common; u32 port_id; - struct phy_device *phydev; - bool has_phy; - ofnode phy_node; - u32 phy_addr; - - bool mdio_manual_mode; }; #ifdef PKTSIZE_ALIGN @@ -622,111 +608,15 @@ static const struct eth_ops am65_cpsw_ops = { .read_rom_hwaddr = am65_cpsw_read_rom_hwaddr, }; -static const struct soc_attr k3_mdio_soc_data[] = { - { .family = "AM62X", .revision = "SR1.0" }, - { .family = "AM64X", .revision = "SR1.0" }, - { .family = "AM64X", .revision = "SR2.0" }, - { .family = "AM65X", .revision = "SR1.0" }, - { .family = "AM65X", .revision = "SR2.0" }, - { .family = "J7200", .revision = "SR1.0" }, - { .family = "J7200", .revision = "SR2.0" }, - { .family = "J721E", .revision = "SR1.0" }, - { .family = "J721E", .revision = "SR1.1" }, - { .family = "J721S2", .revision = "SR1.0" }, - { /* sentinel */ }, -}; - -static ofnode am65_cpsw_find_mdio(ofnode parent) -{ - ofnode node; - - ofnode_for_each_subnode(node, parent) - if (ofnode_device_is_compatible(node, "ti,cpsw-mdio")) - return node; - - return ofnode_null(); -} - -static int am65_cpsw_mdio_setup(struct udevice *dev) -{ - struct am65_cpsw_priv *priv = dev_get_priv(dev); - struct am65_cpsw_common *cpsw_common = priv->cpsw_common; - struct udevice *mdio_dev; - ofnode mdio; - int ret; - - mdio = am65_cpsw_find_mdio(dev_ofnode(cpsw_common->dev)); - if (!ofnode_valid(mdio)) - return 0; - - /* - * The MDIO controller is represented in the DT binding by a - * subnode of the MAC controller. - * - * We don't have a DM driver for the MDIO device yet, and thus any - * pinctrl setting on its node will be ignored. - * - * However, we do need to make sure the pins states tied to the - * MDIO node are configured properly. Fortunately, the core DM - * does that for use when we get a device, so we can work around - * that whole issue by just requesting a dummy MDIO driver to - * probe, and our pins will get muxed. - */ - ret = uclass_get_device_by_ofnode(UCLASS_MDIO, mdio, &mdio_dev); - if (ret) - return ret; - - return 0; -} - -static int am65_cpsw_mdio_init(struct udevice *dev) -{ - struct am65_cpsw_priv *priv = dev_get_priv(dev); - struct am65_cpsw_common *cpsw_common = priv->cpsw_common; - int ret; - - if (!priv->has_phy || cpsw_common->bus) - return 0; - - if (IS_ENABLED(CONFIG_DM_GPIO)) { - if (dm_gpio_is_valid(&cpsw_common->mdio_gpio_reset)) { - dm_gpio_set_value(&cpsw_common->mdio_gpio_reset, 1); - udelay(cpsw_common->reset_delay_us); - dm_gpio_set_value(&cpsw_common->mdio_gpio_reset, 0); - if (cpsw_common->reset_post_delay_us > 0) - udelay(cpsw_common->reset_post_delay_us); - } - } - - ret = am65_cpsw_mdio_setup(dev); - if (ret) - return ret; - - cpsw_common->bus = cpsw_mdio_init(dev->name, - cpsw_common->mdio_base, - cpsw_common->bus_freq, - clk_get_rate(&cpsw_common->fclk), - priv->mdio_manual_mode); - if (!cpsw_common->bus) - return -EFAULT; - - return 0; -} - static int am65_cpsw_phy_init(struct udevice *dev) { struct am65_cpsw_priv *priv = dev_get_priv(dev); - struct am65_cpsw_common *cpsw_common = priv->cpsw_common; struct eth_pdata *pdata = dev_get_plat(dev); struct phy_device *phydev; u32 supported = PHY_GBIT_FEATURES; int ret; - phydev = phy_connect(cpsw_common->bus, - priv->phy_addr, - priv->dev, - pdata->phy_interface); - + phydev = dm_eth_phy_connect(dev); if (!phydev) { dev_err(dev, "phy_connect() failed\n"); return -ENODEV; @@ -740,13 +630,10 @@ static int am65_cpsw_phy_init(struct udevice *dev) } phydev->advertising = phydev->supported; - if (ofnode_valid(priv->phy_node)) - phydev->node = priv->phy_node; - priv->phydev = phydev; ret = phy_config(phydev); if (ret < 0) - pr_err("phy_config() failed: %d", ret); + dev_err(dev, "phy_config() failed: %d", ret); return ret; } @@ -755,8 +642,6 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct am65_cpsw_priv *priv = dev_get_priv(dev); - struct ofnode_phandle_args out_args; - int ret = 0; dev_read_u32(dev, "reg", &priv->port_id); @@ -771,28 +656,7 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev) dev_err(dev, "Port %u speed froced to %uMbit\n", priv->port_id, pdata->max_speed); - priv->has_phy = true; - ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "phy-handle", - NULL, 0, 0, &out_args); - if (ret) { - dev_err(dev, "can't parse phy-handle port %u (%d)\n", - priv->port_id, ret); - priv->has_phy = false; - ret = 0; - } - - priv->phy_node = out_args.node; - if (priv->has_phy) { - ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr); - if (ret) { - dev_err(dev, "failed to get phy_addr port %u (%d)\n", - priv->port_id, ret); - goto out; - } - } - -out: - return ret; + return 0; } static int am65_cpsw_port_probe(struct udevice *dev) @@ -811,10 +675,6 @@ static int am65_cpsw_port_probe(struct udevice *dev) sprintf(portname, "%s%s", dev->parent->name, dev->name); device_set_name(dev, portname); - priv->mdio_manual_mode = false; - if (soc_device_match(k3_mdio_soc_data)) - priv->mdio_manual_mode = true; - ret = am65_cpsw_ofdata_parse_phy(dev); if (ret) goto out; @@ -823,13 +683,8 @@ static int am65_cpsw_port_probe(struct udevice *dev) if (ret) goto out; - ret = am65_cpsw_mdio_init(dev); - if (ret) - goto out; - ret = am65_cpsw_phy_init(dev); - if (ret) - goto out; + out: return ret; } @@ -837,7 +692,7 @@ out: static int am65_cpsw_probe_nuss(struct udevice *dev) { struct am65_cpsw_common *cpsw_common = dev_get_priv(dev); - ofnode ports_np, node, mdio_np; + ofnode ports_np, node; int ret, i; struct udevice *port_dev; @@ -862,25 +717,6 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) cpsw_common->cpsw_base = cpsw_common->ss_base + AM65_CPSW_CPSW_NU_BASE; cpsw_common->ale_base = cpsw_common->cpsw_base + AM65_CPSW_CPSW_NU_ALE_BASE; - cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE; - - if (IS_ENABLED(CONFIG_DM_GPIO)) { - /* get bus level PHY reset GPIO details */ - mdio_np = dev_read_subnode(dev, "mdio"); - if (!ofnode_valid(mdio_np)) { - ret = -ENOENT; - goto out; - } - - cpsw_common->reset_delay_us = ofnode_read_u32_default(mdio_np, "reset-delay-us", - DEFAULT_GPIO_RESET_DELAY); - cpsw_common->reset_post_delay_us = ofnode_read_u32_default(mdio_np, - "reset-post-delay-us", - 0); - ret = gpio_request_by_name_nodev(mdio_np, "reset-gpios", 0, - &cpsw_common->mdio_gpio_reset, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); - } ports_np = dev_read_subnode(dev, "ethernet-ports"); if (!ofnode_valid(ports_np)) { @@ -940,12 +776,11 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) dev_read_u32_default(dev, "bus_freq", AM65_CPSW_MDIO_BUS_FREQ_DEF); - dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u mdio_freq:%u\n", + dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u\n", readl(cpsw_common->ss_base), readl(cpsw_common->cpsw_base), readl(cpsw_common->ale_base), - cpsw_common->port_num, - cpsw_common->bus_freq); + cpsw_common->port_num); out: power_domain_free(&cpsw_common->pwrdmn); @@ -976,14 +811,3 @@ U_BOOT_DRIVER(am65_cpsw_nuss_port) = { .plat_auto = sizeof(struct eth_pdata), .flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE, }; - -static const struct udevice_id am65_cpsw_mdio_ids[] = { - { .compatible = "ti,cpsw-mdio" }, - { } -}; - -U_BOOT_DRIVER(am65_cpsw_mdio) = { - .name = "am65_cpsw_mdio", - .id = UCLASS_MDIO, - .of_match = am65_cpsw_mdio_ids, -}; diff --git a/drivers/net/ti/cpsw_mdio.c b/drivers/net/ti/cpsw_mdio.c index 74cc956785f..f1b1eba75d0 100644 --- a/drivers/net/ti/cpsw_mdio.c +++ b/drivers/net/ti/cpsw_mdio.c @@ -5,11 +5,15 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <clk.h> #include <common.h> +#include <dm/device_compat.h> #include <log.h> #include <malloc.h> +#include <phy.h> #include <asm/io.h> #include <miiphy.h> +#include <soc.h> #include <wait_bit.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -22,6 +26,7 @@ struct cpsw_mdio_regs { #define CONTROL_FAULT BIT(19) #define CONTROL_FAULT_ENABLE BIT(18) #define CONTROL_DIV_MASK GENMASK(15, 0) +#define CONTROL_MAX_DIV CONTROL_DIV_MASK #define MDIO_MAN_MDCLK_O BIT(2) #define MDIO_MAN_OE BIT(1) @@ -72,6 +77,8 @@ struct cpsw_mdio_regs { */ #define CPSW_MDIO_TIMEOUT 100 /* msecs */ +#define CPSW_MDIO_DEF_BUS_FREQ 2200000 /* 2.2 MHz */ + enum cpsw_mdio_manual { MDIO_PIN = 0, MDIO_OE, @@ -82,8 +89,35 @@ struct cpsw_mdio { struct cpsw_mdio_regs *regs; struct mii_dev *bus; int div; + bool manual_mode; + struct clk clk; + unsigned long bus_freq; }; +static int cpsw_mdio_enable(struct cpsw_mdio *data) +{ + int ret; + + /* set enable and clock divider */ + writel(data->div | CONTROL_ENABLE, &data->regs->control); + ret = wait_for_bit_le32(&data->regs->control, + CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true); + if (ret) + return ret; + + /* + * wait for scan logic to settle: + * the scan time consists of (a) a large fixed component, and (b) a + * small component that varies with the mii bus frequency. These + * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x + * silicon. Since the effect of (b) was found to be largely + * negligible, we keep things simple here. + */ + mdelay(1); + + return 0; +} + static void cpsw_mdio_disable(struct cpsw_mdio *mdio) { u32 reg; @@ -206,10 +240,16 @@ static void cpsw_mdio_sw_preamble(struct cpsw_mdio *mdio) } } +#if defined(CONFIG_DM_MDIO) +#define MII_TO_CPSW_MDIO(bus) (dev_get_priv((struct udevice *)(bus)->priv)) +#else +#define MII_TO_CPSW_MDIO(bus) ((bus)->priv) +#endif + static int cpsw_mdio_sw_read(struct mii_dev *bus, int phy_id, int dev_addr, int phy_reg) { - struct cpsw_mdio *mdio = bus->priv; + struct cpsw_mdio *mdio = MII_TO_CPSW_MDIO(bus); u32 reg, i; u8 ack; @@ -266,7 +306,7 @@ static int cpsw_mdio_sw_read(struct mii_dev *bus, int phy_id, static int cpsw_mdio_sw_write(struct mii_dev *bus, int phy_id, int dev_addr, int phy_reg, u16 phy_data) { - struct cpsw_mdio *mdio = bus->priv; + struct cpsw_mdio *mdio = MII_TO_CPSW_MDIO(bus); if ((phy_reg & ~PHY_REG_MASK) || (phy_id & ~PHY_ID_MASK)) return -EINVAL; @@ -316,7 +356,7 @@ static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio) static int cpsw_mdio_read(struct mii_dev *bus, int phy_id, int dev_addr, int phy_reg) { - struct cpsw_mdio *mdio = bus->priv; + struct cpsw_mdio *mdio = MII_TO_CPSW_MDIO(bus); int data, ret; u32 reg; @@ -342,7 +382,7 @@ static int cpsw_mdio_read(struct mii_dev *bus, int phy_id, static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr, int phy_reg, u16 data) { - struct cpsw_mdio *mdio = bus->priv; + struct cpsw_mdio *mdio = MII_TO_CPSW_MDIO(bus); u32 reg; int ret; @@ -361,9 +401,10 @@ static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr, return cpsw_mdio_wait_for_user_access(mdio); } +#if !defined(CONFIG_MDIO_TI_CPSW) u32 cpsw_mdio_get_alive(struct mii_dev *bus) { - struct cpsw_mdio *mdio = bus->priv; + struct cpsw_mdio *mdio = MII_TO_CPSW_MDIO(bus); u32 val; val = readl(&mdio->regs->alive); @@ -396,22 +437,11 @@ struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, else cpsw_mdio->div = (fck_freq / bus_freq) - 1; cpsw_mdio->div &= CONTROL_DIV_MASK; - - /* set enable and clock divider */ - writel(cpsw_mdio->div | CONTROL_ENABLE | CONTROL_FAULT | - CONTROL_FAULT_ENABLE, &cpsw_mdio->regs->control); - wait_for_bit_le32(&cpsw_mdio->regs->control, - CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true); - - /* - * wait for scan logic to settle: - * the scan time consists of (a) a large fixed component, and (b) a - * small component that varies with the mii bus frequency. These - * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x - * silicon. Since the effect of (b) was found to be largely - * negligible, we keep things simple here. - */ - mdelay(1); + ret = cpsw_mdio_enable(cpsw_mdio); + if (ret) { + debug("mdio_enable failed: %d\n", ret); + goto free_bus; + } if (manual_mode) { cpsw_mdio->bus->read = cpsw_mdio_sw_read; @@ -452,3 +482,129 @@ void cpsw_mdio_free(struct mii_dev *bus) mdio_free(bus); free(mdio); } + +#else + +static int cpsw_mdio_init_clk(struct cpsw_mdio *data) +{ + u32 mdio_in, div; + + mdio_in = clk_get_rate(&data->clk); + div = (mdio_in / data->bus_freq) - 1; + if (div > CONTROL_MAX_DIV) + div = CONTROL_MAX_DIV; + + data->div = div; + return cpsw_mdio_enable(data); +} + +static int cpsw_mdio_bus_read(struct udevice *dev, int addr, + int devad, int reg) +{ + struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : + NULL; + struct cpsw_mdio *priv = dev_get_priv(dev); + + if (pdata && pdata->mii_bus) { + if (priv->manual_mode) + return cpsw_mdio_sw_read(pdata->mii_bus, addr, devad, reg); + else + return cpsw_mdio_read(pdata->mii_bus, addr, devad, reg); + } + + return -1; +} + +static int cpsw_mdio_bus_write(struct udevice *dev, int addr, + int devad, int reg, u16 val) +{ + struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : + NULL; + struct cpsw_mdio *priv = dev_get_priv(dev); + + if (pdata && pdata->mii_bus) { + if (priv->manual_mode) + return cpsw_mdio_sw_write(pdata->mii_bus, addr, devad, reg, val); + else + return cpsw_mdio_write(pdata->mii_bus, addr, devad, reg, val); + } + + return -1; +} + +static const struct mdio_ops cpsw_mdio_ops = { + .read = cpsw_mdio_bus_read, + .write = cpsw_mdio_bus_write, +}; + +static const struct soc_attr k3_mdio_soc_data[] = { + { .family = "AM62X", .revision = "SR1.0" }, + { .family = "AM64X", .revision = "SR1.0" }, + { .family = "AM64X", .revision = "SR2.0" }, + { .family = "AM65X", .revision = "SR1.0" }, + { .family = "AM65X", .revision = "SR2.0" }, + { .family = "J7200", .revision = "SR1.0" }, + { .family = "J7200", .revision = "SR2.0" }, + { .family = "J721E", .revision = "SR1.0" }, + { .family = "J721E", .revision = "SR1.1" }, + { .family = "J721S2", .revision = "SR1.0" }, + { /* sentinel */ }, +}; + +static const struct udevice_id cpsw_mdio_ids[] = { + { .compatible = "ti,davinci_mdio", }, + { .compatible = "ti,cpsw-mdio", }, + { /* sentinel */ }, +}; + +static int cpsw_mdio_probe(struct udevice *dev) +{ + struct cpsw_mdio *priv = dev_get_priv(dev); + int ret; + + if (!priv) { + dev_err(dev, "dev_get_priv(dev %p) = NULL\n", dev); + return -ENOMEM; + } + + priv->regs = dev_remap_addr(dev); + + if (soc_device_match(k3_mdio_soc_data)) + priv->manual_mode = true; + + ret = clk_get_by_name(dev, "fck", &priv->clk); + if (ret) { + dev_err(dev, "failed to get clock %d\n", ret); + return ret; + } + + priv->bus_freq = dev_read_u32_default(dev, "bus_freq", + CPSW_MDIO_DEF_BUS_FREQ); + ret = cpsw_mdio_init_clk(priv); + if (ret) { + dev_err(dev, "init clock failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int cpsw_mdio_remove(struct udevice *dev) +{ + struct cpsw_mdio *priv = dev_get_priv(dev); + + cpsw_mdio_disable(priv); + + return 0; +} + +U_BOOT_DRIVER(cpsw_mdio) = { + .name = "cpsw_mdio", + .id = UCLASS_MDIO, + .of_match = cpsw_mdio_ids, + .probe = cpsw_mdio_probe, + .remove = cpsw_mdio_remove, + .ops = &cpsw_mdio_ops, + .priv_auto = sizeof(struct cpsw_mdio), +}; +#endif /* CONFIG_MDIO_TI_CPSW */ diff --git a/drivers/net/ti/cpsw_mdio.h b/drivers/net/ti/cpsw_mdio.h index ddf65a4686d..240c972d697 100644 --- a/drivers/net/ti/cpsw_mdio.h +++ b/drivers/net/ti/cpsw_mdio.h @@ -10,9 +10,11 @@ struct cpsw_mdio; +#if !defined(CONFIG_MDIO_TI_CPSW) struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, u32 bus_freq, int fck_freq, bool manual_mode); void cpsw_mdio_free(struct mii_dev *bus); u32 cpsw_mdio_get_alive(struct mii_dev *bus); +#endif /* CONFIG_MDIO_TI_CPSW */ #endif /* CPSW_MDIO_H_ */ |