@ -18,7 +18,7 @@
* Bug fixes and cleanup by Philippe De Muyter ( phdm @ macqel . be )
* Copyright ( c ) 2004 - 2006 Macq Electronique SA .
*
* Copyright ( C ) 2010 Freescale Semiconductor , Inc .
* Copyright ( C ) 2010 - 2011 Freescale Semiconductor , Inc .
*/
# include <linux/module.h>
@ -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 [ ] = {
{
@ -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 */
}
@ -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 ) ;
@ -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 ) ;
@ -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 ) {
@ -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 */
@ -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 ) {
@ -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 ) ;
}
@ -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 ] ;
@ -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 ;
@ -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 ( ) ;