net: sh_eth: add support for SH7757's GETHER
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Mon, 7 Mar 2011 21:59:49 +0000 (21:59 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 14 Mar 2011 21:10:15 +0000 (14:10 -0700)
The SH7757 have GETHER and ETHER both. This patch supports them.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/sh_eth.c

index 5d28ce68f357a674c8791ef79cad86c8869b5cd2..dcf9f87d021fea201319e5bdc3a3c9b7c05eb43e 100644 (file)
@@ -94,7 +94,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .rpadir_value   = 0x00020000, /* NET_IP_ALIGN assumed to be 2 */
 };
 #elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-#define SH_ETH_RESET_DEFAULT   1
+#define SH_ETH_HAS_BOTH_MODULES        1
+#define SH_ETH_HAS_TSU 1
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
        struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -141,6 +142,135 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .no_ade         = 1,
 };
 
+#define SH_GIGA_ETH_BASE       0xfee00000
+#define GIGA_MALR(port)                (SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c8)
+#define GIGA_MAHR(port)                (SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c0)
+static void sh_eth_chip_reset_giga(struct net_device *ndev)
+{
+       int i;
+       unsigned long mahr[2], malr[2];
+
+       /* save MAHR and MALR */
+       for (i = 0; i < 2; i++) {
+               malr[i] = readl(GIGA_MALR(i));
+               mahr[i] = readl(GIGA_MAHR(i));
+       }
+
+       /* reset device */
+       writel(ARSTR_ARSTR, SH_GIGA_ETH_BASE + 0x1800);
+       mdelay(1);
+
+       /* restore MAHR and MALR */
+       for (i = 0; i < 2; i++) {
+               writel(malr[i], GIGA_MALR(i));
+               writel(mahr[i], GIGA_MAHR(i));
+       }
+}
+
+static int sh_eth_is_gether(struct sh_eth_private *mdp);
+static void sh_eth_reset(struct net_device *ndev)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+       int cnt = 100;
+
+       if (sh_eth_is_gether(mdp)) {
+               sh_eth_write(ndev, 0x03, EDSR);
+               sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
+                               EDMR);
+               while (cnt > 0) {
+                       if (!(sh_eth_read(ndev, EDMR) & 0x3))
+                               break;
+                       mdelay(1);
+                       cnt--;
+               }
+               if (cnt < 0)
+                       printk(KERN_ERR "Device reset fail\n");
+
+               /* Table Init */
+               sh_eth_write(ndev, 0x0, TDLAR);
+               sh_eth_write(ndev, 0x0, TDFAR);
+               sh_eth_write(ndev, 0x0, TDFXR);
+               sh_eth_write(ndev, 0x0, TDFFR);
+               sh_eth_write(ndev, 0x0, RDLAR);
+               sh_eth_write(ndev, 0x0, RDFAR);
+               sh_eth_write(ndev, 0x0, RDFXR);
+               sh_eth_write(ndev, 0x0, RDFFR);
+       } else {
+               sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER,
+                               EDMR);
+               mdelay(3);
+               sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER,
+                               EDMR);
+       }
+}
+
+static void sh_eth_set_duplex_giga(struct net_device *ndev)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+
+       if (mdp->duplex) /* Full */
+               sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
+       else            /* Half */
+               sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
+}
+
+static void sh_eth_set_rate_giga(struct net_device *ndev)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+
+       switch (mdp->speed) {
+       case 10: /* 10BASE */
+               sh_eth_write(ndev, 0x00000000, GECMR);
+               break;
+       case 100:/* 100BASE */
+               sh_eth_write(ndev, 0x00000010, GECMR);
+               break;
+       case 1000: /* 1000BASE */
+               sh_eth_write(ndev, 0x00000020, GECMR);
+               break;
+       default:
+               break;
+       }
+}
+
+/* SH7757(GETHERC) */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data_giga = {
+       .chip_reset     = sh_eth_chip_reset_giga,
+       .set_duplex     = sh_eth_set_duplex_giga,
+       .set_rate       = sh_eth_set_rate_giga,
+
+       .ecsr_value     = ECSR_ICD | ECSR_MPD,
+       .ecsipr_value   = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
+       .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+
+       .tx_check       = EESR_TC1 | EESR_FTC,
+       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
+                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
+                         EESR_ECI,
+       .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
+                         EESR_TFE,
+       .fdr_value      = 0x0000072f,
+       .rmcr_value     = 0x00000001,
+
+       .apr            = 1,
+       .mpr            = 1,
+       .tpauser        = 1,
+       .bculr          = 1,
+       .hw_swap        = 1,
+       .rpadir         = 1,
+       .rpadir_value   = 2 << 16,
+       .no_trimd       = 1,
+       .no_ade         = 1,
+};
+
+static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp)
+{
+       if (sh_eth_is_gether(mdp))
+               return &sh_eth_my_cpu_data_giga;
+       else
+               return &sh_eth_my_cpu_data;
+}
+
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
 #define SH_ETH_HAS_TSU 1
 static void sh_eth_chip_reset(struct net_device *ndev)
@@ -1677,7 +1807,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        mdp->reg_offset = sh_eth_get_register_offset(pd->register_type);
 
        /* set cpu data */
+#if defined(SH_ETH_HAS_BOTH_MODULES)
+       mdp->cd = sh_eth_get_cpu_data(mdp);
+#else
        mdp->cd = &sh_eth_my_cpu_data;
+#endif
        sh_eth_set_default_cpu_data(mdp->cd);
 
        /* set function */