]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/net/cpsw.c
karo: cleanup after merge of v2015.10-rc2
[karo-tx-uboot.git] / drivers / net / cpsw.c
index b572177ad36703c3b2064dd4321bb552f6c8d7ce..5fd2b08cfca99a0b487c14a2bea86b4fd79e2ec6 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <cpsw.h>
 #include <net.h>
 #include <miiphy.h>
 #include <malloc.h>
 #include <asm/arch/cpu.h>
 
 #define BITMASK(bits)          (BIT(bits) - 1)
+
 #define PHY_REG_MASK           0x1f
 #define PHY_ID_MASK            0x1f
 #define NUM_DESCS              (PKTBUFSRX * 2)
 #define PKT_MIN                        60
 #define PKT_MAX                        (1500 + 14 + 4 + 4)
 #define CLEAR_BIT              1
+
+/* MAC_CONTROL register bits */
 #define GIGABITEN              BIT(7)
 #define FULLDUPLEXEN           BIT(0)
+#define MAC_CTRL_CMD_IDLE      BIT(11)
 #define MIIEN                  BIT(15)
 
+/* MAC_STATUS register bits */
+#define MAC_STAT_IDLE          BIT(31)
+
 /* DMA Registers */
 #define CPDMA_TXCONTROL                0x004
 #define CPDMA_RXCONTROL                0x014
 #define CPDMA_SOFTRESET                0x01c
+#define CPDMA_DMACONTROL       0x020
+#define CPDMA_DMASTATUS                0x024
 #define CPDMA_RXFREE           0x0e0
 #define CPDMA_TXHDP_VER1       0x100
 #define CPDMA_TXHDP_VER2       0x200
@@ -50,7 +60,9 @@
 #define CPDMA_RXCP_VER1                0x160
 #define CPDMA_RXCP_VER2                0x260
 
-#define CPDMA_RAM_ADDR         0x4a102000
+#define DMACONTROL_CMD_IDLE    BIT(3)
+
+#define DMASTATUS_IDLE         BIT(31)
 
 /* Descriptor mode bits */
 #define CPDMA_DESC_SOP         BIT(31)
@@ -108,7 +120,13 @@ struct cpsw_slave_regs {
        u32     flow_thresh;
        u32     port_vlan;
        u32     tx_pri_map;
+#ifdef CONFIG_AM33XX
        u32     gap_thresh;
+#elif defined(CONFIG_TI814X)
+       u32     ts_ctl;
+       u32     ts_seq_ltype;
+       u32     ts_vlan;
+#endif
        u32     sa_lo;
        u32     sa_hi;
 };
@@ -209,6 +227,8 @@ struct cpdma_chan {
 #define chan_read(chan, fld)           __raw_readl((chan)->fld)
 #define chan_read_ptr(chan, fld)       ((void *)__raw_readl((chan)->fld))
 
+#define for_active_slave(slave, priv) \
+       slave = (priv)->slaves + (priv)->data->active_slave; if (slave)
 #define for_each_slave(slave, priv) \
        for (slave = (priv)->slaves; slave != (priv)->slaves + \
                                (priv)->data->slaves; slave++)
@@ -230,6 +250,8 @@ struct cpsw_priv {
        struct cpsw_slave               *slaves;
        struct phy_device               *phydev;
        struct mii_dev                  *bus;
+
+       u32                             phy_mask;
 };
 
 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
@@ -283,7 +305,7 @@ static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
                addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
 }
 
-static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
+static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr)
 {
        int i;
 
@@ -315,7 +337,7 @@ static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry)
        return idx;
 }
 
-static int cpsw_ale_match_addr(struct cpsw_priv *priv, u8* addr)
+static int cpsw_ale_match_addr(struct cpsw_priv *priv, const u8 *addr)
 {
        u32 ale_entry[ALE_ENTRY_WORDS];
        int type, idx;
@@ -368,7 +390,7 @@ static int cpsw_ale_find_ageable(struct cpsw_priv *priv)
        return -ENOENT;
 }
 
