]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/faraday/ftgmac100.c
ftgmac100: Rework MAC reset and init
[karo-tx-linux.git] / drivers / net / ethernet / faraday / ftgmac100.c
index 88c492e956da42dede32cada0bfbaa1f7939a115..2c08bacd066ca151010b6f3e369bdfb890455afd 100644 (file)
@@ -114,27 +114,64 @@ static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
        iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
 }
 
-static int ftgmac100_reset_hw(struct ftgmac100 *priv)
+static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
 {
        struct net_device *netdev = priv->netdev;
        int i;
 
        /* NOTE: reset clears all registers */
-       iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR);
-       for (i = 0; i < 5; i++) {
+       iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
+       iowrite32(maccr | FTGMAC100_MACCR_SW_RST,
+                 priv->base + FTGMAC100_OFFSET_MACCR);
+       for (i = 0; i < 50; i++) {
                unsigned int maccr;
 
                maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
                if (!(maccr & FTGMAC100_MACCR_SW_RST))
                        return 0;
 
-               udelay(1000);
+               udelay(1);
        }
 
-       netdev_err(netdev, "software reset failed\n");
+       netdev_err(netdev, "Hardware reset failed\n");
        return -EIO;
 }
 
+static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv)
+{
+       u32 maccr = 0;
+
+       switch (priv->cur_speed) {
+       case SPEED_10:
+       case 0: /* no link */
+               break;
+
+       case SPEED_100:
+               maccr |= FTGMAC100_MACCR_FAST_MODE;
+               break;
+
+       case SPEED_1000:
+               maccr |= FTGMAC100_MACCR_GIGA_MODE;
+               break;
+       default:
+               netdev_err(priv->netdev, "Unknown speed %d !\n",
+                          priv->cur_speed);
+               break;
+       }
+
+       /* (Re)initialize the queue pointers */
+       priv->rx_pointer = 0;
+       priv->tx_clean_pointer = 0;
+       priv->tx_pointer = 0;
+       priv->tx_pending = 0;
+
+       /* The doc says reset twice with 10us interval */
+       if (ftgmac100_reset_mac(priv, maccr))
+               return -EIO;
+       usleep_range(10, 1000);
+       return ftgmac100_reset_mac(priv, maccr);
+}
+
 static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
 {
        unsigned int maddr = mac[0] << 8 | mac[1];
@@ -210,35 +247,28 @@ static void ftgmac100_init_hw(struct ftgmac100 *priv)
        ftgmac100_set_mac(priv, priv->netdev->dev_addr);
 }
 
-#define MACCR_ENABLE_ALL       (FTGMAC100_MACCR_TXDMA_EN       | \
-                                FTGMAC100_MACCR_RXDMA_EN       | \
-                                FTGMAC100_MACCR_TXMAC_EN       | \
-                                FTGMAC100_MACCR_RXMAC_EN       | \
-                                FTGMAC100_MACCR_CRC_APD        | \
-                                FTGMAC100_MACCR_RX_RUNT        | \
-                                FTGMAC100_MACCR_RX_BROADPKT)
-
 static void ftgmac100_start_hw(struct ftgmac100 *priv)
 {
-       int maccr = MACCR_ENABLE_ALL;
+       u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
 
-       switch (priv->cur_speed) {
-       default:
-       case 10:
-               break;
+       /* Keep the original GMAC and FAST bits */
+       maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE);
 
-       case 100:
-               maccr |= FTGMAC100_MACCR_FAST_MODE;
-               break;
-
-       case 1000:
-               maccr |= FTGMAC100_MACCR_GIGA_MODE;
-               break;
-       }
+       /* Add all the main enable bits */
+       maccr |= FTGMAC100_MACCR_TXDMA_EN       |
+                FTGMAC100_MACCR_RXDMA_EN       |
+                FTGMAC100_MACCR_TXMAC_EN       |
+                FTGMAC100_MACCR_RXMAC_EN       |
+                FTGMAC100_MACCR_CRC_APD        |
+                FTGMAC100_MACCR_PHY_LINK_LEVEL |
+                FTGMAC100_MACCR_RX_RUNT        |
+                FTGMAC100_MACCR_RX_BROADPKT;
 
+       /* Add other bits as needed */
        if (priv->cur_duplex == DUPLEX_FULL)
                maccr |= FTGMAC100_MACCR_FULLDUP;
 
+       /* Hit the HW */
        iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
 }
 
@@ -1156,7 +1186,7 @@ static void ftgmac100_reset_task(struct work_struct *work)
 
        /* Stop and reset the MAC */
        ftgmac100_stop_hw(priv);
-       err = ftgmac100_reset_hw(priv);
+       err = ftgmac100_reset_and_config_mac(priv);
        if (err) {
                /* Not much we can do ... it might come back... */
                netdev_err(netdev, "attempting to continue...\n");
@@ -1165,12 +1195,6 @@ static void ftgmac100_reset_task(struct work_struct *work)
        /* Free all rx and tx buffers */
        ftgmac100_free_buffers(priv);
 
-       /* The ring pointers have been reset in HW, reflect this here */
-       priv->rx_pointer = 0;
-       priv->tx_clean_pointer = 0;
-       priv->tx_pointer = 0;
-       priv->tx_pending = 0;
-
        /* Setup everything again and restart chip */
        ftgmac100_init_all(priv, true);
 
@@ -1209,12 +1233,8 @@ static int ftgmac100_open(struct net_device *netdev)
                priv->cur_speed = 0;
        }
 
-       priv->rx_pointer = 0;
-       priv->tx_clean_pointer = 0;
-       priv->tx_pointer = 0;
-       priv->tx_pending = 0;
-
-       err = ftgmac100_reset_hw(priv);
+       /* Reset the hardware */
+       err = ftgmac100_reset_and_config_mac(priv);
        if (err)
                goto err_hw;