[OpenWrt-Devel] [PATCH] Update MT7530 switch driver.

xfguo at credosemi.com xfguo at credosemi.com
Sat Jun 21 11:10:39 EDT 2014


From: Xiongfei Guo <xfguo at credosemi.com>

- Support set VLAN ID of each vlan.
- Support untag feature.
- Replace register address with C MACRO.
- There are 8 ports for MT7530 actually.

Signed-off-by: Xiongfei Guo <xfguo at credosemi.com>
---
 ...8-NET-MIPS-add-ralink-SoC-ethernet-driver.patch | 268 ++++++++++++++-------
 1 file changed, 186 insertions(+), 82 deletions(-)

diff --git a/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch b/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch
index 75f78bf..c8ec17c 100644
--- a/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch
+++ b/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch
@@ -2814,7 +2814,7 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +#endif
 --- /dev/null
 +++ b/drivers/net/ethernet/ralink/mt7530.c
-@@ -0,0 +1,467 @@
+@@ -0,0 +1,571 @@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
@@ -2851,25 +2851,45 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +#include "mt7530.h"
 +
 +#define MT7530_CPU_PORT		6
-+#define MT7530_NUM_PORTS	7
++#define MT7530_NUM_PORTS	8
 +#define MT7530_NUM_VLANS	16
-+#define MT7530_NUM_VIDS		16
++#define MT7530_MAX_VID		4095
++#define MT7530_MIN_VID		0
 +
-+#define REG_ESW_VLAN_VTCR	0x90
-+#define REG_ESW_VLAN_VAWD1	0x94
-+#define REG_ESW_VLAN_VAWD2	0x98
++/* registers */
++#define REG_ESW_VLAN_VTCR		0x90
++#define REG_ESW_VLAN_VAWD1		0x94
++#define REG_ESW_VLAN_VAWD2		0x98
++#define REG_ESW_VLAN_VTIM(x)	(0x100 + 4 * ((x) / 2))
++
++#define REG_ESW_VLAN_VAWD1_IVL_MAC	BIT(30)
++#define REG_ESW_VLAN_VAWD1_VTAG_EN	BIT(28)
++#define REG_ESW_VLAN_VAWD1_VALID	BIT(0)
++
++/* vlan egress mode */
++enum {
++	ETAG_CTRL_UNTAG	= 0,
++	ETAG_CTRL_TAG	= 2,
++	ETAG_CTRL_SWAP	= 1,
++	ETAG_CTRL_STACK	= 3,
++};
 +
++#define REG_ESW_PORT_PCR(x)	(0x2004 | ((x) << 8))
++#define REG_ESW_PORT_PVC(x)	(0x2010 | ((x) << 8))
++#define REG_ESW_PORT_PPBV1(x)	(0x2014 | ((x) << 8))
 +enum {
 +	/* Global attributes. */
 +	MT7530_ATTR_ENABLE_VLAN,
 +};
 +
