[U-Boot] [PATCH v4] Marvell MV88E61XX Switch Driver support

Chips supported:- 1. 88E6161 6 port gbe swtich with 5 integrated PHYs 2. 88E6165 6 port gbe swtich with 5 integrated PHYs 2. 88E6132 3 port gbe swtich with 2 integrated PHYs Platform specific configuration supported
Note: This driver is supported and tested against kirkwood egiga interface
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com --- Changelog:- v2: updated as per review comments for v1 removed other two drivers form earlier patch debug_prints removed driver moved to drivers/net/
v3: updated as per review comments for v2 miiphy interface used, platform specific dependency resolved Chip id detection and printing added common code forked out some cosmetic and magic number fixes
v4: updated as per review comments for v3 mv88e61xx.h added platform specific configuration support added some more documentation references provided cleaned rgmii delay enable related code
drivers/net/Makefile | 1 + drivers/net/mv88e61xx.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/mv88e61xx.h | 73 ++++++++++++ 3 files changed, 370 insertions(+), 0 deletions(-) create mode 100644 drivers/net/mv88e61xx.c create mode 100644 drivers/net/mv88e61xx.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a360a50..7d397d6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_MACB) += macb.o COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o COBJS-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o +COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o COBJS-$(CONFIG_NATSEMI) += natsemi.o COBJS-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o diff --git a/drivers/net/mv88e61xx.c b/drivers/net/mv88e61xx.c new file mode 100644 index 0000000..713e728 --- /dev/null +++ b/drivers/net/mv88e61xx.c @@ -0,0 +1,296 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <miiphy.h> +#include "mv88e61xx.h" + +/* Chip Address mode + * The Switch support two modes of operation + * 1. single chip mode and + * 2. Multi-chip mode + * Refer section 9.2 &9.3 in chip datasheet-02 for more details + * + * By default single chip mode is configured + * multichip mode operation can be configured in board header + */ +#ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +#define mv88e61xx_wr_phy miiphy_write +#define mv88e61xx_rd_phy miiphy_read +#else + +static int mv88e61xx_busychk_multic(u32 devaddr) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + + /* Poll till SMIBusy bit is clear */ + do { + miiphy_read(name, devaddr, 0x0, ®); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & BIT15); + return 0; +} + +static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr); + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write data to Switch indirect data register */ + miiphy_write(name, mii_dev_addr, 0x1, data); + /* Write command to Switch indirect command register (write) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15); +} + +static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr); + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write command to Switch indirect command register (read) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15); + mv88e61xx_busychk_multic(mii_dev_addr); + /* Read data from Switch indirect data register */ + miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data); +} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ + +static void mv88e61xx_vlaninit(struct mv88f61xx_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; + + /* be sure all ports are disabled */ + for (prt = 0; prt < max_prtnum; prt++) { + mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, + ®); + reg &= ~0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, + reg); + } + /* Set CPU port VID to 0x1 */ + mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG, + ®); + reg &= ~0xfff; + reg |= 0x1; + mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG, + reg); + + /* Setting Port default priority for all ports to zero */ + for (prt = 0; prt < max_prtnum; prt++) { + mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, + ®); + reg &= ~0xc000; + mv88e61xx_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 (prt == cpu_port) + continue; + + /* + * set Ports VLAN Mapping. + * port prt <--> cpu_port VLAN #prt+1. + */ + + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, ®); + reg &= ~0x0fff; + reg |= (prt + 1); + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, reg); + + /* + * Set Vlan map table for all ports to send only to + * cpu_port + */ + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VMAP_REG, ®); + reg &= ~((1 << max_prtnum) - 1); + reg |= (1 << cpu_port); + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VMAP_REG, reg); + } + } + /* Set Vlan map table for cpu_port to see all ports */ + mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VMAP_REG, + ®); + reg &= ~((1 << max_prtnum) - 1); + reg |= port_mask & ~(1 << cpu_port); + mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), 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) { + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg |= 0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } else { + /* Disable port */ + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg &= ~0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } + } +} + +/* + * Make sure SMIBusy bit cleared before another + * SMI operation can take place + */ +static int mv88361xx_busychk(char *name) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + do { + mv88e61xx_rd_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (u16 *) & reg); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & BIT28); /* busy mask */ + return 0; +} + +/* + * Marvell 88E61XX Switch initialization + */ +int mv_switch_88e61xx_init(struct mv88f61xx_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->mode != MV88F61XX_MODE_SW_MANAGEED) { + printf("Unsupported mode %s failed\n", __FUNCTION__); + return -1; + } + + if (swconfig->cpuport < 4) { + swconfig->cpuport = 5; + printf("Invalid cpu port config, using default port5\n"); + } + + mv88e61xx_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"; + swconfig->ports_enabled &= 0x023; /* ports 2,3,4 no available */ + } + + /* Init vlan */ + mv88e61xx_vlaninit(swconfig, MV88E61XX_MAX_PORTS_NUM, + MV88E61XX_PRT_OFST); + + if (swconfig->rgmii_delay == MV88F61XX_RGMII_DELAY_EN) { + /* + * Enable RGMII delay on Tx and Rx for CPU port + * Ref: sec 9.5 of chip datasheet-02 + */ + mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 5, + MV88E61XX_RGMII_TIMECTRL_REG, 0x18); + mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 4, + MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + } + + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + if (prt != swconfig->cpuport) { + /* Write Copper Specific control reg1 (0x14) for- + * Enable Phy power up + * Energy Detect on (sense&Xmit NLP Periodically + * reset other settings default + */ + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_DATA, 0x3360); + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, + (0x9410 | (prt << 5))); + + if (mv88361xx_busychk(name)) + return -1; + + /* Write PHY ctrl reg (0x0) to apply + * Phy reset (BIT15=low) + * reset other default values + */ + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_DATA, 0x1140); + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, + (0x9400 | (prt << 5))); + + if (mv88361xx_busychk(name)) + return -1; + } + + /*Program port state */ + mv88e61xx_rd_phy(name, MV88E61XX_PRT_OFST + prt, + MV88E61XX_PRT_CTRL_REG, ®); + mv88e61xx_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; +} diff --git a/drivers/net/mv88e61xx.h b/drivers/net/mv88e61xx.h new file mode 100644 index 0000000..f1c86a6 --- /dev/null +++ b/drivers/net/mv88e61xx.h @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _MV88E61XX_H +#define _MV88E61XX_H + +#define PORT(_x) (1 << _x) +#define MV88E61XX_CPU_PORT 0x5 +#define MV88E61XX_MAX_PORTS_NUM 0x6 + +#define MV88E61XX_PHY_TIMEOUT 100000 + +#define MV88E61XX_PRT_STS_REG 0x1 +#define MV88E61XX_PRT_CTRL_REG 0x4 +#define MV88E61XX_PRT_VMAP_REG 0x6 +#define MV88E61XX_PRT_VID_REG 0x7 + +#define MV88E61XX_PRT_OFST 0x10 +#define MV88E61XX_PHY_CMD 0x18 +#define MV88E61XX_PHY_DATA 0x19 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A +#define MV88E61XX_GLB2REG_DEVADR 0x1C + +/* constants for switch configuration */ +enum mv88f61xx_cfg_mode { + MV88F61XX_MODE_SW_MANAGEED, + MV88F61XX_MODE_SW_UNMANAGEED +}; + +enum mv88f61xx_cfg_rgmiid { + MV88F61XX_RGMII_DELAY_DIS, + MV88F61XX_RGMII_DELAY_EN +}; + +enum mv88f61xx_cfg_prtstt { + MV88E61XX_PORTSTT_DISABLED, + MV88E61XX_PORTSTT_BLOCKING, + MV88E61XX_PORTSTT_LEARNING, + MV88E61XX_PORTSTT_FORWARDING +}; + +/* switch configuration structure */ +struct mv88f61xx_config { + char *name; + enum mv88f61xx_cfg_mode mode; + enum mv88f61xx_cfg_rgmiid rgmii_delay; + enum mv88f61xx_cfg_prtstt portstate; + u32 ports_enabled; + u8 cpuport; +}; + +#endif /* _MV88E61XX_H */

