<div dir="ltr">hi,<div><br></div><div>I'm test it on Mercury MW305R with a modified dts file for RT-N14U. Maybe I can give a dts patch for this board later.</div><div><br></div><div>Actually, MT7530 is the ethernet switch inside the MTK MT7620A/N. So you can try it with any MT7620 based board.</div>
<div><br></div><div>Xiongfei Guo</div><div>Credo Semi.</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Jun 24, 2014 at 8:54 PM, John Crispin <span dir="ltr"><<a href="mailto:john@phrozen.org" target="_blank">john@phrozen.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<div class=""><br>
On 21/06/2014 17:10, <a href="mailto:xfguo@credosemi.com">xfguo@credosemi.com</a> wrote:<br>
> From: Xiongfei Guo <<a href="mailto:xfguo@credosemi.com">xfguo@credosemi.com</a>><br>
><br>
> - Support set VLAN ID of each vlan. - Support untag feature. -<br>
> Replace register address with C MACRO. - There are 8 ports for<br>
> MT7530 actually.<br>
><br>
> Signed-off-by: Xiongfei Guo <<a href="mailto:xfguo@credosemi.com">xfguo@credosemi.com</a>><br>
<br>
<br>
</div>on which boards did you test this ? i want to give it a quick try on<br>
the eval kit today before merging the patch. i have so far not seen<br>
any boards in the wild with this switch<br>
<span class="HOEnZb"><font color="#888888"><br>
        John<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
