]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
net: cpsw: Support new cpsw-switch DT bindings
authorMarkus Schneider-Pargmann (TI) <msp@baylibre.com>
Fri, 10 Apr 2026 11:04:06 +0000 (13:04 +0200)
committerJerome Forissier <jerome.forissier@arm.com>
Wed, 6 May 2026 09:07:22 +0000 (11:07 +0200)
Upstream devicetrees use a newer DT binding using cpsw-switch
compatibles. The bindings are a bit different, so two functions are
introduced to capture the differences, cpsw_eth_of_to_plat_switch() and
cpsw_eth_of_to_plat_legacy().

Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
drivers/net/ti/cpsw.c

index b1fb009822e9586886e5487e4fbeee115eec9a59..7a7cb83bd9847bc79ed21b2786ef6fe869e3fc0d 100644 (file)
@@ -33,6 +33,7 @@
 #define PKT_MAX                        (1500 + 14 + 4 + 4)
 #define CLEAR_BIT              1
 #define GIGABITEN              BIT(7)
+#define GMII_EN                        BIT(5)
 #define FULLDUPLEXEN           BIT(0)
 #define MIIEN                  BIT(15)
 #define CTL_EXT_EN             BIT(18)
@@ -1133,33 +1134,13 @@ static void cpsw_eth_of_parse_slave(struct cpsw_platform_data *data,
                                                        "max-speed", 0);
 }
 
-static int cpsw_eth_of_to_plat(struct udevice *dev)
+static int cpsw_eth_of_to_plat_legacy(struct udevice *dev,
+                                     struct cpsw_platform_data *data)
 {
-       struct eth_pdata *pdata = dev_get_plat(dev);
-       struct cpsw_platform_data *data;
-       struct gpio_desc *mode_gpios;
        int slave_index = 0;
-       int num_mode_gpios;
        ofnode subnode;
        int ret;
 
-       data = calloc(1, sizeof(struct cpsw_platform_data));
-       if (!data)
-               return -ENOMEM;
-
-       pdata->priv_pdata = data;
-       pdata->iobase = dev_read_addr(dev);
-       data->version = CPSW_CTRL_VERSION_2;
-       data->bd_ram_ofs = CPSW_BD_OFFSET;
-       data->ale_reg_ofs = CPSW_ALE_OFFSET;
-       data->cpdma_reg_ofs = CPSW_CPDMA_OFFSET;
-       data->mdio_div = CPSW_MDIO_DIV;
-       data->host_port_reg_ofs = CPSW_HOST_PORT_OFFSET,
-
-       pdata->phy_interface = -1;
-
-       data->cpsw_base = pdata->iobase;
-
        ret = dev_read_s32(dev, "cpdma_channels", &data->channels);
        if (ret) {
                printf("error: cpdma_channels not found in dt\n");
@@ -1192,17 +1173,6 @@ static int cpsw_eth_of_to_plat(struct udevice *dev)
                return ret;
        }
 
-       num_mode_gpios = gpio_get_list_count(dev, "mode-gpios");
-       if (num_mode_gpios > 0) {
-               mode_gpios = malloc(sizeof(struct gpio_desc) *
-                                   num_mode_gpios);
-               gpio_request_list_by_name(dev, "mode-gpios", mode_gpios,
-                                         num_mode_gpios, GPIOD_IS_OUT);
-               free(mode_gpios);
-       }
-
-       data->active_slave = dev_read_u32_default(dev, "active_slave", 0);
-
        ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
                const char *name;
 
@@ -1236,6 +1206,115 @@ static int cpsw_eth_of_to_plat(struct udevice *dev)
                }
        }
 