On 18:54 Wed 15 Apr , Prafulla Wadaskar wrote:
Chips supported:-
- 88E6161 6 port gbe swtich with 5 integrated PHYs
- 88E6165 6 port gbe swtich with 5 integrated PHYs
- 88E6132 3 port gbe swtich with 2 integrated PHYs
Platform specific configuration supported
Note: This driver is supported and tested against kirkwood egiga interface
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com
Changelog:- v2: updated as per review comments for v1 removed other two drivers form earlier patch debug_prints removed driver moved to drivers/net/
v3: updated as per review comments for v2 miiphy interface used, platform specific dependency resolved Chip id detection and printing added common code forked out some cosmetic and magic number fixes
v4: updated as per review comments for v3 mv88e61xx.h added platform specific configuration support added some more documentation references provided cleaned rgmii delay enable related code
this version looks better
I've just 2 comments on it
1) drivers/net/phy/ is for phylib and drivers as a switch can be consider as a multiple phy port please move it there
2) the Vlan init is not so clear for people who need to maintain or update the code as the Marvell's switch datasheets are all under NDA
Best Regards, J.

-----Original Message----- From: Jean-Christophe PLAGNIOL-VILLARD [mailto:plagnioj@jcrosoft.com] Sent: Friday, April 17, 2009 1:06 PM To: Prafulla Wadaskar Cc: u-boot@lists.denx.de; Ashish Karkare; Ronen Shitrit; Ben Warren Subject: Re: [U-Boot] [PATCH v4] Marvell MV88E61XX Switch Driver support
On 18:54 Wed 15 Apr , Prafulla Wadaskar wrote:
Chips supported:-
- 88E6161 6 port gbe swtich with 5 integrated PHYs 2.
88E6165 6 port
gbe swtich with 5 integrated PHYs 2. 88E6132 3 port gbe
swtich with 2
integrated PHYs Platform specific configuration supported
Note: This driver is supported and tested against kirkwood egiga interface
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com
Changelog:- v2: updated as per review comments for v1 removed other two drivers form earlier patch debug_prints removed driver moved to drivers/net/
v3: updated as per review comments for v2 miiphy interface used, platform specific dependency resolved Chip id detection and
printing
added common code forked out some cosmetic and magic number fixes
v4: updated as per review comments for v3 mv88e61xx.h added
platform
specific configuration support added some more documentation references provided cleaned rgmii delay enable related code
this version looks better
I've just 2 comments on it
Thanks jean.... :-)
- drivers/net/phy/ is for phylib and drivers as a switch can
be consider as a multiple phy port please move it there
Okay... I will move this driver to suggested location.
- the Vlan init is not so clear for people who need to
maintain or update the code as the Marvell's switch datasheets are all under NDA
The name vlan init may be confusing. I can easily put this in platform specific code, but this is very common combination used most of the boards. So there will be unnecessary code duplication. I will restructure and rename it to the proper switch use case so that it will be clear to most of the users.
Regards.. Prafulla . .
Best Regards, J.

