Merge branch 'wireless-next-2.6' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / net / sh_eth.c
index 6734311..e9e7a53 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)
@@ -382,6 +512,7 @@ static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
 }
 
 struct bb_info {
+       void (*set_gate)(unsigned long addr);
        struct mdiobb_ctrl ctrl;
        u32 addr;
        u32 mmd_msk;/* MMD */
@@ -412,6 +543,10 @@ static int bb_read(u32 addr, u32 msk)
 static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
 {
        struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
+       if (bitbang->set_gate)
+               bitbang->set_gate(bitbang->addr);
+
        if (bit)
                bb_set(bitbang->addr, bitbang->mmd_msk);
        else
@@ -423,6 +558,9 @@ static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
 {
        struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 
+       if (bitbang->set_gate)
+               bitbang->set_gate(bitbang->addr);
+
        if (bit)
                bb_set(bitbang->addr, bitbang->mdo_msk);
        else
@@ -433,6 +571,10 @@ static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
 static int sh_get_mdio(struct mdiobb_ctrl *ctrl)
 {
        struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
+       if (bitbang->set_gate)
+               bitbang->set_gate(bitbang->addr);
+
        return bb_read(bitbang->addr, bitbang->mdi_msk);
 }
 
@@ -441,6 +583,9 @@ static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
 {
        struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 
+       if (bitbang->set_gate)
+               bitbang->set_gate(bitbang->addr);
+
        if (bit)
                bb_set(bitbang->addr, bitbang->mdc_msk);
        else
@@ -1071,7 +1216,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
 
        /* Try connect to PHY */
        phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
-                               0, PHY_INTERFACE_MODE_MII);
+                               0, mdp->phy_interface);
        if (IS_ERR(phydev)) {
                dev_err(&ndev->dev, "phy_connect failed\n");
                return PTR_ERR(phydev);
@@ -1516,7 +1661,8 @@ static int sh_mdio_release(struct net_device *ndev)
 }
 
 /* MDIO bus init function */
-static int sh_mdio_init(struct net_device *ndev, int id)
+static int sh_mdio_init(struct net_device *ndev, int id,
+                       struct sh_eth_plat_data *pd)
 {
        int ret, i;
        struct bb_info *bitbang;
@@ -1531,6 +1677,7 @@ static int sh_mdio_init(struct net_device *ndev, int id)
 
        /* bitbang init */
        bitbang->addr = ndev->base_addr + mdp->reg_offset[PIR];
+       bitbang->set_gate = pd->set_mdio_gate;
        bitbang->mdi_msk = 0x08;
        bitbang->mdo_msk = 0x04;
        bitbang->mmd_msk = 0x02;/* MMD */
@@ -1669,6 +1816,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data);
        /* get PHY ID */
        mdp->phy_id = pd->phy;
+       mdp->phy_interface = pd->phy_interface;
        /* EDMAC endian */
        mdp->edmac_endian = pd->edmac_endian;
        mdp->no_ether_link = pd->no_ether_link;
@@ -1676,7 +1824,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 */
@@ -1719,7 +1871,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
                goto out_release;
 
        /* mdio bus init */
-       ret = sh_mdio_init(ndev, pdev->id);
+       ret = sh_mdio_init(ndev, pdev->id, pd);
        if (ret)
                goto out_unregister;