-+struct mt7530_port {
++struct mt7530_port_entry {
 +	u16	pvid;
 +};
 +
-+struct mt7530_vlan {
-+	u8	ports;
++struct mt7530_vlan_entry {
++	u16	vid;
++	u8	member;
++	u8	etags;
 +};
 +
 +struct mt7530_priv {
@@ -2878,23 +2898,29 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +	struct switch_dev	swdev;
 +
 +	bool			global_vlan_enable;
-+	struct mt7530_vlan	vlans[MT7530_NUM_VLANS];
-+	struct mt7530_port	ports[MT7530_NUM_PORTS];
++	struct mt7530_vlan_entry	vlan_entries[MT7530_NUM_VLANS];
++	struct mt7530_port_entry	port_entries[MT7530_NUM_PORTS];
 +};
 +
 +struct mt7530_mapping {
 +	char	*name;
-+	u8	pvids[6];
-+	u8	vlans[8];
++	u16	pvids[MT7530_NUM_PORTS];
++	u8	members[MT7530_NUM_VLANS];
++	u8	etags[MT7530_NUM_VLANS];
++	u16	vids[MT7530_NUM_VLANS];
 +} mt7530_defaults[] = {
 +	{
 +		.name = "llllw",
-+		.pvids = { 1, 1, 1, 1, 2, 1 },
-+		.vlans = { 0, 0x6f, 0x50 },
++		.pvids = { 1, 1, 1, 1, 2, 1, 1 },
++		.members = { 0x6f, 0x50 },
++		.etags = { 0x40, 0x40 },
++		.vids = { 1, 2 },
 +	}, {
 +		.name = "wllll",
-+		.pvids = { 2, 1, 1, 1, 1, 1 },
-+		.vlans = { 0, 0x7e, 0x41 },
++		.pvids = { 2, 1, 1, 1, 1, 1, 1 },
++		.members = { 0x7e, 0x41 },
++		.etags = { 0x40, 0x40 },
++		.vids = { 1, 2 },
 +	},
 +};
 +
@@ -2921,10 +2947,14 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +
 +	mt7530->global_vlan_enable = 1;
 +
-+	for (i = 0; i < 6; i++)
-+		mt7530->ports[i].pvid = map->pvids[i];
-+	for (i = 0; i < 8; i++)
-+		mt7530->vlans[i].ports = map->vlans[i];
++	for (i = 0; i < MT7530_NUM_PORTS; i++)
++		mt7530->port_entries[i].pvid = map->pvids[i];
++
++	for (i = 0; i < MT7530_NUM_VLANS; i++) {
++		mt7530->vlan_entries[i].member = map->members[i];
++		mt7530->vlan_entries[i].etags = map->etags[i];
++		mt7530->vlan_entries[i].vid = map->vids[i];
++	}
 +}
 +
 +static int
@@ -2932,8 +2962,8 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +{
 +	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
 +
-+	memset(priv->ports, 0, sizeof(priv->ports));
-+	memset(priv->vlans, 0, sizeof(priv->vlans));
++	memset(priv->port_entries, 0, sizeof(priv->port_entries));
++	memset(priv->vlan_entries, 0, sizeof(priv->vlan_entries));
 +
 +	return 0;
 +}
@@ -2965,6 +2995,7 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +static u32
 +mt7530_r32(struct mt7530_priv *priv, u32 reg)
 +{
++	u32 val;
 +	if (priv->bus) {
 +		u16 high, low;
 +
@@ -2975,7 +3006,10 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +		return (high << 16) | (low & 0xffff);
 +	}
 +
-+        return ioread32(priv->base + reg);
++	val = ioread32(priv->base + reg);
++	pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
++
++	return val;
 +}
 +
 +static void
@@ -2988,6 +3022,7 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +		return;
 +	}
 +
++	pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
 +	iowrite32(val, priv->base + reg);
 +}
 +
@@ -3018,8 +3053,8 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +	if (port >= MT7530_NUM_PORTS)
 +		return -EINVAL;
 +
-+	*val = mt7530_r32(priv, 0x2014 + (0x100 * port));
-+	*val &= 0xff;
++	*val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(port));
++	*val &= 0xfff;
 +
 +	return 0;
 +}
@@ -3030,9 +3065,12 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
 +
 +	if (port >= MT7530_NUM_PORTS)
-+		return -1;
++		return -EINVAL;
++
++	if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
++		return -EINVAL;
 +
-+	priv->ports[port].pvid = pvid;
++	priv->port_entries[port].pvid = pvid;
 +
 +	return 0;
 +}
@@ -3042,26 +3080,38 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +{
 +	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
 +	u32 member;
++	u32 etags;
 +	int i;
 +
 +	val->len = 0;
 +
-+	if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VIDS)
++	if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
 +		return -EINVAL;
 +
 +	mt7530_vtcr(priv, 0, val->port_vlan);
++
 +	member = mt7530_r32(priv, REG_ESW_VLAN_VAWD1);
 +	member >>= 16;
 +	member &= 0xff;
 +