Chips supported:- 1. 88E6161 6 port gbe swtich with 5 integrated PHYs 2. 88E6165 6 port gbe swtich with 5 integrated PHYs 2. 88E6132 3 port gbe swtich with 2 integrated PHYs Platform specific configuration supported default and router port vlan config supported
Note: This driver is supported and tested against kirkwood egiga interface
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com --- Changelog:- v2: updated as per review comments for v1 removed other two drivers form earlier patch debug_prints removed driver moved to drivers/net/
v3: updated as per review comments for v2 miiphy interface used, platform specific dependency resolved Chip id detection and printing added common code forked out some cosmetic and magic number fixes
v4: updated as per review comments for v3 mv88e61xx.h added platform specific configuration support added some more documentation references provided cleaned rgmii delay enable related code
v5: updated as per review comments for v3 code moved to drivers/net/phy/ vlan_init changed to vlan_config and platform specific
drivers/net/phy/Makefile | 1 + drivers/net/phy/mv88e61xx.c | 313 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mv88e61xx.h | 73 ++++++++++ 3 files changed, 387 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/mv88e61xx.c create mode 100644 drivers/net/phy/mv88e61xx.h
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 4fe3b05..3b92614 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libphy.a
COBJS-$(CONFIG_BITBANGMII) += miiphybb.o +COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c new file mode 100644 index 0000000..8ba2291 --- /dev/null +++ b/drivers/net/phy/mv88e61xx.c @@ -0,0 +1,313 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <miiphy.h> +#include "mv88e61xx.h" + +/* Chip Address mode + * The Switch support two modes of operation + * 1. single chip mode and + * 2. Multi-chip mode + * Refer section 9.2 &9.3 in chip datasheet-02 for more details + * + * By default single chip mode is configured + * multichip mode operation can be configured in board header + */ +#ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +#define mv88e61xx_wr_phy miiphy_write +#define mv88e61xx_rd_phy miiphy_read +#else + +static int mv88e61xx_busychk_multic(u32 devaddr) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + + /* Poll till SMIBusy bit is clear */ + do { + miiphy_read(name, devaddr, 0x0, ®); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & BIT15); + return 0; +} + +static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + printf("Error..could not read PHY dev address\n"); + return; + } + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write data to Switch indirect data register */ + miiphy_write(name, mii_dev_addr, 0x1, data); + /* Write command to Switch indirect command register (write) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15); +} + +static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + printf("Error..could not read PHY dev address\n"); + return; + } + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write command to Switch indirect command register (read) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15); + mv88e61xx_busychk_multic(mii_dev_addr); + /* Read data from Switch indirect data register */ + miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data); +} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ + +static void mv88e61xx_vlan_config(struct mv88f61xx_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 mv88f61xx_cfg_vlan vlancfg = swconfig->vlancfg; + + /* be sure all ports are disabled */ + for (prt = 0; prt < max_prtnum; prt++) { + mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, + ®); + reg &= ~0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, + reg); + } + /* Set CPU port VID to 0x1 */ + mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG, + ®); + reg &= ~0xfff; + reg |= 0x1; + mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG, + reg); + + /* Setting Port default priority for all ports to zero */ + for (prt = 0; prt < max_prtnum; prt++) { + mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, + ®); + reg &= ~0xc000; + mv88e61xx_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 (prt == cpu_port) + continue; + + /* + * set Ports VLAN Mapping. + * port prt <--> cpu_port VLAN #prt+1. + */ + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, ®); + reg &= ~0x0fff; + reg |= (prt + 1); + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, reg); + + mv88e61xx_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 |= (1 << cpu_port); + } + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VMAP_REG, reg); + } + } + /* Set Vlan map table for cpu_port to see all ports */ + mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VMAP_REG, + ®); + reg &= ~((1 << max_prtnum) - 1); + reg |= port_mask & ~(1 << cpu_port); + mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), 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) { + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg |= 0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } else { + /* Disable port */ + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg &= ~0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } + } +} + +/* + * Make sure SMIBusy bit cleared before another + * SMI operation can take place + */ +static int mv88361xx_busychk(char *name) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + do { + mv88e61xx_rd_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (u16 *) & reg); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & BIT28); /* busy mask */ + return 0; +} + +/* + * Marvell 88E61XX Switch initialization + */ +int mv_switch_88e61xx_init(struct mv88f61xx_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 < 4) { + swconfig->cpuport = 5; + printf("Invalid cpu port config, using default port5\n"); + } + + mv88e61xx_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_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 + */ + mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 5, + MV88E61XX_RGMII_TIMECTRL_REG, 0x18); + mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 4, + MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + } + + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + if (prt != swconfig->cpuport) { + /* Write Copper Specific control reg1 (0x14) for- + * Enable Phy power up + * Energy Detect on (sense&Xmit NLP Periodically + * reset other settings default + */ + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_DATA, 0x3360); + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, + (0x9410 | (prt << 5))); + + if (mv88361xx_busychk(name)) + return -1; + + /* Write PHY ctrl reg (0x0) to apply + * Phy reset (BIT15=low) + * reset other default values + */ + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_DATA, 0x1140); + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, + (0x9400 | (prt << 5))); + + if (mv88361xx_busychk(name)) + return -1; + } + + /*Program port state */ + mv88e61xx_rd_phy(name, MV88E61XX_PRT_OFST + prt, + MV88E61XX_PRT_CTRL_REG, ®); + mv88e61xx_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; +} diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h new file mode 100644 index 0000000..400a4ad --- /dev/null +++ b/drivers/net/phy/mv88e61xx.h @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _MV88E61XX_H +#define _MV88E61XX_H + +#define PORT(_x) (1 << _x) +#define MV88E61XX_CPU_PORT 0x5 +#define MV88E61XX_MAX_PORTS_NUM 0x6 + +#define MV88E61XX_PHY_TIMEOUT 100000 + +#define MV88E61XX_PRT_STS_REG 0x1 +#define MV88E61XX_PRT_CTRL_REG 0x4 +#define MV88E61XX_PRT_VMAP_REG 0x6 +#define MV88E61XX_PRT_VID_REG 0x7 + +#define MV88E61XX_PRT_OFST 0x10 +#define MV88E61XX_PHY_CMD 0x18 +#define MV88E61XX_PHY_DATA 0x19 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A +#define MV88E61XX_GLB2REG_DEVADR 0x1C + +/* constants for switch configuration */ +enum mv88f61xx_cfg_vlan { + MV88E61XX_VLANCFG_DEFAULT, + MV88E61XX_VLANCFG_ROUTER +}; + +enum mv88f61xx_cfg_rgmiid { + MV88E61XX_RGMII_DELAY_DIS, + MV88E61XX_RGMII_DELAY_EN +}; + +enum mv88f61xx_cfg_prtstt { + MV88E61XX_PORTSTT_DISABLED, + MV88E61XX_PORTSTT_BLOCKING, + MV88E61XX_PORTSTT_LEARNING, + MV88E61XX_PORTSTT_FORWARDING +}; + +/* switch configuration structure */ +struct mv88f61xx_config { + char *name; + enum mv88f61xx_cfg_vlan vlancfg; + enum mv88f61xx_cfg_rgmiid rgmii_delay; + enum mv88f61xx_cfg_prtstt portstate; + u32 ports_enabled; + u8 cpuport; +}; + +#endif /* _MV88E61XX_H */ -- 1.5.3.4

