+ /* Shut down the PHY, as needed */
+ phy_run_commands(priv, priv->phyinfo->shutdown);
+}
+
+
+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,}
+ },
+};
+
+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},
+ {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,}
+ },
+};
+
+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, NULL},
+ {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 */
+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,}
+ },
+};
+
+
+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,}
+ },
+};
+
+static struct phy_info phy_info_lxt971 = {
+ 0x0001378e,
+ "LXT971",
+ 4,
+ (struct phy_cmd []) { /* config */
+ { MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init }, /* autonegotiate */
+ { miim_end, }
+ },
+ (struct phy_cmd []) { /* startup - enable interrupts */
+ /* { 0x12, 0x00f2, NULL }, */
+ { 0x14, 0xd422, NULL }, /* LED config */
+ { MIIM_STATUS, miim_read, NULL },
+ { MIIM_STATUS, miim_read, mii_parse_sr },
+ { miim_end, }
+ },
+ (struct phy_cmd []) { /* shutdown - disable interrupts */
+ { miim_end, }
+ },
+};
+
+struct phy_info *phy_info[] = {
+#if 0
+ &phy_info_cis8201,
+#endif
+ &phy_info_cis8204,
+ &phy_info_M88E1011S,
+ &phy_info_M88E1111S,
+ &phy_info_dm9161,
+ &phy_info_lxt971,
+ 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 */
+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];
+ }
+
+ if(theInfo == NULL)
+ {
+ printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
+ return NULL;
+ } else {
+ printf("%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*/
+void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
+{
+ int i;
+ uint result;
+ volatile tsec_t *phyregs = priv->phyregs;
+
+ phyregs->miimcfg = MIIMCFG_RESET;
+
+ phyregs->miimcfg = MIIMCFG_INIT_VALUE;
+
+ while(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++;
+ }
+}
+
+
+/* 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;
+ DECLARE_GLOBAL_DATA_PTR;
+
+ 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;
+}
+
+
+#ifndef CONFIG_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.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
+{
+ unsigned short ret;
+ struct tsec_private *priv = get_priv_for_phy(addr);
+
+ if(NULL == priv) {
+ printf("Can't read PHY at address %d\n", addr);
+ return -1;
+ }
+
+ ret = (unsigned short)read_phy_reg(priv, reg);
+ *value = ret;
+
+ return 0;