1/*
2 * Broadcom 53xx RoboSwitch device driver.
3 *
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: bcmrobo.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $
13 */
14
15
16#include <typedefs.h>
17#include <osl.h>
18#include <bcmutils.h>
19#include <sbutils.h>
20#include <sbconfig.h>
21#include <bcmutils.h>
22#include <bcmendian.h>
23#include <bcmparams.h>
24#include <bcmnvram.h>
25#include <bcmdevs.h>
26#include <bcmrobo.h>
27#include <proto/ethernet.h>
28
29#define	ET_ERROR(args)
30#define	ET_MSG(args)
31
32/*
33 * Switch can be programmed through SPI interface, which
34 * has a rreg and a wreg functions to read from and write to
35 * registers.
36 */
37
38/* MII access registers */
39#define PSEUDO_PHYAD	0x1E	/* MII Pseudo PHY address */
40#define REG_MII_PAGE	0x10	/* MII Page register */
41#define REG_MII_ADDR	0x11	/* MII Address register */
42#define REG_MII_DATA0	0x18	/* MII Data register 0 */
43#define REG_MII_DATA1	0x19	/* MII Data register 1 */
44#define REG_MII_DATA2	0x1a	/* MII Data register 2 */
45#define REG_MII_DATA3	0x1b	/* MII Data register 3 */
46
47/* Page numbers */
48#define PAGE_CTRL	0x00	/* Control page */
49#define PAGE_MMR	0x02	/* 5397 Management/Mirroring page */
50#define PAGE_VTBL	0x05	/* ARL/VLAN Table access page */
51#define PAGE_VLAN	0x34	/* VLAN page */
52
53/* Control page registers */
54#define REG_CTRL_PORT0	0x00	/* Port 0 traffic control register */
55#define REG_CTRL_PORT1	0x01	/* Port 1 traffic control register */
56#define REG_CTRL_PORT2	0x02	/* Port 2 traffic control register */
57#define REG_CTRL_PORT3	0x03	/* Port 3 traffic control register */
58#define REG_CTRL_PORT4	0x04	/* Port 4 traffic control register */
59#define REG_CTRL_PORT5	0x05	/* Port 5 traffic control register */
60#define REG_CTRL_PORT6	0x06	/* Port 6 traffic control register */
61#define REG_CTRL_PORT7	0x07	/* Port 7 traffic control register */
62#define REG_CTRL_MODE	0x0B	/* Switch Mode register */
63#define REG_CTRL_MIIPO	0x0E	/* 5325: MII Port Override register */
64#define REG_CTRL_SRST	0x79	/* Software reset control register */
65
66#define REG_DEVICE_ID	0x30	/* 539x Device id: */
67#define	DEVID5325	0x25	/*  5325 (Not really be we fake it) */
68#define	DEVID5395	0x95	/*  5395 */
69#define	DEVID5397	0x97	/*  5397 */
70#define	DEVID5398	0x98	/*  5398 */
71
72/* VLAN page registers */
73#define REG_VLAN_CTRL0	0x00	/* VLAN Control 0 register */
74#define REG_VLAN_CTRL1	0x01	/* VLAN Control 1 register */
75#define REG_VLAN_CTRL4	0x04	/* VLAN Control 4 register */
76#define REG_VLAN_CTRL5	0x05	/* VLAN Control 5 register */
77#define REG_VLAN_ACCESS	0x06	/* VLAN Table Access register */
78#define REG_VLAN_WRITE	0x08	/* VLAN Write register */
79#define REG_VLAN_READ	0x0C	/* VLAN Read register */
80#define REG_VLAN_PTAG0	0x10	/* VLAN Default Port Tag register - port 0 */
81#define REG_VLAN_PTAG1	0x12	/* VLAN Default Port Tag register - port 1 */
82#define REG_VLAN_PTAG2	0x14	/* VLAN Default Port Tag register - port 2 */
83#define REG_VLAN_PTAG3	0x16	/* VLAN Default Port Tag register - port 3 */
84#define REG_VLAN_PTAG4	0x18	/* VLAN Default Port Tag register - port 4 */
85#define REG_VLAN_PTAG5	0x1a	/* VLAN Default Port Tag register - port 5 */
86#define REG_VLAN_PTAG6	0x1c	/* VLAN Default Port Tag register - port 6 */
87#define REG_VLAN_PTAG7	0x1e	/* VLAN Default Port Tag register - port 7 */
88#define REG_VLAN_PTAG8	0x20	/* 539x: VLAN Default Port Tag register - IMP port */
89#define REG_VLAN_PMAP	0x20	/* 5325: VLAN Priority Re-map register */
90
91#define VLAN_NUMVLANS	16	/* # of VLANs */
92
93
94/* ARL/VLAN Table Access page registers */
95#define REG_VTBL_CTRL		0x00	/* ARL Read/Write Control */
96#define REG_VTBL_MINDX		0x02	/* MAC Address Index */
97#define REG_VTBL_VINDX		0x08	/* VID Table Index */
98#define REG_VTBL_ARL_E0		0x10	/* ARL Entry 0 */
99#define REG_VTBL_ARL_E1		0x18	/* ARL Entry 1 */
100#define REG_VTBL_DAT_E0		0x18	/* ARL Table Data Entry 0 */
101#define REG_VTBL_SCTRL		0x20	/* ARL Search Control */
102#define REG_VTBL_SADDR		0x22	/* ARL Search Address */
103#define REG_VTBL_SRES		0x24	/* ARL Search Result */
104#define REG_VTBL_SREXT		0x2c	/* ARL Search Result */
105#define REG_VTBL_VID_E0		0x30	/* VID Entry 0 */
106#define REG_VTBL_VID_E1		0x32	/* VID Entry 1 */
107#define REG_VTBL_PREG		0xFF	/* Page Register */
108#define REG_VTBL_ACCESS		0x60	/* VLAN table access register */
109#define REG_VTBL_INDX		0x61	/* VLAN table address index register */
110#define REG_VTBL_ENTRY		0x63	/* VLAN table entry register */
111#define REG_VTBL_ACCESS_5395	0x80	/* VLAN table access register */
112#define REG_VTBL_INDX_5395	0x81	/* VLAN table address index register */
113#define REG_VTBL_ENTRY_5395	0x83	/* VLAN table entry register */
114
115/* SPI registers */
116#define REG_SPI_PAGE	0xff	/* SPI Page register */
117
118/* Access switch registers through GPIO/SPI */
119
120/* Minimum timing constants */
121#define SCK_EDGE_TIME	2	/* clock edge duration - 2us */
122#define MOSI_SETUP_TIME	1	/* input setup duration - 1us */
123#define SS_SETUP_TIME	1 	/* select setup duration - 1us */
124
125/* misc. constants */
126#define SPI_MAX_RETRY	100
127
128/* Enable GPIO access to the chip */
129static void
130gpio_enable(robo_info_t *robo)
131{
132	/* Enable GPIO outputs with SCK and MOSI low, SS high */
133	sb_gpioout(robo->sbh, robo->ss | robo->sck | robo->mosi, robo->ss, GPIO_DRV_PRIORITY);
134	sb_gpioouten(robo->sbh, robo->ss | robo->sck | robo->mosi,
135	             robo->ss | robo->sck | robo->mosi, GPIO_DRV_PRIORITY);
136}
137
138/* Disable GPIO access to the chip */
139static void
140gpio_disable(robo_info_t *robo)
141{
142	/* Disable GPIO outputs with all their current values */
143	sb_gpioouten(robo->sbh, robo->ss | robo->sck | robo->mosi, 0, GPIO_DRV_PRIORITY);
144}
145
146/* Write a byte stream to the chip thru SPI */
147static int
148spi_write(robo_info_t *robo, uint8 *buf, uint len)
149{
150	uint i;
151	uint8 mask;
152
153	/* Byte bang from LSB to MSB */
154	for (i = 0; i < len; i++) {
155		/* Bit bang from MSB to LSB */
156		for (mask = 0x80; mask; mask >>= 1) {
157			/* Clock low */
158			sb_gpioout(robo->sbh, robo->sck, 0, GPIO_DRV_PRIORITY);
159			OSL_DELAY(SCK_EDGE_TIME);
160
161			/* Sample on rising edge */
162			if (mask & buf[i])
163				sb_gpioout(robo->sbh, robo->mosi, robo->mosi, GPIO_DRV_PRIORITY);
164			else
165				sb_gpioout(robo->sbh, robo->mosi, 0, GPIO_DRV_PRIORITY);
166			OSL_DELAY(MOSI_SETUP_TIME);
167
168			/* Clock high */
169			sb_gpioout(robo->sbh, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
170			OSL_DELAY(SCK_EDGE_TIME);
171		}
172	}
173
174	return 0;
175}
176
177/* Read a byte stream from the chip thru SPI */
178static int
179spi_read(robo_info_t *robo, uint8 *buf, uint len)
180{
181	uint i, timeout;
182	uint8 rack, mask, byte;
183
184	/* Timeout after 100 tries without RACK */
185	for (i = 0, rack = 0, timeout = SPI_MAX_RETRY; i < len && timeout;) {
186		/* Bit bang from MSB to LSB */
187		for (mask = 0x80, byte = 0; mask; mask >>= 1) {
188			/* Clock low */
189			sb_gpioout(robo->sbh, robo->sck, 0, GPIO_DRV_PRIORITY);
190			OSL_DELAY(SCK_EDGE_TIME);
191
192			/* Sample on falling edge */
193			if (sb_gpioin(robo->sbh) & robo->miso)
194				byte |= mask;
195
196			/* Clock high */
197			sb_gpioout(robo->sbh, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
198			OSL_DELAY(SCK_EDGE_TIME);
199		}
200		/* RACK when bit 0 is high */
201		if (!rack) {
202			rack = (byte & 1);
203			timeout--;
204			continue;
205		}
206		/* Byte bang from LSB to MSB */
207		buf[i] = byte;
208		i++;
209	}
210
211	if (timeout == 0) {
212		ET_ERROR(("spi_read: timeout"));
213		return -1;
214	}
215
216	return 0;
217}
218
219/* Enable/disable SPI access */
220static void
221spi_select(robo_info_t *robo, uint8 spi)
222{
223	if (spi) {
224		/* Enable SPI access */
225		sb_gpioout(robo->sbh, robo->ss, 0, GPIO_DRV_PRIORITY);
226	} else {
227		/* Disable SPI access */
228		sb_gpioout(robo->sbh, robo->ss, robo->ss, GPIO_DRV_PRIORITY);
229	}
230	OSL_DELAY(SS_SETUP_TIME);
231}
232
233
234/* Select chip and page */
235static void
236spi_goto(robo_info_t *robo, uint8 page)
237{
238	uint8 reg8 = REG_SPI_PAGE;	/* page select register */
239	uint8 cmd8;
240
241	/* Issue the command only when we are on a different page */
242	if (robo->page == page)
243		return;
244
245	robo->page = page;
246
247	/* Enable SPI access */
248	spi_select(robo, 1);
249
250	/* Select new page with CID 0 */
251	cmd8 = ((6 << 4) |		/* normal SPI */
252	        1);			/* write */
253	spi_write(robo, &cmd8, 1);
254	spi_write(robo, &reg8, 1);
255	spi_write(robo, &page, 1);
256
257	/* Disable SPI access */
258	spi_select(robo, 0);
259}
260
261/* Write register thru SPI */
262static int
263spi_wreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
264{
265	int status = 0;
266	uint8 cmd8;
267	union {
268		uint8 val8;
269		uint16 val16;
270		uint32 val32;
271	} bytes;
272
273	/* validate value length and buffer address */
274	ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
275	       (len == 4 && !((int)val & 3)));
276
277	/* Select chip and page */
278	spi_goto(robo, page);
279
280	/* Enable SPI access */
281	spi_select(robo, 1);
282
283	/* Write with CID 0 */
284	cmd8 = ((6 << 4) |		/* normal SPI */
285	        1);			/* write */
286	spi_write(robo, &cmd8, 1);
287	spi_write(robo, &addr, 1);
288	switch (len) {
289	case 1:
290		bytes.val8 = *(uint8 *)val;
291		break;
292	case 2:
293		bytes.val16 = htol16(*(uint16 *)val);
294		break;
295	case 4:
296		bytes.val32 = htol32(*(uint32 *)val);
297		break;
298	}
299	spi_write(robo, (uint8 *)val, len);
300
301	ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, addr,
302	        *(uint16 *)val, len));
303	/* Disable SPI access */
304	spi_select(robo, 0);
305	return status;
306}
307
308/* Read register thru SPI in fast SPI mode */
309static int
310spi_rreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
311{
312	int status = 0;
313	uint8 cmd8;
314	union {
315		uint8 val8;
316		uint16 val16;
317		uint32 val32;
318	} bytes;
319
320	/* validate value length and buffer address */
321	ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
322	       (len == 4 && !((int)val & 3)));
323
324	/* Select chip and page */
325	spi_goto(robo, page);
326
327	/* Enable SPI access */
328	spi_select(robo, 1);
329
330	/* Fast SPI read with CID 0 and byte offset 0 */
331	cmd8 = (1 << 4);		/* fast SPI */
332	spi_write(robo, &cmd8, 1);
333	spi_write(robo, &addr, 1);
334	status = spi_read(robo, (uint8 *)&bytes, len);
335	switch (len) {
336	case 1:
337		*(uint8 *)val = bytes.val8;
338		break;
339	case 2:
340		*(uint16 *)val = ltoh16(bytes.val16);
341		break;
342	case 4:
343		*(uint32 *)val = ltoh32(bytes.val32);
344		break;
345	}
346
347	ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, addr,
348	        *(uint16 *)val, len));
349
350	/* Disable SPI access */
351	spi_select(robo, 0);
352	return status;
353}
354
355/* SPI/gpio interface functions */
356static dev_ops_t spigpio = {
357	gpio_enable,
358	gpio_disable,
359	spi_wreg,
360	spi_rreg,
361	"SPI (GPIO)"
362};
363
364
365/* Access switch registers through MII (MDC/MDIO) */
366
367#define MII_MAX_RETRY	100
368
369/* Write register thru MDC/MDIO */
370static int
371mii_wreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
372{
373	uint16 cmd16, val16;
374	void *h = robo->h;
375	int i;
376	uint8 *ptr = (uint8 *)val;
377
378	/* validate value length and buffer address */
379	ASSERT(len == 1 || len == 6 || len == 8 ||
380	       ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
381
382	ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, reg,
383	          *(uint16 *)val, len));
384
385	/* set page number - MII register 0x10 */
386	if (robo->page != page) {
387		cmd16 = ((page << 8) |		/* page number */
388		         1);			/* mdc/mdio access enable */
389		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
390		robo->page = page;
391	}
392
393	switch (len) {
394	case 8:
395		val16 = ptr[7];
396		val16 = ((val16 << 8) | ptr[6]);
397		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA3, val16);
398		/* FALLTHRU */
399
400	case 6:
401		val16 = ptr[5];
402		val16 = ((val16 << 8) | ptr[4]);
403		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA2, val16);
404		val16 = ptr[3];
405		val16 = ((val16 << 8) | ptr[2]);
406		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
407		val16 = ptr[1];
408		val16 = ((val16 << 8) | ptr[0]);
409		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
410		break;
411
412	case 4:
413		val16 = (uint16)((*(uint32 *)val) >> 16);
414		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
415		val16 = (uint16)(*(uint32 *)val);
416		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
417		break;
418
419	case 2:
420		val16 = *(uint16 *)val;
421		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
422		break;
423
424	case 1:
425		val16 = *(uint8 *)val;
426		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
427		break;
428	}
429
430	/* set register address - MII register 0x11 */
431	cmd16 = ((reg << 8) |		/* register address */
432	         1);		/* opcode write */
433	robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
434
435	/* is operation finished? */
436	for (i = MII_MAX_RETRY; i > 0; i --) {
437		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
438		if ((val16 & 3) == 0)
439			break;
440	}
441
442	/* timed out */
443	if (!i) {
444		ET_ERROR(("mii_wreg: timeout"));
445		return -1;
446	}
447	return 0;
448}
449
450/* Read register thru MDC/MDIO */
451static int
452mii_rreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
453{
454	uint16 cmd16, val16;
455	void *h = robo->h;
456	int i;
457	uint8 *ptr = (uint8 *)val;
458
459	/* validate value length and buffer address */
460	ASSERT(len == 1 || len == 6 || len == 8 ||
461	       ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
462
463	/* set page number - MII register 0x10 */
464	if (robo->page != page) {
465		cmd16 = ((page << 8) |		/* page number */
466		         1);			/* mdc/mdio access enable */
467		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
468		robo->page = page;
469	}
470
471	/* set register address - MII register 0x11 */
472	cmd16 = ((reg << 8) |		/* register address */
473	         2);			/* opcode read */
474	robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
475
476	/* is operation finished? */
477	for (i = MII_MAX_RETRY; i > 0; i --) {
478		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
479		if ((val16 & 3) == 0)
480			break;
481	}
482	/* timed out */
483	if (!i) {
484		ET_ERROR(("mii_rreg: timeout"));
485		return -1;
486	}
487
488	ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, reg, val16, len));
489
490	switch (len) {
491	case 8:
492		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA3);
493		ptr[7] = (val16 >> 8);
494		ptr[6] = (val16 & 0xff);
495		/* FALLTHRU */
496
497	case 6:
498		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA2);
499		ptr[5] = (val16 >> 8);
500		ptr[4] = (val16 & 0xff);
501		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
502		ptr[3] = (val16 >> 8);
503		ptr[2] = (val16 & 0xff);
504		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
505		ptr[1] = (val16 >> 8);
506		ptr[0] = (val16 & 0xff);
507		break;
508
509	case 4:
510		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
511		*(uint32 *)val = (((uint32)val16) << 16);
512		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
513		*(uint32 *)val |= val16;
514		break;
515
516	case 2:
517		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
518		*(uint16 *)val = val16;
519		break;
520
521	case 1:
522		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
523		*(uint8 *)val = (uint8)(val16 & 0xff);
524		break;
525	}
526
527	return 0;
528}
529
530/* MII interface functions */
531static dev_ops_t mdcmdio = {
532	NULL,
533	NULL,
534	mii_wreg,
535	mii_rreg,
536	"MII (MDC/MDIO)"
537};
538
539/* High level switch configuration functions. */
540
541/* Get access to the RoboSwitch */
542robo_info_t *
543bcm_robo_attach(sb_t *sbh, void *h, char *vars, miird_f miird, miiwr_f miiwr)
544{
545	robo_info_t *robo;
546	uint32 reset, idx;
547
548	/* Allocate and init private state */
549	if (!(robo = MALLOC(sb_osh(sbh), sizeof(robo_info_t)))) {
550		ET_ERROR(("robo_attach: out of memory, malloced %d bytes", MALLOCED(sb_osh(sbh))));
551		return NULL;
552	}
553	bzero(robo, sizeof(robo_info_t));
554
555	robo->h = h;
556	robo->sbh = sbh;
557	robo->vars = vars;
558	robo->miird = miird;
559	robo->miiwr = miiwr;
560	robo->page = -1;
561
562	/* Trigger external reset by nvram variable existance */
563	if ((reset = getgpiopin(robo->vars, "robo_reset", GPIO_PIN_NOTDEFINED)) !=
564	    GPIO_PIN_NOTDEFINED) {
565		/*
566		 * Reset sequence: RESET low(50ms)->high(20ms)
567		 *
568		 * We have to perform a full sequence for we don't know how long
569		 * it has been from power on till now.
570		 */
571		ET_MSG(("%s: Using external reset in gpio pin %d\n", __FUNCTION__, reset));
572		reset = 1 << reset;
573
574		/* Keep RESET low for 50 ms */
575		sb_gpioout(robo->sbh, reset, 0, GPIO_DRV_PRIORITY);
576		sb_gpioouten(robo->sbh, reset, reset, GPIO_DRV_PRIORITY);
577		bcm_mdelay(50);
578
579		/* Keep RESET high for at least 20 ms */
580		sb_gpioout(robo->sbh, reset, reset, GPIO_DRV_PRIORITY);
581		bcm_mdelay(20);
582	} else {
583		/* In case we need it */
584		idx = sb_coreidx(robo->sbh);
585
586		if (sb_setcore(robo->sbh, SB_ROBO, 0)) {
587			/* If we have an internal robo core, reset it using sb_core_reset */
588			ET_MSG(("%s: Resetting internal robo core\n", __FUNCTION__));
589			sb_core_reset(robo->sbh, 0, 0);
590		}
591
592		sb_setcoreidx(robo->sbh, idx);
593	}
594
595	if (miird && miiwr) {
596		uint16 tmp;
597		int rc, retry_count = 0;
598
599		/* Read the PHY ID */
600		tmp = miird(h, PSEUDO_PHYAD, 2);
601		if (tmp != 0xffff) {
602			do {
603				rc = mii_rreg(robo, PAGE_MMR, REG_DEVICE_ID, \
604							  &robo->devid, sizeof(uint16));
605				if (rc != 0)
606					break;
607				retry_count++;
608			} while ((robo->devid == 0) && (retry_count < 10));
609
610			ET_MSG(("%s: devid read %ssuccesfully via mii: 0x%x\n", __FUNCTION__, \
611			        rc ? "un" : "", robo->devid));
612			ET_MSG(("%s: mii access to switch works\n", __FUNCTION__));
613			robo->ops = &mdcmdio;
614			if ((rc != 0) || (robo->devid == 0)) {
615				ET_MSG(("%s: error reading devid, assuming 5325e\n", __FUNCTION__));
616				robo->devid = DEVID5325;
617			}
618			ET_MSG(("%s: devid: 0x%x\n", __FUNCTION__, robo->devid));
619		}
620	}
621
622	if ((robo->devid == DEVID5395) ||
623	    (robo->devid == DEVID5397) ||
624	    (robo->devid == DEVID5398)) {
625		uint8 srst_ctrl;
626
627		/* If it is a 539x switch, use the soft reset register */
628		ET_MSG(("%s: Resetting 539x robo switch\n", __FUNCTION__));
629
630		/* Reset the 539x switch core and register file */
631		srst_ctrl = 0x83;
632		mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
633		srst_ctrl = 0x00;
634		mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
635	}
636
637	if (!robo->ops) {
638		int mosi, miso, ss, sck;
639
640		robo->ops = &spigpio;
641		robo->devid = DEVID5325;
642
643		/* Init GPIO mapping. Default 2, 3, 4, 5 */
644		ss = getgpiopin(vars, "robo_ss", 2);
645		if (ss == GPIO_PIN_NOTDEFINED) {
646			ET_ERROR(("robo_attach: robo_ss gpio fail: GPIO 2 in use"));
647			goto error;
648		}
649		robo->ss = 1 << ss;
650		sck = getgpiopin(vars, "robo_sck", 3);
651		if (sck == GPIO_PIN_NOTDEFINED) {
652			ET_ERROR(("robo_attach: robo_sck gpio fail: GPIO 3 in use"));
653			goto error;
654		}
655		robo->sck = 1 << sck;
656		mosi = getgpiopin(vars, "robo_mosi", 4);
657		if (mosi == GPIO_PIN_NOTDEFINED) {
658			ET_ERROR(("robo_attach: robo_mosi gpio fail: GPIO 4 in use"));
659			goto error;
660		}
661		robo->mosi = 1 << mosi;
662		miso = getgpiopin(vars, "robo_miso", 5);
663		if (miso == GPIO_PIN_NOTDEFINED) {
664			ET_ERROR(("robo_attach: robo_miso gpio fail: GPIO 5 in use"));
665			goto error;
666		}
667		robo->miso = 1 << miso;
668		ET_MSG(("%s: ss %d sck %d mosi %d miso %d\n", __FUNCTION__,
669		        ss, sck, mosi, miso));
670	}
671
672	/* sanity check */
673	ASSERT(robo->ops);
674	ASSERT(robo->ops->write_reg);
675	ASSERT(robo->ops->read_reg);
676	ASSERT((robo->devid == DEVID5325) ||
677	       (robo->devid == DEVID5395) ||
678	       (robo->devid == DEVID5397) ||
679	       (robo->devid == DEVID5398));
680
681	return robo;
682
683error:
684	bcm_robo_detach(robo);
685	return NULL;
686}
687
688/* Release access to the RoboSwitch */
689void
690bcm_robo_detach(robo_info_t *robo)
691{
692	MFREE(sb_osh(robo->sbh), robo, sizeof(robo_info_t));
693}
694
695/* Enable the device and set it to a known good state */
696int
697bcm_robo_enable_device(robo_info_t *robo)
698{
699	uint8 reg_offset, reg_val;
700	int ret = 0;
701
702	/* Enable management interface access */
703	if (robo->ops->enable_mgmtif)
704		robo->ops->enable_mgmtif(robo);
705
706	if (robo->devid == DEVID5398) {
707		/* Disable unused ports: port 6 and 7 */
708		for (reg_offset = REG_CTRL_PORT6; reg_offset <= REG_CTRL_PORT7; reg_offset ++) {
709			/* Set bits [1:0] to disable RX and TX */
710			reg_val = 0x03;
711			robo->ops->write_reg(robo, PAGE_CTRL, reg_offset, &reg_val,
712			                     sizeof(reg_val));
713		}
714	}
715
716	if (robo->devid == DEVID5325) {
717		/* Must put the switch into Reverse MII mode! */
718
719		/* MII port state override (page 0 register 14) */
720		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val, sizeof(reg_val));
721
722		/* Bit 4 enables reverse MII mode */
723		if (!(reg_val & (1 << 4))) {
724			/* Enable RvMII */
725			reg_val |= (1 << 4);
726			robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
727			                     sizeof(reg_val));
728
729			/* Read back */
730			robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
731			                    sizeof(reg_val));
732			if (!(reg_val & (1 << 4))) {
733				ET_ERROR(("robo_enable_device: enabling RvMII mode failed\n"));
734				ret = -1;
735			}
736		}
737	}
738
739	/* Disable management interface access */
740	if (robo->ops->disable_mgmtif)
741		robo->ops->disable_mgmtif(robo);
742
743	return ret;
744}
745
746/* Port flags */
747#define FLAG_TAGGED	't'	/* output tagged (external ports only) */
748#define FLAG_UNTAG	'u'	/* input & output untagged (CPU port only, for OS (linux, ...) */
749#define FLAG_LAN	'*'	/* input & output untagged (CPU port only, for CFE */
750
751/* port descriptor */
752typedef	struct {
753	uint32 untag;	/* untag enable bit (Page 0x05 Address 0x63-0x66 Bit[17:9]) */
754	uint32 member;	/* vlan member bit (Page 0x05 Address 0x63-0x66 Bit[7:0]) */
755	uint8 ptagr;	/* port tag register address (Page 0x34 Address 0x10-0x1F) */
756	uint8 cpu;	/* is this cpu port? */
757} pdesc_t;
758
759pdesc_t pdesc97[] = {
760	/* 5395/5397/5398 is 0 ~ 7.  port 8 is IMP port. */
761	/* port 0 */ {1 << 9, 1 << 0, REG_VLAN_PTAG0, 0},
762	/* port 1 */ {1 << 10, 1 << 1, REG_VLAN_PTAG1, 0},
763	/* port 2 */ {1 << 11, 1 << 2, REG_VLAN_PTAG2, 0},
764	/* port 3 */ {1 << 12, 1 << 3, REG_VLAN_PTAG3, 0},
765	/* port 4 */ {1 << 13, 1 << 4, REG_VLAN_PTAG4, 0},
766	/* port 5 */ {1 << 14, 1 << 5, REG_VLAN_PTAG5, 0},
767	/* port 6 */ {1 << 15, 1 << 6, REG_VLAN_PTAG6, 0},
768	/* port 7 */ {1 << 16, 1 << 7, REG_VLAN_PTAG7, 0},
769	/* mii port */ {1 << 17, 1 << 8, REG_VLAN_PTAG8, 1},
770};
771
772pdesc_t pdesc25[] = {
773	/* port 0 */ {1 << 6, 1 << 0, REG_VLAN_PTAG0, 0},
774	/* port 1 */ {1 << 7, 1 << 1, REG_VLAN_PTAG1, 0},
775	/* port 2 */ {1 << 8, 1 << 2, REG_VLAN_PTAG2, 0},
776	/* port 3 */ {1 << 9, 1 << 3, REG_VLAN_PTAG3, 0},
777	/* port 4 */ {1 << 10, 1 << 4, REG_VLAN_PTAG4, 0},
778	/* mii port */ {1 << 11, 1 << 5, REG_VLAN_PTAG5, 1},
779};
780
781/* Configure the VLANs */
782int
783bcm_robo_config_vlan(robo_info_t *robo, uint8 *mac_addr)
784{
785	uint8 val8;
786	uint16 val16;
787	uint32 val32;
788	pdesc_t *pdesc;
789	int pdescsz;
790	uint16 vid;
791	uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 };
792
793	/* Enable management interface access */
794	if (robo->ops->enable_mgmtif)
795		robo->ops->enable_mgmtif(robo);
796
797	/* setup global vlan configuration */
798	/* VLAN Control 0 Register (Page 0x34, Address 0) */
799	val8 = ((1 << 7) |		/* enable 802.1Q VLAN */
800	        (3 << 5));		/* individual VLAN learning mode */
801	robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
802
803	/* VLAN Control 1 Register (Page 0x34, Address 1) */
804	val8 = ((1 << 2) |		/* enable RSV multicast V Fwdmap */
805		(1 << 3));		/* enable RSV multicast V Untagmap */
806	if (robo->devid == DEVID5325)
807		val8 |= (1 << 1);	/* enable RSV multicast V Tagging */
808	robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
809
810	arl_entry[0] = mac_addr[5];
811	arl_entry[1] = mac_addr[4];
812	arl_entry[2] = mac_addr[3];
813	arl_entry[3] = mac_addr[2];
814	arl_entry[4] = mac_addr[1];
815	arl_entry[5] = mac_addr[0];
816
817	if (robo->devid == DEVID5325) {
818		/* Init the entry 1 of the bin */
819		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1, \
820				     arl_entry1, sizeof(arl_entry1));
821		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1, \
822				     arl_entry1, 1);
823
824		/* Init the entry 0 of the bin */
825		arl_entry[6] = 0x8;		/* Port Id: MII */
826		arl_entry[7] = 0xc0;	/* Static Entry, Valid */
827
828		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \
829				     arl_entry, sizeof(arl_entry));
830		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \
831				     arl_entry, ETHER_ADDR_LEN);
832
833		/* VLAN Control 4 Register (Page 0x34, Address 4) */
834		val8 = (1 << 6);		/* drop frame with VID violation */
835		robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8));
836
837		/* VLAN Control 5 Register (Page 0x34, Address 5) */
838		val8 = (1 << 3);		/* drop frame when miss V table */
839		robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8));
840
841		pdesc = pdesc25;
842		pdescsz = sizeof(pdesc25) / sizeof(pdesc_t);
843	} else {
844		/* Initialize the MAC Addr Index Register */
845		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \
846				     arl_entry, ETHER_ADDR_LEN);
847
848		pdesc = pdesc97;
849		pdescsz = sizeof(pdesc97) / sizeof(pdesc_t);
850	}
851
852	/* setup each vlan. max. 16 vlans. */
853	/* force vlan id to be equal to vlan number */
854	for (vid = 0; vid < VLAN_NUMVLANS; vid ++) {
855		char vlanports[] = "vlanXXXXports";
856		char port[] = "XXXX", *ports, *next, *cur;
857		uint32 untag = 0;
858		uint32 member = 0;
859		int pid, len;
860
861		/* no members if VLAN id is out of limitation */
862		if (vid > VLAN_MAXVID)
863			goto vlan_setup;
864
865		/* get vlan member ports from nvram */
866		sprintf(vlanports, "vlan%dports", vid);
867		ports = getvar(robo->vars, vlanports);
868
869		/* In 539x vid == 0 us invalid?? */
870		if ((robo->devid != DEVID5325) && (vid == 0)) {
871			if (ports)
872				ET_ERROR(("VID 0 is set in nvram, Ignoring\n"));
873			continue;
874		}
875
876		/* disable this vlan if not defined */
877		if (!ports)
878			goto vlan_setup;
879
880		/*
881		 * setup each port in the vlan. cpu port needs special handing
882		 * (with or without output tagging) to support linux/pmon/cfe.
883		 */
884		for (cur = ports; cur; cur = next) {
885			/* tokenize the port list */
886			while (*cur == ' ')
887				cur ++;
888			next = bcmstrstr(cur, " ");
889			len = next ? next - cur : strlen(cur);
890			if (!len)
891				break;
892			if (len > sizeof(port) - 1)
893				len = sizeof(port) - 1;
894			strncpy(port, cur, len);
895			port[len] = 0;
896
897			/* make sure port # is within the range */
898			pid = bcm_atoi(port);
899			if (pid >= pdescsz) {
900				ET_ERROR(("robo_config_vlan: port %d in vlan%dports is out "
901				          "of range[0-%d]\n", pid, vid, pdescsz));
902				continue;
903			}
904
905			/* build VLAN registers values */
906#ifndef	_CFE_
907			if ((!pdesc[pid].cpu && !strchr(port, FLAG_TAGGED)) ||
908			    (pdesc[pid].cpu && strchr(port, FLAG_UNTAG)))
909#endif
910				untag |= pdesc[pid].untag;
911
912			member |= pdesc[pid].member;
913
914			/* set port tag - applies to untagged ingress frames */
915			/* Default Port Tag Register (Page 0x34, Address 0x10-0x1D) */
916#ifdef	_CFE_
917#define	FL	FLAG_LAN
918#else
919#define	FL	FLAG_UNTAG
920#endif /* _CFE_ */
921			if (!pdesc[pid].cpu || strchr(port, FL)) {
922				val16 = ((0 << 13) |		/* priority - always 0 */
923				         vid);			/* vlan id */
924				robo->ops->write_reg(robo, PAGE_VLAN, pdesc[pid].ptagr,
925				                     &val16, sizeof(val16));
926			}
927		}
928
929		/* Add static ARL entries */
930		if (robo->devid == DEVID5325) {
931			val8 = vid;
932			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E0, \
933					     &val8, sizeof(val8));
934			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX, \
935					     &val8, sizeof(val8));
936
937			/* Write the entry */
938			val8 = 0x80;
939			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
940					     &val8, sizeof(val8));
941			/* Wait for write to complete */
942			SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
943				 &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
944				 100 /* usec */);
945		} else {
946			/* Set the VLAN Id in VLAN ID Index Register */
947			val8 = vid;
948			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX, \
949					     &val8, sizeof(val8));
950
951			/* Set the MAC addr and VLAN Id in ARL Table MAC/VID Entry 0
952			 * Register.
953			 */
954			arl_entry[6] = vid;
955			arl_entry[7] = 0x0;
956			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \
957					     arl_entry, sizeof(arl_entry));
958
959			/* Set the Static bit , Valid bit and Port ID fields in
960			 * ARL Table Data Entry 0 Register
961			 */
962			val16 = 0xc008;
963			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_DAT_E0, \
964					     &val16, sizeof(val16));
965
966			/* Clear the ARL_R/W bit and set the START/DONE bit in
967			 * the ARL Read/Write Control Register.
968			 */
969			val8 = 0x80;
970			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
971					     &val8, sizeof(val8));
972			/* Wait for write to complete */
973			SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
974				 &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
975				 100 /* usec */);
976		}
977
978vlan_setup:
979		/* setup VLAN ID and VLAN memberships */
980
981		val32 = (untag |			/* untag enable */
982		         member);			/* vlan members */
983		if (robo->devid == DEVID5325) {
984			val32 |= ((1 << 20) |		/* valid write */
985			          ((vid >> 4) << 12));	/* vlan id bit[11:4] */
986			/* VLAN Write Register (Page 0x34, Address 0x08-0x0B) */
987			robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_WRITE, &val32,
988			                     sizeof(val32));
989			/* VLAN Table Access Register (Page 0x34, Address 0x06-0x07) */
990			val16 = ((1 << 13) |	/* start command */
991			         (1 << 12) |	/* write state */
992			         vid);		/* vlan id */
993			robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_ACCESS, &val16,
994			                     sizeof(val16));
995		} else {
996			uint8 vtble, vtbli, vtbla;
997
998			if (robo->devid == DEVID5395) {
999				vtble = REG_VTBL_ENTRY_5395;
1000				vtbli = REG_VTBL_INDX_5395;
1001				vtbla = REG_VTBL_ACCESS_5395;
1002			} else {
1003				vtble = REG_VTBL_ENTRY;
1004				vtbli = REG_VTBL_INDX;
1005				vtbla = REG_VTBL_ACCESS;
1006			}
1007
1008			/* VLAN Table Entry Register (Page 0x05, Address 0x63-0x66/0x83-0x86) */
1009			robo->ops->write_reg(robo, PAGE_VTBL, vtble, &val32,
1010			                     sizeof(val32));
1011			/* VLAN Table Address Index Reg (Page 0x05, Address 0x61-0x62/0x81-0x82) */
1012			val16 = vid;        /* vlan id */
1013			robo->ops->write_reg(robo, PAGE_VTBL, vtbli, &val16,
1014			                     sizeof(val16));
1015
1016			/* VLAN Table Access Register (Page 0x34, Address 0x60/0x80) */
1017			val8 = ((1 << 7) | 	/* start command */
1018			        0);	        /* write */
1019			robo->ops->write_reg(robo, PAGE_VTBL, vtbla, &val8,
1020			                     sizeof(val8));
1021		}
1022	}
1023
1024	if (robo->devid == DEVID5325) {
1025		/* setup priority mapping - applies to tagged ingress frames */
1026		/* Priority Re-map Register (Page 0x34, Address 0x20-0x23) */
1027		val32 = ((0 << 0) |	/* 0 -> 0 */
1028		         (1 << 3) |	/* 1 -> 1 */
1029		         (2 << 6) |	/* 2 -> 2 */
1030		         (3 << 9) |	/* 3 -> 3 */
1031		         (4 << 12) |	/* 4 -> 4 */
1032		         (5 << 15) |	/* 5 -> 5 */
1033		         (6 << 18) |	/* 6 -> 6 */
1034		         (7 << 21));	/* 7 -> 7 */
1035		robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_PMAP, &val32, sizeof(val32));
1036	}
1037
1038	/* Disable management interface access */
1039	if (robo->ops->disable_mgmtif)
1040		robo->ops->disable_mgmtif(robo);
1041
1042	return 0;
1043}
1044
1045/* Enable switching/forwarding */
1046int
1047bcm_robo_enable_switch(robo_info_t *robo)
1048{
1049	int i, max_port_ind, ret = 0;
1050	uint8 val8;
1051	uint32 aging;
1052
1053	/* Enable management interface access */
1054	if (robo->ops->enable_mgmtif)
1055		robo->ops->enable_mgmtif(robo);
1056
1057	/* Switch Mode register (Page 0, Address 0x0B) */
1058	robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1059
1060	/* Bit 1 enables switching/forwarding */
1061	if (!(val8 & (1 << 1))) {
1062		/* Set unmanaged mode */
1063		val8 &= (~(1 << 0));
1064
1065		/* Enable forwarding */
1066		val8 |= (1 << 1);
1067		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1068
1069		/* Read back */
1070		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1071		if (!(val8 & (1 << 1))) {
1072			ET_ERROR(("robo_enable_switch: enabling forwarding failed\n"));
1073			ret = -1;
1074		}
1075
1076		/* No spanning tree for unmanaged mode */
1077		val8 = 0;
1078		max_port_ind = ((robo->devid == DEVID5398) ? REG_CTRL_PORT7 : REG_CTRL_PORT4);
1079		for (i = REG_CTRL_PORT0; i <= max_port_ind; i++) {
1080			robo->ops->write_reg(robo, PAGE_CTRL, i, &val8, sizeof(val8));
1081		}
1082	}
1083
1084	/* Disable management interface access */
1085	if (robo->ops->disable_mgmtif)
1086		robo->ops->disable_mgmtif(robo);
1087
1088	aging = 0x10;   /* set to 16s. default is 768s. */
1089	robo->ops->write_reg(robo, 0x02, 0x06, &aging, sizeof(aging));
1090
1091	return ret;
1092}
1093
1094