Hi Prafulla,
Sorry for dragging this out... you've made a lot of good changes already, and are almost there. Prafulla Wadaskar wrote:
Chips supported:-
- 88E6161 6 port gbe swtich with 5 integrated PHYs
- 88E6165 6 port gbe swtich with 5 integrated PHYs
- 88E6132 3 port gbe swtich with 2 integrated PHYs
Platform specific configuration supported default and router port vlan config supported
Note: This driver is supported and tested against kirkwood egiga interface
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com
Changelog:- v2: updated as per review comments for v1 removed other two drivers form earlier patch debug_prints removed driver moved to drivers/net/
v3: updated as per review comments for v2 miiphy interface used, platform specific dependency resolved Chip id detection and printing added common code forked out some cosmetic and magic number fixes
v4: updated as per review comments for v3 mv88e61xx.h added platform specific configuration support added some more documentation references provided cleaned rgmii delay enable related code
v5: updated as per review comments for v3 code moved to drivers/net/phy/ vlan_init changed to vlan_config and platform specific
drivers/net/phy/Makefile | 1 + drivers/net/phy/mv88e61xx.c | 313 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mv88e61xx.h | 73 ++++++++++ 3 files changed, 387 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/mv88e61xx.c create mode 100644 drivers/net/phy/mv88e61xx.h
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 4fe3b05..3b92614 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libphy.a
COBJS-$(CONFIG_BITBANGMII) += miiphybb.o +COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c new file mode 100644 index 0000000..8ba2291 --- /dev/null +++ b/drivers/net/phy/mv88e61xx.c @@ -0,0 +1,313 @@ +/*
- (C) Copyright 2009
- Marvell Semiconductor <www.marvell.com>
- Prafulla Wadaskar prafulla@marvell.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- MA 02110-1301 USA
- */
+#include <common.h> +#include <miiphy.h> +#include "mv88e61xx.h"
+/* Chip Address mode
- The Switch support two modes of operation
- single chip mode and
- Multi-chip mode
- Refer section 9.2 &9.3 in chip datasheet-02 for more details
- By default single chip mode is configured
- multichip mode operation can be configured in board header
- */
+#ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +#define mv88e61xx_wr_phy miiphy_write +#define mv88e61xx_rd_phy miiphy_read +#else
+static int mv88e61xx_busychk_multic(u32 devaddr) +{
I mentioned this previously - if you're going to alias functions please do it in a header (I see that you have one now).
- u32 reg = 0;
- u32 timeout = MV88E61XX_PHY_TIMEOUT;
- /* Poll till SMIBusy bit is clear */
- do {
miiphy_read(name, devaddr, 0x0, ®);
if (timeout-- == 0) {
printf("SMI busy timeout\n");
return -1;
}
- } while (reg & BIT15);
- return 0;
+}
+static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +{
- u16 reg;
- u32 mii_dev_addr;
- /* command to read PHY dev address */
- if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
- }
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Write data to Switch indirect data register */
- miiphy_write(name, mii_dev_addr, 0x1, data);
- /* Write command to Switch indirect command register (write) */
- miiphy_write(name, mii_dev_addr, 0x0,
reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
+}
+static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +{
- u16 reg;
- u32 mii_dev_addr;
- /* command to read PHY dev address */
- if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
- }
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Write command to Switch indirect command register (read) */
- miiphy_write(name, mii_dev_addr, 0x0,
reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Read data from Switch indirect data register */
- miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data);
+} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
+static void mv88e61xx_vlan_config(struct mv88f61xx_config *swconfig,
u32 max_prtnum, u32 ports_ofs)
Please rename these functions to make clear that you're configuring port-based VLANs. Maybe 'mv88e61xx_port_vlan_config()' or something like that.
+{
- u32 prt;
- u16 reg;
- char *name = swconfig->name;
- u32 cpu_port = swconfig->cpuport;
- u32 port_mask = swconfig->ports_enabled;
- enum mv88f61xx_cfg_vlan vlancfg = swconfig->vlancfg;
- /* be sure all ports are disabled */
- for (prt = 0; prt < max_prtnum; prt++) {
mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG,
®);
reg &= ~0x3;
mv88e61xx_wr_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG,
reg);
- }
- /* Set CPU port VID to 0x1 */
- mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG,
®);
- reg &= ~0xfff;
- reg |= 0x1;
- mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG,
reg);
- /* Setting Port default priority for all ports to zero */
- for (prt = 0; prt < max_prtnum; prt++) {
mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG,
®);
reg &= ~0xc000;
mv88e61xx_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 (prt == cpu_port)
continue;
/*
* set Ports VLAN Mapping.
* port prt <--> cpu_port VLAN #prt+1.
*/
mv88e61xx_rd_phy(name, ports_ofs + prt,
MV88E61XX_PRT_VID_REG, ®);
reg &= ~0x0fff;
reg |= (prt + 1);
mv88e61xx_wr_phy(name, ports_ofs + prt,
MV88E61XX_PRT_VID_REG, reg);
mv88e61xx_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 |= (1 << cpu_port);
}
mv88e61xx_wr_phy(name, ports_ofs + prt,
MV88E61XX_PRT_VMAP_REG, reg);
}
- }
- /* Set Vlan map table for cpu_port to see all ports */
- mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VMAP_REG,
®);
- reg &= ~((1 << max_prtnum) - 1);
- reg |= port_mask & ~(1 << cpu_port);
- mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), 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) {
mv88e61xx_rd_phy(name, ports_ofs + prt,
MV88E61XX_PRT_CTRL_REG, ®);
reg |= 0x3;
mv88e61xx_wr_phy(name, ports_ofs + prt,
MV88E61XX_PRT_CTRL_REG, reg);
} else {
/* Disable port */
mv88e61xx_rd_phy(name, ports_ofs + prt,
MV88E61XX_PRT_CTRL_REG, ®);
reg &= ~0x3;
mv88e61xx_wr_phy(name, ports_ofs + prt,
MV88E61XX_PRT_CTRL_REG, reg);
}
- }
+}
+/*
- Make sure SMIBusy bit cleared before another
- SMI operation can take place
- */
+static int mv88361xx_busychk(char *name) +{
- u32 reg = 0;
- u32 timeout = MV88E61XX_PHY_TIMEOUT;
- do {
mv88e61xx_rd_phy(name, MV88E61XX_GLB2REG_DEVADR,
MV88E61XX_PHY_CMD, (u16 *) & reg);
if (timeout-- == 0) {
printf("SMI busy timeout\n");
return -1;
}
- } while (reg & BIT28); /* busy mask */
- return 0;
+}
+/*
- Marvell 88E61XX Switch initialization
- */
+int mv_switch_88e61xx_init(struct mv88f61xx_config *swconfig)
Please add this function's prototype to include/netdev.h
+{
- 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 < 4) {
swconfig->cpuport = 5;
printf("Invalid cpu port config, using default port5\n");
- }
- mv88e61xx_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_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
*/
mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 5,
MV88E61XX_RGMII_TIMECTRL_REG, 0x18);
mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 4,
MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7);
- }
- for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
if (prt != swconfig->cpuport) {
/* Write Copper Specific control reg1 (0x14) for-
* Enable Phy power up
* Energy Detect on (sense&Xmit NLP Periodically
* reset other settings default
*/
mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR,
MV88E61XX_PHY_DATA, 0x3360);
mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR,
MV88E61XX_PHY_CMD,
(0x9410 | (prt << 5)));
if (mv88361xx_busychk(name))
return -1;
/* Write PHY ctrl reg (0x0) to apply
* Phy reset (BIT15=low)
* reset other default values
*/
mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR,
MV88E61XX_PHY_DATA, 0x1140);
mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR,
MV88E61XX_PHY_CMD,
(0x9400 | (prt << 5)));
if (mv88361xx_busychk(name))
return -1;
}
/*Program port state */
mv88e61xx_rd_phy(name, MV88E61XX_PRT_OFST + prt,
MV88E61XX_PRT_CTRL_REG, ®);
mv88e61xx_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;
+} diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h new file mode 100644 index 0000000..400a4ad --- /dev/null +++ b/drivers/net/phy/mv88e61xx.h @@ -0,0 +1,73 @@ +/*
- (C) Copyright 2009
- Marvell Semiconductor <www.marvell.com>
- Prafulla Wadaskar prafulla@marvell.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- MA 02110-1301 USA
- */
+#ifndef _MV88E61XX_H +#define _MV88E61XX_H
+#define PORT(_x) (1 << _x) +#define MV88E61XX_CPU_PORT 0x5 +#define MV88E61XX_MAX_PORTS_NUM 0x6
+#define MV88E61XX_PHY_TIMEOUT 100000
+#define MV88E61XX_PRT_STS_REG 0x1 +#define MV88E61XX_PRT_CTRL_REG 0x4 +#define MV88E61XX_PRT_VMAP_REG 0x6 +#define MV88E61XX_PRT_VID_REG 0x7
+#define MV88E61XX_PRT_OFST 0x10 +#define MV88E61XX_PHY_CMD 0x18 +#define MV88E61XX_PHY_DATA 0x19 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A +#define MV88E61XX_GLB2REG_DEVADR 0x1C
+/* constants for switch configuration */ +enum mv88f61xx_cfg_vlan {
- MV88E61XX_VLANCFG_DEFAULT,
- MV88E61XX_VLANCFG_ROUTER
+};
+enum mv88f61xx_cfg_rgmiid {
- MV88E61XX_RGMII_DELAY_DIS,
- MV88E61XX_RGMII_DELAY_EN
+};
+enum mv88f61xx_cfg_prtstt {
- MV88E61XX_PORTSTT_DISABLED,
- MV88E61XX_PORTSTT_BLOCKING,
- MV88E61XX_PORTSTT_LEARNING,
- MV88E61XX_PORTSTT_FORWARDING
+};
+/* switch configuration structure */ +struct mv88f61xx_config {
- char *name;
- enum mv88f61xx_cfg_vlan vlancfg;
- enum mv88f61xx_cfg_rgmiid rgmii_delay;
- enum mv88f61xx_cfg_prtstt portstate;
- u32 ports_enabled;
- u8 cpuport;
+};
+#endif /* _MV88E61XX_H */
1.5.3.4
Thanks for all the hard work. Address these issues and I'll pull it into the net branch.
regards, Ben

