]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/net/sun8i_emac.c
net: sun8i_emac: Fix build for non-H3/H5 SoCs
[people/ms/u-boot.git] / drivers / net / sun8i_emac.c
index 7c088c311d1d2b166fc5ab43198400f2b5bb05f7..3ccc6b0bb612de20e6973979c28bb7d981cbc2df 100644 (file)
@@ -21,6 +21,9 @@
 #include <malloc.h>
 #include <miiphy.h>
 #include <net.h>
+#ifdef CONFIG_DM_GPIO
+#include <asm-generic/gpio.h>
+#endif
 
 #define MDIO_CMD_MII_BUSY              BIT(0)
 #define MDIO_CMD_MII_WRITE             BIT(1)
 
 #define CONFIG_TX_DESCR_NUM    32
 #define CONFIG_RX_DESCR_NUM    32
-#define CONFIG_ETH_BUFSIZE     2024
+#define CONFIG_ETH_BUFSIZE     2048 /* Note must be dma aligned */
+
+/*
+ * The datasheet says that each descriptor can transfers up to 4096 bytes
+ * But later, the register documentation reduces that value to 2048,
+ * using 2048 cause strange behaviours and even BSP driver use 2047
+ */
+#define CONFIG_ETH_RXSIZE      2044 /* Note must fit in ETH_BUFSIZE */
 
 #define TX_TOTAL_BUFSIZE       (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
 #define RX_TOTAL_BUFSIZE       (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
@@ -55,7 +65,7 @@
 
 #define AHB_GATE_OFFSET_EPHY   0
 
-#if defined(CONFIG_MACH_SUN8I_H3)
+#if defined(CONFIG_MACH_SUNXI_H3_H5)
 #define SUN8I_GPD8_GMAC                2
 #else
 #define SUN8I_GPD8_GMAC                4
@@ -121,11 +131,22 @@ struct emac_eth_dev {
        phys_addr_t sysctl_reg;
        struct phy_device *phydev;
        struct mii_dev *bus;
+#ifdef CONFIG_DM_GPIO
+       struct gpio_desc reset_gpio;
+#endif
 };
 
+
+struct sun8i_eth_pdata {
+       struct eth_pdata eth_pdata;
+       u32 reset_delays[3];
+};
+
+
 static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 {
-       struct emac_eth_dev *priv = bus->priv;
+       struct udevice *dev = bus->priv;
+       struct emac_eth_dev *priv = dev_get_priv(dev);
        ulong start;
        u32 miiaddr = 0;
        int timeout = CONFIG_MDIO_TIMEOUT;
@@ -157,7 +178,8 @@ static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
                            u16 val)
 {
-       struct emac_eth_dev *priv = bus->priv;
+       struct udevice *dev = bus->priv;
+       struct emac_eth_dev *priv = dev_get_priv(dev);
        ulong start;
        u32 miiaddr = 0;
        int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
@@ -173,8 +195,8 @@ static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
        miiaddr |= MDIO_CMD_MII_WRITE;
        miiaddr |= MDIO_CMD_MII_BUSY;
 
-       writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
        writel(val, priv->mac_reg + EMAC_MII_DATA);
+       writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
 
        start = get_timer(0);
        while (get_timer(start) < timeout) {
@@ -324,7 +346,7 @@ static void rx_descs_init(struct emac_eth_dev *priv)
                desc_p->buf_addr = (uintptr_t)&rxbuffs[idx * CONFIG_ETH_BUFSIZE]
                        ;
                desc_p->next = (uintptr_t)&desc_table_p[idx + 1];
-               desc_p->st |= CONFIG_ETH_BUFSIZE;
+               desc_p->st |= CONFIG_ETH_RXSIZE;
                desc_p->status = BIT(31);
        }
 
@@ -435,7 +457,7 @@ static int parse_phy_pins(struct udevice *dev)
        const char *pin_name;
        int drive, pull, i;
 
-       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
                                       "pinctrl-0");
        if (offset < 0) {
                printf("WARNING: emac: cannot find pinctrl-0 node\n");
@@ -449,8 +471,9 @@ static int parse_phy_pins(struct udevice *dev)
        for (i = 0; ; i++) {
                int pin;
 
-               if (fdt_get_string_index(gd->fdt_blob, offset,
-                                        "allwinner,pins", i, &pin_name))
+               pin_name = fdt_stringlist_get(gd->fdt_blob, offset,
+                                             "allwinner,pins", i, NULL);
+               if (!pin_name)
                        break;
                if (pin_name[0] != 'P')
                        continue;
@@ -506,7 +529,7 @@ static int _sun8i_eth_recv(struct emac_eth_dev *priv, uchar **packetp)
                                        roundup(data_end,
                                                ARCH_DMA_MINALIGN));
                if (good_packet) {
-                       if (length > CONFIG_ETH_BUFSIZE) {
+                       if (length > CONFIG_ETH_RXSIZE) {
                                printf("Received packet is too big (len=%d)\n",
                                       length);
                                return -EMSGSIZE;
@@ -581,6 +604,8 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
 {
        struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
+#ifdef CONFIG_MACH_SUNXI_H3_H5
+       /* Only H3/H5 have clock controls for internal EPHY */
        if (priv->use_internal_phy) {
                /* Set clock gating for ephy */
                setbits_le32(&ccm->bus_gate4, BIT(AHB_GATE_OFFSET_EPHY));
@@ -588,6 +613,7 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
                /* Deassert EPHY */
                setbits_le32(&ccm->ahb_reset2_cfg, BIT(AHB_RESET_OFFSET_EPHY));
        }
+#endif
 
        /* Set clock gating for emac */
        setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC));
@@ -596,7 +622,41 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
        setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC));
 }
 
