From b743bbd2ebec440f42b44392b7dc4f79a9f588cf Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 May 2019 17:59:56 +0200 Subject: [PATCH 1/7] net: eth-uclass: Write MAC address to hardware after probe In order for the device to use the proper MAC address, which can have been configured in the environment prior to the device being registered, ensure that the MAC address is written after the device has been probed. For devices that are registered before the network stack is initialized, this is already done during eth_initialize(). If the Ethernet device is on a bus that is not initialized on early boot, such as PCI, the device is not available at the time eth_initialize() is called, so we need the MAC address programming to also happen after probe. Acked-by: Joe Hershberger Signed-off-by: Thierry Reding --- net/eth-uclass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 2ef20df192..4225aabf1f 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -524,6 +524,8 @@ static int eth_post_probe(struct udevice *dev) #endif } + eth_write_hwaddr(dev); + return 0; } From 379af67ab3ba1a16e032c8d082fe85efa4bf21fe Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 May 2019 17:59:57 +0200 Subject: [PATCH 2/7] net: eth-uclass: Support device tree MAC addresses Add the standard Ethernet device tree bindings (imported from v5.0 of the Linux kernel) and implement support for reading the MAC address for Ethernet devices in the Ethernet uclass. If the "mac-address" property exists, the MAC address will be parsed from that. If that property does not exist, the "local-mac-address" property will be tried as fallback. MAC addresses from device tree take precedence over the ones stored in a network interface card's ROM. Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko Signed-off-by: Thierry Reding --- .../devicetree/bindings/net/ethernet.txt | 66 +++++++++++++++++++ net/eth-uclass.c | 30 ++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/ethernet.txt diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt new file mode 100644 index 0000000000..cfc376bc97 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ethernet.txt @@ -0,0 +1,66 @@ +The following properties are common to the Ethernet controllers: + +NOTE: All 'phy*' properties documented below are Ethernet specific. For the +generic PHY 'phys' property, see +Documentation/devicetree/bindings/phy/phy-bindings.txt. + +- local-mac-address: array of 6 bytes, specifies the MAC address that was + assigned to the network device; +- mac-address: array of 6 bytes, specifies the MAC address that was last used by + the boot program; should be used in cases where the MAC address assigned to + the device by the boot program is different from the "local-mac-address" + property; +- nvmem-cells: phandle, reference to an nvmem node for the MAC address; +- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used; +- max-speed: number, specifies maximum speed in Mbit/s supported by the device; +- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than + the maximum frame size (there's contradiction in the Devicetree + Specification). +- phy-mode: string, operation mode of the PHY interface. This is now a de-facto + standard property; supported values are: + * "internal" + * "mii" + * "gmii" + * "sgmii" + * "qsgmii" + * "tbi" + * "rev-mii" + * "rmii" + * "rgmii" (RX and TX delays are added by the MAC when required) + * "rgmii-id" (RGMII with internal RX and TX delays provided by the PHY, the + MAC should not add the RX or TX delays in this case) + * "rgmii-rxid" (RGMII with internal RX delay provided by the PHY, the MAC + should not add an RX delay in this case) + * "rgmii-txid" (RGMII with internal TX delay provided by the PHY, the MAC + should not add an TX delay in this case) + * "rtbi" + * "smii" + * "xgmii" + * "trgmii" + * "2000base-x", + * "2500base-x", + * "rxaui" + * "xaui" + * "10gbase-kr" (10GBASE-KR, XFI, SFI) +- phy-connection-type: the same as "phy-mode" property but described in the + Devicetree Specification; +- phy-handle: phandle, specifies a reference to a node representing a PHY + device; this property is described in the Devicetree Specification and so + preferred; +- phy: the same as "phy-handle" property, not recommended for new bindings. +- phy-device: the same as "phy-handle" property, not recommended for new + bindings. +- rx-fifo-depth: the size of the controller's receive fifo in bytes. This + is used for components that can have configurable receive fifo sizes, + and is useful for determining certain configuration settings such as + flow control thresholds. +- tx-fifo-depth: the size of the controller's transmit fifo in bytes. This + is used for components that can have configurable fifo sizes. +- managed: string, specifies the PHY management type. Supported values are: + "auto", "in-band-status". "auto" is the default, it usess MDIO for + management if fixed-link is not specified. + +Child nodes of the Ethernet controller are typically the individual PHY devices +connected via the MDIO bus (sometimes the MDIO bus controller is separate). +They are described in the phy.txt file in this same directory. +For non-MDIO PHY management see fixed-link.txt. diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 4225aabf1f..031d558625 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -455,6 +455,26 @@ static int eth_pre_unbind(struct udevice *dev) return 0; } +static bool eth_dev_get_mac_address(struct udevice *dev, u8 mac[ARP_HLEN]) +{ +#if IS_ENABLED(CONFIG_OF_CONTROL) + const uint8_t *p; + + p = dev_read_u8_array_ptr(dev, "mac-address", ARP_HLEN); + if (!p) + p = dev_read_u8_array_ptr(dev, "local-mac-address", ARP_HLEN); + + if (!p) + return false; + + memcpy(mac, p, ARP_HLEN); + + return true; +#else + return false; +#endif +} + static int eth_post_probe(struct udevice *dev) { struct eth_device_priv *priv = dev->uclass_priv; @@ -489,9 +509,13 @@ static int eth_post_probe(struct udevice *dev) priv->state = ETH_STATE_INIT; - /* Check if the device has a MAC address in ROM */ - if (eth_get_ops(dev)->read_rom_hwaddr) - eth_get_ops(dev)->read_rom_hwaddr(dev); + /* Check if the device has a valid MAC address in device tree */ + if (!eth_dev_get_mac_address(dev, pdata->enetaddr) || + !is_valid_ethaddr(pdata->enetaddr)) { + /* Check if the device has a MAC address in ROM */ + if (eth_get_ops(dev)->read_rom_hwaddr) + eth_get_ops(dev)->read_rom_hwaddr(dev); + } eth_env_get_enetaddr_by_index("eth", dev->seq, env_enetaddr); if (!is_zero_ethaddr(env_enetaddr)) { From 49191d259f433f8341a71ab6f821c1d89e2f5092 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 22 May 2019 00:09:44 -0700 Subject: [PATCH 3/7] clk: sifive: Add clock driver for GEMGXL MGMT This adds a clock driver to support the GEMGXL management IP block found in FU540 SoCs to control GEM TX clock operation mode for 10/100/1000 Mbps. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Tested-by: Lukas Auer --- drivers/clk/sifive/Kconfig | 7 ++++ drivers/clk/sifive/Makefile | 2 ++ drivers/clk/sifive/gemgxl-mgmt.c | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 drivers/clk/sifive/gemgxl-mgmt.c diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig index 81fc9f8fda..644881b948 100644 --- a/drivers/clk/sifive/Kconfig +++ b/drivers/clk/sifive/Kconfig @@ -17,3 +17,10 @@ config CLK_SIFIVE_FU540_PRCI Supports the Power Reset Clock interface (PRCI) IP block found in FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC, enable this driver. + +config CLK_SIFIVE_GEMGXL_MGMT + bool "GEMGXL management for SiFive FU540 SoCs" + depends on CLK_SIFIVE + help + Supports the GEMGXL management IP block found in FU540 SoCs to + control GEM TX clock operation mode for 10/100/1000 Mbps. diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile index 1155e07e37..f8263e79b7 100644 --- a/drivers/clk/sifive/Makefile +++ b/drivers/clk/sifive/Makefile @@ -3,3 +3,5 @@ obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o + +obj-$(CONFIG_CLK_SIFIVE_GEMGXL_MGMT) += gemgxl-mgmt.o diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c new file mode 100644 index 0000000000..eb37416b5e --- /dev/null +++ b/drivers/clk/sifive/gemgxl-mgmt.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019, Bin Meng + */ + +#include +#include +#include +#include + +struct gemgxl_mgmt_regs { + __u32 tx_clk_sel; +}; + +struct gemgxl_mgmt_platdata { + struct gemgxl_mgmt_regs *regs; +}; + +static int gemgxl_mgmt_ofdata_to_platdata(struct udevice *dev) +{ + struct gemgxl_mgmt_platdata *plat = dev_get_platdata(dev); + + plat->regs = (struct gemgxl_mgmt_regs *)dev_read_addr(dev); + + return 0; +} + +static ulong gemgxl_mgmt_set_rate(struct clk *clk, ulong rate) +{ + struct gemgxl_mgmt_platdata *plat = dev_get_platdata(clk->dev); + + /* + * GEMGXL TX clock operation mode: + * + * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic + * and output clock on GMII output signal GTX_CLK + * 1 = MII mode. Use MII input signal TX_CLK in TX logic + */ + writel(rate != 125000000, &plat->regs->tx_clk_sel); + + return 0; +} + +const struct clk_ops gemgxl_mgmt_ops = { + .set_rate = gemgxl_mgmt_set_rate, +}; + +static const struct udevice_id gemgxl_mgmt_match[] = { + { .compatible = "sifive,cadencegemgxlmgmt0", }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sifive_gemgxl_mgmt) = { + .name = "sifive-gemgxl-mgmt", + .id = UCLASS_CLK, + .of_match = gemgxl_mgmt_match, + .ofdata_to_platdata = gemgxl_mgmt_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct gemgxl_mgmt_platdata), + .ops = &gemgxl_mgmt_ops, +}; From a5e3d2350b271d6281c01ae7ad0dd7290ba66aee Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 22 May 2019 00:09:45 -0700 Subject: [PATCH 4/7] dm: net: macb: Update macb_linkspd_cb() signature This updates DM version macb_linkspd_cb() signature for future expansion, eg: adding an implementation for link speed changes. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Acked-by: Joe Hershberger --- drivers/net/macb.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 72614164e9..b7f404e857 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -488,15 +488,23 @@ static int macb_phy_find(struct macb_device *macb, const char *name) /** * macb_linkspd_cb - Linkspeed change callback function - * @regs: Base Register of MACB devices + * @dev/@regs: MACB udevice (DM version) or + * Base Register of MACB devices (non-DM version) * @speed: Linkspeed * Returns 0 when operation success and negative errno number * when operation failed. */ +#ifdef CONFIG_DM_ETH +int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed) +{ + return 0; +} +#else int __weak macb_linkspd_cb(void *regs, unsigned int speed) { return 0; } +#endif #ifdef CONFIG_DM_ETH static int macb_phy_init(struct udevice *dev, const char *name) @@ -589,7 +597,11 @@ static int macb_phy_init(struct macb_device *macb, const char *name) macb_writel(macb, NCFGR, ncfgr); +#ifdef CONFIG_DM_ETH + ret = macb_linkspd_cb(dev, _1000BASET); +#else ret = macb_linkspd_cb(macb->regs, _1000BASET); +#endif if (ret) return ret; @@ -614,9 +626,17 @@ static int macb_phy_init(struct macb_device *macb, const char *name) ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); if (speed) { ncfgr |= MACB_BIT(SPD); +#ifdef CONFIG_DM_ETH + ret = macb_linkspd_cb(dev, _100BASET); +#else ret = macb_linkspd_cb(macb->regs, _100BASET); +#endif } else { +#ifdef CONFIG_DM_ETH + ret = macb_linkspd_cb(dev, _10BASET); +#else ret = macb_linkspd_cb(macb->regs, _10BASET); +#endif } if (ret) From 3ef64444de157a2e4f6a61b3ea617b9d201a6836 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 22 May 2019 00:09:46 -0700 Subject: [PATCH 5/7] dm: net: macb: Implement link speed change callback At present the link speed change callback is a nop. According to macb device tree bindings, an optional "tx_clk" is used to clock the ethernet controller's TX_CLK under different link speed. In 10/100 MII mode, transmit logic must be clocked from a free running clock generated by the external PHY. In gigabit GMII mode, the controller, not the external PHY, must generate the 125 MHz transmit clock towards the PHY. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Tested-by: Lukas Auer Acked-by: Joe Hershberger --- drivers/net/macb.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index b7f404e857..c5560a7111 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -497,6 +497,41 @@ static int macb_phy_find(struct macb_device *macb, const char *name) #ifdef CONFIG_DM_ETH int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed) { +#ifdef CONFIG_CLK + struct clk tx_clk; + ulong rate; + int ret; + + /* + * "tx_clk" is an optional clock source for MACB. + * Ignore if it does not exist in DT. + */ + ret = clk_get_by_name(dev, "tx_clk", &tx_clk); + if (ret) + return 0; + + switch (speed) { + case _10BASET: + rate = 2500000; /* 2.5 MHz */ + break; + case _100BASET: + rate = 25000000; /* 25 MHz */ + break; + case _1000BASET: + rate = 125000000; /* 125 MHz */ + break; + default: + /* does not change anything */ + return 0; + } + + if (tx_clk.dev) { + ret = clk_set_rate(&tx_clk, rate); + if (ret) + return ret; + } +#endif + return 0; } #else From 776d39d9a10d92e3dc753e6b052bc6a53523f3c7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 22 May 2019 00:09:47 -0700 Subject: [PATCH 6/7] riscv: sifive: fu540: Enable GEMGXL MGMT driver Enable the new GEMGXL MGMT driver so that GEM 10/100 Mbps works now. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Tested-by: Lukas Auer --- board/sifive/fu540/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig index f46437901d..8eb5e304ab 100644 --- a/board/sifive/fu540/Kconfig +++ b/board/sifive/fu540/Kconfig @@ -28,6 +28,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply CMD_PING imply CLK_SIFIVE imply CLK_SIFIVE_FU540_PRCI + imply CLK_SIFIVE_GEMGXL_MGMT imply DOS_PARTITION imply EFI_PARTITION imply IP_DYN From b4c20f20adad8d246b95be5bebacb730462c8c01 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 30 May 2019 03:08:32 +0300 Subject: [PATCH 7/7] cmd: mdio: Fix access to arbitrary PHY addresses Alex reported the following: " I'm doing some MDIO work on a freescale/NXP platform and I bumped into errors with this command: => mdio r emdio#3 5 3 Reading from bus emdio#3 "Synchronous Abort" handler, esr 0x8600000e elr: ffffffff862b8000 lr : 000000008200cce4 (reloc) ... mdio list does not list any PHYs currently because ethernet is using DM and the interfaces are not probed at this time. The PHY does exist on the bus though. The above scenario works with this commit reverted: e55047ec51a662c12ed53ff543ec7cdf158b2137 cmd: mdio: Switch to generic helpers when accessing the registers The current code using generic helpers only works for PHYs that have been registered and show up in bus->phymap and crashes for arbitrary IDs. I find it useful to allow reading from other addresses over MDIO too, certainly helpful for people debugging MDIO on various boards. " Fix this by reverting to use the raw MDIO bus operations in case there is no PHY probed based on DT at the specified address. This restores the old behavior for these PHYs, which means that the newly introduced MMD-over-C22 helpers won't be available for them, but at least they will be accessible again without crashing the system. Fixes: commit e55047ec51a6 ("cmd: mdio: Switch to generic helpers when accessing the registers") Reported-by: Alex Marginean Signed-off-by: Vladimir Oltean Reviewed-by: Alex Marginean Acked-by: Joe Hershberger --- cmd/mdio.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/mdio.c b/cmd/mdio.c index efe8c9ef09..5e219f699d 100644 --- a/cmd/mdio.c +++ b/cmd/mdio.c @@ -54,7 +54,10 @@ static int mdio_write_ranges(struct mii_dev *bus, for (devad = devadlo; devad <= devadhi; devad++) { for (reg = reglo; reg <= reghi; reg++) { - if (!extended) + if (!phydev) + err = bus->write(bus, addr, devad, + reg, data); + else if (!extended) err = phy_write_mmd(phydev, devad, reg, data); else @@ -88,7 +91,9 @@ static int mdio_read_ranges(struct mii_dev *bus, for (reg = reglo; reg <= reghi; reg++) { int val; - if (!extended) + if (!phydev) + val = bus->read(bus, addr, devad, reg); + else if (!extended) val = phy_read_mmd(phydev, devad, reg); else val = phydev->drv->readext(phydev, addr,