aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@freescale.com>2011-01-05 16:13:13 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-09 18:42:56 -0500
commitb5680e0b591f2701c5ba7d5fc8f96b55414073c8 (patch)
tree393a02162339aba1c10e6c558b078d82bf6cef96
parentbcc67771ed8ee31cc1f2b1e033ae822b40c72ff9 (diff)
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>
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/fec.c148
-rw-r--r--drivers/net/fec.h5
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
1944config FEC 1944config 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
1953config FEC2 1953config 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
1960config FEC_MPC52xx 1961config 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
70static 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
62static unsigned char macaddr[ETH_ALEN]; 80static unsigned char macaddr[ETH_ALEN];
63module_param_array(macaddr, byte, NULL, 0); 81module_param_array(macaddr, byte, NULL, 0);
64MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); 82MODULE_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
230static 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
211static netdev_tx_t 241static netdev_tx_t
212fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) 242fec_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
424fec_enet_rx(struct net_device *dev) 464fec_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
738static int fec_enet_mii_init(struct platform_device *pdev) 786static 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
782err_out_free_mdio_irq: 859err_out_free_mdio_irq:
@@ -1148,12 +1225,25 @@ static void
1148fec_restart(struct net_device *dev, int duplex) 1225fec_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
1411static struct platform_driver fec_driver = { 1526static 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)
82struct bufdesc { 83struct 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 */