mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			393 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			393 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From c562ab80fe383e6fa49dbe38257421cf37f0e4b3 Mon Sep 17 00:00:00 2001
 | |
| From: Kurt Mahan <kmahan@freescale.com>
 | |
| Date: Wed, 31 Oct 2007 17:07:25 -0600
 | |
| Subject: [PATCH] MCF5445x FEC support.
 | |
| 
 | |
| LTIBName: m5445x-fec
 | |
| Signed-off-by: Kurt Mahan <kmahan@freescale.com>
 | |
| ---
 | |
|  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 <asm/coldfire.h>
 | |
|  #include <asm/mcfsim.h>
 | |
|  #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<TX_RING_SIZE; i++) {
 | |
|  		if (j >= 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
 |