]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/net/keystone_net.c
net/phy/cortina: Fix compilation warning
[karo-tx-uboot.git] / drivers / net / keystone_net.c
index 63f33611cb6a77fc39f58b29c4a9a81246fe73be..0c5fdeefd758424bc64e97fd51ed97762e793094 100644 (file)
@@ -10,6 +10,8 @@
 #include <command.h>
 
 #include <net.h>
+#include <phy.h>
+#include <errno.h>
 #include <miiphy.h>
 #include <malloc.h>
 #include <asm/ti-common/keystone_nav.h>
@@ -17,6 +19,7 @@
 #include <asm/ti-common/keystone_serdes.h>
 
 unsigned int emac_open;
+static struct mii_dev *mdio_bus;
 static unsigned int sys_has_mdio = 1;
 
 #ifdef KEYSTONE2_EMAC_GIG_ENABLE
@@ -28,6 +31,7 @@ static unsigned int sys_has_mdio = 1;
 #define RX_BUFF_NUMS   24
 #define RX_BUFF_LEN    1520
 #define MAX_SIZE_STREAM_BUFFER RX_BUFF_LEN
+#define SGMII_ANEG_TIMEOUT             4000
 
 static u8 rx_buffs[RX_BUFF_NUMS * RX_BUFF_LEN] __aligned(16);
 
@@ -38,15 +42,8 @@ struct rx_buff_desc net_rx_buffs = {
        .rx_flow        = 22,
 };
 
-static void keystone2_eth_mdio_enable(void);
 static void keystone2_net_serdes_setup(void);
 
-static int gen_get_link_speed(int phy_addr);
-
-/* EMAC Addresses */
-static volatile struct mdio_regs       *adap_mdio =
-       (struct mdio_regs *)EMAC_MDIO_BASE_ADDR;
-
 int keystone2_eth_read_mac_addr(struct eth_device *dev)
 {
        struct eth_priv_t *eth_priv;
@@ -71,64 +68,67 @@ int keystone2_eth_read_mac_addr(struct eth_device *dev)
        return 0;
 }
 
-static void keystone2_eth_mdio_enable(void)
+/* MDIO */
+
+static int keystone2_mdio_reset(struct mii_dev *bus)
 {
-       u_int32_t       clkdiv;
+       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,
+       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;
 }
 
-/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
-int keystone2_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
+/**
+ * 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;
+       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_num & 0x1f) << 21) |
-              ((phy_addr & 0x1f) << 16),
+       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) {
-               *data = tmp & 0xffff;
-               return 0;
-       }
+       if (tmp & MDIO_USERACCESS0_ACK)
+               return tmp & 0xffff;
 
-       *data = -1;
        return -1;
 }
 
-/*
- * Write to a PHY register via MDIO inteface.
+/**
+ * keystone2_mdio_write - write to a PHY register via MDIO interface.
  * Blocks until operation is complete.
  */
-int keystone2_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
+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_num & 0x1f) << 21) |
-              ((phy_addr & 0x1f) << 16) |
-              (data & 0xffff),
-              &adap_mdio->useraccess0);
+       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)
@@ -137,19 +137,6 @@ int keystone2_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
        return 0;
 }
 
-/* PHY functions for a generic PHY */
-static int gen_get_link_speed(int phy_addr)
-{
-       u_int16_t       tmp;
-
-       if ((!keystone2_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp)) &&
-           (tmp & 0x04)) {
-               return 0;
-       }
-
-       return -1;
-}
-
 static void  __attribute__((unused))
        keystone2_eth_gigabit_enable(struct eth_device *dev)
 {
@@ -157,8 +144,10 @@ static void  __attribute__((unused))
        struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
 
        if (sys_has_mdio) {
-               if (keystone2_eth_phy_read(eth_priv->phy_addr, 0, &data) ||
-                   !(data & (1 << 6))) /* speed selection MSB */
+               data = keystone2_mdio_read(mdio_bus, eth_priv->phy_addr,
+                                          MDIO_DEVAD_NONE, 0);
+               /* speed selection MSB */
+               if (!(data & (1 << 6)))
                        return;
        }
 
@@ -178,38 +167,11 @@ int keystone_sgmii_link_status(int port)
 
        status = __raw_readl(SGMII_STATUS_REG(port));
 
-       return status & SGMII_REG_STATUS_LINK;
+       return (status & SGMII_REG_STATUS_LOCK) &&
+              (status & SGMII_REG_STATUS_LINK);
 }
 
