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