All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Warren <biggerbadderben@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v5] Marvell MV88E61XX Switch Driver support
Date: Sun, 19 Apr 2009 20:48:34 -0700	[thread overview]
Message-ID: <49EBF092.9060102@gmail.com> (raw)
In-Reply-To: <73173D32E9439E4ABB5151606C3E19E201C6B9BA3D@SC-VEXCH1.marvell.com>

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:-
> 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)
> +{
>   
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, &reg);
> +		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);
> +		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);
> +	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);
> +		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);
> +			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, &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);
> +	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);
> +			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);
> +			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);
> +	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, &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

  reply	other threads:[~2009-04-20  3:48 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-04-15 13:24 [U-Boot] [PATCH v4] Marvell MV88E61XX Switch Driver support Prafulla Wadaskar
2009-04-17  7:36 ` Jean-Christophe PLAGNIOL-VILLARD
2009-04-18  6:44   ` Prafulla Wadaskar
2009-04-19  6:11     ` [U-Boot] [PATCH v5] " Prafulla Wadaskar
2009-04-20  3:48       ` Ben Warren [this message]
2009-04-22  7:11         ` Prafulla Wadaskar
2009-04-22 12:23           ` [U-Boot] [PATCH v6] " Prafulla Wadaskar
2009-04-23  5:30             ` Ben Warren
2009-04-23 12:29               ` Detlev Zundel
2009-04-23 13:54                 ` Prafulla Wadaskar
2013-01-25  6:44                 ` Kenny
2009-04-23 14:04               ` Prafulla Wadaskar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=49EBF092.9060102@gmail.com \
    --to=biggerbadderben@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.