diff options
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.patch | 387 |
1 files changed, 387 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..e6bb374 --- /dev/null +++ b/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch @@ -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 + |