Skip to content

Commit

Permalink
net/fec: add imx6q enet support
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
shawnguo2 authored and davem330 committed Sep 23, 2011
1 parent c828827 commit 230dec6
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 18 deletions.
9 changes: 4 additions & 5 deletions drivers/net/ethernet/freescale/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ config NET_VENDOR_FREESCALE
default y
depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC || \
ARCH_MXC || ARCH_MXS || \
(PPC_MPC52xx && PPC_BESTCOMM)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
Expand All @@ -16,16 +16,15 @@ config NET_VENDOR_FREESCALE

Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about IBM devices. If you say Y, you will be asked for
your specific card in the following questions.
the questions about Freescale devices. If you say Y, you will be
asked for your specific card in the following questions.

if NET_VENDOR_FREESCALE

config FEC
bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \
IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC)
default IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC if ARM
ARCH_MXC || ARCH_MXS)
select PHYLIB
---help---
Say Y here if you want to use the built-in 10/100 Fast ethernet
Expand Down
66 changes: 53 additions & 13 deletions drivers/net/ethernet/freescale/fec.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* Bug fixes and cleanup by Philippe De Muyter ([email protected])
* Copyright (c) 2004-2006 Macq Electronique SA.
*
* Copyright (C) 2010 Freescale Semiconductor, Inc.
* Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
*/

#include <linux/module.h>
Expand Down Expand Up @@ -72,6 +72,8 @@
#define FEC_QUIRK_SWAP_FRAME (1 << 1)
/* Controller uses gasket */
#define FEC_QUIRK_USE_GASKET (1 << 2)
/* Controller has GBIT support */
#define FEC_QUIRK_HAS_GBIT (1 << 3)

static struct platform_device_id fec_devtype[] = {
{
Expand All @@ -87,6 +89,9 @@ static struct platform_device_id fec_devtype[] = {
}, {
.name = "imx28-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
}, {
.name = "imx6q-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
}, {
/* sentinel */
}
Expand All @@ -97,12 +102,14 @@ enum imx_fec_type {
IMX25_FEC = 1, /* runs on i.mx25/50/53 */
IMX27_FEC, /* runs on i.mx27/35/51 */
IMX28_FEC,
IMX6Q_FEC,
};

static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
Expand Down Expand Up @@ -373,6 +380,7 @@ fec_restart(struct net_device *ndev, int duplex)
int i;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
u32 ecntl = 0x2; /* ETHEREN */

/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
Expand Down Expand Up @@ -442,18 +450,23 @@ fec_restart(struct net_device *ndev, int duplex)
/* Enable flow control and length check */
rcntl |= 0x40000000 | 0x00000020;

/* MII or RMII */
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
/* RGMII, RMII or MII */
if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
rcntl |= (1 << 6);
else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
rcntl |= (1 << 8);
else
rcntl &= ~(1 << 8);

/* 10M or 100M */
if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
rcntl &= ~(1 << 9);
else
rcntl |= (1 << 9);

/* 1G, 100M or 10M */
if (fep->phy_dev) {
if (fep->phy_dev->speed == SPEED_1000)
ecntl |= (1 << 5);
else if (fep->phy_dev->speed == SPEED_100)
rcntl &= ~(1 << 9);
else
rcntl |= (1 << 9);
}
} else {
#ifdef FEC_MIIGSK_ENR
if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
Expand All @@ -478,8 +491,15 @@ fec_restart(struct net_device *ndev, int duplex)
}
writel(rcntl, fep->hwp + FEC_R_CNTRL);

if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
/* enable ENET endian swap */
ecntl |= (1 << 8);
/* enable ENET store and forward mode */
writel(1 << 8, fep->hwp + FEC_X_WMRK);
}

/* And last, enable the transmit and receive processing */
writel(2, fep->hwp + FEC_ECNTRL);
writel(ecntl, fep->hwp + FEC_ECNTRL);
writel(0, fep->hwp + FEC_R_DES_ACTIVE);

/* Enable interrupts we wish to service */
Expand All @@ -490,6 +510,8 @@ static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);

/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
Expand All @@ -504,6 +526,10 @@ fec_stop(struct net_device *ndev)
udelay(10);
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);

/* We have to keep ENET enabled to have MII interrupt stay working */
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
writel(2, fep->hwp + FEC_ECNTRL);
}


Expand Down Expand Up @@ -918,6 +944,8 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
Expand Down Expand Up @@ -949,14 +977,18 @@ static int fec_enet_mii_probe(struct net_device *ndev)

snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
fep->phy_interface);
if (IS_ERR(phy_dev)) {
printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
return PTR_ERR(phy_dev);
}

/* mask with MAC supported features */
phy_dev->supported &= PHY_BASIC_FEATURES;
if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
phy_dev->supported &= PHY_GBIT_FEATURES;
else
phy_dev->supported &= PHY_BASIC_FEATURES;

phy_dev->advertising = phy_dev->supported;

fep->phy_dev = phy_dev;
Expand Down Expand Up @@ -1006,8 +1038,16 @@ static int fec_enet_mii_init(struct platform_device *pdev)

/*
* Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
*
* The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
* for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28
* Reference Manual has an error on this, and gets fixed on i.MX6Q
* document.
*/
fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000);
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
fep->phy_speed--;
fep->phy_speed <<= 1;
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);

fep->mii_bus = mdiobus_alloc();
Expand Down

0 comments on commit 230dec6

Please sign in to comment.