aboutsummaryrefslogtreecommitdiffstats
path: root/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch')
-rw-r--r--package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch375
1 files changed, 375 insertions, 0 deletions
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
index 0000000..4c01ad0
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch
@@ -0,0 +1,375 @@
+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>
+
+--- 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)
+--- /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);
++}
+--- 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();
+ }
+--- a/include/switch.h
++++ b/include/switch.h
+@@ -100,6 +100,7 @@ static inline void switch_setup(struct s
+ 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 */
+