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

net: mv643xx_eth: add DT parsing support

This adds device tree parsing support for the shared driver of mv643xx_eth.
As the bindings are slightly different from current PPC bindings new binding
documentation is also added. Following PPC-style device setup, the shared
driver now also adds port platform_devices and sets up port platform_data.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Sebastian Hesselbarth and committed by
David S. Miller
76723bca cb85215f

+234 -4
+85
Documentation/devicetree/bindings/net/marvell-orion-net.txt
··· 1 + Marvell Orion/Discovery ethernet controller 2 + ============================================= 3 + 4 + The Marvell Discovery ethernet controller can be found on Marvell Orion SoCs 5 + (Kirkwood, Dove, Orion5x, and Discovery Innovation) and as part of Marvell 6 + Discovery system controller chips (mv64[345]60). 7 + 8 + The Discovery ethernet controller is described with two levels of nodes. The 9 + first level describes the ethernet controller itself and the second level 10 + describes up to 3 ethernet port nodes within that controller. The reason for 11 + the multiple levels is that the port registers are interleaved within a single 12 + set of controller registers. Each port node describes port-specific properties. 13 + 14 + Note: The above separation is only true for Discovery system controllers. 15 + For Orion SoCs we stick to the separation, although there each controller has 16 + only one port associated. Multiple ports are implemented as multiple single-port 17 + controllers. As Kirkwood has some issues with proper initialization after reset, 18 + an extra compatible string is added for it. 19 + 20 + * Ethernet controller node 21 + 22 + Required controller properties: 23 + - #address-cells: shall be 1. 24 + - #size-cells: shall be 0. 25 + - compatible: shall be one of "marvell,orion-eth", "marvell,kirkwood-eth". 26 + - reg: address and length of the controller registers. 27 + 28 + Optional controller properties: 29 + - clocks: phandle reference to the controller clock. 30 + - marvell,tx-checksum-limit: max tx packet size for hardware checksum. 31 + 32 + * Ethernet port node 33 + 34 + Required port properties: 35 + - device_type: shall be "network". 36 + - compatible: shall be one of "marvell,orion-eth-port", 37 + "marvell,kirkwood-eth-port". 38 + - reg: port number relative to ethernet controller, shall be 0, 1, or 2. 39 + - interrupts: port interrupt. 40 + - local-mac-address: 6 bytes MAC address. 41 + 42 + Optional port properties: 43 + - marvell,tx-queue-size: size of the transmit ring buffer. 44 + - marvell,tx-sram-addr: address of transmit descriptor buffer located in SRAM. 45 + - marvell,tx-sram-size: size of transmit descriptor buffer located in SRAM. 46 + - marvell,rx-queue-size: size of the receive ring buffer. 47 + - marvell,rx-sram-addr: address of receive descriptor buffer located in SRAM. 48 + - marvell,rx-sram-size: size of receive descriptor buffer located in SRAM. 49 + 50 + and 51 + 52 + - phy-handle: phandle reference to ethernet PHY. 53 + 54 + or 55 + 56 + - speed: port speed if no PHY connected. 57 + - duplex: port mode if no PHY connected. 58 + 59 + * Node example: 60 + 61 + mdio-bus { 62 + ... 63 + ethphy: ethernet-phy@8 { 64 + device_type = "ethernet-phy"; 65 + ... 66 + }; 67 + }; 68 + 69 + eth: ethernet-controller@72000 { 70 + compatible = "marvell,orion-eth"; 71 + #address-cells = <1>; 72 + #size-cells = <0>; 73 + reg = <0x72000 0x2000>; 74 + clocks = <&gate_clk 2>; 75 + marvell,tx-checksum-limit = <1600>; 76 + 77 + ethernet@0 { 78 + device_type = "network"; 79 + compatible = "marvell,orion-eth-port"; 80 + reg = <0>; 81 + interrupts = <29>; 82 + phy-handle = <&ethphy>; 83 + local-mac-address = [00 00 00 00 00 00]; 84 + }; 85 + };
+149 -4
drivers/net/ethernet/marvell/mv643xx_eth.c
··· 60 60 #include <linux/types.h> 61 61 #include <linux/slab.h> 62 62 #include <linux/clk.h> 63 + #include <linux/of.h> 64 + #include <linux/of_irq.h> 65 + #include <linux/of_net.h> 63 66 #include <linux/of_mdio.h> 64 67 65 68 static char mv643xx_eth_driver_name[] = "mv643xx_eth"; ··· 2456 2453 } 2457 2454 } 2458 2455 2456 + #if defined(CONFIG_OF) 2457 + static const struct of_device_id mv643xx_eth_shared_ids[] = { 2458 + { .compatible = "marvell,orion-eth", }, 2459 + { .compatible = "marvell,kirkwood-eth", }, 2460 + { } 2461 + }; 2462 + MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids); 2463 + #endif 2464 + 2465 + #if defined(CONFIG_OF) && !defined(CONFIG_MV64X60) 2466 + #define mv643xx_eth_property(_np, _name, _v) \ 2467 + do { \ 2468 + u32 tmp; \ 2469 + if (!of_property_read_u32(_np, "marvell," _name, &tmp)) \ 2470 + _v = tmp; \ 2471 + } while (0) 2472 + 2473 + static struct platform_device *port_platdev[3]; 2474 + 2475 + static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev, 2476 + struct device_node *pnp) 2477 + { 2478 + struct platform_device *ppdev; 2479 + struct mv643xx_eth_platform_data ppd; 2480 + struct resource res; 2481 + const char *mac_addr; 2482 + int ret; 2483 + 2484 + memset(&ppd, 0, sizeof(ppd)); 2485 + ppd.shared = pdev; 2486 + 2487 + memset(&res, 0, sizeof(res)); 2488 + if (!of_irq_to_resource(pnp, 0, &res)) { 2489 + dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name); 2490 + return -EINVAL; 2491 + } 2492 + 2493 + if (of_property_read_u32(pnp, "reg", &ppd.port_number)) { 2494 + dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name); 2495 + return -EINVAL; 2496 + } 2497 + 2498 + if (ppd.port_number >= 3) { 2499 + dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name); 2500 + return -EINVAL; 2501 + } 2502 + 2503 + mac_addr = of_get_mac_address(pnp); 2504 + if (mac_addr) 2505 + memcpy(ppd.mac_addr, mac_addr, 6); 2506 + 2507 + mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size); 2508 + mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr); 2509 + mv643xx_eth_property(pnp, "tx-sram-size", ppd.tx_sram_size); 2510 + mv643xx_eth_property(pnp, "rx-queue-size", ppd.rx_queue_size); 2511 + mv643xx_eth_property(pnp, "rx-sram-addr", ppd.rx_sram_addr); 2512 + mv643xx_eth_property(pnp, "rx-sram-size", ppd.rx_sram_size); 2513 + 2514 + ppd.phy_node = of_parse_phandle(pnp, "phy-handle", 0); 2515 + if (!ppd.phy_node) { 2516 + ppd.phy_addr = MV643XX_ETH_PHY_NONE; 2517 + of_property_read_u32(pnp, "speed", &ppd.speed); 2518 + of_property_read_u32(pnp, "duplex", &ppd.duplex); 2519 + } 2520 + 2521 + ppdev = platform_device_alloc(MV643XX_ETH_NAME, ppd.port_number); 2522 + if (!ppdev) 2523 + return -ENOMEM; 2524 + ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 2525 + 2526 + ret = platform_device_add_resources(ppdev, &res, 1); 2527 + if (ret) 2528 + goto port_err; 2529 + 2530 + ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd)); 2531 + if (ret) 2532 + goto port_err; 2533 + 2534 + ret = platform_device_add(ppdev); 2535 + if (ret) 2536 + goto port_err; 2537 + 2538 + port_platdev[ppd.port_number] = ppdev; 2539 + 2540 + return 0; 2541 + 2542 + port_err: 2543 + platform_device_put(ppdev); 2544 + return ret; 2545 + } 2546 + 2547 + static int mv643xx_eth_shared_of_probe(struct platform_device *pdev) 2548 + { 2549 + struct mv643xx_eth_shared_platform_data *pd; 2550 + struct device_node *pnp, *np = pdev->dev.of_node; 2551 + int ret; 2552 + 2553 + /* bail out if not registered from DT */ 2554 + if (!np) 2555 + return 0; 2556 + 2557 + pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL); 2558 + if (!pd) 2559 + return -ENOMEM; 2560 + pdev->dev.platform_data = pd; 2561 + 2562 + mv643xx_eth_property(np, "tx-checksum-limit", pd->tx_csum_limit); 2563 + 2564 + for_each_available_child_of_node(np, pnp) { 2565 + ret = mv643xx_eth_shared_of_add_port(pdev, pnp); 2566 + if (ret) 2567 + return ret; 2568 + } 2569 + return 0; 2570 + } 2571 + 2572 + static void mv643xx_eth_shared_of_remove(void) 2573 + { 2574 + int n; 2575 + 2576 + for (n = 0; n < 3; n++) { 2577 + platform_device_del(port_platdev[n]); 2578 + port_platdev[n] = NULL; 2579 + } 2580 + } 2581 + #else 2582 + static int mv643xx_eth_shared_of_probe(struct platform_device *pdev) 2583 + { 2584 + return 0 2585 + } 2586 + 2587 + #define mv643xx_eth_shared_of_remove() 2588 + #endif 2589 + 2459 2590 static int mv643xx_eth_shared_probe(struct platform_device *pdev) 2460 2591 { 2461 2592 static int mv643xx_eth_version_printed; 2462 - struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; 2593 + struct mv643xx_eth_shared_platform_data *pd; 2463 2594 struct mv643xx_eth_shared_private *msp; 2464 2595 const struct mbus_dram_target_info *dram; 2465 2596 struct resource *res; 2597 + int ret; 2466 2598 2467 2599 if (!mv643xx_eth_version_printed++) 2468 2600 pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n", ··· 2610 2472 msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL); 2611 2473 if (msp == NULL) 2612 2474 return -ENOMEM; 2475 + platform_set_drvdata(pdev, msp); 2613 2476 2614 2477 msp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 2615 2478 if (msp->base == NULL) ··· 2627 2488 if (dram) 2628 2489 mv643xx_eth_conf_mbus_windows(msp, dram); 2629 2490 2491 + ret = mv643xx_eth_shared_of_probe(pdev); 2492 + if (ret) 2493 + return ret; 2494 + pd = pdev->dev.platform_data; 2495 + 2630 2496 msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ? 2631 2497 pd->tx_csum_limit : 9 * 1024; 2632 2498 infer_hw_params(msp); 2633 - 2634 - platform_set_drvdata(pdev, msp); 2635 2499 2636 2500 return 0; 2637 2501 } ··· 2643 2501 { 2644 2502 struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); 2645 2503 2504 + mv643xx_eth_shared_of_remove(); 2646 2505 if (!IS_ERR(msp->clk)) 2647 2506 clk_disable_unprepare(msp->clk); 2648 - 2649 2507 return 0; 2650 2508 } 2651 2509 ··· 2655 2513 .driver = { 2656 2514 .name = MV643XX_ETH_SHARED_NAME, 2657 2515 .owner = THIS_MODULE, 2516 + .of_match_table = of_match_ptr(mv643xx_eth_shared_ids), 2658 2517 }, 2659 2518 }; 2660 2519 ··· 2864 2721 if (!IS_ERR(mp->clk)) { 2865 2722 clk_prepare_enable(mp->clk); 2866 2723 mp->t_clk = clk_get_rate(mp->clk); 2724 + } else if (!IS_ERR(mp->shared->clk)) { 2725 + mp->t_clk = clk_get_rate(mp->shared->clk); 2867 2726 } 2868 2727 2869 2728 set_params(mp, pd);