add chaos_calmer branch
[15.05/openwrt.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 --- 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@openwrt.org>
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