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