Commit b5680e0b591f2701c5ba7d5fc8f96b55414073c8

Authored by Shawn Guo
Committed by David S. Miller
1 parent bcc67771ed

net/fec: add dual fec support for mx28

This patch is to add mx28 dual fec support. Here are some key notes
for mx28 fec controller.

 - The mx28 fec controller naming ENET-MAC is a different IP from FEC
   used on other i.mx variants.  But they are basically compatible
   on software interface, so it's possible to share the same driver.
 - ENET-MAC design on mx28 made an improper assumption that it runs
   on a big-endian system. As the result, driver has to swap every
   frame going to and coming from the controller.
 - The external phys can only be configured by fec0, which means fec1
   can not work independently and both phys need to be configured by
   mii_bus attached on fec0.
 - ENET-MAC reset will get mac address registers reset too.
 - ENET-MAC MII/RMII mode and 10M/100M speed are configured
   differently FEC.
 - ETHER_EN bit must be set to get ENET-MAC interrupt work.

Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 139 additions and 21 deletions Side-by-side Diff

... ... @@ -1944,18 +1944,19 @@
1944 1944 config FEC
1945 1945 bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
1946 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 1948 select PHYLIB
1949 1949 help
1950 1950 Say Y here if you want to use the built-in 10/100 Fast ethernet
1951 1951 controller on some Motorola ColdFire and Freescale i.MX processors.
1952 1952  
1953 1953 config FEC2
1954   - bool "Second FEC ethernet controller (on some ColdFire CPUs)"
  1954 + bool "Second FEC ethernet controller"
1955 1955 depends on FEC
1956 1956 help
1957 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 1961 config FEC_MPC52xx
1961 1962 tristate "MPC52xx FEC driver"
... ... @@ -17,6 +17,8 @@
17 17 *
18 18 * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
19 19 * Copyright (c) 2004-2006 Macq Electronique SA.
  20 + *
  21 + * Copyright (C) 2010 Freescale Semiconductor, Inc.
20 22 */
21 23  
22 24 #include <linux/module.h>
23 25  
24 26  
... ... @@ -45,20 +47,36 @@
45 47  
46 48 #include <asm/cacheflush.h>
47 49  
48   -#ifndef CONFIG_ARCH_MXC
  50 +#ifndef CONFIG_ARM
49 51 #include <asm/coldfire.h>
50 52 #include <asm/mcfsim.h>
51 53 #endif
52 54  
53 55 #include "fec.h"
54 56  
55   -#ifdef CONFIG_ARCH_MXC
56   -#include <mach/hardware.h>
  57 +#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