++	etags = mt7530_r32(priv, REG_ESW_VLAN_VAWD2);
++
 +	for (i = 0; i < MT7530_NUM_PORTS; i++) {
 +		struct switch_port *p;
++		int etag;
++
 +		if (!(member & BIT(i)))
 +			continue;
 +
 +		p = &val->value.ports[val->len++];
 +		p->id = i;
-+		p->flags = 0;
++
++		etag = (etags >> (i * 2)) & 0x3;
++
++		if (etag == ETAG_CTRL_TAG)
++			p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
++		else if (etag != ETAG_CTRL_UNTAG)
++			printk("vlan egress tag control neither untag nor tag.\n");
 +	}
 +
 +	return 0;
@@ -3071,10 +3121,11 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
 +{
 +	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
-+	int ports = 0;
++	u8 member = 0;
++	u8 etags = 0;
 +	int i;
 +
-+	if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VIDS ||
++	if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
 +			val->len > MT7530_NUM_PORTS)
 +		return -EINVAL;
 +
@@ -3084,90 +3135,135 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +		if (p->id >= MT7530_NUM_PORTS)
 +			return -EINVAL;
 +
-+		ports |= BIT(p->id);
++		member |= BIT(p->id);
++
++		if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
++			etags |= BIT(p->id);
 +	}
-+	priv->vlans[val->port_vlan].ports = ports;
++	priv->vlan_entries[val->port_vlan].member = member;
++	priv->vlan_entries[val->port_vlan].etags = etags;
 +
 +	return 0;
 +}
 +
 +static int
++mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
++		struct switch_val *val)
++{
++	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
++	int vlan;
++	u16 vid;
++
++	vlan = val->port_vlan;
++	vid = (u16)val->value.i;
++
++	if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
++	    return -EINVAL;
++
++	if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
++		return -EINVAL;
++
++	priv->vlan_entries[vlan].vid = vid;
++	return 0;
++}
++
++static int
++mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
++		struct switch_val *val)
++{
++	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
++	u32 vid;
++	int vlan;
++
++	vlan = val->port_vlan;
++
++	vid = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
++	if (vlan & 1)
++		vid = vid >> 12;
++	vid &= 0xfff;
++
++	val->value.i = vid;
++	return 0;
++}
++
++static int
 +mt7530_apply_config(struct switch_dev *dev)
 +{
 +	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
-+	int i;
++	int i, j;
 +
 +	if (!priv->global_vlan_enable) {
-+		mt7530_w32(priv, 0x2004, 0xff000);
-+		mt7530_w32(priv, 0x2104, 0xff000);
-+		mt7530_w32(priv, 0x2204, 0xff000);
-+		mt7530_w32(priv, 0x2304, 0xff000);
-+		mt7530_w32(priv, 0x2404, 0xff000);
-+		mt7530_w32(priv, 0x2504, 0xff000);
-+		mt7530_w32(priv, 0x2604, 0xff000);
-+		mt7530_w32(priv, 0x2010, 0x810000c);
-+		mt7530_w32(priv, 0x2110, 0x810000c);
-+		mt7530_w32(priv, 0x2210, 0x810000c);
-+		mt7530_w32(priv, 0x2310, 0x810000c);
-+		mt7530_w32(priv, 0x2410, 0x810000c);
-+		mt7530_w32(priv, 0x2510, 0x810000c);
-+		mt7530_w32(priv, 0x2610, 0x810000c);
-+		return 0;
++		for (i = 0; i < MT7530_NUM_PORTS; i++)
++			mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0000);
++
++		for (i = 0; i < MT7530_NUM_PORTS; i++)
++			mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x8100000c);
++
++	  	return 0;
 +	}
 +
