mtkswitch_rt3050.c revision 299910
1/*-
2 * Copyright (c) 2016 Stanislav Galabov.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/etherswitch/mtkswitch/mtkswitch_rt3050.c 299910 2016-05-16 07:00:49Z sgalabov $
27 */
28
29#include <sys/param.h>
30#include <sys/bus.h>
31#include <sys/errno.h>
32#include <sys/kernel.h>
33#include <sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/module.h>
36#include <sys/mutex.h>
37#include <sys/rman.h>
38#include <sys/socket.h>
39#include <sys/sockio.h>
40#include <sys/sysctl.h>
41#include <sys/systm.h>
42
43#include <net/if.h>
44#include <net/if_var.h>
45#include <net/ethernet.h>
46#include <net/if_media.h>
47#include <net/if_types.h>
48
49#include <machine/bus.h>
50#include <dev/mii/mii.h>
51#include <dev/mii/miivar.h>
52#include <dev/mdio/mdio.h>
53
54#include <dev/etherswitch/etherswitch.h>
55#include <dev/etherswitch/mtkswitch/mtkswitchvar.h>
56#include <dev/etherswitch/mtkswitch/mtkswitch_rt3050.h>
57
58static int
59mtkswitch_reg_read(device_t dev, int reg)
60{
61	struct mtkswitch_softc *sc = device_get_softc(dev);
62	uint32_t val;
63
64	MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
65	val = MTKSWITCH_READ(sc, MTKSWITCH_REG32(reg));
66	if (MTKSWITCH_IS_HI16(reg))
67		return (MTKSWITCH_HI16(val));
68	return (MTKSWITCH_LO16(val));
69}
70
71static int
72mtkswitch_reg_write(device_t dev, int reg, int val)
73{
74	struct mtkswitch_softc *sc = device_get_softc(dev);
75	uint32_t tmp;
76
77	MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
78	tmp = MTKSWITCH_READ(sc, MTKSWITCH_REG32(reg));
79	if (MTKSWITCH_IS_HI16(reg)) {
80		tmp &= MTKSWITCH_LO16_MSK;
81		tmp |= MTKSWITCH_TO_HI16(val);
82	} else {
83		tmp &= MTKSWITCH_HI16_MSK;
84		tmp |= MTKSWITCH_TO_LO16(val);
85	}
86	MTKSWITCH_WRITE(sc, MTKSWITCH_REG32(reg), tmp);
87
88	return (0);
89}
90
91static int
92mtkswitch_phy_read(device_t dev, int phy, int reg)
93{
94	struct mtkswitch_softc *sc = device_get_softc(dev);
95	int val;
96
97	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
98	MTKSWITCH_LOCK(sc);
99	while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE);
100	MTKSWITCH_WRITE(sc, MTKSWITCH_PCR0, PCR0_READ | PCR0_REG(reg) |
101	    PCR0_PHY(phy));
102	while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE);
103	val = (MTKSWITCH_READ(sc, MTKSWITCH_PCR1) >> PCR1_DATA_OFF) &
104	    PCR1_DATA_MASK;
105	MTKSWITCH_UNLOCK(sc);
106	return (val);
107}
108
109static int
110mtkswitch_phy_write(device_t dev, int phy, int reg, int val)
111{
112	struct mtkswitch_softc *sc = device_get_softc(dev);
113
114	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
115	MTKSWITCH_LOCK(sc);
116	while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE);
117	MTKSWITCH_WRITE(sc, MTKSWITCH_PCR0, PCR0_WRITE | PCR0_REG(reg) |
118	    PCR0_PHY(phy) | PCR0_DATA(val));
119	while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE);
120	MTKSWITCH_UNLOCK(sc);
121	return (0);
122}
123
124static int
125mtkswitch_reset(struct mtkswitch_softc *sc)
126{
127
128	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
129	MTKSWITCH_LOCK(sc);
130	MTKSWITCH_WRITE(sc, MTKSWITCH_STRT, STRT_RESET);
131	while (MTKSWITCH_READ(sc, MTKSWITCH_STRT) != 0);
132	MTKSWITCH_UNLOCK(sc);
133
134	return (0);
135}
136
137static int
138mtkswitch_hw_setup(struct mtkswitch_softc *sc)
139{
140
141	/*
142	 * TODO: parse the device tree and see if we need to configure
143	 *       ports, etc. differently. For now we fallback to defaults.
144	 */
145
146	/* Called early and hence unlocked */
147	/* Set ports 0-4 to auto negotiation */
148	MTKSWITCH_WRITE(sc, MTKSWITCH_FPA, FPA_ALL_AUTO);
149
150	return (0);
151}
152
153static int
154mtkswitch_hw_global_setup(struct mtkswitch_softc *sc)
155{
156
157	/* Called early and hence unlocked */
158	return (0);
159}
160
161static void
162mtkswitch_port_init(struct mtkswitch_softc *sc, int port)
163{
164	/* Called early and hence unlocked */
165	/* Do nothing - ports are set to auto negotiation in hw_setup */
166}
167
168static uint32_t
169mtkswitch_get_port_status(struct mtkswitch_softc *sc, int port)
170{
171	uint32_t val, res;
172
173	MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
174	res = 0;
175	val = MTKSWITCH_READ(sc, MTKSWITCH_POA);
176
177	if (val & POA_PRT_LINK(port))
178		res |= MTKSWITCH_LINK_UP;
179	if (val & POA_PRT_DPX(port))
180		res |= MTKSWITCH_DUPLEX;
181
182	if (MTKSWITCH_PORT_IS_100M(port)) {
183		if (val & POA_FE_SPEED(port))
184			res |= MTKSWITCH_SPEED_100;
185		if (val & POA_FE_XFC(port))
186			res |= (MTKSWITCH_TXFLOW | MTKSWITCH_RXFLOW);
187	} else {
188		switch (POA_GE_SPEED(val, port)) {
189		case POA_GE_SPEED_10:
190			res |= MTKSWITCH_SPEED_10;
191			break;
192		case POA_GE_SPEED_100:
193			res |= MTKSWITCH_SPEED_100;
194			break;
195		case POA_GE_SPEED_1000:
196			res |= MTKSWITCH_SPEED_1000;
197			break;
198		}
199
200		val = POA_GE_XFC(val, port);
201		if (val & POA_GE_XFC_TX_MSK)
202			res |= MTKSWITCH_TXFLOW;
203		if (val & POA_GE_XFC_RX_MSK)
204			res |= MTKSWITCH_RXFLOW;
205	}
206
207	return (res);
208}
209
210static int
211mtkswitch_atu_flush(struct mtkswitch_softc *sc)
212{
213	return (0);
214}
215
216static int
217mtkswitch_port_vlan_setup(struct mtkswitch_softc *sc, etherswitch_port_t *p)
218{
219	uint32_t val;
220	int err, invert = 0;
221
222	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
223	MTKSWITCH_LOCK(sc);
224	/* Set the PVID. */
225	if (p->es_pvid != 0) {
226		err = sc->hal.mtkswitch_vlan_set_pvid(sc, p->es_port,
227		    p->es_pvid);
228		if (err != 0) {
229			MTKSWITCH_UNLOCK(sc);
230			return (err);
231		}
232	}
233
234	/* Mutually exclusive */
235	if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
236	    p->es_flags & ETHERSWITCH_PORT_STRIPTAG) {
237		invert = 1;
238	}
239
240	val = MTKSWITCH_READ(sc, MTKSWITCH_SGC2);
241	if (p->es_flags & ETHERSWITCH_PORT_DOUBLE_TAG)
242		val |= SGC2_DOUBLE_TAG_PORT(p->es_port);
243	else
244		val &= ~SGC2_DOUBLE_TAG_PORT(p->es_port);
245	MTKSWITCH_WRITE(sc, MTKSWITCH_SGC2, val);
246
247	val = MTKSWITCH_READ(sc, MTKSWITCH_POC2);
248	if (invert) {
249		if (val & POC2_UNTAG_PORT(p->es_port))
250			val &= ~POC2_UNTAG_PORT(p->es_port);
251		else
252			val |= POC2_UNTAG_PORT(p->es_port);
253	} else if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
254		val |= POC2_UNTAG_PORT(p->es_port);
255	else
256		val &= ~POC2_UNTAG_PORT(p->es_port);
257	MTKSWITCH_WRITE(sc, MTKSWITCH_POC2, val);
258	MTKSWITCH_UNLOCK(sc);
259
260	return (0);
261}
262
263static int
264mtkswitch_port_vlan_get(struct mtkswitch_softc *sc, etherswitch_port_t *p)
265{
266	uint32_t val;
267
268	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
269	MTKSWITCH_LOCK(sc);
270
271	/* Retrieve the PVID */
272	sc->hal.mtkswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid);
273
274	/* Port flags */
275	p->es_flags = 0;
276	val = MTKSWITCH_READ(sc, MTKSWITCH_SGC2);
277	if (val & SGC2_DOUBLE_TAG_PORT(p->es_port))
278		p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG;
279
280	val = MTKSWITCH_READ(sc, MTKSWITCH_POC2);
281	if (val & POC2_UNTAG_PORT(p->es_port))
282		p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
283	else
284		p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
285
286	MTKSWITCH_UNLOCK(sc);
287
288	return (0);
289}
290
291static void
292mtkswitch_vlan_init_hw(struct mtkswitch_softc *sc)
293{
294	uint32_t val, vid;
295	int i;
296
297	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
298	MTKSWITCH_LOCK(sc);
299
300	/* Reset everything to defaults first */
301	for (i = 0; i < sc->info.es_nvlangroups; i++) {
302		/* Remove all VLAN members and untag info, if any */
303		if (i % 4 == 0) {
304			MTKSWITCH_WRITE(sc, MTKSWITCH_VMSC(i), 0);
305			if (sc->sc_switchtype != MTK_SWITCH_RT3050)
306				MTKSWITCH_WRITE(sc, MTKSWITCH_VUB(i), 0);
307		}
308		/* Reset to default VIDs */
309		val = MTKSWITCH_READ(sc, MTKSWITCH_VLANI(i));
310		val &= ~(VLANI_MASK << VLANI_OFF(i));
311		val |= ((i + 1) << VLANI_OFF(i));
312		MTKSWITCH_WRITE(sc, MTKSWITCH_VLANI(i), val);
313	}
314
315	/* Now, add all ports as untagged members to VLAN1 */
316	vid = 0;
317	val = MTKSWITCH_READ(sc, MTKSWITCH_VMSC(vid));
318	val &= ~(VMSC_MASK << VMSC_OFF(vid));
319	val |= (((1<<sc->numports)-1) << VMSC_OFF(vid));
320	MTKSWITCH_WRITE(sc, MTKSWITCH_VMSC(vid), val);
321	if (sc->sc_switchtype != MTK_SWITCH_RT3050) {
322		val = MTKSWITCH_READ(sc, MTKSWITCH_VUB(vid));
323		val &= ~(VUB_MASK << VUB_OFF(vid));
324		val |= (((1<<sc->numports)-1) << VUB_OFF(vid));
325		MTKSWITCH_WRITE(sc, MTKSWITCH_VUB(vid), val);
326	}
327	val = MTKSWITCH_READ(sc, MTKSWITCH_POC2);
328	if (sc->sc_switchtype != MTK_SWITCH_RT3050)
329		val |= POC2_UNTAG_VLAN;
330	val |= ((1<<sc->numports)-1);
331	MTKSWITCH_WRITE(sc, MTKSWITCH_POC2, val);
332
333	/* only the first vlangroup is valid */
334	sc->valid_vlans = (1<<0);
335
336	/* Set all port PVIDs to 1 */
337	vid = 1;
338	for (i = 0; i < sc->info.es_nports; i++) {
339		val = MTKSWITCH_READ(sc, MTKSWITCH_PVID(i));
340		val &= ~(PVID_MASK << PVID_OFF(i));
341		val |= (vid << PVID_OFF(i));
342		MTKSWITCH_WRITE(sc, MTKSWITCH_PVID(i), val);
343	}
344
345	MTKSWITCH_UNLOCK(sc);
346}
347
348static int
349mtkswitch_vlan_getvgroup(struct mtkswitch_softc *sc, etherswitch_vlangroup_t *v)
350{
351	uint32_t val;
352
353	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
354
355	if ((sc->vlan_mode != ETHERSWITCH_VLAN_DOT1Q) ||
356	    (v->es_vlangroup > sc->info.es_nvlangroups))
357		return (EINVAL);
358
359	/* Reset the member ports. */
360	v->es_untagged_ports = 0;
361	v->es_member_ports = 0;
362
363	/* Not supported */
364	v->es_fid = 0;
365
366	/* Vlan ID */
367	v->es_vid = 0;
368	if ((sc->valid_vlans & (1<<v->es_vlangroup)) == 0)
369		return (0);
370
371	MTKSWITCH_LOCK(sc);
372	v->es_vid = (MTKSWITCH_READ(sc, MTKSWITCH_VLANI(v->es_vlangroup)) >>
373	    VLANI_OFF(v->es_vlangroup)) & VLANI_MASK;
374	v->es_vid |= ETHERSWITCH_VID_VALID;
375
376	/* Member ports */
377	v->es_member_ports = v->es_untagged_ports =
378	    (MTKSWITCH_READ(sc, MTKSWITCH_VMSC(v->es_vlangroup)) >>
379	    VMSC_OFF(v->es_vlangroup)) & VMSC_MASK;
380
381	val = MTKSWITCH_READ(sc, MTKSWITCH_POC2);
382
383	if ((val & POC2_UNTAG_VLAN) && sc->sc_switchtype != MTK_SWITCH_RT3050) {
384		val = (MTKSWITCH_READ(sc, MTKSWITCH_VUB(v->es_vlangroup)) >>
385		    VUB_OFF(v->es_vlangroup)) & VUB_MASK;
386	} else {
387		val &= VUB_MASK;
388	}
389	v->es_untagged_ports &= val;
390
391	MTKSWITCH_UNLOCK(sc);
392	return (0);
393}
394
395static int
396mtkswitch_vlan_setvgroup(struct mtkswitch_softc *sc, etherswitch_vlangroup_t *v)
397{
398	uint32_t val, tmp;
399
400	if ((sc->vlan_mode != ETHERSWITCH_VLAN_DOT1Q) ||
401	    (v->es_vlangroup > sc->info.es_nvlangroups))
402		return (EINVAL);
403
404	MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
405	MTKSWITCH_LOCK(sc);
406	/* First, see if we can accomodate the request at all */
407	val = MTKSWITCH_READ(sc, MTKSWITCH_POC2);
408	if ((val & POC2_UNTAG_VLAN) == 0 ||
409	    sc->sc_switchtype == MTK_SWITCH_RT3050) {
410		val &= VUB_MASK;
411		tmp = v->es_untagged_ports & v->es_member_ports;
412		if (val != tmp) {
413			/* Cannot accomodate request */
414			MTKSWITCH_UNLOCK(sc);
415			return (ENOTSUP);
416		}
417	} else {
418		/* Prefer per-Vlan untag and set its members */
419		val = MTKSWITCH_READ(sc, MTKSWITCH_VUB(v->es_vlangroup));
420		val &= ~(VUB_MASK << VUB_OFF(v->es_vlangroup));
421		val |= (((v->es_untagged_ports) & VUB_MASK) <<
422		    VUB_OFF(v->es_vlangroup));
423		MTKSWITCH_WRITE(sc, MTKSWITCH_VUB(v->es_vlangroup), val);
424	}
425
426	/* Set VID */
427	val = MTKSWITCH_READ(sc, MTKSWITCH_VLANI(v->es_vlangroup));
428	val &= ~(VLANI_MASK << VLANI_OFF(v->es_vlangroup));
429	val |= (v->es_vid & VLANI_MASK) << VLANI_OFF(v->es_vlangroup);
430	MTKSWITCH_WRITE(sc, MTKSWITCH_VLANI(v->es_vlangroup), val);
431
432	/* Set members */
433	val = MTKSWITCH_READ(sc, MTKSWITCH_VMSC(v->es_vlangroup));
434	val &= ~(VMSC_MASK << VMSC_OFF(v->es_vlangroup));
435	val |= (v->es_member_ports << VMSC_OFF(v->es_vlangroup));
436	MTKSWITCH_WRITE(sc, MTKSWITCH_VMSC(v->es_vlangroup), val);
437
438	sc->valid_vlans |= (1<<v->es_vlangroup);
439
440	MTKSWITCH_UNLOCK(sc);
441	return (0);
442}
443
444static int
445mtkswitch_vlan_get_pvid(struct mtkswitch_softc *sc, int port, int *pvid)
446{
447
448	MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
449	*pvid = (MTKSWITCH_READ(sc, MTKSWITCH_PVID(port)) >> PVID_OFF(port)) &
450	    PVID_MASK;
451
452	return (0);
453}
454
455static int
456mtkswitch_vlan_set_pvid(struct mtkswitch_softc *sc, int port, int pvid)
457{
458	uint32_t val;
459
460	MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
461	val = MTKSWITCH_READ(sc, MTKSWITCH_PVID(port));
462	val &= ~(PVID_MASK << PVID_OFF(port));
463	val |= (pvid & PVID_MASK) << PVID_OFF(port);
464	MTKSWITCH_WRITE(sc, MTKSWITCH_PVID(port), val);
465
466	return (0);
467}
468
469extern void
470mtk_attach_switch_rt3050(struct mtkswitch_softc *sc)
471{
472
473	sc->portmap = 0x7f;
474	sc->phymap = 0x1f;
475
476	sc->info.es_nports = 7;
477	sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q;
478	sc->info.es_nvlangroups = 16;
479	sprintf(sc->info.es_name, "Ralink ESW");
480
481	sc->hal.mtkswitch_reset = mtkswitch_reset;
482	sc->hal.mtkswitch_hw_setup = mtkswitch_hw_setup;
483	sc->hal.mtkswitch_hw_global_setup = mtkswitch_hw_global_setup;
484	sc->hal.mtkswitch_port_init = mtkswitch_port_init;
485	sc->hal.mtkswitch_get_port_status = mtkswitch_get_port_status;
486	sc->hal.mtkswitch_atu_flush = mtkswitch_atu_flush;
487	sc->hal.mtkswitch_port_vlan_setup = mtkswitch_port_vlan_setup;
488	sc->hal.mtkswitch_port_vlan_get = mtkswitch_port_vlan_get;
489	sc->hal.mtkswitch_vlan_init_hw = mtkswitch_vlan_init_hw;
490	sc->hal.mtkswitch_vlan_getvgroup = mtkswitch_vlan_getvgroup;
491	sc->hal.mtkswitch_vlan_setvgroup = mtkswitch_vlan_setvgroup;
492	sc->hal.mtkswitch_vlan_get_pvid = mtkswitch_vlan_get_pvid;
493	sc->hal.mtkswitch_vlan_set_pvid = mtkswitch_vlan_set_pvid;
494	sc->hal.mtkswitch_phy_read = mtkswitch_phy_read;
495	sc->hal.mtkswitch_phy_write = mtkswitch_phy_write;
496	sc->hal.mtkswitch_reg_read = mtkswitch_reg_read;
497	sc->hal.mtkswitch_reg_write = mtkswitch_reg_write;
498}
499