[PATCH master] net: cpsw: add support for new binding in Linux v5.15-rc1 DTs

Ahmad Fatoum a.fatoum at pengutronix.de
Fri Dec 3 12:50:35 PST 2021


As is customary, upstream OMAP DTs have yet again added a new binding
breaking compatibility with a barebox driver. This time, the old Ethernet
node was disabled in favor of a new node that is matched by the new Linux
cpsw driver introduced with Linux commit ed3525eda4c4 ("net: ethernet:
ti: introduce cpsw switchdev based driver part 1 - dual-emac").

Add support for the new binding to restore working Beaglebone Black
networking. These changes have been tested against both the old and new
bindings.

Fixes: 618948e4e5b3 ("dts: update to v5.15-rc1")
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/net/cpsw.c | 120 +++++++++++++++++++++++++++++++++------------
 1 file changed, 89 insertions(+), 31 deletions(-)

diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index 4a8f9e67d6f0..6725c7b9bdb4 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -592,7 +592,12 @@ static int cpsw_mdio_probe(struct device_d *dev)
 
 	priv = xzalloc(sizeof(*priv));
 
+	/* If we can't request I/O memory region, we'll assume parent did
+	 * it for us
+	 */
 	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY)
+		iores = dev_get_resource(dev, IORESOURCE_MEM, 0);
 	if (IS_ERR(iores))
 		return PTR_ERR(iores);
 	priv->mdio_regs = IOMEM(iores->start);
@@ -1214,11 +1219,27 @@ static void cpsw_gmii_sel_am335x(struct cpsw_slave *slave)
 	writel(reg, phy_sel_addr);
 }
 
-static int cpsw_probe_dt(struct cpsw_priv *priv)
+static void cpsw_add_slave(struct cpsw_slave *slave, struct device_node *child, int i)
+{
+	uint32_t phy_id[2] = {-1, -1};
+	int ret;
+
+	if (!of_find_node_by_name(child, "fixed-link")) {
+		ret = of_property_read_u32_array(child, "phy_id", phy_id, 2);
+		if (!ret)
+			dev_warn(slave->cpsw->dev, "phy_id is deprecated, use phy-handle\n");
+	}
+
+	slave->dev.device_node = child;
+	slave->phy_id = phy_id[1];
+	slave->phy_if = of_get_phy_mode(child);
+	slave->slave_num = i;
+}
+
+static int cpsw_legacy_probe_dt(struct cpsw_priv *priv)
 {
 	struct device_d *dev = priv->dev;
 	struct device_node *np = dev->device_node, *child;
-	struct device_node *physel;
 	int ret, i = 0;
 
 	ret = of_property_read_u32(np, "slaves", &priv->num_slaves);
@@ -1227,15 +1248,6 @@ static int cpsw_probe_dt(struct cpsw_priv *priv)
 
 	priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
 
-	physel = of_find_compatible_node(NULL, NULL, "ti,am3352-phy-gmii-sel");
-	if (!physel) {
-		dev_err(dev, "Cannot find ti,am3352-phy-gmii-sel node\n");
-		return -EINVAL;
-	}
-	ret = cpsw_phy_sel_init(priv, physel);
-	if (ret)
-		return ret;
-
 	for_each_child_of_node(np, child) {
 		if (of_device_is_compatible(child, "ti,davinci_mdio")) {
 			ret = of_pinctrl_select_state_default(child);
@@ -1244,29 +1256,73 @@ static int cpsw_probe_dt(struct cpsw_priv *priv)
 		}
 
 		if (i < priv->num_slaves && !strncmp(child->name, "slave", 5)) {
-			struct cpsw_slave *slave = &priv->slaves[i];
-			uint32_t phy_id[2] = {-1, -1};
+			cpsw_add_slave(&priv->slaves[i], child, i);
+			i++;
+		}
+	}
 
-			if (!of_find_node_by_name(child, "fixed-link")) {
-				ret = of_property_read_u32_array(child, "phy_id", phy_id, 2);
-				if (!ret)
-					dev_warn(dev, "phy_id is deprecated, use phy-handle\n");
-			}
+	return 0;
+}
+
+static int cpsw_switch_probe_dt(struct cpsw_priv *priv)
+{
+	struct device_d *dev = priv->dev;
+	struct device_node *np = dev->device_node, *child;
+	struct device_node *ports = NULL;
+	int ret, i = 0;
 
-			slave->dev.device_node = child;
-			slave->phy_id = phy_id[1];
-			slave->phy_if = of_get_phy_mode(child);
-			slave->slave_num = i;
+	for_each_child_of_node(np, child) {
+		if (of_device_is_compatible(child, "ti,davinci_mdio")) {
+			ret = of_pinctrl_select_state_default(child);
+			if (ret)
+				return ret;
+		}
 
-			i++;
+		if (!strcmp(child->name, "ethernet-ports")) {
+			ports = child;
+			priv->num_slaves = of_get_available_child_count(ports);
 		}
 	}
 
-	for (i = 0; i < priv->num_slaves; i++) {
-		struct cpsw_slave *slave = &priv->slaves[i];
+	if (!ports)
+		return -EINVAL;
+
+	priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
+
+	for_each_available_child_of_node(ports, child) {
+		cpsw_add_slave(&priv->slaves[i], child, i);
+		i++;
+	}
+
+	return 0;
+}
 
-		cpsw_gmii_sel_am335x(slave);
+static int cpsw_probe_dt(struct cpsw_priv *priv)
+{
+	struct device_d *dev = priv->dev;
+	struct device_node *physel;
+	int (*probe_slaves_dt)(struct cpsw_priv *priv);
+	int ret, i = 0;
+
+	physel = of_find_compatible_node(NULL, NULL, "ti,am3352-phy-gmii-sel");
+	if (!physel) {
+		dev_err(dev, "Cannot find ti,am3352-phy-gmii-sel node\n");
+		return -EINVAL;
 	}
+	ret = cpsw_phy_sel_init(priv, physel);
+	if (ret)
+		return ret;
+
+	probe_slaves_dt = device_get_match_data(dev);
+	if (!probe_slaves_dt)
+		return -EINVAL;
+
+	ret = probe_slaves_dt(priv);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < priv->num_slaves; i++)
+		cpsw_gmii_sel_am335x(&priv->slaves[i]);
 
 	return 0;
 }
@@ -1282,15 +1338,15 @@ static int cpsw_probe(struct device_d *dev)
 
 	dev_dbg(dev, "* %s\n", __func__);
 
-	ret = of_platform_populate(dev->device_node, NULL, dev);
-	if (ret)
-		return ret;
-
 	iores = dev_request_mem_resource(dev, 0);
 	if (IS_ERR(iores))
 		return PTR_ERR(iores);
 	regs = IOMEM(iores->start);
 
+	ret = of_platform_populate(dev->device_node, NULL, dev);
+	if (ret)
+		return ret;
+
 	priv = xzalloc(sizeof(*priv));
 	priv->dev = dev;
 
@@ -1371,7 +1427,9 @@ static void cpsw_remove(struct device_d *dev)
 
 static __maybe_unused struct of_device_id cpsw_dt_ids[] = {
 	{
-		.compatible = "ti,cpsw",
+		.compatible = "ti,cpsw", .data = cpsw_legacy_probe_dt
+	}, {
+		.compatible = "ti,cpsw-switch", .data = cpsw_switch_probe_dt
 	}, {
 		/* sentinel */
 	}
-- 
2.30.2




More information about the barebox mailing list