[U-Boot] [PATCH v3 0/5] Add helper function for linking a DM Eth device to a PHY

The patch set introduces dm_eth_phy_connect which takes in an ethernet device and uses DT information to find the associated PHY and connect the Ethernet interface to it. This should simplify similar code in ethernet drivers. A new binding is introduced for scanning an MDIO bus, useful if the bus is private to the Ethernet interface. Finally the patch set updates fsl_enetc driver to use the new helper function.
This patch set supersedes v2 series: https://patchwork.ozlabs.org/project/uboot/list/?series=124537
Patch 6 of this series removes code modified in the following patch, a similar change is now part of MDIO helper functions: https://patchwork.ozlabs.org/patch/1184523/
Changes in v3: - added cover letter - check for null PHY pointer before using it in dm_eth_connect_phy_handle - moved the code dealing with MDIO scanning into a separate patch - renames several arguments and variables for a bit more clarity and consistency
Changes in v2: - Moved MDIO scan code into dm_mdio_phy_scan which is also exported - Use interface instead of if_type for consistency - don't use phy pointer if NULL in fsl_enetc code
Alex Marginean (5): net: mdio-uclass: rename arguments of dm_mdio_phy_connect for consistency net: mdio-uclass: add dm_eth_phy_connect helper function net: mdio-uclass: Add helper functions for scanning the MDIO bus doc: bindings: add mdio-handle property to ethernet nodes drivers: net: fsl_enetc: use the new MDIO DM helper functions
doc/device-tree-bindings/net/ethernet.txt | 2 + drivers/net/fsl_enetc.c | 52 ++------ drivers/net/fsl_enetc.h | 1 + include/miiphy.h | 32 ++++- net/mdio-uclass.c | 139 +++++++++++++++++++++- 5 files changed, 175 insertions(+), 51 deletions(-)

