diff options
| -rw-r--r-- | drivers/net/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/net/fec.c | 148 | ||||
| -rw-r--r-- | drivers/net/fec.h | 5 |
3 files changed, 139 insertions, 21 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3fda24a28d2..5780dad6a3c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
| @@ -1944,18 +1944,19 @@ config 68360_ENET | |||
| 1944 | config FEC | 1944 | config FEC |
| 1945 | bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" | 1945 | bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" |
| 1946 | depends on M523x || M527x || M5272 || M528x || M520x || M532x || \ | 1946 | depends on M523x || M527x || M5272 || M528x || M520x || M532x || \ |
| 1947 | MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5 | 1947 | MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5 || SOC_IMX28 |
| 1948 | select PHYLIB | 1948 | select PHYLIB |
| 1949 | help | 1949 | help |
| 1950 | Say Y here if you want to use the built-in 10/100 Fast ethernet | 1950 | Say Y here if you want to use the built-in 10/100 Fast ethernet |
| 1951 | controller on some Motorola ColdFire and Freescale i.MX processors. | 1951 | controller on some Motorola ColdFire and Freescale i.MX processors. |
| 1952 | 1952 | ||
| 1953 | config FEC2 | 1953 | config FEC2 |
| 1954 | bool "Second FEC ethernet controller (on some ColdFire CPUs)" | 1954 | bool "Second FEC ethernet controller" |
| 1955 | depends on FEC | 1955 | depends on FEC |
| 1956 | help | 1956 | help |
| 1957 | Say Y here if you want to use the second built-in 10/100 Fast | 1957 | Say Y here if you want to use the second built-in 10/100 Fast |
| 1958 | ethernet controller on some Motorola ColdFire processors. | 1958 | ethernet controller on some Motorola ColdFire and Freescale |
| 1959 | i.MX processors. | ||
| 1959 | 1960 | ||
| 1960 | config FEC_MPC52xx | 1961 | config FEC_MPC52xx |
| 1961 | tristate "MPC52xx FEC driver" | 1962 | tristate "MPC52xx FEC driver" |
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 8a1c51f8641..2a71373719a 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | * | 17 | * |
| 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 | * | ||
| 21 | * Copyright (C) 2010 Freescale Semiconductor, Inc. | ||
| 20 | */ | 22 | */ |
| 21 | 23 | ||
| 22 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -45,20 +47,36 @@ | |||
| 45 | 47 | ||
| 46 | #include <asm/cacheflush.h> | 48 | #include <asm/cacheflush.h> |
| 47 | 49 | ||
| 48 | #ifndef CONFIG_ARCH_MXC | 50 | #ifndef CONFIG_ARM |
| 49 | #include <asm/coldfire.h> | 51 | #include <asm/coldfire.h> |
| 50 | #include <asm/mcfsim.h> | 52 | #include <asm/mcfsim.h> |
| 51 | #endif | 53 | #endif |
| 52 | 54 | ||
| 53 | #include "fec.h" | 55 | #include "fec.h" |
| 54 | 56 | ||
| 55 | #ifdef CONFIG_ARCH_MXC | 57 | #if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) |
| 56 | #include <mach/hardware.h> | ||
| 57 | #define FEC_ALIGNMENT 0xf | 58 | #define FEC_ALIGNMENT 0xf |
| 58 | #else | 59 | #else |
| 59 | #define FEC_ALIGNMENT 0x3 | 60 | #define FEC_ALIGNMENT 0x3 |
| 60 | #endif | 61 | #endif |
| 61 | 62 | ||
| 63 | #define DRIVER_NAME "fec" | ||
| 64 | |||
| 65 | /* Controller is ENET-MAC */ | ||
| 66 | #define FEC_QUIRK_ENET_MAC (1 << 0) | ||
| 67 | /* Controller needs driver to swap frame */ | ||
| 68 | #define FEC_QUIRK_SWAP_FRAME (1 << 1) | ||
| 69 | |||
| 70 | static struct platform_device_id fec_devtype[] = { | ||
| 71 | { | ||
| 72 | .name = DRIVER_NAME, | ||
| 73 | .driver_data = 0, | ||
| 74 | }, { | ||
| 75 | .name = "imx28-fec", | ||
| 76 | .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, | ||
| 77 | } | ||
| 78 | }; | ||
| 79 | |||
| 62 | static unsigned char macaddr[ETH_ALEN]; | 80 | static unsigned char macaddr[ETH_ALEN]; |
| 63 | module_param_array(macaddr, byte, NULL, 0); | 81 | module_param_array(macaddr, byte, NULL, 0); |
| 64 | MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); | 82 | MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); |
| @@ -129,7 +147,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); | |||
| 129 | * account when setting it. | 147 | * account when setting it. |
| 130 | */ | 148 | */ |
| 131 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ | 149 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ |
| 132 | defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC) | 150 | defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ |
| 151 | defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) | ||
| 133 | #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) | 152 | #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) |
| 134 | #else | 153 | #else |
| 135 | #define OPT_FRAME_SIZE 0 | 154 | #define OPT_FRAME_SIZE 0 |
| @@ -208,10 +227,23 @@ static void fec_stop(struct net_device *dev); | |||
| 208 | /* Transmitter timeout */ | 227 | /* Transmitter timeout */ |
| 209 | #define TX_TIMEOUT (2 * HZ) | 228 | #define TX_TIMEOUT (2 * HZ) |
| 210 | 229 | ||
| 230 | static void *swap_buffer(void *bufaddr, int len) | ||
| 231 | { | ||
| 232 | int i; | ||
| 233 | unsigned int *buf = bufaddr; | ||
| 234 | |||
| 235 | for (i = 0; i < (len + 3) / 4; i++, buf++) | ||
| 236 | *buf = cpu_to_be32(*buf); | ||
| 237 | |||
| 238 | return bufaddr; | ||
| 239 | } | ||
| 240 | |||
| 211 | static netdev_tx_t | 241 | static netdev_tx_t |
| 212 | fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | 242 | fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) |
| 213 | { | 243 | { |
| 214 | struct fec_enet_private *fep = netdev_priv(dev); | 244 | struct fec_enet_private *fep = netdev_priv(dev); |
| 245 | const struct platform_device_id *id_entry = | ||
| 246 | platform_get_device_id(fep->pdev); | ||
| 215 | struct bufdesc *bdp; | 247 | struct bufdesc *bdp; |
| 216 | void *bufaddr; | 248 | void *bufaddr; |
| 217 | unsigned short status; | 249 | unsigned short status; |
| @@ -256,6 +288,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 256 | bufaddr = fep->tx_bounce[index]; | 288 | bufaddr = fep->tx_bounce[index]; |
| 257 | } | 289 | } |
| 258 | 290 | ||
| 291 | /* | ||
| 292 | * Some design made an incorrect assumption on endian mode of | ||
| 293 | * the system that it's running on. As the result, driver has to | ||
| 294 | * swap every frame going to and coming from the controller. | ||
| 295 | */ | ||
| 296 | if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) | ||
| 297 | swap_buffer(bufaddr, skb->len); | ||
| 298 | |||
| 259 | /* Save skb pointer */ | 299 | /* Save skb pointer */ |
| 260 | fep->tx_skbuff[fep->skb_cur] = skb; | 300 | fep->tx_skbuff[fep->skb_cur] = skb; |
| 261 | 301 | ||
| @@ -424,6 +464,8 @@ static void | |||
| 424 | fec_enet_rx(struct net_device *dev) | 464 | fec_enet_rx(struct net_device *dev) |
| 425 | { | 465 | { |
| 426 | struct fec_enet_private *fep = netdev_priv(dev); | 466 | struct fec_enet_private *fep = netdev_priv(dev); |
| 467 | const struct platform_device_id *id_entry = | ||
| 468 | platform_get_device_id(fep->pdev); | ||
| 427 | struct bufdesc *bdp; | 469 | struct bufdesc *bdp; |
| 428 | unsigned short status; | 470 | unsigned short status; |
| 429 | struct sk_buff *skb; | 471 | struct sk_buff *skb; |
| @@ -487,6 +529,9 @@ fec_enet_rx(struct net_device *dev) | |||
| 487 | dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen, | 529 | dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen, |
| 488 | DMA_FROM_DEVICE); | 530 | DMA_FROM_DEVICE); |
| 489 | 531 | ||
| 532 | if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) | ||
| 533 | swap_buffer(data, pkt_len); | ||
| 534 | |||
| 490 | /* This does 16 byte alignment, exactly what we need. | 535 | /* This does 16 byte alignment, exactly what we need. |
| 491 | * The packet length includes FCS, but we don't want to | 536 | * The packet length includes FCS, but we don't want to |
| 492 | * include that when passing upstream as it messes up | 537 | * include that when passing upstream as it messes up |
| @@ -689,6 +734,7 @@ static int fec_enet_mii_probe(struct net_device *dev) | |||
| 689 | char mdio_bus_id[MII_BUS_ID_SIZE]; | 734 | char mdio_bus_id[MII_BUS_ID_SIZE]; |
| 690 | char phy_name[MII_BUS_ID_SIZE + 3]; | 735 | char phy_name[MII_BUS_ID_SIZE + 3]; |
| 691 | int phy_id; | 736 | int phy_id; |
| 737 | int dev_id = fep->pdev->id; | ||
| 692 | 738 | ||
| 693 | fep->phy_dev = NULL; | 739 | fep->phy_dev = NULL; |
| 694 | 740 | ||
| @@ -700,6 +746,8 @@ static int fec_enet_mii_probe(struct net_device *dev) | |||
| 700 | continue; | 746 | continue; |
| 701 | if (fep->mii_bus->phy_map[phy_id]->phy_id == 0) | 747 | if (fep->mii_bus->phy_map[phy_id]->phy_id == 0) |
| 702 | continue; | 748 | continue; |
| 749 | if (dev_id--) | ||
| 750 | continue; | ||
| 703 | strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); | 751 | strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); |
| 704 | break; | 752 | break; |
| 705 | } | 753 | } |
| @@ -737,10 +785,35 @@ static int fec_enet_mii_probe(struct net_device *dev) | |||
| 737 | 785 | ||
| 738 | static int fec_enet_mii_init(struct platform_device *pdev) | 786 | static int fec_enet_mii_init(struct platform_device *pdev) |
| 739 | { | 787 | { |
| 788 | static struct mii_bus *fec0_mii_bus; | ||
| 740 | struct net_device *dev = platform_get_drvdata(pdev); | 789 | struct net_device *dev = platform_get_drvdata(pdev); |
| 741 | struct fec_enet_private *fep = netdev_priv(dev); | 790 | struct fec_enet_private *fep = netdev_priv(dev); |
| 791 | const struct platform_device_id *id_entry = | ||
| 792 | platform_get_device_id(fep->pdev); | ||
| 742 | int err = -ENXIO, i; | 793 | int err = -ENXIO, i; |
| 743 | 794 | ||
| 795 | /* | ||
| 796 | * The dual fec interfaces are not equivalent with enet-mac. | ||
| 797 | * Here are the differences: | ||
| 798 | * | ||
| 799 | * - fec0 supports MII & RMII modes while fec1 only supports RMII | ||
| 800 | * - fec0 acts as the 1588 time master while fec1 is slave | ||
| 801 | * - external phys can only be configured by fec0 | ||
| 802 | * | ||
| 803 | * That is to say fec1 can not work independently. It only works | ||
| 804 | * when fec0 is working. The reason behind this design is that the | ||
| 805 | * second interface is added primarily for Switch mode. | ||
| 806 | * | ||
| 807 | * Because of the last point above, both phys are attached on fec0 | ||
| 808 | * mdio interface in board design, and need to be configured by | ||
| 809 | * fec0 mii_bus. | ||
| 810 | */ | ||
| 811 | if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id) { | ||
| 812 | /* fec1 uses fec0 mii_bus */ | ||
| 813 | fep->mii_bus = fec0_mii_bus; | ||
| 814 | return 0; | ||
| 815 | } | ||
| 816 | |||
| 744 | fep->mii_timeout = 0; | 817 | fep->mii_timeout = 0; |
| 745 | 818 | ||
| 746 | /* | 819 | /* |
| @@ -777,6 +850,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) | |||
| 777 | if (mdiobus_register(fep->mii_bus)) | 850 | if (mdiobus_register(fep->mii_bus)) |
| 778 | goto err_out_free_mdio_irq; | 851 | goto err_out_free_mdio_irq; |
| 779 | 852 | ||
| 853 | /* save fec0 mii_bus */ | ||
| 854 | if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) | ||
| 855 | fec0_mii_bus = fep->mii_bus; | ||
| 856 | |||
| 780 | return 0; | 857 | return 0; |
| 781 | 858 | ||
| 782 | err_out_free_mdio_irq: | 859 | err_out_free_mdio_irq: |
| @@ -1148,12 +1225,25 @@ static void | |||
| 1148 | fec_restart(struct net_device *dev, int duplex) | 1225 | fec_restart(struct net_device *dev, int duplex) |
| 1149 | { | 1226 | { |
| 1150 | struct fec_enet_private *fep = netdev_priv(dev); | 1227 | struct fec_enet_private *fep = netdev_priv(dev); |
| 1228 | const struct platform_device_id *id_entry = | ||
| 1229 | platform_get_device_id(fep->pdev); | ||
| 1151 | int i; | 1230 | int i; |
| 1231 | u32 val, temp_mac[2]; | ||
| 1152 | 1232 | ||
| 1153 | /* Whack a reset. We should wait for this. */ | 1233 | /* Whack a reset. We should wait for this. */ |
| 1154 | writel(1, fep->hwp + FEC_ECNTRL); | 1234 | writel(1, fep->hwp + FEC_ECNTRL); |
| 1155 | udelay(10); | 1235 | udelay(10); |
| 1156 | 1236 | ||
| 1237 | /* | ||
| 1238 | * enet-mac reset will reset mac address registers too, | ||
| 1239 | * so need to reconfigure it. | ||
| 1240 | */ | ||
| 1241 | if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { | ||
| 1242 | memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); | ||
| 1243 | writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); | ||
| 1244 | writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); | ||
| 1245 | } | ||
| 1246 | |||
| 1157 | /* Clear any outstanding interrupt. */ | 1247 | /* Clear any outstanding interrupt. */ |
| 1158 | writel(0xffc00000, fep->hwp + FEC_IEVENT); | 1248 | writel(0xffc00000, fep->hwp + FEC_IEVENT); |
| 1159 | 1249 | ||
| @@ -1200,20 +1290,45 @@ fec_restart(struct net_device *dev, int duplex) | |||
| 1200 | /* Set MII speed */ | 1290 | /* Set MII speed */ |
| 1201 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); | 1291 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); |
| 1202 | 1292 | ||
| 1203 | #ifdef FEC_MIIGSK_ENR | 1293 | /* |
| 1204 | if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { | 1294 | * The phy interface and speed need to get configured |
| 1205 | /* disable the gasket and wait */ | 1295 | * differently on enet-mac. |
| 1206 | writel(0, fep->hwp + FEC_MIIGSK_ENR); | 1296 | */ |
| 1207 | while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) | 1297 | if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { |
| 1208 | udelay(1); | 1298 | val = readl(fep->hwp + FEC_R_CNTRL); |
| 1209 | 1299 | ||
| 1210 | /* configure the gasket: RMII, 50 MHz, no loopback, no echo */ | 1300 | /* MII or RMII */ |
| 1211 | writel(1, fep->hwp + FEC_MIIGSK_CFGR); | 1301 | if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) |
| 1302 | val |= (1 << 8); | ||
| 1303 | else | ||
| 1304 | val &= ~(1 << 8); | ||
| 1212 | 1305 | ||
| 1213 | /* re-enable the gasket */ | 1306 | /* 10M or 100M */ |
| 1214 | writel(2, fep->hwp + FEC_MIIGSK_ENR); | 1307 | if (fep->phy_dev && fep->phy_dev->speed == SPEED_100) |
| 1215 | } | 1308 | val &= ~(1 << 9); |
| 1309 | else | ||
| 1310 | val |= (1 << 9); | ||
| 1311 | |||
| 1312 | writel(val, fep->hwp + FEC_R_CNTRL); | ||
| 1313 | } else { | ||
| 1314 | #ifdef FEC_MIIGSK_ENR | ||
| 1315 | if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { | ||
| 1316 | /* disable the gasket and wait */ | ||
| 1317 | writel(0, fep->hwp + FEC_MIIGSK_ENR); | ||
| 1318 | while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) | ||
| 1319 | udelay(1); | ||
| 1320 | |||
| 1321 | /* | ||
| 1322 | * configure the gasket: | ||
| 1323 | * RMII, 50 MHz, no loopback, no echo | ||
| 1324 | */ | ||
| 1325 | writel(1, fep->hwp + FEC_MIIGSK_CFGR); | ||
| 1326 | |||
| 1327 | /* re-enable the gasket */ | ||
| 1328 | writel(2, fep->hwp + FEC_MIIGSK_ENR); | ||
| 1329 | } | ||
| 1216 | #endif | 1330 | #endif |
| 1331 | } | ||
| 1217 | 1332 | ||
| 1218 | /* And last, enable the transmit and receive processing */ | 1333 | /* And last, enable the transmit and receive processing */ |
| 1219 | writel(2, fep->hwp + FEC_ECNTRL); | 1334 | writel(2, fep->hwp + FEC_ECNTRL); |
| @@ -1410,12 +1525,13 @@ static const struct dev_pm_ops fec_pm_ops = { | |||
| 1410 | 1525 | ||
| 1411 | static struct platform_driver fec_driver = { | 1526 | static struct platform_driver fec_driver = { |
| 1412 | .driver = { | 1527 | .driver = { |
| 1413 | .name = "fec", | 1528 | .name = DRIVER_NAME, |
| 1414 | .owner = THIS_MODULE, | 1529 | .owner = THIS_MODULE, |
| 1415 | #ifdef CONFIG_PM | 1530 | #ifdef CONFIG_PM |
| 1416 | .pm = &fec_pm_ops, | 1531 | .pm = &fec_pm_ops, |
| 1417 | #endif | 1532 | #endif |
| 1418 | }, | 1533 | }, |
| 1534 | .id_table = fec_devtype, | ||
| 1419 | .probe = fec_probe, | 1535 | .probe = fec_probe, |
| 1420 | .remove = __devexit_p(fec_drv_remove), | 1536 | .remove = __devexit_p(fec_drv_remove), |
| 1421 | }; | 1537 | }; |
diff --git a/drivers/net/fec.h b/drivers/net/fec.h index 2c48b25668d..ace318df4c8 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h | |||
| @@ -14,7 +14,8 @@ | |||
| 14 | /****************************************************************************/ | 14 | /****************************************************************************/ |
| 15 | 15 | ||
| 16 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ | 16 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ |
| 17 | defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC) | 17 | defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ |
| 18 | defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) | ||
| 18 | /* | 19 | /* |
| 19 | * Just figures, Motorola would have to change the offsets for | 20 | * Just figures, Motorola would have to change the offsets for |
| 20 | * registers in the same peripheral device on different models | 21 | * registers in the same peripheral device on different models |
| @@ -78,7 +79,7 @@ | |||
| 78 | /* | 79 | /* |
| 79 | * Define the buffer descriptor structure. | 80 | * Define the buffer descriptor structure. |
| 80 | */ | 81 | */ |
| 81 | #ifdef CONFIG_ARCH_MXC | 82 | #if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) |
| 82 | struct bufdesc { | 83 | struct bufdesc { |
| 83 | unsigned short cbd_datlen; /* Data length */ | 84 | unsigned short cbd_datlen; /* Data length */ |
| 84 | unsigned short cbd_sc; /* Control and status info */ | 85 | unsigned short cbd_sc; /* Control and status info */ |