-
-int keystone_get_link_status(struct eth_device *dev)
-{
-       struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
-       int sgmii_link;
-       int link_state = 0;
-#if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1
-       int j;
-
-       for (j = 0; (j < CONFIG_GET_LINK_STATUS_ATTEMPTS) && (link_state == 0);
-            j++) {
-#endif
-               sgmii_link =
-                       keystone_sgmii_link_status(eth_priv->slave_port - 1);
-
-               if (sgmii_link) {
-                       link_state = 1;
-
-                       if (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY)
-                               if (gen_get_link_speed(eth_priv->phy_addr))
-                                       link_state = 0;
-               }
-#if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1
-       }
-#endif
-       return link_state;
-}
-
-int keystone_sgmii_config(int port, int interface)
+int keystone_sgmii_config(struct phy_device *phy_dev, int port, int interface)
 {
        unsigned int i, status, mask;
        unsigned int mr_adv_ability, control;
@@ -270,11 +232,35 @@ int keystone_sgmii_config(int port, int interface)
        if (control & SGMII_REG_CONTROL_AUTONEG)
                mask |= SGMII_REG_STATUS_AUTONEG;
 
-       for (i = 0; i < 1000; i++) {
+       status = __raw_readl(SGMII_STATUS_REG(port));
+       if ((status & mask) == mask)
+               return 0;
+
+       printf("\n%s Waiting for SGMII auto negotiation to complete",
+              phy_dev->dev->name);
+       while ((status & mask) != mask) {
+               /*
+                * Timeout reached ?
+                */
+               if (i > SGMII_ANEG_TIMEOUT) {
+                       puts(" TIMEOUT !\n");
+                       phy_dev->link = 0;
+                       return 0;
+               }
+
+               if (ctrlc()) {
+                       puts("user interrupt!\n");
+                       phy_dev->link = 0;
+                       return -EINTR;
+               }
+
+               if ((i++ % 500) == 0)
+                       printf(".");
+
+               udelay(1000);   /* 1 ms */
                status = __raw_readl(SGMII_STATUS_REG(port));
-               if ((status & mask) == mask)
-                       break;
        }
+       puts(" done\n");
 
        return 0;
 }
@@ -329,6 +315,11 @@ int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
        writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN);
        writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL);
 
+#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
+       /* Map RX packet flow priority to 0 */
+       writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP);
+#endif
+
        return ret;
 }
 
