diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/e1000.c | 15 | ||||
-rw-r--r-- | drivers/net/e1000.h | 2 | ||||
-rw-r--r-- | drivers/net/fec_mxc.c | 2 | ||||
-rw-r--r-- | drivers/net/gmac_rockchip.c | 1 | ||||
-rw-r--r-- | drivers/net/hifemac.c | 229 | ||||
-rw-r--r-- | drivers/net/hifemac_mdio.c | 11 | ||||
-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/phy/broadcom.c | 17 | ||||
-rw-r--r-- | drivers/net/phy/ethernet_id.c | 37 | ||||
-rw-r--r-- | drivers/net/phy/ncsi.c | 17 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 62 | ||||
-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 |
18 files changed, 672 insertions, 374 deletions
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 84a2a7cf904..4e7ba666770 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -116,6 +116,8 @@ static struct pci_device_id e1000_supported[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I210_SERDES) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I210_SERDES_FLASHLESS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I210_1000BASEKX) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I225_UNPROGRAMMED) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I225_IT) }, {} }; @@ -1575,6 +1577,8 @@ e1000_set_mac_type(struct e1000_hw *hw) case PCI_DEVICE_ID_INTEL_I210_SERDES: case PCI_DEVICE_ID_INTEL_I210_SERDES_FLASHLESS: case PCI_DEVICE_ID_INTEL_I210_1000BASEKX: + case PCI_DEVICE_ID_INTEL_I225_UNPROGRAMMED: + case PCI_DEVICE_ID_INTEL_I225_IT: hw->mac_type = e1000_igb; break; default: @@ -3258,7 +3262,8 @@ e1000_setup_copper_link(struct e1000_hw *hw) if (ret_val) return ret_val; } else if (hw->phy_type == e1000_phy_m88 || - hw->phy_type == e1000_phy_igb) { + hw->phy_type == e1000_phy_igb || + hw->phy_type == e1000_phy_igc) { ret_val = e1000_copper_link_mgp_setup(hw); if (ret_val) return ret_val; @@ -4531,6 +4536,8 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) case e1000_igb: while (timeout) { if (hw->mac_type == e1000_igb) { + if (hw->phy_type == e1000_phy_igc) + break; if (E1000_READ_REG(hw, I210_EEMNGCTL) & cfg_mask) break; } else { @@ -4769,6 +4776,7 @@ e1000_phy_reset(struct e1000_hw *hw) case e1000_phy_igp_3: case e1000_phy_ife: case e1000_phy_igb: + case e1000_phy_igc: ret_val = e1000_phy_hw_reset(hw); if (ret_val) return ret_val; @@ -4834,6 +4842,9 @@ static int e1000_set_phy_type (struct e1000_hw *hw) case I210_I_PHY_ID: hw->phy_type = e1000_phy_igb; break; + case I225_I_PHY_ID: + hw->phy_type = e1000_phy_igc; + break; /* Fall Through */ default: /* Should never have loaded on this device */ @@ -4941,6 +4952,8 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_igb: if (hw->phy_id == I210_I_PHY_ID) match = true; + if (hw->phy_id == I225_I_PHY_ID) + match = true; break; default: DEBUGOUT("Invalid MAC type %d\n", hw->mac_type); diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index f788394da87..e1311126a3f 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -212,6 +212,7 @@ typedef enum { e1000_phy_igp_3, e1000_phy_ife, e1000_phy_igb, + e1000_phy_igc, e1000_phy_bm, e1000_phy_undefined = 0xFF } e1000_phy_type; @@ -2420,6 +2421,7 @@ struct e1000_hw { #define BME1000_E_PHY_ID 0x01410CB0 #define I210_I_PHY_ID 0x01410C00 +#define I225_I_PHY_ID 0x67C9DCC0 /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index ac937676f9c..90af18f80a8 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -1310,7 +1310,7 @@ static int fecmxc_probe(struct udevice *dev) #ifdef CONFIG_DM_REGULATOR if (priv->phy_supply) { - ret = regulator_set_enable(priv->phy_supply, true); + ret = regulator_set_enable_if_allowed(priv->phy_supply, true); if (ret) { printf("%s: Error enabling phy supply\n", dev->name); return ret; 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/hifemac.c b/drivers/net/hifemac.c index b61a29e6360..90cc247b3b6 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -15,6 +15,9 @@ #include <wait_bit.h> #include <asm/io.h> #include <dm/device_compat.h> +#include <dm/lists.h> +#include <linux/bitfield.h> +#include <linux/ethtool.h> #include <linux/delay.h> #include <linux/kernel.h> @@ -124,6 +127,57 @@ struct hisi_femac_priv { u32 link_status; }; +struct hisi_femac_stat_entry { + const char *name; + u32 offset; + u32 mask; +}; + +/* please refer to the datasheet for the description of these entries */ +static const struct hisi_femac_stat_entry hisi_femac_stats_table[] = { + { "rxsof_cnt", 0x584, GENMASK(31, 28) }, + { "rxeof_cnt", 0x584, GENMASK(27, 24) }, + { "rxcrcok_cnt", 0x584, GENMASK(23, 20) }, + { "rxcrcbad_cnt", 0x584, GENMASK(19, 16) }, + { "txsof_cnt", 0x584, GENMASK(15, 12) }, + { "txeof_cnt", 0x584, GENMASK(11, 8) }, + { "txcrcok_cnt", 0x584, GENMASK(7, 4) }, + { "txcrcbad_cnt", 0x584, GENMASK(3, 0) }, + { "pkts_cpu", 0x5a0, GENMASK(15, 0) }, + { "addr_cpu", 0x5a4, GENMASK(15, 0) }, + { "pkts_port", 0x5a8, GENMASK(15, 0) }, + { "pkts_cpu2tx", 0x5ac, GENMASK(15, 0) }, + { "rxdvrise", 0x600, GENMASK(31, 0) }, + { "ifinoctets", 0x604, GENMASK(31, 0) }, + { "octets_rx", 0x608, GENMASK(31, 0) }, + { "local_mac_match", 0x60c, GENMASK(31, 0) }, + { "pkts", 0x610, GENMASK(31, 0) }, + { "broadcastpkts", 0x614, GENMASK(31, 0) }, + { "multicastpkts", 0x618, GENMASK(31, 0) }, + { "ifinucastpkts", 0x61c, GENMASK(31, 0) }, + { "ifinerrors", 0x620, GENMASK(31, 0) }, + { "crcerr", 0x624, GENMASK(31, 0) }, + { "abnormalsizepkts", 0x628, GENMASK(31, 0) }, + { "dot3alignmenterr", 0x62c, GENMASK(31, 0) }, + { "dot3pause", 0x630, GENMASK(31, 0) }, + { "dropevents", 0x634, GENMASK(31, 0) }, + { "flux_frame_cnt", 0x638, GENMASK(31, 0) }, + { "flux_drop_cnt", 0x63c, GENMASK(31, 0) }, + { "mac_not2cpu_pkts", 0x64c, GENMASK(31, 0) }, + { "pkts_tx", 0x780, GENMASK(31, 0) }, + { "broadcastpkts_tx", 0x784, GENMASK(31, 0) }, + { "multicastpkts_tx", 0x788, GENMASK(31, 0) }, + { "ifoutucastpkts_tx", 0x78c, GENMASK(31, 0) }, + { "octets_tx", 0x790, GENMASK(31, 0) }, + { "dot3pause", 0x794, GENMASK(31, 0) }, + { "retry_times_tx", 0x798, GENMASK(31, 0) }, + { "collisions", 0x79c, GENMASK(31, 0) }, + { "dot3latecol", 0x7a0, GENMASK(31, 0) }, + { "dot3colok", 0x7a4, GENMASK(31, 0) }, + { "dot3excessivecol", 0x7a8, GENMASK(31, 0) }, + { "dot3colcnt", 0x7ac, GENMASK(31, 0) }, +}; + static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs) { u32 val; @@ -245,8 +299,10 @@ static int hisi_femac_start(struct udevice *dev) hisi_femac_rx_refill(priv); ret = phy_startup(priv->phy); - if (ret) - return log_msg_ret("Failed to startup phy", ret); + if (ret) { + dev_err(dev, "Failed to startup phy: %d\n", ret); + return log_msg_ret("phy", ret); + } if (!priv->phy->link) { debug("%s: link down\n", __func__); @@ -281,8 +337,10 @@ static int hisi_femac_send(struct udevice *dev, void *packet, int length) // wait until FIFO is empty ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false); - if (ret == -ETIMEDOUT) - return log_msg_ret("FIFO timeout", ret); + if (ret == -ETIMEDOUT) { + dev_err(dev, "FIFO timeout\n"); + return log_msg_ret("net", ret); + } return 0; } @@ -329,10 +387,43 @@ static void hisi_femac_stop(struct udevice *dev) writel(SOFT_RESET_ALL, priv->glb_base + GLB_SOFT_RESET); } -int hisi_femac_of_to_plat(struct udevice *dev) +static int hisi_femac_get_sset_count(struct udevice *dev) +{ + return ARRAY_SIZE(hisi_femac_stats_table); +} + +static void hisi_femac_get_strings(struct udevice *dev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hisi_femac_stats_table); i++) + strcpy(data + i * ETH_GSTRING_LEN, hisi_femac_stats_table[i].name); +} + +/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) + +static void hisi_femac_get_stats(struct udevice *dev, u64 *data) +{ + int i; + u32 mask, reg; + struct hisi_femac_priv *priv = dev_get_priv(dev); + void __iomem *port_base = priv->port_base; + + for (i = 0; i < ARRAY_SIZE(hisi_femac_stats_table); i++) { + mask = hisi_femac_stats_table[i].mask; + reg = readl(port_base + hisi_femac_stats_table[i].offset); + + data[i] = field_get(mask, reg); + } +} + +static int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; struct hisi_femac_priv *priv = dev_get_priv(dev); + ofnode mdio_node; + bool mdio_registered = false; static const char * const clk_strs[] = { [CLK_MAC] = "mac", [CLK_BUS] = "bus", @@ -340,40 +431,75 @@ int hisi_femac_of_to_plat(struct udevice *dev) }; priv->port_base = dev_remap_addr_name(dev, "port"); - if (IS_ERR(priv->port_base)) - return log_msg_ret("Failed to remap port address space", PTR_ERR(priv->port_base)); + if (!priv->port_base) { + dev_err(dev, "Failed to remap port address space\n"); + return log_msg_ret("net", -EINVAL); + } priv->glb_base = dev_remap_addr_name(dev, "glb"); - if (IS_ERR(priv->glb_base)) - return log_msg_ret("Failed to remap global address space", PTR_ERR(priv->glb_base)); + if (IS_ERR(priv->glb_base)) { + dev_err(dev, "Failed to remap global address space\n"); + return log_msg_ret("net", -EINVAL); + } for (i = 0; i < ARRAY_SIZE(clk_strs); i++) { priv->clks[i] = devm_clk_get(dev, clk_strs[i]); if (IS_ERR(priv->clks[i])) { dev_err(dev, "Error getting clock %s\n", clk_strs[i]); - return log_msg_ret("Failed to get clocks", PTR_ERR(priv->clks[i])); + return log_msg_ret("clk", PTR_ERR(priv->clks[i])); } } priv->mac_rst = devm_reset_control_get(dev, "mac"); - if (IS_ERR(priv->mac_rst)) - return log_msg_ret("Failed to get MAC reset", PTR_ERR(priv->mac_rst)); + if (IS_ERR(priv->mac_rst)) { + dev_err(dev, "Failed to get MAC reset %ld\n", PTR_ERR(priv->mac_rst)); + return log_msg_ret("rst", PTR_ERR(priv->mac_rst)); + } priv->phy_rst = devm_reset_control_get(dev, "phy"); - if (IS_ERR(priv->phy_rst)) - return log_msg_ret("Failed to get PHY reset", PTR_ERR(priv->phy_rst)); + if (IS_ERR(priv->phy_rst)) { + dev_err(dev, "Failed to get PHY reset %ld\n", PTR_ERR(priv->phy_rst)); + return log_msg_ret("rst", PTR_ERR(priv->phy_rst)); + } ret = dev_read_u32_array(dev, PHY_RESET_DELAYS_PROPERTY, priv->phy_reset_delays, DELAYS_NUM); - if (ret < 0) - return log_msg_ret("Failed to get PHY reset delays", ret); + if (ret < 0) { + dev_err(dev, "Failed to get PHY reset delays %d\n", ret); + return log_msg_ret("rst", ret); + } priv->mac_reset_delay = dev_read_u32_default(dev, MAC_RESET_DELAY_PROPERTY, MAC_RESET_ASSERT_PERIOD); + /* Create MDIO bus */ + ofnode_for_each_subnode(mdio_node, dev_ofnode(dev)) { + const char *subnode_name = ofnode_get_name(mdio_node); + struct udevice *mdiodev; + + // Skip subnodes not starting with "mdio" + if (strncmp(subnode_name, "mdio", 4)) + continue; + + ret = device_bind_driver_to_node(dev, "hisi-femac-mdio", + subnode_name, mdio_node, &mdiodev); + if (ret) { + dev_err(dev, "Failed to register MDIO bus device %d\n", ret); + return log_msg_ret("net", ret); + } + + mdio_registered = true; + break; + } + + if (!mdio_registered) { + dev_err(dev, "No MDIO subnode is found!\n"); + return log_msg_ret("mdio", -ENODATA); + } + return 0; } @@ -385,37 +511,49 @@ static int hisi_femac_phy_reset(struct hisi_femac_priv *priv) // Disable MAC clk before phy reset ret = clk_disable(priv->clks[CLK_MAC]); - if (ret < 0) - return log_msg_ret("Failed to disable MAC clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable MAC clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } ret = clk_disable(priv->clks[CLK_BUS]); - if (ret < 0) - return log_msg_ret("Failed to disable bus clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable bus clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } udelay(delays[PRE_DELAY]); ret = reset_assert(rst); - if (ret < 0) - return log_msg_ret("Failed to assert reset", ret); + if (ret < 0) { + pr_err("%s: Failed to assert reset %d\n", __func__, ret); + return log_msg_ret("rst", ret); + } udelay(delays[PULSE]); ret = reset_deassert(rst); - if (ret < 0) - return log_msg_ret("Failed to deassert reset", ret); + if (ret < 0) { + pr_err("%s: Failed to deassert reset %d\n", __func__, ret); + return log_msg_ret("rst", ret); + } udelay(delays[POST_DELAY]); ret = clk_enable(priv->clks[CLK_MAC]); - if (ret < 0) - return log_msg_ret("Failed to enable MAC clock", ret); + if (ret < 0) { + pr_err("%s: Failed to enable MAC clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } ret = clk_enable(priv->clks[CLK_BUS]); - if (ret < 0) - return log_msg_ret("Failed to enable MAC bus clock", ret); + if (ret < 0) { + pr_err("%s: Failed to enable MAC bus clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } return 0; } -int hisi_femac_probe(struct udevice *dev) +static int hisi_femac_probe(struct udevice *dev) { struct hisi_femac_priv *priv = dev_get_priv(dev); int ret, i; @@ -423,30 +561,40 @@ int hisi_femac_probe(struct udevice *dev) // Enable clocks for (i = 0; i < CLK_NUM; i++) { ret = clk_prepare_enable(priv->clks[i]); - if (ret < 0) - return log_msg_ret("Failed to enable clks", ret); + if (ret < 0) { + dev_err(dev, "Failed to enable clk %d: %d\n", i, ret); + return log_msg_ret("clk", ret); + } } // Reset MAC ret = reset_assert(priv->mac_rst); - if (ret < 0) - return log_msg_ret("Failed to assert MAC reset", ret); + if (ret < 0) { + dev_err(dev, "Failed to assert MAC reset: %d\n", ret); + return log_msg_ret("net", ret); + } udelay(priv->mac_reset_delay); ret = reset_deassert(priv->mac_rst); - if (ret < 0) - return log_msg_ret("Failed to deassert MAC reset", ret); + if (ret < 0) { + dev_err(dev, "Failed to deassert MAC reset: %d\n", ret); + return log_msg_ret("net", ret); + } // Reset PHY ret = hisi_femac_phy_reset(priv); - if (ret < 0) - return log_msg_ret("Failed to reset phy", ret); + if (ret < 0) { + dev_err(dev, "Failed to reset PHY: %d\n", ret); + return log_msg_ret("net", ret); + } // Connect to PHY priv->phy = dm_eth_phy_connect(dev); - if (!priv->phy) - return log_msg_ret("Failed to connect to phy", -EINVAL); + if (!priv->phy) { + dev_err(dev, "Failed to connect to phy\n"); + return log_msg_ret("phy", -EINVAL); + } hisi_femac_port_init(priv); return 0; @@ -459,6 +607,9 @@ static const struct eth_ops hisi_femac_ops = { .free_pkt = hisi_femac_free_pkt, .stop = hisi_femac_stop, .write_hwaddr = hisi_femac_set_hw_mac_addr, + .get_sset_count = hisi_femac_get_sset_count, + .get_strings = hisi_femac_get_strings, + .get_stats = hisi_femac_get_stats, }; static const struct udevice_id hisi_femac_ids[] = { diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c index 343c5f3a38a..0b59d060917 100644 --- a/drivers/net/hifemac_mdio.c +++ b/drivers/net/hifemac_mdio.c @@ -8,6 +8,7 @@ #include <dm.h> #include <clk.h> #include <miiphy.h> +#include <dm/device_compat.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -74,7 +75,8 @@ static int hisi_femac_mdio_of_to_plat(struct udevice *dev) data->membase = dev_remap_addr(dev); if (IS_ERR(data->membase)) { ret = PTR_ERR(data->membase); - return log_msg_ret("Failed to remap base addr", ret); + dev_err(dev, "Failed to remap base addr %d\n", ret); + return log_msg_ret("mdio", ret); } // clk is optional @@ -89,8 +91,10 @@ static int hisi_femac_mdio_probe(struct udevice *dev) int ret; ret = clk_prepare_enable(data->clk); - if (ret) - return log_msg_ret("Failed to enable clk", ret); + if (ret) { + dev_err(dev, "Failed to enable clock: %d\n", ret); + return log_msg_ret("clk", ret); + } return 0; } @@ -112,5 +116,6 @@ U_BOOT_DRIVER(hisi_femac_mdio_driver) = { .of_to_plat = hisi_femac_mdio_of_to_plat, .probe = hisi_femac_mdio_probe, .ops = &hisi_femac_mdio_ops, + .plat_auto = sizeof(struct mdio_perdev_priv), .priv_auto = sizeof(struct hisi_femac_mdio_data), }; 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/phy/broadcom.c b/drivers/net/phy/broadcom.c index 82e3bbef7dd..ecccb7c3b54 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -42,6 +42,12 @@ #define BCM54810_SHD_CLK_CTL 0x3 #define BCM54810_SHD_CLK_CTL_GTXCLK_EN BIT(9) +#define BCM54XX_SHD_LEDS1 0x0d +#define BCM_LED_SRC_LINKSPD2 0x1 +#define BCM_LED_SRC_ACTIVITYLED 0x3 +#define BCM54XX_SHD_LEDS1_LED3(src) (((src) & 0xf) << 4) +#define BCM54XX_SHD_LEDS1_LED1(src) (((src) & 0xf) << 0) + static int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum) { /* The register must be written to both the Shadow Register Select and @@ -148,7 +154,16 @@ static int bcm54210e_config(struct phy_device *phydev) if (ret < 0) return ret; - return bcm5461_config(phydev); + ret = bcm5461_config(phydev); + if (ret < 0) + return ret; + + /* Configure LEDs to blink. */ + bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDS1, + BCM54XX_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | + BCM54XX_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); + + return 0; } static int bcm54xx_parse_status(struct phy_device *phydev) diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c index 6cb1fd4453e..4dfdee60dcc 100644 --- a/drivers/net/phy/ethernet_id.c +++ b/drivers/net/phy/ethernet_id.c @@ -18,12 +18,11 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, { struct phy_device *phydev; struct ofnode_phandle_args phandle_args; - struct gpio_desc gpio; const char *node_name; struct udevice *pdev; - ofnode node; - u32 id, assert, deassert; u16 vendor, device; + ofnode node; + u32 id; int ret; if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, @@ -41,35 +40,9 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, return NULL; } - if (!IS_ENABLED(CONFIG_DM_ETH_PHY)) { - ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio, - GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); - if (!ret) { - assert = ofnode_read_u32_default(node, - "reset-assert-us", 0); - deassert = ofnode_read_u32_default(node, - "reset-deassert-us", - 0); - ret = dm_gpio_set_value(&gpio, 1); - if (ret) { - dev_err(dev, - "Failed assert gpio, err: %d\n", ret); - return NULL; - } - - udelay(assert); - - ret = dm_gpio_set_value(&gpio, 0); - if (ret) { - dev_err(dev, - "Failed deassert gpio, err: %d\n", - ret); - return NULL; - } - - udelay(deassert); - } - } + ret = phy_gpio_reset(dev); + if (ret) + return NULL; if (phyaddr == -1) phyaddr = ofnode_read_u32_default(phandle_args.node, "reg", -1); diff --git a/drivers/net/phy/ncsi.c b/drivers/net/phy/ncsi.c index eb3fd65bb47..2bca116a9d8 100644 --- a/drivers/net/phy/ncsi.c +++ b/drivers/net/phy/ncsi.c @@ -286,11 +286,11 @@ static void ncsi_rsp_gc(struct ncsi_rsp_pkt *pkt) } c = &ncsi_priv->packages[np].channels[nc]; - c->cap_generic = ntohl(gc->cap) & NCSI_CAP_GENERIC_MASK; - c->cap_bc = ntohl(gc->bc_cap) & NCSI_CAP_BC_MASK; - c->cap_mc = ntohl(gc->mc_cap) & NCSI_CAP_MC_MASK; - c->cap_aen = ntohl(gc->aen_cap) & NCSI_CAP_AEN_MASK; - c->cap_vlan = ntohl(gc->vlan_mode) & NCSI_CAP_VLAN_MASK; + c->cap_generic = get_unaligned_be32(&gc->cap) & NCSI_CAP_GENERIC_MASK; + c->cap_bc = get_unaligned_be32(&gc->bc_cap) & NCSI_CAP_BC_MASK; + c->cap_mc = get_unaligned_be32(&gc->mc_cap) & NCSI_CAP_MC_MASK; + c->cap_aen = get_unaligned_be32(&gc->aen_cap) & NCSI_CAP_AEN_MASK; + c->cap_vlan = gc->vlan_mode & NCSI_CAP_VLAN_MASK; /* End of probe for this channel */ } @@ -551,7 +551,7 @@ static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd, checksum = ncsi_calculate_checksum((unsigned char *)hdr, sizeof(*hdr) + len); pchecksum = (__be32 *)((void *)(hdr + 1) + len); - put_unaligned_be32(htonl(checksum), pchecksum); + put_unaligned_be32(checksum, pchecksum); if (wait) { net_set_timeout_handler(1000UL, ncsi_timeout_handler); @@ -619,9 +619,12 @@ static void ncsi_handle_aen(struct ip_udp_hdr *ip, unsigned int len) /* Link or configuration lost - just redo the discovery process */ ncsi_priv->state = NCSI_PROBE_PACKAGE_SP; - for (i = 0; i < ncsi_priv->n_packages; i++) + for (i = 0; i < ncsi_priv->n_packages; i++) { free(ncsi_priv->packages[i].channels); + ncsi_priv->packages[i].channels = NULL; + } free(ncsi_priv->packages); + ncsi_priv->packages = NULL; ncsi_priv->n_packages = 0; ncsi_priv->current_package = NCSI_PACKAGE_MAX; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 63b3e46f101..270176cfe62 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -18,6 +18,8 @@ #include <phy.h> #include <errno.h> #include <asm/global_data.h> +#include <asm-generic/gpio.h> +#include <dm/device_compat.h> #include <dm/of_extra.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -566,7 +568,8 @@ struct phy_device *phy_device_create(struct mii_dev *bus, int addr, return NULL; } - if (addr >= 0 && addr < PHY_MAX_ADDR && phy_id != PHY_FIXED_ID) + if (addr >= 0 && addr < PHY_MAX_ADDR && phy_id != PHY_FIXED_ID && + phy_id != PHY_NCSI_ID) bus->phymap[addr] = dev; return dev; @@ -642,12 +645,12 @@ static struct phy_device *search_for_existing_phy(struct mii_dev *bus, { /* If we have one, return the existing device, with new interface */ while (phy_mask) { - int addr = ffs(phy_mask) - 1; + unsigned int addr = ffs(phy_mask) - 1; if (bus->phymap[addr]) return bus->phymap[addr]; - phy_mask &= ~(1 << addr); + phy_mask &= ~(1U << addr); } return NULL; } @@ -768,6 +771,59 @@ int miiphy_reset(const char *devname, unsigned char addr) return phy_reset(phydev); } +#if CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(OF_REAL) && \ + !IS_ENABLED(CONFIG_DM_ETH_PHY) +int phy_gpio_reset(struct udevice *dev) +{ + struct ofnode_phandle_args phandle_args; + struct gpio_desc gpio; + u32 assert, deassert; + ofnode node; + int ret; + + ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args); + /* No PHY handle is OK */ + if (ret) + return 0; + + node = phandle_args.node; + if (!ofnode_valid(node)) + return -EINVAL; + + ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); + /* No PHY reset GPIO is OK */ + if (ret) + return 0; + + assert = ofnode_read_u32_default(node, "reset-assert-us", 20000); + deassert = ofnode_read_u32_default(node, "reset-deassert-us", 1000); + ret = dm_gpio_set_value(&gpio, 1); + if (ret) { + dev_err(dev, "Failed assert gpio, err: %d\n", ret); + return ret; + } + + udelay(assert); + + ret = dm_gpio_set_value(&gpio, 0); + if (ret) { + dev_err(dev, "Failed deassert gpio, err: %d\n", ret); + return ret; + } + + udelay(deassert); + + return 0; +} +#else +int phy_gpio_reset(struct udevice *dev) +{ + return 0; +} +#endif + struct phy_device *phy_find_by_mask(struct mii_dev *bus, uint phy_mask) { /* Reset the bus */ 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_ */ |