Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Florian Fainelli and committed by
David S. Miller
c3a07134 2ec98521

+84 -209
+31 -23
arch/arm/plat-orion/common.c
··· 238 238 struct mv643xx_eth_shared_platform_data *orion_ge_shared_data, 239 239 struct resource *orion_ge_resource, unsigned long irq, 240 240 struct platform_device *orion_ge_shared, 241 + struct platform_device *orion_ge_mvmdio, 241 242 struct mv643xx_eth_platform_data *eth_data, 242 243 struct platform_device *orion_ge) 243 244 { ··· 248 247 orion_ge->dev.platform_data = eth_data; 249 248 250 249 platform_device_register(orion_ge_shared); 250 + if (orion_ge_mvmdio) 251 + platform_device_register(orion_ge_mvmdio); 251 252 platform_device_register(orion_ge); 252 253 } 253 254 ··· 261 258 static struct resource orion_ge00_shared_resources[] = { 262 259 { 263 260 .name = "ge00 base", 264 - }, { 265 - .name = "ge00 err irq", 266 261 }, 267 262 }; 268 263 ··· 270 269 .dev = { 271 270 .platform_data = &orion_ge00_shared_data, 272 271 }, 272 + }; 273 + 274 + static struct resource orion_ge_mvmdio_resources[] = { 275 + { 276 + .name = "ge00 mvmdio base", 277 + }, { 278 + .name = "ge00 mvmdio err irq", 279 + }, 280 + }; 281 + 282 + static struct platform_device orion_ge_mvmdio = { 283 + .name = "orion-mdio", 284 + .id = -1, 273 285 }; 274 286 275 287 static struct resource orion_ge00_resources[] = { ··· 309 295 unsigned int tx_csum_limit) 310 296 { 311 297 fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, 312 - mapbase + 0x2000, SZ_16K - 1, irq_err); 298 + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); 299 + fill_resources(&orion_ge_mvmdio, orion_ge_mvmdio_resources, 300 + mapbase + 0x2004, 0x84 - 1, irq_err); 313 301 orion_ge00_shared_data.tx_csum_limit = tx_csum_limit; 314 302 ge_complete(&orion_ge00_shared_data, 315 303 orion_ge00_resources, irq, &orion_ge00_shared, 304 + &orion_ge_mvmdio, 316 305 eth_data, &orion_ge00); 317 306 } 318 307 319 308 /***************************************************************************** 320 309 * GE01 321 310 ****************************************************************************/ 322 - struct mv643xx_eth_shared_platform_data orion_ge01_shared_data = { 323 - .shared_smi = &orion_ge00_shared, 324 - }; 311 + struct mv643xx_eth_shared_platform_data orion_ge01_shared_data; 325 312 326 313 static struct resource orion_ge01_shared_resources[] = { 327 314 { 328 315 .name = "ge01 base", 329 - }, { 330 - .name = "ge01 err irq", 331 - }, 316 + } 332 317 }; 333 318 334 319 static struct platform_device orion_ge01_shared = { ··· 362 349 unsigned int tx_csum_limit) 363 350 { 364 351 fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, 365 - mapbase + 0x2000, SZ_16K - 1, irq_err); 352 + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); 366 353 orion_ge01_shared_data.tx_csum_limit = tx_csum_limit; 367 354 ge_complete(&orion_ge01_shared_data, 368 355 orion_ge01_resources, irq, &orion_ge01_shared, 356 + NULL, 369 357 eth_data, &orion_ge01); 370 358 } 371 359 372 360 /***************************************************************************** 373 361 * GE10 374 362 ****************************************************************************/ 375 - struct mv643xx_eth_shared_platform_data orion_ge10_shared_data = { 376 - .shared_smi = &orion_ge00_shared, 377 - }; 363 + struct mv643xx_eth_shared_platform_data orion_ge10_shared_data; 378 364 379 365 static struct resource orion_ge10_shared_resources[] = { 380 366 { 381 367 .name = "ge10 base", 382 - }, { 383 - .name = "ge10 err irq", 384 - }, 368 + } 385 369 }; 386 370 387 371 static struct platform_device orion_ge10_shared = { ··· 412 402 unsigned long irq_err) 413 403 { 414 404 fill_resources(&orion_ge10_shared, orion_ge10_shared_resources, 415 - mapbase + 0x2000, SZ_16K - 1, irq_err); 405 + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); 416 406 ge_complete(&orion_ge10_shared_data, 417 407 orion_ge10_resources, irq, &orion_ge10_shared, 408 + NULL, 418 409 eth_data, &orion_ge10); 419 410 } 420 411 421 412 /***************************************************************************** 422 413 * GE11 423 414 ****************************************************************************/ 424 - struct mv643xx_eth_shared_platform_data orion_ge11_shared_data = { 425 - .shared_smi = &orion_ge00_shared, 426 - }; 415 + struct mv643xx_eth_shared_platform_data orion_ge11_shared_data; 427 416 428 417 static struct resource orion_ge11_shared_resources[] = { 429 418 { 430 419 .name = "ge11 base", 431 - }, { 432 - .name = "ge11 err irq", 433 420 }, 434 421 }; 435 422 ··· 461 454 unsigned long irq_err) 462 455 { 463 456 fill_resources(&orion_ge11_shared, orion_ge11_shared_resources, 464 - mapbase + 0x2000, SZ_16K - 1, irq_err); 457 + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); 465 458 ge_complete(&orion_ge11_shared_data, 466 459 orion_ge11_resources, irq, &orion_ge11_shared, 460 + NULL, 467 461 eth_data, &orion_ge11); 468 462 } 469 463
+20
arch/powerpc/platforms/chrp/pegasos_eth.c
··· 47 47 .resource = mv643xx_eth_shared_resources, 48 48 }; 49 49 50 + /* 51 + * The orion mdio driver only covers shared + 0x4 up to shared + 0x84 - 1 52 + */ 53 + static struct resource mv643xx_eth_mvmdio_resources[] = { 54 + [0] = { 55 + .name = "ethernet mdio base", 56 + .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS + 0x4, 57 + .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + 0x83, 58 + .flags = IORESOURCE_MEM, 59 + }, 60 + }; 61 + 62 + static struct platform_device mv643xx_eth_mvmdio_device = { 63 + .name = "orion-mdio", 64 + .id = -1, 65 + .num_resources = ARRAY_SIZE(mv643xx_eth_mvmdio_resources), 66 + .resource = mv643xx_eth_shared_resources, 67 + }; 68 + 50 69 static struct resource mv643xx_eth_port1_resources[] = { 51 70 [0] = { 52 71 .name = "eth port1 irq", ··· 101 82 102 83 static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { 103 84 &mv643xx_eth_shared_device, 85 + &mv643xx_eth_mvmdio_device, 104 86 &eth_port1_device, 105 87 }; 106 88
+14 -2
arch/powerpc/sysdev/mv64x60_dev.c
··· 214 214 struct device_node *np, int id) 215 215 { 216 216 struct platform_device *pdev; 217 - struct resource r[1]; 217 + struct resource r[2]; 218 218 int err; 219 219 220 220 err = of_address_to_resource(np, 0, &r[0]); 221 221 if (err) 222 222 return ERR_PTR(err); 223 223 224 + /* register an orion mdio bus driver */ 225 + r[1].start = r[0].start + 0x4; 226 + r[1].end = r[0].start + 0x84 - 1; 227 + r[1].flags = IORESOURCE_MEM; 228 + 229 + if (id == 0) { 230 + pdev = platform_device_register_simple("orion-mdio", -1, &r[1], 1); 231 + if (!pdev) 232 + return pdev; 233 + } 234 + 224 235 pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, id, 225 - r, 1); 236 + &r[0], 1); 237 + 226 238 return pdev; 227 239 } 228 240
+2 -3
drivers/net/ethernet/marvell/Kconfig
··· 23 23 depends on (MV64X60 || PPC32 || PLAT_ORION) && INET 24 24 select INET_LRO 25 25 select PHYLIB 26 + select MVMDIO 26 27 ---help--- 27 28 This driver supports the gigabit ethernet MACs in the 28 29 Marvell Discovery PPC/MIPS chipset family (MV643XX) and ··· 39 38 interface units of the Marvell EBU SoCs (Kirkwood, Orion5x, 40 39 Dove, Armada 370 and Armada XP). 41 40 42 - For now, this driver is only needed for the MVNETA driver 43 - (used on Armada 370 and XP), but it could be used in the 44 - future by the MV643XX_ETH driver. 41 + This driver is used by the MV643XX_ETH and MVNETA drivers. 45 42 46 43 config MVNETA 47 44 tristate "Marvell Armada 370/XP network interface support"
+1 -1
drivers/net/ethernet/marvell/Makefile
··· 2 2 # Makefile for the Marvell device drivers. 3 3 # 4 4 5 - obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o 6 5 obj-$(CONFIG_MVMDIO) += mvmdio.o 6 + obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o 7 7 obj-$(CONFIG_MVNETA) += mvneta.o 8 8 obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o 9 9 obj-$(CONFIG_SKGE) += skge.o
+16 -179
drivers/net/ethernet/marvell/mv643xx_eth.c
··· 69 69 * Registers shared between all ports. 70 70 */ 71 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 72 #define WINDOW_BASE(w) (0x0200 + ((w) << 3)) 81 73 #define WINDOW_SIZE(w) (0x0204 + ((w) << 3)) 82 74 #define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2)) ··· 256 264 * Ethernet controller base address. 257 265 */ 258 266 void __iomem *base; 259 - 260 - /* 261 - * Points at the right SMI instance to use. 262 - */ 263 - struct mv643xx_eth_shared_private *smi; 264 - 265 - /* 266 - * Provides access to local SMI interface. 267 - */ 268 - struct mii_bus *smi_bus; 269 - 270 - /* 271 - * If we have access to the error interrupt pin (which is 272 - * somewhat misnamed as it not only reflects internal errors 273 - * but also reflects SMI completion), use that to wait for 274 - * SMI access completion instead of polling the SMI busy bit. 275 - */ 276 - int err_interrupt; 277 - wait_queue_head_t smi_busy_wait; 278 267 279 268 /* 280 269 * Per-port MBUS window access register value. ··· 1094 1121 out_write: 1095 1122 wrlp(mp, PORT_SERIAL_CONTROL, pscr); 1096 1123 } 1097 - 1098 - static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id) 1099 - { 1100 - struct mv643xx_eth_shared_private *msp = dev_id; 1101 - 1102 - if (readl(msp->base + ERR_INT_CAUSE) & ERR_INT_SMI_DONE) { 1103 - writel(~ERR_INT_SMI_DONE, msp->base + ERR_INT_CAUSE); 1104 - wake_up(&msp->smi_busy_wait); 1105 - return IRQ_HANDLED; 1106 - } 1107 - 1108 - return IRQ_NONE; 1109 - } 1110 - 1111 - static int smi_is_done(struct mv643xx_eth_shared_private *msp) 1112 - { 1113 - return !(readl(msp->base + SMI_REG) & SMI_BUSY); 1114 - } 1115 - 1116 - static int smi_wait_ready(struct mv643xx_eth_shared_private *msp) 1117 - { 1118 - if (msp->err_interrupt == NO_IRQ) { 1119 - int i; 1120 - 1121 - for (i = 0; !smi_is_done(msp); i++) { 1122 - if (i == 10) 1123 - return -ETIMEDOUT; 1124 - msleep(10); 1125 - } 1126 - 1127 - return 0; 1128 - } 1129 - 1130 - if (!smi_is_done(msp)) { 1131 - wait_event_timeout(msp->smi_busy_wait, smi_is_done(msp), 1132 - msecs_to_jiffies(100)); 1133 - if (!smi_is_done(msp)) 1134 - return -ETIMEDOUT; 1135 - } 1136 - 1137 - return 0; 1138 - } 1139 - 1140 - static int smi_bus_read(struct mii_bus *bus, int addr, int reg) 1141 - { 1142 - struct mv643xx_eth_shared_private *msp = bus->priv; 1143 - void __iomem *smi_reg = msp->base + SMI_REG; 1144 - int ret; 1145 - 1146 - if (smi_wait_ready(msp)) { 1147 - pr_warn("SMI bus busy timeout\n"); 1148 - return -ETIMEDOUT; 1149 - } 1150 - 1151 - writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); 1152 - 1153 - if (smi_wait_ready(msp)) { 1154 - pr_warn("SMI bus busy timeout\n"); 1155 - return -ETIMEDOUT; 1156 - } 1157 - 1158 - ret = readl(smi_reg); 1159 - if (!(ret & SMI_READ_VALID)) { 1160 - pr_warn("SMI bus read not valid\n"); 1161 - return -ENODEV; 1162 - } 1163 - 1164 - return ret & 0xffff; 1165 - } 1166 - 1167 - static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val) 1168 - { 1169 - struct mv643xx_eth_shared_private *msp = bus->priv; 1170 - void __iomem *smi_reg = msp->base + SMI_REG; 1171 - 1172 - if (smi_wait_ready(msp)) { 1173 - pr_warn("SMI bus busy timeout\n"); 1174 - return -ETIMEDOUT; 1175 - } 1176 - 1177 - writel(SMI_OPCODE_WRITE | (reg << 21) | 1178 - (addr << 16) | (val & 0xffff), smi_reg); 1179 - 1180 - if (smi_wait_ready(msp)) { 1181 - pr_warn("SMI bus busy timeout\n"); 1182 - return -ETIMEDOUT; 1183 - } 1184 - 1185 - return 0; 1186 - } 1187 - 1188 1124 1189 1125 /* statistics ***************************************************************/ 1190 1126 static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) ··· 2570 2688 goto out_free; 2571 2689 2572 2690 /* 2573 - * Set up and register SMI bus. 2574 - */ 2575 - if (pd == NULL || pd->shared_smi == NULL) { 2576 - msp->smi_bus = mdiobus_alloc(); 2577 - if (msp->smi_bus == NULL) 2578 - goto out_unmap; 2579 - 2580 - msp->smi_bus->priv = msp; 2581 - msp->smi_bus->name = "mv643xx_eth smi"; 2582 - msp->smi_bus->read = smi_bus_read; 2583 - msp->smi_bus->write = smi_bus_write, 2584 - snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d", 2585 - pdev->name, pdev->id); 2586 - msp->smi_bus->parent = &pdev->dev; 2587 - msp->smi_bus->phy_mask = 0xffffffff; 2588 - if (mdiobus_register(msp->smi_bus) < 0) 2589 - goto out_free_mii_bus; 2590 - msp->smi = msp; 2591 - } else { 2592 - msp->smi = platform_get_drvdata(pd->shared_smi); 2593 - } 2594 - 2595 - msp->err_interrupt = NO_IRQ; 2596 - init_waitqueue_head(&msp->smi_busy_wait); 2597 - 2598 - /* 2599 - * Check whether the error interrupt is hooked up. 2600 - */ 2601 - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 2602 - if (res != NULL) { 2603 - int err; 2604 - 2605 - err = request_irq(res->start, mv643xx_eth_err_irq, 2606 - IRQF_SHARED, "mv643xx_eth", msp); 2607 - if (!err) { 2608 - writel(ERR_INT_SMI_DONE, msp->base + ERR_INT_MASK); 2609 - msp->err_interrupt = res->start; 2610 - } 2611 - } 2612 - 2613 - /* 2614 2691 * (Re-)program MBUS remapping windows if we are asked to. 2615 2692 */ 2616 2693 dram = mv_mbus_dram_info(); ··· 2584 2743 2585 2744 return 0; 2586 2745 2587 - out_free_mii_bus: 2588 - mdiobus_free(msp->smi_bus); 2589 - out_unmap: 2590 - iounmap(msp->base); 2591 2746 out_free: 2592 2747 kfree(msp); 2593 2748 out: ··· 2593 2756 static int mv643xx_eth_shared_remove(struct platform_device *pdev) 2594 2757 { 2595 2758 struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); 2596 - struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; 2597 2759 2598 - if (pd == NULL || pd->shared_smi == NULL) { 2599 - mdiobus_unregister(msp->smi_bus); 2600 - mdiobus_free(msp->smi_bus); 2601 - } 2602 - if (msp->err_interrupt != NO_IRQ) 2603 - free_irq(msp->err_interrupt, msp); 2604 2760 iounmap(msp->base); 2605 2761 kfree(msp); 2606 2762 ··· 2656 2826 mp->txq_count = pd->tx_queue_count ? : 1; 2657 2827 } 2658 2828 2829 + static void mv643xx_eth_adjust_link(struct net_device *dev) 2830 + { 2831 + struct mv643xx_eth_private *mp = netdev_priv(dev); 2832 + 2833 + mv643xx_adjust_pscr(mp); 2834 + } 2835 + 2659 2836 static struct phy_device *phy_scan(struct mv643xx_eth_private *mp, 2660 2837 int phy_addr) 2661 2838 { 2662 - struct mii_bus *bus = mp->shared->smi->smi_bus; 2663 2839 struct phy_device *phydev; 2664 2840 int start; 2665 2841 int num; 2666 2842 int i; 2843 + char phy_id[MII_BUS_ID_SIZE + 3]; 2667 2844 2668 2845 if (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) { 2669 2846 start = phy_addr_get(mp) & 0x1f; ··· 2680 2843 num = 1; 2681 2844 } 2682 2845 2846 + /* Attempt to connect to the PHY using orion-mdio */ 2683 2847 phydev = NULL; 2684 2848 for (i = 0; i < num; i++) { 2685 2849 int addr = (start + i) & 0x1f; 2686 2850 2687 - if (bus->phy_map[addr] == NULL) 2688 - mdiobus_scan(bus, addr); 2851 + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, 2852 + "orion-mdio-mii", addr); 2689 2853 2690 - if (phydev == NULL) { 2691 - phydev = bus->phy_map[addr]; 2692 - if (phydev != NULL) 2693 - phy_addr_set(mp, addr); 2854 + phydev = phy_connect(mp->dev, phy_id, mv643xx_eth_adjust_link, 2855 + PHY_INTERFACE_MODE_GMII); 2856 + if (!IS_ERR(phydev)) { 2857 + phy_addr_set(mp, addr); 2858 + break; 2694 2859 } 2695 2860 } 2696 2861 ··· 2704 2865 struct phy_device *phy = mp->phy; 2705 2866 2706 2867 phy_reset(mp); 2707 - 2708 - phy_attach(mp->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_GMII); 2709 2868 2710 2869 if (speed == 0) { 2711 2870 phy->autoneg = AUTONEG_ENABLE;
-1
include/linux/mv643xx_eth.h
··· 19 19 20 20 struct mv643xx_eth_shared_platform_data { 21 21 struct mbus_dram_target_info *dram; 22 - struct platform_device *shared_smi; 23 22 /* 24 23 * Max packet size for Tx IP/Layer 4 checksum, when set to 0, default 25 24 * limit of 9KiB will be used.