> -----Original Message----- > From: Albert ARIBAUD [mailto:albert.u.b...@aribaud.net] > Sent: 05 November 2012 05:02 > To: U-Boot > Cc: Prafulla Wadaskar; Simon Guinot; Albert ARIBAUD; > joe.hershber...@gmail.com > Subject: [PATCH v4 2/4] mv88e61xx: refactor PHY and SWITCH level-code > > > Signed-off-by: Albert ARIBAUD <albert.u.b...@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 <prafu...@marvell.com> Regards... Prafulla . . . _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot