]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/net/cpsw.c
net: cpsw: Add support to drive gpios for ethernet to be functional
[people/ms/u-boot.git] / drivers / net / cpsw.c
index 71047544634e6e73707832d08f54d03e5f24e84a..774b021e356e430251a26d1a068b45608869a7d1 100644 (file)
 #include <netdev.h>
 #include <cpsw.h>
 #include <asm/errno.h>
+#include <asm/gpio.h>
 #include <asm/io.h>
 #include <phy.h>
 #include <asm/arch/cpu.h>
 #include <dm.h>
+#include <fdt_support.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -965,6 +967,11 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave)
        phydev->supported &= supported;
        phydev->advertising = phydev->supported;
 
+#ifdef CONFIG_DM_ETH
+       if (slave->data->phy_of_handle)
+               phydev->dev->of_offset = slave->data->phy_of_handle;
+#endif
+
        priv->phydev = phydev;
        phy_config(phydev);
 
@@ -1137,18 +1144,24 @@ static const struct eth_ops cpsw_eth_ops = {
        .stop           = cpsw_eth_stop,
 };
 
+static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node)
+{
+       return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL);
+}
+
 static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
 {
        struct eth_pdata *pdata = dev_get_platdata(dev);
        struct cpsw_priv *priv = dev_get_priv(dev);
+       struct gpio_desc *mode_gpios;
        const char *phy_mode;
        const void *fdt = gd->fdt_blob;
        int node = dev->of_offset;
        int subnode;
        int slave_index = 0;
-       uint32_t mac_hi, mac_lo;
-       fdt32_t gmii = 0;
        int active_slave;
+       int num_mode_gpios;
+       int ret;
 
        pdata->iobase = dev_get_addr(dev);
        priv->data.version = CPSW_CTRL_VERSION_2;
@@ -1193,6 +1206,15 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
                return -ENOENT;
        }
 
+       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);
+       }
+
        active_slave = fdtdec_get_int(fdt, node, "active_slave", 0);
        priv->data.active_slave = active_slave;
 
@@ -1202,29 +1224,52 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
 
                name = fdt_get_name(fdt, subnode, &len);
                if (!strncmp(name, "mdio", 4)) {
-                       priv->data.mdio_base = fdtdec_get_addr(fdt, subnode,
-                                                              "reg");
+                       u32 mdio_base;
+
+                       mdio_base = cpsw_get_addr_by_node(fdt, subnode);
+                       if (mdio_base == FDT_ADDR_T_NONE) {
+                               error("Not able to get MDIO address space\n");
+                               return -ENOENT;
+                       }
+                       priv->data.mdio_base = mdio_base;
                }
 
                if (!strncmp(name, "slave", 5)) {
                        u32 phy_id[2];
 
-                       if (slave_index >= priv->data.slaves) {
-                               printf("error: num slaves and slave nodes did not match\n");
-                               return -EINVAL;
-                       }
+                       if (slave_index >= priv->data.slaves)
+                               continue;
                        phy_mode = fdt_getprop(fdt, subnode, "phy-mode", NULL);
                        if (phy_mode)
                                priv->data.slave_data[slave_index].phy_if =
                                        phy_get_interface_by_name(phy_mode);
-                       fdtdec_get_int_array(fdt, subnode, "phy_id", phy_id, 2);
-                       priv->data.slave_data[slave_index].phy_addr = phy_id[1];
+
+                       priv->data.slave_data[slave_index].phy_of_handle =
+                               fdtdec_lookup_phandle(fdt, subnode,
+                                                     "phy-handle");
+
+                       if (priv->data.slave_data[slave_index].phy_of_handle >= 0) {
+                               priv->data.slave_data[slave_index].phy_addr =
+                                               fdtdec_get_int(gd->fdt_blob,
+                                                              priv->data.slave_data[slave_index].phy_of_handle,
+                                                              "reg", -1);
+                       } else {
+                               fdtdec_get_int_array(fdt, subnode, "phy_id",
+                                                    phy_id, 2);
+                               priv->data.slave_data[slave_index].phy_addr =
+                                               phy_id[1];
+                       }
                        slave_index++;
                }
 
                if (!strncmp(name, "cpsw-phy-sel", 12)) {
-                       priv->data.gmii_sel = fdtdec_get_addr(fdt, subnode,
-                                                             "reg");
+                       priv->data.gmii_sel = cpsw_get_addr_by_node(fdt,
+                                                                   subnode);
+
+                       if (priv->data.gmii_sel == FDT_ADDR_T_NONE) {
+                               error("Not able to get gmii_sel reg address\n");
+                               return -ENOENT;
+                       }
                }
        }
 
@@ -1236,20 +1281,11 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
                priv->data.slave_data[1].sliver_reg_ofs = CPSW_SLIVER1_OFFSET;
        }
 
-       subnode = fdtdec_lookup_phandle(fdt, node, "syscon");
-       priv->data.mac_id = fdt_translate_address((void *)fdt, subnode, &gmii);
-       priv->data.mac_id += AM335X_GMII_SEL_OFFSET;
-       priv->data.mac_id += active_slave * 8;
-
-       /* try reading mac address from efuse */
-       mac_lo = readl(priv->data.mac_id);
-       mac_hi = readl(priv->data.mac_id + 4);
-       pdata->enetaddr[0] = mac_hi & 0xFF;
-       pdata->enetaddr[1] = (mac_hi & 0xFF00) >> 8;
-       pdata->enetaddr[2] = (mac_hi & 0xFF0000) >> 16;
-       pdata->enetaddr[3] = (mac_hi & 0xFF000000) >> 24;
-       pdata->enetaddr[4] = mac_lo & 0xFF;
-       pdata->enetaddr[5] = (mac_lo & 0xFF00) >> 8;
+       ret = ti_cm_get_macid(dev, active_slave, pdata->enetaddr);
+       if (ret < 0) {
+               error("cpsw read efuse mac failed\n");
+               return ret;
+       }
 
        pdata->phy_interface = priv->data.slave_data[active_slave].phy_if;
        if (pdata->phy_interface == -1) {
@@ -1270,6 +1306,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
                writel(RGMII_MODE_ENABLE, priv->data.gmii_sel);
                break;
        }
+
        return 0;
 }