diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-01-28 18:03:11 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-01 03:58:26 -0500 |
commit | ead731837d142b103eab9870105f50bc40b69255 (patch) | |
tree | 2c58dcfb60b042af8e73d58e8dbef9a351768c32 /drivers/net/fec.c | |
parent | 196719ecec0c526de273dcb902f0be956a193232 (diff) |
FEC: Turn FEC driver into platform device driver
This turns the fec driver into a platform device driver for new
platforms. Old platforms are still supported through a FEC_LEGACY define
till they are also ported.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Greg Ungerer <gerg@uclinux.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fec.c')
-rw-r--r-- | drivers/net/fec.c | 249 |
1 files changed, 220 insertions, 29 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 7631062cd44d..ea23baaf0256 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/io.h> | 39 | #include <linux/io.h> |
40 | #include <linux/irq.h> | 40 | #include <linux/irq.h> |
41 | #include <linux/clk.h> | 41 | #include <linux/clk.h> |
42 | #include <linux/platform_device.h> | ||
42 | 43 | ||
43 | #include <asm/cacheflush.h> | 44 | #include <asm/cacheflush.h> |
44 | 45 | ||
@@ -49,12 +50,6 @@ | |||
49 | 50 | ||
50 | #include "fec.h" | 51 | #include "fec.h" |
51 | 52 | ||
52 | #if defined(CONFIG_FEC2) | ||
53 | #define FEC_MAX_PORTS 2 | ||
54 | #else | ||
55 | #define FEC_MAX_PORTS 1 | ||
56 | #endif | ||
57 | |||
58 | #ifdef CONFIG_ARCH_MXC | 53 | #ifdef CONFIG_ARCH_MXC |
59 | #include <mach/hardware.h> | 54 | #include <mach/hardware.h> |
60 | #define FEC_ALIGNMENT 0xf | 55 | #define FEC_ALIGNMENT 0xf |
@@ -62,13 +57,22 @@ | |||
62 | #define FEC_ALIGNMENT 0x3 | 57 | #define FEC_ALIGNMENT 0x3 |
63 | #endif | 58 | #endif |
64 | 59 | ||
60 | #if defined CONFIG_M5272 || defined CONFIG_M527x || defined CONFIG_M523x \ | ||
61 | || defined CONFIG_M528x || defined CONFIG_M532x || defined CONFIG_M520x | ||
62 | #define FEC_LEGACY | ||
63 | /* | ||
64 | * Define the fixed address of the FEC hardware. | ||
65 | */ | ||
65 | #if defined(CONFIG_M5272) | 66 | #if defined(CONFIG_M5272) |
66 | #define HAVE_mii_link_interrupt | 67 | #define HAVE_mii_link_interrupt |
67 | #endif | 68 | #endif |
68 | 69 | ||
69 | /* | 70 | #if defined(CONFIG_FEC2) |
70 | * Define the fixed address of the FEC hardware. | 71 | #define FEC_MAX_PORTS 2 |
71 | */ | 72 | #else |
73 | #define FEC_MAX_PORTS 1 | ||
74 | #endif | ||
75 | |||
72 | static unsigned int fec_hw[] = { | 76 | static unsigned int fec_hw[] = { |
73 | #if defined(CONFIG_M5272) | 77 | #if defined(CONFIG_M5272) |
74 | (MCF_MBAR + 0x840), | 78 | (MCF_MBAR + 0x840), |
@@ -106,6 +110,8 @@ static unsigned char fec_mac_default[] = { | |||
106 | #define FEC_FLASHMAC 0 | 110 | #define FEC_FLASHMAC 0 |
107 | #endif | 111 | #endif |
108 | 112 | ||
113 | #endif /* FEC_LEGACY */ | ||
114 | |||
109 | /* Forward declarations of some structures to support different PHYs | 115 | /* Forward declarations of some structures to support different PHYs |
110 | */ | 116 | */ |
111 | 117 | ||
@@ -189,6 +195,8 @@ struct fec_enet_private { | |||
189 | 195 | ||
190 | struct net_device *netdev; | 196 | struct net_device *netdev; |
191 | 197 | ||
198 | struct clk *clk; | ||
199 | |||
192 | /* The saved address of a sent-in-place packet/buffer, for skfree(). */ | 200 | /* The saved address of a sent-in-place packet/buffer, for skfree(). */ |
193 | unsigned char *tx_bounce[TX_RING_SIZE]; | 201 | unsigned char *tx_bounce[TX_RING_SIZE]; |
194 | struct sk_buff* tx_skbuff[TX_RING_SIZE]; | 202 | struct sk_buff* tx_skbuff[TX_RING_SIZE]; |
@@ -1919,7 +1927,9 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) | |||
1919 | printk("FEC: No PHY device found.\n"); | 1927 | printk("FEC: No PHY device found.\n"); |
1920 | /* Disable external MII interface */ | 1928 | /* Disable external MII interface */ |
1921 | fecp->fec_mii_speed = fep->phy_speed = 0; | 1929 | fecp->fec_mii_speed = fep->phy_speed = 0; |
1930 | #ifdef FREC_LEGACY | ||
1922 | fec_disable_phy_intr(); | 1931 | fec_disable_phy_intr(); |
1932 | #endif | ||
1923 | } | 1933 | } |
1924 | } | 1934 | } |
1925 | 1935 | ||
@@ -2101,12 +2111,12 @@ fec_set_mac_address(struct net_device *dev) | |||
2101 | 2111 | ||
2102 | } | 2112 | } |
2103 | 2113 | ||
2104 | /* Initialize the FEC Ethernet on 860T (or ColdFire 5272). | ||
2105 | */ | ||
2106 | /* | 2114 | /* |
2107 | * XXX: We need to clean up on failure exits here. | 2115 | * XXX: We need to clean up on failure exits here. |
2116 | * | ||
2117 | * index is only used in legacy code | ||
2108 | */ | 2118 | */ |
2109 | int __init fec_enet_init(struct net_device *dev) | 2119 | int __init fec_enet_init(struct net_device *dev, int index) |
2110 | { | 2120 | { |
2111 | struct fec_enet_private *fep = netdev_priv(dev); | 2121 | struct fec_enet_private *fep = netdev_priv(dev); |
2112 | unsigned long mem_addr; | 2122 | unsigned long mem_addr; |
@@ -2114,11 +2124,6 @@ int __init fec_enet_init(struct net_device *dev) | |||
2114 | cbd_t *cbd_base; | 2124 | cbd_t *cbd_base; |
2115 | volatile fec_t *fecp; | 2125 | volatile fec_t *fecp; |
2116 | int i, j; | 2126 | int i, j; |
2117 | static int index = 0; | ||
2118 | |||
2119 | /* Only allow us to be probed once. */ | ||
2120 | if (index >= FEC_MAX_PORTS) | ||
2121 | return -ENXIO; | ||
2122 | 2127 | ||
2123 | /* Allocate memory for buffer descriptors. | 2128 | /* Allocate memory for buffer descriptors. |
2124 | */ | 2129 | */ |
@@ -2134,7 +2139,7 @@ int __init fec_enet_init(struct net_device *dev) | |||
2134 | 2139 | ||
2135 | /* Create an Ethernet device instance. | 2140 | /* Create an Ethernet device instance. |
2136 | */ | 2141 | */ |
2137 | fecp = (volatile fec_t *) fec_hw[index]; | 2142 | fecp = (volatile fec_t *)dev->base_addr; |
2138 | 2143 | ||
2139 | fep->index = index; | 2144 | fep->index = index; |
2140 | fep->hwp = fecp; | 2145 | fep->hwp = fecp; |
@@ -2145,16 +2150,24 @@ int __init fec_enet_init(struct net_device *dev) | |||
2145 | fecp->fec_ecntrl = 1; | 2150 | fecp->fec_ecntrl = 1; |
2146 | udelay(10); | 2151 | udelay(10); |
2147 | 2152 | ||
2148 | /* Set the Ethernet address. If using multiple Enets on the 8xx, | 2153 | /* Set the Ethernet address */ |
2149 | * this needs some work to get unique addresses. | 2154 | #ifdef FEC_LEGACY |
2150 | * | ||
2151 | * This is our default MAC address unless the user changes | ||
2152 | * it via eth_mac_addr (our dev->set_mac_addr handler). | ||
2153 | */ | ||
2154 | fec_get_mac(dev); | 2155 | fec_get_mac(dev); |
2156 | #else | ||
2157 | { | ||
2158 | unsigned long l; | ||
2159 | l = fecp->fec_addr_low; | ||
2160 | dev->dev_addr[0] = (unsigned char)((l & 0xFF000000) >> 24); | ||
2161 | dev->dev_addr[1] = (unsigned char)((l & 0x00FF0000) >> 16); | ||
2162 | dev->dev_addr[2] = (unsigned char)((l & 0x0000FF00) >> 8); | ||
2163 | dev->dev_addr[3] = (unsigned char)((l & 0x000000FF) >> 0); | ||
2164 | l = fecp->fec_addr_high; | ||
2165 | dev->dev_addr[4] = (unsigned char)((l & 0xFF000000) >> 24); | ||
2166 | dev->dev_addr[5] = (unsigned char)((l & 0x00FF0000) >> 16); | ||
2167 | } | ||
2168 | #endif | ||
2155 | 2169 | ||
2156 | cbd_base = (cbd_t *)mem_addr; | 2170 | cbd_base = (cbd_t *)mem_addr; |
2157 | /* XXX: missing check for allocation failure */ | ||
2158 | 2171 | ||
2159 | /* Set receive and transmit descriptor base. | 2172 | /* Set receive and transmit descriptor base. |
2160 | */ | 2173 | */ |
@@ -2222,10 +2235,12 @@ int __init fec_enet_init(struct net_device *dev) | |||
2222 | fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) | 2235 | fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) |
2223 | * RX_RING_SIZE; | 2236 | * RX_RING_SIZE; |
2224 | 2237 | ||
2238 | #ifdef FEC_LEGACY | ||
2225 | /* Install our interrupt handlers. This varies depending on | 2239 | /* Install our interrupt handlers. This varies depending on |
2226 | * the architecture. | 2240 | * the architecture. |
2227 | */ | 2241 | */ |
2228 | fec_request_intrs(dev); | 2242 | fec_request_intrs(dev); |
2243 | #endif | ||
2229 | 2244 | ||
2230 | fecp->fec_grp_hash_table_high = 0; | 2245 | fecp->fec_grp_hash_table_high = 0; |
2231 | fecp->fec_grp_hash_table_low = 0; | 2246 | fecp->fec_grp_hash_table_low = 0; |
@@ -2237,8 +2252,6 @@ int __init fec_enet_init(struct net_device *dev) | |||
2237 | fecp->fec_hash_table_low = 0; | 2252 | fecp->fec_hash_table_low = 0; |
2238 | #endif | 2253 | #endif |
2239 | 2254 | ||
2240 | dev->base_addr = (unsigned long)fecp; | ||
2241 | |||
2242 | /* The FEC Ethernet specific entries in the device structure. */ | 2255 | /* The FEC Ethernet specific entries in the device structure. */ |
2243 | dev->open = fec_enet_open; | 2256 | dev->open = fec_enet_open; |
2244 | dev->hard_start_xmit = fec_enet_start_xmit; | 2257 | dev->hard_start_xmit = fec_enet_start_xmit; |
@@ -2252,7 +2265,20 @@ int __init fec_enet_init(struct net_device *dev) | |||
2252 | mii_free = mii_cmds; | 2265 | mii_free = mii_cmds; |
2253 | 2266 | ||
2254 | /* setup MII interface */ | 2267 | /* setup MII interface */ |
2268 | #ifdef FEC_LEGACY | ||
2255 | fec_set_mii(dev, fep); | 2269 | fec_set_mii(dev, fep); |
2270 | #else | ||
2271 | fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; | ||
2272 | fecp->fec_x_cntrl = 0x00; | ||
2273 | |||
2274 | /* | ||
2275 | * Set MII speed to 2.5 MHz | ||
2276 | */ | ||
2277 | fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) | ||
2278 | / 2500000) / 2) & 0x3F) << 1; | ||
2279 | fecp->fec_mii_speed = fep->phy_speed; | ||
2280 | fec_restart(dev, 0); | ||
2281 | #endif | ||
2256 | 2282 | ||
2257 | /* Clear and enable interrupts */ | 2283 | /* Clear and enable interrupts */ |
2258 | fecp->fec_ievent = 0xffc00000; | 2284 | fecp->fec_ievent = 0xffc00000; |
@@ -2265,7 +2291,6 @@ int __init fec_enet_init(struct net_device *dev) | |||
2265 | fep->phy_addr = 0; | 2291 | fep->phy_addr = 0; |
2266 | mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); | 2292 | mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); |
2267 | 2293 | ||
2268 | index++; | ||
2269 | return 0; | 2294 | return 0; |
2270 | } | 2295 | } |
2271 | 2296 | ||
@@ -2417,6 +2442,7 @@ fec_stop(struct net_device *dev) | |||
2417 | fecp->fec_mii_speed = fep->phy_speed; | 2442 | fecp->fec_mii_speed = fep->phy_speed; |
2418 | } | 2443 | } |
2419 | 2444 | ||
2445 | #ifdef FEC_LEGACY | ||
2420 | static int __init fec_enet_module_init(void) | 2446 | static int __init fec_enet_module_init(void) |
2421 | { | 2447 | { |
2422 | struct net_device *dev; | 2448 | struct net_device *dev; |
@@ -2428,7 +2454,8 @@ static int __init fec_enet_module_init(void) | |||
2428 | dev = alloc_etherdev(sizeof(struct fec_enet_private)); | 2454 | dev = alloc_etherdev(sizeof(struct fec_enet_private)); |
2429 | if (!dev) | 2455 | if (!dev) |
2430 | return -ENOMEM; | 2456 | return -ENOMEM; |
2431 | err = fec_enet_init(dev); | 2457 | dev->base_addr = (unsigned long)fec_hw[i]; |
2458 | err = fec_enet_init(dev, i); | ||
2432 | if (err) { | 2459 | if (err) { |
2433 | free_netdev(dev); | 2460 | free_netdev(dev); |
2434 | continue; | 2461 | continue; |
@@ -2443,6 +2470,170 @@ static int __init fec_enet_module_init(void) | |||
2443 | } | 2470 | } |
2444 | return 0; | 2471 | return 0; |
2445 | } | 2472 | } |
2473 | #else | ||
2474 | |||
2475 | static int __devinit | ||
2476 | fec_probe(struct platform_device *pdev) | ||
2477 | { | ||
2478 | struct fec_enet_private *fep; | ||
2479 | struct net_device *ndev; | ||
2480 | int i, irq, ret = 0; | ||
2481 | struct resource *r; | ||
2482 | |||
2483 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
2484 | if (!r) | ||
2485 | return -ENXIO; | ||
2486 | |||
2487 | r = request_mem_region(r->start, resource_size(r), pdev->name); | ||
2488 | if (!r) | ||
2489 | return -EBUSY; | ||
2490 | |||
2491 | /* Init network device */ | ||
2492 | ndev = alloc_etherdev(sizeof(struct fec_enet_private)); | ||
2493 | if (!ndev) | ||
2494 | return -ENOMEM; | ||
2495 | |||
2496 | SET_NETDEV_DEV(ndev, &pdev->dev); | ||
2497 | |||
2498 | /* setup board info structure */ | ||
2499 | fep = netdev_priv(ndev); | ||
2500 | memset(fep, 0, sizeof(*fep)); | ||
2501 | |||
2502 | ndev->base_addr = (unsigned long)ioremap(r->start, resource_size(r)); | ||
2503 | |||
2504 | if (!ndev->base_addr) { | ||
2505 | ret = -ENOMEM; | ||
2506 | goto failed_ioremap; | ||
2507 | } | ||
2508 | |||
2509 | platform_set_drvdata(pdev, ndev); | ||
2510 | |||
2511 | /* This device has up to three irqs on some platforms */ | ||
2512 | for (i = 0; i < 3; i++) { | ||
2513 | irq = platform_get_irq(pdev, i); | ||
2514 | if (i && irq < 0) | ||
2515 | break; | ||
2516 | ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); | ||
2517 | if (ret) { | ||
2518 | while (i >= 0) { | ||
2519 | irq = platform_get_irq(pdev, i); | ||
2520 | free_irq(irq, ndev); | ||
2521 | i--; | ||
2522 | } | ||
2523 | goto failed_irq; | ||
2524 | } | ||
2525 | } | ||
2526 | |||
2527 | fep->clk = clk_get(&pdev->dev, "fec_clk"); | ||
2528 | if (IS_ERR(fep->clk)) { | ||
2529 | ret = PTR_ERR(fep->clk); | ||
2530 | goto failed_clk; | ||
2531 | } | ||
2532 | clk_enable(fep->clk); | ||
2533 | |||
2534 | ret = fec_enet_init(ndev, 0); | ||
2535 | if (ret) | ||
2536 | goto failed_init; | ||
2537 | |||
2538 | ret = register_netdev(ndev); | ||
2539 | if (ret) | ||
2540 | goto failed_register; | ||
2541 | |||
2542 | return 0; | ||
2543 | |||
2544 | failed_register: | ||
2545 | failed_init: | ||
2546 | clk_disable(fep->clk); | ||
2547 | clk_put(fep->clk); | ||
2548 | failed_clk: | ||
2549 | for (i = 0; i < 3; i++) { | ||
2550 | irq = platform_get_irq(pdev, i); | ||
2551 | if (irq > 0) | ||
2552 | free_irq(irq, ndev); | ||
2553 | } | ||
2554 | failed_irq: | ||
2555 | iounmap((void __iomem *)ndev->base_addr); | ||
2556 | failed_ioremap: | ||
2557 | free_netdev(ndev); | ||
2558 | |||
2559 | return ret; | ||
2560 | } | ||
2561 | |||
2562 | static int __devexit | ||
2563 | fec_drv_remove(struct platform_device *pdev) | ||
2564 | { | ||
2565 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
2566 | struct fec_enet_private *fep = netdev_priv(ndev); | ||
2567 | |||
2568 | platform_set_drvdata(pdev, NULL); | ||
2569 | |||
2570 | fec_stop(ndev); | ||
2571 | clk_disable(fep->clk); | ||
2572 | clk_put(fep->clk); | ||
2573 | iounmap((void __iomem *)ndev->base_addr); | ||
2574 | unregister_netdev(ndev); | ||
2575 | free_netdev(ndev); | ||
2576 | return 0; | ||
2577 | } | ||
2578 | |||
2579 | static int | ||
2580 | fec_suspend(struct platform_device *dev, pm_message_t state) | ||
2581 | { | ||
2582 | struct net_device *ndev = platform_get_drvdata(dev); | ||
2583 | struct fec_enet_private *fep; | ||
2584 | |||
2585 | if (ndev) { | ||
2586 | fep = netdev_priv(ndev); | ||
2587 | if (netif_running(ndev)) { | ||
2588 | netif_device_detach(ndev); | ||
2589 | fec_stop(ndev); | ||
2590 | } | ||
2591 | } | ||
2592 | return 0; | ||
2593 | } | ||
2594 | |||
2595 | static int | ||
2596 | fec_resume(struct platform_device *dev) | ||
2597 | { | ||
2598 | struct net_device *ndev = platform_get_drvdata(dev); | ||
2599 | |||
2600 | if (ndev) { | ||
2601 | if (netif_running(ndev)) { | ||
2602 | fec_enet_init(ndev, 0); | ||
2603 | netif_device_attach(ndev); | ||
2604 | } | ||
2605 | } | ||
2606 | return 0; | ||
2607 | } | ||
2608 | |||
2609 | static struct platform_driver fec_driver = { | ||
2610 | .driver = { | ||
2611 | .name = "fec", | ||
2612 | .owner = THIS_MODULE, | ||
2613 | }, | ||
2614 | .probe = fec_probe, | ||
2615 | .remove = __devexit_p(fec_drv_remove), | ||
2616 | .suspend = fec_suspend, | ||
2617 | .resume = fec_resume, | ||
2618 | }; | ||
2619 | |||
2620 | static int __init | ||
2621 | fec_enet_module_init(void) | ||
2622 | { | ||
2623 | printk(KERN_INFO "FEC Ethernet Driver\n"); | ||
2624 | |||
2625 | return platform_driver_register(&fec_driver); | ||
2626 | } | ||
2627 | |||
2628 | static void __exit | ||
2629 | fec_enet_cleanup(void) | ||
2630 | { | ||
2631 | platform_driver_unregister(&fec_driver); | ||
2632 | } | ||
2633 | |||
2634 | module_exit(fec_enet_cleanup); | ||
2635 | |||
2636 | #endif /* FEC_LEGACY */ | ||
2446 | 2637 | ||
2447 | module_init(fec_enet_module_init); | 2638 | module_init(fec_enet_module_init); |
2448 | 2639 | ||