57 58 #define FEC_ALIGNMENT 0xf
58 59 #else
59 60 #define FEC_ALIGNMENT 0x3
60 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 80 static unsigned char macaddr[ETH_ALEN];
63 81 module_param_array(macaddr, byte, NULL, 0);
64 82 MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
... ... @@ -129,7 +147,8 @@
129 147 * account when setting it.
130 148 */
131 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 152 #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
134 153 #else
135 154 #define OPT_FRAME_SIZE 0
136 155  
... ... @@ -208,10 +227,23 @@
208 227 /* Transmitter timeout */
209 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 241 static netdev_tx_t
212 242 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
213 243 {
214 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 247 struct bufdesc *bdp;
216 248 void *bufaddr;
217 249 unsigned short status;
... ... @@ -256,6 +288,14 @@
256 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 299 /* Save skb pointer */
260 300 fep->tx_skbuff[fep->skb_cur] = skb;
261 301  
... ... @@ -424,6 +464,8 @@
424 464 fec_enet_rx(struct net_device *dev)
425 465 {
426 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 469 struct bufdesc *bdp;
428 470 unsigned short status;
429 471 struct sk_buff *skb;
... ... @@ -487,6 +529,9 @@
487 529 dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
488 530 DMA_FROM_DEVICE);
489 531  
  532 + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
  533 + swap_buffer(data, pkt_len);
  534 +
490 535 /* This does 16 byte alignment, exactly what we need.
491 536 * The packet length includes FCS, but we don't want to
492 537 * include that when passing upstream as it messes up
... ... @@ -689,6 +734,7 @@
689 734 char mdio_bus_id[MII_BUS_ID_SIZE];
690 735 char phy_name[MII_BUS_ID_SIZE + 3];
691 736 int phy_id;
  737 + int dev_id = fep->pdev->id;
692 738  
693 739 fep->phy_dev = NULL;
694 740  
... ... @@ -700,6 +746,8 @@
700 746 continue;
701 747 if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)
702 748 continue;
  749 + if (dev_id--)
  750 + continue;
703 751 strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);
704 752 break;
705 753 }
706 754  
707 755  
... ... @@ -737,10 +785,35 @@
737 785  
738 786 static int fec_enet_mii_init(struct platform_device *pdev)
739 787 {
  788 + static struct mii_bus *fec0_mii_bus;
740 789 struct net_device *dev = platform_get_drvdata(pdev);
741 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 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 817 fep->mii_timeout = 0;
745 818  
746 819 /*
... ... @@ -777,6 +850,10 @@
777 850 if (mdiobus_register(fep->mii_bus))
778 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 857 return 0;
781 858  
782 859 err_out_free_mdio_irq:
783 860  
784 861  
... ... @@ -1148,12 +1225,25 @@
1148 1225 fec_restart(struct net_device *dev, int duplex)
1149 1226 {
1150 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 1230 int i;
  1231 + u32 val, temp_mac[2];
1152 1232  
1153 1233 /* Whack a reset. We should wait for this. */
1154 1234 writel(1, fep->hwp + FEC_ECNTRL);
1155 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 1247 /* Clear any outstanding interrupt. */
1158 1248 writel(0xffc00000, fep->hwp + FEC_IEVENT);
1159 1249  
1160 1250  
1161 1251  
1162 1252  
1163 1253  
... ... @@ -1200,20 +1290,45 @@
1200 1290 /* Set MII speed */
1201 1291 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
1202 1292  
  1293 + /*
  1294 + * The phy interface and speed need to get configured
  1295 + * differently on enet-mac.
  1296 + */
  1297 + if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
  1298 + val = readl(fep->hwp + FEC_R_CNTRL);
  1299 +
  1300 + /* MII or RMII */
  1301 + if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
  1302 + val |= (1 << 8);
  1303 + else
  1304 + val &= ~(1 << 8);
  1305 +
  1306 + /* 10M or 100M */
  1307 + if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
  1308 + val &= ~(1 << 9);
  1309 + else
  1310 + val |= (1 << 9);
  1311 +
  1312 + writel(val, fep->hwp + FEC_R_CNTRL);
  1313 + } else {
1203 1314 #ifdef FEC_MIIGSK_ENR
1204   - if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
1205   - /* disable the gasket and wait */
1206   - writel(0, fep->hwp + FEC_MIIGSK_ENR);
1207   - while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
1208   - udelay(1);
  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);
1209 1320  
1210   - /* configure the gasket: RMII, 50 MHz, no loopback, no echo */
1211   - writel(1, fep->hwp + FEC_MIIGSK_CFGR);
  1321 + /*
  1322 + * configure the gasket:
  1323 + * RMII, 50 MHz, no loopback, no echo
  1324 + */
  1325 + writel(1, fep->hwp + FEC_MIIGSK_CFGR);
1212 1326  
1213   - /* re-enable the gasket */
1214   - writel(2, fep->hwp + FEC_MIIGSK_ENR);
1215   - }
  1327 + /* re-enable the gasket */
  1328 + writel(2, fep->hwp + FEC_MIIGSK_ENR);
  1329 + }
1216 1330 #endif
  1331 + }
1217 1332  
1218 1333 /* And last, enable the transmit and receive processing */
1219 1334 writel(2, fep->hwp + FEC_ECNTRL);
1220 1335  
... ... @@ -1410,12 +1525,13 @@
1410 1525  
1411 1526 static struct platform_driver fec_driver = {
1412 1527 .driver = {
1413   - .name = "fec",
  1528 + .name = DRIVER_NAME,
1414 1529 .owner = THIS_MODULE,
1415 1530 #ifdef CONFIG_PM
1416 1531 .pm = &fec_pm_ops,
1417 1532 #endif
1418 1533 },
  1534 + .id_table = fec_devtype,
1419 1535 .probe = fec_probe,
1420 1536 .remove = __devexit_p(fec_drv_remove),
1421 1537 };
... ... @@ -14,7 +14,8 @@
14 14 /****************************************************************************/
15 15  
16 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 20 * Just figures, Motorola would have to change the offsets for
20 21 * registers in the same peripheral device on different models
... ... @@ -78,7 +79,7 @@
78 79 /*
79 80 * Define the buffer descriptor structure.
80 81 */
81   -#ifdef CONFIG_ARCH_MXC
  82 +#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
82 83 struct bufdesc {
83 84 unsigned short cbd_datlen; /* Data length */
84 85 unsigned short cbd_sc; /* Control and status info */