+#include <common.h> +#include <miiphy.h> +#include "mv88e61xx.h"
+/* Chip Address mode
- The Switch support two modes of operation
- single chip mode and
- Multi-chip mode
- Refer section 9.2 &9.3 in chip datasheet-02 for more details
- By default single chip mode is configured
- multichip mode operation can be configured in board header */
+#ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +#define mv88e61xx_wr_phy miiphy_write #define mv88e61xx_rd_phy +miiphy_read #else
+static int mv88e61xx_busychk_multic(u32 devaddr) {
I mentioned this previously - if you're going to alias functions please do it in a header (I see that you have one now).
This is moved to header file
+static void mv88e61xx_vlan_config(struct mv88f61xx_config
*swconfig,
u32 max_prtnum, u32 ports_ofs)
Please rename these functions to make clear that you're configuring port-based VLANs. Maybe 'mv88e61xx_port_vlan_config()' or something like that.
This is renamed as mv88e61xx_port_vlan_config
+/*
- Marvell 88E61XX Switch initialization */ int
+mv_switch_88e61xx_init(struct mv88f61xx_config *swconfig)
Please add this function's prototype to include/netdev.h
Added also it is renamed as 'mv88f61xx_switch_initialization()'
1.5.3.4
Thanks for all the hard work. Address these issues and I'll pull it into the net branch.
I am sending patch v6 for the same, pls kindly pull it
Regards.. Prafulla . .

Chips supported:- 1. 88E6161 6 port gbe swtich with 5 integrated PHYs 2. 88E6165 6 port gbe swtich with 5 integrated PHYs 2. 88E6132 3 port gbe swtich with 2 integrated PHYs Platform specific configuration supported default and router port vlan config supported
Note: This driver is supported and tested against kirkwood egiga interface
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com --- Changelog:- v2: updated as per review comments for v1 removed other two drivers form earlier patch debug_prints removed driver moved to drivers/net/
v3: updated as per review comments for v2 miiphy interface used, platform specific dependency resolved Chip id detection and printing added common code forked out some cosmetic and magic number fixes
v4: updated as per review comments for v3 mv88e61xx.h added platform specific configuration support added some more documentation references provided cleaned rgmii delay enable related code
v5: updated as per review comments for v3 code moved to drivers/net/phy/ vlan_init changed to vlan_config and platform specific
v6: mutichip related alias moved to header file vlan_config functions renamed as port_vlan_config mv_switch_88f61xx_init renamed as mv88e61xx_switch_initialization the function prototype for same is added in netdev.h
drivers/net/phy/Makefile | 1 + drivers/net/phy/mv88e61xx.c | 244 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mv88e61xx.h | 143 +++++++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 389 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/mv88e61xx.c create mode 100644 drivers/net/phy/mv88e61xx.h
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 4fe3b05..3b92614 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libphy.a
COBJS-$(CONFIG_BITBANGMII) += miiphybb.o +COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c new file mode 100644 index 0000000..0bb08a0 --- /dev/null +++ b/drivers/net/phy/mv88e61xx.c @@ -0,0 +1,244 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include "mv88e61xx.h" + +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++) { + mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, + ®); + reg &= ~0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, + reg); + } + /* Set CPU port VID to 0x1 */ + mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG, + ®); + reg &= ~0xfff; + reg |= 0x1; + mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VID_REG, + reg); + + /* Setting Port default priority for all ports to zero */ + for (prt = 0; prt < max_prtnum; prt++) { + mv88e61xx_rd_phy(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, + ®); + reg &= ~0xc000; + mv88e61xx_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 (prt == cpu_port) + continue; + + /* + * set Ports VLAN Mapping. + * port prt <--> cpu_port VLAN #prt+1. + */ + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, ®); + reg &= ~0x0fff; + reg |= (prt + 1); + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, reg); + + mv88e61xx_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 |= (1 << cpu_port); + } + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_VMAP_REG, reg); + } + } + /* Set Vlan map table for cpu_port to see all ports */ + mv88e61xx_rd_phy(name, (ports_ofs + cpu_port), MV88E61XX_PRT_VMAP_REG, + ®); + reg &= ~((1 << max_prtnum) - 1); + reg |= port_mask & ~(1 << cpu_port); + mv88e61xx_wr_phy(name, (ports_ofs + cpu_port), 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) { + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg |= 0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } else { + /* Disable port */ + mv88e61xx_rd_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg &= ~0x3; + mv88e61xx_wr_phy(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } + } +} + +/* + * Make sure SMIBusy bit cleared before another + * SMI operation can take place + */ +static int mv88361xx_busychk(char *name) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + do { + mv88e61xx_rd_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (u16 *) & reg); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & BIT28); /* busy mask */ + 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 < 4) { + swconfig->cpuport = 5; + printf("Invalid cpu port config, using default port5\n"); + } + + mv88e61xx_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 + */ + mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 5, + MV88E61XX_RGMII_TIMECTRL_REG, 0x18); + mv88e61xx_wr_phy(name, MV88E61XX_PRT_OFST + 4, + MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + } + + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + if (prt != swconfig->cpuport) { + /* Write Copper Specific control reg1 (0x14) for- + * Enable Phy power up + * Energy Detect on (sense&Xmit NLP Periodically + * reset other settings default + */ + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_DATA, 0x3360); + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, + (0x9410 | (prt << 5))); + + if (mv88361xx_busychk(name)) + return -1; + + /* Write PHY ctrl reg (0x0) to apply + * Phy reset (BIT15=low) + * reset other default values + */ + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_DATA, 0x1140); + mv88e61xx_wr_phy(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, + (0x9400 | (prt << 5))); + + if (mv88361xx_busychk(name)) + return -1; + } + + /*Program port state */ + mv88e61xx_rd_phy(name, MV88E61XX_PRT_OFST + prt, + MV88E61XX_PRT_CTRL_REG, ®); + mv88e61xx_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; +} diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h new file mode 100644 index 0000000..e85341b --- /dev/null +++ b/drivers/net/phy/mv88e61xx.h @@ -0,0 +1,143 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _MV88E61XX_H +#define _MV88E61XX_H + +#include <miiphy.h> + +#define PORT(_x) (1 << _x) +#define MV88E61XX_CPU_PORT 0x5 +#define MV88E61XX_MAX_PORTS_NUM 0x6 + +#define MV88E61XX_PHY_TIMEOUT 100000 + +#define MV88E61XX_PRT_STS_REG 0x1 +#define MV88E61XX_PRT_CTRL_REG 0x4 +#define MV88E61XX_PRT_VMAP_REG 0x6 +#define MV88E61XX_PRT_VID_REG 0x7 + +#define MV88E61XX_PRT_OFST 0x10 +#define MV88E61XX_PHY_CMD 0x18 +#define MV88E61XX_PHY_DATA 0x19 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A +#define MV88E61XX_GLB2REG_DEVADR 0x1C + +/* constants for switch configuration */ +enum mv88e61xx_cfg_vlan { + MV88E61XX_VLANCFG_DEFAULT, + MV88E61XX_VLANCFG_ROUTER +}; + +enum mv88e61xx_cfg_rgmiid { + MV88E61XX_RGMII_DELAY_DIS, + MV88E61XX_RGMII_DELAY_EN +}; + +enum mv88e61xx_cfg_prtstt { + MV88E61XX_PORTSTT_DISABLED, + MV88E61XX_PORTSTT_BLOCKING, + MV88E61XX_PORTSTT_LEARNING, + MV88E61XX_PORTSTT_FORWARDING +}; + +/* switch configuration structure */ +struct mv88e61xx_config { + char *name; + enum mv88e61xx_cfg_vlan vlancfg; + enum mv88e61xx_cfg_rgmiid rgmii_delay; + enum mv88e61xx_cfg_prtstt portstate; + u32 ports_enabled; + u8 cpuport; +}; + +/* Chip Address mode + * The Switch support two modes of operation + * 1. single chip mode and + * 2. Multi-chip mode + * Refer section 9.2 &9.3 in chip datasheet-02 for more details + * + * By default single chip mode is configured + * multichip mode operation can be configured in board header + */ +#ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +#define mv88e61xx_wr_phy miiphy_write +#define mv88e61xx_rd_phy miiphy_read +#else + +static int mv88e61xx_busychk_multic(u32 devaddr) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + + /* Poll till SMIBusy bit is clear */ + do { + miiphy_read(name, devaddr, 0x0, ®); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & BIT15); + return 0; +} + +static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + printf("Error..could not read PHY dev address\n"); + return; + } + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write data to Switch indirect data register */ + miiphy_write(name, mii_dev_addr, 0x1, data); + /* Write command to Switch indirect command register (write) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15); +} + +static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + printf("Error..could not read PHY dev address\n"); + return; + } + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write command to Switch indirect command register (read) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15); + mv88e61xx_busychk_multic(mii_dev_addr); + /* Read data from Switch indirect data register */ + miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data); +} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ + +#endif /* _MV88E61XX_H */ diff --git a/include/netdev.h b/include/netdev.h index 2794ddd..e6832de 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -59,6 +59,7 @@ int mpc512x_fec_initialize(bd_t *bis); int mpc5xxx_fec_initialize(bd_t *bis); int mpc8220_fec_initialize(bd_t *bis); int mpc82xx_scc_enet_initialize(bd_t *bis); +int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig); int natsemi_initialize(bd_t *bis); int npe_initialize(bd_t *bis); int ns8382x_initialize(bd_t *bis);

