diff options
Diffstat (limited to 'cpu/mpc85xx')
-rw-r--r-- | cpu/mpc85xx/tsec.c | 129 | ||||
-rw-r--r-- | cpu/mpc85xx/tsec.h | 30 |
2 files changed, 127 insertions, 32 deletions
diff --git a/cpu/mpc85xx/tsec.c b/cpu/mpc85xx/tsec.c index e9ca340..2d0517a 100644 --- a/cpu/mpc85xx/tsec.c +++ b/cpu/mpc85xx/tsec.c @@ -49,9 +49,12 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length); static int tsec_recv(struct eth_device* dev); static int tsec_init(struct eth_device* dev, bd_t * bd); static void tsec_halt(struct eth_device* dev); -static void init_registers(volatile tsec_t *regs); -static void startup_tsec(volatile tsec_t *regs); -static void init_phy(volatile tsec_t *regs); +static void init_registers(tsec_t *regs); +static void startup_tsec(tsec_t *regs); +static void init_phy(tsec_t *regs); +uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset); + +static int phy_id = -1; /* Initialize device structure. returns 0 on failure, 1 on * success */ @@ -59,6 +62,7 @@ int tsec_initialize(bd_t *bis) { struct eth_device* dev; int i; + tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); dev = (struct eth_device*) malloc(sizeof *dev); @@ -67,7 +71,7 @@ int tsec_initialize(bd_t *bis) memset(dev, 0, sizeof *dev); - sprintf(dev->name, "MOTOROLA ETHERNET"); + sprintf(dev->name, "MOTO ETHERNET"); dev->iobase = 0; dev->priv = 0; dev->init = tsec_init; @@ -81,6 +85,45 @@ int tsec_initialize(bd_t *bis) eth_register(dev); + /* Reconfigure the PHY to advertise everything here + * so that it works with both gigabit and 10/100 */ +#ifdef CONFIG_PHY_M88E1011 + /* Assign a Physical address to the TBI */ + regs->tbipa=TBIPA_VALUE; + + /* reset the management interface */ + regs->miimcfg=MIIMCFG_RESET; + + regs->miimcfg=MIIMCFG_INIT_VALUE; + + /* Wait until the bus is free */ + while(regs->miimind & MIIMIND_BUSY); + + /* Locate PHYs. Skip TBIPA, which we know is 31. + */ + for (i=0; i<31; i++) { + if (read_phy_reg(regs, i, 2) == 0x141) { + if (phy_id == -1) + phy_id = i; +#ifdef TSEC_DEBUG + printf("Found Marvell PHY at 0x%02x\n", i); +#endif + } + } +#ifdef TSEC_DEBUG + printf("Using PHY ID 0x%02x\n", phy_id); +#endif + write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET); + + RESET_ERRATA(regs, phy_id); + + /* Configure the PHY to advertise gbit and 10/100 */ + write_phy_reg(regs, phy_id, MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT); + write_phy_reg(regs, phy_id, MIIM_ANAR, MIIM_ANAR_INIT); + + /* Reset the PHY so the new settings take effect */ + write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET); +#endif return 1; } @@ -89,12 +132,12 @@ int tsec_initialize(bd_t *bis) * and brings the interface up */ int tsec_init(struct eth_device* dev, bd_t * bd) { - volatile tsec_t *regs; + tsec_t *regs; uint tempval; char tmpbuf[MAC_ADDR_LEN]; int i; - regs = (volatile tsec_t *)(TSEC_BASE_ADDR); + regs = (tsec_t *)(TSEC_BASE_ADDR); /* Make sure the controller is stopped */ tsec_halt(dev); @@ -146,7 +189,7 @@ int tsec_init(struct eth_device* dev, bd_t * bd) /* and then passes those bits on to the variable specified in */ /* value */ /* Before it does the read, it needs to clear the command field */ -uint read_phy_reg(volatile tsec_t *regbase, uint phyid, uint offset) +uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset) { uint value; @@ -173,7 +216,7 @@ uint read_phy_reg(volatile tsec_t *regbase, uint phyid, uint offset) } /* Setup the PHY */ -static void init_phy(volatile tsec_t *regs) +static void init_phy(tsec_t *regs) { uint testval; unsigned int timeout = TSEC_TIMEOUT; @@ -198,17 +241,17 @@ static void init_phy(volatile tsec_t *regs) #endif /* Set the PHY to gigabit, full duplex, Auto-negotiate */ - write_phy_reg(regs, 0, MIIM_CONTROL, MIIM_CONTROL_INIT); + write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_INIT); - /* Wait until TBI_STATUS indicates AN is done */ + /* Wait until STATUS indicates Auto-Negotiation is done */ DBGPRINT("Waiting for Auto-negotiation to complete\n"); - testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS); + testval=read_phy_reg(regs, phy_id, MIIM_STATUS); - while((!(testval & MIIM_TBI_STATUS_AN_DONE))&& timeout--) { - testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS); + while((!(testval & MIIM_STATUS_AN_DONE))&& timeout--) { + testval=read_phy_reg(regs, phy_id, MIIM_STATUS); } - if(testval & MIIM_TBI_STATUS_AN_DONE) + if(testval & MIIM_STATUS_AN_DONE) DBGPRINT("Auto-negotiation done\n"); else DBGPRINT("Auto-negotiation timed-out.\n"); @@ -216,7 +259,7 @@ static void init_phy(volatile tsec_t *regs) #ifdef CONFIG_PHY_CIS8201 /* Find out what duplexity (duplicity?) we have */ /* Read it twice to make sure */ - testval=read_phy_reg(regs, 0, MIIM_AUX_CONSTAT); + testval=read_phy_reg(regs, phy_id, MIIM_AUX_CONSTAT); if(testval & MIIM_AUXCONSTAT_DUPLEX) { DBGPRINT("Enet starting in full duplex\n"); @@ -246,17 +289,17 @@ static void init_phy(volatile tsec_t *regs) #ifdef CONFIG_PHY_M88E1011 /* Read the PHY to see what speed and duplex we are */ - testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS); + testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS); timeout = TSEC_TIMEOUT; while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) { - testval = read_phy_reg(regs,0,MIIM_PHY_STATUS); + testval = read_phy_reg(regs,phy_id,MIIM_PHY_STATUS); } if(!(testval & MIIM_PHYSTAT_SPDDONE)) DBGPRINT("Enet: Speed not resolved\n"); - testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS); + testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS); if(testval & MIIM_PHYSTAT_DUPLEX) { DBGPRINT("Enet starting in Full Duplex\n"); regs->maccfg2 |= MACCFG2_FULL_DUPLEX; @@ -280,7 +323,7 @@ static void init_phy(volatile tsec_t *regs) } -static void init_registers(volatile tsec_t *regs) +static void init_registers(tsec_t *regs) { /* Clear IEVENT */ regs->ievent = IEVENT_INIT_CLEAR; @@ -322,7 +365,7 @@ static void init_registers(volatile tsec_t *regs) } -static void startup_tsec(volatile tsec_t *regs) +static void startup_tsec(tsec_t *regs) { int i; @@ -363,7 +406,7 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length) { int i; int result = 0; - volatile tsec_t * regs = (volatile tsec_t *)(TSEC_BASE_ADDR); + tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR); /* Find an empty buffer descriptor */ for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) { @@ -397,7 +440,7 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length) static int tsec_recv(struct eth_device* dev) { int length; - volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR); + tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { @@ -428,7 +471,7 @@ static int tsec_recv(struct eth_device* dev) static void tsec_halt(struct eth_device* dev) { - volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR); + tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); @@ -438,4 +481,44 @@ static void tsec_halt(struct eth_device* dev) regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); } + +#ifndef CONFIG_BITBANGMII +/* + * Read a MII PHY register. + * + * Returns: + * 0 on success + */ +int miiphy_read(unsigned char addr, + unsigned char reg, + unsigned short *value) +{ + tsec_t *regs; + unsigned short rv; + + regs = (tsec_t *)(TSEC_BASE_ADDR); + rv = (unsigned short)read_phy_reg(regs, addr, reg); + *value = rv; + + return 0; +} + +/* + * Write a MII PHY register. + * + * Returns: + * 0 on success + */ +int miiphy_write(unsigned char addr, + unsigned char reg, + unsigned short value) +{ + tsec_t *regs; + + regs = (tsec_t *)(TSEC_BASE_ADDR); + write_phy_reg(regs, addr, reg, value); + + return 0; +} +#endif /* CONFIG_BITBANGMII */ #endif /* CONFIG_TSEC_ENET */ diff --git a/cpu/mpc85xx/tsec.h b/cpu/mpc85xx/tsec.h index cfcfd39..db4169c 100644 --- a/cpu/mpc85xx/tsec.h +++ b/cpu/mpc85xx/tsec.h @@ -19,6 +19,9 @@ #include <net.h> #include <mpc85xx.h> +/* TSEC1 is offset 0x24000, TSEC2 is offset 0x25000 +#define TSEC_BASE_ADDR (CFG_IMMR + 0x25000) +*/ #define TSEC_BASE_ADDR (CFG_IMMR + 0x24000) #define TSEC_MEM_SIZE 0x01000 @@ -56,16 +59,16 @@ #define MIIMIND_BUSY 0x00000001 #define MIIMIND_NOTVALID 0x00000004 -#define MIIM_TBICON 0x11 -#define MIIM_TBICON_GMII 0x00000010 -#define MIIM_TBICON_AN 0x00000100 - #define MIIM_CONTROL 0x00 #define MIIM_CONTROL_INIT 0x00001140 #define MIIM_ANEN 0x00001000 +#define MIIM_CONTROL_RESET 0x00009140 + +#define MIIM_STATUS 0x1 +#define MIIM_STATUS_AN_DONE 0x00000020 -#define MIIM_TBI_STATUS 0x1 -#define MIIM_TBI_STATUS_AN_DONE 0x00000020 +#define MIIM_GBIT_CONTROL 0x9 +#define MIIM_GBIT_CONTROL_INIT 0xe00 #define MIIM_TBI_ANEX 0x6 #define MIIM_TBI_ANEX_NP 0x00000004 @@ -89,11 +92,11 @@ #endif #ifdef CONFIG_PHY_M88E1011 -#define MIIM_ANAR 0x04 -#define MIIM_ANAR_ADVERTISEMENT 0x01e1 +#define MIIM_ANAR 0x4 +#define MIIM_ANAR_INIT 0x1e1 #define MIIM_GBIT_CON 0x09 -#define MIIM_GBIT_CON_ADVERT 0x1e00 +#define MIIM_GBIT_CON_ADVERT 0x0e00 #define MIIM_PHY_STATUS 0x11 #define MIIM_PHYSTAT_SPEED 0xc000 @@ -130,6 +133,15 @@ } while(0) +/* This works around errata in reseting the PHY */ +#define RESET_ERRATA(regs, ID) do { \ + write_phy_reg(regs, (ID), 0x1d, 0x1f); \ + write_phy_reg(regs, (ID), 0x1e, 0x200c); \ + write_phy_reg(regs, (ID), 0x1d, 0x5); \ + write_phy_reg(regs, (ID), 0x1e, 0x0); \ + write_phy_reg(regs, (ID), 0x1e, 0x100); \ +} while(0) + #define IEVENT_INIT_CLEAR 0xffffffff #define IEVENT_BABR 0x80000000 #define IEVENT_RXC 0x40000000 |