From c562ab80fe383e6fa49dbe38257421cf37f0e4b3 Mon Sep 17 00:00:00 2001 From: Kurt Mahan Date: Wed, 31 Oct 2007 17:07:25 -0600 Subject: [PATCH] MCF5445x FEC support. LTIBName: m5445x-fec Signed-off-by: Kurt Mahan --- drivers/net/Kconfig | 8 ++- drivers/net/fec.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/fec.h | 2 +- 3 files changed, 198 insertions(+), 19 deletions(-) --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1973,7 +1973,7 @@ config 68360_ENET config FEC bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x + depends on M523x || M527x || M5272 || M528x || M520x || M54455 help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire processors. @@ -1985,6 +1985,12 @@ config FEC2 Say Y here if you want to use the second built-in 10/100 Fast ethernet controller on some Motorola ColdFire processors. +config FEC_SHARED_PHY + bool "Shared PHY interface(on some ColdFire designs)" + depends on FEC2 + help + Say Y here if both PHYs are controlled via a single channel. + config FEC_MPC52xx tristate "MPC52xx FEC driver" depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -51,7 +51,9 @@ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ + defined(CONFIG_M54455) + #include #include #include "fec.h" @@ -82,6 +84,11 @@ static unsigned int fec_hw[] = { (MCF_MBAR+0x30000), #elif defined(CONFIG_M532x) (MCF_MBAR+0xfc030000), +#elif defined(CONFIG_M54455) + (MCF_MBAR+0xfc030000), +#if defined(CONFIG_FEC2) + (MCF_MBAR+0xfc034000), +#endif #else &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), #endif @@ -172,7 +179,7 @@ typedef struct { * account when setting it. */ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M54455) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -213,6 +220,7 @@ struct fec_enet_private { uint phy_speed; phy_info_t const *phy; struct work_struct phy_task; + volatile fec_t *phy_hwp; uint sequence_done; uint mii_phy_task_queued; @@ -349,7 +357,8 @@ fec_enet_start_xmit(struct sk_buff *skb, if (bdp->cbd_bufaddr & 0x3) { unsigned int index; index = bdp - fep->tx_bd_base; - memcpy(fep->tx_bounce[index], (void *) bdp->cbd_bufaddr, bdp->cbd_datlen); + memcpy(fep->tx_bounce[index], + (void *)skb->data, bdp->cbd_datlen); bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]); } @@ -702,7 +711,7 @@ fec_enet_mii(struct net_device *dev) uint mii_reg; fep = netdev_priv(dev); - ep = fep->hwp; + ep = fep->phy_hwp; mii_reg = ep->fec_mii_data; spin_lock(&fep->lock); @@ -753,7 +762,7 @@ mii_queue(struct net_device *dev, int re mii_tail = mip; } else { mii_head = mii_tail = mip; - fep->hwp->fec_mii_data = regval; + fep->phy_hwp->fec_mii_data = regval; } } else { retval = 1; @@ -1151,8 +1160,7 @@ static phy_info_t const phy_info_ks8721b }; /* ------------------------------------------------------------------------- */ -/* register definitions for the DP83848 */ - +/* register definitions for the DP83848 and DP83849 */ #define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) @@ -1186,27 +1194,50 @@ static void mii_parse_dp8384x_sr2(uint m *s |= PHY_STAT_FAULT; } +static phy_cmd_t const phy_cmd_dp8384x_ack_int[] = { + { mk_mii_end, } + }; + +static phy_cmd_t const phy_cmd_dp8384x_shutdown[] = { + { mk_mii_end, } + }; + static phy_info_t phy_info_dp83848= { - 0x020005c9, - "DP83848", + .id = 0x020005c9, + .name = "DP83848", - (const phy_cmd_t []) { /* config */ + .config = (const phy_cmd_t []) { /* config */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, { mk_mii_end, } }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + .startup = (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, - (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ + .ack_int = phy_cmd_dp8384x_ack_int, + .shutdown = phy_cmd_dp8384x_shutdown, +}; + +static phy_info_t phy_info_dp83849 = { + .id = 0x020005ca, + .name = "DP83849", + + .config = (const phy_cmd_t []) { /* config */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, { mk_mii_end, } }, - (const phy_cmd_t []) { /* shutdown */ + .startup = (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, + .ack_int = phy_cmd_dp8384x_ack_int, + .shutdown = phy_cmd_dp8384x_shutdown, }; /* ------------------------------------------------------------------------- */ @@ -1218,6 +1249,7 @@ static phy_info_t const * const phy_info &phy_info_am79c874, &phy_info_ks8721bl, &phy_info_dp83848, + &phy_info_dp83849, NULL }; @@ -1799,6 +1831,138 @@ static void __inline__ fec_uncache(unsig /* ------------------------------------------------------------------------- */ +#elif defined(CONFIG_M54455) +/* + * Code specific for M54455 + */ + +static void __inline__ fec_request_intrs(struct net_device *dev) +{ + struct fec_enet_private *fep; + int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 36 }, + { "fec(TXB)", 37 }, + { "fec(TXFIFO)", 38 }, + { "fec(TXCR)", 39 }, + { "fec(RXF)", 40 }, + { "fec(RXB)", 41 }, + { "fec(MII)", 42 }, + { "fec(LC)", 43 }, + { "fec(HBERR)", 44 }, + { "fec(GRA)", 45 }, + { "fec(EBERR)", 46 }, + { "fec(BABT)", 47 }, + { "fec(BABR)", 48 }, + { NULL }, + }; + + fep = netdev_priv(dev); + b = (fep->index) ? 77 : 64; + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq, fec_enet_interrupt, 0, + idp->name, dev) != 0) + printk(KERN_ERR "FEC: Could not alloc %s IRQ(%d)!\n", + idp->name, b+idp->irq); + } + + if (fep->index) { + /* Configure RMII */ + MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & + MCF_GPIO_PAR_FEC_FEC1_MASK) | + MCF_GPIO_PAR_FEC_FEC1_RMII_GPIO; + } else { + /* Configure RMII */ + MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & + MCF_GPIO_PAR_FEC_FEC0_MASK) | + MCF_GPIO_PAR_FEC_FEC0_RMII_GPIO; + } + + /* Set up gpio outputs for MII lines on FEC0 */ + MCF_GPIO_PAR_FECI2C |= (0 | + MCF_GPIO_PAR_FECI2C_MDIO0_MDIO0 | + MCF_GPIO_PAR_FECI2C_MDC0_MDC0); +} + +static void __inline__ fec_set_mii(struct net_device *dev, + struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + + fecp = fep->hwp; + fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; + fecp->fec_x_cntrl = 0x00; + + /* + * Set MII speed to 2.5 MHz + */ + fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; + fecp->fec_mii_speed = fep->phy_speed; + + fec_restart(dev, 0); +} + +static void __inline__ fec_get_mac(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; + unsigned char *iap, tmpaddr[ETH_ALEN]; + + fecp = fep->hwp; + + if (FEC_FLASHMAC) { + /* + * Get MAC address from FLASH. + * If it is all 1's or 0's, use the default. + */ + iap = FEC_FLASHMAC; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && + (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = fec_mac_default; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { + *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; + *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + + memcpy(dev->dev_addr, iap, ETH_ALEN); + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + + fep->index; +} + +static void __inline__ fec_enable_phy_intr(void) +{ +} + +static void __inline__ fec_disable_phy_intr(void) +{ +} + +static void __inline__ fec_phy_ack_intr(void) +{ +} + +static void __inline__ fec_localhw_setup(void) +{ +} + +static void __inline__ fec_uncache(unsigned long addr) +{ +} + +/* ------------------------------------------------------------------------- */ + #else @@ -2305,7 +2469,7 @@ fec_set_mac_address(struct net_device *d } -/* Initialize the FEC Ethernet on 860T (or ColdFire 5272). +/* Initialize the FEC Ethernet. */ /* * XXX: We need to clean up on failure exits here. @@ -2326,7 +2490,7 @@ int __init fec_enet_init(struct net_devi /* Allocate memory for buffer descriptors. */ - mem_addr = __get_free_page(GFP_KERNEL); + mem_addr = __get_free_page(GFP_DMA); if (mem_addr == 0) { printk("FEC: allocate descriptor memory failed?\n"); return -ENOMEM; @@ -2339,6 +2503,11 @@ int __init fec_enet_init(struct net_devi fep->index = index; fep->hwp = fecp; fep->netdev = dev; +#ifdef CONFIG_FEC_SHARED_PHY + fep->phy_hwp = (volatile fec_t *) fec_hw[index & ~1]; +#else + fep->phy_hwp = fecp; +#endif /* Whack a reset. We should wait for this. */ @@ -2375,7 +2544,7 @@ int __init fec_enet_init(struct net_devi /* Allocate a page. */ - mem_addr = __get_free_page(GFP_KERNEL); + mem_addr = __get_free_page(GFP_DMA); /* XXX: missing check for allocation failure */ fec_uncache(mem_addr); @@ -2400,7 +2569,7 @@ int __init fec_enet_init(struct net_devi bdp = fep->tx_bd_base; for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { - mem_addr = __get_free_page(GFP_KERNEL); + mem_addr = __get_free_page(GFP_DMA); j = 1; } else { mem_addr += FEC_ENET_TX_FRSIZE; @@ -2462,7 +2631,11 @@ int __init fec_enet_init(struct net_devi * remainder of the interface. */ fep->phy_id_done = 0; +#ifndef CONFIG_FEC_SHARED_PHY fep->phy_addr = 0; +#else + fep->phy_addr = fep->index; +#endif mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); index++; --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -14,7 +14,7 @@ /****************************************************************************/ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M54455) /* * Just figures, Motorola would have to change the offsets for * registers in the same peripheral device on different models