Hi Prafulla,
So close...
Prafulla Wadaskar wrote: <snip>
+/* Chip Address mode
- The Switch support two modes of operation
- single chip mode and
- Multi-chip mode
- Refer section 9.2 &9.3 in chip datasheet-02 for more details
- By default single chip mode is configured
- multichip mode operation can be configured in board header
- */
+#ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +#define mv88e61xx_wr_phy miiphy_write +#define mv88e61xx_rd_phy miiphy_read +#else
+static int mv88e61xx_busychk_multic(u32 devaddr) +{
- u32 reg = 0;
- u32 timeout = MV88E61XX_PHY_TIMEOUT;
- /* Poll till SMIBusy bit is clear */
- do {
miiphy_read(name, devaddr, 0x0, ®);
if (timeout-- == 0) {
printf("SMI busy timeout\n");
return -1;
}
- } while (reg & BIT15);
- return 0;
+}
+static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +{
- u16 reg;
- u32 mii_dev_addr;
- /* command to read PHY dev address */
- if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
- }
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Write data to Switch indirect data register */
- miiphy_write(name, mii_dev_addr, 0x1, data);
- /* Write command to Switch indirect command register (write) */
- miiphy_write(name, mii_dev_addr, 0x0,
reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
+}
+static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +{
- u16 reg;
- u32 mii_dev_addr;
- /* command to read PHY dev address */
- if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
- }
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Write command to Switch indirect command register (read) */
- miiphy_write(name, mii_dev_addr, 0x0,
reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Read data from Switch indirect data register */
- miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data);
+} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
I apologize for not being more clear here. Please don't put non-trivial functions in header files. What I was hoping you'd do was put something like this in the header file:
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);
/* Helpful comment here */ #ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE #define WRITE_PHY miiphy_write #define READ_PHY miiphy_read #else #define WRITE_PHY mv88e61xx_wr_phy #define READ_PHY mv88e61xx_rd_phy #endif
and then use these macros throughout. You'll agree that it's much easier to follow.
+#endif /* _MV88E61XX_H */ diff --git a/include/netdev.h b/include/netdev.h index 2794ddd..e6832de 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -59,6 +59,7 @@ int mpc512x_fec_initialize(bd_t *bis); int mpc5xxx_fec_initialize(bd_t *bis); int mpc8220_fec_initialize(bd_t *bis); int mpc82xx_scc_enet_initialize(bd_t *bis); +int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig); int natsemi_initialize(bd_t *bis); int npe_initialize(bd_t *bis); int ns8382x_initialize(bd_t *bis);
Apart from that, it looks really good. Thanks for all the hard work.
regards, Ben

