aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fec.c
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 /drivers/net/fec.c
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>
Diffstat (limited to 'drivers/net/fec.c')
-rw-r--r--drivers/net/fec.c148
1 files changed, 132 insertions, 16 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 8a1c51f86414..2a71373719ae 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};