Renamed dm_mdio_phy_connect arguments dev to mdiodev and addr to phyaddr for a bit more clarity and consistency with the following patches. Also use NULL instead of 0 on error return path.
Signed-off-by: Alex Marginean alexandru.marginean@nxp.com --- include/miiphy.h | 6 +++--- net/mdio-uclass.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/miiphy.h b/include/miiphy.h index 9b97d09f18..94bf0da24a 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -154,14 +154,14 @@ void dm_mdio_probe_devices(void); /** * dm_mdio_phy_connect - Wrapper over phy_connect for DM MDIO * - * @dev: mdio dev - * @addr: PHY address on MDIO bus + * @mdiodev: mdio device the PHY is accesible on + * @phyaddr: PHY address on MDIO bus * @ethdev: ethernet device to connect to the PHY * @interface: MAC-PHY protocol * * @return pointer to phy_device, or 0 on error */ -struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, +struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface);
diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index 6f922e80b6..7a5f1d6dcc 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -104,16 +104,16 @@ static int dm_mdio_pre_remove(struct udevice *dev) return 0; }
-struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, +struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface) { - struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); + struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdiodev);
- if (device_probe(dev)) - return 0; + if (device_probe(mdiodev)) + return NULL;
- return phy_connect(pdata->mii_bus, addr, ethdev, interface); + return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); }
UCLASS_DRIVER(mdio) = {

The function connects an ethernet device to a PHY using DT information. This API is only available for eth devices with an associated device tree node.
Signed-off-by: Alex Marginean alexandru.marginean@nxp.com --- include/miiphy.h | 12 ++++++++ net/mdio-uclass.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+)
diff --git a/include/miiphy.h b/include/miiphy.h index 94bf0da24a..e591d93416 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -165,6 +165,18 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface);
+/** + * dm_eth_phy_connect - Connect an Eth device to a PHY based on device tree + * + * Picks up the DT phy-handle/mdio-handle and phy-mode from ethernet device node + * and connects the ethernet device to the linked PHY. + * + * @ethdev: ethernet device + * + * @return pointer to phy_device, or 0 on error + */ +struct phy_device *dm_eth_phy_connect(struct udevice *ethdev); + #endif
#ifdef CONFIG_DM_MDIO_MUX diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index 7a5f1d6dcc..cf736a3ae5 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -116,6 +116,78 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); }
+static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, + phy_interface_t interface) +{ + u32 phy_phandle, phy_addr; + struct udevice *mdiodev; + struct phy_device *phy; + ofnode phy_node; + + if (ofnode_read_u32(ethdev->node, "phy-handle", &phy_phandle)) { + dev_dbg(dev, "phy-handle missing in ethernet node\n"); + return NULL; + } + + phy_node = ofnode_get_by_phandle(phy_phandle); + if (!ofnode_valid(phy_node)) { + dev_dbg(dev, "invalid phy node\n"); + return NULL; + } + + if (ofnode_read_u32(phy_node, "reg", &phy_addr)) { + dev_dbg(ethdev, "missing reg property in phy node\n"); + return NULL; + } + + if (uclass_get_device_by_ofnode(UCLASS_MDIO, + ofnode_get_parent(phy_node), + &mdiodev)) { + dev_dbg(dev, "can't find MDIO bus for node %s\n", + ofnode_get_name(ofnode_get_parent(phy_node))); + return NULL; + } + + phy = dm_mdio_phy_connect(mdiodev, phy_addr, ethdev, interface); + + if (phy) + phy->node = phy_node; + + return phy; +} + +/* Connect to a PHY linked in eth DT node */ +struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) +{ + const char *if_str; + phy_interface_t interface; + struct phy_device *phy; + + if (!ofnode_valid(ethdev->node)) { + debug("%s: supplied eth dev has no DT node!\n", ethdev->name); + return NULL; + } + + interface = PHY_INTERFACE_MODE_NONE; + if_str = ofnode_read_string(ethdev->node, "phy-mode"); + if (if_str) + interface = phy_get_interface_by_name(if_str); + if (interface < 0) + interface = PHY_INTERFACE_MODE_NONE; + + if (interface == PHY_INTERFACE_MODE_NONE) + dev_dbg(ethdev, "can't find interface mode, default to NONE\n"); + + phy = dm_eth_connect_phy_handle(ethdev, interface); + + if (!phy) + return NULL; + + phy->interface = interface; + + return phy; +} + UCLASS_DRIVER(mdio) = { .id = UCLASS_MDIO, .name = "mdio",

The patch introduces dm_mdio_phy_scan which is a DM wrapper over phy_find_by_mask. It also updates dm_eth_phy_connect to scan a MDIO bus for PHYs if the ethernet node contains a mdio-handle property.
Signed-off-by: Alex Marginean alexandru.marginean@nxp.com --- include/miiphy.h | 14 ++++++++++++ net/mdio-uclass.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+)
diff --git a/include/miiphy.h b/include/miiphy.h index e591d93416..a5bdc29a47 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -165,6 +165,20 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface);
+/** + * dm_mdio_phy_scan - Scan for a PHY on the given MDIO bus + * + * @mdiodev: mdio device to scan + * @ethdev: ethernet device to connect to the PHY + * @interface: MAC-PHY protocol + * @addrmask: bitmask of PHY addresses to scan, use all Fs to scan all addresses + * + * @return pointer to phy_device, or 0 on error + */ +struct phy_device *dm_mdio_phy_scan(struct udevice *mdiodev, + struct udevice *ethdev, + phy_interface_t interface, uint addrmask); + /** * dm_eth_phy_connect - Connect an Eth device to a PHY based on device tree * diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index cf736a3ae5..9ca462edb2 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -116,6 +116,24 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); }
+struct phy_device *dm_mdio_phy_scan(struct udevice *mdiodev, + struct udevice *ethdev, + phy_interface_t interface, uint addrmask) +{ + struct mdio_perdev_priv *pdata; + struct phy_device *phy; + + pdata = dev_get_uclass_priv(mdiodev); + + phy = phy_find_by_mask(pdata->mii_bus, addrmask, interface); + if (phy) + phy_connect_dev(phy, ethdev); + else + dev_dbg(mdiodev, "no PHY detected on bus\n"); + + return phy; +} + static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, phy_interface_t interface) { @@ -156,6 +174,34 @@ static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, return phy; }
+static struct phy_device *dm_eth_connect_mdio_handle(struct udevice *ethdev, + phy_interface_t interface) +{ + u32 mdio_phandle; + ofnode mdio_node; + struct udevice *mdiodev; + uint mask = 0xffffffff; + + if (ofnode_read_u32(ethdev->node, "mdio-handle", &mdio_phandle)) { + dev_dbg(ethdev, "mdio-handle missing in ethernet node\n"); + return NULL; + } + + mdio_node = ofnode_get_by_phandle(mdio_phandle); + if (!ofnode_valid(mdio_node)) { + dev_dbg(dev, "invalid mdio node\n"); + return NULL; + } + + if (uclass_get_device_by_ofnode(UCLASS_MDIO, mdio_node, &mdiodev)) { + dev_dbg(ethdev, "can't find MDIO bus for node %s\n", + ofnode_get_name(mdio_node)); + return NULL; + } + + return dm_mdio_phy_scan(mdiodev, ethdev, interface, mask); +} + /* Connect to a PHY linked in eth DT node */ struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) { @@ -178,8 +224,19 @@ struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) if (interface == PHY_INTERFACE_MODE_NONE) dev_dbg(ethdev, "can't find interface mode, default to NONE\n");
+ /* + * The sequence is: + * - if there is a phy-handle property, follow that, + * - if there is a mdio-handle property, follow that and scan for the + * PHY, + * - if the above came out empty, return NULL. + */ + phy = dm_eth_connect_phy_handle(ethdev, interface);
+ if (!phy) + phy = dm_eth_connect_mdio_handle(ethdev, interface); + if (!phy) return NULL;

