Merge tag 'u-boot-amlogic-20190423' of git://git.denx.de/u-boot-amlogic
[oweals/u-boot.git] / drivers / net / ti / keystone_net.c
index 55505722077b397679f044042faec872503ebf2b..4baeeb83f109cb551cc748c520b2f05e6264010c 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/ti-common/keystone_serdes.h>
 #include <asm/arch/psc_defs.h>
 
+#include "cpsw_mdio.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef KEYSTONE2_EMAC_GIG_ENABLE
@@ -86,6 +88,7 @@ struct ks2_eth_priv {
        struct mii_dev                  *mdio_bus;
        int                             phy_addr;
        phy_interface_t                 phy_if;
+       int                             phy_of_handle;
        int                             sgmii_link_type;
        void                            *mdio_base;
        struct rx_buff_desc             net_rx_buffs;
@@ -97,93 +100,20 @@ struct ks2_eth_priv {
        bool                            has_mdio;
 };
 
-/* MDIO */
-
-static int keystone2_mdio_reset(struct mii_dev *bus)
-{
-       u_int32_t clkdiv;
-       struct mdio_regs *adap_mdio = bus->priv;
-
-       clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
-
-       writel((clkdiv & 0xffff) | MDIO_CONTROL_ENABLE |
-              MDIO_CONTROL_FAULT | MDIO_CONTROL_FAULT_ENABLE,
-              &adap_mdio->control);
-
-       while (readl(&adap_mdio->control) & MDIO_CONTROL_IDLE)
-               ;
-
-       return 0;
-}
-
-/**
- * keystone2_mdio_read - read a PHY register via MDIO interface.
- * Blocks until operation is complete.
- */
-static int keystone2_mdio_read(struct mii_dev *bus,
-                              int addr, int devad, int reg)
-{
-       int tmp;
-       struct mdio_regs *adap_mdio = bus->priv;
-
-       while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO)
-               ;
-
-       writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_READ |
-              ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16),
-              &adap_mdio->useraccess0);
-
-       /* Wait for command to complete */
-       while ((tmp = readl(&adap_mdio->useraccess0)) & MDIO_USERACCESS0_GO)
-               ;
-
-       if (tmp & MDIO_USERACCESS0_ACK)
-               return tmp & 0xffff;
-
-       return -1;
-}
-
-/**
- * keystone2_mdio_write - write to a PHY register via MDIO interface.
- * Blocks until operation is complete.
- */
-static int keystone2_mdio_write(struct mii_dev *bus,
-                               int addr, int devad, int reg, u16 val)
-{
-       struct mdio_regs *adap_mdio = bus->priv;
-
-       while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO)
-               ;
-
-       writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_WRITE |
-              ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16) |
-              (val & 0xffff), &adap_mdio->useraccess0);
-
-       /* Wait for command to complete */
-       while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO)
-               ;
-
-       return 0;
-}
-
 static void  __attribute__((unused))
        keystone2_eth_gigabit_enable(struct udevice *dev)
 {
        struct ks2_eth_priv *priv = dev_get_priv(dev);
-       u_int16_t data;
-
-       if (priv->has_mdio) {
-               data = keystone2_mdio_read(priv->mdio_bus, priv->phy_addr,
-                                          MDIO_DEVAD_NONE, 0);
-               /* speed selection MSB */
-               if (!(data & (1 << 6)))
-                       return;
-       }
 
        /*
         * Check if link detected is giga-bit
         * If Gigabit mode detected, enable gigbit in MAC
         */
+       if (priv->has_mdio) {
+               if (priv->phydev->speed != 1000)
+                       return;
+       }
+
        writel(readl(DEVICE_EMACSL_BASE(priv->slave_port - 1) +
                     CPGMACSL_REG_CTL) |
               EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE,
@@ -484,8 +414,6 @@ static int ks2_eth_start(struct udevice *dev)
        hw_config_streaming_switch();
 
        if (priv->has_mdio) {
-               keystone2_mdio_reset(priv->mdio_bus);
-
                phy_startup(priv->phydev);
                if (priv->phydev->link == 0) {
                        pr_err("phy startup failed\n");
@@ -605,9 +533,9 @@ static int ks2_eth_probe(struct udevice *dev)
 {
        struct ks2_eth_priv *priv = dev_get_priv(dev);
        struct mii_dev *mdio_bus;
-       int ret;
 
        priv->dev = dev;
+       priv->emac_open = false;
 
        /* These clock enables has to be moved to common location */
        if (cpu_is_k2g())
@@ -626,50 +554,45 @@ static int ks2_eth_probe(struct udevice *dev)
        if (cpu_is_k2e() || cpu_is_k2l())
                pll_pa_clk_sel();
 
-
        priv->net_rx_buffs.buff_ptr = rx_buffs;
        priv->net_rx_buffs.num_buffs = RX_BUFF_NUMS;
        priv->net_rx_buffs.buff_len = RX_BUFF_LEN;
 
        if (priv->slave_port == 1) {
+#ifndef CONFIG_SOC_K2G
+               keystone2_net_serdes_setup();
+#endif
                /*
                 * Register MDIO bus for slave 0 only, other slave have
                 * to re-use the same
                 */
-               mdio_bus = mdio_alloc();
+               mdio_bus = cpsw_mdio_init("ethernet-mdio",
+                                         (u32)priv->mdio_base,
+                                         EMAC_MDIO_CLOCK_FREQ,
+                                         EMAC_MDIO_BUS_FREQ);
                if (!mdio_bus) {
                        pr_err("MDIO alloc failed\n");
                        return -ENOMEM;
                }
                priv->mdio_bus = mdio_bus;
-               mdio_bus->read  = keystone2_mdio_read;
-               mdio_bus->write = keystone2_mdio_write;
-               mdio_bus->reset = keystone2_mdio_reset;
-               mdio_bus->priv  = priv->mdio_base;
-               sprintf(mdio_bus->name, "ethernet-mdio");
-
-               ret = mdio_register(mdio_bus);
-               if (ret) {
-                       pr_err("MDIO bus register failed\n");
-                       return ret;
-               }
        } else {
                /* Get the MDIO bus from slave 0 device */
                struct ks2_eth_priv *parent_priv;
 
                parent_priv = dev_get_priv(dev->parent);
                priv->mdio_bus = parent_priv->mdio_bus;
+               priv->mdio_base = parent_priv->mdio_base;
        }
 
-#ifndef CONFIG_SOC_K2G
-       keystone2_net_serdes_setup();
-#endif
-
        priv->netcp_pktdma = &netcp_pktdma;
 
        if (priv->has_mdio) {
                priv->phydev = phy_connect(priv->mdio_bus, priv->phy_addr,
                                           dev, priv->phy_if);
+#ifdef CONFIG_DM_ETH
+       if (priv->phy_of_handle)
+               priv->phydev->node = offset_to_ofnode(priv->phy_of_handle);
+#endif
                phy_config(priv->phydev);
        }
 
@@ -680,9 +603,7 @@ int ks2_eth_remove(struct udevice *dev)
 {
        struct ks2_eth_priv *priv = dev_get_priv(dev);
 
-       free(priv->phydev);
-       mdio_unregister(priv->mdio_bus);
-       mdio_free(priv->mdio_bus);
+       cpsw_mdio_free(priv->mdio_bus);
 
        return 0;
 }
@@ -763,6 +684,7 @@ static int ks2_eth_parse_slave_interface(int netcp, int slave,
        int phy;
        int dma_count;
        u32 dma_channel[8];
+       const char *phy_mode;
 
        priv->slave_port = fdtdec_get_int(fdt, slave, "slave-port", -1);
        priv->net_rx_buffs.rx_flow = priv->slave_port * 8;
@@ -784,7 +706,9 @@ static int ks2_eth_parse_slave_interface(int netcp, int slave,
        priv->link_type = fdtdec_get_int(fdt, slave, "link-interface", -1);
 
        phy = fdtdec_lookup_phandle(fdt, slave, "phy-handle");
+
        if (phy >= 0) {
+               priv->phy_of_handle = phy;
                priv->phy_addr = fdtdec_get_int(fdt, phy, "reg", -1);
 
                mdio = fdt_parent_offset(fdt, phy);
@@ -801,7 +725,19 @@ static int ks2_eth_parse_slave_interface(int netcp, int slave,
                priv->sgmii_link_type = SGMII_LINK_MAC_PHY;
                priv->has_mdio = true;
        } else if (priv->link_type == LINK_TYPE_RGMII_LINK_MAC_PHY) {
-               priv->phy_if = PHY_INTERFACE_MODE_RGMII;
+               phy_mode = fdt_getprop(fdt, slave, "phy-mode", NULL);
+               if (phy_mode) {
+                       priv->phy_if = phy_get_interface_by_name(phy_mode);
+                       if (priv->phy_if != PHY_INTERFACE_MODE_RGMII &&
+                           priv->phy_if != PHY_INTERFACE_MODE_RGMII_ID &&
+                           priv->phy_if != PHY_INTERFACE_MODE_RGMII_RXID &&
+                           priv->phy_if != PHY_INTERFACE_MODE_RGMII_TXID) {
+                               pr_err("invalid phy-mode\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       priv->phy_if = PHY_INTERFACE_MODE_RGMII;
+               }
                pdata->phy_interface = priv->phy_if;
                priv->has_mdio = true;
        }