+       return 0;
+}
+
+static int cpsw_eth_of_to_plat_switch(struct udevice *dev,
+                                     struct cpsw_platform_data *data)
+{
+       ofnode eth_ports_node, subnode;
+       int ret;
+
+       data->channels = 8;
+       data->ale_entries = 1024;
+       data->mac_control = GMII_EN;
+
+       eth_ports_node = ofnode_find_subnode(dev_ofnode(dev), "ethernet-ports");
+       data->slaves = ofnode_get_child_count(eth_ports_node);
+       if (!data->slaves) {
+               pr_err("cpsw: No ethernet-ports defined\n");
+               return -EINVAL;
+       }
+
+       data->slave_data = malloc(sizeof(struct cpsw_slave_data) * data->slaves);
+       if (!data->slave_data)
+               return -ENOMEM;
+
+       ofnode_for_each_subnode(subnode, eth_ports_node) {
+               struct ofnode_phandle_args args;
+               u32 port_id;
+
+               ret = ofnode_read_u32(subnode, "reg", &port_id);
+               if (ret || !port_id || port_id > data->slaves) {
+                       pr_err("cpsw: invalid or missing reg in port node\n");
+                       return -EINVAL;
+               }
+
+               cpsw_eth_of_parse_slave(data, port_id - 1, subnode);
+
+               if (!data->gmii_sel) {
+                       ret = ofnode_parse_phandle_with_args(subnode, "phys", "#phy-cells",
+                                                            0, 0, &args);
+                       if (!ret)
+                               data->gmii_sel = ofnode_get_addr(args.node);
+               }
+       }
+
+       if (!data->gmii_sel) {
+               pr_err("No port specified phys correctly\n");
+               return -ENOENT;
+       }
+
+       ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
+               const char *name = ofnode_get_name(subnode);
+
+               if (strncmp(name, "mdio", 4))
+                       continue;
+
+               data->mdio_base = ofnode_get_addr(subnode);
+               if (data->mdio_base == FDT_ADDR_T_NONE) {
+                       pr_err("Not able to get MDIO address space\n");
+                       return -ENOENT;
+               }
+       }
+
+       return 0;
+}
+
+static int cpsw_eth_of_to_plat(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct cpsw_platform_data *data;
+       struct gpio_desc *mode_gpios;
+       int num_mode_gpios;
+       int ret;
+       bool switch_dt_bindings =
+               ofnode_valid(ofnode_find_subnode(dev_ofnode(dev), "ethernet-ports"));
+
+       data = calloc(1, sizeof(struct cpsw_platform_data));
+       if (!data)
+               return -ENOMEM;
+
+       pdata->priv_pdata = data;
+       pdata->iobase = dev_read_addr(dev);
+       data->version = CPSW_CTRL_VERSION_2;
+       data->bd_ram_ofs = CPSW_BD_OFFSET;
+       data->ale_reg_ofs = CPSW_ALE_OFFSET;
+       data->cpdma_reg_ofs = CPSW_CPDMA_OFFSET;
+       data->mdio_div = CPSW_MDIO_DIV;
+       data->host_port_reg_ofs = CPSW_HOST_PORT_OFFSET;
+
+       pdata->phy_interface = -1;
+
+       data->cpsw_base = pdata->iobase;
+
+       num_mode_gpios = gpio_get_list_count(dev, "mode-gpios");
+       if (num_mode_gpios > 0) {
+               mode_gpios = malloc(sizeof(struct gpio_desc) * num_mode_gpios);
+               gpio_request_list_by_name(dev, "mode-gpios", mode_gpios,
+                                         num_mode_gpios, GPIOD_IS_OUT);
+               free(mode_gpios);
+       }
+
+       data->active_slave = dev_read_u32_default(dev, "active_slave", 0);
+
+       if (switch_dt_bindings)
+               ret = cpsw_eth_of_to_plat_switch(dev, data);
+       else
+               ret = cpsw_eth_of_to_plat_legacy(dev, data);
+       if (ret)
+               return ret;
+
        data->slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET;
        data->slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET;
 
@@ -1270,6 +1349,9 @@ static const struct udevice_id cpsw_eth_ids[] = {
        { .compatible = "ti,am335x-cpsw",               .data = (ulong)&cpsw_data_am3352 },
        { .compatible = "ti,am4372-cpsw",               .data = (ulong)&cpsw_data_am3352 },
        { .compatible = "ti,dra7-cpsw",                 .data = (ulong)&cpsw_data_dra7xx },
+       { .compatible = "ti,am335x-cpsw-switch",        .data = (ulong)&cpsw_data_am3352 },
+       { .compatible = "ti,am4372-cpsw-switch",        .data = (ulong)&cpsw_data_am3352 },
+       { .compatible = "ti,dra7-cpsw-switch",          .data = (ulong)&cpsw_data_dra7xx },
        { }
 };
 #endif