From: Markus Schneider-Pargmann (TI) Date: Fri, 10 Apr 2026 11:04:06 +0000 (+0200) Subject: net: cpsw: Support new cpsw-switch DT bindings X-Git-Tag: v2026.07-rc2~15^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5bb7ae8921eea48e3fa1a810dc5668123ceacb38;p=thirdparty%2Fu-boot.git net: cpsw: Support new cpsw-switch DT bindings 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) --- diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c index b1fb009822e..7a7cb83bd98 100644 --- a/drivers/net/ti/cpsw.c +++ b/drivers/net/ti/cpsw.c @@ -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