| Submitter | Albert ARIBAUD |
|---|---|
| Date | Nov. 4, 2012, 11:32 p.m. |
| Message ID | <1352071924-20268-2-git-send-email-albert.u.boot@aribaud.net> |
| Download | mbox | patch |
| Permalink | /patch/197116/ |
| State | Superseded |
| Delegated to: | Prafulla Wadaskar |
| Headers | show |
Comments
> -----Original Message----- > From: Albert ARIBAUD [mailto:albert.u.boot@aribaud.net] > Sent: 05 November 2012 05:02 > To: U-Boot > Cc: Prafulla Wadaskar; Simon Guinot; Albert ARIBAUD; > joe.hershberger@gmail.com > Subject: [PATCH v4 2/4] mv88e61xx: refactor PHY and SWITCH level-code > > > Signed-off-by: Albert ARIBAUD <albert.u.boot@aribaud.net> > --- > > drivers/net/phy/mv88e61xx.c | 300 ++++++++++++++++++---------------- > --------- > drivers/net/phy/mv88e61xx.h | 23 ++-- > include/netdev.h | 21 ++- > 3 files changed, 155 insertions(+), 189 deletions(-) > > diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c > index 483a920..2d484ff 100644 > --- a/drivers/net/phy/mv88e61xx.c > +++ b/drivers/net/phy/mv88e61xx.c > @@ -52,7 +52,8 @@ static int mv88e61xx_busychk_multic(char *name, u32 > devaddr) > return 0; > } > > -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, > u16 data) > +static void mv88e61xx_switch_write(char *name, u32 phy_adr, > + u32 reg_ofs, u16 data) > { > u16 mii_dev_addr; > > @@ -70,7 +71,8 @@ static void mv88e61xx_wr_phy(char *name, u32 > phy_adr, u32 reg_ofs, u16 data) > 15)); > } > > -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, > u16 * data) > +static void mv88e61xx_switch_read(char *name, u32 phy_adr, > + u32 reg_ofs, u16 *data) > { > u16 mii_dev_addr; > > @@ -90,111 +92,6 @@ static void mv88e61xx_rd_phy(char *name, u32 > phy_adr, u32 reg_ofs, u16 * data) > } > #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ > > -static void mv88e61xx_port_vlan_config(struct mv88e61xx_config > *swconfig, > - u32 max_prtnum, u32 ports_ofs) > -{ > - u32 prt; > - u16 reg; > - char *name = swconfig->name; > - u32 cpu_port = swconfig->cpuport; > - u32 port_mask = swconfig->ports_enabled; > - enum mv88e61xx_cfg_vlan vlancfg = swconfig->vlancfg; > - > - /* be sure all ports are disabled */ > - for (prt = 0; prt < max_prtnum; prt++) { > - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, ®); > - reg &= ~0x3; > - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, reg); > - > - if (!(cpu_port & (1 << prt))) > - continue; > - /* Set CPU port VID to 0x1 */ > - RD_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, ®); > - reg &= ~0xfff; > - reg |= 0x1; > - WR_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, reg); > - } > - > - /* Setting Port default priority for all ports to zero */ > - for (prt = 0; prt < max_prtnum; prt++) { > - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, ®); > - reg &= ~0xc000; > - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, reg); > - } > - /* Setting VID and VID map for all ports except CPU port */ > - for (prt = 0; prt < max_prtnum; prt++) { > - /* only for enabled ports */ > - if ((1 << prt) & port_mask) { > - /* skip CPU port */ > - if ((1 << prt) & cpu_port) { > - /* > - * Set Vlan map table for cpu_port to see > - * all ports > - */ > - RD_PHY(name, (ports_ofs + prt), > - MV88E61XX_PRT_VMAP_REG, ®); > - reg &= ~((1 << max_prtnum) - 1); > - reg |= port_mask & ~(1 << prt); > - WR_PHY(name, (ports_ofs + prt), > - MV88E61XX_PRT_VMAP_REG, reg); > - } else { > - > - /* > - * set Ports VLAN Mapping. > - * port prt <--> cpu_port VLAN #prt+1. > - */ > - RD_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_VID_REG, ®); > - reg &= ~0x0fff; > - reg |= (prt + 1); > - WR_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_VID_REG, reg); > - > - RD_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_VMAP_REG, ®); > - if (vlancfg == MV88E61XX_VLANCFG_DEFAULT) { > - /* > - * all any port can send frames to all other > ports > - * ref: sec 3.2.1.1 of datasheet > - */ > - reg |= 0x03f; > - reg &= ~(1 << prt); > - } else if (vlancfg == MV88E61XX_VLANCFG_ROUTER) { > - /* > - * all other ports can send frames to CPU port > only > - * ref: sec 3.2.1.2 of datasheet > - */ > - reg &= ~((1 << max_prtnum) - 1); > - reg |= cpu_port; > - } > - WR_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_VMAP_REG, reg); > - } > - } > - } > - > - /* > - * enable only appropriate ports to forwarding mode > - * and disable the others > - */ > - for (prt = 0; prt < max_prtnum; prt++) { > - if ((1 << prt) & port_mask) { > - RD_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_CTRL_REG, ®); > - reg |= 0x3; > - WR_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_CTRL_REG, reg); > - } else { > - /* Disable port */ > - RD_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_CTRL_REG, ®); > - reg &= ~0x3; > - WR_PHY(name, ports_ofs + prt, > - MV88E61XX_PRT_CTRL_REG, reg); > - } > - } > -} > - > /* > * Make sure SMIBusy bit cleared before another > * SMI operation can take place > @@ -204,7 +101,7 @@ static int mv88e61xx_busychk(char *name) > u16 reg = 0; > u32 timeout = MV88E61XX_PHY_TIMEOUT; > do { > - RD_PHY(name, MV88E61XX_GLB2REG_DEVADR, > + RD_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, > MV88E61XX_PHY_CMD, ®); > if (timeout-- == 0) { > printf("SMI busy timeout\n"); > @@ -215,33 +112,104 @@ static int mv88e61xx_busychk(char *name) > } > > /* > + * Convenience macros for switch PORT reads > + */ > + > +#define WR_SWITCH_PORT_REG(n, p, r, d) \ > + WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) > +#define RD_SWITCH_PORT_REG(n, p, r, d) \ > + RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) > + > +/* > + * Local functions to read/write registers on the switch PHYs. > + * NOTE! This goes through switch, not direct miiphy, writes and > reads! > + */ > + > +static inline int mv88e61xx_switch_miiphy_write(char *name, u32 phy, > + u32 reg, u16 data) > +{ > + /* write switch data reg then cmd reg then check completion */ > + WR_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, > + data); > + WR_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, > + (MV88E61XX_PHY_WRITE_CMD | (phy << 5) | reg)); > + return mv88e61xx_busychk(name); > +} > + > +static inline int mv88e61xx_switch_miiphy_read(char *name, u32 phy, > + u32 reg, u16 *data) > +{ > + /* write switch cmd reg, check for completion */ > + WR_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, > + (MV88E61XX_PHY_READ_CMD | (phy << 5) | reg)); > + if (mv88e61xx_busychk(name)) > + return -1; > + /* read switch data reg and return success */ > + RD_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, > data); > + return 0; > +} > + > +/* > + * Convenience macros for switch PHY reads > + */ > + > +#define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write > +#define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read > + > +static void mv88e61xx_port_vlan_config(struct mv88e61xx_config > *swconfig) > +{ > + u32 prt; > + u16 reg; > + char *name = swconfig->name; > + u32 port_mask = swconfig->ports_enabled; > + > + /* 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); > + } > + > + /* apply internal vlan config */ > + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { > + /* only for enabled ports */ > + if ((1 << prt) & port_mask) { > + /* take vlan map from swconfig */ > + u8 vlanmap = swconfig->vlancfg[prt]; > + /* remove disabled ports from vlan map */ > + vlanmap &= swconfig->ports_enabled; > + /* apply vlan map to port */ > + RD_SWITCH_PORT_REG(name, prt, > + MV88E61XX_PRT_VMAP_REG, ®); > + reg &= ~((1 << MV88E61XX_MAX_PORTS_NUM) - 1); > + reg |= vlanmap; > + WR_SWITCH_PORT_REG(name, prt, > + MV88E61XX_PRT_VMAP_REG, reg); > + } > + } > + > +} > + > +/* > * Power up the specified port and reset PHY > */ > static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 > prt) > { > char *name = swconfig->name; > > - /* Write Copper Specific control reg1 (0x14) for- > + /* Write Copper Specific control reg1 (0x10) for- > * Enable Phy power up > * Energy Detect on (sense&Xmit NLP Periodically > * reset other settings default > */ > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, > 0x3360); > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, > - MV88E61XX_PHY_CMD, (0x9410 | (prt << 5))); > - > - if (mv88e61xx_busychk(name)) > + if (WR_SWITCH_PHY_REG(name, prt, 0x10, 0x3360)) > return -1; > > /* Write PHY ctrl reg (0x0) to apply > * Phy reset (set bit 15 low) > * reset other default values > */ > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, > 0x1140); > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, > - MV88E61XX_PHY_CMD, (0x9400 | (prt << 5))); > - > - if (mv88e61xx_busychk(name)) > + if (WR_SWITCH_PHY_REG(name, prt, 0x00, 0x9140)) > return -1; > > return 0; > @@ -259,45 +227,23 @@ static int mv88361xx_powerup(struct > mv88e61xx_config *swconfig, u32 prt) > static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 > prt) > { > char *name = swconfig->name; > - u16 reg; > > if (swconfig->led_init != MV88E61XX_LED_INIT_EN) > return 0; > > /* set page address to 3 */ > - reg = 3; > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, > - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | > - 1 << MV88E61XX_MODE_OFST | > - 1 << MV88E61XX_OP_OFST | > - prt << MV88E61XX_ADDR_OFST | 22)); > - > - if (mv88e61xx_busychk(name)) > + if (WR_SWITCH_PHY_REG(name, prt, 0x16, 0x0003)) > return -1; > > - /* set LED Func Ctrl reg */ > - reg = 1; /* LED[0] On-Link, Blink-Activity, Off-NoLink */ > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, > - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | > - 1 << MV88E61XX_MODE_OFST | > - 1 << MV88E61XX_OP_OFST | > - prt << MV88E61XX_ADDR_OFST | 16)); > - > - if (mv88e61xx_busychk(name)) > + /* > + * set LED Func Ctrl reg > + * value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink > + */ > + if (WR_SWITCH_PHY_REG(name, prt, 0x10, 0x0001)) > return -1; > > /* set page address to 0 */ > - reg = 0; > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, > - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | > - 1 << MV88E61XX_MODE_OFST | > - 1 << MV88E61XX_OP_OFST | > - prt << MV88E61XX_ADDR_OFST | 22)); > - > - if (mv88e61xx_busychk(name)) > + if (WR_SWITCH_PHY_REG(name, prt, 0x16, 0x0000)) > return -1; > > return 0; > @@ -315,20 +261,12 @@ static int mv88361xx_led_init(struct > mv88e61xx_config *swconfig, u32 prt) > static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, > u32 prt) > { > char *name = swconfig->name; > - u16 reg; > > if (swconfig->mdip != MV88E61XX_MDIP_REVERSE) > return 0; > > - reg = 0x0f; /*Reverse MDIP/N[3:0] bits */ > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); > - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, > - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | > - 1 << MV88E61XX_MODE_OFST | > - 1 << MV88E61XX_OP_OFST | > - prt << MV88E61XX_ADDR_OFST | 20)); > - > - if (mv88e61xx_busychk(name)) > + /*Reverse MDIP/N[3:0] bits */ > + if (WR_SWITCH_PHY_REG(name, prt, 0x14, 0x000f)) > return -1; > > return 0; > @@ -354,7 +292,7 @@ int mv88e61xx_switch_initialize(struct > mv88e61xx_config *swconfig) > printf("Invalid cpu port config, using default port5\n"); > } > > - RD_PHY(name, MV88E61XX_PRT_OFST, MII_PHYSID2, ®); > + RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, ®); > switch (reg &= 0xfff0) { > case 0x1610: > idstr = "88E6161"; > @@ -374,45 +312,57 @@ int mv88e61xx_switch_initialize(struct > mv88e61xx_config *swconfig) > } > > /* 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; > - } > + 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 > */ > - WR_PHY(name, MV88E61XX_PRT_OFST + 5, > - MV88E61XX_RGMII_TIMECTRL_REG, 0x18); > - WR_PHY(name, MV88E61XX_PRT_OFST + 4, > - MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); > + /*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++) { > if (!((1 << prt) & swconfig->cpuport)) { > > - if (mv88361xx_led_init(swconfig, prt)) > + if (mv88361xx_powerup(swconfig, prt)) > return -1; > + WR_SWITCH_PORT_REG(name, prt, 4, 0x7f); > if (mv88361xx_reverse_mdipn(swconfig, prt)) > return -1; > - if (mv88361xx_powerup(swconfig, prt)) > + if (mv88361xx_led_init(swconfig, prt)) > return -1; > } > > /*Program port state */ > - RD_PHY(name, MV88E61XX_PRT_OFST + prt, > + RD_SWITCH_PORT_REG(name, prt, > MV88E61XX_PRT_CTRL_REG, ®); > - WR_PHY(name, MV88E61XX_PRT_OFST + prt, > + WR_SWITCH_PORT_REG(name, prt, > MV88E61XX_PRT_CTRL_REG, > reg | (swconfig->portstate & 0x03)); > + > } > > + /* do a sw reset */ > + RD_SWITCH_REG(name, 0x1B, 0x04, ®); > + reg |= 0x8000; > + WR_SWITCH_REG(name, 0x1B, 0x04, reg); > + /* wait for at least 2 ms */ > + udelay(2500); > + > printf("%s Initialized on %s\n", idstr, name); > return 0; > } > diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h > index 57762b6..7595cbc 100644 > --- a/drivers/net/phy/mv88e61xx.h > +++ b/drivers/net/phy/mv88e61xx.h > @@ -28,11 +28,10 @@ > #include <miiphy.h> > > #define MV88E61XX_CPU_PORT 0x5 > -#define MV88E61XX_MAX_PORTS_NUM 0x6 > > #define MV88E61XX_PHY_TIMEOUT 100000 > > -#define MV88E61XX_PRT_STS_REG 0x1 > +#define MV88E61XX_PCS_CTRL_REG 0x1 > #define MV88E61XX_PRT_CTRL_REG 0x4 > #define MV88E61XX_PRT_VMAP_REG 0x6 > #define MV88E61XX_PRT_VID_REG 0x7 > @@ -43,20 +42,26 @@ > #define MV88E61XX_RGMII_TIMECTRL_REG 0x1A > #define MV88E61XX_GLB2REG_DEVADR 0x1C > > +#define MV88E61XX_PHY_WRITE_CMD 0x9400 > +#define MV88E61XX_PHY_READ_CMD 0x9800 > + > #define MV88E61XX_BUSY_OFST 15 > #define MV88E61XX_MODE_OFST 12 > -#define MV88E61XX_OP_OFST 10 > +#define MV88E61XX_OP_OFST 10 > #define MV88E61XX_ADDR_OFST 5 > > #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE > static int mv88e61xx_busychk_multic(char *name, u32 devaddr); > -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, > u16 data); > -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, > u16 * data); > -#define WR_PHY mv88e61xx_wr_phy > -#define RD_PHY mv88e61xx_rd_phy > +static void mv88e61xx_switch_write(char *name, u32 phy_adr, > + u32 reg_ofs, u16 data); > +static void mv88e61xx_switch_read(char *name, u32 phy_adr, > + u32 reg_ofs, u16 *data); > +#define WR_SWITCH_REG mv88e61xx_switch_write > +#define RD_SWITCH_REG mv88e61xx_switch_read > #else > -#define WR_PHY miiphy_write > -#define RD_PHY miiphy_read > +/* switch appears a s simple PHY and can thus use miiphy */ > +#define WR_SWITCH_REG miiphy_write > +#define RD_SWITCH_REG miiphy_read > #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ > > #endif /* _MV88E61XX_H */ > diff --git a/include/netdev.h b/include/netdev.h > index b8d303d..e1eb40a 100644 > --- a/include/netdev.h > +++ b/include/netdev.h > @@ -163,10 +163,9 @@ static inline int pci_eth_init(bd_t *bis) > * the stuct and enums here are used to specify switch configuration > params > */ > #if defined(CONFIG_MV88E61XX_SWITCH) > -enum mv88e61xx_cfg_vlan { > - MV88E61XX_VLANCFG_DEFAULT, > - MV88E61XX_VLANCFG_ROUTER > -}; > + > +/* constants for any 88E61xx switch */ > +#define MV88E61XX_MAX_PORTS_NUM 6 > > enum mv88e61xx_cfg_mdip { > MV88E61XX_MDIP_NOCHANGE, > @@ -192,7 +191,7 @@ enum mv88e61xx_cfg_prtstt { > > struct mv88e61xx_config { > char *name; > - enum mv88e61xx_cfg_vlan vlancfg; > + u8 vlancfg[MV88E61XX_MAX_PORTS_NUM]; > enum mv88e61xx_cfg_rgmiid rgmii_delay; > enum mv88e61xx_cfg_prtstt portstate; > enum mv88e61xx_cfg_ledinit led_init; > @@ -201,6 +200,18 @@ struct mv88e61xx_config { > u8 cpuport; > }; > > +/* > + * Common mappings for Internal VLANs > + * These mappings consider that all ports are useable; the driver > + * will mask inexistent/unused ports. > + */ > + > +/* Switch mode : routes any port to any port */ > +#define MV88E61XX_VLANCFG_SWITCH { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F > } > + > +/* Router mode: routes only CPU port 5 to/from non-CPU ports 0-4 */ > +#define MV88E61XX_VLANCFG_ROUTER { 0x30, 0x30, 0x30, 0x30, 0x2F, 0x1F > } > + > int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig); > #endif /* CONFIG_MV88E61XX_SWITCH */ > Entire patch looks good, but I would like to try it on the board (may be in the next week) just to confirm the functionality is not broken. Othwerwise, Acked-by: Prafulla Wadaskar <Prafulla@marvell.com> Regards... Prafulla . . .
Patch
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index 483a920..2d484ff 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -52,7 +52,8 @@ static int mv88e61xx_busychk_multic(char *name, u32 devaddr) return 0; } -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +static void mv88e61xx_switch_write(char *name, u32 phy_adr, + u32 reg_ofs, u16 data) { u16 mii_dev_addr; @@ -70,7 +71,8 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) 15)); } -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +static void mv88e61xx_switch_read(char *name, u32 phy_adr, + u32 reg_ofs, u16 *data) { u16 mii_dev_addr; @@ -90,111 +92,6 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) } #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ -static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig, - u32 max_prtnum, u32 ports_ofs) -{ - u32 prt; - u16 reg; - char *name = swconfig->name; - u32 cpu_port = swconfig->cpuport; - u32 port_mask = swconfig->ports_enabled; - enum mv88e61xx_cfg_vlan vlancfg = swconfig->vlancfg; - - /* be sure all ports are disabled */ - for (prt = 0; prt < max_prtnum; prt++) { - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, ®); - reg &= ~0x3; - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, reg); - - if (!(cpu_port & (1 << prt))) - continue; - /* Set CPU port VID to 0x1 */ - RD_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, ®); - reg &= ~0xfff; - reg |= 0x1; - WR_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, reg); - } - - /* Setting Port default priority for all ports to zero */ - for (prt = 0; prt < max_prtnum; prt++) { - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, ®); - reg &= ~0xc000; - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, reg); - } - /* Setting VID and VID map for all ports except CPU port */ - for (prt = 0; prt < max_prtnum; prt++) { - /* only for enabled ports */ - if ((1 << prt) & port_mask) { - /* skip CPU port */ - if ((1 << prt) & cpu_port) { - /* - * Set Vlan map table for cpu_port to see - * all ports - */ - RD_PHY(name, (ports_ofs + prt), - MV88E61XX_PRT_VMAP_REG, ®); - reg &= ~((1 << max_prtnum) - 1); - reg |= port_mask & ~(1 << prt); - WR_PHY(name, (ports_ofs + prt), - MV88E61XX_PRT_VMAP_REG, reg); - } else { - - /* - * set Ports VLAN Mapping. - * port prt <--> cpu_port VLAN #prt+1. - */ - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VID_REG, ®); - reg &= ~0x0fff; - reg |= (prt + 1); - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VID_REG, reg); - - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VMAP_REG, ®); - if (vlancfg == MV88E61XX_VLANCFG_DEFAULT) { - /* - * all any port can send frames to all other ports - * ref: sec 3.2.1.1 of datasheet - */ - reg |= 0x03f; - reg &= ~(1 << prt); - } else if (vlancfg == MV88E61XX_VLANCFG_ROUTER) { - /* - * all other ports can send frames to CPU port only - * ref: sec 3.2.1.2 of datasheet - */ - reg &= ~((1 << max_prtnum) - 1); - reg |= cpu_port; - } - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VMAP_REG, reg); - } - } - } - - /* - * enable only appropriate ports to forwarding mode - * and disable the others - */ - for (prt = 0; prt < max_prtnum; prt++) { - if ((1 << prt) & port_mask) { - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, ®); - reg |= 0x3; - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, reg); - } else { - /* Disable port */ - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, ®); - reg &= ~0x3; - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, reg); - } - } -} - /* * Make sure SMIBusy bit cleared before another * SMI operation can take place @@ -204,7 +101,7 @@ static int mv88e61xx_busychk(char *name) u16 reg = 0; u32 timeout = MV88E61XX_PHY_TIMEOUT; do { - RD_PHY(name, MV88E61XX_GLB2REG_DEVADR, + RD_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, ®); if (timeout-- == 0) { printf("SMI busy timeout\n"); @@ -215,33 +112,104 @@ static int mv88e61xx_busychk(char *name) } /* + * Convenience macros for switch PORT reads + */ + +#define WR_SWITCH_PORT_REG(n, p, r, d) \ + WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) +#define RD_SWITCH_PORT_REG(n, p, r, d) \ + RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) + +/* + * Local functions to read/write registers on the switch PHYs. + * NOTE! This goes through switch, not direct miiphy, writes and reads! + */ + +static inline int mv88e61xx_switch_miiphy_write(char *name, u32 phy, + u32 reg, u16 data) +{ + /* write switch data reg then cmd reg then check completion */ + WR_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, + data); + WR_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, + (MV88E61XX_PHY_WRITE_CMD | (phy << 5) | reg)); + return mv88e61xx_busychk(name); +} + +static inline int mv88e61xx_switch_miiphy_read(char *name, u32 phy, + u32 reg, u16 *data) +{ + /* write switch cmd reg, check for completion */ + WR_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, + (MV88E61XX_PHY_READ_CMD | (phy << 5) | reg)); + if (mv88e61xx_busychk(name)) + return -1; + /* read switch data reg and return success */ + RD_SWITCH_REG(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, data); + return 0; +} + +/* + * Convenience macros for switch PHY reads + */ + +#define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write +#define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read + +static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig) +{ + u32 prt; + u16 reg; + char *name = swconfig->name; + u32 port_mask = swconfig->ports_enabled; + + /* 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); + } + + /* apply internal vlan config */ + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + /* only for enabled ports */ + if ((1 << prt) & port_mask) { + /* take vlan map from swconfig */ + u8 vlanmap = swconfig->vlancfg[prt]; + /* remove disabled ports from vlan map */ + vlanmap &= swconfig->ports_enabled; + /* apply vlan map to port */ + RD_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_VMAP_REG, ®); + reg &= ~((1 << MV88E61XX_MAX_PORTS_NUM) - 1); + reg |= vlanmap; + WR_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_VMAP_REG, reg); + } + } + +} + +/* * Power up the specified port and reset PHY */ static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt) { char *name = swconfig->name; - /* Write Copper Specific control reg1 (0x14) for- + /* Write Copper Specific control reg1 (0x10) for- * Enable Phy power up * Energy Detect on (sense&Xmit NLP Periodically * reset other settings default */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x3360); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (0x9410 | (prt << 5))); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, prt, 0x10, 0x3360)) return -1; /* Write PHY ctrl reg (0x0) to apply * Phy reset (set bit 15 low) * reset other default values */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x1140); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (0x9400 | (prt << 5))); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, prt, 0x00, 0x9140)) return -1; return 0; @@ -259,45 +227,23 @@ static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt) static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt) { char *name = swconfig->name; - u16 reg; if (swconfig->led_init != MV88E61XX_LED_INIT_EN) return 0; /* set page address to 3 */ - reg = 3; - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 22)); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, prt, 0x16, 0x0003)) return -1; - /* set LED Func Ctrl reg */ - reg = 1; /* LED[0] On-Link, Blink-Activity, Off-NoLink */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 16)); - - if (mv88e61xx_busychk(name)) + /* + * set LED Func Ctrl reg + * value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink + */ + if (WR_SWITCH_PHY_REG(name, prt, 0x10, 0x0001)) return -1; /* set page address to 0 */ - reg = 0; - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 22)); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, prt, 0x16, 0x0000)) return -1; return 0; @@ -315,20 +261,12 @@ static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt) static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 prt) { char *name = swconfig->name; - u16 reg; if (swconfig->mdip != MV88E61XX_MDIP_REVERSE) return 0; - reg = 0x0f; /*Reverse MDIP/N[3:0] bits */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 20)); - - if (mv88e61xx_busychk(name)) + /*Reverse MDIP/N[3:0] bits */ + if (WR_SWITCH_PHY_REG(name, prt, 0x14, 0x000f)) return -1; return 0; @@ -354,7 +292,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) printf("Invalid cpu port config, using default port5\n"); } - RD_PHY(name, MV88E61XX_PRT_OFST, MII_PHYSID2, ®); + RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, ®); switch (reg &= 0xfff0) { case 0x1610: idstr = "88E6161"; @@ -374,45 +312,57 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) } /* 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; - } + 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 */ - WR_PHY(name, MV88E61XX_PRT_OFST + 5, - MV88E61XX_RGMII_TIMECTRL_REG, 0x18); - WR_PHY(name, MV88E61XX_PRT_OFST + 4, - MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + /*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++) { if (!((1 << prt) & swconfig->cpuport)) { - if (mv88361xx_led_init(swconfig, prt)) + if (mv88361xx_powerup(swconfig, prt)) return -1; + WR_SWITCH_PORT_REG(name, prt, 4, 0x7f); if (mv88361xx_reverse_mdipn(swconfig, prt)) return -1; - if (mv88361xx_powerup(swconfig, prt)) + if (mv88361xx_led_init(swconfig, prt)) return -1; } /*Program port state */ - RD_PHY(name, MV88E61XX_PRT_OFST + prt, + RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, ®); - WR_PHY(name, MV88E61XX_PRT_OFST + prt, + WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg | (swconfig->portstate & 0x03)); + } + /* do a sw reset */ + RD_SWITCH_REG(name, 0x1B, 0x04, ®); + reg |= 0x8000; + WR_SWITCH_REG(name, 0x1B, 0x04, reg); + /* wait for at least 2 ms */ + udelay(2500); + printf("%s Initialized on %s\n", idstr, name); return 0; } diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h index 57762b6..7595cbc 100644 --- a/drivers/net/phy/mv88e61xx.h +++ b/drivers/net/phy/mv88e61xx.h @@ -28,11 +28,10 @@ #include <miiphy.h> #define MV88E61XX_CPU_PORT 0x5 -#define MV88E61XX_MAX_PORTS_NUM 0x6 #define MV88E61XX_PHY_TIMEOUT 100000 -#define MV88E61XX_PRT_STS_REG 0x1 +#define MV88E61XX_PCS_CTRL_REG 0x1 #define MV88E61XX_PRT_CTRL_REG 0x4 #define MV88E61XX_PRT_VMAP_REG 0x6 #define MV88E61XX_PRT_VID_REG 0x7 @@ -43,20 +42,26 @@ #define MV88E61XX_RGMII_TIMECTRL_REG 0x1A #define MV88E61XX_GLB2REG_DEVADR 0x1C +#define MV88E61XX_PHY_WRITE_CMD 0x9400 +#define MV88E61XX_PHY_READ_CMD 0x9800 + #define MV88E61XX_BUSY_OFST 15 #define MV88E61XX_MODE_OFST 12 -#define MV88E61XX_OP_OFST 10 +#define MV88E61XX_OP_OFST 10 #define MV88E61XX_ADDR_OFST 5 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE static int mv88e61xx_busychk_multic(char *name, u32 devaddr); -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data); -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data); -#define WR_PHY mv88e61xx_wr_phy -#define RD_PHY mv88e61xx_rd_phy +static void mv88e61xx_switch_write(char *name, u32 phy_adr, + u32 reg_ofs, u16 data); +static void mv88e61xx_switch_read(char *name, u32 phy_adr, + u32 reg_ofs, u16 *data); +#define WR_SWITCH_REG mv88e61xx_switch_write +#define RD_SWITCH_REG mv88e61xx_switch_read #else -#define WR_PHY miiphy_write -#define RD_PHY miiphy_read +/* switch appears a s simple PHY and can thus use miiphy */ +#define WR_SWITCH_REG miiphy_write +#define RD_SWITCH_REG miiphy_read #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ #endif /* _MV88E61XX_H */ diff --git a/include/netdev.h b/include/netdev.h index b8d303d..e1eb40a 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -163,10 +163,9 @@ static inline int pci_eth_init(bd_t *bis) * the stuct and enums here are used to specify switch configuration params */ #if defined(CONFIG_MV88E61XX_SWITCH) -enum mv88e61xx_cfg_vlan { - MV88E61XX_VLANCFG_DEFAULT, - MV88E61XX_VLANCFG_ROUTER -}; + +/* constants for any 88E61xx switch */ +#define MV88E61XX_MAX_PORTS_NUM 6 enum mv88e61xx_cfg_mdip { MV88E61XX_MDIP_NOCHANGE, @@ -192,7 +191,7 @@ enum mv88e61xx_cfg_prtstt { struct mv88e61xx_config { char *name; - enum mv88e61xx_cfg_vlan vlancfg; + u8 vlancfg[MV88E61XX_MAX_PORTS_NUM]; enum mv88e61xx_cfg_rgmiid rgmii_delay; enum mv88e61xx_cfg_prtstt portstate; enum mv88e61xx_cfg_ledinit led_init; @@ -201,6 +200,18 @@ struct mv88e61xx_config { u8 cpuport; }; +/* + * Common mappings for Internal VLANs + * These mappings consider that all ports are useable; the driver + * will mask inexistent/unused ports. + */ + +/* Switch mode : routes any port to any port */ +#define MV88E61XX_VLANCFG_SWITCH { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F } + +/* Router mode: routes only CPU port 5 to/from non-CPU ports 0-4 */ +#define MV88E61XX_VLANCFG_ROUTER { 0x30, 0x30, 0x30, 0x30, 0x2F, 0x1F } + int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig); #endif /* CONFIG_MV88E61XX_SWITCH */
Signed-off-by: Albert ARIBAUD <albert.u.boot@aribaud.net> --- drivers/net/phy/mv88e61xx.c | 300 ++++++++++++++++++------------------------- drivers/net/phy/mv88e61xx.h | 23 ++-- include/netdev.h | 21 ++- 3 files changed, 155 insertions(+), 189 deletions(-)