/* * Marvell 88E61XX Switch initialization */ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) { u32 prt; u16 reg; char *idstr; char *name = swconfig->name; int time; if (miiphy_set_current_dev(name)) { printf("%s failed\n", __FUNCTION__); return -1; } if (!(swconfig->cpuport & ((1 << 4) | (1 << 5)))) { swconfig->cpuport = (1 << 5); printf("Invalid cpu port config, using default port5\n"); } RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, ®); switch (reg &= 0xfff0) { case 0x1610: idstr = "88E6161"; break; case 0x1650: idstr = "88E6165"; break; case 0x1210: idstr = "88E6123"; /* ports 2,3,4 not available */ swconfig->ports_enabled &= 0x023; break; default: /* Could not detect switch id */ idstr = "88E61??"; break; } /* be sure all ports are disabled */ for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, ®); reg &= ~0x3; WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg); } /* wait 2 ms for queues to drain */ udelay(2000); /* reset switch */ RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, ®); reg |= 0x8000; WR_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, reg); /* wait up to 1 second for switch reset complete */ for (time = 1000; time; time--) { RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGSR, ®); if ((reg & 0xc800) == 0xc800) break; udelay(1000); } if (!time) return -1; /* Port based VLANs configuration */ mv88e61xx_port_vlan_config(swconfig); if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) { /* * Enable RGMII delay on Tx and Rx for CPU port * Ref: sec 9.5 of chip datasheet-02 */ /*Force port link down */ WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x10); /* configure port RGMII delay */ WR_SWITCH_PORT_REG(name, 4, MV88E61XX_RGMII_TIMECTRL_REG, 0x81e7); RD_SWITCH_PORT_REG(name, 5, MV88E61XX_RGMII_TIMECTRL_REG, ®); WR_SWITCH_PORT_REG(name, 5, MV88E61XX_RGMII_TIMECTRL_REG, reg | 0x18); WR_SWITCH_PORT_REG(name, 4, MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); /* Force port to RGMII FDX 1000Base then up */ WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x1e); WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x3e); } for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { /* configure port's PHY */ if (!((1 << prt) & swconfig->cpuport)) { /* port 4 has phy 6, not 4 */ int phy = (prt == 4) ? 6 : prt; if (mv88361xx_powerup(swconfig, phy)) return -1; if (mv88361xx_reverse_mdipn(swconfig, phy)) return -1; if (mv88361xx_led_init(swconfig, phy)) return -1; } /* set port VID to port+1 except for cpu port */ if (!((1 << prt) & swconfig->cpuport)) { RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_VID_REG, ®); WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_VID_REG, (reg & ~1023) | (prt+1)); } /*Program port state */ RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, ®); WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg | (swconfig->portstate & 0x03)); } printf("%s Initialized on %s\n", idstr, name); return 0; }
/* * Marvell 88E61XX Switch initialization */ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) { u32 prt; u16 reg; char *idstr; char *name = swconfig->name; if (miiphy_set_current_dev(name)) { printf("%s failed\n", __FUNCTION__); return -1; } if (!(swconfig->cpuport & ((1 << 4) | (1 << 5)))) { swconfig->cpuport = (1 << 5); printf("Invalid cpu port config, using default port5\n"); } RD_PHY(name, MV88E61XX_PRT_OFST, PHY_PHYIDR2, ®); reg &= 0xfff0; if (reg == 0x1610) idstr = "88E6161"; if (reg == 0x1650) idstr = "88E6165"; if (reg == 0x1210) { idstr = "88E6123"; /* ports 2,3,4 not available */ swconfig->ports_enabled &= 0x023; } /* Port based VLANs configuration */ if ((swconfig->vlancfg == MV88E61XX_VLANCFG_DEFAULT) || (swconfig->vlancfg == MV88E61XX_VLANCFG_ROUTER)) mv88e61xx_port_vlan_config(swconfig, MV88E61XX_MAX_PORTS_NUM, MV88E61XX_PRT_OFST); else { printf("Unsupported mode %s failed\n", __FUNCTION__); return -1; } if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) { /* * Enable RGMII delay on Tx and Rx for CPU port * Ref: sec 9.5 of chip datasheet-02 */ WR_PHY(name, MV88E61XX_PRT_OFST + 5, MV88E61XX_RGMII_TIMECTRL_REG, 0x18); WR_PHY(name, MV88E61XX_PRT_OFST + 4, MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); } for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { if (!((1 << prt) & swconfig->cpuport)) { if (mv88361xx_led_init(swconfig, prt)) return -1; if (mv88361xx_reverse_mdipn(swconfig, prt)) return -1; if (mv88361xx_powerup(swconfig, prt)) return -1; } /*Program port state */ RD_PHY(name, MV88E61XX_PRT_OFST + prt, MV88E61XX_PRT_CTRL_REG, ®); WR_PHY(name, MV88E61XX_PRT_OFST + prt, MV88E61XX_PRT_CTRL_REG, reg | (swconfig->portstate & 0x03)); } printf("%s Initialized on %s\n", idstr, name); return 0; }