aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2013-03-21 23:39:28 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-22 10:25:15 -0400
commitc3a07134e6aa5b93a37f72ffa3d11fadf72bf757 (patch)
treee61bf96df027d188c5b07722911121ec1186e701 /drivers/net/ethernet
parent2ec985213864cb64c45dc0284d7316142eefb5d4 (diff)
mv643xx_eth: convert to use the Marvell Orion MDIO driver
This patch converts the Marvell MV643XX ethernet driver to use the Marvell Orion MDIO driver. As a result, PowerPC and ARM platforms registering the Marvell MV643XX ethernet driver are also updated to register a Marvell Orion MDIO driver. This driver voluntarily overlaps with the Marvell Ethernet shared registers because it will use a subset of this shared register (shared_base + 0x4 to shared_base + 0x84). The Ethernet driver is also updated to look up for a PHY device using the Orion MDIO bus driver. For ARM and PowerPC we register a single instance of the "mvmdio" driver in the system like it used to be done with the use of the "shared_smi" platform_data cookie on ARM. Note that it is safe to register the mvmdio driver only for the "ge00" instance of the driver because this "ge00" interface is guaranteed to always be explicitely registered by consumers of arch/arm/plat-orion/common.c and other instances (ge01, ge10 and ge11) were all pointing their shared_smi to ge00. For PowerPC the in-tree Device Tree Source files mention only one MV643XX ethernet MAC instance so the MDIO bus driver is registered only when id == 0. Signed-off-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/marvell/Kconfig5
-rw-r--r--drivers/net/ethernet/marvell/Makefile2
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c195
3 files changed, 19 insertions, 183 deletions
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index edfba9370922..5170ecb00acc 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -23,6 +23,7 @@ config MV643XX_ETH
23 depends on (MV64X60 || PPC32 || PLAT_ORION) && INET 23 depends on (MV64X60 || PPC32 || PLAT_ORION) && INET
24 select INET_LRO 24 select INET_LRO
25 select PHYLIB 25 select PHYLIB
26 select MVMDIO
26 ---help--- 27 ---help---
27 This driver supports the gigabit ethernet MACs in the 28 This driver supports the gigabit ethernet MACs in the
28 Marvell Discovery PPC/MIPS chipset family (MV643XX) and 29 Marvell Discovery PPC/MIPS chipset family (MV643XX) and
@@ -38,9 +39,7 @@ config MVMDIO
38 interface units of the Marvell EBU SoCs (Kirkwood, Orion5x, 39 interface units of the Marvell EBU SoCs (Kirkwood, Orion5x,
39 Dove, Armada 370 and Armada XP). 40 Dove, Armada 370 and Armada XP).
40 41
41 For now, this driver is only needed for the MVNETA driver 42 This driver is used by the MV643XX_ETH and MVNETA drivers.
42 (used on Armada 370 and XP), but it could be used in the
43 future by the MV643XX_ETH driver.
44 43
45config MVNETA 44config MVNETA
46 tristate "Marvell Armada 370/XP network interface support" 45 tristate "Marvell Armada 370/XP network interface support"
diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile
index 7f63b4aac434..5c4a7765ff0e 100644
--- a/drivers/net/ethernet/marvell/Makefile
+++ b/drivers/net/ethernet/marvell/Makefile
@@ -2,8 +2,8 @@
2# Makefile for the Marvell device drivers. 2# Makefile for the Marvell device drivers.
3# 3#
4 4
5obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
6obj-$(CONFIG_MVMDIO) += mvmdio.o 5obj-$(CONFIG_MVMDIO) += mvmdio.o
6obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
7obj-$(CONFIG_MVNETA) += mvneta.o 7obj-$(CONFIG_MVNETA) += mvneta.o
8obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o 8obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
9obj-$(CONFIG_SKGE) += skge.o 9obj-$(CONFIG_SKGE) += skge.o
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index d1ecf4bf7da7..a65a92ef19ec 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -69,14 +69,6 @@ static char mv643xx_eth_driver_version[] = "1.4";
69 * Registers shared between all ports. 69 * Registers shared between all ports.
70 */ 70 */
71#define PHY_ADDR 0x0000 71#define PHY_ADDR 0x0000
72#define SMI_REG 0x0004
73#define SMI_BUSY 0x10000000
74#define SMI_READ_VALID 0x08000000
75#define SMI_OPCODE_READ 0x04000000
76#define SMI_OPCODE_WRITE 0x00000000
77#define ERR_INT_CAUSE 0x0080
78#define ERR_INT_SMI_DONE 0x00000010
79#define ERR_INT_MASK 0x0084
80#define WINDOW_BASE(w) (0x0200 + ((w) << 3)) 72#define WINDOW_BASE(w) (0x0200 + ((w) << 3))
81#define WINDOW_SIZE(w) (0x0204 + ((w) << 3)) 73#define WINDOW_SIZE(w) (0x0204 + ((w) << 3))
82#define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2)) 74#define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2))
@@ -266,25 +258,6 @@ struct mv643xx_eth_shared_private {
266 void __iomem *base; 258 void __iomem *base;
267 259
268 /* 260 /*
269 * Points at the right SMI instance to use.
270 */
271 struct mv643xx_eth_shared_private *smi;
272
273 /*
274 * Provides access to local SMI interface.
275 */
276 struct mii_bus *smi_bus;
277
278 /*
279 * If we have access to the error interrupt pin (which is
280 * somewhat misnamed as it not only reflects internal errors
281 * but also reflects SMI completion), use that to wait for
282 * SMI access completion instead of polling the SMI busy bit.
283 */
284 int err_interrupt;
285 wait_queue_head_t smi_busy_wait;
286
287 /*
288 * Per-port MBUS window access register value. 261 * Per-port MBUS window access register value.
289 */ 262 */
290 u32 win_protect; 263 u32 win_protect;
@@ -1122,97 +1095,6 @@ out_write:
1122 wrlp(mp, PORT_SERIAL_CONTROL, pscr); 1095 wrlp(mp, PORT_SERIAL_CONTROL, pscr);
1123} 1096}
1124 1097
1125static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id)
1126{
1127 struct mv643xx_eth_shared_private *msp = dev_id;
1128
1129 if (readl(msp->base + ERR_INT_CAUSE) & ERR_INT_SMI_DONE) {
1130 writel(~ERR_INT_SMI_DONE, msp->base + ERR_INT_CAUSE);
1131 wake_up(&msp->smi_busy_wait);
1132 return IRQ_HANDLED;
1133 }
1134
1135 return IRQ_NONE;
1136}
1137
1138static int smi_is_done(struct mv643xx_eth_shared_private *msp)
1139{
1140 return !(readl(msp->base + SMI_REG) & SMI_BUSY);
1141}
1142
1143static int smi_wait_ready(struct mv643xx_eth_shared_private *msp)
1144{
1145 if (msp->err_interrupt == NO_IRQ) {
1146 int i;
1147
1148 for (i = 0; !smi_is_done(msp); i++) {
1149 if (i == 10)
1150 return -ETIMEDOUT;
1151 msleep(10);
1152 }
1153
1154 return 0;
1155 }
1156
1157 if (!smi_is_done(msp)) {
1158 wait_event_timeout(msp->smi_busy_wait, smi_is_done(msp),
1159 msecs_to_jiffies(100));
1160 if (!smi_is_done(msp))
1161 return -ETIMEDOUT;
1162 }
1163
1164 return 0;
1165}
1166
1167static int smi_bus_read(struct mii_bus *bus, int addr, int reg)
1168{
1169 struct mv643xx_eth_shared_private *msp = bus->priv;
1170 void __iomem *smi_reg = msp->base + SMI_REG;
1171 int ret;
1172
1173 if (smi_wait_ready(msp)) {
1174 pr_warn("SMI bus busy timeout\n");
1175 return -ETIMEDOUT;
1176 }
1177
1178 writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg);
1179
1180 if (smi_wait_ready(msp)) {
1181 pr_warn("SMI bus busy timeout\n");
1182 return -ETIMEDOUT;
1183 }
1184
1185 ret = readl(smi_reg);
1186 if (!(ret & SMI_READ_VALID)) {
1187 pr_warn("SMI bus read not valid\n");
1188 return -ENODEV;
1189 }
1190
1191 return ret & 0xffff;
1192}
1193
1194static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val)
1195{
1196 struct mv643xx_eth_shared_private *msp = bus->priv;
1197 void __iomem *smi_reg = msp->base + SMI_REG;
1198
1199 if (smi_wait_ready(msp)) {
1200 pr_warn("SMI bus busy timeout\n");
1201 return -ETIMEDOUT;
1202 }
1203
1204 writel(SMI_OPCODE_WRITE | (reg << 21) |
1205 (addr << 16) | (val & 0xffff), smi_reg);
1206
1207 if (smi_wait_ready(msp)) {
1208 pr_warn("SMI bus busy timeout\n");
1209 return -ETIMEDOUT;
1210 }
1211
1212 return 0;
1213}
1214
1215
1216/* statistics ***************************************************************/ 1098/* statistics ***************************************************************/
1217static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) 1099static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
1218{ 1100{
@@ -2688,47 +2570,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
2688 goto out_free; 2570 goto out_free;
2689 2571
2690 /* 2572 /*
2691 * Set up and register SMI bus.
2692 */
2693 if (pd == NULL || pd->shared_smi == NULL) {
2694 msp->smi_bus = mdiobus_alloc();
2695 if (msp->smi_bus == NULL)
2696 goto out_unmap;
2697
2698 msp->smi_bus->priv = msp;
2699 msp->smi_bus->name = "mv643xx_eth smi";
2700 msp->smi_bus->read = smi_bus_read;
2701 msp->smi_bus->write = smi_bus_write,
2702 snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d",
2703 pdev->name, pdev->id);
2704 msp->smi_bus->parent = &pdev->dev;
2705 msp->smi_bus->phy_mask = 0xffffffff;
2706 if (mdiobus_register(msp->smi_bus) < 0)
2707 goto out_free_mii_bus;
2708 msp->smi = msp;
2709 } else {
2710 msp->smi = platform_get_drvdata(pd->shared_smi);
2711 }
2712
2713 msp->err_interrupt = NO_IRQ;
2714 init_waitqueue_head(&msp->smi_busy_wait);
2715
2716 /*
2717 * Check whether the error interrupt is hooked up.
2718 */
2719 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
2720 if (res != NULL) {
2721 int err;
2722
2723 err = request_irq(res->start, mv643xx_eth_err_irq,
2724 IRQF_SHARED, "mv643xx_eth", msp);
2725 if (!err) {
2726 writel(ERR_INT_SMI_DONE, msp->base + ERR_INT_MASK);
2727 msp->err_interrupt = res->start;
2728 }
2729 }
2730
2731 /*
2732 * (Re-)program MBUS remapping windows if we are asked to. 2573 * (Re-)program MBUS remapping windows if we are asked to.
2733 */ 2574 */
2734 dram = mv_mbus_dram_info(); 2575 dram = mv_mbus_dram_info();
@@ -2743,10 +2584,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
2743 2584
2744 return 0; 2585 return 0;
2745 2586
2746out_free_mii_bus:
2747 mdiobus_free(msp->smi_bus);
2748out_unmap:
2749 iounmap(msp->base);
2750out_free: 2587out_free:
2751 kfree(msp); 2588 kfree(msp);
2752out: 2589out:
@@ -2756,14 +2593,7 @@ out:
2756static int mv643xx_eth_shared_remove(struct platform_device *pdev) 2593static int mv643xx_eth_shared_remove(struct platform_device *pdev)
2757{ 2594{
2758 struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); 2595 struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);
2759 struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
2760 2596
2761 if (pd == NULL || pd->shared_smi == NULL) {
2762 mdiobus_unregister(msp->smi_bus);
2763 mdiobus_free(msp->smi_bus);
2764 }
2765 if (msp->err_interrupt != NO_IRQ)
2766 free_irq(msp->err_interrupt, msp);
2767 iounmap(msp->base); 2597 iounmap(msp->base);
2768 kfree(msp); 2598 kfree(msp);
2769 2599
@@ -2826,14 +2656,21 @@ static void set_params(struct mv643xx_eth_private *mp,
2826 mp->txq_count = pd->tx_queue_count ? : 1; 2656 mp->txq_count = pd->tx_queue_count ? : 1;
2827} 2657}
2828 2658
2659static void mv643xx_eth_adjust_link(struct net_device *dev)
2660{
2661 struct mv643xx_eth_private *mp = netdev_priv(dev);
2662
2663 mv643xx_adjust_pscr(mp);
2664}
2665
2829static struct phy_device *phy_scan(struct mv643xx_eth_private *mp, 2666static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
2830 int phy_addr) 2667 int phy_addr)
2831{ 2668{
2832 struct mii_bus *bus = mp->shared->smi->smi_bus;
2833 struct phy_device *phydev; 2669 struct phy_device *phydev;
2834 int start; 2670 int start;
2835 int num; 2671 int num;
2836 int i; 2672 int i;
2673 char phy_id[MII_BUS_ID_SIZE + 3];
2837 2674
2838 if (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) { 2675 if (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) {
2839 start = phy_addr_get(mp) & 0x1f; 2676 start = phy_addr_get(mp) & 0x1f;
@@ -2843,17 +2680,19 @@ static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
2843 num = 1; 2680 num = 1;
2844 } 2681 }
2845 2682
2683 /* Attempt to connect to the PHY using orion-mdio */
2846 phydev = NULL; 2684 phydev = NULL;
2847 for (i = 0; i < num; i++) { 2685 for (i = 0; i < num; i++) {
2848 int addr = (start + i) & 0x1f; 2686 int addr = (start + i) & 0x1f;
2849 2687
2850 if (bus->phy_map[addr] == NULL) 2688 snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
2851 mdiobus_scan(bus, addr); 2689 "orion-mdio-mii", addr);
2852 2690
2853 if (phydev == NULL) { 2691 phydev = phy_connect(mp->dev, phy_id, mv643xx_eth_adjust_link,
2854 phydev = bus->phy_map[addr]; 2692 PHY_INTERFACE_MODE_GMII);
2855 if (phydev != NULL) 2693 if (!IS_ERR(phydev)) {
2856 phy_addr_set(mp, addr); 2694 phy_addr_set(mp, addr);
2695 break;
2857 } 2696 }
2858 } 2697 }
2859 2698
@@ -2866,8 +2705,6 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)
2866 2705
2867 phy_reset(mp); 2706 phy_reset(mp);
2868 2707
2869 phy_attach(mp->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_GMII);
2870
2871 if (speed == 0) { 2708 if (speed == 0) {
2872 phy->autoneg = AUTONEG_ENABLE; 2709 phy->autoneg = AUTONEG_ENABLE;
2873 phy->speed = 0; 2710 phy->speed = 0;