diff options
Diffstat (limited to 'drivers/net/bfin_mac.c')
| -rw-r--r-- | drivers/net/bfin_mac.c | 284 | 
1 files changed, 134 insertions, 150 deletions
| diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index a620fcc13..a622ca174 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -12,6 +12,8 @@  #include <netdev.h>  #include <command.h>  #include <malloc.h> +#include <miiphy.h> +#include <linux/mii.h>  #include <asm/blackfin.h>  #include <asm/mach-common/bits/dma.h> @@ -43,8 +45,6 @@ ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];  static u16 txIdx;		/* index of the current RX buffer */  static u16 rxIdx;		/* index of the current TX buffer */ -u16 PHYregs[NO_PHY_REGS];	/* u16 PHYADDR; */ -  /* DMAx_CONFIG values at DMA Restart */  const ADI_DMA_CONFIG_REG rxdmacfg = {  	.b_DMA_EN  = 1,	/* enabled */ @@ -70,10 +70,38 @@ const ADI_DMA_CONFIG_REG txdmacfg = {  	.b_FLOW    = 7	/* large desc flow */  }; +static int bfin_miiphy_wait(void) +{ +	/* poll the STABUSY bit */ +	while (bfin_read_EMAC_STAADD() & STABUSY) +		continue; +	return 0; +} + +static int bfin_miiphy_read(char *devname, uchar addr, uchar reg, ushort *val) +{ +	if (bfin_miiphy_wait()) +		return 1; +	bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY); +	if (bfin_miiphy_wait()) +		return 1; +	*val = bfin_read_EMAC_STADAT(); +	return 0; +} + +static int bfin_miiphy_write(char *devname, uchar addr, uchar reg, ushort val) +{ +	if (bfin_miiphy_wait()) +		return 1; +	bfin_write_EMAC_STADAT(val); +	bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY); +	return 0; +} +  int bfin_EMAC_initialize(bd_t *bis)  {  	struct eth_device *dev; -	dev = (struct eth_device *)malloc(sizeof(*dev)); +	dev = malloc(sizeof(*dev));  	if (dev == NULL)  		hang(); @@ -89,6 +117,10 @@ int bfin_EMAC_initialize(bd_t *bis)  	eth_register(dev); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +	miiphy_register(dev->name, bfin_miiphy_read, bfin_miiphy_write); +#endif +  	return 0;  } @@ -182,6 +214,100 @@ static int bfin_EMAC_recv(struct eth_device *dev)   *   *************************************************************/ +/* MDC = SCLK / MDC_freq / 2 - 1 */ +#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1) + +static int bfin_miiphy_init(struct eth_device *dev, int *opmode) +{ +	u16 phydat; +	size_t count; + +	/* Enable PHY output */ +	*pVR_CTL |= CLKBUFOE; + +	/* Set all the pins to peripheral mode */ +#ifdef CONFIG_BFIN_MAC_RMII +	/* grab RMII pins */ +# if defined(__ADSPBF51x__) +	*pPORTF_MUX = (*pPORTF_MUX & \ +		~(PORT_x_MUX_3_MASK | PORT_x_MUX_4_MASK | PORT_x_MUX_5_MASK)) | \ +		PORT_x_MUX_3_FUNC_1 | PORT_x_MUX_4_FUNC_1 | PORT_x_MUX_5_FUNC_1; +	*pPORTF_FER |= PF8 | PF9 | PF10 | PF11 | PF12 | PF13 | PF14 | PF15; +	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_1; +	*pPORTG_FER |= PG0 | PG1 | PG2; +# elif defined(__ADSPBF52x__) +	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_6_MASK) | PORT_x_MUX_6_FUNC_2; +	*pPORTG_FER |= PG14 | PG15; +	*pPORTH_MUX = (*pPORTH_MUX & ~(PORT_x_MUX_0_MASK | PORT_x_MUX_1_MASK)) | \ +		PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2; +	*pPORTH_FER |= PH0 | PH1 | PH2 | PH3 | PH4 | PH5 | PH6 | PH7 | PH8; +# else +	*pPORTH_FER |= PH0 | PH1 | PH4 | PH5 | PH6 | PH8 | PH9 | PH14 | PH15; +# endif +#else +	/* grab MII & RMII pins */ +# if defined(__ADSPBF51x__) +	*pPORTF_MUX = (*pPORTF_MUX & \ +		~(PORT_x_MUX_0_MASK | PORT_x_MUX_1_MASK | PORT_x_MUX_3_MASK | PORT_x_MUX_4_MASK | PORT_x_MUX_5_MASK)) | \ +		PORT_x_MUX_0_FUNC_1 | PORT_x_MUX_1_FUNC_1 | PORT_x_MUX_3_FUNC_1 | PORT_x_MUX_4_FUNC_1 | PORT_x_MUX_5_FUNC_1; +	*pPORTF_FER |= PF0 | PF1 | PF2 | PF3 | PF4 | PF5 | PF6 | PF8 | PF9 | PF10 | PF11 | PF12 | PF13 | PF14 | PF15; +	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_1; +	*pPORTG_FER |= PG0 | PG1 | PG2; +# elif defined(__ADSPBF52x__) +	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_6_MASK) | PORT_x_MUX_6_FUNC_2; +	*pPORTG_FER |= PG14 | PG15; +	*pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2 | PORT_x_MUX_2_FUNC_2; +	*pPORTH_FER = -1; /* all pins */ +# else +	*pPORTH_FER = -1; /* all pins */ +# endif +#endif + +	/* Odd word alignment for Receive Frame DMA word */ +	/* Configure checksum support and rcve frame word alignment */ +	bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(2500000))); + +	/* turn on auto-negotiation and wait for link to come up */ +	bfin_miiphy_write(dev->name, PHYADDR, MII_BMCR, BMCR_ANENABLE); +	count = 0; +	while (1) { +		++count; +		if (bfin_miiphy_read(dev->name, PHYADDR, MII_BMSR, &phydat)) +			return -1; +		if (phydat & BMSR_LSTATUS) +			break; +		if (count > 30000) { +			printf("%s: link down, check cable\n", dev->name); +			return -1; +		} +		udelay(100); +	} + +	/* see what kind of link we have */ +	if (bfin_miiphy_read(dev->name, PHYADDR, MII_LPA, &phydat)) +		return -1; +	if (phydat & LPA_DUPLEX) +		*opmode = FDMODE; +	else +		*opmode = 0; + +	bfin_write_EMAC_MMC_CTL(RSTC | CROLL); + +	/* Initialize the TX DMA channel registers */ +	*pDMA2_X_COUNT = 0; +	*pDMA2_X_MODIFY = 4; +	*pDMA2_Y_COUNT = 0; +	*pDMA2_Y_MODIFY = 0; + +	/* Initialize the RX DMA channel registers */ +	*pDMA1_X_COUNT = 0; +	*pDMA1_X_MODIFY = 4; +	*pDMA1_Y_COUNT = 0; +	*pDMA1_Y_MODIFY = 0; + +	return 0; +} +  static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)  {  	u32 opmode; @@ -192,14 +318,14 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)  	txIdx = 0;  	rxIdx = 0; -/* Initialize System Register */ -	if (SetupSystemRegs(&dat) < 0) +	/* Initialize System Register */ +	if (bfin_miiphy_init(dev, &dat) < 0)  		return -1; -/* Initialize EMAC address */ +	/* Initialize EMAC address */  	bfin_EMAC_setup_addr(bd); -/* Initialize TX and RX buffer */ +	/* Initialize TX and RX buffer */  	for (i = 0; i < PKTBUFSRX; i++) {  		rxbuf[i] = SetupRxBuffer(i);  		if (i > 0) { @@ -226,7 +352,7 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)  	*pDMA1_CONFIG = *((u16 *) (void *)&rxbuf[0]->Dma[0].CONFIG);  	/* Wait MII done */ -	PollMdcDone(); +	bfin_miiphy_wait();  	/* We enable only RX here */  	/* ASTP   : Enable Automatic Pad Stripping @@ -271,148 +397,6 @@ void bfin_EMAC_setup_addr(bd_t *bd)  		bd->bi_enetaddr[5] << 8;  } -static void PollMdcDone(void) -{ -	/* poll the STABUSY bit */ -	while (*pEMAC_STAADD & STABUSY) ; -} - -static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data) -{ -	PollMdcDone(); - -	*pEMAC_STADAT = Data; - -	*pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | -	    STAOP | STAIE | STABUSY; -} - -/********************************************************************************* - *		Read an off-chip register in a PHY through the MDC/MDIO port     * - *********************************************************************************/ -static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr) -{ -	u16 Data; - -	PollMdcDone(); - -	*pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | -	    STAIE | STABUSY; - -	PollMdcDone(); - -	Data = (u16) * pEMAC_STADAT; - -	PHYregs[RegAddr] = Data;	/* save shadow copy */ - -	return Data; -} - -#if 0 /* dead code ? */ -static void SoftResetPHY(void) -{ -	u16 phydat; -	/* set the reset bit */ -	WrPHYReg(PHYADDR, PHY_MODECTL, PHY_RESET); -	/* and clear it again */ -	WrPHYReg(PHYADDR, PHY_MODECTL, 0x0000); -	do { -		/* poll until reset is complete */ -		phydat = RdPHYReg(PHYADDR, PHY_MODECTL); -	} while ((phydat & PHY_RESET) != 0); -} -#endif - -/* MDC = SCLK / MDC_freq / 2 - 1 */ -#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1) - -static int SetupSystemRegs(int *opmode) -{ -	u16 phydat; -	int count = 0; -	/* Enable PHY output */ -	*pVR_CTL |= CLKBUFOE; -	/* Set all the pins to peripheral mode */ - -#ifdef CONFIG_BFIN_MAC_RMII -	/* grab RMII pins */ -# if defined(__ADSPBF51x__) -	*pPORTF_MUX = (*pPORTF_MUX & \ -		~(PORT_x_MUX_3_MASK | PORT_x_MUX_4_MASK | PORT_x_MUX_5_MASK)) | \ -		PORT_x_MUX_3_FUNC_1 | PORT_x_MUX_4_FUNC_1 | PORT_x_MUX_5_FUNC_1; -	*pPORTF_FER |= PF8 | PF9 | PF10 | PF11 | PF12 | PF13 | PF14 | PF15; -	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_1; -	*pPORTG_FER |= PG0 | PG1 | PG2; -# elif defined(__ADSPBF52x__) -	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_6_MASK) | PORT_x_MUX_6_FUNC_2; -	*pPORTG_FER |= PG14 | PG15; -	*pPORTH_MUX = (*pPORTH_MUX & ~(PORT_x_MUX_0_MASK | PORT_x_MUX_1_MASK)) | \ -		PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2; -	*pPORTH_FER |= PH0 | PH1 | PH2 | PH3 | PH4 | PH5 | PH6 | PH7 | PH8; -# else -	*pPORTH_FER |= PH0 | PH1 | PH4 | PH5 | PH6 | PH8 | PH9 | PH14 | PH15; -# endif -#else -	/* grab MII & RMII pins */ -# if defined(__ADSPBF51x__) -	*pPORTF_MUX = (*pPORTF_MUX & \ -		~(PORT_x_MUX_0_MASK | PORT_x_MUX_1_MASK | PORT_x_MUX_3_MASK | PORT_x_MUX_4_MASK | PORT_x_MUX_5_MASK)) | \ -		PORT_x_MUX_0_FUNC_1 | PORT_x_MUX_1_FUNC_1 | PORT_x_MUX_3_FUNC_1 | PORT_x_MUX_4_FUNC_1 | PORT_x_MUX_5_FUNC_1; -	*pPORTF_FER |= PF0 | PF1 | PF2 | PF3 | PF4 | PF5 | PF6 | PF8 | PF9 | PF10 | PF11 | PF12 | PF13 | PF14 | PF15; -	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_1; -	*pPORTG_FER |= PG0 | PG1 | PG2; -# elif defined(__ADSPBF52x__) -	*pPORTG_MUX = (*pPORTG_MUX & ~PORT_x_MUX_6_MASK) | PORT_x_MUX_6_FUNC_2; -	*pPORTG_FER |= PG14 | PG15; -	*pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2 | PORT_x_MUX_2_FUNC_2; -	*pPORTH_FER = -1; /* all pins */ -# else -	*pPORTH_FER = -1; /* all pins */ -# endif -#endif - -	/* Odd word alignment for Receive Frame DMA word */ -	/* Configure checksum support and rcve frame word alignment */ -	*pEMAC_SYSCTL = RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(2500000)); -	/* auto negotiation on  */ -	/* full duplex */ -	/* 100 Mbps */ -	phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; -	WrPHYReg(PHYADDR, PHY_MODECTL, phydat); -	do { -		udelay(1000); -		phydat = RdPHYReg(PHYADDR, PHY_MODESTAT); -		if (count > 3000) { -			printf -			    ("Link is down, please check your network connection\n"); -			return -1; -		} -		count++; -	} while (!(phydat & 0x0004)); - -	phydat = RdPHYReg(PHYADDR, PHY_ANLPAR); - -	if ((phydat & 0x0100) || (phydat & 0x0040)) -		*opmode = FDMODE; -	else -		*opmode = 0; - -	*pEMAC_MMC_CTL = RSTC | CROLL; - -	/* Initialize the TX DMA channel registers */ -	*pDMA2_X_COUNT = 0; -	*pDMA2_X_MODIFY = 4; -	*pDMA2_Y_COUNT = 0; -	*pDMA2_Y_MODIFY = 0; - -	/* Initialize the RX DMA channel registers */ -	*pDMA1_X_COUNT = 0; -	*pDMA1_X_MODIFY = 4; -	*pDMA1_Y_COUNT = 0; -	*pDMA1_Y_MODIFY = 0; -	return 0; -} -  ADI_ETHER_BUFFER *SetupRxBuffer(int no)  {  	ADI_ETHER_FRAME_BUFFER *frmbuf; |