Blackfin: bfin_mac: cleanup MII/PHY functions

Cleanup and rewrite the MII/PHY related functions so that we can reuse the
existing common linux/miiphy.h code and hook into the `mii` command.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Acked-by: Ben Warren <biggerbadderben@gmail.com>
This commit is contained in:
Mike Frysinger 2008-10-14 04:52:00 -04:00
parent 6b310a05f0
commit ac45af4e63
2 changed files with 134 additions and 175 deletions

View file

@ -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;

View file

@ -10,28 +10,8 @@
#define __BFIN_MAC_H__
#define PHYADDR 0x01
#define NO_PHY_REGS 0x20
#define DEFAULT_PHY_PHYID1 0x0007
#define DEFAULT_PHY_PHYID2 0xC0A3
#define PHY_MODECTL 0x00
#define PHY_MODESTAT 0x01
#define PHY_PHYID1 0x02
#define PHY_PHYID2 0x03
#define PHY_ANAR 0x04
#define PHY_ANLPAR 0x05
#define PHY_ANER 0x06
#define PHY_RESET 0x8000
#define PHY_ANEG_EN 0x1000
#define PHY_DUPLEX 0x0100
#define PHY_SPD_SET 0x2000
#define RECV_BUFSIZE (0x614)
typedef volatile u32 reg32;
typedef volatile u16 reg16;
typedef struct ADI_DMA_CONFIG_REG {
u16 b_DMA_EN:1; /* 0 Enabled */
u16 b_WNR:1; /* 1 Direction */
@ -79,11 +59,6 @@ static void bfin_EMAC_halt(struct eth_device *dev);
static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, int length);
static int bfin_EMAC_recv(struct eth_device *dev);
static void PollMdcDone(void);
static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data);
static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr);
static int SetupSystemRegs(int *opmode);
static void bfin_EMAC_setup_addr(bd_t *bd);
#endif