net: designware: support phy reset device-tree bindings
authorSjoerd Simons <sjoerd.simons@collabora.co.uk>
Sun, 28 Feb 2016 21:24:55 +0000 (22:24 +0100)
committerSimon Glass <sjg@chromium.org>
Fri, 27 May 2016 15:00:48 +0000 (09:00 -0600)
Add support for the snps,reset-gpio, snps,reset-active-low (optional) and
snps,reset-delays-us device-tree bindings. The combination of these
three define how the PHY should be reset to ensure it's in a sane state.

Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/net/designware.c
drivers/net/designware.h

index ca58f34f13bf9af6e62fd9b1760a8ccfdac688b7..14dd7b83494091855b2e204b0e5e7335e7def1f1 100644 (file)
@@ -24,7 +24,12 @@ DECLARE_GLOBAL_DATA_PTR;
 
 static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 {
+#ifdef CONFIG_DM_ETH
+       struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
+       struct eth_mac_regs *mac_p = priv->mac_regs_p;
+#else
        struct eth_mac_regs *mac_p = bus->priv;
+#endif
        ulong start;
        u16 miiaddr;
        int timeout = CONFIG_MDIO_TIMEOUT;
@@ -47,7 +52,12 @@ static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
                        u16 val)
 {
+#ifdef CONFIG_DM_ETH
+       struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
+       struct eth_mac_regs *mac_p = priv->mac_regs_p;
+#else
        struct eth_mac_regs *mac_p = bus->priv;
+#endif
        ulong start;
        u16 miiaddr;
        int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT;
@@ -70,7 +80,41 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
        return ret;
 }
 
-static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
+#if CONFIG_DM_ETH
+static int dw_mdio_reset(struct mii_dev *bus)
+{
+       struct udevice *dev = bus->priv;
+       struct dw_eth_dev *priv = dev_get_priv(dev);
+       struct dw_eth_pdata *pdata = dev_get_platdata(dev);
+       int ret;
+
+       if (!dm_gpio_is_valid(&priv->reset_gpio))
+               return 0;
+
+       /* reset the phy */
+       ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+       if (ret)
+               return ret;
+
+       udelay(pdata->reset_delays[0]);
+
+       ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+       if (ret)
+               return ret;
+
+       udelay(pdata->reset_delays[1]);
+
+       ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+       if (ret)
+               return ret;
+
+       udelay(pdata->reset_delays[2]);
+
+       return 0;
+}
+#endif
+
+static int dw_mdio_init(const char *name, void *priv)
 {
        struct mii_dev *bus = mdio_alloc();
 
@@ -82,8 +126,11 @@ static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
        bus->read = dw_mdio_read;
        bus->write = dw_mdio_write;
        snprintf(bus->name, sizeof(bus->name), "%s", name);
+#ifdef CONFIG_DM_ETH
+       bus->reset = dw_mdio_reset;
+#endif
 
-       bus->priv = (void *)mac_regs_p;
+       bus->priv = priv;
 
        return mdio_register(bus);
 }
@@ -606,7 +653,7 @@ static int designware_eth_probe(struct udevice *dev)
        priv->interface = pdata->phy_interface;
        priv->max_speed = pdata->max_speed;
 
-       dw_mdio_init(dev->name, priv->mac_regs_p);
+       dw_mdio_init(dev->name, dev);
        priv->bus = miiphy_get_dev_by_name(dev->name);
 
        ret = dw_phy_init(priv, dev);
@@ -637,9 +684,13 @@ static const struct eth_ops designware_eth_ops = {
 
 static int designware_eth_ofdata_to_platdata(struct udevice *dev)
 {
-       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
+       struct dw_eth_dev *priv = dev_get_priv(dev);
+       struct eth_pdata *pdata = &dw_pdata->eth_pdata;
        const char *phy_mode;
        const fdt32_t *cell;
+       int reset_flags = GPIOD_IS_OUT;
+       int ret = 0;
 
        pdata->iobase = dev_get_addr(dev);
        pdata->phy_interface = -1;
@@ -656,7 +707,20 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
        if (cell)
                pdata->max_speed = fdt32_to_cpu(*cell);
 
-       return 0;
+       if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
+                           "snps,reset-active-low"))
+               reset_flags |= GPIOD_ACTIVE_LOW;
+
+       ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
+               &priv->reset_gpio, reset_flags);
+       if (ret == 0) {
+               ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
+                       "snps,reset-delays-us", dw_pdata->reset_delays, 3);
+       } else if (ret == -ENOENT) {
+               ret = 0;
+       }
+
+       return ret;
 }
 
 static const struct udevice_id designware_eth_ids[] = {
@@ -675,7 +739,7 @@ U_BOOT_DRIVER(eth_designware) = {
        .remove = designware_eth_remove,
        .ops    = &designware_eth_ops,
        .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
-       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+       .platdata_auto_alloc_size = sizeof(struct dw_eth_pdata),
        .flags = DM_FLAG_ALLOC_PRIV_DMA,
 };
 
index ed6344cc28f3cfdde713d27476be8abf2f8fb30b..04a45e050985713584444caa6e73b17037f3cd2b 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _DW_ETH_H
 #define _DW_ETH_H
 
+#include <asm/gpio.h>
+
 #define CONFIG_TX_DESCR_NUM    16
 #define CONFIG_RX_DESCR_NUM    16
 #define CONFIG_ETH_BUFSIZE     2048
@@ -232,8 +234,16 @@ struct dw_eth_dev {
 #ifndef CONFIG_DM_ETH
        struct eth_device *dev;
 #endif
+       struct gpio_desc reset_gpio;
        struct phy_device *phydev;
        struct mii_dev *bus;
 };
 
+#ifdef CONFIG_DM_ETH
+struct dw_eth_pdata {
+       struct eth_pdata eth_pdata;
+       u32 reset_delays[3];
+};
+#endif
+
 #endif