-static int sun8i_mdio_init(const char *name, struct  emac_eth_dev *priv)
+#if defined(CONFIG_DM_GPIO)
+static int sun8i_mdio_reset(struct mii_dev *bus)
+{
+       struct udevice *dev = bus->priv;
+       struct emac_eth_dev *priv = dev_get_priv(dev);
+       struct sun8i_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 sun8i_mdio_init(const char *name, struct udevice *priv)
 {
        struct mii_dev *bus = mdio_alloc();
 
@@ -609,6 +669,9 @@ static int sun8i_mdio_init(const char *name, struct  emac_eth_dev *priv)
        bus->write = sun8i_mdio_write;
        snprintf(bus->name, sizeof(bus->name), name);
        bus->priv = (void *)priv;
+#if defined(CONFIG_DM_GPIO)
+       bus->reset = sun8i_mdio_reset;
+#endif
 
        return  mdio_register(bus);
 }
@@ -688,7 +751,7 @@ static int sun8i_emac_eth_probe(struct udevice *dev)
        sun8i_emac_board_setup(priv);
        sun8i_emac_set_syscon(priv);
 
-       sun8i_mdio_init(dev->name, priv);
+       sun8i_mdio_init(dev->name, dev);
        priv->bus = miiphy_get_dev_by_name(dev->name);
 
        return sun8i_phy_init(priv, dev);
@@ -705,25 +768,31 @@ static const struct eth_ops sun8i_emac_eth_ops = {
 
 static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
 {
-       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev);
+       struct eth_pdata *pdata = &sun8i_pdata->eth_pdata;
        struct emac_eth_dev *priv = dev_get_priv(dev);
        const char *phy_mode;
+       int node = dev_of_offset(dev);
        int offset = 0;
+#ifdef CONFIG_DM_GPIO
+       int reset_flags = GPIOD_IS_OUT;
+       int ret = 0;
+#endif
 
-       pdata->iobase = dev_get_addr_name(dev, "emac");
-       priv->sysctl_reg = dev_get_addr_name(dev, "syscon");
+       pdata->iobase = devfdt_get_addr_name(dev, "emac");
+       priv->sysctl_reg = devfdt_get_addr_name(dev, "syscon");
 
        pdata->phy_interface = -1;
        priv->phyaddr = -1;
        priv->use_internal_phy = false;
 
-       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, node,
                                       "phy");
        if (offset > 0)
                priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg",
                                               -1);
 
-       phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+       phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
 
        if (phy_mode)
                pdata->phy_interface = phy_get_interface_by_name(phy_mode);
@@ -743,7 +812,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
        }
 
        if (priv->variant == H3_EMAC) {
-               if (fdt_getprop(gd->fdt_blob, dev->of_offset,
+               if (fdt_getprop(gd->fdt_blob, node,
                                "allwinner,use-internal-phy", NULL))
                        priv->use_internal_phy = true;
        }
@@ -753,6 +822,23 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
        if (!priv->use_internal_phy)
                parse_phy_pins(dev);
 
+#ifdef CONFIG_DM_GPIO
+       if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+                           "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(dev),
+                                          "snps,reset-delays-us",
+                                          sun8i_pdata->reset_delays, 3);
+       } else if (ret == -ENOENT) {
+               ret = 0;
+       }
+#endif
+
        return 0;
 }
 
@@ -773,6 +859,6 @@ U_BOOT_DRIVER(eth_sun8i_emac) = {
        .probe  = sun8i_emac_eth_probe,
        .ops    = &sun8i_emac_eth_ops,
        .priv_auto_alloc_size = sizeof(struct emac_eth_dev),
-       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+       .platdata_auto_alloc_size = sizeof(struct sun8i_eth_pdata),
        .flags = DM_FLAG_ALLOC_PRIV_DMA,
 };