1/*
2 * Broadcom 53xx RoboSwitch device driver.
3 *
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: bcmrobo.c,v 1.35.10.5 2010-10-14 22:36:02 Exp $
19 */
20
21
22#include <typedefs.h>
23#include <osl.h>
24#include <bcmutils.h>
25#include <siutils.h>
26#include <hndsoc.h>
27#include <bcmutils.h>
28#include <bcmendian.h>
29#include <bcmparams.h>
30#include <bcmnvram.h>
31#include <bcmdevs.h>
32#include <bcmrobo.h>
33#include <proto/ethernet.h>
34#include <hndpmu.h>
35
36#define	ET_ERROR(args)
37#define	ET_MSG(args)
38
39#define VARG(var, len) (((len) == 1) ? *((uint8 *)(var)) : \
40		        ((len) == 2) ? *((uint16 *)(var)) : \
41		        *((uint32 *)(var)))
42
43/*
44 * Switch can be programmed through SPI interface, which
45 * has a rreg and a wreg functions to read from and write to
46 * registers.
47 */
48
49/* MII access registers */
50#define PSEUDO_PHYAD	0x1E	/* MII Pseudo PHY address */
51#define REG_MII_CTRL    0x00    /* 53115 MII control register */
52#define REG_MII_PAGE	0x10	/* MII Page register */
53#define REG_MII_ADDR	0x11	/* MII Address register */
54#define REG_MII_DATA0	0x18	/* MII Data register 0 */
55#define REG_MII_DATA1	0x19	/* MII Data register 1 */
56#define REG_MII_DATA2	0x1a	/* MII Data register 2 */
57#define REG_MII_DATA3	0x1b	/* MII Data register 3 */
58#define REG_MII_AUX_STATUS2	0x1b	/* Auxiliary status 2 register */
59#define REG_MII_AUTO_PWRDOWN	0x1c	/* 53115 Auto power down register */
60#define REG_MII_BRCM_TEST	0x1f	/* Broadcom test register */
61
62/* Page numbers */
63#define PAGE_CTRL	0x00	/* Control page */
64#define PAGE_STATUS	0x01	/* Status page */
65#define PAGE_MMR	0x02	/* 5397 Management/Mirroring page */
66#define PAGE_VTBL	0x05	/* ARL/VLAN Table access page */
67#define PAGE_QOS    0x30    /* QoS page, Foxconn added pling 01/31/2007 */
68#define PAGE_VLAN	0x34	/* VLAN page */
69
70/* Control page registers */
71#define REG_CTRL_PORT0	0x00	/* Port 0 traffic control register */
72#define REG_CTRL_PORT1	0x01	/* Port 1 traffic control register */
73#define REG_CTRL_PORT2	0x02	/* Port 2 traffic control register */
74#define REG_CTRL_PORT3	0x03	/* Port 3 traffic control register */
75#define REG_CTRL_PORT4	0x04	/* Port 4 traffic control register */
76#define REG_CTRL_PORT5	0x05	/* Port 5 traffic control register */
77#define REG_CTRL_PORT6	0x06	/* Port 6 traffic control register */
78#define REG_CTRL_PORT7	0x07	/* Port 7 traffic control register */
79#define REG_CTRL_IMP	0x08	/* IMP port traffic control register */
80#define REG_CTRL_MODE	0x0B	/* Switch Mode register */
81#define REG_CTRL_MIIPO	0x0E	/* 5325: MII Port Override register */
82#define REG_CTRL_PWRDOWN 0x0F   /* 5325: Power Down Mode register */
83#define REG_CTRL_SRST	0x79	/* Software reset control register */
84#define REG_CTRL_MIIP5O	0x5d	/* 53115: Port State Override register for port 5 */
85
86/* Management/Mirroring Registers */
87#define REG_MMR_ATCR	0x06	/* Aging Time Control register */
88#define REG_MMR_MCCR	0x10	/* Mirror Capture Control register */
89#define REG_MMR_IMCR	0x12	/* Ingress Mirror Control register */
90
91/* Status Page Registers */
92#define REG_STATUS_LINK	0x00	/* Link Status Summary */
93#define REG_STATUS_REV	0x50	/* Revision Register */
94
95#define REG_DEVICE_ID	0x30	/* 539x Device id: */
96
97/* Foxconn added start pling 12/04/2006 */
98/* Foxconn modify by aspen Bai, 09/02/2008, for 53115S Giga switch on bcm4718 */
99/* Status page registers */
100#if (defined BCM4716) || (defined BCM5356) || (defined BCM5325E)
101/* 5325E & 5325F */
102#define REG_LINK_SUM    0x00    /* Link Status summary register, 16-bit */
103#define REG_SPEED_SUM   0x04    /* Port speed summary register, 16-bit */
104#define REG_DUPLEX_SUM  0x06    /* Duplex status summary register, 16-bit */
105#else
106/* 53115S */
107#define REG_LINK_SUM    0x00    /* Link Status summary register, 16-bit */
108#define REG_SPEED_SUM   0x04    /* Port speed summary register, 32-bit */
109#define REG_DUPLEX_SUM  0x08    /* Duplex status summary register, 16-bit */
110#endif
111/* Foxconn added end pling 12/04/2006 */
112
113/* Foxconn added start pling 01/31/2007 */
114#define REG_QOS_CTRL        0x00    /* QoS Control Register */
115#define REG_QOS_PRIO_CTRL   0x02    /* QoS Priority Control Register */
116#define REG_QOS_DSCP_ENABLE 0x06    /* QoS DiffServ Enable Register */
117#define REG_QOS_DSCP_PRIO   0x30    /* QoS DiffServ Priority Register */
118/* Foxconn added end pling 01/31/2007 */
119
120/* VLAN page registers */
121#define REG_VLAN_CTRL0	0x00	/* VLAN Control 0 register */
122#define REG_VLAN_CTRL1	0x01	/* VLAN Control 1 register */
123#define REG_VLAN_CTRL4	0x04	/* VLAN Control 4 register */
124#define REG_VLAN_CTRL5	0x05	/* VLAN Control 5 register */
125#define REG_VLAN_ACCESS	0x06	/* VLAN Table Access register */
126#define REG_VLAN_WRITE	0x08	/* VLAN Write register */
127#define REG_VLAN_READ	0x0C	/* VLAN Read register */
128#define REG_VLAN_PTAG0	0x10	/* VLAN Default Port Tag register - port 0 */
129#define REG_VLAN_PTAG1	0x12	/* VLAN Default Port Tag register - port 1 */
130#define REG_VLAN_PTAG2	0x14	/* VLAN Default Port Tag register - port 2 */
131#define REG_VLAN_PTAG3	0x16	/* VLAN Default Port Tag register - port 3 */
132#define REG_VLAN_PTAG4	0x18	/* VLAN Default Port Tag register - port 4 */
133#define REG_VLAN_PTAG5	0x1a	/* VLAN Default Port Tag register - port 5 */
134#define REG_VLAN_PTAG6	0x1c	/* VLAN Default Port Tag register - port 6 */
135#define REG_VLAN_PTAG7	0x1e	/* VLAN Default Port Tag register - port 7 */
136#define REG_VLAN_PTAG8	0x20	/* 539x: VLAN Default Port Tag register - IMP port */
137#define REG_VLAN_PMAP	0x20	/* 5325: VLAN Priority Re-map register */
138
139#define VLAN_NUMVLANS	16	/* # of VLANs */
140
141
142/* ARL/VLAN Table Access page registers */
143#define REG_VTBL_CTRL		0x00	/* ARL Read/Write Control */
144#define REG_VTBL_MINDX		0x02	/* MAC Address Index */
145#define REG_VTBL_VINDX		0x08	/* VID Table Index */
146#define REG_VTBL_ARL_E0		0x10	/* ARL Entry 0 */
147#define REG_VTBL_ARL_E1		0x18	/* ARL Entry 1 */
148#define REG_VTBL_DAT_E0		0x18	/* ARL Table Data Entry 0 */
149#define REG_VTBL_SCTRL		0x20	/* ARL Search Control */
150#define REG_VTBL_SADDR		0x22	/* ARL Search Address */
151#define REG_VTBL_SRES		0x24	/* ARL Search Result */
152#define REG_VTBL_SREXT		0x2c	/* ARL Search Result */
153#define REG_VTBL_VID_E0		0x30	/* VID Entry 0 */
154#define REG_VTBL_VID_E1		0x32	/* VID Entry 1 */
155#define REG_VTBL_PREG		0xFF	/* Page Register */
156#define REG_VTBL_ACCESS		0x60	/* VLAN table access register */
157#define REG_VTBL_INDX		0x61	/* VLAN table address index register */
158#define REG_VTBL_ENTRY		0x63	/* VLAN table entry register */
159#define REG_VTBL_ACCESS_5395	0x80	/* VLAN table access register */
160#define REG_VTBL_INDX_5395	0x81	/* VLAN table address index register */
161#define REG_VTBL_ENTRY_5395	0x83	/* VLAN table entry register */
162
163#ifndef	_CFE_
164/* SPI registers */
165#define REG_SPI_PAGE	0xff	/* SPI Page register */
166
167/* Access switch registers through GPIO/SPI */
168
169/* Minimum timing constants */
170#define SCK_EDGE_TIME	2	/* clock edge duration - 2us */
171#define MOSI_SETUP_TIME	1	/* input setup duration - 1us */
172#define SS_SETUP_TIME	1 	/* select setup duration - 1us */
173
174/* Foxconn add start by Lewis Min, 04/02/2008, for igmp snooping */
175#ifdef __CONFIG_IGMP_SNOOPING__
176igmp_snooping_table_t snooping_table[2];
177int is_reg_snooping_enable = 0;
178#endif
179/* Foxconn add end by Lewis Min, 04/02/2008, for igmp snooping */
180
181#if defined(INCLUDE_QOS) || defined(__CONFIG_IGMP_SNOOPING__)
182int is_reg_mgmt_mode_enable = 0;
183#endif
184
185/* misc. constants */
186#define SPI_MAX_RETRY	100
187
188static robo_info_t *robo_ptr = NULL;    /* Foxconn added pling 08/10/2006 */
189
190/* Foxconn added start pling 11/23/2010 */
191/* make this global and export it, for 'et_bridge' module to use
192 * (Needed by WNR3500L Samknows) */
193void* get_robo_ptr(void)
194{
195    return (void *)robo_ptr;
196}
197
198//EXPORT_SYMBOL(get_robo_ptr);
199/* Foxconn added end pling 11/23/2010 */
200
201/* foxconn added start, zacker, 01/13/2012, @iptv_igmp */
202#if defined(CONFIG_RUSSIA_IPTV)
203static uint16 iptv_ports = 0x00;
204void set_iptv_ports(robo_info_t *robo)
205{
206    char *iptv_enabled;
207
208    iptv_ports = 0x00;
209    iptv_enabled = getvar(robo->vars, "iptv_enabled");
210    if (iptv_enabled && (strcmp(iptv_enabled, "1") == 0))
211    {
212        unsigned int iptv_intf_val = 0x00;
213        char iptv_intf[8];
214
215        /* get iptv ports from nvram */
216        if (getvar(robo->vars, "iptv_interfaces"))
217        {
218           strcpy(iptv_intf, getvar(robo->vars, "iptv_interfaces"));
219           sscanf(iptv_intf, "0x%02X", &iptv_intf_val);
220           if (iptv_intf_val & 0x01)
221               iptv_ports |= 1 << (LABEL_PORT_TO_ROBO_PORT(1));
222           if (iptv_intf_val & 0x02)
223               iptv_ports |= 1 << (LABEL_PORT_TO_ROBO_PORT(2));
224           if (iptv_intf_val & 0x04)
225               iptv_ports |= 1 << (LABEL_PORT_TO_ROBO_PORT(3));
226           if (iptv_intf_val & 0x08)
227               iptv_ports |= 1 << (LABEL_PORT_TO_ROBO_PORT(4));
228        }
229    }
230}
231
232uint16 get_iptv_ports(void)
233{
234    return iptv_ports;
235}
236
237int is_iptv_port(int port)
238{
239    if (port >= ROBO_LAN_PORT_IDX_START
240        && port <= ROBO_LAN_PORT_IDX_END)
241    {
242        if ((1 << port) & get_iptv_ports())
243            return 1;
244    }
245
246    return 0;
247}
248#endif
249/* foxconn modified start, zacker, 01/13/2012, @iptv_igmp */
250
251/* Enable GPIO access to the chip */
252static void
253gpio_enable(robo_info_t *robo)
254{
255	/* Enable GPIO outputs with SCK and MOSI low, SS high */
256	si_gpioout(robo->sih, robo->ss | robo->sck | robo->mosi, robo->ss, GPIO_DRV_PRIORITY);
257	si_gpioouten(robo->sih, robo->ss | robo->sck | robo->mosi,
258	             robo->ss | robo->sck | robo->mosi, GPIO_DRV_PRIORITY);
259}
260
261/* Disable GPIO access to the chip */
262static void
263gpio_disable(robo_info_t *robo)
264{
265	/* Disable GPIO outputs with all their current values */
266	si_gpioouten(robo->sih, robo->ss | robo->sck | robo->mosi, 0, GPIO_DRV_PRIORITY);
267}
268
269/* Write a byte stream to the chip thru SPI */
270static int
271spi_write(robo_info_t *robo, uint8 *buf, uint len)
272{
273	uint i;
274	uint8 mask;
275
276	/* Byte bang from LSB to MSB */
277	for (i = 0; i < len; i++) {
278		/* Bit bang from MSB to LSB */
279		for (mask = 0x80; mask; mask >>= 1) {
280			/* Clock low */
281			si_gpioout(robo->sih, robo->sck, 0, GPIO_DRV_PRIORITY);
282			OSL_DELAY(SCK_EDGE_TIME);
283
284			/* Sample on rising edge */
285			if (mask & buf[i])
286				si_gpioout(robo->sih, robo->mosi, robo->mosi, GPIO_DRV_PRIORITY);
287			else
288				si_gpioout(robo->sih, robo->mosi, 0, GPIO_DRV_PRIORITY);
289			OSL_DELAY(MOSI_SETUP_TIME);
290
291			/* Clock high */
292			si_gpioout(robo->sih, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
293			OSL_DELAY(SCK_EDGE_TIME);
294		}
295	}
296
297	return 0;
298}
299
300/* Read a byte stream from the chip thru SPI */
301static int
302spi_read(robo_info_t *robo, uint8 *buf, uint len)
303{
304	uint i, timeout;
305	uint8 rack, mask, byte;
306
307	/* Timeout after 100 tries without RACK */
308	for (i = 0, rack = 0, timeout = SPI_MAX_RETRY; i < len && timeout;) {
309		/* Bit bang from MSB to LSB */
310		for (mask = 0x80, byte = 0; mask; mask >>= 1) {
311			/* Clock low */
312			si_gpioout(robo->sih, robo->sck, 0, GPIO_DRV_PRIORITY);
313			OSL_DELAY(SCK_EDGE_TIME);
314
315			/* Sample on falling edge */
316			if (si_gpioin(robo->sih) & robo->miso)
317				byte |= mask;
318
319			/* Clock high */
320			si_gpioout(robo->sih, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
321			OSL_DELAY(SCK_EDGE_TIME);
322		}
323		/* RACK when bit 0 is high */
324		if (!rack) {
325			rack = (byte & 1);
326			timeout--;
327			continue;
328		}
329		/* Byte bang from LSB to MSB */
330		buf[i] = byte;
331		i++;
332	}
333
334	if (timeout == 0) {
335		ET_ERROR(("spi_read: timeout"));
336		return -1;
337	}
338
339	return 0;
340}
341
342/* Enable/disable SPI access */
343static void
344spi_select(robo_info_t *robo, uint8 spi)
345{
346	if (spi) {
347		/* Enable SPI access */
348		si_gpioout(robo->sih, robo->ss, 0, GPIO_DRV_PRIORITY);
349	} else {
350		/* Disable SPI access */
351		si_gpioout(robo->sih, robo->ss, robo->ss, GPIO_DRV_PRIORITY);
352	}
353	OSL_DELAY(SS_SETUP_TIME);
354}
355
356
357/* Select chip and page */
358static void
359spi_goto(robo_info_t *robo, uint8 page)
360{
361	uint8 reg8 = REG_SPI_PAGE;	/* page select register */
362	uint8 cmd8;
363
364	/* Issue the command only when we are on a different page */
365	if (robo->page == page)
366		return;
367
368	robo->page = page;
369
370	/* Enable SPI access */
371	spi_select(robo, 1);
372
373	/* Select new page with CID 0 */
374	cmd8 = ((6 << 4) |		/* normal SPI */
375	        1);			/* write */
376	spi_write(robo, &cmd8, 1);
377	spi_write(robo, &reg8, 1);
378	spi_write(robo, &page, 1);
379
380	/* Disable SPI access */
381	spi_select(robo, 0);
382}
383
384/* Write register thru SPI */
385static int
386spi_wreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
387{
388	int status = 0;
389	uint8 cmd8;
390	union {
391		uint8 val8;
392		uint16 val16;
393		uint32 val32;
394	} bytes;
395
396	/* validate value length and buffer address */
397	ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
398	       (len == 4 && !((int)val & 3)));
399
400	/* Select chip and page */
401	spi_goto(robo, page);
402
403	/* Enable SPI access */
404	spi_select(robo, 1);
405
406	/* Write with CID 0 */
407	cmd8 = ((6 << 4) |		/* normal SPI */
408	        1);			/* write */
409	spi_write(robo, &cmd8, 1);
410	spi_write(robo, &addr, 1);
411	switch (len) {
412	case 1:
413		bytes.val8 = *(uint8 *)val;
414		break;
415	case 2:
416		bytes.val16 = htol16(*(uint16 *)val);
417		break;
418	case 4:
419		bytes.val32 = htol32(*(uint32 *)val);
420		break;
421	}
422	spi_write(robo, (uint8 *)val, len);
423
424	ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, addr,
425	        *(uint16 *)val, len));
426	/* Disable SPI access */
427	spi_select(robo, 0);
428	return status;
429}
430
431/* Read register thru SPI in fast SPI mode */
432static int
433spi_rreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
434{
435	int status = 0;
436	uint8 cmd8;
437	union {
438		uint8 val8;
439		uint16 val16;
440		uint32 val32;
441	} bytes;
442
443	/* validate value length and buffer address */
444	ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
445	       (len == 4 && !((int)val & 3)));
446
447	/* Select chip and page */
448	spi_goto(robo, page);
449
450	/* Enable SPI access */
451	spi_select(robo, 1);
452
453	/* Fast SPI read with CID 0 and byte offset 0 */
454	cmd8 = (1 << 4);		/* fast SPI */
455	spi_write(robo, &cmd8, 1);
456	spi_write(robo, &addr, 1);
457	status = spi_read(robo, (uint8 *)&bytes, len);
458	switch (len) {
459	case 1:
460		*(uint8 *)val = bytes.val8;
461		break;
462	case 2:
463		*(uint16 *)val = ltoh16(bytes.val16);
464		break;
465	case 4:
466		*(uint32 *)val = ltoh32(bytes.val32);
467		break;
468	}
469
470	ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, addr,
471	        *(uint16 *)val, len));
472
473	/* Disable SPI access */
474	spi_select(robo, 0);
475	return status;
476}
477
478/* SPI/gpio interface functions */
479static dev_ops_t spigpio = {
480	gpio_enable,
481	gpio_disable,
482	spi_wreg,
483	spi_rreg,
484	"SPI (GPIO)"
485};
486#endif /* _CFE_ */
487
488
489/* Access switch registers through MII (MDC/MDIO) */
490
491#define MII_MAX_RETRY	100
492
493/* Write register thru MDC/MDIO */
494static int
495mii_wreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
496{
497	uint16 cmd16, val16;
498	void *h = robo->h;
499	int i;
500	uint8 *ptr = (uint8 *)val;
501
502	/* validate value length and buffer address */
503	ASSERT(len == 1 || len == 6 || len == 8 ||
504	       ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
505
506	ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, reg,
507	       VARG(val, len), len));
508
509	/* set page number - MII register 0x10 */
510	if (robo->page != page) {
511		cmd16 = ((page << 8) |		/* page number */
512		         1);			/* mdc/mdio access enable */
513		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
514		robo->page = page;
515	}
516
517	switch (len) {
518	case 8:
519		val16 = ptr[7];
520		val16 = ((val16 << 8) | ptr[6]);
521		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA3, val16);
522		/* FALLTHRU */
523
524	case 6:
525		val16 = ptr[5];
526		val16 = ((val16 << 8) | ptr[4]);
527		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA2, val16);
528		val16 = ptr[3];
529		val16 = ((val16 << 8) | ptr[2]);
530		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
531		val16 = ptr[1];
532		val16 = ((val16 << 8) | ptr[0]);
533		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
534		break;
535
536	case 4:
537		val16 = (uint16)((*(uint32 *)val) >> 16);
538		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
539		val16 = (uint16)(*(uint32 *)val);
540		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
541		break;
542
543	case 2:
544		val16 = *(uint16 *)val;
545		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
546		break;
547
548	case 1:
549		val16 = *(uint8 *)val;
550		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
551		break;
552	}
553
554	/* set register address - MII register 0x11 */
555	cmd16 = ((reg << 8) |		/* register address */
556	         1);		/* opcode write */
557	robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
558
559	/* is operation finished? */
560	for (i = MII_MAX_RETRY; i > 0; i --) {
561		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
562		if ((val16 & 3) == 0)
563			break;
564	}
565
566	/* timed out */
567	if (!i) {
568		ET_ERROR(("mii_wreg: timeout"));
569		return -1;
570	}
571	return 0;
572}
573
574/* Read register thru MDC/MDIO */
575static int
576mii_rreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
577{
578	uint16 cmd16, val16;
579	void *h = robo->h;
580	int i;
581	uint8 *ptr = (uint8 *)val;
582
583	/* validate value length and buffer address */
584	ASSERT(len == 1 || len == 6 || len == 8 ||
585	       ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
586
587	/* set page number - MII register 0x10 */
588	if (robo->page != page) {
589		cmd16 = ((page << 8) |		/* page number */
590		         1);			/* mdc/mdio access enable */
591		robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
592		robo->page = page;
593	}
594
595	/* set register address - MII register 0x11 */
596	cmd16 = ((reg << 8) |		/* register address */
597	         2);			/* opcode read */
598	robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
599
600	/* is operation finished? */
601	for (i = MII_MAX_RETRY; i > 0; i --) {
602		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
603		if ((val16 & 3) == 0)
604			break;
605	}
606	/* timed out */
607	if (!i) {
608		ET_ERROR(("mii_rreg: timeout"));
609		return -1;
610	}
611
612	switch (len) {
613	case 8:
614		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA3);
615		ptr[7] = (val16 >> 8);
616		ptr[6] = (val16 & 0xff);
617		/* FALLTHRU */
618
619	case 6:
620		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA2);
621		ptr[5] = (val16 >> 8);
622		ptr[4] = (val16 & 0xff);
623		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
624		ptr[3] = (val16 >> 8);
625		ptr[2] = (val16 & 0xff);
626		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
627		ptr[1] = (val16 >> 8);
628		ptr[0] = (val16 & 0xff);
629		break;
630
631	case 4:
632		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
633		*(uint32 *)val = (((uint32)val16) << 16);
634		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
635		*(uint32 *)val |= val16;
636		break;
637
638	case 2:
639		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
640		*(uint16 *)val = val16;
641		break;
642
643	case 1:
644		val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
645		*(uint8 *)val = (uint8)(val16 & 0xff);
646		break;
647	}
648
649	ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, reg,
650	       VARG(val, len), len));
651
652	return 0;
653}
654
655/* MII interface functions */
656static dev_ops_t mdcmdio = {
657	NULL,
658	NULL,
659	mii_wreg,
660	mii_rreg,
661	"MII (MDC/MDIO)"
662};
663
664/* High level switch configuration functions. */
665
666/* Get access to the RoboSwitch */
667robo_info_t *
668bcm_robo_attach(si_t *sih, void *h, char *vars, miird_f miird, miiwr_f miiwr)
669{
670	robo_info_t *robo;
671	uint32 reset, idx;
672#ifndef	_CFE_
673	char *et1port, *et1phyaddr;
674	int mdcport = 0, phyaddr = 0, lan_portenable = 0;
675#endif /* _CFE_ */
676
677	/* Allocate and init private state */
678	if (!(robo = MALLOC(si_osh(sih), sizeof(robo_info_t)))) {
679		ET_ERROR(("robo_attach: out of memory, malloced %d bytes",
680		          MALLOCED(si_osh(sih))));
681		return NULL;
682	}
683	bzero(robo, sizeof(robo_info_t));
684
685	robo->h = h;
686	robo->sih = sih;
687	robo->vars = vars;
688	robo->miird = miird;
689	robo->miiwr = miiwr;
690	robo->page = -1;
691
692#ifndef	_CFE_
693	/* Enable center tap voltage for LAN ports using gpio23. Usefull in case when
694	 * romboot CFE loads linux over WAN port and Linux enables LAN ports later
695	 */
696	if ((lan_portenable = getgpiopin(robo->vars, "lanports_enable", GPIO_PIN_NOTDEFINED)) !=
697	    GPIO_PIN_NOTDEFINED) {
698		lan_portenable = 1 << lan_portenable;
699		si_gpioout(sih, lan_portenable, lan_portenable, GPIO_DRV_PRIORITY);
700		si_gpioouten(sih, lan_portenable, lan_portenable, GPIO_DRV_PRIORITY);
701		bcm_mdelay(5);
702	}
703#endif /* _CFE_ */
704
705    /* Foxconn modified start pling 12/05/2006 */
706    /* Don't reset the switch to avoid unncessary link down/link up */
707	/* Trigger external reset by nvram variable existance */
708#if 0
709	if ((reset = getgpiopin(robo->vars, "robo_reset", GPIO_PIN_NOTDEFINED)) !=
710	    GPIO_PIN_NOTDEFINED) {
711#endif
712    if (0) {
713    /* Foxconn modified end pling 12/05/2006 */
714		/*
715		 * Reset sequence: RESET low(50ms)->high(20ms)
716		 *
717		 * We have to perform a full sequence for we don't know how long
718		 * it has been from power on till now.
719		 */
720		ET_MSG(("%s: Using external reset in gpio pin %d\n", __FUNCTION__, reset));
721		reset = 1 << reset;
722
723		/* Keep RESET low for 50 ms */
724		si_gpioout(sih, reset, 0, GPIO_DRV_PRIORITY);
725		si_gpioouten(sih, reset, reset, GPIO_DRV_PRIORITY);
726		bcm_mdelay(50);
727
728		/* Keep RESET high for at least 20 ms */
729		si_gpioout(sih, reset, reset, GPIO_DRV_PRIORITY);
730		bcm_mdelay(20);
731	} else {
732		/* In case we need it */
733		idx = si_coreidx(sih);
734
735		if (si_setcore(sih, ROBO_CORE_ID, 0)) {
736			/* If we have an internal robo core, reset it using si_core_reset */
737			ET_MSG(("%s: Resetting internal robo core\n", __FUNCTION__));
738			si_core_reset(sih, 0, 0);
739			robo->corerev = si_corerev(sih);
740		}
741		else if (sih->chip == BCM5356_CHIP_ID) {
742			/* Testing chipid is a temporary hack. We need to really
743			 * figure out how to treat non-cores in ai chips.
744			 */
745			robo->corerev = 3;
746		}
747		else {
748			mii_rreg(robo, PAGE_STATUS, REG_STATUS_REV, &robo->corerev, 1);
749		}
750		si_setcoreidx(sih, idx);
751		ET_MSG(("%s: Internal robo rev %d\n", __FUNCTION__, robo->corerev));
752	}
753
754	if (miird && miiwr) {
755		uint16 tmp;
756		int rc, retry_count = 0;
757
758		/* Read the PHY ID */
759		tmp = miird(h, PSEUDO_PHYAD, 2);
760
761		/* WAR: Enable mdc/mdio access to the switch registers. Unless
762		 * a write to bit 0 of pseudo phy register 16 is done we are
763		 * unable to talk to the switch on a customer ref design.
764		 */
765		if (tmp == 0xffff) {
766			miiwr(h, PSEUDO_PHYAD, 16, 1);
767			tmp = miird(h, PSEUDO_PHYAD, 2);
768		}
769
770		if (tmp != 0xffff) {
771			do {
772				rc = mii_rreg(robo, PAGE_MMR, REG_DEVICE_ID,
773				              &robo->devid, sizeof(uint16));
774				if (rc != 0)
775					break;
776				retry_count++;
777			} while ((robo->devid == 0) && (retry_count < 10));
778
779			ET_MSG(("%s: devid read %ssuccesfully via mii: 0x%x\n",
780			        __FUNCTION__, rc ? "un" : "", robo->devid));
781			ET_MSG(("%s: mii access to switch works\n", __FUNCTION__));
782			robo->ops = &mdcmdio;
783			if ((rc != 0) || (robo->devid == 0)) {
784				ET_MSG(("%s: error reading devid, assuming 5325e\n",
785				        __FUNCTION__));
786				robo->devid = DEVID5325;
787			}
788		}
789		ET_MSG(("%s: devid: 0x%x\n", __FUNCTION__, robo->devid));
790	}
791
792	if ((robo->devid == DEVID5395) ||
793	    (robo->devid == DEVID5397) ||
794	    (robo->devid == DEVID5398)) {
795		uint8 srst_ctrl;
796
797		/* If it is a 539x switch, use the soft reset register */
798		ET_MSG(("%s: Resetting 539x robo switch\n", __FUNCTION__));
799
800		/* Reset the 539x switch core and register file */
801		srst_ctrl = 0x83;
802		mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
803		srst_ctrl = 0x00;
804		mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
805	}
806
807	/* Enable switch leds */
808	if (sih->chip == BCM5356_CHIP_ID) {
809		si_pmu_chipcontrol(sih, 2, (1 << 25), (1 << 25));
810	} else if ((sih->chip == BCM5357_CHIP_ID) || (sih->chip == BCM53572_CHIP_ID)) {
811		uint32 led_gpios = 0;
812		char *var;
813
814		if ((sih->chippkg != BCM47186_PKG_ID) && (sih->chippkg != BCM47188_PKG_ID))
815			led_gpios = 0x1f;
816		var = getvar(vars, "et_swleds");
817		if (var)
818			led_gpios = bcm_strtoul(var, NULL, 0);
819		if (led_gpios)
820			si_pmu_chipcontrol(sih, 2, (0x3ff << 8), (led_gpios << 8));
821	}
822
823#ifndef	_CFE_
824	if (!robo->ops) {
825		int mosi, miso, ss, sck;
826
827		robo->ops = &spigpio;
828		robo->devid = DEVID5325;
829
830		/* Init GPIO mapping. Default 2, 3, 4, 5 */
831		ss = getgpiopin(vars, "robo_ss", 2);
832		if (ss == GPIO_PIN_NOTDEFINED) {
833			ET_ERROR(("robo_attach: robo_ss gpio fail: GPIO 2 in use"));
834			goto error;
835		}
836		robo->ss = 1 << ss;
837		sck = getgpiopin(vars, "robo_sck", 3);
838		if (sck == GPIO_PIN_NOTDEFINED) {
839			ET_ERROR(("robo_attach: robo_sck gpio fail: GPIO 3 in use"));
840			goto error;
841		}
842		robo->sck = 1 << sck;
843		mosi = getgpiopin(vars, "robo_mosi", 4);
844		if (mosi == GPIO_PIN_NOTDEFINED) {
845			ET_ERROR(("robo_attach: robo_mosi gpio fail: GPIO 4 in use"));
846			goto error;
847		}
848		robo->mosi = 1 << mosi;
849		miso = getgpiopin(vars, "robo_miso", 5);
850		if (miso == GPIO_PIN_NOTDEFINED) {
851			ET_ERROR(("robo_attach: robo_miso gpio fail: GPIO 5 in use"));
852			goto error;
853		}
854		robo->miso = 1 << miso;
855		ET_MSG(("%s: ss %d sck %d mosi %d miso %d\n", __FUNCTION__,
856		        ss, sck, mosi, miso));
857	}
858#endif /* _CFE_ */
859
860	/* sanity check */
861	ASSERT(robo->ops);
862	ASSERT(robo->ops->write_reg);
863	ASSERT(robo->ops->read_reg);
864	ASSERT((robo->devid == DEVID5325) ||
865	       (robo->devid == DEVID5395) ||
866	       (robo->devid == DEVID5397) ||
867	       (robo->devid == DEVID5398) ||
868	       (robo->devid == DEVID53115) ||
869	       (robo->devid == DEVID53125));
870
871#ifndef	_CFE_
872	/* nvram variable switch_mode controls the power save mode on the switch
873	 * set the default value in the beginning
874	 */
875	robo->pwrsave_mode_manual = getintvar(robo->vars, "switch_mode_manual");
876	robo->pwrsave_mode_auto = getintvar(robo->vars, "switch_mode_auto");
877
878	/* Determining what all phys need to be included in
879	 * power save operation
880	 */
881	et1port = getvar(vars, "et1mdcport");
882	if (et1port)
883		mdcport = bcm_atoi(et1port);
884
885	et1phyaddr = getvar(vars, "et1phyaddr");
886	if (et1phyaddr)
887		phyaddr = bcm_atoi(et1phyaddr);
888
889	if ((mdcport == 0) && (phyaddr == 4))
890		/* For 5325F switch we need to do only phys 0-3 */
891		robo->pwrsave_phys = 0xf;
892	else
893		/* By default all 5 phys are put into power save if there is no link */
894		robo->pwrsave_phys = 0x1f;
895#endif /* _CFE_ */
896
897#ifdef PLC
898	/* See if one of the ports is connected to plc chipset */
899	robo->plc_hw = (getvar(vars, "plc_vifs") != NULL);
900#endif /* PLC */
901    /* Foxconn added start pling 08/10/2006 */
902    /* Store pointer to robo */
903    robo_ptr = robo;
904    /* Foxconn added end pling 08/10/2006 */
905
906	return robo;
907
908#ifndef	_CFE_
909error:
910	bcm_robo_detach(robo);
911	return NULL;
912#endif /* _CFE_ */
913}
914
915/* Release access to the RoboSwitch */
916void
917bcm_robo_detach(robo_info_t *robo)
918{
919	MFREE(si_osh(robo->sih), robo, sizeof(robo_info_t));
920}
921
922/* Enable the device and set it to a known good state */
923int
924bcm_robo_enable_device(robo_info_t *robo)
925{
926	uint8 reg_offset, reg_val;
927	int ret = 0;
928#ifdef PLC
929	uint32 val32;
930#endif /* PLC */
931
932	/* Enable management interface access */
933	if (robo->ops->enable_mgmtif)
934		robo->ops->enable_mgmtif(robo);
935
936	if (robo->devid == DEVID5398) {
937		/* Disable unused ports: port 6 and 7 */
938		for (reg_offset = REG_CTRL_PORT6; reg_offset <= REG_CTRL_PORT7; reg_offset ++) {
939			/* Set bits [1:0] to disable RX and TX */
940			reg_val = 0x03;
941			robo->ops->write_reg(robo, PAGE_CTRL, reg_offset, &reg_val,
942			                     sizeof(reg_val));
943		}
944	}
945
946	if (robo->devid == DEVID5325) {
947		/* Must put the switch into Reverse MII mode! */
948
949		/* MII port state override (page 0 register 14) */
950		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val, sizeof(reg_val));
951
952		/* Bit 4 enables reverse MII mode */
953		if (!(reg_val & (1 << 4))) {
954			/* Enable RvMII */
955			reg_val |= (1 << 4);
956			robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
957			                     sizeof(reg_val));
958
959			/* Read back */
960			robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
961			                    sizeof(reg_val));
962			if (!(reg_val & (1 << 4))) {
963				ET_ERROR(("robo_enable_device: enabling RvMII mode failed\n"));
964				ret = -1;
965			}
966		}
967	}
968
969#ifdef PLC
970	if (robo->plc_hw) {
971		val32 = 0x100002;
972		robo->ops->write_reg(robo, PAGE_MMR, REG_MMR_ATCR, &val32, sizeof(val32));
973	}
974#endif /* PLC */
975
976	/* Disable management interface access */
977	if (robo->ops->disable_mgmtif)
978		robo->ops->disable_mgmtif(robo);
979
980	return ret;
981}
982
983/* Port flags */
984#define FLAG_TAGGED	't'	/* output tagged (external ports only) */
985#define FLAG_UNTAG	'u'	/* input & output untagged (CPU port only, for OS (linux, ...) */
986#define FLAG_LAN	'*'	/* input & output untagged (CPU port only, for CFE */
987
988/* port descriptor */
989typedef	struct {
990	uint32 untag;	/* untag enable bit (Page 0x05 Address 0x63-0x66 Bit[17:9]) */
991	uint32 member;	/* vlan member bit (Page 0x05 Address 0x63-0x66 Bit[7:0]) */
992	uint8 ptagr;	/* port tag register address (Page 0x34 Address 0x10-0x1F) */
993	uint8 cpu;	/* is this cpu port? */
994} pdesc_t;
995
996pdesc_t pdesc97[] = {
997	/* 5395/5397/5398/53115S is 0 ~ 7.  port 8 is IMP port. */
998	/* port 0 */ {1 << 9, 1 << 0, REG_VLAN_PTAG0, 0},
999	/* port 1 */ {1 << 10, 1 << 1, REG_VLAN_PTAG1, 0},
1000	/* port 2 */ {1 << 11, 1 << 2, REG_VLAN_PTAG2, 0},
1001	/* port 3 */ {1 << 12, 1 << 3, REG_VLAN_PTAG3, 0},
1002	/* port 4 */ {1 << 13, 1 << 4, REG_VLAN_PTAG4, 0},
1003	/* port 5 */ {1 << 14, 1 << 5, REG_VLAN_PTAG5, 0},
1004	/* port 6 */ {1 << 15, 1 << 6, REG_VLAN_PTAG6, 0},
1005	/* port 7 */ {1 << 16, 1 << 7, REG_VLAN_PTAG7, 0},
1006	/* mii port */ {1 << 17, 1 << 8, REG_VLAN_PTAG8, 1},
1007};
1008
1009pdesc_t pdesc25[] = {
1010	/* port 0 */ {1 << 6, 1 << 0, REG_VLAN_PTAG0, 0},
1011	/* port 1 */ {1 << 7, 1 << 1, REG_VLAN_PTAG1, 0},
1012	/* port 2 */ {1 << 8, 1 << 2, REG_VLAN_PTAG2, 0},
1013	/* port 3 */ {1 << 9, 1 << 3, REG_VLAN_PTAG3, 0},
1014	/* port 4 */ {1 << 10, 1 << 4, REG_VLAN_PTAG4, 0},
1015	/* mii port */ {1 << 11, 1 << 5, REG_VLAN_PTAG5, 1},
1016};
1017
1018/* Configure the VLANs */
1019int
1020bcm_robo_config_vlan(robo_info_t *robo, uint8 *mac_addr)
1021{
1022	uint8 val8;
1023	uint16 val16;
1024	uint32 val32;
1025	pdesc_t *pdesc;
1026	int pdescsz;
1027	uint16 vid;
1028	uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 };
1029
1030	/* Enable management interface access */
1031	if (robo->ops->enable_mgmtif)
1032		robo->ops->enable_mgmtif(robo);
1033
1034	/* setup global vlan configuration */
1035	/* VLAN Control 0 Register (Page 0x34, Address 0) */
1036	robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
1037	val8 |= ((1 << 7) |		/* enable 802.1Q VLAN */
1038	         (3 << 5));		/* individual VLAN learning mode */
1039	if (robo->devid == DEVID5325)
1040		val8 &= ~(1 << 1);	/* must clear reserved bit 1 */
1041	robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
1042	/* VLAN Control 1 Register (Page 0x34, Address 1) */
1043	robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
1044	val8 |= ((1 << 2) |		/* enable RSV multicast V Fwdmap */
1045		 (1 << 3));		/* enable RSV multicast V Untagmap */
1046	if (robo->devid == DEVID5325)
1047		val8 |= (1 << 1);	/* enable RSV multicast V Tagging */
1048	robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
1049
1050	arl_entry[0] = mac_addr[5];
1051	arl_entry[1] = mac_addr[4];
1052	arl_entry[2] = mac_addr[3];
1053	arl_entry[3] = mac_addr[2];
1054	arl_entry[4] = mac_addr[1];
1055	arl_entry[5] = mac_addr[0];
1056
1057	if (robo->devid == DEVID5325) {
1058		/* Init the entry 1 of the bin */
1059		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1,
1060		                     arl_entry1, sizeof(arl_entry1));
1061		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1,
1062		                     arl_entry1, 1);
1063
1064		/* Init the entry 0 of the bin */
1065		arl_entry[6] = 0x8;		/* Port Id: MII */
1066		arl_entry[7] = 0xc0;	/* Static Entry, Valid */
1067
1068		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0,
1069		                     arl_entry, sizeof(arl_entry));
1070		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX,
1071		                     arl_entry, ETHER_ADDR_LEN);
1072
1073		/* VLAN Control 4 Register (Page 0x34, Address 4) */
1074		val8 = (1 << 6);		/* drop frame with VID violation */
1075		robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8));
1076
1077		/* VLAN Control 5 Register (Page 0x34, Address 5) */
1078		val8 = (1 << 3);		/* drop frame when miss V table */
1079		robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8));
1080
1081		pdesc = pdesc25;
1082		pdescsz = sizeof(pdesc25) / sizeof(pdesc_t);
1083	} else {
1084		/* Initialize the MAC Addr Index Register */
1085		robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX,
1086		                     arl_entry, ETHER_ADDR_LEN);
1087
1088		pdesc = pdesc97;
1089		pdescsz = sizeof(pdesc97) / sizeof(pdesc_t);
1090	}
1091
1092	/* setup each vlan. max. 16 vlans. */
1093	/* force vlan id to be equal to vlan number */
1094	for (vid = 0; vid < VLAN_NUMVLANS; vid ++) {
1095		char vlanports[] = "vlanXXXXports";
1096		char port[] = "XXXX", *ports, *next, *cur;
1097		uint32 untag = 0;
1098		uint32 member = 0;
1099		int pid, len;
1100
1101		/* no members if VLAN id is out of limitation */
1102		if (vid > VLAN_MAXVID)
1103			goto vlan_setup;
1104
1105		/* get vlan member ports from nvram */
1106		sprintf(vlanports, "vlan%dports", vid);
1107		ports = getvar(robo->vars, vlanports);
1108
1109		/* In 539x vid == 0 us invalid?? */
1110		if ((robo->devid != DEVID5325) && (vid == 0)) {
1111			if (ports)
1112				ET_ERROR(("VID 0 is set in nvram, Ignoring\n"));
1113			continue;
1114		}
1115
1116		/* disable this vlan if not defined */
1117		if (!ports)
1118			goto vlan_setup;
1119
1120		/*
1121		 * setup each port in the vlan. cpu port needs special handing
1122		 * (with or without output tagging) to support linux/pmon/cfe.
1123		 */
1124		for (cur = ports; cur; cur = next) {
1125			/* tokenize the port list */
1126			while (*cur == ' ')
1127				cur ++;
1128			next = bcmstrstr(cur, " ");
1129			len = next ? next - cur : strlen(cur);
1130			if (!len)
1131				break;
1132			if (len > sizeof(port) - 1)
1133				len = sizeof(port) - 1;
1134			strncpy(port, cur, len);
1135			port[len] = 0;
1136
1137			/* make sure port # is within the range */
1138			pid = bcm_atoi(port);
1139			if (pid >= pdescsz) {
1140				ET_ERROR(("robo_config_vlan: port %d in vlan%dports is out "
1141				          "of range[0-%d]\n", pid, vid, pdescsz));
1142				continue;
1143			}
1144
1145			/* build VLAN registers values */
1146#ifndef	_CFE_
1147			if ((!pdesc[pid].cpu && !strchr(port, FLAG_TAGGED)) ||
1148			    (pdesc[pid].cpu && strchr(port, FLAG_UNTAG)))
1149#endif
1150				untag |= pdesc[pid].untag;
1151
1152			member |= pdesc[pid].member;
1153
1154			/* set port tag - applies to untagged ingress frames */
1155			/* Default Port Tag Register (Page 0x34, Address 0x10-0x1D) */
1156#ifdef	_CFE_
1157#define	FL	FLAG_LAN
1158#else
1159#define	FL	FLAG_UNTAG
1160#endif /* _CFE_ */
1161			if (!pdesc[pid].cpu || strchr(port, FL)) {
1162				val16 = ((0 << 13) |		/* priority - always 0 */
1163				         vid);			/* vlan id */
1164				robo->ops->write_reg(robo, PAGE_VLAN, pdesc[pid].ptagr,
1165				                     &val16, sizeof(val16));
1166			}
1167		}
1168
1169		/* Add static ARL entries */
1170		if (robo->devid == DEVID5325) {
1171			val8 = vid;
1172			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E0,
1173			                     &val8, sizeof(val8));
1174			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX,
1175			                     &val8, sizeof(val8));
1176
1177			/* Write the entry */
1178			val8 = 0x80;
1179			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1180			                     &val8, sizeof(val8));
1181			/* Wait for write to complete */
1182			SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1183			         &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
1184			         100 /* usec */);
1185		} else {
1186			/* Set the VLAN Id in VLAN ID Index Register */
1187			val8 = vid;
1188			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX,
1189			                     &val8, sizeof(val8));
1190
1191			/* Set the MAC addr and VLAN Id in ARL Table MAC/VID Entry 0
1192			 * Register.
1193			 */
1194			arl_entry[6] = vid;
1195			arl_entry[7] = 0x0;
1196			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0,
1197			                     arl_entry, sizeof(arl_entry));
1198
1199			/* Set the Static bit , Valid bit and Port ID fields in
1200			 * ARL Table Data Entry 0 Register
1201			 */
1202			val16 = 0xc008;
1203			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_DAT_E0,
1204			                     &val16, sizeof(val16));
1205
1206			/* Clear the ARL_R/W bit and set the START/DONE bit in
1207			 * the ARL Read/Write Control Register.
1208			 */
1209			val8 = 0x80;
1210			robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1211			                     &val8, sizeof(val8));
1212			/* Wait for write to complete */
1213			SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1214			         &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
1215			         100 /* usec */);
1216		}
1217
1218vlan_setup:
1219		/* setup VLAN ID and VLAN memberships */
1220
1221		val32 = (untag |			/* untag enable */
1222		         member);			/* vlan members */
1223		if (robo->devid == DEVID5325) {
1224			if (robo->corerev < 3) {
1225				val32 |= ((1 << 20) |		/* valid write */
1226				          ((vid >> 4) << 12));	/* vlan id bit[11:4] */
1227			} else {
1228				val32 |= ((1 << 24) |		/* valid write */
1229				          (vid << 12));	/* vlan id bit[11:4] */
1230			}
1231			ET_MSG(("bcm_robo_config_vlan: programming REG_VLAN_WRITE %08x\n", val32));
1232
1233			/* VLAN Write Register (Page 0x34, Address 0x08-0x0B) */
1234			robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_WRITE, &val32,
1235			                     sizeof(val32));
1236			/* VLAN Table Access Register (Page 0x34, Address 0x06-0x07) */
1237			val16 = ((1 << 13) |	/* start command */
1238			         (1 << 12) |	/* write state */
1239			         vid);		/* vlan id */
1240			robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_ACCESS, &val16,
1241			                     sizeof(val16));
1242		} else {
1243			uint8 vtble, vtbli, vtbla;
1244
1245			if ((robo->devid == DEVID5395) ||
1246				(robo->devid == DEVID53115) ||
1247				(robo->devid == DEVID53125)) {
1248				vtble = REG_VTBL_ENTRY_5395;
1249				vtbli = REG_VTBL_INDX_5395;
1250				vtbla = REG_VTBL_ACCESS_5395;
1251			} else {
1252				vtble = REG_VTBL_ENTRY;
1253				vtbli = REG_VTBL_INDX;
1254				vtbla = REG_VTBL_ACCESS;
1255			}
1256
1257			/* VLAN Table Entry Register (Page 0x05, Address 0x63-0x66/0x83-0x86) */
1258			robo->ops->write_reg(robo, PAGE_VTBL, vtble, &val32,
1259			                     sizeof(val32));
1260			/* VLAN Table Address Index Reg (Page 0x05, Address 0x61-0x62/0x81-0x82) */
1261			val16 = vid;        /* vlan id */
1262			robo->ops->write_reg(robo, PAGE_VTBL, vtbli, &val16,
1263			                     sizeof(val16));
1264
1265			/* VLAN Table Access Register (Page 0x34, Address 0x60/0x80) */
1266			val8 = ((1 << 7) | 	/* start command */
1267			        0);	        /* write */
1268			robo->ops->write_reg(robo, PAGE_VTBL, vtbla, &val8,
1269			                     sizeof(val8));
1270		}
1271	}
1272
1273	if (robo->devid == DEVID5325) {
1274		/* setup priority mapping - applies to tagged ingress frames */
1275		/* Priority Re-map Register (Page 0x34, Address 0x20-0x23) */
1276		val32 = ((0 << 0) |	/* 0 -> 0 */
1277		         (1 << 3) |	/* 1 -> 1 */
1278		         (2 << 6) |	/* 2 -> 2 */
1279		         (3 << 9) |	/* 3 -> 3 */
1280		         (4 << 12) |	/* 4 -> 4 */
1281		         (5 << 15) |	/* 5 -> 5 */
1282		         (6 << 18) |	/* 6 -> 6 */
1283		         (7 << 21));	/* 7 -> 7 */
1284		robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_PMAP, &val32, sizeof(val32));
1285	}
1286
1287	if (robo->devid == DEVID53115) {
1288		/* Configure the priority system to use to determine the TC of
1289		 * ingress frames. Use DiffServ TC mapping, otherwise 802.1p
1290		 * TC mapping, otherwise MAC based TC mapping.
1291		 */
1292		val8 = ((0 << 6) |		/* Disable port based QoS */
1293	                (2 << 2));		/* QoS priority selection */
1294		robo->ops->write_reg(robo, 0x30, 0, &val8, sizeof(val8));
1295
1296		/* Configure tx queues scheduling mechanism */
1297		val8 = (3 << 0);		/* Strict priority */
1298		robo->ops->write_reg(robo, 0x30, 0x80, &val8, sizeof(val8));
1299
1300		/* Enable 802.1p Priority to TC mapping for individual ports */
1301		val16 = 0x11f;
1302		robo->ops->write_reg(robo, 0x30, 0x4, &val16, sizeof(val16));
1303
1304		/* Configure the TC to COS mapping. This determines the egress
1305		 * transmit queue.
1306		 */
1307		val16 = ((1 << 0)  |	/* Pri 0 mapped to TXQ 1 */
1308			 (0 << 2)  |	/* Pri 1 mapped to TXQ 0 */
1309			 (0 << 4)  |	/* Pri 2 mapped to TXQ 0 */
1310			 (1 << 6)  |	/* Pri 3 mapped to TXQ 1 */
1311			 (2 << 8)  |	/* Pri 4 mapped to TXQ 2 */
1312			 (2 << 10) |	/* Pri 5 mapped to TXQ 2 */
1313			 (3 << 12) |	/* Pri 6 mapped to TXQ 3 */
1314			 (3 << 14));	/* Pri 7 mapped to TXQ 3 */
1315		robo->ops->write_reg(robo, 0x30, 0x62, &val16, sizeof(val16));
1316	}
1317
1318	/* Disable management interface access */
1319	if (robo->ops->disable_mgmtif)
1320		robo->ops->disable_mgmtif(robo);
1321
1322	return 0;
1323}
1324
1325/* Enable switching/forwarding */
1326int
1327bcm_robo_enable_switch(robo_info_t *robo)
1328{
1329	int i, max_port_ind, ret = 0;
1330	uint8 val8;
1331
1332	/* Enable management interface access */
1333	if (robo->ops->enable_mgmtif)
1334		robo->ops->enable_mgmtif(robo);
1335
1336	/* foxconn added start, zacker, 01/13/2012, @iptv_igmp */
1337#if defined(CONFIG_RUSSIA_IPTV)
1338	set_iptv_ports(robo);
1339#endif
1340	/* foxconn added end, zacker, 01/13/2012, @iptv_igmp */
1341
1342	/* Foxconn added start, zacker, 10/22/2008 */
1343#if defined(__CONFIG_IGMP_SNOOPING__)
1344	char *igmp_snooping_flag;
1345	igmp_snooping_flag = getvar(robo->vars, "emf_enable");
1346	if (igmp_snooping_flag && (strcmp(igmp_snooping_flag, "1") == 0))
1347	{
1348
1349		/* Enables the receipt of unicast, multicast and broadcast on IMP port*/
1350		robo->ops->read_reg(robo, 0, 0x8, &val8, sizeof(val8));
1351		val8 |= 0x1c;
1352		robo->ops->write_reg(robo, 0, 0x8, &val8, sizeof(val8));
1353		ET_ERROR(("Alex:P:0 A:0x8 val8=%x\n",val8));
1354
1355		/* Enable Frame-managment mode*/
1356		robo->ops->read_reg(robo, 0, 0xb, &val8, sizeof(val8));
1357		val8 |= 0x03;
1358		robo->ops->write_reg(robo, 0, 0xb, &val8, sizeof(val8));
1359		ET_ERROR(("Alex:P:0 A:0xb val8=%x\n",val8));
1360
1361		/*Enable management port*/
1362		robo->ops->read_reg(robo, 0x2, 0, &val8, sizeof(val8));
1363		val8 |= 0x80;
1364		robo->ops->write_reg(robo, 0x2, 0, &val8, sizeof(val8));
1365		is_reg_mgmt_mode_enable = 1;
1366		ET_ERROR(("Alex:P:0x2 A:0 val8=%x\n",val8));
1367
1368		/*CRC bypass and auto generation*/
1369		robo->ops->read_reg(robo, 0x34, 0x06, &val8, sizeof(val8));
1370		val8 |= 0x1;
1371		robo->ops->write_reg(robo, 0x34, 0x06, &val8, sizeof(val8));
1372		ET_ERROR(("Alex:P:0x34 A:0x6 val8=%x\n",val8));
1373
1374#ifdef __CONFIG_IGMP_SNOOPING__
1375		if (igmp_snooping_flag && (strcmp(igmp_snooping_flag, "1") == 0))
1376		{
1377			uint32 val32;
1378			uint16 val16;
1379
1380#if 1		/* ?? BCM53115S doesn't need it for this case */
1381			/* Set IMP port default tag id */
1382			/* Otherwise, the packet with correct vid can not be sent out */
1383			robo->ops->read_reg(robo, 0x34, 0x20, &val16, sizeof(val16));
1384			val16 = (val16 & 0xF000) | WAN_VLAN_ENTRY_IDX;
1385			robo->ops->write_reg(robo, 0x34, 0x20, &val16, sizeof(val16));
1386			ET_ERROR(("Alex:P:0x34 A:0x20 val16=%x\n",val16));
1387#endif
1388
1389			/* VLAN Control 1 Register (Page 0x34, Address 1) */
1390			robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
1391			val8 |= (1 << 5); /* enable IPMC bypass V fwdmap */
1392			robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
1393			ET_ERROR(("Alex:P:0x34 A:0x1 val8=%x\n",val8));
1394
1395			/* Set IGMP packet be trap to CPU only.*/
1396            /* foxconn wklin removed start, 12/03/2010, fix WNDR4000 IGMP issues */
1397#if 0
1398			robo->ops->read_reg(robo, PAGE_MMR, 0x50, &val32, sizeof(val32));
1399			val32 |= 0x7E00;
1400			robo->ops->write_reg(robo, PAGE_MMR, 0x50, &val32, sizeof(val32));
1401			ET_ERROR(("Alex:P:0x2 A:0x50 val32=%x\n",val32));
1402#endif
1403            /* foxconn wklin removed end, 12/03/2010 */
1404
1405			/*Set Multiport address enable */
1406			robo->ops->read_reg(robo, 0x4, 0xE, &val16, sizeof(val16));
1407			val16 |= 0x0AAA;
1408			robo->ops->write_reg(robo, 0x4, 0xE, &val16, sizeof(val16));
1409			is_reg_snooping_enable = 1;
1410			ET_ERROR(("Alex:P:0x4 A:0xE val16=%x\n",val16));
1411
1412			memset(snooping_table,0,sizeof(snooping_table[2]));
1413			robo->ops->write_reg(robo, 0x4, (0x10), snooping_table[0].mh_mac, sizeof(snooping_table[0].mh_mac));
1414			robo->ops->write_reg(robo, 0x4, (0x18), &(snooping_table[0].port_mapping), sizeof(snooping_table[0].port_mapping));
1415			robo->ops->write_reg(robo, 0x4, (0x20), snooping_table[0].mh_mac, sizeof(snooping_table[0].mh_mac));
1416			robo->ops->write_reg(robo, 0x4, (0x28), &(snooping_table[0].port_mapping), sizeof(snooping_table[0].port_mapping));
1417		}
1418#endif
1419	}
1420#endif
1421	/* Foxconn added end, zacker, 10/22/2008 */
1422	/* Switch Mode register (Page 0, Address 0x0B) */
1423	robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1424
1425	/* Bit 1 enables switching/forwarding */
1426	if (!(val8 & (1 << 1))) {
1427		/* Set unmanaged mode */
1428		val8 &= (~(1 << 0));
1429
1430		/* Enable forwarding */
1431		val8 |= (1 << 1);
1432		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1433
1434		/* Read back */
1435		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1436		if (!(val8 & (1 << 1))) {
1437			ET_ERROR(("robo_enable_switch: enabling forwarding failed\n"));
1438			ret = -1;
1439		}
1440
1441		/* No spanning tree for unmanaged mode */
1442		val8 = 0;
1443		max_port_ind = ((robo->devid == DEVID5398) ? REG_CTRL_PORT7 :
1444		                (robo->devid == DEVID53115) ? REG_CTRL_PORT5 : REG_CTRL_PORT4);
1445		for (i = REG_CTRL_PORT0; i <= max_port_ind; i++) {
1446			robo->ops->write_reg(robo, PAGE_CTRL, i, &val8, sizeof(val8));
1447		}
1448
1449		/* No spanning tree on IMP port too */
1450		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_IMP, &val8, sizeof(val8));
1451	}
1452
1453	if (robo->devid == DEVID53125) {
1454		/* Over ride IMP port status to make it link by default */
1455		val8 = 0;
1456		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &val8, sizeof(val8));
1457		val8 |= 0x81;	/* Make Link pass and override it. */
1458		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &val8, sizeof(val8));
1459	}
1460
1461	/* Disable management interface access */
1462	if (robo->ops->disable_mgmtif)
1463		robo->ops->disable_mgmtif(robo);
1464
1465	return ret;
1466}
1467
1468#ifdef __CONFIG_IGMP_SNOOPING__/* Foxconn add start by Lewis Min, 04/02/2008, for igmp snooping */
1469/*
1470 * Description: This function is called by IGMP Snooper when it wants
1471 *              to add snooping entry or refresh the entry.
1472 *              If the mac entry is not present, it then update the older one and return 0 or 1;
1473 *              If the mac entry do exist, it then check port map, if exist,  do nothing, return 4.
1474                 if not, then update the port mapping and return 2 or 3
1475 *
1476 *
1477 * Input:      mac address, port no.
1478 *
1479 * Return:      0---MAC address not exist and should using 0 reg
1480                    1---MAC address not exist and should using 1 reg
1481                    2---MAC address exist and should update 0 port reg
1482                    3---MAC address exist and should update 1 reg
1483                    4---Do nothing
1484 */
1485
1486uint8 record_mac_address(uint8 *p_mh_mac,uint16 *port_id)
1487{
1488         static int MultiPortInuse=1;
1489
1490          if(memcmp(snooping_table[0].mh_mac,p_mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1491          {
1492               if(*port_id&snooping_table[0].port_mapping)
1493                    return 4;
1494               else
1495               {
1496                          snooping_table[0].port_mapping|=*port_id;
1497                          *port_id=snooping_table[0].port_mapping;
1498                          return 2;
1499               }
1500          }
1501          else if(memcmp(snooping_table[1].mh_mac,p_mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1502          {
1503                if(*port_id&snooping_table[1].port_mapping)
1504                       return 4;
1505                else
1506                {
1507                     snooping_table[1].port_mapping|=*port_id;
1508                     *port_id=snooping_table[1].port_mapping;
1509                     return 3;
1510                }
1511          }
1512          else
1513          {
1514               if(0==snooping_table[0].mh_mac[0])
1515                {
1516                     memcpy(snooping_table[0].mh_mac,p_mh_mac,sizeof(snooping_table[0].mh_mac));
1517                     snooping_table[0].port_mapping=*port_id;
1518                     MultiPortInuse=0;
1519                     return 0;
1520                }
1521                else if(0==snooping_table[1].mh_mac[0])
1522                {
1523                     memcpy(snooping_table[1].mh_mac,p_mh_mac,sizeof(snooping_table[1].mh_mac));
1524                     snooping_table[1].port_mapping=*port_id;
1525                     MultiPortInuse=1;
1526                     return 1;
1527                }
1528                else
1529                {
1530#if 0
1531                     if(MultiPortInuse==0)
1532                        MultiPortInuse=1;
1533                     else
1534                        MultiPortInuse=0;
1535                     memcpy(snooping_table[MultiPortInuse].mh_mac,p_mh_mac,sizeof(snooping_table[MultiPortInuse].mh_mac));
1536                     snooping_table[MultiPortInuse].port_mapping=*port_id;
1537
1538                     return MultiPortInuse;
1539#endif
1540                    return 4;
1541                }
1542          }
1543}
1544
1545int bcm_robo_snoop_ip_match(uint32 mh_ip)
1546{
1547         uint8 mh_mac[6];
1548
1549             mh_mac[0] = 0x01;
1550             mh_mac[1] = 0x00;
1551             mh_mac[2] = 0x5e;
1552             mh_mac[5] = mh_ip & 0xff; mh_ip >>= 8;
1553             mh_mac[4] = mh_ip & 0xff; mh_ip >>= 8;
1554             mh_mac[3] = mh_ip & 0x7f;
1555          if(memcmp(snooping_table[0].mh_mac,mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1556          {
1557                return 1;
1558          }
1559          else if(memcmp(snooping_table[1].mh_mac,mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1560          {
1561                return 1;
1562          }
1563          return 0;
1564}
1565int bcm_robo_snoop_mac_match(uint8 *p_mh_mac)
1566{
1567          if(memcmp(snooping_table[0].mh_mac,p_mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1568          {
1569                return 1;
1570          }
1571          else if(memcmp(snooping_table[1].mh_mac,p_mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1572          {
1573                return 1;
1574          }
1575          return 0;
1576}
1577
1578/*
1579 * Description: This function is called by IGMP Snooper when it wants
1580 *              to del snooping entry or refresh the entry.
1581 *              If the mac entry is not present, it then return 2;
1582 *              If the mac entry do exist, it then remove and return 0 or 1
1583 *
1584 *
1585 * Input:      mac address, port no.
1586 *
1587 * Return:      0---MAC address exist and should using 0 reg
1588                    1---MAC address  exist and should using 1 reg
1589                    2---MAC address not exist
1590 */
1591
1592uint8 remove_mac_address(uint8 *p_mh_mac,uint16 *port_id)
1593{
1594            if(memcmp(snooping_table[0].mh_mac,p_mh_mac,sizeof(snooping_table[0].mh_mac))==0)
1595            {
1596                      if(*port_id==snooping_table[0].port_mapping)/*Should delete the entire entry*/
1597                      {
1598                            memset(snooping_table[0].mh_mac,0,sizeof(snooping_table[0].mh_mac));
1599                            memset(p_mh_mac,0,sizeof(snooping_table[0].mh_mac));
1600                            *port_id=snooping_table[0].port_mapping=0;
1601                       }
1602                       else/*only need to update port mapping*/
1603                       {
1604                                    if(*port_id==(1<<5))
1605                                    {
1606                                        memset(snooping_table[0].mh_mac,0,sizeof(snooping_table[0].mh_mac));
1607                                        memset(p_mh_mac,0,sizeof(snooping_table[0].mh_mac));
1608                                        snooping_table[0].port_mapping=0;
1609                                    }
1610                                    else
1611                                        snooping_table[0].port_mapping&=~(*port_id);
1612
1613                                    *port_id=snooping_table[0].port_mapping;
1614                       }
1615                       return 0;
1616            }
1617            else if(memcmp(snooping_table[1].mh_mac,p_mh_mac,sizeof(snooping_table[1].mh_mac))==0)
1618            {
1619                      if(*port_id==snooping_table[1].port_mapping)/*Should delete the entire entry*/
1620                      {
1621                            memset(snooping_table[1].mh_mac,0,sizeof(snooping_table[1].mh_mac));
1622                            memset(p_mh_mac,0,sizeof(snooping_table[1].mh_mac));
1623                            *port_id=snooping_table[1].port_mapping=0;
1624                       }
1625                       else/*only need to update port mapping*/
1626                       {
1627                                    if(*port_id==(1<<5))
1628                                    {
1629                                        memset(snooping_table[1].mh_mac,0,sizeof(snooping_table[1].mh_mac));
1630                                        memset(p_mh_mac,0,sizeof(snooping_table[1].mh_mac));
1631                                        snooping_table[1].port_mapping=0;
1632                                    }
1633                                    else
1634                                        snooping_table[1].port_mapping&=~(*port_id);
1635
1636                                    *port_id=snooping_table[1].port_mapping;
1637                       }
1638                   return 1;/*1---MAC address  exist and should using 1 reg*/
1639            }
1640            else
1641            {
1642                 return 2;/*MAC address not exist*/
1643            }
1644}
1645/*
1646 * Description: This function is called by IGMP Snooper when it wants
1647 *              to add multiport entry or refresh the entry.
1648 *
1649 *              If the MFDB entry is not present, it allocates group
1650 *              entry, interface entry and links them together.
1651 *
1652 * Input:       mgrp_ip: multicast group IP address
1653                   portid:    which port the IGMP packet come from
1654 *
1655 * Return:      1 or 0
1656 */
1657void
1658bcm_robo_snooping_add(uint32 mgrp_ip, int portid)
1659{
1660       uint8 mh_mac[6],mh_mac_tmp[6],retVal;
1661       uint16 valu16;
1662       uint32 *pIntTmp;
1663       robo_info_t *robo = robo_ptr;
1664
1665       if ((robo == NULL) || (portid == ROBO_WAN_PORT))
1666           return ;
1667
1668       if((mgrp_ip==0xeffffffa)||(mgrp_ip==0xe00000fc))
1669           return ;
1670
1671       /* Enable management interface access */
1672       if (robo->ops->enable_mgmtif)
1673        robo->ops->enable_mgmtif(robo);
1674
1675       mgrp_ip=(mgrp_ip & 0x7fffff);
1676       mgrp_ip=htonl(mgrp_ip);
1677
1678       pIntTmp=(uint32 *)&mh_mac[2];
1679       *pIntTmp=mgrp_ip ;
1680       mh_mac[0]=0x01;
1681       mh_mac[1]=0x0;
1682       mh_mac[2]=0x5e;
1683
1684       valu16=1<<portid;
1685
1686       retVal=record_mac_address(mh_mac,&valu16);
1687       mh_mac_tmp[0]=mh_mac[5];
1688       mh_mac_tmp[1]=mh_mac[4];
1689       mh_mac_tmp[2]=mh_mac[3];
1690       mh_mac_tmp[3]=mh_mac[2];
1691       mh_mac_tmp[4]=mh_mac[1];
1692       mh_mac_tmp[5]=mh_mac[0];
1693
1694       valu16|=0x100;
1695        if((0==retVal)||(1==retVal))
1696        {
1697             robo->ops->write_reg(robo, 0x4, (0x10+retVal*0x10), mh_mac_tmp, sizeof(mh_mac_tmp));
1698             robo->ops->write_reg(robo, 0x4, (0x18+retVal*0x10), &valu16, sizeof(valu16));
1699        }
1700        else if((2==retVal)||(3==retVal))
1701        {
1702            robo->ops->write_reg(robo, 0x4, (0x18+(retVal-2)*0x10), &valu16, sizeof(valu16));
1703        }
1704
1705       /* Disable management interface access */
1706       if (robo->ops->disable_mgmtif)
1707           robo->ops->disable_mgmtif(robo);
1708
1709       return ;
1710}
1711
1712/*
1713 * Description: This function is called by IGMP Snooper when it wants
1714 *              to add MFDB entry or refresh the entry. This function
1715 *              is also called by the management application to add a
1716 *              static MFDB entry.
1717 *
1718 *              If the MFDB entry is not present, it allocates group
1719 *              entry, interface entry and links them together.
1720 *
1721 * Input:       Same as above function.
1722 *
1723 * Return:      SUCCESS or FAILURE
1724 */
1725void
1726bcm_robo_snooping_del(uint32 mgrp_ip, int portid)
1727{
1728       uint8 mh_mac[6],mh_mac_tmp[6],retVal;
1729       uint16 valu16;
1730       uint32 *pIntTmp;
1731       robo_info_t *robo = robo_ptr;
1732
1733       if ((robo == NULL)||(portid<0)||(portid>5)||(portid==ROBO_WAN_PORT))
1734           return ;
1735
1736       if((mgrp_ip==0xeffffffa)||(mgrp_ip==0xe00000fc))
1737           return ;
1738
1739       /* Enable management interface access */
1740       if (robo->ops->enable_mgmtif)
1741           robo->ops->enable_mgmtif(robo);
1742
1743       mgrp_ip=(mgrp_ip & 0x7fffff);
1744       mgrp_ip=htonl(mgrp_ip);
1745
1746       pIntTmp=(uint32 *)&mh_mac[2];
1747       *pIntTmp=mgrp_ip ;
1748       mh_mac[0]=0x01;
1749       mh_mac[1]=0x0;
1750       mh_mac[2]=0x5e;
1751       valu16=1<<portid;
1752
1753       retVal=remove_mac_address(&mh_mac[0],&valu16);
1754       mh_mac_tmp[0]=mh_mac[5];
1755       mh_mac_tmp[1]=mh_mac[4];
1756       mh_mac_tmp[2]=mh_mac[3];
1757       mh_mac_tmp[3]=mh_mac[2];
1758       mh_mac_tmp[4]=mh_mac[1];
1759       mh_mac_tmp[5]=mh_mac[0];
1760
1761       valu16|=0x100;
1762
1763       if((0==retVal)||(1==retVal))
1764       {
1765              robo->ops->write_reg(robo, 0x4, (0x10+retVal*0x10), mh_mac_tmp, sizeof(mh_mac_tmp));
1766              robo->ops->write_reg(robo, 0x4, (0x18+retVal*0x10), &valu16, sizeof(valu16));
1767       }
1768
1769        /* Disable management interface access */
1770        if (robo->ops->disable_mgmtif)
1771            robo->ops->disable_mgmtif(robo);
1772
1773        return ;
1774}
1775
1776void
1777bcm_robo_snooping_list(igmp_snooping_table_t *pSnoop_entry)
1778{
1779       robo_info_t *robo = robo_ptr;
1780
1781       if (robo == NULL)
1782          return;
1783
1784      /* Enable management interface access */
1785      if (robo->ops->enable_mgmtif)
1786           robo->ops->enable_mgmtif(robo);
1787
1788       robo->ops->read_reg(robo, 0x4, 0x10, &pSnoop_entry->mh_mac[0], sizeof(pSnoop_entry->mh_mac));
1789       robo->ops->read_reg(robo, 0x4, 0x18, &pSnoop_entry->port_mapping, sizeof(uint16));
1790       pSnoop_entry++;
1791       robo->ops->read_reg(robo, 0x4, 0x20, &pSnoop_entry->mh_mac[0], sizeof(pSnoop_entry->mh_mac));
1792       robo->ops->read_reg(robo, 0x4, 0x28, &pSnoop_entry->port_mapping, sizeof(uint16));
1793
1794       /* Disable management interface access */
1795       if (robo->ops->disable_mgmtif)
1796           robo->ops->disable_mgmtif(robo);
1797
1798       return ;
1799}
1800#endif
1801/*Add end by foxconn lewis min for snooping function ,04/01/2008*/
1802
1803#ifndef	_CFE_
1804/*
1805 * Update the power save configuration for ports that changed link status.
1806 */
1807void
1808robo_power_save_mode_update(robo_info_t *robo)
1809{
1810	uint phy;
1811
1812	for (phy = 0; phy < MAX_NO_PHYS; phy++) {
1813		if (robo->pwrsave_mode_auto & (1 << phy)) {
1814			ET_MSG(("%s: set port %d to auto mode\n",
1815				__FUNCTION__, phy));
1816			robo_power_save_mode(robo, ROBO_PWRSAVE_AUTO, phy);
1817		}
1818	}
1819
1820	return;
1821}
1822
1823static int32
1824robo_power_save_mode_clear_auto(robo_info_t *robo, int32 phy)
1825{
1826	uint16 val16;
1827
1828	if (robo->devid == DEVID53115) {
1829		/* For 53115 0x1C is the MII address of the auto power
1830		 * down register. Bit 5 is enabling the mode
1831		 * bits has the following purpose
1832		 * 15 - write enable 10-14 shadow register select 01010 for
1833		 * auto power 6-9 reserved 5 auto power mode enable
1834		 * 4 sleep timer select : 1 means 5.4 sec
1835		 * 0-3 wake up timer select: 0xF 1.26 sec
1836		 */
1837		val16 = 0xa800;
1838		robo->miiwr(robo->h, phy, REG_MII_AUTO_PWRDOWN, val16);
1839	} else if (robo->sih->chip == BCM5356_CHIP_ID) {
1840		/* To disable auto power down mode
1841		 * clear bit 5 of Aux Status 2 register
1842		 * (Shadow reg 0x1b). Shadow register
1843		 * access is enabled by writing
1844		 * 1 to bit 7 of MII register 0x1f.
1845		 */
1846		val16 = robo->miird(robo->h, phy, REG_MII_BRCM_TEST);
1847		robo->miiwr(robo->h, phy, REG_MII_BRCM_TEST,
1848		            (val16 | (1 << 7)));
1849
1850		/* Disable auto power down by clearing
1851		 * bit 5 of to Aux Status 2 reg.
1852		 */
1853		val16 = robo->miird(robo->h, phy, REG_MII_AUX_STATUS2);
1854		robo->miiwr(robo->h, phy, REG_MII_AUX_STATUS2,
1855		            (val16 & ~(1 << 5)));
1856
1857		/* Undo shadow access */
1858		val16 = robo->miird(robo->h, phy, REG_MII_BRCM_TEST);
1859		robo->miiwr(robo->h, phy, REG_MII_BRCM_TEST,
1860		            (val16 & ~(1 << 7)));
1861	} else
1862		return -1;
1863
1864	robo->pwrsave_mode_phys[phy] &= ~ROBO_PWRSAVE_AUTO;
1865
1866	return 0;
1867}
1868
1869static int32
1870robo_power_save_mode_clear_manual(robo_info_t *robo, int32 phy)
1871{
1872	uint8 val8;
1873	uint16 val16;
1874
1875	if ((robo->devid == DEVID53115) ||
1876	    (robo->sih->chip == BCM5356_CHIP_ID)) {
1877		/* For 53115 0x0 is the MII control register
1878		 * Bit 11 is the power down mode bit
1879		 */
1880		val16 = robo->miird(robo->h, phy, REG_MII_CTRL);
1881		val16 &= 0xf7ff;
1882		robo->miiwr(robo->h, phy, REG_MII_CTRL, val16);
1883	} else if (robo->devid == DEVID5325) {
1884		if (phy == 0)
1885			return -1;
1886		/* For 5325 page 0x00 address 0x0F is the power down
1887		 * mode register. Bits 1-4 determines which of the
1888		 * phys are enabled for this mode
1889		 */
1890		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN,
1891		                    &val8, sizeof(val8));
1892		val8 &= ~(0x1  << phy);
1893		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN,
1894		                     &val8, sizeof(val8));
1895	} else
1896		return -1;
1897
1898	robo->pwrsave_mode_phys[phy] &= ~ROBO_PWRSAVE_MANUAL;
1899
1900	return 0;
1901}
1902
1903/*
1904 * Function which periodically checks the power save mode on the switch
1905 */
1906int32
1907robo_power_save_toggle(robo_info_t *robo, int32 normal)
1908{
1909	int32 phy;
1910	uint16 link_status;
1911
1912
1913	/* read the link status of all ports */
1914	robo->ops->read_reg(robo, PAGE_STATUS, REG_STATUS_LINK,
1915		&link_status, sizeof(uint16));
1916	link_status &= 0x1f;
1917
1918	/* Take the phys out of the manual mode first so that link status
1919	 * can be checked. Once out of that  mode check the link status
1920	 * and if any of the link is up do not put that phy into
1921	 * manual power save mode
1922	 */
1923	for (phy = 0; phy < MAX_NO_PHYS; phy++) {
1924		/* When auto+manual modes are enabled we toggle between
1925		 * manual and auto modes. When only manual mode is enabled
1926		 * we toggle between manual and normal modes. When only
1927		 * auto mode is enabled there is no need to do anything
1928		 * here since auto mode is one time config.
1929		 */
1930		if ((robo->pwrsave_phys & (1 << phy)) &&
1931		    (robo->pwrsave_mode_manual & (1 << phy))) {
1932			if (!normal) {
1933				/* Take the port out of the manual mode */
1934				robo_power_save_mode_clear_manual(robo, phy);
1935			} else {
1936				/* If the link is down put it back to manual else
1937				 * remain in the current state
1938				 */
1939				if (!(link_status & (1 << phy))) {
1940					ET_MSG(("%s: link down, set port %d to man mode\n",
1941						__FUNCTION__, phy));
1942					robo_power_save_mode(robo, ROBO_PWRSAVE_MANUAL, phy);
1943				}
1944			}
1945		}
1946	}
1947
1948	return 0;
1949}
1950
1951/*
1952 * Switch the ports to normal mode.
1953 */
1954static int32
1955robo_power_save_mode_normal(robo_info_t *robo, int32 phy)
1956{
1957	int32 error = 0;
1958
1959	/* If the phy in the power save mode come out of it */
1960	switch (robo->pwrsave_mode_phys[phy]) {
1961		case ROBO_PWRSAVE_AUTO_MANUAL:
1962		case ROBO_PWRSAVE_AUTO:
1963			error = robo_power_save_mode_clear_auto(robo, phy);
1964			if ((error == -1) ||
1965			    (robo->pwrsave_mode_phys[phy] == ROBO_PWRSAVE_AUTO))
1966				break;
1967
1968		case ROBO_PWRSAVE_MANUAL:
1969			error = robo_power_save_mode_clear_manual(robo, phy);
1970			break;
1971
1972		default:
1973			break;
1974	}
1975
1976	return error;
1977}
1978
1979/*
1980 * Switch all the inactive ports to auto power down mode.
1981 */
1982static int32
1983robo_power_save_mode_auto(robo_info_t *robo, int32 phy)
1984{
1985	uint16 val16;
1986
1987	/* If the switch supports auto power down enable that */
1988	if (robo->devid ==  DEVID53115) {
1989		/* For 53115 0x1C is the MII address of the auto power
1990		 * down register. Bit 5 is enabling the mode
1991		 * bits has the following purpose
1992		 * 15 - write enable 10-14 shadow register select 01010 for
1993		 * auto power 6-9 reserved 5 auto power mode enable
1994		 * 4 sleep timer select : 1 means 5.4 sec
1995		 * 0-3 wake up timer select: 0xF 1.26 sec
1996		 */
1997		robo->miiwr(robo->h, phy, REG_MII_AUTO_PWRDOWN, 0xA83F);
1998	} else if (robo->sih->chip == BCM5356_CHIP_ID) {
1999		/* To enable auto power down mode set bit 5 of
2000		 * Auxillary Status 2 register (Shadow reg 0x1b)
2001		 * Shadow register access is enabled by writing
2002		 * 1 to bit 7 of MII register 0x1f.
2003		 */
2004		val16 = robo->miird(robo->h, phy, REG_MII_BRCM_TEST);
2005		robo->miiwr(robo->h, phy, REG_MII_BRCM_TEST,
2006		            (val16 | (1 << 7)));
2007
2008		/* Enable auto power down by writing to Auxillary
2009		 * Status 2 reg.
2010		 */
2011		val16 = robo->miird(robo->h, phy, REG_MII_AUX_STATUS2);
2012		robo->miiwr(robo->h, phy, REG_MII_AUX_STATUS2,
2013		            (val16 | (1 << 5)));
2014
2015		/* Undo shadow access */
2016		val16 = robo->miird(robo->h, phy, REG_MII_BRCM_TEST);
2017		robo->miiwr(robo->h, phy, REG_MII_BRCM_TEST,
2018		            (val16 & ~(1 << 7)));
2019	} else
2020		return -1;
2021
2022	robo->pwrsave_mode_phys[phy] |= ROBO_PWRSAVE_AUTO;
2023
2024	return 0;
2025}
2026
2027/*
2028 * Switch all the inactive ports to manual power down mode.
2029 */
2030static int32
2031robo_power_save_mode_manual(robo_info_t *robo, int32 phy)
2032{
2033	uint8 val8;
2034	uint16 val16;
2035
2036	/* For both 5325 and 53115 the link status register is the same */
2037	robo->ops->read_reg(robo, PAGE_STATUS, REG_STATUS_LINK,
2038	                    &val16, sizeof(val16));
2039	if (val16 & (0x1 << phy))
2040		return 0;
2041
2042	/* If the switch supports manual power down enable that */
2043	if ((robo->devid ==  DEVID53115) ||
2044	    (robo->sih->chip == BCM5356_CHIP_ID)) {
2045		/* For 53115 0x0 is the MII control register bit 11 is the
2046		 * power down mode bit
2047		 */
2048		val16 = robo->miird(robo->h, phy, REG_MII_CTRL);
2049		robo->miiwr(robo->h, phy, REG_MII_CTRL, val16 | 0x800);
2050	} else  if (robo->devid == DEVID5325) {
2051		if (phy == 0)
2052			return -1;
2053		/* For 5325 page 0x00 address 0x0F is the power down mode
2054		 * register. Bits 1-4 determines which of the phys are enabled
2055		 * for this mode
2056		 */
2057		robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN, &val8,
2058		                    sizeof(val8));
2059		val8 |= (1 << phy);
2060		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN, &val8,
2061		                     sizeof(val8));
2062	} else
2063		return -1;
2064
2065	robo->pwrsave_mode_phys[phy] |= ROBO_PWRSAVE_MANUAL;
2066
2067	return 0;
2068}
2069
2070/*
2071 * Set power save modes on the robo switch
2072 */
2073int32
2074robo_power_save_mode(robo_info_t *robo, int32 mode, int32 phy)
2075{
2076	int32 error = -1;
2077
2078	if (phy > MAX_NO_PHYS) {
2079		ET_ERROR(("Passed parameter phy is out of range\n"));
2080		return -1;
2081	}
2082
2083	/* Enable management interface access */
2084	if (robo->ops->enable_mgmtif)
2085		robo->ops->enable_mgmtif(robo);
2086
2087	switch (mode) {
2088		case ROBO_PWRSAVE_NORMAL:
2089			/* If the phy in the power save mode come out of it */
2090			error = robo_power_save_mode_normal(robo, phy);
2091			break;
2092
2093		case ROBO_PWRSAVE_AUTO_MANUAL:
2094			/* If the switch supports auto and manual power down
2095			 * enable both of them
2096			 */
2097		case ROBO_PWRSAVE_AUTO:
2098			error = robo_power_save_mode_auto(robo, phy);
2099			if ((error == -1) || (mode == ROBO_PWRSAVE_AUTO))
2100				break;
2101
2102		case ROBO_PWRSAVE_MANUAL:
2103			error = robo_power_save_mode_manual(robo, phy);
2104			break;
2105
2106		default:
2107			break;
2108	}
2109
2110	/* Disable management interface access */
2111	if (robo->ops->disable_mgmtif)
2112		robo->ops->disable_mgmtif(robo);
2113
2114	return error;
2115}
2116
2117/*
2118 * Get the current power save mode of the switch ports.
2119 */
2120int32
2121robo_power_save_mode_get(robo_info_t *robo, int32 phy)
2122{
2123	ASSERT(robo);
2124
2125	if (phy >= MAX_NO_PHYS)
2126		return -1;
2127
2128	return robo->pwrsave_mode_phys[phy];
2129}
2130
2131/*
2132 * Configure the power save mode for the switch ports.
2133 */
2134int32
2135robo_power_save_mode_set(robo_info_t *robo, int32 mode, int32 phy)
2136{
2137	int32 error;
2138
2139	ASSERT(robo);
2140
2141	if (phy >= MAX_NO_PHYS)
2142		return -1;
2143
2144	error = robo_power_save_mode(robo, mode, phy);
2145
2146	if (error)
2147		return error;
2148
2149	if (mode == ROBO_PWRSAVE_NORMAL) {
2150		robo->pwrsave_mode_manual &= ~(1 << phy);
2151		robo->pwrsave_mode_auto &= ~(1 << phy);
2152	} else if (mode == ROBO_PWRSAVE_AUTO) {
2153		robo->pwrsave_mode_auto |= (1 << phy);
2154		robo->pwrsave_mode_manual &= ~(1 << phy);
2155		robo_power_save_mode_clear_manual(robo, phy);
2156	} else if (mode == ROBO_PWRSAVE_MANUAL) {
2157		robo->pwrsave_mode_manual |= (1 << phy);
2158		robo->pwrsave_mode_auto &= ~(1 << phy);
2159		robo_power_save_mode_clear_auto(robo, phy);
2160	} else {
2161		robo->pwrsave_mode_auto |= (1 << phy);
2162		robo->pwrsave_mode_manual |= (1 << phy);
2163	}
2164
2165	return 0;
2166}
2167#endif /* _CFE_ */
2168
2169#ifdef PLC
2170void
2171robo_plc_hw_init(robo_info_t *robo)
2172{
2173	uint8 val8;
2174
2175	ASSERT(robo);
2176
2177	if (!robo->plc_hw)
2178		return;
2179
2180	/* Enable management interface access */
2181	if (robo->ops->enable_mgmtif)
2182		robo->ops->enable_mgmtif(robo);
2183
2184	if (robo->devid == DEVID53115) {
2185		/* Fix the duplex mode and speed for Port 5 */
2186		val8 = ((1 << 6) | (1 << 2) | 3);
2187		robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIP5O, &val8, sizeof(val8));
2188	} else if ((robo->sih->chip == BCM5357_CHIP_ID) &&
2189	           (robo->sih->chippkg == BCM5358_PKG_ID)) {
2190		/* Fix the duplex mode and speed for Port 4 (MII port). Force
2191		 * full duplex mode and set speed to 100.
2192		 */
2193		si_pmu_chipcontrol(robo->sih, 2, (1 << 1) | (1 << 2), (1 << 1) | (1 << 2));
2194	}
2195
2196	/* Disable management interface access */
2197	if (robo->ops->disable_mgmtif)
2198		robo->ops->disable_mgmtif(robo);
2199
2200	ET_MSG(("%s: Configured PLC MII interface\n", __FUNCTION__));
2201}
2202#endif /* PLC */
2203
2204/* Foxconn added start pling 08/10/2006 */
2205#ifndef _CFE_
2206/* Foxconn add start by aspen Bai, 10/09/2008 */
2207/* Add Linux API to read link status */
2208int robo_read_link_status(int lan_wan, int *link, int *speed, int *duplex)
2209{
2210    robo_info_t *robo = robo_ptr;
2211    uint16 reg_link, reg_duplex;
2212    uint32 reg_speed;
2213    int port_speed, port_link;
2214    int i;
2215
2216    if (robo == NULL)
2217        return 0;
2218
2219	/* Read link status summary register */
2220	robo->ops->read_reg(robo, PAGE_STATUS, REG_LINK_SUM, &reg_link, sizeof(reg_link));
2221
2222	/* Read port speed summary register */
2223	robo->ops->read_reg(robo, PAGE_STATUS, REG_SPEED_SUM, &reg_speed, sizeof(reg_speed));
2224
2225	/* Read duplex status summary register */
2226	robo->ops->read_reg(robo, PAGE_STATUS, REG_DUPLEX_SUM, &reg_duplex, sizeof(reg_duplex));
2227
2228    if (lan_wan == 0) /*lan status*/
2229    {
2230        *speed = 0;
2231        *link = (reg_link & ROBO_LAN_PORTMAP);
2232
2233        /* Check speed of link "up" ports only */
2234        for (i = ROBO_LAN_PORT_IDX_START; i <= ROBO_LAN_PORT_IDX_END; i++) {
2235            port_link  = (reg_link >> i) & 0x01;
2236            /* Foxconn add start by aspen Bai, 10/09/2008 */
2237#if (defined BCM4716) || (defined BCM5356) || (defined BCM5325E)
2238            /* BCM5325E & BCM5325F */
2239            port_speed = (reg_speed >> i) & 0x01;
2240#else
2241            /* BCM53115S */
2242            port_speed = (reg_speed >> (2*i)) & 0x03;
2243#endif
2244            /* Foxconn add end by aspen Bai, 10/09/2008 */
2245            if (port_link && port_speed > *speed)
2246                *speed = port_speed;
2247        }
2248
2249        *duplex = reg_duplex & *link;
2250    }
2251    else /*wan status*/
2252    {
2253        *link  = (reg_link >> ROBO_WAN_PORT) & 0x01;
2254#if (defined BCM4716) || (defined BCM5356) || (defined BCM5325E)
2255        /* BCM5325E & BCM5325F */
2256        *speed = (reg_speed >> ROBO_WAN_PORT) & 0x01;
2257#else
2258        /* BCM53115S */
2259        *speed = (reg_speed >> (2*ROBO_WAN_PORT)) & 0x03;
2260#endif
2261        *duplex = (reg_duplex >> ROBO_WAN_PORT) & 0x01;
2262    }
2263
2264	return 0;
2265}
2266/* Foxconn add end by aspen Bai, 10/09/2008 */
2267
2268#endif  /* ! _CFE_ */
2269/* Foxconn added end pling 08/10/2006 */
2270