@@ -397,9 +388,8 @@ int32_t cpmac_drv_send(u32 *buffer, int num_bytes, int slave_port_num)
 /* Eth device open */
 static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
 {
-       u_int32_t clkdiv;
-       int link;
        struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+       struct phy_device *phy_dev = eth_priv->phy_dev;
 
        debug("+ emac_open\n");
 
@@ -408,12 +398,10 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
        sys_has_mdio =
                (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY) ? 1 : 0;
 
-       keystone2_net_serdes_setup();
-
        if (sys_has_mdio)
-               keystone2_eth_mdio_enable();
+               keystone2_mdio_reset(mdio_bus);
 
-       keystone_sgmii_config(eth_priv->slave_port - 1,
+       keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1,
                              eth_priv->sgmii_link_type);
 
        udelay(10000);
@@ -440,17 +428,10 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
        hw_config_streaming_switch();
 
        if (sys_has_mdio) {
-               /* Init MDIO & get link state */
-               clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
-               writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE |
-                      MDIO_CONTROL_FAULT, &adap_mdio->control)
-                       ;
-
-               /* We need to wait for MDIO to start */
-               udelay(1000);
+               keystone2_mdio_reset(mdio_bus);
 
-               link = keystone_get_link_status(dev);
-               if (link == 0) {
+               phy_startup(phy_dev);
+               if (phy_dev->link == 0) {
                        ksnav_close(&netcp_pktdma);
                        qm_close();
                        return -1;
@@ -471,6 +452,9 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
 /* Eth device close */
 void keystone2_eth_close(struct eth_device *dev)
 {
+       struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+       struct phy_device *phy_dev = eth_priv->phy_dev;
+
        debug("+ emac_close\n");
 
        if (!emac_open)
@@ -480,6 +464,7 @@ void keystone2_eth_close(struct eth_device *dev)
 
        ksnav_close(&netcp_pktdma);
        qm_close();
+       phy_shutdown(phy_dev);
 
        emac_open = 0;
 
@@ -495,8 +480,10 @@ static int keystone2_eth_send_packet(struct eth_device *dev,
 {
        int ret_status = -1;
        struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+       struct phy_device *phy_dev = eth_priv->phy_dev;
 
-       if (keystone_get_link_status(dev) == 0)
+       genphy_update_link(phy_dev);
+       if (phy_dev->link == 0)
                return -1;
 
        if (cpmac_drv_send((u32 *)packet, length, eth_priv->slave_port) != 0)
@@ -518,7 +505,7 @@ static int keystone2_eth_rcv_packet(struct eth_device *dev)
        if (hd == NULL)
                return 0;
 
-       NetReceive((uchar *)pkt, pkt_size);
+       net_process_received_packet((uchar *)pkt, pkt_size);
 
        ksnav_release_rxhd(&netcp_pktdma, hd);
 
@@ -530,7 +517,9 @@ static int keystone2_eth_rcv_packet(struct eth_device *dev)
  */
 int keystone2_emac_initialize(struct eth_priv_t *eth_priv)
 {
+       int res;
        struct eth_device *dev;
+       struct phy_device *phy_dev;
 
        dev = malloc(sizeof(struct eth_device));
        if (dev == NULL)
@@ -551,10 +540,57 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv)
 
        eth_register(dev);
 
+       /* Register MDIO bus if it's not registered yet */
+       if (!mdio_bus) {
+               mdio_bus        = mdio_alloc();
+               mdio_bus->read  = keystone2_mdio_read;
+               mdio_bus->write = keystone2_mdio_write;
+               mdio_bus->reset = keystone2_mdio_reset;
+               mdio_bus->priv  = (void *)EMAC_MDIO_BASE_ADDR;
+               sprintf(mdio_bus->name, "ethernet-mdio");
+
+               res = mdio_register(mdio_bus);
+               if (res)
+                       return res;
+       }
+
+       keystone2_net_serdes_setup();
+
+       /* Create phy device and bind it with driver */
+#ifdef CONFIG_KSNET_MDIO_PHY_CONFIG_ENABLE
+       phy_dev = phy_connect(mdio_bus, eth_priv->phy_addr,
+                             dev, PHY_INTERFACE_MODE_SGMII);
+       phy_config(phy_dev);
+#else
+       phy_dev = phy_find_by_mask(mdio_bus, 1 << eth_priv->phy_addr,
+                                  PHY_INTERFACE_MODE_SGMII);
+       phy_dev->dev = dev;
+#endif
+       eth_priv->phy_dev = phy_dev;
+
        return 0;
 }
 
+struct ks2_serdes ks2_serdes_sgmii_156p25mhz = {
+       .clk = SERDES_CLOCK_156P25M,
+       .rate = SERDES_RATE_5G,
+       .rate_mode = SERDES_QUARTER_RATE,
+       .intf = SERDES_PHY_SGMII,
+       .loopback = 0,
+};
+
 static void keystone2_net_serdes_setup(void)
 {
-       ks2_serdes_sgmii_156p25mhz_setup();
+       ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE,
+                       &ks2_serdes_sgmii_156p25mhz,
+                       CONFIG_KSNET_SERDES_LANES_PER_SGMII);
+
+#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
+       ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE,
+                       &ks2_serdes_sgmii_156p25mhz,
+                       CONFIG_KSNET_SERDES_LANES_PER_SGMII);
+#endif
+
+       /* wait till setup */
+       udelay(5000);
 }