Merge tag 'u-boot-rockchip-20200501' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / drivers / net / dwc_eth_qos.c
index 6df9956..60dfd17 100644 (file)
  */
 #include <common.h>
 #include <clk.h>
+#include <cpu_func.h>
 #include <dm.h>
 #include <errno.h>
+#include <malloc.h>
 #include <memalign.h>
 #include <miiphy.h>
 #include <net.h>
@@ -304,6 +306,8 @@ struct eqos_priv {
        struct clk clk_slave_bus;
        struct mii_dev *mii;
        struct phy_device *phy;
+       int phyaddr;
+       u32 max_speed;
        void *descs;
        struct eqos_desc *tx_descs;
        struct eqos_desc *rx_descs;
@@ -692,6 +696,29 @@ static int eqos_start_resets_tegra186(struct udevice *dev)
 
 static int eqos_start_resets_stm32(struct udevice *dev)
 {
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       int ret;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+       if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+               ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+               if (ret < 0) {
+                       pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
+                              ret);
+                       return ret;
+               }
+
+               udelay(2);
+
+               ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
+               if (ret < 0) {
+                       pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d",
+                              ret);
+                       return ret;
+               }
+       }
+       debug("%s: OK\n", __func__);
+
        return 0;
 }
 
@@ -707,6 +734,18 @@ static int eqos_stop_resets_tegra186(struct udevice *dev)
 
 static int eqos_stop_resets_stm32(struct udevice *dev)
 {
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       int ret;
+
+       if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+               ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+               if (ret < 0) {
+                       pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
+                              ret);
+                       return ret;
+               }
+       }
+
        return 0;
 }
 
@@ -1044,12 +1083,21 @@ static int eqos_start(struct udevice *dev)
         * don't need to reconnect/reconfigure again
         */
        if (!eqos->phy) {
-               eqos->phy = phy_connect(eqos->mii, 0, dev,
+               eqos->phy = phy_connect(eqos->mii, eqos->phyaddr, dev,
                                        eqos->config->interface(dev));
                if (!eqos->phy) {
                        pr_err("phy_connect() failed");
                        goto err_stop_resets;
                }
+
+               if (eqos->max_speed) {
+                       ret = phy_set_supported(eqos->phy, eqos->max_speed);
+                       if (ret) {
+                               pr_err("phy_set_supported() failed: %d", ret);
+                               goto err_shutdown_phy;
+                       }
+               }
+
                ret = phy_config(eqos->phy);
                if (ret < 0) {
                        pr_err("phy_config() failed: %d", ret);
@@ -1240,9 +1288,9 @@ static int eqos_start(struct udevice *dev)
                struct eqos_desc *rx_desc = &(eqos->rx_descs[i]);
                rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
                                             (i * EQOS_MAX_PACKET_SIZE));
-               rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+               rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+               eqos->config->ops->eqos_flush_desc(rx_desc);
        }
-       eqos->config->ops->eqos_flush_desc(eqos->descs);
 
        writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
        writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address);
@@ -1371,7 +1419,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length)
        tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length;
        eqos->config->ops->eqos_flush_desc(tx_desc);
 
-       writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer);
+       writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])),
+               &eqos->dma_regs->ch0_txdesc_tail_pointer);
 
        for (i = 0; i < 1000000; i++) {
                eqos->config->ops->eqos_inval_desc(tx_desc);
@@ -1394,6 +1443,7 @@ static int eqos_recv(struct udevice *dev, int flags, uchar **packetp)
        debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags);
 
        rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
+       eqos->config->ops->eqos_inval_desc(rx_desc);
        if (rx_desc->des3 & EQOS_DESC3_OWN) {
                debug("%s: RX packet not available\n", __func__);
                return -EAGAIN;
@@ -1426,6 +1476,11 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
        }
 
        rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
+
+       rx_desc->des0 = 0;
+       mb();
+       eqos->config->ops->eqos_flush_desc(rx_desc);
+       eqos->config->ops->eqos_inval_buffer(packet, length);
        rx_desc->des0 = (u32)(ulong)packet;
        rx_desc->des1 = 0;
        rx_desc->des2 = 0;
@@ -1434,7 +1489,7 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
         * writes to the rest of the descriptor too.
         */
        mb();
-       rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+       rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
        eqos->config->ops->eqos_flush_desc(rx_desc);
 
        writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
@@ -1488,6 +1543,9 @@ static int eqos_probe_resources_core(struct udevice *dev)
        }
        debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt);
 
+       eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf,
+                       EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX);
+
        debug("%s: OK\n", __func__);
        return 0;
 
@@ -1591,8 +1649,8 @@ err_free_reset_eqos:
 }
 
 /* board-specific Ethernet Interface initializations. */
-__weak int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg,
-                                   bool eth_ref_clk_sel_reg)
+__weak int board_interface_eth_init(struct udevice *dev,
+                                   phy_interface_t interface_type)
 {
        return 0;
 }
@@ -1602,8 +1660,7 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
        struct eqos_priv *eqos = dev_get_priv(dev);
        int ret;
        phy_interface_t interface;
-       bool eth_clk_sel_reg = false;
-       bool eth_ref_clk_sel_reg = false;
+       struct ofnode_phandle_args phandle_args;
 
        debug("%s(dev=%p):\n", __func__, dev);
 
@@ -1614,18 +1671,12 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
                return -EINVAL;
        }
 
-       /* Gigabit Ethernet 125MHz clock selection. */
-       eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel");
-
-       /* Ethernet 50Mhz RMII clock selection */
-       eth_ref_clk_sel_reg =
-               dev_read_bool(dev, "st,eth_ref_clk_sel");
-
-       ret = board_interface_eth_init(interface, eth_clk_sel_reg,
-                                      eth_ref_clk_sel_reg);
+       ret = board_interface_eth_init(dev, interface);
        if (ret)
                return -EINVAL;
 
+       eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);
+
        ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
        if (ret) {
                pr_err("clk_get_by_name(master_bus) failed: %d", ret);
@@ -1649,6 +1700,24 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
        if (ret)
                pr_warn("No phy clock provided %d", ret);
 
+       eqos->phyaddr = -1;
+       ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
+                                        &phandle_args);
+       if (!ret) {
+               /* search "reset-gpios" in phy node */
+               ret = gpio_request_by_name_nodev(phandle_args.node,
+                                                "reset-gpios", 0,
+                                                &eqos->phy_reset_gpio,
+                                                GPIOD_IS_OUT |
+                                                GPIOD_IS_OUT_ACTIVE);
+               if (ret)
+                       pr_warn("gpio_request_by_name(phy reset) not provided %d",
+                               ret);
+
+               eqos->phyaddr = ofnode_read_u32_default(phandle_args.node,
+                                                       "reg", -1);
+       }
+
        debug("%s: OK\n", __func__);
        return 0;
 
@@ -1712,6 +1781,9 @@ static int eqos_remove_resources_stm32(struct udevice *dev)
        if (clk_valid(&eqos->clk_ck))
                clk_free(&eqos->clk_ck);
 
+       if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
+               dm_gpio_free(dev, &eqos->phy_reset_gpio);
+
        debug("%s: OK\n", __func__);
        return 0;
 }