* terms of the GNU Public License, Version 2, incorporated
* herein by reference.
*
- * Copyright 2004, 2007 Freescale Semiconductor, Inc.
+ * Copyright 2004-2009 Freescale Semiconductor, Inc.
* (C) Copyright 2003, Motorola, Inc.
* author Andy Fleming
*
#include <malloc.h>
#include <net.h>
#include <command.h>
+#include <tsec.h>
+#include <asm/errno.h>
-#if defined(CONFIG_TSEC_ENET)
-#include "tsec.h"
#include "miiphy.h"
DECLARE_GLOBAL_DATA_PTR;
rxbd8_t rxbd[PKTBUFSRX];
} RTXBD;
-struct tsec_info_struct {
- unsigned int phyaddr;
- u32 flags;
- unsigned int phyregidx;
-};
-
-/* The tsec_info structure contains 3 values which the
- * driver uses to determine how to operate a given ethernet
- * device. The information needed is:
- * phyaddr - The address of the PHY which is attached to
- * the given device.
- *
- * flags - This variable indicates whether the device
- * supports gigabit speed ethernet, and whether it should be
- * in reduced mode.
- *
- * phyregidx - This variable specifies which ethernet device
- * controls the MII Management registers which are connected
- * to the PHY. For now, only TSEC1 (index 0) has
- * access to the PHYs, so all of the entries have "0".
- *
- * The values specified in the table are taken from the board's
- * config file in include/configs/. When implementing a new
- * board with ethernet capability, it is necessary to define:
- * TSECn_PHY_ADDR
- * TSECn_PHYIDX
- *
- * for n = 1,2,3, etc. And for FEC:
- * FEC_PHY_ADDR
- * FEC_PHYIDX
- */
-static struct tsec_info_struct tsec_info[] = {
-#ifdef CONFIG_TSEC1
- {TSEC1_PHY_ADDR, TSEC1_FLAGS, TSEC1_PHYIDX},
-#else
- {0, 0, 0},
-#endif
-#ifdef CONFIG_TSEC2
- {TSEC2_PHY_ADDR, TSEC2_FLAGS, TSEC2_PHYIDX},
-#else
- {0, 0, 0},
-#endif
-#ifdef CONFIG_MPC85XX_FEC
- {FEC_PHY_ADDR, FEC_FLAGS, FEC_PHYIDX},
-#else
-#ifdef CONFIG_TSEC3
- {TSEC3_PHY_ADDR, TSEC3_FLAGS, TSEC3_PHYIDX},
-#else
- {0, 0, 0},
-#endif
-#ifdef CONFIG_TSEC4
- {TSEC4_PHY_ADDR, TSEC4_FLAGS, TSEC4_PHYIDX},
-#else
- {0, 0, 0},
-#endif /* CONFIG_TSEC4 */
-#endif /* CONFIG_MPC85XX_FEC */
-};
-
-#define MAXCONTROLLERS (4)
-
-static int relocated = 0;
+#define MAXCONTROLLERS (8)
static struct tsec_private *privlist[MAXCONTROLLERS];
+static int num_tsecs = 0;
#ifdef __GNUC__
static RTXBD rtx __attribute__ ((aligned(8)));
struct phy_info *get_phy_info(struct eth_device *dev);
void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
static void adjust_link(struct eth_device *dev);
-static void relocate_cmds(void);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
&& !defined(BITBANGMII)
static int tsec_miiphy_write(char *devname, unsigned char addr,
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[] = {
+#ifdef CONFIG_TSEC1
+ STD_TSEC_INFO(1), /* TSEC1 */
+#endif
+#ifdef CONFIG_TSEC2
+ STD_TSEC_INFO(2), /* TSEC2 */
+#endif
+#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
+ }, /* FEC */
+#endif
+#ifdef CONFIG_TSEC3
+ STD_TSEC_INFO(3), /* TSEC3 */
+#endif
+#ifdef CONFIG_TSEC4
+ STD_TSEC_INFO(4), /* TSEC4 */
+#endif
+};
+
+int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ tsec_initialize(bis, &tsecs[i]);
+
+ return 0;
+}
+
+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)
*/
-int tsec_initialize(bd_t * bis, int index, char *devname)
+int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
{
struct eth_device *dev;
int i;
if (NULL == priv)
return 0;
- privlist[index] = priv;
- priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index * TSEC_SIZE);
- priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +
- tsec_info[index].phyregidx *
- TSEC_SIZE);
+ 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[index].phyaddr;
- priv->flags = tsec_info[index].flags;
+ priv->phyaddr = tsec_info->phyaddr;
+ priv->flags = tsec_info->flags;
- sprintf(dev->name, devname);
+ sprintf(dev->name, tsec_info->devname);
dev->iobase = 0;
dev->priv = priv;
dev->init = tsec_init;
/* Reset the MAC */
priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
+ udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
for (i = 0; i < MAC_ADDR_LEN; i++) {
tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
}
- regs->macstnaddr1 = *((uint *) (tmpbuf));
+ tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
+ tmpbuf[3];
+
+ regs->macstnaddr1 = tempval;
tempval = *((uint *) (tmpbuf + 4));
/* If there's no link, fail */
return (priv->link ? 0 : -1);
-
}
-/* Write value to the device's PHY through the registers
- * specified in priv, modifying the register specified in regnum.
- * It will wait for the write to be done (or for a timeout to
- * expire) before exiting
- */
-void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
+/* 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,
+ uint reg, uint value)
{
- volatile tsec_t *regbase = priv->phyregs;
- uint phyid = priv->phyaddr;
int timeout = 1000000;
- regbase->miimadd = (phyid << 8) | regnum;
- regbase->miimcon = value;
+ phyregs->miimadd = (addr << 8) | reg;
+ phyregs->miimcon = value;
asm("sync");
timeout = 1000000;
- while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
+ while ((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
- * registers specified in priv. It lowers and raises the read
+ * 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
*/
-uint read_phy_reg(struct tsec_private *priv, uint regnum)
+uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs, uint phyid, uint regnum)
{
uint value;
- volatile tsec_t *regbase = priv->phyregs;
- uint phyid = priv->phyaddr;
/* Put the address of the phy, and the register
* number into MIIMADD */
- regbase->miimadd = (phyid << 8) | regnum;
+ phyregs->miimadd = (phyid << 8) | regnum;
/* Clear the command register, and wait */
- regbase->miimcom = 0;
+ phyregs->miimcom = 0;
asm("sync");
/* Initiate a read command, and wait */
- regbase->miimcom = MIIM_READ_COMMAND;
+ phyregs->miimcom = MIIM_READ_COMMAND;
asm("sync");
/* Wait for the the indication that the read is done */
- while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
+ while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
/* Grab the value read from the PHY */
- value = regbase->miimstat;
+ value = 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 \
+ | TBIANA_FULL_DUPLEX \
+ )
+
+/* Force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
+#define TBICR_SETTINGS ( \
+ TBICR_PHY_RESET \
+ | TBICR_FULL_DUPLEX \
+ | TBICR_SPEED1_SET \
+ )
+
+/* Configure the TBI for SGMII operation */
+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,
+ 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
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct phy_info *curphy;
- volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
+ volatile tsec_t *regs = priv->regs;
/* Assign a Physical address to the TBI */
- regs->tbipa = CFG_TBIPA_VALUE;
- regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
- regs->tbipa = CFG_TBIPA_VALUE;
+ regs->tbipa = CONFIG_SYS_TBIPA_VALUE;
asm("sync");
/* Reset MII (due to new addresses) */
asm("sync");
while (priv->phyregs->miimind & MIIMIND_BUSY) ;
- if (0 == relocated)
- relocate_cmds();
-
/* Get the cmd structure corresponding to the attached
* PHY */
curphy = get_phy_info(dev);
return 0;
}
+ if (regs->ecntrl & ECNTRL_SGMII_MODE)
+ tsec_configure_serdes(priv);
+
priv->phyinfo = curphy;
phy_run_commands(priv, priv->phyinfo->config);
return MIIM_CR_INIT;
}
-/* Parse the status register for link, and then do
- * auto-negotiation
+/*
+ * Wait for auto-negotiation to complete, then determine link
*/
uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
{
* (ie - we're capable and it's not done)
*/
mii_reg = read_phy_reg(priv, MIIM_STATUS);
- if ((mii_reg & MIIM_STATUS_LINK) && (mii_reg & PHY_BMSR_AUTN_ABLE)
- && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
+ if ((mii_reg & PHY_BMSR_AUTN_ABLE) && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
int i = 0;
puts("Waiting for PHY auto negotiation to complete");
return 0;
}
+ if (ctrlc()) {
+ puts("user interrupt!\n");
+ priv->link = 0;
+ return -EINTR;
+ }
+
if ((i++ % 1000) == 0) {
putc('.');
}
mii_reg = read_phy_reg(priv, MIIM_STATUS);
}
puts(" done\n");
- priv->link = 1;
+
+ /* 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) */
- } else {
- if (mii_reg & MIIM_STATUS_LINK)
- priv->link = 1;
- else
- priv->link = 0;
}
+ priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0;
+
return 0;
}
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.
+ */
+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.
*/
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:
- printf("Enet starting in 10BT/HD\n");
- priv->duplexity = 0;
- priv->speed = 10;
- break;
-
- case 2:
- printf("Enet starting in 10BT/FD\n");
- priv->duplexity = 1;
- priv->speed = 10;
- break;
-
- case 3:
- printf("Enet starting in 100BT/HD\n");
- priv->duplexity = 0;
- priv->speed = 100;
- break;
-
- case 5:
- printf("Enet starting in 100BT/FD\n");
- priv->duplexity = 1;
- priv->speed = 100;
- break;
-
- case 6:
- printf("Enet starting in 1000BT/HD\n");
- priv->duplexity = 0;
- priv->speed = 1000;
- break;
-
- case 7:
- printf("Enet starting in 1000BT/FD\n");
- priv->duplexity = 1;
- priv->speed = 1000;
- break;
-
- default:
- printf("Auto-neg error, defaulting to 10BT/HD\n");
- priv->duplexity = 0;
- priv->speed = 10;
- break;
+ 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;
return 0;
}
+/* Parse the RTL8211B's status register for speed and duplex
+ * information
+ */
+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
*/
uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
{
uint phyid;
- volatile tsec_t *regbase = priv->phyregs;
+ volatile tsec_mdio_t *regbase = priv->phyregs;
int timeout = 1000000;
for (phyid = 0; phyid < 4; phyid++) {
},
};
+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},
+ {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,}
+ },
+};
+
struct phy_info phy_info_M88E1011S = {
0x01410c6,
"Marvell 88E1011S",
},
};
+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
+ */
+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;
+}
+
+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);
{miim_end,}
},
};
+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,}
+ },
+};
struct phy_info phy_info_VSC8244 = {
0x3f1b,
"Vitesse VSC8244",
},
};
+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,}
+ },
+};
+
+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,}
+ },
+};
+
+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,}
+ },
+};
+
+
struct phy_info phy_info_dm9161 = {
0x0181b88,
"Davicom DM9161E",
},
};
+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[] = {
&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_lxt971,
+ &phy_info_VSC8211,
&phy_info_VSC8244,
+ &phy_info_VSC8601,
+ &phy_info_VSC8641,
+ &phy_info_VSC8221,
&phy_info_dp83865,
- &phy_info_generic,
+ &phy_info_rtl8211b,
+ &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */
NULL
};
}
}
- if (theInfo == NULL) {
- printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
- return NULL;
+ 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);
}
{
int i;
uint result;
- volatile tsec_t *phyregs = priv->phyregs;
+ volatile tsec_mdio_t *phyregs = priv->phyregs;
phyregs->miimcfg = MIIMCFG_RESET;
}
}
-/* Relocate the function pointers in the phy cmd lists */
-static void relocate_cmds(void)
-{
- struct phy_cmd **cmdlistptr;
- struct phy_cmd *cmd;
- int i, j, k;
-
- for (i = 0; phy_info[i]; i++) {
- /* First thing's first: relocate the pointers to the
- * PHY command structures (the structs were done) */
- phy_info[i] = (struct phy_info *)((uint) phy_info[i]
- + gd->reloc_off);
- phy_info[i]->name += gd->reloc_off;
- phy_info[i]->config =
- (struct phy_cmd *)((uint) phy_info[i]->config
- + gd->reloc_off);
- phy_info[i]->startup =
- (struct phy_cmd *)((uint) phy_info[i]->startup
- + gd->reloc_off);
- phy_info[i]->shutdown =
- (struct phy_cmd *)((uint) phy_info[i]->shutdown
- + gd->reloc_off);
-
- cmdlistptr = &phy_info[i]->config;
- j = 0;
- for (; cmdlistptr <= &phy_info[i]->shutdown; cmdlistptr++) {
- k = 0;
- for (cmd = *cmdlistptr;
- cmd->mii_reg != miim_end;
- cmd++) {
- /* Only relocate non-NULL pointers */
- if (cmd->funct)
- cmd->funct += gd->reloc_off;
-
- k++;
- }
- j++;
- }
- }
-
- relocated = 1;
-}
-
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
&& !defined(BITBANGMII)
-struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
-{
- int i;
-
- for (i = 0; i < MAXCONTROLLERS; i++) {
- if (privlist[i]->phyaddr == phyaddr)
- return privlist[i];
- }
-
- return NULL;
-}
-
/*
* Read a MII PHY register.
*
unsigned char reg, unsigned short *value)
{
unsigned short ret;
- struct tsec_private *priv = get_priv_for_phy(addr);
+ struct tsec_private *priv = privlist[0];
if (NULL == priv) {
printf("Can't read PHY at address %d\n", addr);
return -1;
}
- ret = (unsigned short)read_phy_reg(priv, reg);
+ ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg);
*value = ret;
return 0;
static int tsec_miiphy_write(char *devname, unsigned char addr,
unsigned char reg, unsigned short value)
{
- struct tsec_private *priv = get_priv_for_phy(addr);
+ struct tsec_private *priv = privlist[0];
if (NULL == priv) {
printf("Can't write PHY at address %d\n", addr);
return -1;
}
- write_phy_reg(priv, reg, value);
+ tsec_local_mdio_write(priv->phyregs, addr, reg, value);
return 0;
}
return 0;
}
#endif /* Multicast TFTP ? */
-
-#endif /* CONFIG_TSEC_ENET */