> --- ...8-NET-MIPS-add-ralink-SoC-ethernet-driver.patch | 268<br>
> ++++++++++++++------- 1 file changed, 186 insertions(+), 82<br>
> deletions(-)<br>
><br>
> diff --git<br>
> a/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch<br>
> b/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch<br>
><br>
><br>
index 75f78bf..c8ec17c 100644<br>
> ---<br>
> a/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch<br>
><br>
><br>
+++<br>
b/target/linux/ramips/patches-3.10/0118-NET-MIPS-add-ralink-SoC-ethernet-driver.patch<br>
> @@ -2814,7 +2814,7 @@ Signed-off-by: John Crispin<br>
> <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +#endif --- /dev/null +++<br>
> b/drivers/net/ethernet/ralink/mt7530.c -@@ -0,0 +1,467 @@ +@@ -0,0<br>
> +1,571 @@ +/* + * This program is free software; you can<br>
> redistribute it and/or + * modify it under the terms of the GNU<br>
> General Public License @@ -2851,25 +2851,45 @@ Signed-off-by: John<br>
> Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +#include "mt7530.h" + +#define<br>
> MT7530_CPU_PORT               6 -+#define MT7530_NUM_PORTS    7 ++#define<br>
> MT7530_NUM_PORTS      8 +#define MT7530_NUM_VLANS     16 -+#define<br>
> MT7530_NUM_VIDS               16 ++#define MT7530_MAX_VID             4095 ++#define<br>
> MT7530_MIN_VID                0 + -+#define REG_ESW_VLAN_VTCR 0x90 -+#define<br>
> REG_ESW_VLAN_VAWD1    0x94 -+#define REG_ESW_VLAN_VAWD2       0x98 ++/*<br>
> registers */ ++#define REG_ESW_VLAN_VTCR              0x90 ++#define<br>
> REG_ESW_VLAN_VAWD1            0x94 ++#define REG_ESW_VLAN_VAWD2               0x98<br>
> ++#define REG_ESW_VLAN_VTIM(x)        (0x100 + 4 * ((x) / 2)) ++ ++#define<br>
> REG_ESW_VLAN_VAWD1_IVL_MAC    BIT(30) ++#define<br>
> REG_ESW_VLAN_VAWD1_VTAG_EN    BIT(28) ++#define<br>
> REG_ESW_VLAN_VAWD1_VALID      BIT(0) ++ ++/* vlan egress mode */ ++enum<br>
> { ++  ETAG_CTRL_UNTAG = 0, ++ ETAG_CTRL_TAG   = 2, ++ ETAG_CTRL_SWAP  =<br>
> 1, ++ ETAG_CTRL_STACK = 3, ++}; + ++#define REG_ESW_PORT_PCR(x)<br>
> (0x2004 | ((x) << 8)) ++#define REG_ESW_PORT_PVC(x)   (0x2010 | ((x)<br>
> << 8)) ++#define REG_ESW_PORT_PPBV1(x)        (0x2014 | ((x) << 8)) +enum<br>
> { +   /* Global attributes. */ +      MT7530_ATTR_ENABLE_VLAN, +}; +<br>
> -+struct mt7530_port { ++struct mt7530_port_entry { + u16     pvid;<br>
> +}; + -+struct mt7530_vlan { -+       u8      ports; ++struct<br>
> mt7530_vlan_entry { ++        u16     vid; ++ u8      member; ++      u8      etags; +}; +<br>
> +struct mt7530_priv { @@ -2878,23 +2898,29 @@ Signed-off-by: John<br>
> Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +        struct switch_dev       swdev; + +      bool<br>
> global_vlan_enable; -+        struct mt7530_vlan      vlans[MT7530_NUM_VLANS];<br>
> -+    struct mt7530_port      ports[MT7530_NUM_PORTS]; ++     struct<br>
> mt7530_vlan_entry     vlan_entries[MT7530_NUM_VLANS]; ++      struct<br>
> mt7530_port_entry     port_entries[MT7530_NUM_PORTS]; +}; + +struct<br>
> mt7530_mapping { +    char    *name; -+       u8      pvids[6]; -+    u8      vlans[8]; ++<br>
> u16   pvids[MT7530_NUM_PORTS]; ++     u8      members[MT7530_NUM_VLANS]; ++   u8<br>
> etags[MT7530_NUM_VLANS]; ++   u16     vids[MT7530_NUM_VLANS]; +}<br>
> mt7530_defaults[] = { +       { +             .name = "llllw", -+             .pvids = { 1, 1,<br>
> 1, 1, 2, 1 }, -+              .vlans = { 0, 0x6f, 0x50 }, ++          .pvids = { 1, 1,<br>
> 1, 1, 2, 1, 1 }, ++           .members = { 0x6f, 0x50 }, ++           .etags = {<br>
> 0x40, 0x40 }, ++              .vids = { 1, 2 }, +     }, { +          .name = "wllll", -+<br>
> .pvids = { 2, 1, 1, 1, 1, 1 }, -+             .vlans = { 0, 0x7e, 0x41 }, ++<br>
> .pvids = { 2, 1, 1, 1, 1, 1, 1 }, ++          .members = { 0x7e, 0x41 }, ++<br>
> .etags = { 0x40, 0x40 }, ++           .vids = { 1, 2 }, +     }, +}; + @@<br>
> -2921,10 +2947,14 @@ Signed-off-by: John Crispin<br>
> <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> + +      mt7530->global_vlan_enable = 1; + -+    for<br>
> (i = 0; i < 6; i++) -+                mt7530->ports[i].pvid = map->pvids[i]; -+<br>
> for (i = 0; i < 8; i++) -+            mt7530->vlans[i].ports =<br>
> map->vlans[i]; ++     for (i = 0; i < MT7530_NUM_PORTS; i++) ++<br>
> mt7530->port_entries[i].pvid = map->pvids[i]; ++ ++   for (i = 0; i <<br>
> MT7530_NUM_VLANS; i++) { ++           mt7530->vlan_entries[i].member =<br>
> map->members[i]; ++           mt7530->vlan_entries[i].etags =<br>
> map->etags[i]; ++             mt7530->vlan_entries[i].vid = map->vids[i]; ++<br>
> } +} + +static int @@ -2932,8 +2962,8 @@ Signed-off-by: John<br>
> Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +{ +     struct mt7530_priv *priv =<br>
> container_of(dev, struct mt7530_priv, swdev); + -+<br>
> memset(priv->ports, 0, sizeof(priv->ports)); -+       memset(priv->vlans,<br>
> 0, sizeof(priv->vlans)); ++   memset(priv->port_entries, 0,<br>
> sizeof(priv->port_entries)); ++       memset(priv->vlan_entries, 0,<br>
> sizeof(priv->vlan_entries)); + +      return 0; +} @@ -2965,6 +2995,7 @@<br>
> Signed-off-by: John Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +static u32<br>
> +mt7530_r32(struct mt7530_priv *priv, u32 reg) +{ ++  u32 val; +      if<br>
> (priv->bus) { +               u16 high, low; + @@ -2975,7 +3006,10 @@<br>
> Signed-off-by: John Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +            return (high <<<br>
> 16) | (low & 0xffff); +       } + -+        return ioread32(priv->base +<br>
> reg); ++      val = ioread32(priv->base + reg); ++    pr_debug("MT7530 MDIO<br>
> Read [%04x]=%08x\n", reg, val); ++ ++ return val; +} + +static<br>
> void @@ -2988,6 +3022,7 @@ Signed-off-by: John Crispin<br>
> <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +                return; +       } + ++  pr_debug("MT7530 MDIO<br>
> Write[%04x]=%08x\n", reg, val); +     iowrite32(val, priv->base +<br>
> reg); +} + @@ -3018,8 +3053,8 @@ Signed-off-by: John Crispin<br>
> <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +        if (port >= MT7530_NUM_PORTS) +         return<br>
> -EINVAL; + -+ *val = mt7530_r32(priv, 0x2014 + (0x100 * port)); -+<br>
> *val &= 0xff; ++      *val = mt7530_r32(priv,<br>
> REG_ESW_PORT_PPBV1(port)); ++ *val &= 0xfff; + +      return 0; +} @@<br>
> -3030,9 +3065,12 @@ Signed-off-by: John Crispin<br>
> <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +        struct mt7530_priv *priv = container_of(dev,<br>
> struct mt7530_priv, swdev); + +       if (port >= MT7530_NUM_PORTS) -+<br>
> return -1; ++         return -EINVAL; ++ ++   if (pvid < MT7530_MIN_VID ||<br>
> pvid > MT7530_MAX_VID) ++             return -EINVAL; + -+<br>
> priv->ports[port].pvid = pvid; ++     priv->port_entries[port].pvid =<br>
> pvid; + +     return 0; +} @@ -3042,26 +3080,38 @@ Signed-off-by: John<br>
> Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +{ +     struct mt7530_priv *priv =<br>
> container_of(dev, struct mt7530_priv, swdev); +       u32 member; ++  u32<br>
> etags; +      int i; + +      val->len = 0; + -+      if (val->port_vlan < 0 ||<br>
> val->port_vlan >= MT7530_NUM_VIDS) ++ if (val->port_vlan < 0 ||<br>
> val->port_vlan >= MT7530_NUM_VLANS) +         return -EINVAL; + +<br>
> mt7530_vtcr(priv, 0, val->port_vlan); ++ +    member =<br>
> mt7530_r32(priv, REG_ESW_VLAN_VAWD1); +       member >>= 16; +        member &=<br>
> 0xff; + ++    etags = mt7530_r32(priv, REG_ESW_VLAN_VAWD2); ++ +      for<br>
> (i = 0; i < MT7530_NUM_PORTS; i++) { +                struct switch_port *p; ++<br>
> int etag; ++ +                if (!(member & BIT(i))) +                       continue; + +           p =<br>
> &val->value.ports[val->len++]; +              p->id = i; -+           p->flags = 0; ++<br>
> ++            etag = (etags >> (i * 2)) & 0x3; ++ ++          if (etag ==<br>
> ETAG_CTRL_TAG) ++                     p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED); ++<br>
> else if (etag != ETAG_CTRL_UNTAG) ++                  printk("vlan egress tag<br>
> control neither untag nor tag.\n"); + } + +   return 0; @@ -3071,10<br>
> +3121,11 @@ Signed-off-by: John Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>><br>
> +mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val<br>
> *val) +{ +    struct mt7530_priv *priv = container_of(dev, struct<br>
> mt7530_priv, swdev); -+       int ports = 0; ++       u8 member = 0; ++       u8<br>
> etags = 0; +  int i; + -+     if (val->port_vlan < 0 || val->port_vlan<br>
> >= MT7530_NUM_VIDS || ++      if (val->port_vlan < 0 || val->port_vlan<br>
> >= MT7530_NUM_VLANS || +                      val->len > MT7530_NUM_PORTS) +          return<br>
> -EINVAL; + @@ -3084,90 +3135,135 @@ Signed-off-by: John Crispin<br>
> <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +                if (p->id >= MT7530_NUM_PORTS) +                        return<br>
> -EINVAL; + -+         ports |= BIT(p->id); ++         member |= BIT(p->id); ++ ++<br>
> if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) ++                       etags |=<br>
> BIT(p->id); + } -+    priv->vlans[val->port_vlan].ports = ports; ++<br>
> priv->vlan_entries[val->port_vlan].member = member; ++<br>
> priv->vlan_entries[val->port_vlan].etags = etags; + + return 0; +}<br>
> + +static int ++mt7530_set_vid(struct switch_dev *dev, const struct<br>
> switch_attr *attr, ++         struct switch_val *val) ++{ ++  struct<br>
> mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);<br>
> ++    int vlan; ++    u16 vid; ++ ++  vlan = val->port_vlan; ++       vid =<br>
> (u16)val->value.i; ++ ++      if (vlan < 0 || vlan >= MT7530_NUM_VLANS)<br>
> ++        return -EINVAL; ++ ++       if (vid < MT7530_MIN_VID || vid ><br>
> MT7530_MAX_VID) ++            return -EINVAL; ++ ++<br>
> priv->vlan_entries[vlan].vid = vid; ++        return 0; ++} ++ ++static<br>
> int ++mt7530_get_vid(struct switch_dev *dev, const struct<br>
> switch_attr *attr, ++         struct switch_val *val) ++{ ++  struct<br>
> mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);<br>
> ++    u32 vid; ++     int vlan; ++ ++ vlan = val->port_vlan; ++ ++    vid =<br>
> mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan)); ++ if (vlan & 1) ++                vid<br>
> = vid >> 12; ++       vid &= 0xfff; ++ ++     val->value.i = vid; ++  return<br>
> 0; ++} ++ ++static int +mt7530_apply_config(struct switch_dev<br>
> *dev) +{ +    struct mt7530_priv *priv = container_of(dev, struct<br>
> mt7530_priv, swdev); -+       int i; ++       int i, j; + +   if<br>
> (!priv->global_vlan_enable) { -+              mt7530_w32(priv, 0x2004,<br>
> 0xff000); -+          mt7530_w32(priv, 0x2104, 0xff000); -+<br>
> mt7530_w32(priv, 0x2204, 0xff000); -+         mt7530_w32(priv, 0x2304,<br>
> 0xff000); -+          mt7530_w32(priv, 0x2404, 0xff000); -+<br>
> mt7530_w32(priv, 0x2504, 0xff000); -+         mt7530_w32(priv, 0x2604,<br>
> 0xff000); -+          mt7530_w32(priv, 0x2010, 0x810000c); -+<br>
> mt7530_w32(priv, 0x2110, 0x810000c); -+               mt7530_w32(priv, 0x2210,<br>
> 0x810000c); -+                mt7530_w32(priv, 0x2310, 0x810000c); -+<br>
> mt7530_w32(priv, 0x2410, 0x810000c); -+               mt7530_w32(priv, 0x2510,<br>
> 0x810000c); -+                mt7530_w32(priv, 0x2610, 0x810000c); -+         return 0;<br>
> ++            for (i = 0; i < MT7530_NUM_PORTS; i++) ++                       mt7530_w32(priv,<br>
> REG_ESW_PORT_PCR(i), 0x00ff0000); ++ ++               for (i = 0; i <<br>
> MT7530_NUM_PORTS; i++) ++                     mt7530_w32(priv, REG_ESW_PORT_PVC(i),<br>
> 0x8100000c); ++ ++            return 0; +     } + -+  // LAN/WAN ports as<br>
> security mode -+      mt7530_w32(priv, 0x2004, 0xff0003); -+<br>
> mt7530_w32(priv, 0x2104, 0xff0003); -+        mt7530_w32(priv, 0x2204,<br>
> 0xff0003); -+ mt7530_w32(priv, 0x2304, 0xff0003); -+<br>
> mt7530_w32(priv, 0x2404, 0xff0003); -+        mt7530_w32(priv, 0x2504,<br>
> 0xff0003); -+ // LAN/WAN ports as transparent port -+<br>
> mt7530_w32(priv, 0x2010, 0x810000c0); -+      mt7530_w32(priv, 0x2110,<br>
> 0x810000c0); -+       mt7530_w32(priv, 0x2210, 0x810000c0); -+<br>
> mt7530_w32(priv, 0x2310, 0x810000c0); -+      mt7530_w32(priv, 0x2410,<br>
> 0x810000c0); -+       mt7530_w32(priv, 0x2510, 0x810000c0); -+ -+     // set<br>
> CPU/P7 port as user port -+   mt7530_w32(priv, 0x2610, 0x81000000);<br>
> -+    mt7530_w32(priv, 0x2710, 0x81000000); -+ -+     mt7530_w32(priv,<br>
> 0x2604, 0x20ff0003); -+       mt7530_w32(priv, 0x2704, 0x20ff0003); -+<br>
> mt7530_w32(priv, 0x2610, 0x81000000); ++      /* set all ports as<br>
> security mode */ ++   for (i = 0; i < MT7530_NUM_PORTS; i++) ++<br>
> mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0003); ++ ++      /* set all<br>
> ports as user port */ ++      for (i = 0; i < MT7530_NUM_PORTS; i++) ++<br>
> mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x81000000); + +        for (i = 0;<br>
> i < MT7530_NUM_VLANS; i++) { -+               u8 ports = priv->vlans[i].ports;<br>
> -+            u32 val = mt7530_r32(priv, 0x100 + 4 * (i / 2)); ++             u16 vid =<br>
> priv->vlan_entries[i].vid; ++         u8 member =<br>
> priv->vlan_entries[i].member; ++              u8 etags =<br>
> priv->vlan_entries[i].etags; ++               u32 val; + ++           /* vid of vlan */<br>
> ++            val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(i)); +         if (i % 2 ==<br>
> 0) { +                        val &= 0xfff000; -+                     val |= i; ++                    val |= vid; +           } else<br>
> { +                   val &= 0xfff; -+                        val |= (i << 12); ++                    val |= (vid <<<br>
> 12); +                } -+            mt7530_w32(priv, 0x100 + 4 * (i / 2), val); ++<br>
> mt7530_w32(priv, REG_ESW_VLAN_VTIM(i), val); + -+             if (ports) -+<br>
> mt7530_w32(priv, REG_ESW_VLAN_VAWD1, BIT(30) | (ports << 16) |<br>
> BIT(0)); ++           /* vlan port membership */ ++           if (member) ++<br>
> mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |<br>
> ++                            REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) | ++<br>
> REG_ESW_VLAN_VAWD1_VALID); +          else +                  mt7530_w32(priv,<br>
> REG_ESW_VLAN_VAWD1, 0); + ++          /* egress mode */ ++            val = 0; ++<br>
> for (j = 0; j < MT7530_NUM_PORTS; j++) { ++                   if (etags & BIT(j))<br>
> ++                            val |= ETAG_CTRL_TAG << (j * 2); ++                     else ++                         val |=<br>
> ETAG_CTRL_UNTAG << (j * 2); ++                } ++            mt7530_w32(priv,<br>
> REG_ESW_VLAN_VAWD2, val); ++ ++               /* write to vlan table */ +<br>
> mt7530_vtcr(priv, 1, i); +    } + -+  for (i = 0; i < MT7530_NUM_PORTS;<br>
> i++) -+               mt7530_w32(priv, 0x2014 + (0x100 * i), 0x10000 |<br>
> priv->ports[i].pvid); ++      /* Port Default PVID */ ++      for (i = 0; i <<br>
> MT7530_NUM_PORTS; i++) { ++           u32 val; ++             val = mt7530_r32(priv,<br>
> REG_ESW_PORT_PPBV1(i)); ++            val &= ~0xfff; ++               val |=<br>
> priv->port_entries[i].pvid; ++                mt7530_w32(priv,<br>
> REG_ESW_PORT_PPBV1(i), val); ++       } + +   return 0; +} + +static int<br>
> +mt7530_get_port_link(struct switch_dev *dev,  int port, -+<br>
> struct switch_port_link *link) ++                     struct switch_port_link *link)<br>
> +{ +  struct mt7530_priv *priv = container_of(dev, struct<br>
> mt7530_priv, swdev); +        u32 speed, pmsr; @@ -3216,6 +3312,14 @@<br>
> Signed-off-by: John Crispin <<a href="mailto:blogic@openwrt.org">blogic@openwrt.org</a>> +}; + +static<br>
> const struct switch_attr mt7530_vlan[] = { ++ { ++            .type =<br>
> SWITCH_TYPE_INT, ++           .name = "vid", ++               .description = "VLAN ID<br>
> (0-4094)", ++         .set = mt7530_set_vid, ++               .get = mt7530_get_vid, ++<br>
> .max = 4094, ++       }, +}; + +static const struct switch_dev_ops<br>
> mt7530_ops = {<br>
><br>
</div></div></blockquote></div><br></div>