-static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
+static int cpsw_ale_add_ucast(struct cpsw_priv *priv, const u8 *addr,
                              int port, int flags)
 {
        u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
@@ -393,7 +415,8 @@ static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
        return 0;
 }
 
-static int cpsw_ale_add_mcast(struct cpsw_priv *priv, u8 *addr, int port_mask)
+static int cpsw_ale_add_mcast(struct cpsw_priv *priv, const u8 *addr,
+                             int port_mask)
 {
        u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
        int idx, mask;
@@ -483,7 +506,7 @@ static inline void wait_for_idle(void)
 static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
                                int dev_addr, int phy_reg)
 {
-       unsigned short data;
+       int data;
        u32 reg;
 
        if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
@@ -620,13 +643,13 @@ static int cpsw_update_link(struct cpsw_priv *priv)
        int link = 0;
        struct cpsw_slave *slave;
 
-       for_each_slave(slave, priv)
+       for_active_slave(slave, priv)
                cpsw_slave_update_link(slave, priv, &link);
 
        return link;
 }
 
-static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
+static inline u32  cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
 {
        if (priv->host_port == 0)
                return slave_num + 1;
@@ -655,7 +678,9 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
        slave_port = cpsw_get_slave_port(priv, slave->slave_num);
        cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD);
 
-       cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << slave_port);
+       cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << slave_port);
+
+       priv->phy_mask |= 1 << slave->data->phy_addr;
 }
 
 static void cpdma_desc_get(struct cpsw_desc *desc)
@@ -804,14 +829,15 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis)
 
        /* enable statistics collection only on the host port */
        __raw_writel(BIT(priv->host_port), &priv->regs->stat_port_en);
+       __raw_writel(0x7, &priv->regs->stat_port_en);
 
        cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD);
 
        cpsw_ale_add_ucast(priv, priv->dev->enetaddr, priv->host_port,
                           ALE_SECURE);
-       cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << priv->host_port);
+       cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << priv->host_port);
 
-       for_each_slave(slave, priv)
+       for_active_slave(slave, priv)
                cpsw_slave_init(slave, priv);
 
        cpsw_update_link(priv);
