aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale/fec.c
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@linaro.org>2011-09-22 22:12:48 -0400
committerDavid S. Miller <davem@davemloft.net>2011-09-23 13:55:26 -0400
commit230dec61313dc5f5720311d0b492f69f5466b0a4 (patch)
tree6d67c1ee8106752a156468d339e5ae8f1848e16e /drivers/net/ethernet/freescale/fec.c
parentc828827f8426f2cd8e37315c59ae406534a16d48 (diff)
net/fec: add imx6q enet support
The imx6q enet is a derivative of imx28 enet controller. It fixed the frame endian issue found on imx28, and added 1 Gbps support. It also fixes a typo on vendor name in Kconfig. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale/fec.c')
-rw-r--r--drivers/net/ethernet/freescale/fec.c66
1 files changed, 53 insertions, 13 deletions
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 2bbe6a519bf4..cce78ceb63ed 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -18,7 +18,7 @@
18 * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) 18 * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
19 * Copyright (c) 2004-2006 Macq Electronique SA. 19 * Copyright (c) 2004-2006 Macq Electronique SA.
20 * 20 *
21 * Copyright (C) 2010 Freescale Semiconductor, Inc. 21 * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
22 */ 22 */
23 23
24#include <linux/module.h> 24#include <linux/module.h>
@@ -72,6 +72,8 @@
72#define FEC_QUIRK_SWAP_FRAME (1 << 1) 72#define FEC_QUIRK_SWAP_FRAME (1 << 1)
73/* Controller uses gasket */ 73/* Controller uses gasket */
74#define FEC_QUIRK_USE_GASKET (1 << 2) 74#define FEC_QUIRK_USE_GASKET (1 << 2)
75/* Controller has GBIT support */
76#define FEC_QUIRK_HAS_GBIT (1 << 3)
75 77
76static struct platform_device_id fec_devtype[] = { 78static struct platform_device_id fec_devtype[] = {
77 { 79 {
@@ -88,6 +90,9 @@ static struct platform_device_id fec_devtype[] = {
88 .name = "imx28-fec", 90 .name = "imx28-fec",
89 .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, 91 .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
90 }, { 92 }, {
93 .name = "imx6q-fec",
94 .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
95 }, {
91 /* sentinel */ 96 /* sentinel */
92 } 97 }
93}; 98};
@@ -97,12 +102,14 @@ enum imx_fec_type {
97 IMX25_FEC = 1, /* runs on i.mx25/50/53 */ 102 IMX25_FEC = 1, /* runs on i.mx25/50/53 */
98 IMX27_FEC, /* runs on i.mx27/35/51 */ 103 IMX27_FEC, /* runs on i.mx27/35/51 */
99 IMX28_FEC, 104 IMX28_FEC,
105 IMX6Q_FEC,
100}; 106};
101 107
102static const struct of_device_id fec_dt_ids[] = { 108static const struct of_device_id fec_dt_ids[] = {
103 { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], }, 109 { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
104 { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], }, 110 { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
105 { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], }, 111 { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
112 { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
106 { /* sentinel */ } 113 { /* sentinel */ }
107}; 114};
108MODULE_DEVICE_TABLE(of, fec_dt_ids); 115MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -373,6 +380,7 @@ fec_restart(struct net_device *ndev, int duplex)
373 int i; 380 int i;
374 u32 temp_mac[2]; 381 u32 temp_mac[2];
375 u32 rcntl = OPT_FRAME_SIZE | 0x04; 382 u32 rcntl = OPT_FRAME_SIZE | 0x04;
383 u32 ecntl = 0x2; /* ETHEREN */
376 384
377 /* Whack a reset. We should wait for this. */ 385 /* Whack a reset. We should wait for this. */
378 writel(1, fep->hwp + FEC_ECNTRL); 386 writel(1, fep->hwp + FEC_ECNTRL);
@@ -442,18 +450,23 @@ fec_restart(struct net_device *ndev, int duplex)
442 /* Enable flow control and length check */ 450 /* Enable flow control and length check */
443 rcntl |= 0x40000000 | 0x00000020; 451 rcntl |= 0x40000000 | 0x00000020;
444 452
445 /* MII or RMII */ 453 /* RGMII, RMII or MII */
446 if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) 454 if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
455 rcntl |= (1 << 6);
456 else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
447 rcntl |= (1 << 8); 457 rcntl |= (1 << 8);
448 else 458 else
449 rcntl &= ~(1 << 8); 459 rcntl &= ~(1 << 8);
450 460
451 /* 10M or 100M */ 461 /* 1G, 100M or 10M */
452 if (fep->phy_dev && fep->phy_dev->speed == SPEED_100) 462 if (fep->phy_dev) {
453 rcntl &= ~(1 << 9); 463 if (fep->phy_dev->speed == SPEED_1000)
454 else 464 ecntl |= (1 << 5);
455 rcntl |= (1 << 9); 465 else if (fep->phy_dev->speed == SPEED_100)
456 466 rcntl &= ~(1 << 9);
467 else
468 rcntl |= (1 << 9);
469 }
457 } else { 470 } else {
458#ifdef FEC_MIIGSK_ENR 471#ifdef FEC_MIIGSK_ENR
459 if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) { 472 if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
@@ -478,8 +491,15 @@ fec_restart(struct net_device *ndev, int duplex)
478 } 491 }
479 writel(rcntl, fep->hwp + FEC_R_CNTRL); 492 writel(rcntl, fep->hwp + FEC_R_CNTRL);
480 493
494 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
495 /* enable ENET endian swap */
496 ecntl |= (1 << 8);
497 /* enable ENET store and forward mode */
498 writel(1 << 8, fep->hwp + FEC_X_WMRK);
499 }
500
481 /* And last, enable the transmit and receive processing */ 501 /* And last, enable the transmit and receive processing */
482 writel(2, fep->hwp + FEC_ECNTRL); 502 writel(ecntl, fep->hwp + FEC_ECNTRL);
483 writel(0, fep->hwp + FEC_R_DES_ACTIVE); 503 writel(0, fep->hwp + FEC_R_DES_ACTIVE);
484 504
485 /* Enable interrupts we wish to service */ 505 /* Enable interrupts we wish to service */
@@ -490,6 +510,8 @@ static void
490fec_stop(struct net_device *ndev) 510fec_stop(struct net_device *ndev)
491{ 511{
492 struct fec_enet_private *fep = netdev_priv(ndev); 512 struct fec_enet_private *fep = netdev_priv(ndev);
513 const struct platform_device_id *id_entry =
514 platform_get_device_id(fep->pdev);
493 515
494 /* We cannot expect a graceful transmit stop without link !!! */ 516 /* We cannot expect a graceful transmit stop without link !!! */
495 if (fep->link) { 517 if (fep->link) {
@@ -504,6 +526,10 @@ fec_stop(struct net_device *ndev)
504 udelay(10); 526 udelay(10);
505 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 527 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
506 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 528 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
529
530 /* We have to keep ENET enabled to have MII interrupt stay working */
531 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
532 writel(2, fep->hwp + FEC_ECNTRL);
507} 533}
508 534
509 535
@@ -918,6 +944,8 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
918static int fec_enet_mii_probe(struct net_device *ndev) 944static int fec_enet_mii_probe(struct net_device *ndev)
919{ 945{
920 struct fec_enet_private *fep = netdev_priv(ndev); 946 struct fec_enet_private *fep = netdev_priv(ndev);
947 const struct platform_device_id *id_entry =
948 platform_get_device_id(fep->pdev);
921 struct phy_device *phy_dev = NULL; 949 struct phy_device *phy_dev = NULL;
922 char mdio_bus_id[MII_BUS_ID_SIZE]; 950 char mdio_bus_id[MII_BUS_ID_SIZE];
923 char phy_name[MII_BUS_ID_SIZE + 3]; 951 char phy_name[MII_BUS_ID_SIZE + 3];
@@ -949,14 +977,18 @@ static int fec_enet_mii_probe(struct net_device *ndev)
949 977
950 snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); 978 snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
951 phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0, 979 phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
952 PHY_INTERFACE_MODE_MII); 980 fep->phy_interface);
953 if (IS_ERR(phy_dev)) { 981 if (IS_ERR(phy_dev)) {
954 printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name); 982 printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
955 return PTR_ERR(phy_dev); 983 return PTR_ERR(phy_dev);
956 } 984 }
957 985
958 /* mask with MAC supported features */ 986 /* mask with MAC supported features */
959 phy_dev->supported &= PHY_BASIC_FEATURES; 987 if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
988 phy_dev->supported &= PHY_GBIT_FEATURES;
989 else
990 phy_dev->supported &= PHY_BASIC_FEATURES;
991
960 phy_dev->advertising = phy_dev->supported; 992 phy_dev->advertising = phy_dev->supported;
961 993
962 fep->phy_dev = phy_dev; 994 fep->phy_dev = phy_dev;
@@ -1006,8 +1038,16 @@ static int fec_enet_mii_init(struct platform_device *pdev)
1006 1038
1007 /* 1039 /*
1008 * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) 1040 * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
1041 *
1042 * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
1043 * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28
1044 * Reference Manual has an error on this, and gets fixed on i.MX6Q
1045 * document.
1009 */ 1046 */
1010 fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; 1047 fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000);
1048 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
1049 fep->phy_speed--;
1050 fep->phy_speed <<= 1;
1011 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 1051 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
1012 1052
1013 fep->mii_bus = mdiobus_alloc(); 1053 fep->mii_bus = mdiobus_alloc();