uboot-lantiq: update to v2013.10
[openwrt.git] / package / boot / uboot-lantiq / patches / 0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch
diff --git a/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch b/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch
new file mode 100644 (file)
index 0000000..e6bb374
--- /dev/null
@@ -0,0 +1,387 @@
+From 42cb399df978a33539b95d668b3f973d927cb902 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 17 Dec 2012 23:37:57 +0100
+Subject: net: switchlib: add driver for REALTEK RTL8306
+
+Signed-off-by: Oliver Muth <dr.o.muth@gmx.de>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+diff --git a/drivers/net/switch/Makefile b/drivers/net/switch/Makefile
+index 7400897..08c6972 100644
+--- a/drivers/net/switch/Makefile
++++ b/drivers/net/switch/Makefile
+@@ -13,6 +13,7 @@ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
+ COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
+ COBJS-$(CONFIG_SWITCH_ADM6996I) += adm6996i.o
+ COBJS-$(CONFIG_SWITCH_AR8216) += ar8216.o
++COBJS-$(CONFIG_SWITCH_RTL8306) += rtl8306.o
+ COBJS := $(COBJS-y)
+ SRCS  := $(COBJS:.o=.c)
+diff --git a/drivers/net/switch/rtl8306.c b/drivers/net/switch/rtl8306.c
+new file mode 100644
+index 0000000..7a6a917
+--- /dev/null
++++ b/drivers/net/switch/rtl8306.c
+@@ -0,0 +1,332 @@
++/*
++ * Based on OpenWRT linux driver
++ *
++ * Copyright (C) 2011-2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
++ *
++ * SPDX-License-Identifier:   GPL-2.0+
++ */
++#define DEBUG
++#include <common.h>
++#include <malloc.h>
++#include <switch.h>
++#include <miiphy.h>
++
++#define RTL8306_REG_PAGE              16
++#define RTL8306_REG_PAGE_LO           (1 << 15)
++#define RTL8306_REG_PAGE_HI           (1 << 1) /* inverted */
++#define RTL8306_CHIPID                        0x5988
++
++#define RTL8306_NUM_VLANS             16
++#define RTL8306_NUM_PORTS             6
++#define RTL8306_PORT_CPU              5
++#define RTL8306_NUM_PAGES             4
++#define RTL8306_NUM_REGS              32
++
++enum {
++      RTL_TYPE_S,
++      RTL_TYPE_SD,
++      RTL_TYPE_SDM,
++};
++
++struct rtl_reg {
++      int page;
++      int phy;
++      int reg;
++      int bits;
++      int shift;
++      int inverted;
++};
++
++enum rtl_regidx {
++      RTL_REG_CHIPID,
++      RTL_REG_CHIPVER,
++      RTL_REG_CHIPTYPE,
++      RTL_REG_CPUPORT,
++
++      RTL_REG_EN_CPUPORT,
++      RTL_REG_EN_TAG_OUT,
++      RTL_REG_EN_TAG_CLR,
++      RTL_REG_EN_TAG_IN,
++      RTL_REG_TRAP_CPU,
++      RTL_REG_TRUNK_PORTSEL,
++      RTL_REG_EN_TRUNK,
++      RTL_REG_RESET,
++      RTL_REG_PHY_RESET,
++      RTL_REG_CPU_LINKUP,
++
++      RTL_REG_VLAN_ENABLE,
++      RTL_REG_VLAN_FILTER,
++      RTL_REG_VLAN_TAG_ONLY,
++      RTL_REG_VLAN_TAG_AWARE,
++#define RTL_VLAN_ENUM(id) \
++      RTL_REG_VLAN##id##_VID, \
++      RTL_REG_VLAN##id##_PORTMASK
++      RTL_VLAN_ENUM(0),
++      RTL_VLAN_ENUM(1),
++      RTL_VLAN_ENUM(2),
++      RTL_VLAN_ENUM(3),
++      RTL_VLAN_ENUM(4),
++      RTL_VLAN_ENUM(5),
++      RTL_VLAN_ENUM(6),
++      RTL_VLAN_ENUM(7),
++      RTL_VLAN_ENUM(8),
++      RTL_VLAN_ENUM(9),
++      RTL_VLAN_ENUM(10),
++      RTL_VLAN_ENUM(11),
++      RTL_VLAN_ENUM(12),
++      RTL_VLAN_ENUM(13),
++      RTL_VLAN_ENUM(14),
++      RTL_VLAN_ENUM(15),
++#define RTL_PORT_ENUM(id) \
++      RTL_REG_PORT##id##_PVID, \
++      RTL_REG_PORT##id##_NULL_VID_REPLACE, \
++      RTL_REG_PORT##id##_NON_PVID_DISCARD, \
++      RTL_REG_PORT##id##_VID_INSERT, \
++      RTL_REG_PORT##id##_TAG_INSERT, \
++      RTL_REG_PORT##id##_LINK, \
++      RTL_REG_PORT##id##_SPEED, \
++      RTL_REG_PORT##id##_NWAY, \
++      RTL_REG_PORT##id##_NRESTART, \
++      RTL_REG_PORT##id##_DUPLEX, \
++      RTL_REG_PORT##id##_RXEN, \
++      RTL_REG_PORT##id##_TXEN, \
++      RTL_REG_PORT##id##_LRNEN
++      RTL_PORT_ENUM(0),
++      RTL_PORT_ENUM(1),
++      RTL_PORT_ENUM(2),
++      RTL_PORT_ENUM(3),
++      RTL_PORT_ENUM(4),
++      RTL_PORT_ENUM(5),
++};
++
++static const struct rtl_reg rtl_regs[] = {
++      [RTL_REG_CHIPID]         = { 0, 4, 30, 16,  0, 0 },
++      [RTL_REG_CHIPVER]        = { 0, 4, 31,  8,  0, 0 },
++      [RTL_REG_CHIPTYPE]       = { 0, 4, 31,  2,  8, 0 },
++
++      /* CPU port number */
++      [RTL_REG_CPUPORT]        = { 2, 4, 21,  3,  0, 0 },
++      /* Enable CPU port function */
++      [RTL_REG_EN_CPUPORT]     = { 3, 2, 21,  1, 15, 1 },
++      /* Enable CPU port tag insertion */
++      [RTL_REG_EN_TAG_OUT]     = { 3, 2, 21,  1, 12, 0 },
++      /* Enable CPU port tag removal */
++      [RTL_REG_EN_TAG_CLR]     = { 3, 2, 21,  1, 11, 0 },
++      /* Enable CPU port tag checking */
++      [RTL_REG_EN_TAG_IN]      = { 0, 4, 21,  1,  7, 0 },
++      [RTL_REG_EN_TRUNK]       = { 0, 0, 19,  1, 11, 1 },
++      [RTL_REG_TRUNK_PORTSEL]  = { 0, 0, 16,  1,  6, 1 },
++      [RTL_REG_RESET]          = { 0, 0, 16,  1, 12, 0 },
++      [RTL_REG_PHY_RESET]      = { 0, 0,  0,  1, 15, 0 },
++      [RTL_REG_CPU_LINKUP]     = { 0, 6, 22,  1, 15, 0 },
++      [RTL_REG_TRAP_CPU]       = { 3, 2, 22,  1,  6, 0 },
++
++      [RTL_REG_VLAN_TAG_ONLY]  = { 0, 0, 16,  1,  8, 1 },
++      [RTL_REG_VLAN_FILTER]    = { 0, 0, 16,  1,  9, 1 },
++      [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16,  1, 10, 1 },
++      [RTL_REG_VLAN_ENABLE]    = { 0, 0, 18,  1,  8, 1 },
++
++#define RTL_VLAN_REGS(id, phy, page, regofs) \
++      [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \
++      [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 }
++      RTL_VLAN_REGS( 0, 0, 0, 0),
++      RTL_VLAN_REGS( 1, 1, 0, 0),
++      RTL_VLAN_REGS( 2, 2, 0, 0),
++      RTL_VLAN_REGS( 3, 3, 0, 0),
++      RTL_VLAN_REGS( 4, 4, 0, 0),
++      RTL_VLAN_REGS( 5, 0, 1, 2),
++      RTL_VLAN_REGS( 6, 1, 1, 2),
++      RTL_VLAN_REGS( 7, 2, 1, 2),
++      RTL_VLAN_REGS( 8, 3, 1, 2),
++      RTL_VLAN_REGS( 9, 4, 1, 2),
++      RTL_VLAN_REGS(10, 0, 1, 4),
++      RTL_VLAN_REGS(11, 1, 1, 4),
++      RTL_VLAN_REGS(12, 2, 1, 4),
++      RTL_VLAN_REGS(13, 3, 1, 4),
++      RTL_VLAN_REGS(14, 4, 1, 4),
++      RTL_VLAN_REGS(15, 0, 1, 6),
++
++#define REG_PORT_SETTING(port, phy) \
++      [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \
++      [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \
++      [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \
++      [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \
++      [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \
++      [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \
++      [RTL_REG_PORT##port##_LRNEN] = { 0, phy, 24, 1, 9, 0 }, \
++      [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \
++      [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \
++      [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \
++      [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \
++      [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 }
++
++      REG_PORT_SETTING(0, 0),
++      REG_PORT_SETTING(1, 1),
++      REG_PORT_SETTING(2, 2),
++      REG_PORT_SETTING(3, 3),
++      REG_PORT_SETTING(4, 4),
++      REG_PORT_SETTING(5, 6),
++
++#define REG_PORT_PVID(phy, page, regofs) \
++      { page, phy, 24 + regofs, 4, 12, 0 }
++      [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0),
++      [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0),
++      [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0),
++      [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0),
++      [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0),
++      [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2),
++};
++
++static void rtl_set_page(struct mii_dev *bus, unsigned int page)
++{
++      u16 pgsel;
++
++      BUG_ON(page > RTL8306_NUM_PAGES);
++
++      pgsel = bus->read(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE);
++      pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI);
++
++      if (page & (1 << 0))
++              pgsel |= RTL8306_REG_PAGE_LO;
++
++      if (!(page & (1 << 1))) /* bit is inverted */
++              pgsel |= RTL8306_REG_PAGE_HI;
++
++      bus->write(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE, pgsel);
++
++}
++
++static __maybe_unused int rtl_w16(struct mii_dev *bus, unsigned int page, unsigned int phy,
++                      unsigned int reg, u16 val)
++{
++      rtl_set_page(bus, page);
++
++      bus->write(bus, phy, MDIO_DEVAD_NONE, reg, val);
++      bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
++
++      return 0;
++}
++
++static int rtl_r16(struct mii_dev *bus, unsigned int page, unsigned int phy,
++                      unsigned int reg)
++{
++      rtl_set_page(bus, page);
++
++      return bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
++}
++
++static u16 rtl_rmw(struct mii_dev *bus, unsigned int page, unsigned int phy,
++                      unsigned int reg, u16 mask, u16 val)
++{
++      u16 r;
++
++      rtl_set_page(bus, page);
++
++      r = bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
++      r &= ~mask;
++      r |= val;
++      bus->write(bus, phy, MDIO_DEVAD_NONE, reg, r);
++
++      return bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
++}
++
++static int rtl_get(struct mii_dev *bus, enum rtl_regidx s)
++{
++      const struct rtl_reg *r = &rtl_regs[s];
++      u16 val;
++
++      BUG_ON(s >= ARRAY_SIZE(rtl_regs));
++
++      if (r->bits == 0) /* unimplemented */
++              return 0;
++
++      val = rtl_r16(bus, r->page, r->phy, r->reg);
++
++      if (r->shift > 0)
++              val >>= r->shift;
++
++      if (r->inverted)
++              val = ~val;
++
++      val &= (1 << r->bits) - 1;
++
++      return val;
++}
++
++static __maybe_unused int rtl_set(struct mii_dev *bus, enum rtl_regidx s, unsigned int val)
++{
++      const struct rtl_reg *r = &rtl_regs[s];
++      u16 mask = 0xffff;
++
++      BUG_ON(s >= ARRAY_SIZE(rtl_regs));
++
++      if (r->bits == 0) /* unimplemented */
++              return 0;
++
++      if (r->shift > 0)
++              val <<= r->shift;
++
++      if (r->inverted)
++              val = ~val;
++
++      if (r->bits != 16) {
++              mask = (1 << r->bits) - 1;
++              mask <<= r->shift;
++      }
++
++      val &= mask;
++
++      return rtl_rmw(bus, r->page, r->phy, r->reg, mask, val);
++}
++
++static int rtl8306_probe(struct switch_device *dev)
++{
++      struct mii_dev *bus = dev->bus;
++      unsigned int chipid, chipver, chiptype;
++
++      chipid = rtl_get(bus, RTL_REG_CHIPID);
++      chipver = rtl_get(bus, RTL_REG_CHIPVER);
++      chiptype = rtl_get(bus, RTL_REG_CHIPTYPE);
++
++      debug("%s: chipid %x, chipver %x, chiptype %x\n",
++              __func__, chipid, chipver, chiptype);
++
++      if (chipid == RTL8306_CHIPID)
++              return 0;
++
++      return 1;
++}
++
++static void rtl8306_setup(struct switch_device *dev)
++{
++      struct mii_dev *bus = dev->bus;
++
++      /* initialize cpu port settings */
++      rtl_set(bus, RTL_REG_CPUPORT, dev->cpu_port);
++      rtl_set(bus, RTL_REG_EN_CPUPORT, 1);
++
++      /* enable phy 5 link status */
++      rtl_set(bus, RTL_REG_CPU_LINKUP, 1);
++//    rtl_set(bus, RTL_REG_PORT5_TXEN, 1);
++//    rtl_set(bus, RTL_REG_PORT5_RXEN, 1);
++//    rtl_set(bus, RTL_REG_PORT5_LRNEN, 1);
++#ifdef DEBUG
++ debug("%s: CPU link up: %i\n",
++              __func__, rtl_get(bus, RTL_REG_PORT5_LINK));
++#endif
++
++}
++
++static struct switch_driver rtl8306_drv = {
++      .name = "rtl8306",
++};
++
++void switch_rtl8306_init(void)
++{
++      /* For archs with manual relocation */
++      rtl8306_drv.probe = rtl8306_probe;
++      rtl8306_drv.setup = rtl8306_setup;
++
++      switch_driver_register(&rtl8306_drv);
++}
+diff --git a/drivers/net/switch/switch.c b/drivers/net/switch/switch.c
+index 3e34a7f..2e1c668 100644
+--- a/drivers/net/switch/switch.c
++++ b/drivers/net/switch/switch.c
+@@ -26,6 +26,9 @@ void switch_init(void)
+ #if defined(CONFIG_SWITCH_AR8216)
+       switch_ar8216_init();
+ #endif
++#if defined(CONFIG_SWITCH_RTL8306)
++      switch_rtl8306_init();
++#endif
+       board_switch_init();
+ }
+diff --git a/include/switch.h b/include/switch.h
+index ae7b123..927b1d2 100644
+--- a/include/switch.h
++++ b/include/switch.h
+@@ -100,6 +100,7 @@ static inline void switch_setup(struct switch_device *dev)
+ extern void switch_psb697x_init(void);
+ extern void switch_adm6996i_init(void);
+ extern void switch_ar8216_init(void);
++extern void switch_rtl8306_init(void);
+ #endif /* __SWITCH_H */
+-- 
+1.8.3.2
+