@@ -876,7 +902,7 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis)
 
        /* submit rx descs */
        for (i = 0; i < PKTBUFSRX; i++) {
-               ret = cpdma_submit(priv, &priv->rx_chan, NetRxPackets[i],
+               ret = cpdma_submit(priv, &priv->rx_chan, net_rx_packets[i],
                                   PKTSIZE);
                if (ret < 0) {
                        printf("error %d submitting rx desc\n", ret);
@@ -890,6 +916,31 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis)
 static void cpsw_halt(struct eth_device *dev)
 {
        struct cpsw_priv        *priv = dev->priv;
+       struct cpsw_slave       *slave;
+       int idle = 0;
+       int timeout = 1000000;
+
+       __raw_writel(DMACONTROL_CMD_IDLE, priv->dma_regs + CPDMA_DMACONTROL);
+       while (!(__raw_readl(priv->dma_regs + CPDMA_DMASTATUS) &
+                       DMASTATUS_IDLE) && (--timeout >= 0))
+               udelay(1);
+
+       timeout = 1000000;
+       while (!idle) {
+               idle = 1;
+               for_each_slave(slave, priv) {
+                       if (!(__raw_readl(&slave->sliver->mac_status) &
+                                       MAC_STAT_IDLE)) {
+                               idle = 0;
+                               break;
+                       }
+               }
+               if (idle || --timeout < 0)
+                       break;
+               udelay(1);
+       }
+       if (!idle)
+               printf("CPSW: Aborting DMA transfers; packets may be lost\n");
 
        writel(0, priv->dma_regs + CPDMA_TXCONTROL);
        writel(0, priv->dma_regs + CPDMA_RXCONTROL);
@@ -910,13 +961,6 @@ static int cpsw_send(struct eth_device *dev, void *packet, int length)
        void *buffer;
        int len;
 
-       debug("%s@%d: sending packet %p..%p\n", __func__, __LINE__,
-               packet, packet + length - 1);
-
-       if (!priv->data->mac_control && !cpsw_update_link(priv)) {
-               printf("%s: Cannot send packet; link is down\n", __func__);
-               return -EIO;
-       }
 
        /* first reap completed packets */
        while (cpdma_process(priv, &priv->tx_chan, &buffer, &len) == 0)
@@ -933,7 +977,7 @@ static int cpsw_recv(struct eth_device *dev)
 
        while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) == 0) {
                if (buffer) {
-                       NetReceive(buffer, len);
+                       net_process_received_packet(buffer, len);
                        cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE);
                } else {
                        printf("NULL buffer returned from cpdma_process\n");
@@ -962,13 +1006,9 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave)
 {
        struct cpsw_priv *priv = (struct cpsw_priv *)dev->priv;
        struct phy_device *phydev;
-       u32 supported = (SUPPORTED_10baseT_Half |
-                       SUPPORTED_10baseT_Full |
-                       SUPPORTED_100baseT_Half |
-                       SUPPORTED_100baseT_Full |
-                       SUPPORTED_1000baseT_Full);
+       u32 supported = PHY_GBIT_FEATURES;
 
-       if (slave->data->phy_id < 0) {
+       if (slave->data->phy_addr < 0) {
                u32 phy_addr;
 
                for (phy_addr = 0; phy_addr < 32; phy_addr++) {
@@ -981,7 +1021,7 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave)
                }
        } else {
                phydev = phy_connect(priv->bus,
-                               slave->data->phy_id,
+                               slave->data->phy_addr,
                                dev,
                                slave->data->phy_if);
        }
@@ -990,6 +1030,9 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave)
                return -EINVAL;
        }
 
+       if (!phydev)
+               return -1;
+
        phydev->supported &= supported;
        phydev->advertising = phydev->supported;
 
@@ -1006,7 +1049,6 @@ int cpsw_register(struct cpsw_platform_data *data)
        struct cpsw_slave       *slave;
        void                    *regs = (void *)data->cpsw_base;
        struct eth_device       *dev;
-       int i;
        int idx = 0;
 
        debug("%s@%d\n", __func__, __LINE__);
@@ -1031,23 +1073,6 @@ int cpsw_register(struct cpsw_platform_data *data)
                return -ENOMEM;
        }
 
-       for (i = 0; i < NUM_DESCS; i++) {
-               priv->descs[i].dma_desc = memalign(CONFIG_SYS_CACHELINE_SIZE,
-                               sizeof(struct cpsw_desc) * NUM_DESCS);
-               if (!priv->descs[i].dma_desc) {
-                       while (--i >= 0) {
-                               free(priv->descs[i].dma_desc);
-                       }
-                       free(priv->slaves);
-                       free(priv);
-                       free(dev);
-                       return -ENOMEM;
-               }
-               debug("DMA desc[%d] allocated @ %p desc_size %u\n",
-                       i, priv->descs[i].dma_desc,
-                       sizeof(*priv->descs[i].dma_desc));
-       }
-
        priv->host_port         = data->host_port_num;
        priv->regs              = regs;
        priv->host_port_regs    = regs + data->host_port_reg_ofs;
@@ -1071,10 +1096,8 @@ int cpsw_register(struct cpsw_platform_data *data)
 
        cpsw_mdio_init(dev->name, data->mdio_base, data->mdio_div);
        priv->bus = miiphy_get_dev_by_name(dev->name);
-       for_each_slave(slave, priv) {
+       for_active_slave(slave, priv)
                ret = cpsw_phy_init(dev, slave);
-               if (ret < 0)
-                       break;
-       }
+
        return ret;
 }