From a32a6be28fbbec19b6581609844ca3ec313b9d81 Mon Sep 17 00:00:00 2001 From: Mingkai Hu Date: Thu, 27 Jan 2011 12:52:45 +0800 Subject: tsec: use IO accessors for IO accesses Signed-off-by: Mingkai Hu Acked-by: Andy Fleming Signed-off-by: Kumar Gala Acked-by: Detlev Zundel --- drivers/net/tsec.c | 249 +++++++++++++++++++++++++++-------------------------- 1 file changed, 126 insertions(+), 123 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 9a91b9e0b85..a2705e1cab7 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -5,7 +5,7 @@ * terms of the GNU Public License, Version 2, incorporated * herein by reference. * - * Copyright 2004-2010 Freescale Semiconductor, Inc. + * Copyright 2004-2011 Freescale Semiconductor, Inc. * (C) Copyright 2003, Motorola, Inc. * author Andy Fleming * @@ -50,7 +50,7 @@ static int tsec_recv(struct eth_device *dev); static int tsec_init(struct eth_device *dev, bd_t * bd); static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info); static void tsec_halt(struct eth_device *dev); -static void init_registers(volatile tsec_t * regs); +static void init_registers(tsec_t *regs); static void startup_tsec(struct eth_device *dev); static int init_phy(struct eth_device *dev); void write_phy_reg(struct tsec_private *priv, uint regnum, uint value); @@ -166,9 +166,9 @@ static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info) eth_register(dev); /* Reset the MAC */ - priv->regs->maccfg1 |= MACCFG1_SOFT_RESET; + setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ - priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); + clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ && !defined(BITBANGMII) @@ -190,16 +190,16 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) char tmpbuf[MAC_ADDR_LEN]; int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; /* Make sure the controller is stopped */ tsec_halt(dev); /* Init MACCFG2. Defaults to GMII */ - regs->maccfg2 = MACCFG2_INIT_SETTINGS; + out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); /* Init ECNTRL */ - regs->ecntrl = ECNTRL_INIT_SETTINGS; + out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); /* Copy the station address into the address registers. * Backwards, because little endian MACS are dumb */ @@ -209,11 +209,11 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | tmpbuf[3]; - regs->macstnaddr1 = tempval; + out_be32(®s->macstnaddr1, tempval); tempval = *((uint *) (tmpbuf + 4)); - regs->macstnaddr2 = tempval; + out_be32(®s->macstnaddr2, tempval); /* reset the indices to zero */ rxIdx = 0; @@ -230,17 +230,17 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) } /* Writes the given phy's reg with value, using the specified MDIO regs */ -static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr, +static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr, uint reg, uint value) { int timeout = 1000000; - phyregs->miimadd = (addr << 8) | reg; - phyregs->miimcon = value; - asm("sync"); + out_be32(&phyregs->miimadd, (addr << 8) | reg); + out_be32(&phyregs->miimcon, value); timeout = 1000000; - while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ; + while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) + ; } @@ -254,28 +254,26 @@ static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr, * notvalid bit cleared), and the bus to cease activity (miimind * busy bit cleared), and then returns the value */ -static uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs, - uint phyid, uint regnum) +static uint tsec_local_mdio_read(tsec_mdio_t *phyregs, uint phyid, uint regnum) { uint value; /* Put the address of the phy, and the register * number into MIIMADD */ - phyregs->miimadd = (phyid << 8) | regnum; + out_be32(&phyregs->miimadd, (phyid << 8) | regnum); /* Clear the command register, and wait */ - phyregs->miimcom = 0; - asm("sync"); + out_be32(&phyregs->miimcom, 0); /* Initiate a read command, and wait */ - phyregs->miimcom = MIIM_READ_COMMAND; - asm("sync"); + out_be32(&phyregs->miimcom, MIIM_READ_COMMAND); /* Wait for the the indication that the read is done */ - while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ; + while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))) + ; /* Grab the value read from the PHY */ - value = phyregs->miimstat; + value = in_be32(&phyregs->miimstat); return value; } @@ -321,18 +319,16 @@ static int init_phy(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; struct phy_info *curphy; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; /* Assign a Physical address to the TBI */ - regs->tbipa = CONFIG_SYS_TBIPA_VALUE; - asm("sync"); + out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); /* Reset MII (due to new addresses) */ - priv->phyregs->miimcfg = MIIMCFG_RESET; - asm("sync"); - priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE; - asm("sync"); - while (priv->phyregs->miimind & MIIMIND_BUSY) ; + out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET); + out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE); + while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) + ; /* Get the cmd structure corresponding to the attached * PHY */ @@ -345,7 +341,7 @@ static int init_phy(struct eth_device *dev) return 0; } - if (regs->ecntrl & ECNTRL_SGMII_MODE) + if (in_be32(®s->ecntrl) & ECNTRL_SGMII_MODE) tsec_configure_serdes(priv); priv->phyinfo = curphy; @@ -838,16 +834,16 @@ static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv) static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv) { uint phyid; - volatile tsec_mdio_t *regbase = priv->phyregs; + tsec_mdio_t *regbase = priv->phyregs; int timeout = 1000000; for (phyid = 0; phyid < 4; phyid++) { - regbase->miimadd = (phyid << 8) | mii_reg; - regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT; - asm("sync"); + out_be32(®base->miimadd, (phyid << 8) | mii_reg); + out_be32(®base->miimcon, MIIM_CIS8204_SLEDCON_INIT); timeout = 1000000; - while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ; + while ((in_be32(®base->miimind) & MIIMIND_BUSY) && timeout--) + ; } return MIIM_CIS8204_SLEDCON_INIT; @@ -874,45 +870,45 @@ static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv) * those we don't care about (unless zero is bad, in which case, * choose a more appropriate value) */ -static void init_registers(volatile tsec_t * regs) +static void init_registers(tsec_t *regs) { /* Clear IEVENT */ - regs->ievent = IEVENT_INIT_CLEAR; - - regs->imask = IMASK_INIT_CLEAR; - - regs->hash.iaddr0 = 0; - regs->hash.iaddr1 = 0; - regs->hash.iaddr2 = 0; - regs->hash.iaddr3 = 0; - regs->hash.iaddr4 = 0; - regs->hash.iaddr5 = 0; - regs->hash.iaddr6 = 0; - regs->hash.iaddr7 = 0; - - regs->hash.gaddr0 = 0; - regs->hash.gaddr1 = 0; - regs->hash.gaddr2 = 0; - regs->hash.gaddr3 = 0; - regs->hash.gaddr4 = 0; - regs->hash.gaddr5 = 0; - regs->hash.gaddr6 = 0; - regs->hash.gaddr7 = 0; - - regs->rctrl = 0x00000000; + out_be32(®s->ievent, IEVENT_INIT_CLEAR); + + out_be32(®s->imask, IMASK_INIT_CLEAR); + + out_be32(®s->hash.iaddr0, 0); + out_be32(®s->hash.iaddr1, 0); + out_be32(®s->hash.iaddr2, 0); + out_be32(®s->hash.iaddr3, 0); + out_be32(®s->hash.iaddr4, 0); + out_be32(®s->hash.iaddr5, 0); + out_be32(®s->hash.iaddr6, 0); + out_be32(®s->hash.iaddr7, 0); + + out_be32(®s->hash.gaddr0, 0); + out_be32(®s->hash.gaddr1, 0); + out_be32(®s->hash.gaddr2, 0); + out_be32(®s->hash.gaddr3, 0); + out_be32(®s->hash.gaddr4, 0); + out_be32(®s->hash.gaddr5, 0); + out_be32(®s->hash.gaddr6, 0); + out_be32(®s->hash.gaddr7, 0); + + out_be32(®s->rctrl, 0x00000000); /* Init RMON mib registers */ memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); - regs->rmon.cam1 = 0xffffffff; - regs->rmon.cam2 = 0xffffffff; + out_be32(®s->rmon.cam1, 0xffffffff); + out_be32(®s->rmon.cam2, 0xffffffff); - regs->mrblr = MRBLR_INIT_SETTINGS; + out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); - regs->minflr = MINFLR_INIT_SETTINGS; + out_be32(®s->minflr, MINFLR_INIT_SETTINGS); - regs->attr = ATTR_INIT_SETTINGS; - regs->attreli = ATTRELI_INIT_SETTINGS; + out_be32(®s->attr, ATTR_INIT_SETTINGS); + out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); } @@ -922,44 +918,49 @@ static void init_registers(volatile tsec_t * regs) static void adjust_link(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; + u32 ecntrl, maccfg2; - if (priv->link) { - if (priv->duplexity != 0) - regs->maccfg2 |= MACCFG2_FULL_DUPLEX; - else - regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX); + if (!priv->link) { + printf("%s: No link.\n", dev->name); + return; + } - switch (priv->speed) { - case 1000: - regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF)) - | MACCFG2_GMII); - break; - case 100: - case 10: - regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF)) - | MACCFG2_MII); + /* clear all bits relative with interface mode */ + ecntrl = in_be32(®s->ecntrl); + ecntrl &= ~ECNTRL_R100; - /* Set R100 bit in all modes although - * it is only used in RGMII mode - */ - if (priv->speed == 100) - regs->ecntrl |= ECNTRL_R100; - else - regs->ecntrl &= ~(ECNTRL_R100); - break; - default: - printf("%s: Speed was bad\n", dev->name); - break; - } + maccfg2 = in_be32(®s->maccfg2); + maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); - printf("Speed: %d, %s duplex%s\n", priv->speed, - (priv->duplexity) ? "full" : "half", - (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); + if (priv->duplexity) + maccfg2 |= MACCFG2_FULL_DUPLEX; - } else { - printf("%s: No link.\n", dev->name); + switch (priv->speed) { + case 1000: + maccfg2 |= MACCFG2_GMII; + break; + case 100: + case 10: + maccfg2 |= MACCFG2_MII; + + /* Set R100 bit in all modes although + * it is only used in RGMII mode + */ + if (priv->speed == 100) + ecntrl |= ECNTRL_R100; + break; + default: + printf("%s: Speed was bad\n", dev->name); + break; } + + out_be32(®s->ecntrl, ecntrl); + out_be32(®s->maccfg2, maccfg2); + + printf("Speed: %d, %s duplex%s\n", priv->speed, + (priv->duplexity) ? "full" : "half", + (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); } /* Set up the buffers and their descriptors, and bring up the @@ -969,11 +970,11 @@ static void startup_tsec(struct eth_device *dev) { int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; /* Point to the buffer descriptors */ - regs->tbase = (unsigned int)(&rtx.txbd[txIdx]); - regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]); + out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); + out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); /* Initialize the Rx Buffer descriptors */ for (i = 0; i < PKTBUFSRX; i++) { @@ -998,13 +999,13 @@ static void startup_tsec(struct eth_device *dev) adjust_link(dev); /* Enable Transmit and Receive */ - regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); /* Tell the DMA it is clear to go */ - regs->dmactrl |= DMACTRL_INIT_SETTINGS; - regs->tstat = TSTAT_CLEAR_THALT; - regs->rstat = RSTAT_CLEAR_RHALT; - regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); + setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); + out_be32(®s->tstat, TSTAT_CLEAR_THALT); + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); + clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); } /* This returns the status bits of the device. The return value @@ -1017,7 +1018,7 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length) int i; int result = 0; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; /* Find an empty buffer descriptor */ for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { @@ -1033,7 +1034,7 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length) (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); /* Tell the DMA to go */ - regs->tstat = TSTAT_CLEAR_THALT; + out_be32(®s->tstat, TSTAT_CLEAR_THALT); /* Wait for buffer to be transmitted */ for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { @@ -1053,7 +1054,7 @@ static int tsec_recv(struct eth_device *dev) { int length; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { @@ -1076,9 +1077,9 @@ static int tsec_recv(struct eth_device *dev) rxIdx = (rxIdx + 1) % PKTBUFSRX; } - if (regs->ievent & IEVENT_BSY) { - regs->ievent = IEVENT_BSY; - regs->rstat = RSTAT_CLEAR_RHALT; + if (in_be32(®s->ievent) & IEVENT_BSY) { + out_be32(®s->ievent, IEVENT_BSY); + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); } return -1; @@ -1089,15 +1090,16 @@ static int tsec_recv(struct eth_device *dev) static void tsec_halt(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; - regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); - regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); + clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); + setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); - while ((regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)) - != (IEVENT_GRSC | IEVENT_GTSC)) ; + while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) + != (IEVENT_GRSC | IEVENT_GTSC)) + ; - regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); + clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); /* Shut down the PHY, as needed */ if(priv->phyinfo) @@ -1904,13 +1906,14 @@ static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) { int i; uint result; - volatile tsec_mdio_t *phyregs = priv->phyregs; + tsec_mdio_t *phyregs = priv->phyregs; - phyregs->miimcfg = MIIMCFG_RESET; + out_be32(&phyregs->miimcfg, MIIMCFG_RESET); - phyregs->miimcfg = MIIMCFG_INIT_VALUE; + out_be32(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); - while (phyregs->miimind & MIIMIND_BUSY) ; + while (in_be32(&phyregs->miimind) & MIIMIND_BUSY) + ; for (i = 0; cmd->mii_reg != miim_end; i++) { if (cmd->mii_data == miim_read) { -- cgit v1.2.3 From 907519108cd6f45aa067feea6fedd2743739342b Mon Sep 17 00:00:00 2001 From: Mingkai Hu Date: Thu, 27 Jan 2011 12:52:46 +0800 Subject: tsec: arrange the code to avoid useless function declaration This is merely a rearrangement. No changes to the code, except to remove now-useless declarations. Signed-off-by: Mingkai Hu Acked-by: Andy Fleming Signed-off-by: Kumar Gala Acked-by: Detlev Zundel --- drivers/net/tsec.c | 1501 ++++++++++++++++++++++++++-------------------------- 1 file changed, 738 insertions(+), 763 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index a2705e1cab7..a3857b3bbf3 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -44,31 +44,6 @@ static RTXBD rtx __attribute__ ((aligned(8))); #error "rtx must be 64-bit aligned" #endif -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 int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info); -static void tsec_halt(struct eth_device *dev); -static void init_registers(tsec_t *regs); -static void startup_tsec(struct eth_device *dev); -static int init_phy(struct eth_device *dev); -void write_phy_reg(struct tsec_private *priv, uint regnum, uint value); -uint read_phy_reg(struct tsec_private *priv, uint regnum); -static struct phy_info *get_phy_info(struct eth_device *dev); -static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd); -static void adjust_link(struct eth_device *dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) -static int tsec_miiphy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value); -static int tsec_miiphy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value); -#endif -#ifdef CONFIG_MCAST_TFTP -static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set); -#endif - /* Default initializations for TSEC controllers. */ static struct tsec_info_struct tsec_info[] = { @@ -95,140 +70,6 @@ static struct tsec_info_struct tsec_info[] = { #endif }; -/* - * Initialize all the TSEC devices - * - * Returns the number of TSEC devices that were initialized - */ -int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) -{ - int i; - int ret, count = 0; - - for (i = 0; i < num; i++) { - ret = tsec_initialize(bis, &tsecs[i]); - if (ret > 0) - count += ret; - } - - return count; -} - -int tsec_standard_init(bd_t *bis) -{ - return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); -} - -/* Initialize device structure. Returns success if PHY - * initialization succeeded (i.e. if it recognizes the PHY) - */ -static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info) -{ - struct eth_device *dev; - int i; - struct tsec_private *priv; - - dev = (struct eth_device *)malloc(sizeof *dev); - - if (NULL == dev) - return 0; - - memset(dev, 0, sizeof *dev); - - priv = (struct tsec_private *)malloc(sizeof(*priv)); - - if (NULL == priv) - return 0; - - privlist[num_tsecs++] = priv; - priv->regs = tsec_info->regs; - priv->phyregs = tsec_info->miiregs; - priv->phyregs_sgmii = tsec_info->miiregs_sgmii; - - priv->phyaddr = tsec_info->phyaddr; - priv->flags = tsec_info->flags; - - sprintf(dev->name, tsec_info->devname); - dev->iobase = 0; - dev->priv = priv; - dev->init = tsec_init; - dev->halt = tsec_halt; - dev->send = tsec_send; - dev->recv = tsec_recv; -#ifdef CONFIG_MCAST_TFTP - dev->mcast = tsec_mcast_addr; -#endif - - /* Tell u-boot to get the addr from the env */ - for (i = 0; i < 6; i++) - dev->enetaddr[i] = 0; - - eth_register(dev); - - /* Reset the MAC */ - setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); - udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ - clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); - -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) - miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write); -#endif - - /* Try to initialize PHY here, and return */ - return init_phy(dev); -} - -/* Initializes data structures and registers for the controller, - * and brings the interface up. Returns the link status, meaning - * that it returns success if the link is up, failure otherwise. - * This allows u-boot to find the first active controller. - */ -static int tsec_init(struct eth_device *dev, bd_t * bd) -{ - uint tempval; - char tmpbuf[MAC_ADDR_LEN]; - int i; - struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; - - /* Make sure the controller is stopped */ - tsec_halt(dev); - - /* Init MACCFG2. Defaults to GMII */ - out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); - - /* Init ECNTRL */ - out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); - - /* Copy the station address into the address registers. - * Backwards, because little endian MACS are dumb */ - for (i = 0; i < MAC_ADDR_LEN; i++) { - tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; - } - tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | - tmpbuf[3]; - - out_be32(®s->macstnaddr1, tempval); - - tempval = *((uint *) (tmpbuf + 4)); - - out_be32(®s->macstnaddr2, tempval); - - /* reset the indices to zero */ - rxIdx = 0; - txIdx = 0; - - /* Clear out (for the most part) the other registers */ - init_registers(regs); - - /* Ready the device for tx/rx */ - startup_tsec(dev); - - /* If there's no link, fail */ - return (priv->link ? 0 : -1); -} - /* Writes the given phy's reg with value, using the specified MDIO regs */ static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr, uint reg, uint value) @@ -243,7 +84,6 @@ static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr, ; } - /* Provide the default behavior of writing the PHY of this ethernet device */ #define write_phy_reg(priv, regnum, value) \ tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value) @@ -311,46 +151,6 @@ static void tsec_configure_serdes(struct tsec_private *priv) CONFIG_TSEC_TBICR_SETTINGS); } -/* Discover which PHY is attached to the device, and configure it - * properly. If the PHY is not recognized, then return 0 - * (failure). Otherwise, return 1 - */ -static int init_phy(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - struct phy_info *curphy; - tsec_t *regs = priv->regs; - - /* Assign a Physical address to the TBI */ - out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); - - /* Reset MII (due to new addresses) */ - out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET); - out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE); - while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) - ; - - /* Get the cmd structure corresponding to the attached - * PHY */ - curphy = get_phy_info(dev); - - if (curphy == NULL) { - priv->phyinfo = NULL; - printf("%s: No PHY found\n", dev->name); - - return 0; - } - - if (in_be32(®s->ecntrl) & ECNTRL_SGMII_MODE) - tsec_configure_serdes(priv); - - priv->phyinfo = curphy; - - phy_run_commands(priv, priv->phyinfo->config); - - return 1; -} - /* * Returns which value to write to the control register. * For 10/100, the value is slightly different @@ -866,344 +666,104 @@ static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv) return mii_data; } -/* Initialized required registers to appropriate values, zeroing - * those we don't care about (unless zero is bad, in which case, - * choose a more appropriate value) - */ -static void init_registers(tsec_t *regs) -{ - /* Clear IEVENT */ - out_be32(®s->ievent, IEVENT_INIT_CLEAR); - - out_be32(®s->imask, IMASK_INIT_CLEAR); +static struct phy_info phy_info_M88E1149S = { + 0x1410ca, + "Marvell 88E1149S", + 4, + (struct phy_cmd[]) { /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {0x1d, 0x1f, NULL}, + {0x1e, 0x200c, NULL}, + {0x1d, 0x5, NULL}, + {0x1e, 0x0, NULL}, + {0x1e, 0x100, NULL}, + {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + }, +}; - out_be32(®s->hash.iaddr0, 0); - out_be32(®s->hash.iaddr1, 0); - out_be32(®s->hash.iaddr2, 0); - out_be32(®s->hash.iaddr3, 0); - out_be32(®s->hash.iaddr4, 0); - out_be32(®s->hash.iaddr5, 0); - out_be32(®s->hash.iaddr6, 0); - out_be32(®s->hash.iaddr7, 0); +/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */ +static struct phy_info phy_info_BCM5461S = { + 0x02060c1, /* 5461 ID */ + "Broadcom BCM5461S", + 0, /* not clear to me what minor revisions we can shift away */ + (struct phy_cmd[]) { /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + }, +}; - out_be32(®s->hash.gaddr0, 0); - out_be32(®s->hash.gaddr1, 0); - out_be32(®s->hash.gaddr2, 0); - out_be32(®s->hash.gaddr3, 0); - out_be32(®s->hash.gaddr4, 0); - out_be32(®s->hash.gaddr5, 0); - out_be32(®s->hash.gaddr6, 0); - out_be32(®s->hash.gaddr7, 0); - - out_be32(®s->rctrl, 0x00000000); - - /* Init RMON mib registers */ - memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); - - out_be32(®s->rmon.cam1, 0xffffffff); - out_be32(®s->rmon.cam2, 0xffffffff); - - out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); - - out_be32(®s->minflr, MINFLR_INIT_SETTINGS); - - out_be32(®s->attr, ATTR_INIT_SETTINGS); - out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); - -} - -/* Configure maccfg2 based on negotiated speed and duplex - * reported by PHY handling code - */ -static void adjust_link(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; - u32 ecntrl, maccfg2; - - if (!priv->link) { - printf("%s: No link.\n", dev->name); - return; - } - - /* clear all bits relative with interface mode */ - ecntrl = in_be32(®s->ecntrl); - ecntrl &= ~ECNTRL_R100; - - maccfg2 = in_be32(®s->maccfg2); - maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); - - if (priv->duplexity) - maccfg2 |= MACCFG2_FULL_DUPLEX; - - switch (priv->speed) { - case 1000: - maccfg2 |= MACCFG2_GMII; - break; - case 100: - case 10: - maccfg2 |= MACCFG2_MII; - - /* Set R100 bit in all modes although - * it is only used in RGMII mode - */ - if (priv->speed == 100) - ecntrl |= ECNTRL_R100; - break; - default: - printf("%s: Speed was bad\n", dev->name); - break; - } - - out_be32(®s->ecntrl, ecntrl); - out_be32(®s->maccfg2, maccfg2); - - printf("Speed: %d, %s duplex%s\n", priv->speed, - (priv->duplexity) ? "full" : "half", - (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); -} - -/* Set up the buffers and their descriptors, and bring up the - * interface - */ -static void startup_tsec(struct eth_device *dev) -{ - int i; - struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; - - /* Point to the buffer descriptors */ - out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); - out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); - - /* Initialize the Rx Buffer descriptors */ - for (i = 0; i < PKTBUFSRX; i++) { - rtx.rxbd[i].status = RXBD_EMPTY; - rtx.rxbd[i].length = 0; - rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i]; - } - rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; - - /* Initialize the TX Buffer Descriptors */ - for (i = 0; i < TX_BUF_CNT; i++) { - rtx.txbd[i].status = 0; - rtx.txbd[i].length = 0; - rtx.txbd[i].bufPtr = 0; - } - rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; - - /* Start up the PHY */ - if(priv->phyinfo) - phy_run_commands(priv, priv->phyinfo->startup); - - adjust_link(dev); - - /* Enable Transmit and Receive */ - setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); - - /* Tell the DMA it is clear to go */ - setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); - out_be32(®s->tstat, TSTAT_CLEAR_THALT); - out_be32(®s->rstat, RSTAT_CLEAR_RHALT); - clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); -} - -/* This returns the status bits of the device. The return value - * is never checked, and this is what the 8260 driver did, so we - * do the same. Presumably, this would be zero if there were no - * errors - */ -static int tsec_send(struct eth_device *dev, volatile void *packet, int length) -{ - int i; - int result = 0; - struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; - - /* Find an empty buffer descriptor */ - for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { - if (i >= TOUT_LOOP) { - debug("%s: tsec: tx buffers full\n", dev->name); - return result; - } - } - - rtx.txbd[txIdx].bufPtr = (uint) packet; - rtx.txbd[txIdx].length = length; - rtx.txbd[txIdx].status |= - (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); - - /* Tell the DMA to go */ - out_be32(®s->tstat, TSTAT_CLEAR_THALT); - - /* Wait for buffer to be transmitted */ - for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { - if (i >= TOUT_LOOP) { - debug("%s: tsec: tx error\n", dev->name); - return result; - } - } - - txIdx = (txIdx + 1) % TX_BUF_CNT; - result = rtx.txbd[txIdx].status & TXBD_STATS; - - return result; -} - -static int tsec_recv(struct eth_device *dev) -{ - int length; - struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; - - while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { - - length = rtx.rxbd[rxIdx].length; - - /* Send the packet up if there were no errors */ - if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) { - NetReceive(NetRxPackets[rxIdx], length - 4); - } else { - printf("Got error %x\n", - (rtx.rxbd[rxIdx].status & RXBD_STATS)); - } - - rtx.rxbd[rxIdx].length = 0; - - /* Set the wrap bit if this is the last element in the list */ - rtx.rxbd[rxIdx].status = - RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); - - rxIdx = (rxIdx + 1) % PKTBUFSRX; - } - - if (in_be32(®s->ievent) & IEVENT_BSY) { - out_be32(®s->ievent, IEVENT_BSY); - out_be32(®s->rstat, RSTAT_CLEAR_RHALT); - } - - return -1; - -} - -/* Stop the interface */ -static void tsec_halt(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; - - clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); - setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); - - while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) - != (IEVENT_GRSC | IEVENT_GTSC)) - ; - - clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); - - /* Shut down the PHY, as needed */ - if(priv->phyinfo) - phy_run_commands(priv, priv->phyinfo->shutdown); -} - -static struct phy_info phy_info_M88E1149S = { - 0x1410ca, - "Marvell 88E1149S", - 4, - (struct phy_cmd[]) { /* config */ +static struct phy_info phy_info_BCM5464S = { + 0x02060b1, /* 5464 ID */ + "Broadcom BCM5464S", + 0, /* not clear to me what minor revisions we can shift away */ + (struct phy_cmd[]) { /* config */ /* Reset and configure the PHY */ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1d, 0x1f, NULL}, - {0x1e, 0x200c, NULL}, - {0x1d, 0x5, NULL}, - {0x1e, 0x0, NULL}, - {0x1e, 0x100, NULL}, {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, {miim_end,} }, - (struct phy_cmd[]) { /* startup */ + (struct phy_cmd[]) { /* startup */ /* Status is read once to clear old link state */ {MIIM_STATUS, miim_read, NULL}, /* Auto-negotiate */ {MIIM_STATUS, miim_read, &mii_parse_sr}, /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, + {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, {miim_end,} }, - (struct phy_cmd[]) { /* shutdown */ + (struct phy_cmd[]) { /* shutdown */ {miim_end,} }, }; -/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */ -static struct phy_info phy_info_BCM5461S = { - 0x02060c1, /* 5461 ID */ - "Broadcom BCM5461S", - 0, /* not clear to me what minor revisions we can shift away */ +static struct phy_info phy_info_BCM5482S = { + 0x0143bcb, + "Broadcom BCM5482S", + 4, (struct phy_cmd[]) { /* config */ /* Reset and configure the PHY */ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_BCM5464S = { - 0x02060b1, /* 5464 ID */ - "Broadcom BCM5464S", - 0, /* not clear to me what minor revisions we can shift away */ - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_BCM5482S = { - 0x0143bcb, - "Broadcom BCM5482S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - /* Setup read from auxilary control shadow register 7 */ - {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL}, - /* Read Misc Control register and or in Ethernet@Wirespeed */ - {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, + /* Setup read from auxilary control shadow register 7 */ + {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL}, + /* Read Misc Control register and or in Ethernet@Wirespeed */ + {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, /* Initial config/enable of secondary SerDes interface */ {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL}, @@ -1711,317 +1271,732 @@ static uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv) priv->duplexity = 0; } - return 0; -} + return 0; +} + +static struct phy_info phy_info_lxt971 = { + 0x0001378e, + "LXT971", + 4, + (struct phy_cmd[]) { /* config */ + {MIIM_CR, MIIM_CR_INIT, mii_cr_init}, /* autonegotiate */ + {miim_end,} + }, + (struct phy_cmd[]) { /* startup - enable interrupts */ + /* { 0x12, 0x00f2, NULL }, */ + {MIIM_STATUS, miim_read, NULL}, + {MIIM_STATUS, miim_read, &mii_parse_sr}, + {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown - disable interrupts */ + {miim_end,} + }, +}; + +/* Parse the DP83865's link and auto-neg status register for speed and duplex + * information + */ +static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv) +{ + switch (mii_reg & MIIM_DP83865_SPD_MASK) { + + case MIIM_DP83865_SPD_1000: + priv->speed = 1000; + break; + + case MIIM_DP83865_SPD_100: + priv->speed = 100; + break; + + default: + priv->speed = 10; + break; + + } + + if (mii_reg & MIIM_DP83865_DPX_FULL) + priv->duplexity = 1; + else + priv->duplexity = 0; + + return 0; +} + +static struct phy_info phy_info_dp83865 = { + 0x20005c7, + "NatSemi DP83865", + 4, + (struct phy_cmd[]) { /* config */ + {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the link and auto-neg status */ + {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + }, +}; + +static struct phy_info phy_info_rtl8211b = { + 0x001cc91, + "RealTek RTL8211B", + 4, + (struct phy_cmd[]) { /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + }, +}; + +struct phy_info phy_info_AR8021 = { + 0x4dd04, + "AR8021", + 4, + (struct phy_cmd[]) { /* config */ + {MII_BMCR, BMCR_RESET, NULL}, + {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, + {0x1d, 0x05, NULL}, + {0x1e, 0x3D47, NULL}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + {MII_BMSR, miim_read, NULL}, + {MII_BMSR, miim_read, &mii_parse_sr}, + {MII_BMSR, miim_read, &mii_parse_link}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + } +}; + +static struct phy_info *phy_info[] = { + &phy_info_cis8204, + &phy_info_cis8201, + &phy_info_BCM5461S, + &phy_info_BCM5464S, + &phy_info_BCM5482S, + &phy_info_M88E1011S, + &phy_info_M88E1111S, + &phy_info_M88E1118, + &phy_info_M88E1121R, + &phy_info_M88E1145, + &phy_info_M88E1149S, + &phy_info_dm9161, + &phy_info_ksz804, + &phy_info_lxt971, + &phy_info_VSC8211, + &phy_info_VSC8244, + &phy_info_VSC8601, + &phy_info_VSC8641, + &phy_info_VSC8221, + &phy_info_dp83865, + &phy_info_rtl8211b, + &phy_info_AR8021, + &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */ + NULL +}; + +/* Grab the identifier of the device's PHY, and search through + * all of the known PHYs to see if one matches. If so, return + * it, if not, return NULL + */ +static struct phy_info *get_phy_info(struct eth_device *dev) +{ + struct tsec_private *priv = (struct tsec_private *)dev->priv; + uint phy_reg, phy_ID; + int i; + struct phy_info *theInfo = NULL; + + /* Grab the bits from PHYIR1, and put them in the upper half */ + phy_reg = read_phy_reg(priv, MIIM_PHYIR1); + phy_ID = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = read_phy_reg(priv, MIIM_PHYIR2); + phy_ID |= (phy_reg & 0xffff); + + /* loop through all the known PHY types, and find one that */ + /* matches the ID we read from the PHY. */ + for (i = 0; phy_info[i]; i++) { + if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { + theInfo = phy_info[i]; + break; + } + } + + if (theInfo == &phy_info_generic) { + printf("%s: No support for PHY id %x; assuming generic\n", + dev->name, phy_ID); + } else { + debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); + } + + return theInfo; +} + +/* Execute the given series of commands on the given device's + * PHY, running functions as necessary + */ +static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) +{ + int i; + uint result; + tsec_mdio_t *phyregs = priv->phyregs; + + out_be32(&phyregs->miimcfg, MIIMCFG_RESET); + + out_be32(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); + + while (in_be32(&phyregs->miimind) & MIIMIND_BUSY) + ; + + for (i = 0; cmd->mii_reg != miim_end; i++) { + if (cmd->mii_data == miim_read) { + result = read_phy_reg(priv, cmd->mii_reg); + + if (cmd->funct != NULL) + (*(cmd->funct)) (result, priv); + + } else { + if (cmd->funct != NULL) + result = (*(cmd->funct)) (cmd->mii_reg, priv); + else + result = cmd->mii_data; + + write_phy_reg(priv, cmd->mii_reg, result); + + } + cmd++; + } +} + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ + && !defined(BITBANGMII) + +/* + * Read a MII PHY register. + * + * Returns: + * 0 on success + */ +static int tsec_miiphy_read(const char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + unsigned short ret; + struct tsec_private *priv = privlist[0]; + + if (NULL == priv) { + printf("Can't read PHY at address %d\n", addr); + return -1; + } + + ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg); + *value = ret; + + return 0; +} + +/* + * Write a MII PHY register. + * + * Returns: + * 0 on success + */ +static int tsec_miiphy_write(const char *devname, unsigned char addr, + unsigned char reg, unsigned short value) +{ + struct tsec_private *priv = privlist[0]; + + if (NULL == priv) { + printf("Can't write PHY at address %d\n", addr); + return -1; + } + + tsec_local_mdio_write(priv->phyregs, addr, reg, value); + + return 0; +} + +#endif + +#ifdef CONFIG_MCAST_TFTP + +/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ + +/* Set the appropriate hash bit for the given addr */ + +/* The algorithm works like so: + * 1) Take the Destination Address (ie the multicast address), and + * do a CRC on it (little endian), and reverse the bits of the + * result. + * 2) Use the 8 most significant bits as a hash into a 256-entry + * table. The table is controlled through 8 32-bit registers: + * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is + * gaddr7. This means that the 3 most significant bits in the + * hash index which gaddr register to use, and the 5 other bits + * indicate which bit (assuming an IBM numbering scheme, which + * for PowerPC (tm) is usually the case) in the tregister holds + * the entry. */ +static int +tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) +{ + struct tsec_private *priv = privlist[1]; + volatile tsec_t *regs = priv->regs; + volatile u32 *reg_array, value; + u8 result, whichbit, whichreg; + + result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff); + whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ + whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ + value = (1 << (31-whichbit)); + + reg_array = &(regs->hash.gaddr0); + + if (set) { + reg_array[whichreg] |= value; + } else { + reg_array[whichreg] &= ~value; + } + return 0; +} +#endif /* Multicast TFTP ? */ + +/* Initialized required registers to appropriate values, zeroing + * those we don't care about (unless zero is bad, in which case, + * choose a more appropriate value) + */ +static void init_registers(tsec_t *regs) +{ + /* Clear IEVENT */ + out_be32(®s->ievent, IEVENT_INIT_CLEAR); + + out_be32(®s->imask, IMASK_INIT_CLEAR); + + out_be32(®s->hash.iaddr0, 0); + out_be32(®s->hash.iaddr1, 0); + out_be32(®s->hash.iaddr2, 0); + out_be32(®s->hash.iaddr3, 0); + out_be32(®s->hash.iaddr4, 0); + out_be32(®s->hash.iaddr5, 0); + out_be32(®s->hash.iaddr6, 0); + out_be32(®s->hash.iaddr7, 0); + + out_be32(®s->hash.gaddr0, 0); + out_be32(®s->hash.gaddr1, 0); + out_be32(®s->hash.gaddr2, 0); + out_be32(®s->hash.gaddr3, 0); + out_be32(®s->hash.gaddr4, 0); + out_be32(®s->hash.gaddr5, 0); + out_be32(®s->hash.gaddr6, 0); + out_be32(®s->hash.gaddr7, 0); + + out_be32(®s->rctrl, 0x00000000); + + /* Init RMON mib registers */ + memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); + + out_be32(®s->rmon.cam1, 0xffffffff); + out_be32(®s->rmon.cam2, 0xffffffff); + + out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); + + out_be32(®s->minflr, MINFLR_INIT_SETTINGS); + + out_be32(®s->attr, ATTR_INIT_SETTINGS); + out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); + +} + +/* Configure maccfg2 based on negotiated speed and duplex + * reported by PHY handling code + */ +static void adjust_link(struct eth_device *dev) +{ + struct tsec_private *priv = (struct tsec_private *)dev->priv; + tsec_t *regs = priv->regs; + u32 ecntrl, maccfg2; + + if (!priv->link) { + printf("%s: No link.\n", dev->name); + return; + } + + /* clear all bits relative with interface mode */ + ecntrl = in_be32(®s->ecntrl); + ecntrl &= ~ECNTRL_R100; + + maccfg2 = in_be32(®s->maccfg2); + maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); + + if (priv->duplexity) + maccfg2 |= MACCFG2_FULL_DUPLEX; + + switch (priv->speed) { + case 1000: + maccfg2 |= MACCFG2_GMII; + break; + case 100: + case 10: + maccfg2 |= MACCFG2_MII; + + /* Set R100 bit in all modes although + * it is only used in RGMII mode + */ + if (priv->speed == 100) + ecntrl |= ECNTRL_R100; + break; + default: + printf("%s: Speed was bad\n", dev->name); + break; + } + + out_be32(®s->ecntrl, ecntrl); + out_be32(®s->maccfg2, maccfg2); -static struct phy_info phy_info_lxt971 = { - 0x0001378e, - "LXT971", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CR, MIIM_CR_INIT, mii_cr_init}, /* autonegotiate */ - {miim_end,} - }, - (struct phy_cmd[]) { /* startup - enable interrupts */ - /* { 0x12, 0x00f2, NULL }, */ - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown - disable interrupts */ - {miim_end,} - }, -}; + printf("Speed: %d, %s duplex%s\n", priv->speed, + (priv->duplexity) ? "full" : "half", + (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); +} -/* Parse the DP83865's link and auto-neg status register for speed and duplex - * information +/* Set up the buffers and their descriptors, and bring up the + * interface */ -static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv) +static void startup_tsec(struct eth_device *dev) { - switch (mii_reg & MIIM_DP83865_SPD_MASK) { - - case MIIM_DP83865_SPD_1000: - priv->speed = 1000; - break; + int i; + struct tsec_private *priv = (struct tsec_private *)dev->priv; + tsec_t *regs = priv->regs; - case MIIM_DP83865_SPD_100: - priv->speed = 100; - break; + /* Point to the buffer descriptors */ + out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); + out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); - default: - priv->speed = 10; - break; + /* Initialize the Rx Buffer descriptors */ + for (i = 0; i < PKTBUFSRX; i++) { + rtx.rxbd[i].status = RXBD_EMPTY; + rtx.rxbd[i].length = 0; + rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i]; + } + rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; + /* Initialize the TX Buffer Descriptors */ + for (i = 0; i < TX_BUF_CNT; i++) { + rtx.txbd[i].status = 0; + rtx.txbd[i].length = 0; + rtx.txbd[i].bufPtr = 0; } + rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; - if (mii_reg & MIIM_DP83865_DPX_FULL) - priv->duplexity = 1; - else - priv->duplexity = 0; + /* Start up the PHY */ + if (priv->phyinfo) + phy_run_commands(priv, priv->phyinfo->startup); - return 0; + adjust_link(dev); + + /* Enable Transmit and Receive */ + setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); + + /* Tell the DMA it is clear to go */ + setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); + out_be32(®s->tstat, TSTAT_CLEAR_THALT); + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); + clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); } -static struct phy_info phy_info_dp83865 = { - 0x20005c7, - "NatSemi DP83865", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the link and auto-neg status */ - {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; +/* This returns the status bits of the device. The return value + * is never checked, and this is what the 8260 driver did, so we + * do the same. Presumably, this would be zero if there were no + * errors + */ +static int tsec_send(struct eth_device *dev, volatile void *packet, int length) +{ + int i; + int result = 0; + struct tsec_private *priv = (struct tsec_private *)dev->priv; + tsec_t *regs = priv->regs; -static struct phy_info phy_info_rtl8211b = { - 0x001cc91, - "RealTek RTL8211B", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + /* Find an empty buffer descriptor */ + for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { + if (i >= TOUT_LOOP) { + debug("%s: tsec: tx buffers full\n", dev->name); + return result; + } + } -struct phy_info phy_info_AR8021 = { - 0x4dd04, - "AR8021", - 4, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {0x1d, 0x05, NULL}, - {0x1e, 0x3D47, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - } -}; + rtx.txbd[txIdx].bufPtr = (uint) packet; + rtx.txbd[txIdx].length = length; + rtx.txbd[txIdx].status |= + (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); -static struct phy_info *phy_info[] = { - &phy_info_cis8204, - &phy_info_cis8201, - &phy_info_BCM5461S, - &phy_info_BCM5464S, - &phy_info_BCM5482S, - &phy_info_M88E1011S, - &phy_info_M88E1111S, - &phy_info_M88E1118, - &phy_info_M88E1121R, - &phy_info_M88E1145, - &phy_info_M88E1149S, - &phy_info_dm9161, - &phy_info_ksz804, - &phy_info_lxt971, - &phy_info_VSC8211, - &phy_info_VSC8244, - &phy_info_VSC8601, - &phy_info_VSC8641, - &phy_info_VSC8221, - &phy_info_dp83865, - &phy_info_rtl8211b, - &phy_info_AR8021, - &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */ - NULL -}; + /* Tell the DMA to go */ + out_be32(®s->tstat, TSTAT_CLEAR_THALT); -/* Grab the identifier of the device's PHY, and search through - * all of the known PHYs to see if one matches. If so, return - * it, if not, return NULL - */ -static struct phy_info *get_phy_info(struct eth_device *dev) + /* Wait for buffer to be transmitted */ + for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { + if (i >= TOUT_LOOP) { + debug("%s: tsec: tx error\n", dev->name); + return result; + } + } + + txIdx = (txIdx + 1) % TX_BUF_CNT; + result = rtx.txbd[txIdx].status & TXBD_STATS; + + return result; +} + +static int tsec_recv(struct eth_device *dev) { + int length; struct tsec_private *priv = (struct tsec_private *)dev->priv; - uint phy_reg, phy_ID; - int i; - struct phy_info *theInfo = NULL; + tsec_t *regs = priv->regs; - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = read_phy_reg(priv, MIIM_PHYIR1); - phy_ID = (phy_reg & 0xffff) << 16; + while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = read_phy_reg(priv, MIIM_PHYIR2); - phy_ID |= (phy_reg & 0xffff); + length = rtx.rxbd[rxIdx].length; - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) { - if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { - theInfo = phy_info[i]; - break; + /* Send the packet up if there were no errors */ + if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) { + NetReceive(NetRxPackets[rxIdx], length - 4); + } else { + printf("Got error %x\n", + (rtx.rxbd[rxIdx].status & RXBD_STATS)); } + + rtx.rxbd[rxIdx].length = 0; + + /* Set the wrap bit if this is the last element in the list */ + rtx.rxbd[rxIdx].status = + RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + + rxIdx = (rxIdx + 1) % PKTBUFSRX; } - if (theInfo == &phy_info_generic) { - printf("%s: No support for PHY id %x; assuming generic\n", - dev->name, phy_ID); - } else { - debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); + if (in_be32(®s->ievent) & IEVENT_BSY) { + out_be32(®s->ievent, IEVENT_BSY); + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); } - return theInfo; + return -1; + } -/* Execute the given series of commands on the given device's - * PHY, running functions as necessary +/* Stop the interface */ +static void tsec_halt(struct eth_device *dev) +{ + struct tsec_private *priv = (struct tsec_private *)dev->priv; + tsec_t *regs = priv->regs; + + clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); + setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); + + while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) + != (IEVENT_GRSC | IEVENT_GTSC)) + ; + + clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); + + /* Shut down the PHY, as needed */ + if (priv->phyinfo) + phy_run_commands(priv, priv->phyinfo->shutdown); +} + +/* Initializes data structures and registers for the controller, + * and brings the interface up. Returns the link status, meaning + * that it returns success if the link is up, failure otherwise. + * This allows u-boot to find the first active controller. */ -static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) +static int tsec_init(struct eth_device *dev, bd_t * bd) { + uint tempval; + char tmpbuf[MAC_ADDR_LEN]; int i; - uint result; - tsec_mdio_t *phyregs = priv->phyregs; + struct tsec_private *priv = (struct tsec_private *)dev->priv; + tsec_t *regs = priv->regs; - out_be32(&phyregs->miimcfg, MIIMCFG_RESET); + /* Make sure the controller is stopped */ + tsec_halt(dev); - out_be32(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); + /* Init MACCFG2. Defaults to GMII */ + out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); - while (in_be32(&phyregs->miimind) & MIIMIND_BUSY) - ; + /* Init ECNTRL */ + out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); - for (i = 0; cmd->mii_reg != miim_end; i++) { - if (cmd->mii_data == miim_read) { - result = read_phy_reg(priv, cmd->mii_reg); + /* Copy the station address into the address registers. + * Backwards, because little endian MACS are dumb */ + for (i = 0; i < MAC_ADDR_LEN; i++) + tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; - if (cmd->funct != NULL) - (*(cmd->funct)) (result, priv); + tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | + tmpbuf[3]; - } else { - if (cmd->funct != NULL) - result = (*(cmd->funct)) (cmd->mii_reg, priv); - else - result = cmd->mii_data; + out_be32(®s->macstnaddr1, tempval); - write_phy_reg(priv, cmd->mii_reg, result); + tempval = *((uint *) (tmpbuf + 4)); - } - cmd++; - } -} + out_be32(®s->macstnaddr2, tempval); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) + /* reset the indices to zero */ + rxIdx = 0; + txIdx = 0; -/* - * Read a MII PHY register. - * - * Returns: - * 0 on success + /* Clear out (for the most part) the other registers */ + init_registers(regs); + + /* Ready the device for tx/rx */ + startup_tsec(dev); + + /* If there's no link, fail */ + return priv->link ? 0 : -1; +} + +/* Discover which PHY is attached to the device, and configure it + * properly. If the PHY is not recognized, then return 0 + * (failure). Otherwise, return 1 */ -static int tsec_miiphy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value) +static int init_phy(struct eth_device *dev) { - unsigned short ret; - struct tsec_private *priv = privlist[0]; + struct tsec_private *priv = (struct tsec_private *)dev->priv; + struct phy_info *curphy; + tsec_t *regs = priv->regs; - if (NULL == priv) { - printf("Can't read PHY at address %d\n", addr); - return -1; + /* Assign a Physical address to the TBI */ + out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); + + /* Reset MII (due to new addresses) */ + out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET); + out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE); + while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) + ; + + /* Get the cmd structure corresponding to the attached + * PHY */ + curphy = get_phy_info(dev); + + if (curphy == NULL) { + priv->phyinfo = NULL; + printf("%s: No PHY found\n", dev->name); + + return 0; } - ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg); - *value = ret; + if (in_be32(®s->ecntrl) & ECNTRL_SGMII_MODE) + tsec_configure_serdes(priv); - return 0; + priv->phyinfo = curphy; + + phy_run_commands(priv, priv->phyinfo->config); + + return 1; } -/* - * Write a MII PHY register. - * - * Returns: - * 0 on success +/* Initialize device structure. Returns success if PHY + * initialization succeeded (i.e. if it recognizes the PHY) */ -static int tsec_miiphy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value) +static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) { - struct tsec_private *priv = privlist[0]; + struct eth_device *dev; + int i; + struct tsec_private *priv; - if (NULL == priv) { - printf("Can't write PHY at address %d\n", addr); - return -1; - } + dev = (struct eth_device *)malloc(sizeof *dev); - tsec_local_mdio_write(priv->phyregs, addr, reg, value); + if (NULL == dev) + return 0; - return 0; -} + memset(dev, 0, sizeof *dev); -#endif + priv = (struct tsec_private *)malloc(sizeof(*priv)); + + if (NULL == priv) + return 0; + + privlist[num_tsecs++] = priv; + priv->regs = tsec_info->regs; + priv->phyregs = tsec_info->miiregs; + priv->phyregs_sgmii = tsec_info->miiregs_sgmii; + + priv->phyaddr = tsec_info->phyaddr; + priv->flags = tsec_info->flags; + sprintf(dev->name, tsec_info->devname); + dev->iobase = 0; + dev->priv = priv; + dev->init = tsec_init; + dev->halt = tsec_halt; + dev->send = tsec_send; + dev->recv = tsec_recv; #ifdef CONFIG_MCAST_TFTP + dev->mcast = tsec_mcast_addr; +#endif -/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ + /* Tell u-boot to get the addr from the env */ + for (i = 0; i < 6; i++) + dev->enetaddr[i] = 0; -/* Set the appropriate hash bit for the given addr */ + eth_register(dev); -/* The algorithm works like so: - * 1) Take the Destination Address (ie the multicast address), and - * do a CRC on it (little endian), and reverse the bits of the - * result. - * 2) Use the 8 most significant bits as a hash into a 256-entry - * table. The table is controlled through 8 32-bit registers: - * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is - * gaddr7. This means that the 3 most significant bits in the - * hash index which gaddr register to use, and the 5 other bits - * indicate which bit (assuming an IBM numbering scheme, which - * for PowerPC (tm) is usually the case) in the tregister holds - * the entry. */ -static int -tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) -{ - struct tsec_private *priv = privlist[1]; - volatile tsec_t *regs = priv->regs; - volatile u32 *reg_array, value; - u8 result, whichbit, whichreg; + /* Reset the MAC */ + setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); + udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ + clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); - result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff); - whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ - whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ - value = (1 << (31-whichbit)); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ + && !defined(BITBANGMII) + miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write); +#endif - reg_array = &(regs->hash.gaddr0); + /* Try to initialize PHY here, and return */ + return init_phy(dev); +} - if (set) { - reg_array[whichreg] |= value; - } else { - reg_array[whichreg] &= ~value; +/* + * Initialize all the TSEC devices + * + * Returns the number of TSEC devices that were initialized + */ +int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) +{ + int i; + int ret, count = 0; + + for (i = 0; i < num; i++) { + ret = tsec_initialize(bis, &tsecs[i]); + if (ret > 0) + count += ret; } - return 0; + + return count; } -#endif /* Multicast TFTP ? */ + +int tsec_standard_init(bd_t *bis) +{ + return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); +} + -- cgit v1.2.3 From 09c04c20962afd25ce5797e263906f84de5b1f4c Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Tue, 22 Mar 2011 22:49:13 -0500 Subject: Remove instances of phy_read/write There were a few files which were already using phy_read and phy_write for their PHY function names. It's only a few places, and the name seems most appropriate for the high-level abstraction, so let's rename the other versions to something more specific. Also, uec_phy.c had a marvell_init function which I renamed to not conflict with the one in marvell.c Lastly, uec_phy.c was putting a space between the phy writing function names, and the open paren, so I fixed that Signed-off-by: Andy Fleming Acked-by: Detlev Zundel --- drivers/net/dm9000x.c | 18 +++--- drivers/net/enc28j60.c | 24 ++++---- drivers/net/uli526x.c | 24 ++++---- drivers/qe/uec.c | 3 - drivers/qe/uec_phy.c | 145 +++++++++++++++++++++++++------------------------ 5 files changed, 107 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index 709f67aac2c..b5c55738f76 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -110,8 +110,8 @@ static board_info_t dm9000_info; /* function declaration ------------------------------------- */ static int dm9000_probe(void); -static u16 phy_read(int); -static void phy_write(int, u16); +static u16 dm9000_phy_read(int); +static void dm9000_phy_write(int, u16); static u8 DM9000_ior(int); static void DM9000_iow(int reg, u8 value); @@ -361,7 +361,7 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd) DM9000_iow(DM9000_IMR, IMR_PAR); i = 0; - while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ + while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */ udelay(1000); i++; if (i == 10000) { @@ -371,7 +371,7 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd) } /* see what we've got */ - lnk = phy_read(17) >> 12; + lnk = dm9000_phy_read(17) >> 12; printf("operating at "); switch (lnk) { case 1: @@ -445,7 +445,7 @@ static void dm9000_halt(struct eth_device *netdev) DM9000_DBG("%s\n", __func__); /* RESET devie */ - phy_write(0, 0x8000); /* PHY RESET */ + dm9000_phy_write(0, 0x8000); /* PHY RESET */ DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */ DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */ DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */ @@ -581,7 +581,7 @@ DM9000_iow(int reg, u8 value) Read a word from phyxcer */ static u16 -phy_read(int reg) +dm9000_phy_read(int reg) { u16 val; @@ -593,7 +593,7 @@ phy_read(int reg) val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL); /* The read data keeps on REG_0D & REG_0E */ - DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val); + DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val); return val; } @@ -601,7 +601,7 @@ phy_read(int reg) Write a word to phyxcer */ static void -phy_write(int reg, u16 value) +dm9000_phy_write(int reg, u16 value) { /* Fill the phyxcer register into REG_0C */ @@ -613,7 +613,7 @@ phy_write(int reg, u16 value) DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */ udelay(500); /* Wait write complete */ DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ - DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value); + DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value); } int dm9000_initialize(bd_t *bis) diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 6c161b632f4..d55cacdac8c 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -314,7 +314,7 @@ static void enc_release_bus(enc_dev_t *enc) /* * Read PHY register */ -static u16 phy_read(enc_dev_t *enc, const u8 addr) +static u16 enc_phy_read(enc_dev_t *enc, const u8 addr) { uint64_t etime; u8 status; @@ -339,7 +339,7 @@ static u16 phy_read(enc_dev_t *enc, const u8 addr) /* * Write PHY register */ -static void phy_write(enc_dev_t *enc, const u8 addr, const u16 data) +static void enc_phy_write(enc_dev_t *enc, const u8 addr, const u16 data) { uint64_t etime; u8 status; @@ -374,7 +374,7 @@ static int enc_phy_link_wait(enc_dev_t *enc) #ifdef CONFIG_ENC_SILENTLINK /* check if we have a link, then just return */ - status = phy_read(enc, PHY_REG_PHSTAT1); + status = enc_phy_read(enc, PHY_REG_PHSTAT1); if (status & ENC_PHSTAT1_LLSTAT) return 0; #endif @@ -382,10 +382,10 @@ static int enc_phy_link_wait(enc_dev_t *enc) /* wait for link with 1 second timeout */ etime = get_ticks() + get_tbclk(); while (get_ticks() <= etime) { - status = phy_read(enc, PHY_REG_PHSTAT1); + status = enc_phy_read(enc, PHY_REG_PHSTAT1); if (status & ENC_PHSTAT1_LLSTAT) { /* now we have a link */ - status = phy_read(enc, PHY_REG_PHSTAT2); + status = enc_phy_read(enc, PHY_REG_PHSTAT2); duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0; printf("%s: link up, 10Mbps %s-duplex\n", enc->dev->name, duplex ? "full" : "half"); @@ -678,8 +678,8 @@ static int enc_setup(enc_dev_t *enc) enc->bank = 0xff; /* invalidate current bank in enc28j60 */ /* verify PHY identification */ - phid1 = phy_read(enc, PHY_REG_PHID1); - phid2 = phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK; + phid1 = enc_phy_read(enc, PHY_REG_PHID1); + phid2 = enc_phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK; if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) { printf("%s: failed to identify PHY. Found %04x:%04x\n", enc->dev->name, phid1, phid2); @@ -694,7 +694,7 @@ static int enc_setup(enc_dev_t *enc) * Prevent automatic loopback of data beeing transmitted by setting * ENC_PHCON2_HDLDIS */ - phy_write(enc, PHY_REG_PHCON2, (1<<8)); + enc_phy_write(enc, PHY_REG_PHCON2, (1<<8)); /* * LEDs configuration @@ -702,10 +702,10 @@ static int enc_setup(enc_dev_t *enc) * LEDB: LBCFG = 0111 -> display TX & RX activity * STRCH = 1 -> LED pulses */ - phy_write(enc, PHY_REG_PHLCON, 0x0472); + enc_phy_write(enc, PHY_REG_PHLCON, 0x0472); /* Reset PDPXMD-bit => half duplex */ - phy_write(enc, PHY_REG_PHCON1, 0); + enc_phy_write(enc, PHY_REG_PHCON1, 0); #ifdef CONFIG_USE_IRQ /* enable interrupts */ @@ -771,7 +771,7 @@ int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) enc_release_bus(enc); return -1; } - *value = phy_read(enc, reg); + *value = enc_phy_read(enc, reg); enc_release_bus(enc); return 0; } @@ -796,7 +796,7 @@ int enc_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) enc_release_bus(enc); return -1; } - phy_write(enc, reg, value); + enc_phy_write(enc, reg, value); enc_release_bus(enc); return 0; } diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c index a4624e1734d..5933bddce54 100644 --- a/drivers/net/uli526x.c +++ b/drivers/net/uli526x.c @@ -175,9 +175,9 @@ static u16 read_srom_word(long, int); static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long); static void allocate_rx_buffer(struct uli526x_board_info *); static void update_cr6(u32, unsigned long); -static u16 phy_read(unsigned long, u8, u8, u32); +static u16 uli_phy_read(unsigned long, u8, u8, u32); static u16 phy_readby_cr10(unsigned long, u8, u8); -static void phy_write(unsigned long, u8, u8, u16, u32); +static void uli_phy_write(unsigned long, u8, u8, u16, u32); static void phy_writeby_cr10(unsigned long, u8, u8, u16); static void phy_write_1bit(unsigned long, u32, u32); static u16 phy_read_1bit(unsigned long, u32); @@ -349,7 +349,7 @@ static void uli526x_disable(struct eth_device *dev) /* Reset & stop ULI526X board */ outl(ULI526X_RESET, db->ioaddr + DCR0); udelay(5); - phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); + uli_phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); /* reset the board */ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ @@ -385,7 +385,7 @@ static void uli526x_init(struct eth_device *dev) db->tx_packet_cnt = 0; for (phy_tmp = 0; phy_tmp < 32; phy_tmp++) { /* peer add */ - phy_value = phy_read(db->ioaddr, phy_tmp, 3, db->chip_id); + phy_value = uli_phy_read(db->ioaddr, phy_tmp, 3, db->chip_id); if (phy_value != 0xffff && phy_value != 0) { db->phy_addr = phy_tmp; break; @@ -404,10 +404,10 @@ static void uli526x_init(struct eth_device *dev) if (!(inl(db->ioaddr + DCR12) & 0x8)) { /* Phyxcer capability setting */ - phy_reg_reset = phy_read(db->ioaddr, + phy_reg_reset = uli_phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id); phy_reg_reset = (phy_reg_reset | 0x8000); - phy_write(db->ioaddr, db->phy_addr, 0, + uli_phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id); udelay(500); @@ -781,7 +781,8 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db) u16 phy_reg; /* Phyxcer capability setting */ - phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0; + phy_reg = uli_phy_read(db->ioaddr, + db->phy_addr, 4, db->chip_id) & ~0x01e0; if (db->media_mode & ULI526X_AUTO) { /* AUTO Mode */ @@ -802,10 +803,10 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db) phy_reg |= db->PHY_reg4; db->media_mode |= ULI526X_AUTO; } - phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); + uli_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); /* Restart Auto-Negotiation */ - phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); + uli_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); udelay(50); } @@ -813,7 +814,7 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db) * Write a word to Phy register */ -static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, +static void uli_phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) { u16 i; @@ -862,7 +863,8 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, * Read a word data from phy register */ -static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id) +static u16 uli_phy_read(unsigned long iobase, u8 phy_addr, u8 offset, + u32 chip_id) { int i; u16 phy_data; diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 811e3fc3156..cd80f835220 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -67,9 +67,6 @@ static uec_info_t uec_info[] = { static struct eth_device *devlist[MAXCONTROLLERS]; -u16 phy_read (struct uec_mii_info *mii_info, u16 regnum); -void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val); - static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) { uec_t *uec_regs; diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index 55c26229429..c83ca4b5821 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -121,8 +121,8 @@ static int gbit_config_aneg (struct uec_mii_info *mii_info); static int genmii_config_aneg (struct uec_mii_info *mii_info); static int genmii_update_link (struct uec_mii_info *mii_info); static int genmii_read_status (struct uec_mii_info *mii_info); -u16 phy_read (struct uec_mii_info *mii_info, u16 regnum); -void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val); +u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum); +void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val); /* Write value to the PHY for this device to the register at regnum, */ /* waiting until the write is done before it returns. All PHY */ @@ -242,7 +242,7 @@ static void config_genmii_advert (struct uec_mii_info *mii_info) advertise = mii_info->advertising; /* Setup standard advertisement */ - adv = phy_read (mii_info, MII_ADVERTISE); + adv = uec_phy_read(mii_info, MII_ADVERTISE); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (advertise & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; @@ -252,7 +252,7 @@ static void config_genmii_advert (struct uec_mii_info *mii_info) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; - phy_write (mii_info, MII_ADVERTISE, adv); + uec_phy_write(mii_info, MII_ADVERTISE, adv); } static void genmii_setup_forced (struct uec_mii_info *mii_info) @@ -260,7 +260,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info) u16 ctrl; u32 features = mii_info->phyinfo->features; - ctrl = phy_read (mii_info, MII_BMCR); + ctrl = uec_phy_read(mii_info, MII_BMCR); ctrl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); @@ -290,7 +290,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info) break; } - phy_write (mii_info, MII_BMCR, ctrl); + uec_phy_write(mii_info, MII_BMCR, ctrl); } /* Enable and Restart Autonegotiation */ @@ -298,9 +298,9 @@ static void genmii_restart_aneg (struct uec_mii_info *mii_info) { u16 ctl; - ctl = phy_read (mii_info, MII_BMCR); + ctl = uec_phy_read(mii_info, MII_BMCR); ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write (mii_info, MII_BMCR, ctl); + uec_phy_write(mii_info, MII_BMCR, ctl); } static int gbit_config_aneg (struct uec_mii_info *mii_info) @@ -313,14 +313,14 @@ static int gbit_config_aneg (struct uec_mii_info *mii_info) config_genmii_advert (mii_info); advertise = mii_info->advertising; - adv = phy_read (mii_info, MII_CTRL1000); + adv = uec_phy_read(mii_info, MII_CTRL1000); adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); if (advertise & SUPPORTED_1000baseT_Half) adv |= ADVERTISE_1000HALF; if (advertise & SUPPORTED_1000baseT_Full) adv |= ADVERTISE_1000FULL; - phy_write (mii_info, MII_CTRL1000, adv); + uec_phy_write(mii_info, MII_CTRL1000, adv); /* Start/Restart aneg */ genmii_restart_aneg (mii_info); @@ -335,13 +335,13 @@ static int marvell_config_aneg (struct uec_mii_info *mii_info) /* The Marvell PHY has an errata which requires * that certain registers get written in order * to restart autonegotiation */ - phy_write (mii_info, MII_BMCR, BMCR_RESET); + uec_phy_write(mii_info, MII_BMCR, BMCR_RESET); - phy_write (mii_info, 0x1d, 0x1f); - phy_write (mii_info, 0x1e, 0x200c); - phy_write (mii_info, 0x1d, 0x5); - phy_write (mii_info, 0x1e, 0); - phy_write (mii_info, 0x1e, 0x100); + uec_phy_write(mii_info, 0x1d, 0x1f); + uec_phy_write(mii_info, 0x1e, 0x200c); + uec_phy_write(mii_info, 0x1d, 0x5); + uec_phy_write(mii_info, 0x1e, 0); + uec_phy_write(mii_info, 0x1e, 0x100); gbit_config_aneg (mii_info); @@ -373,13 +373,13 @@ static int genmii_update_link (struct uec_mii_info *mii_info) u16 status; /* Status is read once to clear old link state */ - phy_read (mii_info, MII_BMSR); + uec_phy_read(mii_info, MII_BMSR); /* * Wait if the link is up, and autonegotiation is in progress * (ie - we're capable and it's not done) */ - status = phy_read(mii_info, MII_BMSR); + status = uec_phy_read(mii_info, MII_BMSR); if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE) && !(status & BMSR_ANEGCOMPLETE)) { int i = 0; @@ -395,7 +395,7 @@ static int genmii_update_link (struct uec_mii_info *mii_info) i++; udelay(1000); /* 1 ms */ - status = phy_read(mii_info, MII_BMSR); + status = uec_phy_read(mii_info, MII_BMSR); } mii_info->link = 1; } else { @@ -420,7 +420,7 @@ static int genmii_read_status (struct uec_mii_info *mii_info) return err; if (mii_info->autoneg) { - status = phy_read(mii_info, MII_STAT1000); + status = uec_phy_read(mii_info, MII_STAT1000); if (status & (LPA_1000FULL | LPA_1000HALF)) { mii_info->speed = SPEED_1000; @@ -429,7 +429,7 @@ static int genmii_read_status (struct uec_mii_info *mii_info) else mii_info->duplex = DUPLEX_HALF; } else { - status = phy_read(mii_info, MII_LPA); + status = uec_phy_read(mii_info, MII_LPA); if (status & (LPA_10FULL | LPA_100FULL)) mii_info->duplex = DUPLEX_FULL; @@ -463,25 +463,25 @@ static int bcm_init(struct uec_mii_info *mii_info) /* Wait for aneg to complete. */ do - val = phy_read(mii_info, MII_BMSR); + val = uec_phy_read(mii_info, MII_BMSR); while (--cnt && !(val & BMSR_ANEGCOMPLETE)); /* Set RDX clk delay. */ - phy_write(mii_info, 0x18, 0x7 | (7 << 12)); + uec_phy_write(mii_info, 0x18, 0x7 | (7 << 12)); - val = phy_read(mii_info, 0x18); + val = uec_phy_read(mii_info, 0x18); /* Set RDX-RXC skew. */ val |= (1 << 8); val |= (7 | (7 << 12)); /* Write bits 14:0. */ val |= (1 << 15); - phy_write(mii_info, 0x18, val); + uec_phy_write(mii_info, 0x18, val); } return 0; } -static int marvell_init(struct uec_mii_info *mii_info) +static int uec_marvell_init(struct uec_mii_info *mii_info) { struct eth_device *edev = mii_info->dev; uec_private_t *uec = edev->priv; @@ -494,7 +494,7 @@ static int marvell_init(struct uec_mii_info *mii_info) iface == RGMII_TXID)) { int temp; - temp = phy_read(mii_info, MII_M1111_PHY_EXT_CR); + temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_CR); if (iface == RGMII_ID) { temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY; } else if (iface == RGMII_RXID) { @@ -504,14 +504,14 @@ static int marvell_init(struct uec_mii_info *mii_info) temp &= ~MII_M1111_RX_DELAY; temp |= MII_M1111_TX_DELAY; } - phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp); + uec_phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp); - temp = phy_read(mii_info, MII_M1111_PHY_EXT_SR); + temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_SR); temp &= ~MII_M1111_HWCFG_MODE_MASK; temp |= MII_M1111_HWCFG_MODE_RGMII; - phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp); + uec_phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp); - phy_write(mii_info, MII_BMCR, BMCR_RESET); + uec_phy_write(mii_info, MII_BMCR, BMCR_RESET); } return 0; @@ -534,7 +534,7 @@ static int marvell_read_status (struct uec_mii_info *mii_info) if (mii_info->autoneg && mii_info->link) { int speed; - status = phy_read (mii_info, MII_M1011_PHY_SPEC_STATUS); + status = uec_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); /* Get the duplexity */ if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) @@ -564,7 +564,7 @@ static int marvell_read_status (struct uec_mii_info *mii_info) static int marvell_ack_interrupt (struct uec_mii_info *mii_info) { /* Clear the interrupts by reading the reg */ - phy_read (mii_info, MII_M1011_IEVENT); + uec_phy_read(mii_info, MII_M1011_IEVENT); return 0; } @@ -572,9 +572,10 @@ static int marvell_ack_interrupt (struct uec_mii_info *mii_info) static int marvell_config_intr (struct uec_mii_info *mii_info) { if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + uec_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else - phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + uec_phy_write(mii_info, MII_M1011_IMASK, + MII_M1011_IMASK_CLEAR); return 0; } @@ -582,13 +583,13 @@ static int marvell_config_intr (struct uec_mii_info *mii_info) static int dm9161_init (struct uec_mii_info *mii_info) { /* Reset the PHY */ - phy_write (mii_info, MII_BMCR, phy_read (mii_info, MII_BMCR) | + uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) | BMCR_RESET); /* PHY and MAC connect */ - phy_write (mii_info, MII_BMCR, phy_read (mii_info, MII_BMCR) & + uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); - phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + uec_phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); config_genmii_advert (mii_info); /* Start/restart aneg */ @@ -614,7 +615,7 @@ static int dm9161_read_status (struct uec_mii_info *mii_info) /* If the link is up, read the speed and duplex If we aren't autonegotiating assume speeds are as set */ if (mii_info->autoneg && mii_info->link) { - status = phy_read (mii_info, MII_DM9161_SCSR); + status = uec_phy_read(mii_info, MII_DM9161_SCSR); if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) mii_info->speed = SPEED_100; else @@ -632,7 +633,7 @@ static int dm9161_read_status (struct uec_mii_info *mii_info) static int dm9161_ack_interrupt (struct uec_mii_info *mii_info) { /* Clear the interrupt by reading the reg */ - phy_read (mii_info, MII_DM9161_INTR); + uec_phy_read(mii_info, MII_DM9161_INTR); return 0; } @@ -640,9 +641,9 @@ static int dm9161_ack_interrupt (struct uec_mii_info *mii_info) static int dm9161_config_intr (struct uec_mii_info *mii_info) { if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); + uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); else - phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); return 0; } @@ -696,7 +697,7 @@ static int smsc_read_status (struct uec_mii_info *mii_info) if (mii_info->autoneg && mii_info->link) { int val; - status = phy_read (mii_info, 0x1f); + status = uec_phy_read(mii_info, 0x1f); val = (status & 0x1c) >> 2; switch (val) { @@ -751,7 +752,7 @@ static struct phy_info phy_info_marvell = { .phy_id_mask = 0xffffff00, .name = "Marvell 88E11x1", .features = MII_GBIT_FEATURES, - .init = &marvell_init, + .init = &uec_marvell_init, .config_aneg = &marvell_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, @@ -804,12 +805,12 @@ static struct phy_info *phy_info[] = { NULL }; -u16 phy_read (struct uec_mii_info *mii_info, u16 regnum) +u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum) { return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum); } -void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val) +void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val) { mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val); } @@ -825,11 +826,11 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) struct phy_info *theInfo = NULL; /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = phy_read (mii_info, MII_PHYSID1); + phy_reg = uec_phy_read(mii_info, MII_PHYSID1); phy_ID = (phy_reg & 0xffff) << 16; /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = phy_read (mii_info, MII_PHYSID2); + phy_reg = uec_phy_read(mii_info, MII_PHYSID2); phy_ID |= (phy_reg & 0xffff); /* loop through all the known PHY types, and find one that */ @@ -869,39 +870,39 @@ void marvell_phy_interface_mode (struct eth_device *dev, if (type == RGMII) { if (speed == 100) { - phy_write (mii_info, 0x00, 0x9140); - phy_write (mii_info, 0x1d, 0x001f); - phy_write (mii_info, 0x1e, 0x200c); - phy_write (mii_info, 0x1d, 0x0005); - phy_write (mii_info, 0x1e, 0x0000); - phy_write (mii_info, 0x1e, 0x0100); - phy_write (mii_info, 0x09, 0x0e00); - phy_write (mii_info, 0x04, 0x01e1); - phy_write (mii_info, 0x00, 0x9140); - phy_write (mii_info, 0x00, 0x1000); + uec_phy_write(mii_info, 0x00, 0x9140); + uec_phy_write(mii_info, 0x1d, 0x001f); + uec_phy_write(mii_info, 0x1e, 0x200c); + uec_phy_write(mii_info, 0x1d, 0x0005); + uec_phy_write(mii_info, 0x1e, 0x0000); + uec_phy_write(mii_info, 0x1e, 0x0100); + uec_phy_write(mii_info, 0x09, 0x0e00); + uec_phy_write(mii_info, 0x04, 0x01e1); + uec_phy_write(mii_info, 0x00, 0x9140); + uec_phy_write(mii_info, 0x00, 0x1000); udelay (100000); - phy_write (mii_info, 0x00, 0x2900); - phy_write (mii_info, 0x14, 0x0cd2); - phy_write (mii_info, 0x00, 0xa100); - phy_write (mii_info, 0x09, 0x0000); - phy_write (mii_info, 0x1b, 0x800b); - phy_write (mii_info, 0x04, 0x05e1); - phy_write (mii_info, 0x00, 0xa100); - phy_write (mii_info, 0x00, 0x2100); + uec_phy_write(mii_info, 0x00, 0x2900); + uec_phy_write(mii_info, 0x14, 0x0cd2); + uec_phy_write(mii_info, 0x00, 0xa100); + uec_phy_write(mii_info, 0x09, 0x0000); + uec_phy_write(mii_info, 0x1b, 0x800b); + uec_phy_write(mii_info, 0x04, 0x05e1); + uec_phy_write(mii_info, 0x00, 0xa100); + uec_phy_write(mii_info, 0x00, 0x2100); udelay (1000000); } else if (speed == 10) { - phy_write (mii_info, 0x14, 0x8e40); - phy_write (mii_info, 0x1b, 0x800b); - phy_write (mii_info, 0x14, 0x0c82); - phy_write (mii_info, 0x00, 0x8100); + uec_phy_write(mii_info, 0x14, 0x8e40); + uec_phy_write(mii_info, 0x1b, 0x800b); + uec_phy_write(mii_info, 0x14, 0x0c82); + uec_phy_write(mii_info, 0x00, 0x8100); udelay (1000000); } } /* handle 88e1111 rev.B2 erratum 5.6 */ if (mii_info->autoneg) { - status = phy_read (mii_info, MII_BMCR); - phy_write (mii_info, MII_BMCR, status | BMCR_ANENABLE); + status = uec_phy_read(mii_info, MII_BMCR); + uec_phy_write(mii_info, MII_BMCR, status | BMCR_ANENABLE); } /* now the B2 will correctly report autoneg completion status */ } -- cgit v1.2.3 From 5f184715ecd31bfcb8d09ba2d9f14adfa172a141 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 8 Apr 2011 02:10:27 -0500 Subject: Create PHY Lib for U-Boot Extends the mii_dev structure to participate in a full-blown MDIO and PHY driver scheme. The mii_dev structure and miiphy calls are modified in such a way to allow the original mii command and miiphy infrastructure to work as before, but also to support a new set of APIs which allow (among other things) sharing of PHY driver code and 10G support The mii command will continue to support normal PHY management functions (Clause 22 of 802.3), but will not be changed to support 10G (Clause 45). The basic design is similar to PHY Lib from Linux, but simplified for U-Boot's network and driver infrastructure. We now have MDIO drivers and PHY drivers An MDIO driver provides: read write reset A PHY driver provides: (optionally): probe config - initial setup, starting of auto-negotiation startup - waiting for AN, and reading link state shutdown - any cleanup needed The ethernet drivers interact with the PHY Lib using these functions: phy_connect() phy_config() phy_startup() phy_shutdown() Each PHY driver can be configured separately, or all at once using config_phylib_all_drivers.h (added in the patch which adds the drivers) We also provide generic drivers for Clause 22 (10/100/1000), and Clause 45 (10G) PHYs. We also implement phy_reset(), and call it in phy_connect(). Because phy_reset() is essentially the same as miiphy_reset, but: a) must support 10G PHYs, and b) should use the phylib primitives, we implement miiphy_reset, using phy_reset(), but only when CONFIG_PHYLIB is set. Otherwise, we just use the old version. In this way, we save on compile size, even if we don't manage to save code size. Pulled ethtool.h and mdio.h from: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6 782d640afd15af7a1faf01cfe566ca4ac511319d With many, many deletions so as to enable compilation under u-boot Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala Acked-by: Detlev Zundel --- drivers/net/phy/Makefile | 2 + drivers/net/phy/generic_10g.c | 105 ++++++ drivers/net/phy/phy.c | 724 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 831 insertions(+) create mode 100644 drivers/net/phy/generic_10g.c create mode 100644 drivers/net/phy/phy.c (limited to 'drivers') diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index bba890189a2..609a22f2b49 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -27,6 +27,8 @@ LIB := $(obj)libphy.o COBJS-$(CONFIG_BITBANGMII) += miiphybb.o COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o +COBJS-$(CONFIG_PHYLIB) += phy.o +COBJS-$(CONFIG_PHYLIB_10G) += generic_10g.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/phy/generic_10g.c b/drivers/net/phy/generic_10g.c new file mode 100644 index 00000000000..315c50867df --- /dev/null +++ b/drivers/net/phy/generic_10g.c @@ -0,0 +1,105 @@ +/* + * Generic PHY Management code + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Copyright 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + * Based loosely off of Linux's PHY Lib + */ + +#include +#include +#include +#include + +int gen10g_shutdown(struct phy_device *phydev) +{ + return 0; +} + +int gen10g_startup(struct phy_device *phydev) +{ + int devad, reg; + u32 mmd_mask = phydev->mmds; + + phydev->link = 1; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { + if (!mmd_mask & 1) + continue; + + /* Read twice because link state is latched and a + * read moves the current state into the register */ + phy_read(phydev, devad, MDIO_STAT1); + reg = phy_read(phydev, devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} + +int gen10g_discover_mmds(struct phy_device *phydev) +{ + int mmd, stat2, devs1, devs2; + + /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY + * XS or DTE XS; give up if none is present. */ + for (mmd = 1; mmd <= 5; mmd++) { + /* Is this MMD present? */ + stat2 = phy_read(phydev, mmd, MDIO_STAT2); + if (stat2 < 0 || + (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) + continue; + + /* It should tell us about all the other MMDs */ + devs1 = phy_read(phydev, mmd, MDIO_DEVS1); + devs2 = phy_read(phydev, mmd, MDIO_DEVS2); + if (devs1 < 0 || devs2 < 0) + continue; + + phydev->mmds = devs1 | (devs2 << 16); + return 0; + } + + return 0; +} + +int gen10g_config(struct phy_device *phydev) +{ + /* For now, assume 10000baseT. Fill in later */ + phydev->supported = phydev->advertising = SUPPORTED_10000baseT_Full; + + return gen10g_discover_mmds(phydev); +} + +struct phy_driver gen10g_driver = { + .uid = 0xffffffff, + .mask = 0xffffffff, + .name = "Generic 10G PHY", + .features = 0, + .config = gen10g_config, + .startup = gen10g_startup, + .shutdown = gen10g_shutdown, +}; + diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c new file mode 100644 index 00000000000..919011dbe2a --- /dev/null +++ b/drivers/net/phy/phy.c @@ -0,0 +1,724 @@ +/* + * Generic PHY Management code + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Copyright 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + * Based loosely off of Linux's PHY Lib + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Generic PHY support and helper functions */ + +/** + * genphy_config_advert - sanitize and advertise auto-negotation parameters + * @phydev: target phy_device struct + * + * Description: Writes MII_ADVERTISE with the appropriate values, + * after sanitizing the values to make sure we only advertise + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement + * hasn't changed, and > 0 if it has changed. + */ +int genphy_config_advert(struct phy_device *phydev) +{ + u32 advertise; + int oldadv, adv; + int err, changed = 0; + + /* Only allow advertising what + * this PHY supports */ + phydev->advertising &= phydev->supported; + advertise = phydev->advertising; + + /* Setup standard advertisement */ + oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + + if (adv != oldadv) { + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv); + + if (err < 0) + return err; + changed = 1; + } + + /* Configure gigabit if it's supported */ + if (phydev->supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) { + oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + + if (adv != oldadv) { + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, + adv); + + if (err < 0) + return err; + changed = 1; + } + } + + return changed; +} + + +/** + * genphy_setup_forced - configures/forces speed/duplex from @phydev + * @phydev: target phy_device struct + * + * Description: Configures MII_BMCR to force speed/duplex + * to the values in phydev. Assumes that the values are valid. + */ +int genphy_setup_forced(struct phy_device *phydev) +{ + int err; + int ctl = 0; + + phydev->pause = phydev->asym_pause = 0; + + if (SPEED_1000 == phydev->speed) + ctl |= BMCR_SPEED1000; + else if (SPEED_100 == phydev->speed) + ctl |= BMCR_SPEED100; + + if (DUPLEX_FULL == phydev->duplex) + ctl |= BMCR_FULLDPLX; + + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); + + return err; +} + + +/** + * genphy_restart_aneg - Enable and Restart Autonegotiation + * @phydev: target phy_device struct + */ +int genphy_restart_aneg(struct phy_device *phydev) +{ + int ctl; + + ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + if (ctl < 0) + return ctl; + + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + + /* Don't isolate the PHY if we're negotiating */ + ctl &= ~(BMCR_ISOLATE); + + ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); + + return ctl; +} + + +/** + * genphy_config_aneg - restart auto-negotiation or write BMCR + * @phydev: target phy_device struct + * + * Description: If auto-negotiation is enabled, we configure the + * advertising, and then restart auto-negotiation. If it is not + * enabled, then we write the BMCR. + */ +int genphy_config_aneg(struct phy_device *phydev) +{ + int result; + + if (AUTONEG_ENABLE != phydev->autoneg) + return genphy_setup_forced(phydev); + + result = genphy_config_advert(phydev); + + if (result < 0) /* error */ + return result; + + if (result == 0) { + /* Advertisment hasn't changed, but maybe aneg was never on to + * begin with? Or maybe phy was isolated? */ + int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + if (ctl < 0) + return ctl; + + if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) + result = 1; /* do restart aneg */ + } + + /* Only restart aneg if we are advertising something different + * than we were before. */ + if (result > 0) + result = genphy_restart_aneg(phydev); + + return result; +} + +/** + * genphy_update_link - update link status in @phydev + * @phydev: target phy_device struct + * + * Description: Update the value in phydev->link to reflect the + * current link value. In order to do this, we need to read + * the status register twice, keeping the second value. + */ +int genphy_update_link(struct phy_device *phydev) +{ + unsigned int mii_reg; + + /* + * Wait if the link is up, and autonegotiation is in progress + * (ie - we're capable and it's not done) + */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + /* + * If we already saw the link up, and it hasn't gone down, then + * we don't need to wait for autoneg again + */ + if (phydev->link && mii_reg & BMSR_LSTATUS) + return 0; + + if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { + int i = 0; + + printf("%s Waiting for PHY auto negotiation to complete", + phydev->dev->name); + while (!(mii_reg & BMSR_ANEGCOMPLETE)) { + /* + * Timeout reached ? + */ + if (i > PHY_ANEG_TIMEOUT) { + printf(" TIMEOUT !\n"); + phydev->link = 0; + return 0; + } + + if (ctrlc()) { + puts("user interrupt!\n"); + phydev->link = 0; + return -EINTR; + } + + if ((i++ % 500) == 0) + printf("."); + + udelay(1000); /* 1 ms */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + } + printf(" done\n"); + phydev->link = 1; + } else { + /* Read the link a second time to clear the latched state */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + if (mii_reg & BMSR_LSTATUS) + phydev->link = 1; + else + phydev->link = 0; + } + + return 0; +} + +/* + * Generic function which updates the speed and duplex. If + * autonegotiation is enabled, it uses the AND of the link + * partner's advertised capabilities and our advertised + * capabilities. If autonegotiation is disabled, we use the + * appropriate bits in the control register. + * + * Stolen from Linux's mii.c and phy_device.c + */ +static int genphy_parse_link(struct phy_device *phydev) +{ + int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + /* We're using autonegotiation */ + if (mii_reg & BMSR_ANEGCAPABLE) { + u32 lpa = 0; + u32 gblpa = 0; + + /* Check for gigabit capability */ + if (mii_reg & BMSR_ERCAP) { + /* We want a list of states supported by + * both PHYs in the link + */ + gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000); + gblpa &= phy_read(phydev, + MDIO_DEVAD_NONE, MII_CTRL1000) << 2; + } + + /* Set the baseline so we only have to set them + * if they're different + */ + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + /* Check the gigabit fields */ + if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { + phydev->speed = SPEED_1000; + + if (gblpa & PHY_1000BTSR_1000FD) + phydev->duplex = DUPLEX_FULL; + + /* We're done! */ + return 0; + } + + lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); + lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA); + + if (lpa & (LPA_100FULL | LPA_100HALF)) { + phydev->speed = SPEED_100; + + if (lpa & LPA_100FULL) + phydev->duplex = DUPLEX_FULL; + + } else if (lpa & LPA_10FULL) + phydev->duplex = DUPLEX_FULL; + } else { + u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + } + + return 0; +} + +int genphy_config(struct phy_device *phydev) +{ + int val; + u32 features; + + /* For now, I'll claim that the generic driver supports + * all possible port types */ + features = (SUPPORTED_TP | SUPPORTED_MII + | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_BNC); + + /* Do we support autonegotiation? */ + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + if (val < 0) + return val; + + if (val & BMSR_ANEGCAPABLE) + features |= SUPPORTED_Autoneg; + + if (val & BMSR_100FULL) + features |= SUPPORTED_100baseT_Full; + if (val & BMSR_100HALF) + features |= SUPPORTED_100baseT_Half; + if (val & BMSR_10FULL) + features |= SUPPORTED_10baseT_Full; + if (val & BMSR_10HALF) + features |= SUPPORTED_10baseT_Half; + + if (val & BMSR_ESTATEN) { + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS); + + if (val < 0) + return val; + + if (val & ESTATUS_1000_TFULL) + features |= SUPPORTED_1000baseT_Full; + if (val & ESTATUS_1000_THALF) + features |= SUPPORTED_1000baseT_Half; + } + + phydev->supported = features; + phydev->advertising = features; + + genphy_config_aneg(phydev); + + return 0; +} + +int genphy_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + genphy_parse_link(phydev); + + return 0; +} + +int genphy_shutdown(struct phy_device *phydev) +{ + return 0; +} + +static struct phy_driver genphy_driver = { + .uid = 0xffffffff, + .mask = 0xffffffff, + .name = "Generic PHY", + .features = 0, + .config = genphy_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + +static LIST_HEAD(phy_drivers); + +int phy_init(void) +{ + return 0; +} + +int phy_register(struct phy_driver *drv) +{ + INIT_LIST_HEAD(&drv->list); + list_add_tail(&drv->list, &phy_drivers); + + return 0; +} + +int phy_probe(struct phy_device *phydev) +{ + int err = 0; + + phydev->advertising = phydev->supported = phydev->drv->features; + phydev->mmds = phydev->drv->mmds; + + if (phydev->drv->probe) + err = phydev->drv->probe(phydev); + + return err; +} + +static struct phy_driver *generic_for_interface(phy_interface_t interface) +{ +#ifdef CONFIG_PHYLIB_10G + if (is_10g_interface(interface)) + return &gen10g_driver; +#endif + + return &genphy_driver; +} + +struct phy_driver *get_phy_driver(struct phy_device *phydev, + phy_interface_t interface) +{ + struct list_head *entry; + int phy_id = phydev->phy_id; + struct phy_driver *drv = NULL; + + list_for_each(entry, &phy_drivers) { + drv = list_entry(entry, struct phy_driver, list); + if ((drv->uid & drv->mask) == (phy_id & drv->mask)) + return drv; + } + + /* If we made it here, there's no driver for this PHY */ + return generic_for_interface(interface); +} + +struct phy_device *phy_device_create(struct mii_dev *bus, int addr, int phy_id, + phy_interface_t interface) +{ + struct phy_device *dev; + + /* We allocate the device, and initialize the + * default values */ + dev = malloc(sizeof(*dev)); + if (!dev) { + printf("Failed to allocate PHY device for %s:%d\n", + bus->name, addr); + return NULL; + } + + memset(dev, 0, sizeof(*dev)); + + dev->duplex = -1; + dev->link = 1; + dev->interface = interface; + + dev->autoneg = AUTONEG_ENABLE; + + dev->addr = addr; + dev->phy_id = phy_id; + dev->bus = bus; + + dev->drv = get_phy_driver(dev, interface); + + phy_probe(dev); + + bus->phymap[addr] = dev; + + return dev; +} + +/** + * get_phy_id - reads the specified addr for its ID. + * @bus: the target MII bus + * @addr: PHY address on the MII bus + * @phy_id: where to store the ID retrieved. + * + * Description: Reads the ID registers of the PHY at @addr on the + * @bus, stores it in @phy_id and returns zero on success. + */ +int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) +{ + int phy_reg; + + /* Grab the bits from PHYIR1, and put them + * in the upper half */ + phy_reg = bus->read(bus, addr, devad, MII_PHYSID1); + + if (phy_reg < 0) + return -EIO; + + *phy_id = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = bus->read(bus, addr, devad, MII_PHYSID2); + + if (phy_reg < 0) + return -EIO; + + *phy_id |= (phy_reg & 0xffff); + + return 0; +} + +/** + * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * @bus: the target MII bus + * @addr: PHY address on the MII bus + * + * Description: Reads the ID registers of the PHY at @addr on the + * @bus, then allocates and returns the phy_device to represent it. + */ +struct phy_device *get_phy_device(struct mii_dev *bus, int addr, + phy_interface_t interface) +{ + u32 phy_id = 0x1fffffff; + int i; + int r; + + /* If we have one, return the existing device, with new interface */ + if (bus->phymap[addr]) { + bus->phymap[addr]->interface = interface; + + return bus->phymap[addr]; + } + + /* Try Standard (ie Clause 22) access */ + r = get_phy_id(bus, addr, MDIO_DEVAD_NONE, &phy_id); + if (r) + return NULL; + + /* If the PHY ID is mostly f's, we didn't find anything */ + if ((phy_id & 0x1fffffff) != 0x1fffffff) + return phy_device_create(bus, addr, phy_id, interface); + + /* Otherwise we have to try Clause 45 */ + for (i = 1; i < 5; i++) { + r = get_phy_id(bus, addr, i, &phy_id); + if (r) + return NULL; + + /* If the phy_id is mostly Fs, there is no device there */ + if ((phy_id & 0x1fffffff) != 0x1fffffff) + break; + } + + return phy_device_create(bus, addr, phy_id, interface); +} + +int phy_reset(struct phy_device *phydev) +{ + int reg; + int timeout = 500; + int devad = MDIO_DEVAD_NONE; + +#ifdef CONFIG_PHYLIB_10G + /* If it's 10G, we need to issue reset through one of the MMDs */ + if (is_10g_interface(phydev->interface)) { + if (!phydev->mmds) + gen10g_discover_mmds(phydev); + + devad = ffs(phydev->mmds) - 1; + } +#endif + + reg = phy_read(phydev, devad, MII_BMCR); + if (reg < 0) { + debug("PHY status read failed\n"); + return -1; + } + + reg |= BMCR_RESET; + + if (phy_write(phydev, devad, MII_BMCR, reg) < 0) { + debug("PHY reset failed\n"); + return -1; + } + +#ifdef CONFIG_PHY_RESET_DELAY + udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ +#endif + /* + * Poll the control register for the reset bit to go to 0 (it is + * auto-clearing). This should happen within 0.5 seconds per the + * IEEE spec. + */ + while ((reg & BMCR_RESET) && timeout--) { + reg = phy_read(phydev, devad, MII_BMCR); + + if (reg < 0) { + debug("PHY status read failed\n"); + return -1; + } + udelay(1000); + } + + if (reg & BMCR_RESET) { + puts("PHY reset timed out\n"); + return -1; + } + + return 0; +} + +int miiphy_reset(const char *devname, unsigned char addr) +{ + struct mii_dev *bus = miiphy_get_dev_by_name(devname); + struct phy_device *phydev; + + /* + * miiphy_reset was only used on standard PHYs, so we'll fake it here. + * If later code tries to connect with the right interface, this will + * be corrected by get_phy_device in phy_connect() + */ + phydev = get_phy_device(bus, addr, PHY_INTERFACE_MODE_MII); + + return phy_reset(phydev); +} + +struct phy_device *phy_connect(struct mii_dev *bus, int addr, + struct eth_device *dev, + phy_interface_t interface) +{ + struct phy_device *phydev; + + /* Reset the bus */ + bus->reset(bus); + + /* Wait 15ms to make sure the PHY has come out of hard reset */ + udelay(15000); + + phydev = get_phy_device(bus, addr, interface); + + if (!phydev) { + printf("Could not get PHY for %s:%d\n", bus->name, addr); + + return NULL; + } + + /* Soft Reset the PHY */ + phy_reset(phydev); + + if (phydev->dev) + printf("%s:%d is connected to %s. Reconnecting to %s\n", + bus->name, addr, phydev->dev->name, dev->name); + + phydev->dev = dev; + + printf("%s connected to %s\n", dev->name, phydev->drv->name); + + return phydev; +} + +int phy_startup(struct phy_device *phydev) +{ + if (phydev->drv->startup) + phydev->drv->startup(phydev); + + return 0; +} + +static int __board_phy_config(struct phy_device *phydev) +{ + return 0; +} + +int board_phy_config(struct phy_device *phydev) + __attribute__((weak, alias("__board_phy_config"))); + +int phy_config(struct phy_device *phydev) +{ + if (phydev->drv->config) + phydev->drv->config(phydev); + + /* Invoke an optional board-specific helper */ + board_phy_config(phydev); + + return 0; +} + +int phy_shutdown(struct phy_device *phydev) +{ + if (phydev->drv->shutdown) + phydev->drv->shutdown(phydev); + + return 0; +} -- cgit v1.2.3 From 9082eeac5de1335d663016668c9b89c290f5c79b Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Thu, 7 Apr 2011 21:56:05 -0500 Subject: phylib: Add a bunch of PHY drivers from tsec The tsec driver had a bunch of PHY drivers already written. This converts them all into PHY Lib drivers, and serves as the first set of PHY drivers for PHY Lib. While doing that, cleaned up a number of magic numbers (though not all of them, as PHY vendors like to keep their numbers as magical as possible). Also, noticed that almost all of the vitesse/cicada PHYs had the same config/parse/startup functions, so those have been collapsed into one. Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala Acked-by: Detlev Zundel --- drivers/net/phy/Makefile | 11 ++ drivers/net/phy/atheros.c | 48 ++++++ drivers/net/phy/broadcom.c | 288 +++++++++++++++++++++++++++++++++ drivers/net/phy/davicom.c | 98 ++++++++++++ drivers/net/phy/lxt.c | 87 ++++++++++ drivers/net/phy/marvell.c | 367 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/micrel.c | 40 +++++ drivers/net/phy/natsemi.c | 96 +++++++++++ drivers/net/phy/phy.c | 31 ++++ drivers/net/phy/realtek.c | 130 +++++++++++++++ drivers/net/phy/teranetics.c | 62 ++++++++ drivers/net/phy/vitesse.c | 242 ++++++++++++++++++++++++++++ 12 files changed, 1500 insertions(+) create mode 100644 drivers/net/phy/atheros.c create mode 100644 drivers/net/phy/broadcom.c create mode 100644 drivers/net/phy/davicom.c create mode 100644 drivers/net/phy/lxt.c create mode 100644 drivers/net/phy/marvell.c create mode 100644 drivers/net/phy/micrel.c create mode 100644 drivers/net/phy/natsemi.c create mode 100644 drivers/net/phy/realtek.c create mode 100644 drivers/net/phy/teranetics.c create mode 100644 drivers/net/phy/vitesse.c (limited to 'drivers') diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 609a22f2b49..a59834b292d 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -27,8 +27,19 @@ LIB := $(obj)libphy.o COBJS-$(CONFIG_BITBANGMII) += miiphybb.o COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o + COBJS-$(CONFIG_PHYLIB) += phy.o COBJS-$(CONFIG_PHYLIB_10G) += generic_10g.o +COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o +COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o +COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o +COBJS-$(CONFIG_PHY_LXT) += lxt.o +COBJS-$(CONFIG_PHY_MARVELL) += marvell.o +COBJS-$(CONFIG_PHY_MICREL) += micrel.o +COBJS-$(CONFIG_PHY_NATSEMI) += natsemi.o +COBJS-$(CONFIG_PHY_REALTEK) += realtek.o +COBJS-$(CONFIG_PHY_TERANETICS) += teranetics.o +COBJS-$(CONFIG_PHY_VITESSE) += vitesse.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c new file mode 100644 index 00000000000..798473dd68c --- /dev/null +++ b/drivers/net/phy/atheros.c @@ -0,0 +1,48 @@ +/* + * Atheros PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +static int ar8021_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47); + + return 0; +} + +struct phy_driver AR8021_driver = { + .name = "AR8021", + .uid = 0x4dd040, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = ar8021_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + +int phy_atheros_init(void) +{ + phy_register(&AR8021_driver); + + return 0; +} diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c new file mode 100644 index 00000000000..427ac6013ba --- /dev/null +++ b/drivers/net/phy/broadcom.c @@ -0,0 +1,288 @@ +/* + * Broadcom PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include +#include + +/* Broadcom BCM54xx -- taken from linux sungem_phy */ +#define MIIM_BCM54xx_AUXCNTL 0x18 +#define MIIM_BCM54xx_AUXCNTL_ENCODE(val) (((val & 0x7) << 12)|(val & 0x7)) +#define MIIM_BCM54xx_AUXSTATUS 0x19 +#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8 + +#define MIIM_BCM54XX_SHD 0x1c +#define MIIM_BCM54XX_SHD_WRITE 0x8000 +#define MIIM_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) +#define MIIM_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) +#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data) \ + (MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \ + MIIM_BCM54XX_SHD_DATA(data)) + +#define MIIM_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ +#define MIIM_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ +#define MIIM_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ + +/* Broadcom BCM5461S */ +static int bcm5461_config(struct phy_device *phydev) +{ + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +static int bcm54xx_parse_status(struct phy_device *phydev) +{ + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXSTATUS); + + switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> + MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) { + case 1: + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_10; + break; + case 2: + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_10; + break; + case 3: + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_100; + break; + case 5: + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_100; + break; + case 6: + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_1000; + break; + case 7: + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_1000; + break; + default: + printf("Auto-neg error, defaulting to 10BT/HD\n"); + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int bcm54xx_startup(struct phy_device *phydev) +{ + /* Read the Status (2x to make sure link is right) */ + genphy_update_link(phydev); + bcm54xx_parse_status(phydev); + + return 0; +} + +/* Broadcom BCM5482S */ +/* + * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain + * circumstances. eg a gigabit TSEC connected to a gigabit switch with + * a 4-wire ethernet cable. Both ends advertise gigabit, but can't + * link. "Ethernet@Wirespeed" reduces advertised speed until link + * can be achieved. + */ +static u32 bcm5482_read_wirespeed(struct phy_device *phydev, u32 reg) +{ + return (phy_read(phydev, MDIO_DEVAD_NONE, reg) & 0x8FFF) | 0x8010; +} + +static int bcm5482_config(struct phy_device *phydev) +{ + unsigned int reg; + + /* reset the PHY */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + reg |= BMCR_RESET; + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg); + + /* Setup read from auxilary control shadow register 7 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, + MIIM_BCM54xx_AUXCNTL_ENCODE(7)); + /* Read Misc Control register and or in Ethernet@Wirespeed */ + reg = bcm5482_read_wirespeed(phydev, MIIM_BCM54xx_AUXCNTL); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, reg); + + /* Initial config/enable of secondary SerDes interface */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, + MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf)); + /* Write intial value to secondary SerDes Contol */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_SSD | 0); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA, + BMCR_ANRESTART); + /* Enable copper/fiber auto-detect */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, + MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)); + + genphy_config_aneg(phydev); + + return 0; +} + +/* + * Find out if PHY is in copper or serdes mode by looking at Expansion Reg + * 0x42 - "Operating Mode Status Register" + */ +static int bcm5482_is_serdes(struct phy_device *phydev) +{ + u16 val; + int serdes = 0; + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA); + + switch (val & 0x1f) { + case 0x0d: /* RGMII-to-100Base-FX */ + case 0x0e: /* RGMII-to-SGMII */ + case 0x0f: /* RGMII-to-SerDes */ + case 0x12: /* SGMII-to-SerDes */ + case 0x13: /* SGMII-to-100Base-FX */ + case 0x16: /* SerDes-to-Serdes */ + serdes = 1; + break; + case 0x6: /* RGMII-to-Copper */ + case 0x14: /* SGMII-to-Copper */ + case 0x17: /* SerDes-to-Copper */ + break; + default: + printf("ERROR, invalid PHY mode (0x%x\n)", val); + break; + } + + return serdes; +} + +/* + * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating + * Mode Status Register" + */ +static u32 bcm5482_parse_serdes_sr(struct phy_device *phydev) +{ + u16 val; + int i = 0; + + /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ + while (1) { + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA); + + if (val & 0x8000) + break; + + if (i++ > 1000) { + phydev->link = 0; + return 1; + } + + udelay(1000); /* 1 ms */ + } + + phydev->link = 1; + switch ((val >> 13) & 0x3) { + case (0x00): + phydev->speed = 10; + break; + case (0x01): + phydev->speed = 100; + break; + case (0x02): + phydev->speed = 1000; + break; + } + + phydev->duplex = (val & 0x1000) == 0x1000; + + return 0; +} + +/* + * Figure out if BCM5482 is in serdes or copper mode and determine link + * configuration accordingly + */ +static int bcm5482_startup(struct phy_device *phydev) +{ + if (bcm5482_is_serdes(phydev)) { + bcm5482_parse_serdes_sr(phydev); + phydev->port = PORT_FIBRE; + } else { + /* Wait for auto-negotiation to complete or fail */ + genphy_update_link(phydev); + /* Parse BCM54xx copper aux status register */ + bcm54xx_parse_status(phydev); + } + + return 0; +} + +static struct phy_driver BCM5461S_driver = { + .name = "Broadcom BCM5461S", + .uid = 0x2060c0, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm5461_config, + .startup = &bcm54xx_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver BCM5464S_driver = { + .name = "Broadcom BCM5464S", + .uid = 0x2060b0, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm5461_config, + .startup = &bcm54xx_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver BCM5482S_driver = { + .name = "Broadcom BCM5482S", + .uid = 0x143bcb0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm5482_config, + .startup = &bcm5482_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_broadcom_init(void) +{ + phy_register(&BCM5482S_driver); + phy_register(&BCM5464S_driver); + phy_register(&BCM5461S_driver); + + return 0; +} diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c new file mode 100644 index 00000000000..e96a4af03d7 --- /dev/null +++ b/drivers/net/phy/davicom.c @@ -0,0 +1,98 @@ +/* + * Davicom PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +#define MIIM_DM9161_SCR 0x10 +#define MIIM_DM9161_SCR_INIT 0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MIIM_DM9161_SCSR 0x11 +#define MIIM_DM9161_SCSR_100F 0x8000 +#define MIIM_DM9161_SCSR_100H 0x4000 +#define MIIM_DM9161_SCSR_10F 0x2000 +#define MIIM_DM9161_SCSR_10H 0x1000 + +/* DM9161 10BT Configuration/Status */ +#define MIIM_DM9161_10BTCSR 0x12 +#define MIIM_DM9161_10BTCSR_INIT 0x7800 + + +/* Davicom DM9161E */ +static int dm9161_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ISOLATE); + /* Do not bypass the scrambler/descrambler */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCR, + MIIM_DM9161_SCR_INIT); + /* Clear 10BTCSR to default */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_10BTCSR, + MIIM_DM9161_10BTCSR_INIT); + + genphy_config_aneg(phydev); + + return 0; +} + +static int dm9161_parse_status(struct phy_device *phydev) +{ + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCSR); + + if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + return 0; +} + +static int dm9161_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + dm9161_parse_status(phydev); + + return 0; +} + +static struct phy_driver DM9161_driver = { + .name = "Davicom DM9161E", + .uid = 0x181b880, + .mask = 0xffffff0, + .features = PHY_BASIC_FEATURES, + .config = &dm9161_config, + .startup = &dm9161_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_davicom_init(void) +{ + phy_register(&DM9161_driver); + + return 0; +} diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c new file mode 100644 index 00000000000..d67bbdd9ca8 --- /dev/null +++ b/drivers/net/phy/lxt.c @@ -0,0 +1,87 @@ +/* + * LXT PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +/* LXT971 Status 2 registers */ +#define MIIM_LXT971_SR2 0x11 /* Status Register 2 */ +#define MIIM_LXT971_SR2_SPEED_MASK 0x4200 +#define MIIM_LXT971_SR2_10HDX 0x0000 /* 10 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_10FDX 0x0200 /* 10 Mbit full duplex selected */ +#define MIIM_LXT971_SR2_100HDX 0x4000 /* 100 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_100FDX 0x4200 /* 100 Mbit full duplex selected */ + + +/* LXT971 */ +static int lxt971_parse_status(struct phy_device *phydev) +{ + int mii_reg; + int speed; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_LXT971_SR2); + speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK; + + switch (speed) { + case MIIM_LXT971_SR2_10HDX: + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + break; + case MIIM_LXT971_SR2_10FDX: + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_FULL; + break; + case MIIM_LXT971_SR2_100HDX: + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_HALF; + break; + default: + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + } + + return 0; +} + +static int lxt971_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + lxt971_parse_status(phydev); + + return 0; +} + +static struct phy_driver LXT971_driver = { + .name = "LXT971", + .uid = 0x1378e0, + .mask = 0xfffff0, + .features = PHY_BASIC_FEATURES, + .config = &genphy_config_aneg, + .startup = &lxt971_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_lxt_init(void) +{ + phy_register(&LXT971_driver); + + return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c new file mode 100644 index 00000000000..bd1cdc4f11d --- /dev/null +++ b/drivers/net/phy/marvell.c @@ -0,0 +1,367 @@ +/* + * Marvell PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include +#include + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1xxx_PHY_STATUS 0x11 +#define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000 +#define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000 +#define MIIM_88E1xxx_PHYSTAT_100 0x4000 +#define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000 +#define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800 +#define MIIM_88E1xxx_PHYSTAT_LINK 0x0400 + +#define MIIM_88E1xxx_PHY_SCR 0x10 +#define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060 + +/* 88E1111 PHY LED Control Register */ +#define MIIM_88E1111_PHY_LED_CONTROL 24 +#define MIIM_88E1111_PHY_LED_DIRECT 0x4100 +#define MIIM_88E1111_PHY_LED_COMBINE 0x411C + +/* 88E1118 PHY defines */ +#define MIIM_88E1118_PHY_PAGE 22 +#define MIIM_88E1118_PHY_LED_PAGE 3 + +/* 88E1121 PHY LED Control Register */ +#define MIIM_88E1121_PHY_LED_CTRL 16 +#define MIIM_88E1121_PHY_LED_PAGE 3 +#define MIIM_88E1121_PHY_LED_DEF 0x0030 + +/* 88E1121 PHY IRQ Enable/Status Register */ +#define MIIM_88E1121_PHY_IRQ_EN 18 +#define MIIM_88E1121_PHY_IRQ_STATUS 19 + +#define MIIM_88E1121_PHY_PAGE 22 + +/* 88E1145 Extended PHY Specific Control Register */ +#define MIIM_88E1145_PHY_EXT_CR 20 +#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 +#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 + +#define MIIM_88E1145_PHY_LED_CONTROL 24 +#define MIIM_88E1145_PHY_LED_DIRECT 0x4100 + +#define MIIM_88E1145_PHY_PAGE 29 +#define MIIM_88E1145_PHY_CAL_OV 30 + +#define MIIM_88E1149_PHY_PAGE 29 + +/* Marvell 88E1011S */ +static int m88e1011s_config(struct phy_device *phydev) +{ + /* Reset and configure the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + genphy_config_aneg(phydev); + + return 0; +} + +/* Parse the 88E1011's status register for speed and duplex + * information + */ +static uint m88e1xxx_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); + + if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && + !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { + int i = 0; + + puts("Waiting for PHY realtime link"); + while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { + /* Timeout reached ? */ + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { + puts(" TIMEOUT !\n"); + phydev->link = 0; + break; + } + + if ((i++ % 1000) == 0) + putc('.'); + udelay(1000); + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_88E1xxx_PHY_STATUS); + } + puts(" done\n"); + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) + phydev->link = 1; + else + phydev->link = 0; + } + + if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; + + switch (speed) { + case MIIM_88E1xxx_PHYSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_88E1xxx_PHYSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int m88e1011s_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + m88e1xxx_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1111S */ +static int m88e1111s_config(struct phy_device *phydev) +{ + int reg; + + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { + reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1b); + reg = (reg & 0xfff0) | 0xb; + phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, reg); + } else { + phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, 0x1f); + } + + phy_write(phydev, MDIO_DEVAD_NONE, 0x14, 0x0cd2); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +/* Marvell 88E1118 */ +static int m88e1118_config(struct phy_device *phydev) +{ + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); + /* Delay RGMII TX and RX */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); + /* Adjust LED control */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +static int m88e1118_startup(struct phy_device *phydev) +{ + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + + genphy_update_link(phydev); + m88e1xxx_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1121R */ +static int m88e1121_config(struct phy_device *phydev) +{ + int pg; + + /* Configure the PHY */ + genphy_config_aneg(phydev); + + /* Switch the page to access the led register */ + pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, + MIIM_88E1121_PHY_LED_PAGE); + /* Configure leds */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, + MIIM_88E1121_PHY_LED_DEF); + /* Restore the page pointer */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); + + /* Disable IRQs and de-assert interrupt */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); + phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); + + return 0; +} + +/* Marvell 88E1145 */ +static int m88e1145_config(struct phy_device *phydev) +{ + int reg; + + /* Errata E0, E1 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, + MIIM_88E1xxx_PHY_MDI_X_AUTO); + + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + reg |= MIIM_M88E1145_RGMII_RX_DELAY | + MIIM_M88E1145_RGMII_TX_DELAY; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +static int m88e1145_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, + MIIM_88E1145_PHY_LED_DIRECT); + m88e1xxx_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1149S */ +static int m88e1149_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + + +static struct phy_driver M88E1011S_driver = { + .name = "Marvell 88E1011S", + .uid = 0x1410c60, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1011s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1111S_driver = { + .name = "Marvell 88E1111S", + .uid = 0x1410cc0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1111s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1118_driver = { + .name = "Marvell 88E1118", + .uid = 0x1410e10, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1118_config, + .startup = &m88e1118_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1121R_driver = { + .name = "Marvell 88E1121R", + .uid = 0x1410cb0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1121_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1145_driver = { + .name = "Marvell 88E1145", + .uid = 0x1410cd0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1145_config, + .startup = &m88e1145_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1149S_driver = { + .name = "Marvell 88E1149S", + .uid = 0x1410ca0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1149_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_marvell_init(void) +{ + phy_register(&M88E1149S_driver); + phy_register(&M88E1145_driver); + phy_register(&M88E1121R_driver); + phy_register(&M88E1118_driver); + phy_register(&M88E1111S_driver); + phy_register(&M88E1011S_driver); + + return 0; +} diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c new file mode 100644 index 00000000000..47064a18536 --- /dev/null +++ b/drivers/net/phy/micrel.c @@ -0,0 +1,40 @@ +/* + * Micrel PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +static struct phy_driver KSZ804_driver = { + .name = "Micrel KSZ804", + .uid = 0x221510, + .mask = 0xfffff0, + .features = PHY_BASIC_FEATURES, + .config = &genphy_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_micrel_init(void) +{ + phy_register(&KSZ804_driver); + + return 0; +} diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c new file mode 100644 index 00000000000..ea60ac1b0e6 --- /dev/null +++ b/drivers/net/phy/natsemi.c @@ -0,0 +1,96 @@ +/* + * National Semiconductor PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +/* DP83865 Link and Auto-Neg Status Register */ +#define MIIM_DP83865_LANR 0x11 +#define MIIM_DP83865_SPD_MASK 0x0018 +#define MIIM_DP83865_SPD_1000 0x0010 +#define MIIM_DP83865_SPD_100 0x0008 +#define MIIM_DP83865_DPX_FULL 0x0002 + + +/* NatSemi DP83865 */ +static int dp83865_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + genphy_config_aneg(phydev); + + return 0; +} + +static int dp83865_parse_status(struct phy_device *phydev) +{ + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DP83865_LANR); + + switch (mii_reg & MIIM_DP83865_SPD_MASK) { + + case MIIM_DP83865_SPD_1000: + phydev->speed = SPEED_1000; + break; + + case MIIM_DP83865_SPD_100: + phydev->speed = SPEED_100; + break; + + default: + phydev->speed = SPEED_10; + break; + + } + + if (mii_reg & MIIM_DP83865_DPX_FULL) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + return 0; +} + +static int dp83865_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + dp83865_parse_status(phydev); + + return 0; +} + + +static struct phy_driver DP83865_driver = { + .name = "NatSemi DP83865", + .uid = 0x20005c70, + .mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .config = &dp83865_config, + .startup = &dp83865_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_natsemi_init(void) +{ + phy_register(&DP83865_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 919011dbe2a..c7edcc09097 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -420,6 +420,37 @@ static LIST_HEAD(phy_drivers); int phy_init(void) { +#ifdef CONFIG_PHY_ATHEROS + phy_atheros_init(); +#endif +#ifdef CONFIG_PHY_BROADCOM + phy_broadcom_init(); +#endif +#ifdef CONFIG_PHY_DAVICOM + phy_davicom_init(); +#endif +#ifdef CONFIG_PHY_LXT + phy_lxt_init(); +#endif +#ifdef CONFIG_PHY_MARVELL + phy_marvell_init(); +#endif +#ifdef CONFIG_PHY_MICREL + phy_micrel_init(); +#endif +#ifdef CONFIG_PHY_NATSEMI + phy_natsemi_init(); +#endif +#ifdef CONFIG_PHY_REALTEK + phy_realtek_init(); +#endif +#ifdef CONFIG_PHY_TERANETICS + phy_teranetics_init(); +#endif +#ifdef CONFIG_PHY_VITESSE + phy_vitesse_init(); +#endif + return 0; } diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c new file mode 100644 index 00000000000..b7e2753f7bd --- /dev/null +++ b/drivers/net/phy/realtek.c @@ -0,0 +1,130 @@ +/* + * RealTek PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include +#include + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* RTL8211B PHY Status Register */ +#define MIIM_RTL8211B_PHY_STATUS 0x11 +#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000 +#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000 +#define MIIM_RTL8211B_PHYSTAT_100 0x4000 +#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000 +#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800 +#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400 + + +/* RealTek RTL8211B */ +static int rtl8211b_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + genphy_config_aneg(phydev); + + return 0; +} + +static int rtl8211b_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211B_PHY_STATUS); + + if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + int i = 0; + + /* in case of timeout ->link is cleared */ + phydev->link = 1; + puts("Waiting for PHY realtime link"); + while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + /* Timeout reached ? */ + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { + puts(" TIMEOUT !\n"); + phydev->link = 0; + break; + } + + if ((i++ % 1000) == 0) + putc('.'); + udelay(1000); /* 1 ms */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_RTL8211B_PHY_STATUS); + } + puts(" done\n"); + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) + phydev->link = 1; + else + phydev->link = 0; + } + + if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); + + switch (speed) { + case MIIM_RTL8211B_PHYSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_RTL8211B_PHYSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + } + + return 0; +} + +static int rtl8211b_startup(struct phy_device *phydev) +{ + /* Read the Status (2x to make sure link is right) */ + genphy_update_link(phydev); + rtl8211b_parse_status(phydev); + + return 0; +} + +static struct phy_driver RTL8211B_driver = { + .name = "RealTek RTL8211B", + .uid = 0x1cc910, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &rtl8211b_config, + .startup = &rtl8211b_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_realtek_init(void) +{ + phy_register(&RTL8211B_driver); + + return 0; +} diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c new file mode 100644 index 00000000000..a771791b764 --- /dev/null +++ b/drivers/net/phy/teranetics.c @@ -0,0 +1,62 @@ +/* + * Teranetics PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include + +#ifndef CONFIG_PHYLIB_10G +#error The Teranetics PHY needs 10G support +#endif + +int tn2020_config(struct phy_device *phydev) +{ + if (phydev->port == PORT_FIBRE) { + unsigned short restart_an = (MDIO_AN_CTRL1_RESTART | + MDIO_AN_CTRL1_ENABLE | + MDIO_AN_CTRL1_XNP); + + phy_write(phydev, 30, 93, 2); + phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an); + } + + return 0; +} + +struct phy_driver tn2020_driver = { + .name = "Teranetics TN2020", + .uid = 0x00a19410, + .mask = 0xfffffff0, + .features = PHY_10G_FEATURES, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_AN | + MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2), + .config = &tn2020_config, + .startup = &gen10g_startup, + .shutdown = &gen10g_shutdown, +}; + +int phy_teranetics_init(void) +{ + phy_register(&tn2020_driver); + + return 0; +} diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c new file mode 100644 index 00000000000..d48d4fe73f0 --- /dev/null +++ b/drivers/net/phy/vitesse.c @@ -0,0 +1,242 @@ +/* + * Vitesse PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS82xx_AUX_CONSTAT 0x1c +#define MIIM_CIS82xx_AUXCONSTAT_INIT 0x0004 +#define MIIM_CIS82xx_AUXCONSTAT_DUPLEX 0x0020 +#define MIIM_CIS82xx_AUXCONSTAT_SPEED 0x0018 +#define MIIM_CIS82xx_AUXCONSTAT_GBIT 0x0010 +#define MIIM_CIS82xx_AUXCONSTAT_100 0x0008 + +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS82xx_EXT_CON1 0x17 +#define MIIM_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada 8204 Extended PHY Control Register 1 */ +#define MIIM_CIS8204_EPHY_CON 0x17 +#define MIIM_CIS8204_EPHYCON_INIT 0x0006 +#define MIIM_CIS8204_EPHYCON_RGMII 0x1100 + +/* Cicada 8204 Serial LED Control Register */ +#define MIIM_CIS8204_SLED_CON 0x1b +#define MIIM_CIS8204_SLEDCON_INIT 0x1115 + +/* Vitesse VSC8601 Extended PHY Control Register 1 */ +#define MIIM_VSC8601_EPHY_CON 0x17 +#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120 +#define MIIM_VSC8601_SKEW_CTRL 0x1c + +#define PHY_EXT_PAGE_ACCESS 0x1f + +/* CIS8201 */ +static int vitesse_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, + MIIM_CIS82xx_AUXCONSTAT_INIT); + /* Set up the interface mode */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1, + MIIM_CIS8201_EXTCON1_INIT); + + genphy_config_aneg(phydev); + + return 0; +} + +static int vitesse_parse_status(struct phy_device *phydev) +{ + int speed; + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT); + + if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED; + switch (speed) { + case MIIM_CIS82xx_AUXCONSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_CIS82xx_AUXCONSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int vitesse_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + vitesse_parse_status(phydev); + + return 0; +} + +static int cis8204_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, + MIIM_CIS82xx_AUXCONSTAT_INIT); + + genphy_config_aneg(phydev); + + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, + MIIM_CIS8204_EPHYCON_INIT | + MIIM_CIS8204_EPHYCON_RGMII); + else + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, + MIIM_CIS8204_EPHYCON_INIT); + + return 0; +} + +/* Vitesse VSC8601 */ +int vsc8601_config(struct phy_device *phydev) +{ + /* Configure some basic stuff */ +#ifdef CONFIG_SYS_VSC8601_SKEWFIX + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON, + MIIM_VSC8601_EPHY_CON_INIT_SKEW); +#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1); +#define VSC8101_SKEW \ + ((CONFIG_SYS_VSC8601_SKEW_TX << 14) \ + | (CONFIG_SYS_VSC8601_SKEW_RX << 12)) + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL, + VSC8101_SKEW); + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); +#endif +#endif + + genphy_config_aneg(phydev); + + return 0; +} + +static struct phy_driver VSC8211_driver = { + .name = "Vitesse VSC8211", + .uid = 0xfc4b0, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vitesse_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8221_driver = { + .name = "Vitesse VSC8221", + .uid = 0xfc550, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8244_driver = { + .name = "Vitesse VSC8244", + .uid = 0xfc6c0, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8234_driver = { + .name = "Vitesse VSC8234", + .uid = 0xfc620, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8601_driver = { + .name = "Vitesse VSC8601", + .uid = 0x70420, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8601_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8641_driver = { + .name = "Vitesse VSC8641", + .uid = 0x70430, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +/* Vitesse bought Cicada, so we'll put these here */ +static struct phy_driver cis8201_driver = { + .name = "CIS8201", + .uid = 0xfc410, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vitesse_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver cis8204_driver = { + .name = "Cicada Cis8204", + .uid = 0xfc440, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &cis8204_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_vitesse_init(void) +{ + phy_register(&VSC8641_driver); + phy_register(&VSC8601_driver); + phy_register(&VSC8234_driver); + phy_register(&VSC8244_driver); + phy_register(&VSC8211_driver); + phy_register(&VSC8221_driver); + phy_register(&cis8201_driver); + phy_register(&cis8204_driver); + + return 0; +} -- cgit v1.2.3 From 063c12633d5ad74d52152d9c358e715475e17629 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 8 Apr 2011 02:10:54 -0500 Subject: tsec: Convert tsec to use PHY Lib This converts tsec to use the new PHY Lib. All of the old PHY support is ripped out. The old MDIO driver is split off, and placed in fsl_mdio.c. The initialization is modified to initialize the MDIO driver as well. The powerpc config file is modified to configure PHYLIB if TSEC_ENET is configured. Signed-off-by: Mingkai Hu Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala Acked-by: Detlev Zundel --- drivers/net/Makefile | 2 +- drivers/net/fsl_mdio.c | 120 ++++ drivers/net/tsec.c | 1602 +++--------------------------------------------- 3 files changed, 219 insertions(+), 1505 deletions(-) create mode 100644 drivers/net/fsl_mdio.c (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index fd9d0b4be11..819b197673b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -79,7 +79,7 @@ COBJS-$(CONFIG_TIGON3) += tigon3.o COBJS-$(CONFIG_TIGON3) += bcm570x_autoneg.o COBJS-$(CONFIG_TIGON3) += 5701rls.o COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o -COBJS-$(CONFIG_TSEC_ENET) += tsec.o +COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c new file mode 100644 index 00000000000..1aab307897e --- /dev/null +++ b/drivers/net/fsl_mdio.c @@ -0,0 +1,120 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * Jun-jie Zhang + * Mingkai Hu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +void tsec_local_mdio_write(struct tsec_mii_mng *phyregs, int port_addr, + int dev_addr, int regnum, int value) +{ + int timeout = 1000000; + + out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); + out_be32(&phyregs->miimcon, value); + asm("sync"); + + while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) + ; +} + +int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr, + int dev_addr, int regnum) +{ + int value; + int timeout = 1000000; + + /* Put the address of the phy, and the register + * number into MIIMADD */ + out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); + + /* Clear the command register, and wait */ + out_be32(&phyregs->miimcom, 0); + asm("sync"); + + /* Initiate a read command, and wait */ + out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE); + asm("sync"); + + /* Wait for the the indication that the read is done */ + while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + && timeout--) + ; + + /* Grab the value read from the PHY */ + value = in_be32(&phyregs->miimstat); + + return value; +} + +static int fsl_pq_mdio_reset(struct mii_dev *bus) +{ + struct tsec_mii_mng *regs = bus->priv; + + /* Reset MII (due to new addresses) */ + out_be32(®s->miimcfg, MIIMCFG_RESET_MGMT); + + out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); + + while (in_be32(®s->miimind) & MIIMIND_BUSY) + ; + + return 0; +} + +int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum) +{ + struct tsec_mii_mng *phyregs = bus->priv; + + return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum); +} + +int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum, + u16 value) +{ + struct tsec_mii_mng *phyregs = bus->priv; + + tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value); + + return 0; +} + +int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info) +{ + struct mii_dev *bus = mdio_alloc(); + + if (!bus) { + printf("Failed to allocate FSL MDIO bus\n"); + return -1; + } + + bus->read = tsec_phy_read; + bus->write = tsec_phy_write; + bus->reset = fsl_pq_mdio_reset; + sprintf(bus->name, info->name); + + bus->priv = info->regs; + + return mdio_register(bus); +} diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index a3857b3bbf3..06e5834a94c 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -17,10 +17,9 @@ #include #include #include +#include #include -#include "miiphy.h" - DECLARE_GLOBAL_DATA_PTR; #define TX_BUF_CNT 2 @@ -56,10 +55,10 @@ static struct tsec_info_struct tsec_info[] = { #ifdef CONFIG_MPC85XX_FEC { .regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000), - .miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR), .devname = CONFIG_MPC85XX_FEC_NAME, .phyaddr = FEC_PHY_ADDR, - .flags = FEC_FLAGS + .flags = FEC_FLAGS, + .mii_devname = DEFAULT_MII_NAME }, /* FEC */ #endif #ifdef CONFIG_TSEC3 @@ -70,58 +69,6 @@ static struct tsec_info_struct tsec_info[] = { #endif }; -/* Writes the given phy's reg with value, using the specified MDIO regs */ -static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr, - uint reg, uint value) -{ - int timeout = 1000000; - - out_be32(&phyregs->miimadd, (addr << 8) | reg); - out_be32(&phyregs->miimcon, value); - - timeout = 1000000; - while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) - ; -} - -/* Provide the default behavior of writing the PHY of this ethernet device */ -#define write_phy_reg(priv, regnum, value) \ - tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value) - -/* Reads register regnum on the device's PHY through the - * specified registers. It lowers and raises the read - * command, and waits for the data to become valid (miimind - * notvalid bit cleared), and the bus to cease activity (miimind - * busy bit cleared), and then returns the value - */ -static uint tsec_local_mdio_read(tsec_mdio_t *phyregs, uint phyid, uint regnum) -{ - uint value; - - /* Put the address of the phy, and the register - * number into MIIMADD */ - out_be32(&phyregs->miimadd, (phyid << 8) | regnum); - - /* Clear the command register, and wait */ - out_be32(&phyregs->miimcom, 0); - - /* Initiate a read command, and wait */ - out_be32(&phyregs->miimcom, MIIM_READ_COMMAND); - - /* Wait for the the indication that the read is done */ - while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))) - ; - - /* Grab the value read from the PHY */ - value = in_be32(&phyregs->miimstat); - - return value; -} - -/* #define to provide old read_phy_reg functionality without duplicating code */ -#define read_phy_reg(priv,regnum) \ - tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum) - #define TBIANA_SETTINGS ( \ TBIANA_ASYMMETRIC_PAUSE \ | TBIANA_SYMMETRIC_PAUSE \ @@ -143,1407 +90,14 @@ static void tsec_configure_serdes(struct tsec_private *priv) { /* Access TBI PHY registers at given TSEC register offset as opposed * to the register offset used for external PHY accesses */ - tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_ANA, - TBIANA_SETTINGS); - tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_TBICON, - TBICON_CLK_SELECT); - tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_CR, - CONFIG_TSEC_TBICR_SETTINGS); -} - -/* - * Returns which value to write to the control register. - * For 10/100, the value is slightly different - */ -static uint mii_cr_init(uint mii_reg, struct tsec_private * priv) -{ - if (priv->flags & TSEC_GIGABIT) - return MIIM_CONTROL_INIT; - else - return MIIM_CR_INIT; + tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), + 0, TBI_ANA, TBIANA_SETTINGS); + tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), + 0, TBI_TBICON, TBICON_CLK_SELECT); + tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), + 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); } -/* - * Wait for auto-negotiation to complete, then determine link - */ -static uint mii_parse_sr(uint mii_reg, struct tsec_private * priv) -{ - /* - * Wait if the link is up, and autonegotiation is in progress - * (ie - we're capable and it's not done) - */ - mii_reg = read_phy_reg(priv, MIIM_STATUS); - if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { - int i = 0; - - puts("Waiting for PHY auto negotiation to complete"); - while (!(mii_reg & BMSR_ANEGCOMPLETE)) { - /* - * Timeout reached ? - */ - if (i > PHY_AUTONEGOTIATE_TIMEOUT) { - puts(" TIMEOUT !\n"); - priv->link = 0; - return 0; - } - - if (ctrlc()) { - puts("user interrupt!\n"); - priv->link = 0; - return -EINTR; - } - - if ((i++ % 1000) == 0) { - putc('.'); - } - udelay(1000); /* 1 ms */ - mii_reg = read_phy_reg(priv, MIIM_STATUS); - } - puts(" done\n"); - - /* Link status bit is latched low, read it again */ - mii_reg = read_phy_reg(priv, MIIM_STATUS); - - udelay(500000); /* another 500 ms (results in faster booting) */ - } - - priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0; - - return 0; -} - -/* Generic function which updates the speed and duplex. If - * autonegotiation is enabled, it uses the AND of the link - * partner's advertised capabilities and our advertised - * capabilities. If autonegotiation is disabled, we use the - * appropriate bits in the control register. - * - * Stolen from Linux's mii.c and phy_device.c - */ -static uint mii_parse_link(uint mii_reg, struct tsec_private *priv) -{ - /* We're using autonegotiation */ - if (mii_reg & BMSR_ANEGCAPABLE) { - uint lpa = 0; - uint gblpa = 0; - - /* Check for gigabit capability */ - if (mii_reg & BMSR_ERCAP) { - /* We want a list of states supported by - * both PHYs in the link - */ - gblpa = read_phy_reg(priv, MII_STAT1000); - gblpa &= read_phy_reg(priv, MII_CTRL1000) << 2; - } - - /* Set the baseline so we only have to set them - * if they're different - */ - priv->speed = 10; - priv->duplexity = 0; - - /* Check the gigabit fields */ - if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { - priv->speed = 1000; - - if (gblpa & PHY_1000BTSR_1000FD) - priv->duplexity = 1; - - /* We're done! */ - return 0; - } - - lpa = read_phy_reg(priv, MII_ADVERTISE); - lpa &= read_phy_reg(priv, MII_LPA); - - if (lpa & (LPA_100FULL | LPA_100HALF)) { - priv->speed = 100; - - if (lpa & LPA_100FULL) - priv->duplexity = 1; - - } else if (lpa & LPA_10FULL) - priv->duplexity = 1; - } else { - uint bmcr = read_phy_reg(priv, MII_BMCR); - - priv->speed = 10; - priv->duplexity = 0; - - if (bmcr & BMCR_FULLDPLX) - priv->duplexity = 1; - - if (bmcr & BMCR_SPEED1000) - priv->speed = 1000; - else if (bmcr & BMCR_SPEED100) - priv->speed = 100; - } - - return 0; -} - -/* - * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain - * circumstances. eg a gigabit TSEC connected to a gigabit switch with - * a 4-wire ethernet cable. Both ends advertise gigabit, but can't - * link. "Ethernet@Wirespeed" reduces advertised speed until link - * can be achieved. - */ -static uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv) -{ - return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010; -} - -/* - * Parse the BCM54xx status register for speed and duplex information. - * The linux sungem_phy has this information, but in a table format. - */ -static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv) -{ - /* If there is no link, speed and duplex don't matter */ - if (!priv->link) - return 0; - - switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> - MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) { - case 1: - priv->duplexity = 0; - priv->speed = 10; - break; - case 2: - priv->duplexity = 1; - priv->speed = 10; - break; - case 3: - priv->duplexity = 0; - priv->speed = 100; - break; - case 5: - priv->duplexity = 1; - priv->speed = 100; - break; - case 6: - priv->duplexity = 0; - priv->speed = 1000; - break; - case 7: - priv->duplexity = 1; - priv->speed = 1000; - break; - default: - printf("Auto-neg error, defaulting to 10BT/HD\n"); - priv->duplexity = 0; - priv->speed = 10; - break; - } - - return 0; -} - -/* - * Find out if PHY is in copper or serdes mode by looking at Expansion Reg - * 0x42 - "Operating Mode Status Register" - */ -static int BCM8482_is_serdes(struct tsec_private *priv) -{ - u16 val; - int serdes = 0; - - write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42); - val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); - - switch (val & 0x1f) { - case 0x0d: /* RGMII-to-100Base-FX */ - case 0x0e: /* RGMII-to-SGMII */ - case 0x0f: /* RGMII-to-SerDes */ - case 0x12: /* SGMII-to-SerDes */ - case 0x13: /* SGMII-to-100Base-FX */ - case 0x16: /* SerDes-to-Serdes */ - serdes = 1; - break; - case 0x6: /* RGMII-to-Copper */ - case 0x14: /* SGMII-to-Copper */ - case 0x17: /* SerDes-to-Copper */ - break; - default: - printf("ERROR, invalid PHY mode (0x%x\n)", val); - break; - } - - return serdes; -} - -/* - * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating - * Mode Status Register" - */ -uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv) -{ - u16 val; - int i = 0; - - /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ - while (1) { - write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, - MIIM_BCM54XX_EXP_SEL_ER | 0x42); - val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); - - if (val & 0x8000) - break; - - if (i++ > 1000) { - priv->link = 0; - return 1; - } - - udelay(1000); /* 1 ms */ - } - - priv->link = 1; - switch ((val >> 13) & 0x3) { - case (0x00): - priv->speed = 10; - break; - case (0x01): - priv->speed = 100; - break; - case (0x02): - priv->speed = 1000; - break; - } - - priv->duplexity = (val & 0x1000) == 0x1000; - - return 0; -} - -/* - * Figure out if BCM5482 is in serdes or copper mode and determine link - * configuration accordingly - */ -static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv) -{ - if (BCM8482_is_serdes(priv)) { - mii_parse_BCM5482_serdes_sr(priv); - priv->flags |= TSEC_FIBER; - } else { - /* Wait for auto-negotiation to complete or fail */ - mii_parse_sr(mii_reg, priv); - - /* Parse BCM54xx copper aux status register */ - mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS); - mii_parse_BCM54xx_sr(mii_reg, priv); - } - - return 0; -} - -/* Parse the 88E1011's status register for speed and duplex - * information - */ -static uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv) -{ - uint speed; - - mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS); - - if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && - !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { - int i = 0; - - puts("Waiting for PHY realtime link"); - while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { - /* Timeout reached ? */ - if (i > PHY_AUTONEGOTIATE_TIMEOUT) { - puts(" TIMEOUT !\n"); - priv->link = 0; - break; - } - - if ((i++ % 1000) == 0) { - putc('.'); - } - udelay(1000); /* 1 ms */ - mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS); - } - puts(" done\n"); - udelay(500000); /* another 500 ms (results in faster booting) */ - } else { - if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) - priv->link = 1; - else - priv->link = 0; - } - - if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); - - switch (speed) { - case MIIM_88E1011_PHYSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_88E1011_PHYSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - } - - return 0; -} - -/* Parse the RTL8211B's status register for speed and duplex - * information - */ -static uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv) -{ - uint speed; - - mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); - if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { - int i = 0; - - /* in case of timeout ->link is cleared */ - priv->link = 1; - puts("Waiting for PHY realtime link"); - while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { - /* Timeout reached ? */ - if (i > PHY_AUTONEGOTIATE_TIMEOUT) { - puts(" TIMEOUT !\n"); - priv->link = 0; - break; - } - - if ((i++ % 1000) == 0) { - putc('.'); - } - udelay(1000); /* 1 ms */ - mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); - } - puts(" done\n"); - udelay(500000); /* another 500 ms (results in faster booting) */ - } else { - if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) - priv->link = 1; - else - priv->link = 0; - } - - if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); - - switch (speed) { - case MIIM_RTL8211B_PHYSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_RTL8211B_PHYSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - } - - return 0; -} - -/* Parse the cis8201's status register for speed and duplex - * information - */ -static uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv) -{ - uint speed; - - if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; - switch (speed) { - case MIIM_CIS8201_AUXCONSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_CIS8201_AUXCONSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - break; - } - - return 0; -} - -/* Parse the vsc8244's status register for speed and duplex - * information - */ -static uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv) -{ - uint speed; - - if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED; - switch (speed) { - case MIIM_VSC8244_AUXCONSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_VSC8244_AUXCONSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - break; - } - - return 0; -} - -/* Parse the DM9161's status register for speed and duplex - * information - */ -static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv) -{ - if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) - priv->speed = 100; - else - priv->speed = 10; - - if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) - priv->duplexity = 1; - else - priv->duplexity = 0; - - return 0; -} - -/* - * Hack to write all 4 PHYs with the LED values - */ -static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv) -{ - uint phyid; - tsec_mdio_t *regbase = priv->phyregs; - int timeout = 1000000; - - for (phyid = 0; phyid < 4; phyid++) { - out_be32(®base->miimadd, (phyid << 8) | mii_reg); - out_be32(®base->miimcon, MIIM_CIS8204_SLEDCON_INIT); - - timeout = 1000000; - while ((in_be32(®base->miimind) & MIIMIND_BUSY) && timeout--) - ; - } - - return MIIM_CIS8204_SLEDCON_INIT; -} - -static uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv) -{ - if (priv->flags & TSEC_REDUCED) - return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII; - else - return MIIM_CIS8204_EPHYCON_INIT; -} - -static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv) -{ - uint mii_data = read_phy_reg(priv, mii_reg); - - if (priv->flags & TSEC_REDUCED) - mii_data = (mii_data & 0xfff0) | 0x000b; - return mii_data; -} - -static struct phy_info phy_info_M88E1149S = { - 0x1410ca, - "Marvell 88E1149S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1d, 0x1f, NULL}, - {0x1e, 0x200c, NULL}, - {0x1d, 0x5, NULL}, - {0x1e, 0x0, NULL}, - {0x1e, 0x100, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */ -static struct phy_info phy_info_BCM5461S = { - 0x02060c1, /* 5461 ID */ - "Broadcom BCM5461S", - 0, /* not clear to me what minor revisions we can shift away */ - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_BCM5464S = { - 0x02060b1, /* 5464 ID */ - "Broadcom BCM5464S", - 0, /* not clear to me what minor revisions we can shift away */ - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_BCM5482S = { - 0x0143bcb, - "Broadcom BCM5482S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - /* Setup read from auxilary control shadow register 7 */ - {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL}, - /* Read Misc Control register and or in Ethernet@Wirespeed */ - {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - /* Initial config/enable of secondary SerDes interface */ - {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL}, - /* Write intial value to secondary SerDes Contol */ - {MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL}, - {MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL}, - /* Enable copper/fiber auto-detect */ - {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Determine copper/fiber, auto-negotiate, and read the result */ - {MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_M88E1011S = { - 0x01410c6, - "Marvell 88E1011S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1d, 0x1f, NULL}, - {0x1e, 0x200c, NULL}, - {0x1d, 0x5, NULL}, - {0x1e, 0x0, NULL}, - {0x1e, 0x100, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_M88E1111S = { - 0x01410cc, - "Marvell 88E1111S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1b, 0x848f, &mii_m88e1111s_setmode}, - {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */ - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_M88E1118 = { - 0x01410e1, - "Marvell 88E1118", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x16, 0x0002, NULL}, /* Change Page Number */ - {0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */ - {0x16, 0x0003, NULL}, /* Change Page Number */ - {0x10, 0x021e, NULL}, /* Adjust LED control */ - {0x16, 0x0000, NULL}, /* Change Page Number */ - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {0x16, 0x0000, NULL}, /* Change Page Number */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, - &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -/* - * Since to access LED register we need do switch the page, we - * do LED configuring in the miim_read-like function as follows - */ -static uint mii_88E1121_set_led (uint mii_reg, struct tsec_private *priv) -{ - uint pg; - - /* Switch the page to access the led register */ - pg = read_phy_reg(priv, MIIM_88E1121_PHY_PAGE); - write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, MIIM_88E1121_PHY_LED_PAGE); - - /* Configure leds */ - write_phy_reg(priv, MIIM_88E1121_PHY_LED_CTRL, - MIIM_88E1121_PHY_LED_DEF); - - /* Restore the page pointer */ - write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, pg); - return 0; -} - -static struct phy_info phy_info_M88E1121R = { - 0x01410cb, - "Marvell 88E1121R", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - /* Configure leds */ - {MIIM_88E1121_PHY_LED_CTRL, miim_read, &mii_88E1121_set_led}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - /* Disable IRQs and de-assert interrupt */ - {MIIM_88E1121_PHY_IRQ_EN, 0, NULL}, - {MIIM_88E1121_PHY_IRQ_STATUS, miim_read, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_STATUS, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv) -{ - uint mii_data = read_phy_reg(priv, mii_reg); - - /* Setting MIIM_88E1145_PHY_EXT_CR */ - if (priv->flags & TSEC_REDUCED) - return mii_data | - MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY; - else - return mii_data; -} - -static struct phy_info phy_info_M88E1145 = { - 0x01410cd, - "Marvell 88E1145", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - - /* Errata E0, E1 */ - {29, 0x001b, NULL}, - {30, 0x418f, NULL}, - {29, 0x0016, NULL}, - {30, 0xa2da, NULL}, - - /* Configure the PHY */ - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO, NULL}, - {MIIM_88E1145_PHY_EXT_CR, 0, &m88e1145_setmode}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_88E1111_PHY_LED_CONTROL, MIIM_88E1111_PHY_LED_DIRECT, NULL}, - /* Read the Status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_cis8204 = { - 0x3f11, - "Cicada Cis8204", - 6, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT, - &mii_cis8204_fixled}, - {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT, - &mii_cis8204_setmode}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -/* Cicada 8201 */ -static struct phy_info phy_info_cis8201 = { - 0xfc41, - "CIS8201", - 4, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Set up the interface mode */ - {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_VSC8211 = { - 0xfc4b, - "Vitesse VSC8211", - 4, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Set up the interface mode */ - {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_VSC8244 = { - 0x3f1b, - "Vitesse VSC8244", - 6, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_VSC8641 = { - 0x7043, - "Vitesse VSC8641", - 4, - (struct phy_cmd[]) { /* config */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_VSC8221 = { - 0xfc55, - "Vitesse VSC8221", - 4, - (struct phy_cmd[]) { /* config */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_VSC8601 = { - 0x00007042, - "Vitesse VSC8601", - 4, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, -#ifdef CONFIG_SYS_VSC8601_SKEWFIX - {MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL}, -#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) - {MIIM_EXT_PAGE_ACCESS,1,NULL}, -#define VSC8101_SKEW \ - (CONFIG_SYS_VSC8601_SKEW_TX << 14) | (CONFIG_SYS_VSC8601_SKEW_RX << 12) - {MIIM_VSC8601_SKEW_CTRL,VSC8101_SKEW,NULL}, - {MIIM_EXT_PAGE_ACCESS,0,NULL}, -#endif -#endif - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_dm9161 = { - 0x0181b88, - "Davicom DM9161E", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL}, - /* Do not bypass the scrambler/descrambler */ - {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL}, - /* Clear 10BTCSR to default */ - {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CR_INIT, NULL}, - /* Restart Auto Negotiation */ - {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -/* micrel KSZ804 */ -static struct phy_info phy_info_ksz804 = { - 0x0022151, - "Micrel KSZ804 PHY", - 4, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - } -}; - -/* a generic flavor. */ -static struct phy_info phy_info_generic = { - 0, - "Unknown/Generic PHY", - 32, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - } -}; - -static uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv) -{ - unsigned int speed; - if (priv->link) { - speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK; - - switch (speed) { - case MIIM_LXT971_SR2_10HDX: - priv->speed = 10; - priv->duplexity = 0; - break; - case MIIM_LXT971_SR2_10FDX: - priv->speed = 10; - priv->duplexity = 1; - break; - case MIIM_LXT971_SR2_100HDX: - priv->speed = 100; - priv->duplexity = 0; - break; - default: - priv->speed = 100; - priv->duplexity = 1; - } - } else { - priv->speed = 0; - priv->duplexity = 0; - } - - return 0; -} - -static struct phy_info phy_info_lxt971 = { - 0x0001378e, - "LXT971", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CR, MIIM_CR_INIT, mii_cr_init}, /* autonegotiate */ - {miim_end,} - }, - (struct phy_cmd[]) { /* startup - enable interrupts */ - /* { 0x12, 0x00f2, NULL }, */ - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown - disable interrupts */ - {miim_end,} - }, -}; - -/* Parse the DP83865's link and auto-neg status register for speed and duplex - * information - */ -static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv) -{ - switch (mii_reg & MIIM_DP83865_SPD_MASK) { - - case MIIM_DP83865_SPD_1000: - priv->speed = 1000; - break; - - case MIIM_DP83865_SPD_100: - priv->speed = 100; - break; - - default: - priv->speed = 10; - break; - - } - - if (mii_reg & MIIM_DP83865_DPX_FULL) - priv->duplexity = 1; - else - priv->duplexity = 0; - - return 0; -} - -static struct phy_info phy_info_dp83865 = { - 0x20005c7, - "NatSemi DP83865", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the link and auto-neg status */ - {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_rtl8211b = { - 0x001cc91, - "RealTek RTL8211B", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -struct phy_info phy_info_AR8021 = { - 0x4dd04, - "AR8021", - 4, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {0x1d, 0x05, NULL}, - {0x1e, 0x3D47, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - } -}; - -static struct phy_info *phy_info[] = { - &phy_info_cis8204, - &phy_info_cis8201, - &phy_info_BCM5461S, - &phy_info_BCM5464S, - &phy_info_BCM5482S, - &phy_info_M88E1011S, - &phy_info_M88E1111S, - &phy_info_M88E1118, - &phy_info_M88E1121R, - &phy_info_M88E1145, - &phy_info_M88E1149S, - &phy_info_dm9161, - &phy_info_ksz804, - &phy_info_lxt971, - &phy_info_VSC8211, - &phy_info_VSC8244, - &phy_info_VSC8601, - &phy_info_VSC8641, - &phy_info_VSC8221, - &phy_info_dp83865, - &phy_info_rtl8211b, - &phy_info_AR8021, - &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */ - NULL -}; - -/* Grab the identifier of the device's PHY, and search through - * all of the known PHYs to see if one matches. If so, return - * it, if not, return NULL - */ -static struct phy_info *get_phy_info(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - uint phy_reg, phy_ID; - int i; - struct phy_info *theInfo = NULL; - - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = read_phy_reg(priv, MIIM_PHYIR1); - phy_ID = (phy_reg & 0xffff) << 16; - - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = read_phy_reg(priv, MIIM_PHYIR2); - phy_ID |= (phy_reg & 0xffff); - - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) { - if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { - theInfo = phy_info[i]; - break; - } - } - - if (theInfo == &phy_info_generic) { - printf("%s: No support for PHY id %x; assuming generic\n", - dev->name, phy_ID); - } else { - debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); - } - - return theInfo; -} - -/* Execute the given series of commands on the given device's - * PHY, running functions as necessary - */ -static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) -{ - int i; - uint result; - tsec_mdio_t *phyregs = priv->phyregs; - - out_be32(&phyregs->miimcfg, MIIMCFG_RESET); - - out_be32(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); - - while (in_be32(&phyregs->miimind) & MIIMIND_BUSY) - ; - - for (i = 0; cmd->mii_reg != miim_end; i++) { - if (cmd->mii_data == miim_read) { - result = read_phy_reg(priv, cmd->mii_reg); - - if (cmd->funct != NULL) - (*(cmd->funct)) (result, priv); - - } else { - if (cmd->funct != NULL) - result = (*(cmd->funct)) (cmd->mii_reg, priv); - else - result = cmd->mii_data; - - write_phy_reg(priv, cmd->mii_reg, result); - - } - cmd++; - } -} - -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) - -/* - * Read a MII PHY register. - * - * Returns: - * 0 on success - */ -static int tsec_miiphy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value) -{ - unsigned short ret; - struct tsec_private *priv = privlist[0]; - - if (NULL == priv) { - printf("Can't read PHY at address %d\n", addr); - return -1; - } - - ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg); - *value = ret; - - return 0; -} - -/* - * Write a MII PHY register. - * - * Returns: - * 0 on success - */ -static int tsec_miiphy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value) -{ - struct tsec_private *priv = privlist[0]; - - if (NULL == priv) { - printf("Can't write PHY at address %d\n", addr); - return -1; - } - - tsec_local_mdio_write(priv->phyregs, addr, reg, value); - - return 0; -} - -#endif - #ifdef CONFIG_MCAST_TFTP /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ @@ -1635,14 +189,13 @@ static void init_registers(tsec_t *regs) /* Configure maccfg2 based on negotiated speed and duplex * reported by PHY handling code */ -static void adjust_link(struct eth_device *dev) +static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) { - struct tsec_private *priv = (struct tsec_private *)dev->priv; tsec_t *regs = priv->regs; u32 ecntrl, maccfg2; - if (!priv->link) { - printf("%s: No link.\n", dev->name); + if (!phydev->link) { + printf("%s: No link.\n", phydev->dev->name); return; } @@ -1653,10 +206,10 @@ static void adjust_link(struct eth_device *dev) maccfg2 = in_be32(®s->maccfg2); maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); - if (priv->duplexity) + if (phydev->duplex) maccfg2 |= MACCFG2_FULL_DUPLEX; - switch (priv->speed) { + switch (phydev->speed) { case 1000: maccfg2 |= MACCFG2_GMII; break; @@ -1667,20 +220,20 @@ static void adjust_link(struct eth_device *dev) /* Set R100 bit in all modes although * it is only used in RGMII mode */ - if (priv->speed == 100) + if (phydev->speed == 100) ecntrl |= ECNTRL_R100; break; default: - printf("%s: Speed was bad\n", dev->name); + printf("%s: Speed was bad\n", phydev->dev->name); break; } out_be32(®s->ecntrl, ecntrl); out_be32(®s->maccfg2, maccfg2); - printf("Speed: %d, %s duplex%s\n", priv->speed, - (priv->duplexity) ? "full" : "half", - (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); + printf("Speed: %d, %s duplex%s\n", phydev->speed, + (phydev->duplex) ? "full" : "half", + (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); } /* Set up the buffers and their descriptors, and bring up the @@ -1692,6 +245,10 @@ static void startup_tsec(struct eth_device *dev) struct tsec_private *priv = (struct tsec_private *)dev->priv; tsec_t *regs = priv->regs; + /* reset the indices to zero */ + rxIdx = 0; + txIdx = 0; + /* Point to the buffer descriptors */ out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); @@ -1712,12 +269,6 @@ static void startup_tsec(struct eth_device *dev) } rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; - /* Start up the PHY */ - if (priv->phyinfo) - phy_run_commands(priv, priv->phyinfo->startup); - - adjust_link(dev); - /* Enable Transmit and Receive */ setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); @@ -1822,8 +373,7 @@ static void tsec_halt(struct eth_device *dev) clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); /* Shut down the PHY, as needed */ - if (priv->phyinfo) - phy_run_commands(priv, priv->phyinfo->shutdown); + phy_shutdown(priv->phydev); } /* Initializes data structures and registers for the controller, @@ -1862,20 +412,64 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) out_be32(®s->macstnaddr2, tempval); - /* reset the indices to zero */ - rxIdx = 0; - txIdx = 0; - /* Clear out (for the most part) the other registers */ init_registers(regs); /* Ready the device for tx/rx */ startup_tsec(dev); + /* Start up the PHY */ + phy_startup(priv->phydev); + + adjust_link(priv, priv->phydev); + /* If there's no link, fail */ - return priv->link ? 0 : -1; + return priv->phydev->link ? 0 : -1; +} + +static phy_interface_t tsec_get_interface(struct tsec_private *priv) +{ + tsec_t *regs = priv->regs; + u32 ecntrl; + + ecntrl = in_be32(®s->ecntrl); + + if (ecntrl & ECNTRL_SGMII_MODE) + return PHY_INTERFACE_MODE_SGMII; + + if (ecntrl & ECNTRL_TBI_MODE) { + if (ecntrl & ECNTRL_REDUCED_MODE) + return PHY_INTERFACE_MODE_RTBI; + else + return PHY_INTERFACE_MODE_TBI; + } + + if (ecntrl & ECNTRL_REDUCED_MODE) { + if (ecntrl & ECNTRL_REDUCED_MII_MODE) + return PHY_INTERFACE_MODE_RMII; + else { + phy_interface_t interface = priv->interface; + + /* + * This isn't autodetected, so it must + * be set by the platform code. + */ + if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || + (interface == PHY_INTERFACE_MODE_RGMII_TXID) || + (interface == PHY_INTERFACE_MODE_RGMII_RXID)) + return interface; + + return PHY_INTERFACE_MODE_RGMII; + } + } + + if (priv->flags & TSEC_GIGABIT) + return PHY_INTERFACE_MODE_GMII; + + return PHY_INTERFACE_MODE_MII; } + /* Discover which PHY is attached to the device, and configure it * properly. If the PHY is not recognized, then return 0 * (failure). Otherwise, return 1 @@ -1883,35 +477,32 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) static int init_phy(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; - struct phy_info *curphy; + struct phy_device *phydev; tsec_t *regs = priv->regs; + u32 supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full); + + if (priv->flags & TSEC_GIGABIT) + supported |= SUPPORTED_1000baseT_Full; /* Assign a Physical address to the TBI */ out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); - /* Reset MII (due to new addresses) */ - out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET); - out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE); - while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) - ; - - /* Get the cmd structure corresponding to the attached - * PHY */ - curphy = get_phy_info(dev); + priv->interface = tsec_get_interface(priv); - if (curphy == NULL) { - priv->phyinfo = NULL; - printf("%s: No PHY found\n", dev->name); + if (priv->interface == PHY_INTERFACE_MODE_SGMII) + tsec_configure_serdes(priv); - return 0; - } + phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); - if (in_be32(®s->ecntrl) & ECNTRL_SGMII_MODE) - tsec_configure_serdes(priv); + phydev->supported &= supported; + phydev->advertising = phydev->supported; - priv->phyinfo = curphy; + priv->phydev = phydev; - phy_run_commands(priv, priv->phyinfo->config); + phy_config(phydev); return 1; } @@ -1939,13 +530,14 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) privlist[num_tsecs++] = priv; priv->regs = tsec_info->regs; - priv->phyregs = tsec_info->miiregs; priv->phyregs_sgmii = tsec_info->miiregs_sgmii; priv->phyaddr = tsec_info->phyaddr; priv->flags = tsec_info->flags; sprintf(dev->name, tsec_info->devname); + priv->interface = tsec_info->interface; + priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); dev->iobase = 0; dev->priv = priv; dev->init = tsec_init; @@ -1967,11 +559,6 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) - miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write); -#endif - /* Try to initialize PHY here, and return */ return init_phy(dev); } @@ -1997,6 +584,13 @@ int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) int tsec_standard_init(bd_t *bis) { + struct fsl_pq_mdio_info info; + + info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + info.name = DEFAULT_MII_NAME; + + fsl_pq_mdio_init(bis, &info); + return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); } -- cgit v1.2.3 From 865ff856403fb4bec6fe7f18101364384880068f Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Wed, 13 Apr 2011 00:37:12 -0500 Subject: fsl: Change fsl_phy_enet_if to phy_interface_t The fsl_phy_enet_if enum was, essentially, the phy_interface_t enum. This meant that drivers which used fsl_phy_enet_if to deal with PHY interfaces would have to convert between the two (or we would have to have them mirror each other, and deal with the ensuing maintenance headache). Instead, we switch all clients of fsl_phy_enet_if over to phy_interface_t, which should become the standard, anyway. Signed-off-by: Andy Fleming Acked-by: Detlev Zundel --- drivers/qe/uec.c | 56 +++++++++++++++++++++++++++------------------------- drivers/qe/uec.h | 3 ++- drivers/qe/uec_phy.c | 36 ++++++++++++++++----------------- 3 files changed, 49 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index cd80f835220..1ecb1379a5c 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -30,6 +30,7 @@ #include "uec.h" #include "uec_phy.h" #include "miiphy.h" +#include /* Default UTBIPAR SMI address */ #ifndef CONFIG_UTBIPAR_INIT_TBIPA @@ -321,9 +322,9 @@ static int uec_set_mac_duplex(uec_private_t *uec, int duplex) } static int uec_set_mac_if_mode(uec_private_t *uec, - enum fsl_phy_enet_if if_mode, int speed) + phy_interface_t if_mode, int speed) { - enum fsl_phy_enet_if enet_if_mode; + phy_interface_t enet_if_mode; uec_info_t *uec_info; uec_t *uec_regs; u32 upsmr; @@ -345,15 +346,15 @@ static int uec_set_mac_if_mode(uec_private_t *uec, upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM); switch (speed) { - case 10: + case SPEED_10: maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; switch (enet_if_mode) { - case MII: + case PHY_INTERFACE_MODE_MII: break; - case RGMII: + case PHY_INTERFACE_MODE_RGMII: upsmr |= (UPSMR_RPM | UPSMR_R10M); break; - case RMII: + case PHY_INTERFACE_MODE_RMII: upsmr |= (UPSMR_R10M | UPSMR_RMM); break; default: @@ -361,15 +362,15 @@ static int uec_set_mac_if_mode(uec_private_t *uec, break; } break; - case 100: + case SPEED_100: maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; switch (enet_if_mode) { - case MII: + case PHY_INTERFACE_MODE_MII: break; - case RGMII: + case PHY_INTERFACE_MODE_RGMII: upsmr |= UPSMR_RPM; break; - case RMII: + case PHY_INTERFACE_MODE_RMII: upsmr |= UPSMR_RMM; break; default: @@ -377,23 +378,24 @@ static int uec_set_mac_if_mode(uec_private_t *uec, break; } break; - case 1000: + case SPEED_1000: maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; switch (enet_if_mode) { - case GMII: + case PHY_INTERFACE_MODE_GMII: break; - case TBI: + case PHY_INTERFACE_MODE_TBI: upsmr |= UPSMR_TBIM; break; - case RTBI: + case PHY_INTERFACE_MODE_RTBI: upsmr |= (UPSMR_RPM | UPSMR_TBIM); break; - case RGMII_RXID: - case RGMII_ID: - case RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII: upsmr |= UPSMR_RPM; break; - case SGMII: + case PHY_INTERFACE_MODE_SGMII: upsmr |= UPSMR_SGMM; break; default: @@ -518,7 +520,7 @@ static void adjust_link(struct eth_device *dev) struct uec_mii_info *mii_info = uec->mii_info; extern void change_phy_interface_mode(struct eth_device *dev, - enum fsl_phy_enet_if mode, int speed); + phy_interface_t mode, int speed); uec_regs = uec->uec_regs; if (mii_info->link) { @@ -536,19 +538,19 @@ static void adjust_link(struct eth_device *dev) } if (mii_info->speed != uec->oldspeed) { - enum fsl_phy_enet_if mode = \ + phy_interface_t mode = uec->uec_info->enet_interface_type; if (uec->uec_info->uf_info.eth_type == GIGA_ETH) { switch (mii_info->speed) { - case 1000: + case SPEED_1000: break; - case 100: + case SPEED_100: printf ("switching to rgmii 100\n"); - mode = RGMII; + mode = PHY_INTERFACE_MODE_RGMII; break; - case 10: + case SPEED_10: printf ("switching to rgmii 10\n"); - mode = RGMII; + mode = PHY_INTERFACE_MODE_RGMII; break; default: printf("%s: Ack,Speed(%d)is illegal\n", @@ -1112,8 +1114,8 @@ static int uec_startup(uec_private_t *uec) out_be32(&uec_regs->utbipar, utbipar); /* Configure the TBI for SGMII operation */ - if ((uec->uec_info->enet_interface_type == SGMII) && - (uec->uec_info->speed == 1000)) { + if ((uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII) && + (uec->uec_info->speed == SPEED_1000)) { uec_write_phy_reg(uec->dev, uec_regs->utbipar, ENET_TBI_MII_ANA, TBIANA_SETTINGS); diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h index 94eb9a26d7f..e63bf3a6522 100644 --- a/drivers/qe/uec.h +++ b/drivers/qe/uec.h @@ -25,6 +25,7 @@ #include "qe.h" #include "uccf.h" +#include #include #define MAX_TX_THREADS 8 @@ -691,7 +692,7 @@ typedef struct uec_info { u16 rx_bd_ring_len; u16 tx_bd_ring_len; u8 phy_address; - enum fsl_phy_enet_if enet_interface_type; + phy_interface_t enet_interface_type; int speed; } uec_info_t; diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index c83ca4b5821..e26218be88a 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -25,6 +25,7 @@ #include "uec.h" #include "uec_phy.h" #include "miiphy.h" +#include #define ugphy_printk(format, arg...) \ printf(format "\n", ## arg) @@ -456,8 +457,9 @@ static int bcm_init(struct uec_mii_info *mii_info) gbit_config_aneg(mii_info); - if ((uec->uec_info->enet_interface_type == RGMII_RXID) && - (uec->uec_info->speed == 1000)) { + if ((uec->uec_info->enet_interface_type == + PHY_INTERFACE_MODE_RGMII_RXID) && + (uec->uec_info->speed == SPEED_1000)) { u16 val; int cnt = 50; @@ -485,22 +487,22 @@ static int uec_marvell_init(struct uec_mii_info *mii_info) { struct eth_device *edev = mii_info->dev; uec_private_t *uec = edev->priv; - enum fsl_phy_enet_if iface = uec->uec_info->enet_interface_type; + phy_interface_t iface = uec->uec_info->enet_interface_type; int speed = uec->uec_info->speed; - if ((speed == 1000) && - (iface == RGMII_ID || - iface == RGMII_RXID || - iface == RGMII_TXID)) { + if ((speed == SPEED_1000) && + (iface == PHY_INTERFACE_MODE_RGMII_ID || + iface == PHY_INTERFACE_MODE_RGMII_RXID || + iface == PHY_INTERFACE_MODE_RGMII_TXID)) { int temp; temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_CR); - if (iface == RGMII_ID) { + if (iface == PHY_INTERFACE_MODE_RGMII_ID) { temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY; - } else if (iface == RGMII_RXID) { + } else if (iface == PHY_INTERFACE_MODE_RGMII_RXID) { temp &= ~MII_M1111_TX_DELAY; temp |= MII_M1111_RX_DELAY; - } else if (iface == RGMII_TXID) { + } else if (iface == PHY_INTERFACE_MODE_RGMII_TXID) { temp &= ~MII_M1111_RX_DELAY; temp |= MII_M1111_TX_DELAY; } @@ -853,10 +855,8 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) return theInfo; } -void marvell_phy_interface_mode (struct eth_device *dev, - enum fsl_phy_enet_if type, - int speed - ) +void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type, + int speed) { uec_private_t *uec = (uec_private_t *) dev->priv; struct uec_mii_info *mii_info; @@ -868,8 +868,8 @@ void marvell_phy_interface_mode (struct eth_device *dev, } mii_info = uec->mii_info; - if (type == RGMII) { - if (speed == 100) { + if (type == PHY_INTERFACE_MODE_RGMII) { + if (speed == SPEED_100) { uec_phy_write(mii_info, 0x00, 0x9140); uec_phy_write(mii_info, 0x1d, 0x001f); uec_phy_write(mii_info, 0x1e, 0x200c); @@ -890,7 +890,7 @@ void marvell_phy_interface_mode (struct eth_device *dev, uec_phy_write(mii_info, 0x00, 0xa100); uec_phy_write(mii_info, 0x00, 0x2100); udelay (1000000); - } else if (speed == 10) { + } else if (speed == SPEED_10) { uec_phy_write(mii_info, 0x14, 0x8e40); uec_phy_write(mii_info, 0x1b, 0x800b); uec_phy_write(mii_info, 0x14, 0x0c82); @@ -908,7 +908,7 @@ void marvell_phy_interface_mode (struct eth_device *dev, } void change_phy_interface_mode (struct eth_device *dev, - enum fsl_phy_enet_if type, int speed) + phy_interface_t type, int speed) { #ifdef CONFIG_PHY_MODE_NEED_CHANGE marvell_phy_interface_mode (dev, type, speed); -- cgit v1.2.3