blob: 72b885aea656664babd1aabcd71238464a4ce37c [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 42cb399df978a33539b95d668b3f973d927cb902 Mon Sep 17 00:00:00 2001
2From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
3Date: Mon, 17 Dec 2012 23:37:57 +0100
4Subject: net: switchlib: add driver for REALTEK RTL8306
5
6Signed-off-by: Oliver Muth <dr.o.muth@gmx.de>
7Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
8
9--- a/drivers/net/switch/Makefile
10+++ b/drivers/net/switch/Makefile
11@@ -13,6 +13,7 @@ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
12 COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
13 COBJS-$(CONFIG_SWITCH_ADM6996I) += adm6996i.o
14 COBJS-$(CONFIG_SWITCH_AR8216) += ar8216.o
15+COBJS-$(CONFIG_SWITCH_RTL8306) += rtl8306.o
16
17 COBJS := $(COBJS-y)
18 SRCS := $(COBJS:.o=.c)
19--- /dev/null
20+++ b/drivers/net/switch/rtl8306.c
21@@ -0,0 +1,332 @@
22+/*
23+ * Based on OpenWrt linux driver
24+ *
25+ * Copyright (C) 2011-2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
26+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
27+ *
28+ * SPDX-License-Identifier: GPL-2.0+
29+ */
30+#define DEBUG
31+#include <common.h>
32+#include <malloc.h>
33+#include <switch.h>
34+#include <miiphy.h>
35+
36+#define RTL8306_REG_PAGE 16
37+#define RTL8306_REG_PAGE_LO (1 << 15)
38+#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */
39+#define RTL8306_CHIPID 0x5988
40+
41+#define RTL8306_NUM_VLANS 16
42+#define RTL8306_NUM_PORTS 6
43+#define RTL8306_PORT_CPU 5
44+#define RTL8306_NUM_PAGES 4
45+#define RTL8306_NUM_REGS 32
46+
47+enum {
48+ RTL_TYPE_S,
49+ RTL_TYPE_SD,
50+ RTL_TYPE_SDM,
51+};
52+
53+struct rtl_reg {
54+ int page;
55+ int phy;
56+ int reg;
57+ int bits;
58+ int shift;
59+ int inverted;
60+};
61+
62+enum rtl_regidx {
63+ RTL_REG_CHIPID,
64+ RTL_REG_CHIPVER,
65+ RTL_REG_CHIPTYPE,
66+ RTL_REG_CPUPORT,
67+
68+ RTL_REG_EN_CPUPORT,
69+ RTL_REG_EN_TAG_OUT,
70+ RTL_REG_EN_TAG_CLR,
71+ RTL_REG_EN_TAG_IN,
72+ RTL_REG_TRAP_CPU,
73+ RTL_REG_TRUNK_PORTSEL,
74+ RTL_REG_EN_TRUNK,
75+ RTL_REG_RESET,
76+ RTL_REG_PHY_RESET,
77+ RTL_REG_CPU_LINKUP,
78+
79+ RTL_REG_VLAN_ENABLE,
80+ RTL_REG_VLAN_FILTER,
81+ RTL_REG_VLAN_TAG_ONLY,
82+ RTL_REG_VLAN_TAG_AWARE,
83+#define RTL_VLAN_ENUM(id) \
84+ RTL_REG_VLAN##id##_VID, \
85+ RTL_REG_VLAN##id##_PORTMASK
86+ RTL_VLAN_ENUM(0),
87+ RTL_VLAN_ENUM(1),
88+ RTL_VLAN_ENUM(2),
89+ RTL_VLAN_ENUM(3),
90+ RTL_VLAN_ENUM(4),
91+ RTL_VLAN_ENUM(5),
92+ RTL_VLAN_ENUM(6),
93+ RTL_VLAN_ENUM(7),
94+ RTL_VLAN_ENUM(8),
95+ RTL_VLAN_ENUM(9),
96+ RTL_VLAN_ENUM(10),
97+ RTL_VLAN_ENUM(11),
98+ RTL_VLAN_ENUM(12),
99+ RTL_VLAN_ENUM(13),
100+ RTL_VLAN_ENUM(14),
101+ RTL_VLAN_ENUM(15),
102+#define RTL_PORT_ENUM(id) \
103+ RTL_REG_PORT##id##_PVID, \
104+ RTL_REG_PORT##id##_NULL_VID_REPLACE, \
105+ RTL_REG_PORT##id##_NON_PVID_DISCARD, \
106+ RTL_REG_PORT##id##_VID_INSERT, \
107+ RTL_REG_PORT##id##_TAG_INSERT, \
108+ RTL_REG_PORT##id##_LINK, \
109+ RTL_REG_PORT##id##_SPEED, \
110+ RTL_REG_PORT##id##_NWAY, \
111+ RTL_REG_PORT##id##_NRESTART, \
112+ RTL_REG_PORT##id##_DUPLEX, \
113+ RTL_REG_PORT##id##_RXEN, \
114+ RTL_REG_PORT##id##_TXEN, \
115+ RTL_REG_PORT##id##_LRNEN
116+ RTL_PORT_ENUM(0),
117+ RTL_PORT_ENUM(1),
118+ RTL_PORT_ENUM(2),
119+ RTL_PORT_ENUM(3),
120+ RTL_PORT_ENUM(4),
121+ RTL_PORT_ENUM(5),
122+};
123+
124+static const struct rtl_reg rtl_regs[] = {
125+ [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 },
126+ [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 },
127+ [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 },
128+
129+ /* CPU port number */
130+ [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 },
131+ /* Enable CPU port function */
132+ [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 },
133+ /* Enable CPU port tag insertion */
134+ [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 },
135+ /* Enable CPU port tag removal */
136+ [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 },
137+ /* Enable CPU port tag checking */
138+ [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 },
139+ [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 },
140+ [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 },
141+ [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 },
142+ [RTL_REG_PHY_RESET] = { 0, 0, 0, 1, 15, 0 },
143+ [RTL_REG_CPU_LINKUP] = { 0, 6, 22, 1, 15, 0 },
144+ [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 },
145+
146+ [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 },
147+ [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 },
148+ [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 },
149+ [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 },
150+
151+#define RTL_VLAN_REGS(id, phy, page, regofs) \
152+ [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \
153+ [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 }
154+ RTL_VLAN_REGS( 0, 0, 0, 0),
155+ RTL_VLAN_REGS( 1, 1, 0, 0),
156+ RTL_VLAN_REGS( 2, 2, 0, 0),
157+ RTL_VLAN_REGS( 3, 3, 0, 0),
158+ RTL_VLAN_REGS( 4, 4, 0, 0),
159+ RTL_VLAN_REGS( 5, 0, 1, 2),
160+ RTL_VLAN_REGS( 6, 1, 1, 2),
161+ RTL_VLAN_REGS( 7, 2, 1, 2),
162+ RTL_VLAN_REGS( 8, 3, 1, 2),
163+ RTL_VLAN_REGS( 9, 4, 1, 2),
164+ RTL_VLAN_REGS(10, 0, 1, 4),
165+ RTL_VLAN_REGS(11, 1, 1, 4),
166+ RTL_VLAN_REGS(12, 2, 1, 4),
167+ RTL_VLAN_REGS(13, 3, 1, 4),
168+ RTL_VLAN_REGS(14, 4, 1, 4),
169+ RTL_VLAN_REGS(15, 0, 1, 6),
170+
171+#define REG_PORT_SETTING(port, phy) \
172+ [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \
173+ [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \
174+ [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \
175+ [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \
176+ [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \
177+ [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \
178+ [RTL_REG_PORT##port##_LRNEN] = { 0, phy, 24, 1, 9, 0 }, \
179+ [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \
180+ [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \
181+ [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \
182+ [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \
183+ [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 }
184+
185+ REG_PORT_SETTING(0, 0),
186+ REG_PORT_SETTING(1, 1),
187+ REG_PORT_SETTING(2, 2),
188+ REG_PORT_SETTING(3, 3),
189+ REG_PORT_SETTING(4, 4),
190+ REG_PORT_SETTING(5, 6),
191+
192+#define REG_PORT_PVID(phy, page, regofs) \
193+ { page, phy, 24 + regofs, 4, 12, 0 }
194+ [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0),
195+ [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0),
196+ [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0),
197+ [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0),
198+ [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0),
199+ [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2),
200+};
201+
202+static void rtl_set_page(struct mii_dev *bus, unsigned int page)
203+{
204+ u16 pgsel;
205+
206+ BUG_ON(page > RTL8306_NUM_PAGES);
207+
208+ pgsel = bus->read(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE);
209+ pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI);
210+
211+ if (page & (1 << 0))
212+ pgsel |= RTL8306_REG_PAGE_LO;
213+
214+ if (!(page & (1 << 1))) /* bit is inverted */
215+ pgsel |= RTL8306_REG_PAGE_HI;
216+
217+ bus->write(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE, pgsel);
218+
219+}
220+
221+static __maybe_unused int rtl_w16(struct mii_dev *bus, unsigned int page, unsigned int phy,
222+ unsigned int reg, u16 val)
223+{
224+ rtl_set_page(bus, page);
225+
226+ bus->write(bus, phy, MDIO_DEVAD_NONE, reg, val);
227+ bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
228+
229+ return 0;
230+}
231+
232+static int rtl_r16(struct mii_dev *bus, unsigned int page, unsigned int phy,
233+ unsigned int reg)
234+{
235+ rtl_set_page(bus, page);
236+
237+ return bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
238+}
239+
240+static u16 rtl_rmw(struct mii_dev *bus, unsigned int page, unsigned int phy,
241+ unsigned int reg, u16 mask, u16 val)
242+{
243+ u16 r;
244+
245+ rtl_set_page(bus, page);
246+
247+ r = bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
248+ r &= ~mask;
249+ r |= val;
250+ bus->write(bus, phy, MDIO_DEVAD_NONE, reg, r);
251+
252+ return bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
253+}
254+
255+static int rtl_get(struct mii_dev *bus, enum rtl_regidx s)
256+{
257+ const struct rtl_reg *r = &rtl_regs[s];
258+ u16 val;
259+
260+ BUG_ON(s >= ARRAY_SIZE(rtl_regs));
261+
262+ if (r->bits == 0) /* unimplemented */
263+ return 0;
264+
265+ val = rtl_r16(bus, r->page, r->phy, r->reg);
266+
267+ if (r->shift > 0)
268+ val >>= r->shift;
269+
270+ if (r->inverted)
271+ val = ~val;
272+
273+ val &= (1 << r->bits) - 1;
274+
275+ return val;
276+}
277+
278+static __maybe_unused int rtl_set(struct mii_dev *bus, enum rtl_regidx s, unsigned int val)
279+{
280+ const struct rtl_reg *r = &rtl_regs[s];
281+ u16 mask = 0xffff;
282+
283+ BUG_ON(s >= ARRAY_SIZE(rtl_regs));
284+
285+ if (r->bits == 0) /* unimplemented */
286+ return 0;
287+
288+ if (r->shift > 0)
289+ val <<= r->shift;
290+
291+ if (r->inverted)
292+ val = ~val;
293+
294+ if (r->bits != 16) {
295+ mask = (1 << r->bits) - 1;
296+ mask <<= r->shift;
297+ }
298+
299+ val &= mask;
300+
301+ return rtl_rmw(bus, r->page, r->phy, r->reg, mask, val);
302+}
303+
304+static int rtl8306_probe(struct switch_device *dev)
305+{
306+ struct mii_dev *bus = dev->bus;
307+ unsigned int chipid, chipver, chiptype;
308+
309+ chipid = rtl_get(bus, RTL_REG_CHIPID);
310+ chipver = rtl_get(bus, RTL_REG_CHIPVER);
311+ chiptype = rtl_get(bus, RTL_REG_CHIPTYPE);
312+
313+ debug("%s: chipid %x, chipver %x, chiptype %x\n",
314+ __func__, chipid, chipver, chiptype);
315+
316+ if (chipid == RTL8306_CHIPID)
317+ return 0;
318+
319+ return 1;
320+}
321+
322+static void rtl8306_setup(struct switch_device *dev)
323+{
324+ struct mii_dev *bus = dev->bus;
325+
326+ /* initialize cpu port settings */
327+ rtl_set(bus, RTL_REG_CPUPORT, dev->cpu_port);
328+ rtl_set(bus, RTL_REG_EN_CPUPORT, 1);
329+
330+ /* enable phy 5 link status */
331+ rtl_set(bus, RTL_REG_CPU_LINKUP, 1);
332+// rtl_set(bus, RTL_REG_PORT5_TXEN, 1);
333+// rtl_set(bus, RTL_REG_PORT5_RXEN, 1);
334+// rtl_set(bus, RTL_REG_PORT5_LRNEN, 1);
335+#ifdef DEBUG
336+ debug("%s: CPU link up: %i\n",
337+ __func__, rtl_get(bus, RTL_REG_PORT5_LINK));
338+#endif
339+
340+}
341+
342+static struct switch_driver rtl8306_drv = {
343+ .name = "rtl8306",
344+};
345+
346+void switch_rtl8306_init(void)
347+{
348+ /* For archs with manual relocation */
349+ rtl8306_drv.probe = rtl8306_probe;
350+ rtl8306_drv.setup = rtl8306_setup;
351+
352+ switch_driver_register(&rtl8306_drv);
353+}
354--- a/drivers/net/switch/switch.c
355+++ b/drivers/net/switch/switch.c
356@@ -26,6 +26,9 @@ void switch_init(void)
357 #if defined(CONFIG_SWITCH_AR8216)
358 switch_ar8216_init();
359 #endif
360+#if defined(CONFIG_SWITCH_RTL8306)
361+ switch_rtl8306_init();
362+#endif
363
364 board_switch_init();
365 }
366--- a/include/switch.h
367+++ b/include/switch.h
368@@ -100,6 +100,7 @@ static inline void switch_setup(struct s
369 extern void switch_psb697x_init(void);
370 extern void switch_adm6996i_init(void);
371 extern void switch_ar8216_init(void);
372+extern void switch_rtl8306_init(void);
373
374 #endif /* __SWITCH_H */
375