Adds an optional mdio-handle property which identifies a MDIO bus which can be scanned to find the relevant PHY. The property is ignored if phy-handle is also present.
Signed-off-by: Alex Marginean alexandru.marginean@nxp.com --- doc/device-tree-bindings/net/ethernet.txt | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/doc/device-tree-bindings/net/ethernet.txt b/doc/device-tree-bindings/net/ethernet.txt index 3fc360523b..9f9629f8d6 100644 --- a/doc/device-tree-bindings/net/ethernet.txt +++ b/doc/device-tree-bindings/net/ethernet.txt @@ -9,6 +9,8 @@ The following properties are common to the Ethernet controllers: - 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 ePAPR). +- mdio-handle: phandle, specifies a reference to a MDIO bus to be scanned to + find the PHY device. Ignored if phy-handle is also present. - phy-mode: string, operation mode of the PHY interface; supported values are "mii", "gmii", "sgmii", "qsgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii", "xgmii"; this is now a de-facto

Uses the new dm_eth_phy_connect helper to connect to the PHY to simplify the code.
Signed-off-by: Alex Marginean alexandru.marginean@nxp.com --- drivers/net/fsl_enetc.c | 52 +++++++---------------------------------- drivers/net/fsl_enetc.h | 1 + 2 files changed, 10 insertions(+), 43 deletions(-)
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index e7c5062c39..928d071815 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -200,56 +200,20 @@ static void enetc_start_pcs(struct udevice *dev) }
/* Configure the actual/external ethernet PHY, if one is found */ -static void enetc_start_phy(struct udevice *dev) +static void enetc_config_phy(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); - struct udevice *miidev; - struct phy_device *phy; - u32 phandle, phy_id; - ofnode phy_node; int supported;
- if (!ofnode_valid(dev->node)) { - enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n"); - return; - } - - if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) { - enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n"); - return; - } - - phy_node = ofnode_get_by_phandle(phandle); - if (!ofnode_valid(phy_node)) { - enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n"); - return; - } - enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node)); + priv->phy = dm_eth_phy_connect(dev);
- if (ofnode_read_u32(phy_node, "reg", &phy_id)) { - enetc_dbg(dev, - "missing reg in PHY node, skipping PHY set-up\n"); + if (!priv->phy) return; - } - - if (uclass_get_device_by_ofnode(UCLASS_MDIO, - ofnode_get_parent(phy_node), - &miidev)) { - enetc_dbg(dev, "can't find MDIO bus for node %s\n", - ofnode_get_name(ofnode_get_parent(phy_node))); - return; - } - - phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type); - if (!phy) { - enetc_dbg(dev, "dm_mdio_phy_connect returned null\n"); - return; - }
supported = GENMASK(6, 0); /* speeds up to 1G & AN */ - phy->advertising = phy->supported & supported; - phy_config(phy); - phy_startup(phy); + priv->phy->advertising = priv->phy->supported & supported; + + phy_config(priv->phy); }
/* @@ -464,7 +428,9 @@ static int enetc_start(struct udevice *dev) enetc_setup_rx_bdr(dev);
enetc_start_pcs(dev); - enetc_start_phy(dev); + enetc_config_phy(dev); + if (priv->phy) + phy_startup(priv->phy);
return 0; } diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 0bb4cdff47..9a36cdad80 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -154,6 +154,7 @@ struct enetc_priv {
int if_type; struct mii_dev imdio; + struct phy_device *phy; };
/* register accessors */
participants (1)
-
Alex Marginean