Hi all,
just an interesting side note:
Statistics from v1 patch:
board/Marvell/common/mv88e1116.c | 72 +++++++ board/Marvell/common/mv88e60xx.c | 409 +++++++++++++++++++++++++++++++++++++ board/Marvell/common/mv88e61xx.c | 414 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 895 insertions(+), 0 deletions(-) create mode 100644 board/Marvell/common/mv88e1116.c create mode 100644 board/Marvell/common/mv88e60xx.c create mode 100644 board/Marvell/common/mv88e61xx.c
Statistics from v6 patch:
drivers/net/phy/Makefile | 1 + drivers/net/phy/mv88e61xx.c | 244 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mv88e61xx.h | 143 +++++++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 389 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/mv88e61xx.c create mode 100644 drivers/net/phy/mv88e61xx.h
Now even without looking at the details, if this isn't a *pretty* good example of what showing code and a review process can do, then I really don't know.
Thanks all for the good work! Detlev

-----Original Message----- From: Detlev Zundel [mailto:dzu@denx.de] Sent: Thursday, April 23, 2009 6:00 PM To: Ben Warren Cc: Prafulla Wadaskar; u-boot@lists.denx.de; Ashish Karkare; Prabhanjan Sarnaik; Ronen Shitrit Subject: Re: [U-Boot] [PATCH v6] Marvell MV88E61XX Switch Driver support
Hi all,
just an interesting side note:
Statistics from v1 patch:
board/Marvell/common/mv88e1116.c | 72 +++++++ board/Marvell/common/mv88e60xx.c | 409 +++++++++++++++++++++++++++++++++++++ board/Marvell/common/mv88e61xx.c | 414 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 895 insertions(+), 0 deletions(-) create mode 100644 board/Marvell/common/mv88e1116.c create mode 100644 board/Marvell/common/mv88e60xx.c create mode 100644 board/Marvell/common/mv88e61xx.c
Statistics from v6 patch:
drivers/net/phy/Makefile | 1 + drivers/net/phy/mv88e61xx.c | 244 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mv88e61xx.h | 143 +++++++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 389 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/mv88e61xx.c create mode 100644 drivers/net/phy/mv88e61xx.h
Now even without looking at the details, if this isn't a *pretty* good example of what showing code and a review process can do, then I really don't know.
I really appreciate a quality review feedback and great usability of existing code to make this considerable difference.
Even you will find considerable reduced code size for my other upcoming patches. Thanks to everyone to make u-boot more structured...
Regards.. Prafulla . .