-+	// LAN/WAN ports as security mode
-+	mt7530_w32(priv, 0x2004, 0xff0003);
-+	mt7530_w32(priv, 0x2104, 0xff0003);
-+	mt7530_w32(priv, 0x2204, 0xff0003);
-+	mt7530_w32(priv, 0x2304, 0xff0003);
-+	mt7530_w32(priv, 0x2404, 0xff0003);
-+	mt7530_w32(priv, 0x2504, 0xff0003);
-+	// LAN/WAN ports as transparent port
-+	mt7530_w32(priv, 0x2010, 0x810000c0);
-+	mt7530_w32(priv, 0x2110, 0x810000c0);
-+	mt7530_w32(priv, 0x2210, 0x810000c0);
-+	mt7530_w32(priv, 0x2310, 0x810000c0);
-+	mt7530_w32(priv, 0x2410, 0x810000c0);
-+	mt7530_w32(priv, 0x2510, 0x810000c0);
-+
-+	// set CPU/P7 port as user port
-+	mt7530_w32(priv, 0x2610, 0x81000000);
-+	mt7530_w32(priv, 0x2710, 0x81000000);
-+
-+	mt7530_w32(priv, 0x2604, 0x20ff0003);
-+	mt7530_w32(priv, 0x2704, 0x20ff0003);
-+	mt7530_w32(priv, 0x2610, 0x81000000);
++	/* set all ports as security mode */
++	for (i = 0; i < MT7530_NUM_PORTS; i++)
++		mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0003);
++
++	/* set all ports as user port */
++	for (i = 0; i < MT7530_NUM_PORTS; i++)
++		mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x81000000);
 +
 +	for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+		u8 ports = priv->vlans[i].ports;
-+		u32 val = mt7530_r32(priv, 0x100 + 4 * (i / 2));
++		u16 vid = priv->vlan_entries[i].vid;
++		u8 member = priv->vlan_entries[i].member;
++		u8 etags = priv->vlan_entries[i].etags;
++		u32 val;
 +
++		/* vid of vlan */
++		val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(i));
 +		if (i % 2 == 0) {
 +			val &= 0xfff000;
-+			val |= i;
++			val |= vid;
 +		} else {
 +			val &= 0xfff;
-+			val |= (i << 12);
++			val |= (vid << 12);
 +		}
-+		mt7530_w32(priv, 0x100 + 4 * (i / 2), val);
++		mt7530_w32(priv, REG_ESW_VLAN_VTIM(i), val);
 +
-+		if (ports)
-+			mt7530_w32(priv, REG_ESW_VLAN_VAWD1, BIT(30) | (ports << 16) | BIT(0));
++		/* vlan port membership */
++		if (member)
++			mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
++				REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) |
++				REG_ESW_VLAN_VAWD1_VALID);
 +		else
 +			mt7530_w32(priv, REG_ESW_VLAN_VAWD1, 0);
 +
++		/* egress mode */
++		val = 0;
++		for (j = 0; j < MT7530_NUM_PORTS; j++) {
++			if (etags & BIT(j))
++				val |= ETAG_CTRL_TAG << (j * 2);
++			else
++				val |= ETAG_CTRL_UNTAG << (j * 2);
++		}
++		mt7530_w32(priv, REG_ESW_VLAN_VAWD2, val);
++
++		/* write to vlan table */
 +		mt7530_vtcr(priv, 1, i);
 +	}
 +
-+	for (i = 0; i < MT7530_NUM_PORTS; i++)
-+		mt7530_w32(priv, 0x2014 + (0x100 * i), 0x10000 | priv->ports[i].pvid);
++	/* Port Default PVID */
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		u32 val;
++		val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(i));
++		val &= ~0xfff;
++		val |= priv->port_entries[i].pvid;
++		mt7530_w32(priv, REG_ESW_PORT_PPBV1(i), val);
++	}
 +
 +	return 0;
 +}
 +
 +static int
 +mt7530_get_port_link(struct switch_dev *dev,  int port,
-+			 struct switch_port_link *link)
++			struct switch_port_link *link)
 +{
 +	struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
 +	u32 speed, pmsr;
@@ -3216,6 +3312,14 @@ Signed-off-by: John Crispin <blogic at openwrt.org>
 +};
 +
 +static const struct switch_attr mt7530_vlan[] = {
++	{
++		.type = SWITCH_TYPE_INT,
++		.name = "vid",
++		.description = "VLAN ID (0-4094)",
++		.set = mt7530_set_vid,
++		.get = mt7530_get_vid,
++		.max = 4094,
++	},
 +};
 +
 +static const struct switch_dev_ops mt7530_ops = {
-- 
1.9.1
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list