Hi Peter,
Have you found a solution to your problem? I am running into the same situation. Can you shared some of your debug experience on solving this problem? Thanks!
-- View this message in context: http://u-boot.10912.n7.nabble.com/U-Boot-PATCH-v4-Marvell-MV88E61XX-Switch-D... Sent from the U-Boot mailing list archive at Nabble.com.

-----Original Message----- From: Ben Warren [mailto:biggerbadderben@gmail.com] Sent: Thursday, April 23, 2009 11:00 AM To: Prafulla Wadaskar Cc: u-boot@lists.denx.de; Ashish Karkare; Prabhanjan Sarnaik; Ronen Shitrit Subject: Re: [U-Boot] [PATCH v6] Marvell MV88E61XX Switch Driver support
Hi Prafulla,
So close...
+static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32
reg_ofs, u16 * data)
+{
- u16 reg;
- u32 mii_dev_addr;
- /* command to read PHY dev address */
- if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
- }
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Write command to Switch indirect command register (read) */
- miiphy_write(name, mii_dev_addr, 0x0,
reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
- mv88e61xx_busychk_multic(mii_dev_addr);
- /* Read data from Switch indirect data register */
- miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data);
+} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
I apologize for not being more clear here.
That's okay Ben, I am sorry I could not digest your suggestions properly I will re-release with patch with this change
non-trivial functions in header files. What I was hoping you'd do was put something like this in the header file:
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);
These are static functions to be used internally by mv88e61xx driver I was trying to reduce code size by two line putting them in c file And associated macros. But any way putting them in header makes it more redable, I will do it.
/* Helpful comment here */ #ifndef CONFIG_MV88E61XX_MULTICHIP_ADRMODE #define WRITE_PHY miiphy_write #define READ_PHY miiphy_read #else #define WRITE_PHY mv88e61xx_wr_phy #define READ_PHY mv88e61xx_rd_phy #endif
and then use these macros throughout. You'll agree that it's much easier to follow.
Yes I agree, even I can further reduce some ammount of bytes from my patch :-)
Regards.. Prafulla . .
participants (5)
-
Ben Warren
-
Detlev Zundel
-
Jean-Christophe PLAGNIOL-VILLARD
-
Kenny
-
Prafulla Wadaskar