Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / shared / bcmrobo.c
blobb5dfe5dc00712fc08a8b4f98139ecabb2b9eabeb
1 /*
2 * Broadcom 53xx RoboSwitch device driver.
4 * Copyright (C) 2009, 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.
12 * $Id: bcmrobo.c,v 1.16.2.8 2009/07/22 15:00:48 Exp $
16 #include <typedefs.h>
17 #include <osl.h>
18 #include <bcmutils.h>
19 #include <siutils.h>
20 #include <hndsoc.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>
30 #define ET_ERROR(args)
31 #define ET_MSG(args)
33 #define VARG(var, len) (((len) == 1) ? *((uint8 *)(var)) : \
34 ((len) == 2) ? *((uint16 *)(var)) : \
35 *((uint32 *)(var)))
38 * Switch can be programmed through SPI interface, which
39 * has a rreg and a wreg functions to read from and write to
40 * registers.
43 /* MII access registers */
44 #define PSEUDO_PHYAD 0x1E /* MII Pseudo PHY address */
45 #define REG_MII_CTRL 0x00 /* 53115 MII control register */
46 #define REG_MII_PAGE 0x10 /* MII Page register */
47 #define REG_MII_ADDR 0x11 /* MII Address register */
48 #define REG_MII_DATA0 0x18 /* MII Data register 0 */
49 #define REG_MII_DATA1 0x19 /* MII Data register 1 */
50 #define REG_MII_DATA2 0x1a /* MII Data register 2 */
51 #define REG_MII_DATA3 0x1b /* MII Data register 3 */
52 #define REG_MII_BRCM_TEST 0x1f /* Broadcom test register */
53 #define REG_MII_AUX_STATUS2 0x1b /* Auxiliary status 2 register */
54 #define REG_MII_AUTO_PWRDOWN 0x1C /* 53115 Auto power down register */
56 /* Page numbers */
57 #define PAGE_CTRL 0x00 /* Control page */
58 #define PAGE_STATUS 0x01 /* Status page */
59 #define PAGE_MMR 0x02 /* 5397 Management/Mirroring page */
60 #define PAGE_VTBL 0x05 /* ARL/VLAN Table access page */
61 #define PAGE_VLAN 0x34 /* VLAN page */
62 #define PAGE_JUMBO 0x40 /* JUMBO frame page */
64 /* Control page registers */
65 #define REG_CTRL_PORT0 0x00 /* Port 0 traffic control register */
66 #define REG_CTRL_PORT1 0x01 /* Port 1 traffic control register */
67 #define REG_CTRL_PORT2 0x02 /* Port 2 traffic control register */
68 #define REG_CTRL_PORT3 0x03 /* Port 3 traffic control register */
69 #define REG_CTRL_PORT4 0x04 /* Port 4 traffic control register */
70 #define REG_CTRL_PORT5 0x05 /* Port 5 traffic control register */
71 #define REG_CTRL_PORT6 0x06 /* Port 6 traffic control register */
72 #define REG_CTRL_PORT7 0x07 /* Port 7 traffic control register */
73 #define REG_CTRL_IMP 0x08 /* IMP port traffic control register */
74 #define REG_CTRL_MODE 0x0B /* Switch Mode register */
75 #define REG_CTRL_MIIPO 0x0E /* 5325: MII Port Override register */
76 #define REG_CTRL_PWRDOWN 0x0F /* 5325: Power Down Mode register */
77 #define REG_CTRL_SRST 0x79 /* Software reset control register */
79 /* Status Page Registers */
80 #define REG_STATUS_LINK 0x00 /* Link Status Summary */
82 #define REG_DEVICE_ID 0x30 /* 539x Device id: */
84 /* JUMBO Control Register */
85 #define REG_JUMBO_CTRL 0x01
86 #define REG_JUMBO_SIZE 0x05
88 /* Status Page Registers */
89 #define REG_STATUS_LINK 0x00 /* Link Status Summary */
91 /* VLAN page registers */
92 #define REG_VLAN_CTRL0 0x00 /* VLAN Control 0 register */
93 #define REG_VLAN_CTRL1 0x01 /* VLAN Control 1 register */
94 #define REG_VLAN_CTRL4 0x04 /* VLAN Control 4 register */
95 #define REG_VLAN_CTRL5 0x05 /* VLAN Control 5 register */
96 #define REG_VLAN_ACCESS 0x06 /* VLAN Table Access register */
97 #define REG_VLAN_ACCESS_5365 0x08 /* 5365 VLAN Table Access register */
98 #define REG_VLAN_WRITE 0x08 /* VLAN Write register */
99 #define REG_VLAN_WRITE_5365 0x0A /* 5365 VLAN Write register */
100 #define REG_VLAN_READ 0x0C /* VLAN Read register */
101 #define REG_VLAN_PTAG0 0x10 /* VLAN Default Port Tag register - port 0 */
102 #define REG_VLAN_PTAG1 0x12 /* VLAN Default Port Tag register - port 1 */
103 #define REG_VLAN_PTAG2 0x14 /* VLAN Default Port Tag register - port 2 */
104 #define REG_VLAN_PTAG3 0x16 /* VLAN Default Port Tag register - port 3 */
105 #define REG_VLAN_PTAG4 0x18 /* VLAN Default Port Tag register - port 4 */
106 #define REG_VLAN_PTAG5 0x1a /* VLAN Default Port Tag register - port 5 */
107 #define REG_VLAN_PTAG6 0x1c /* VLAN Default Port Tag register - port 6 */
108 #define REG_VLAN_PTAG7 0x1e /* VLAN Default Port Tag register - port 7 */
109 #define REG_VLAN_PTAG8 0x20 /* 539x: VLAN Default Port Tag register - IMP port */
110 #define REG_VLAN_PMAP 0x20 /* 5325: VLAN Priority Re-map register */
112 #define VLAN_NUMVLANS 16 /* # of VLANs */
115 /* ARL/VLAN Table Access page registers */
116 #define REG_VTBL_CTRL 0x00 /* ARL Read/Write Control */
117 #define REG_VTBL_MINDX 0x02 /* MAC Address Index */
118 #define REG_VTBL_VINDX 0x08 /* VID Table Index */
119 #define REG_VTBL_ARL_E0 0x10 /* ARL Entry 0 */
120 #define REG_VTBL_ARL_E1 0x18 /* ARL Entry 1 */
121 #define REG_VTBL_DAT_E0 0x18 /* ARL Table Data Entry 0 */
122 #define REG_VTBL_SCTRL 0x20 /* ARL Search Control */
123 #define REG_VTBL_SADDR 0x22 /* ARL Search Address */
124 #define REG_VTBL_SRES 0x24 /* ARL Search Result */
125 #define REG_VTBL_SREXT 0x2c /* ARL Search Result */
126 #define REG_VTBL_VID_E0 0x30 /* VID Entry 0 */
127 #define REG_VTBL_VID_E1 0x32 /* VID Entry 1 */
128 #define REG_VTBL_PREG 0xFF /* Page Register */
129 #define REG_VTBL_ACCESS 0x60 /* VLAN table access register */
130 #define REG_VTBL_INDX 0x61 /* VLAN table address index register */
131 #define REG_VTBL_ENTRY 0x63 /* VLAN table entry register */
132 #define REG_VTBL_ACCESS_5395 0x80 /* VLAN table access register */
133 #define REG_VTBL_INDX_5395 0x81 /* VLAN table address index register */
134 #define REG_VTBL_ENTRY_5395 0x83 /* VLAN table entry register */
136 /* SPI registers */
137 #define REG_SPI_PAGE 0xff /* SPI Page register */
139 /* Access switch registers through GPIO/SPI */
141 /* Minimum timing constants */
142 #define SCK_EDGE_TIME 2 /* clock edge duration - 2us */
143 #define MOSI_SETUP_TIME 1 /* input setup duration - 1us */
144 #define SS_SETUP_TIME 1 /* select setup duration - 1us */
146 /* misc. constants */
147 #define SPI_MAX_RETRY 100
149 /* Enable GPIO access to the chip */
150 static void
151 gpio_enable(robo_info_t *robo)
153 /* Enable GPIO outputs with SCK and MOSI low, SS high */
154 si_gpioout(robo->sih, robo->ss | robo->sck | robo->mosi, robo->ss, GPIO_DRV_PRIORITY);
155 si_gpioouten(robo->sih, robo->ss | robo->sck | robo->mosi,
156 robo->ss | robo->sck | robo->mosi, GPIO_DRV_PRIORITY);
159 /* Disable GPIO access to the chip */
160 static void
161 gpio_disable(robo_info_t *robo)
163 /* Disable GPIO outputs with all their current values */
164 si_gpioouten(robo->sih, robo->ss | robo->sck | robo->mosi, 0, GPIO_DRV_PRIORITY);
167 /* Write a byte stream to the chip thru SPI */
168 static int
169 spi_write(robo_info_t *robo, uint8 *buf, uint len)
171 uint i;
172 uint8 mask;
174 /* Byte bang from LSB to MSB */
175 for (i = 0; i < len; i++) {
176 /* Bit bang from MSB to LSB */
177 for (mask = 0x80; mask; mask >>= 1) {
178 /* Clock low */
179 si_gpioout(robo->sih, robo->sck, 0, GPIO_DRV_PRIORITY);
180 OSL_DELAY(SCK_EDGE_TIME);
182 /* Sample on rising edge */
183 if (mask & buf[i])
184 si_gpioout(robo->sih, robo->mosi, robo->mosi, GPIO_DRV_PRIORITY);
185 else
186 si_gpioout(robo->sih, robo->mosi, 0, GPIO_DRV_PRIORITY);
187 OSL_DELAY(MOSI_SETUP_TIME);
189 /* Clock high */
190 si_gpioout(robo->sih, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
191 OSL_DELAY(SCK_EDGE_TIME);
195 return 0;
198 /* Read a byte stream from the chip thru SPI */
199 static int
200 spi_read(robo_info_t *robo, uint8 *buf, uint len)
202 uint i, timeout;
203 uint8 rack, mask, byte;
205 /* Timeout after 100 tries without RACK */
206 for (i = 0, rack = 0, timeout = SPI_MAX_RETRY; i < len && timeout;) {
207 /* Bit bang from MSB to LSB */
208 for (mask = 0x80, byte = 0; mask; mask >>= 1) {
209 /* Clock low */
210 si_gpioout(robo->sih, robo->sck, 0, GPIO_DRV_PRIORITY);
211 OSL_DELAY(SCK_EDGE_TIME);
213 /* Sample on falling edge */
214 if (si_gpioin(robo->sih) & robo->miso)
215 byte |= mask;
217 /* Clock high */
218 si_gpioout(robo->sih, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
219 OSL_DELAY(SCK_EDGE_TIME);
221 /* RACK when bit 0 is high */
222 if (!rack) {
223 rack = (byte & 1);
224 timeout--;
225 continue;
227 /* Byte bang from LSB to MSB */
228 buf[i] = byte;
229 i++;
232 if (timeout == 0) {
233 ET_ERROR(("spi_read: timeout"));
234 return -1;
237 return 0;
240 /* Enable/disable SPI access */
241 static void
242 spi_select(robo_info_t *robo, uint8 spi)
244 if (spi) {
245 /* Enable SPI access */
246 si_gpioout(robo->sih, robo->ss, 0, GPIO_DRV_PRIORITY);
247 } else {
248 /* Disable SPI access */
249 si_gpioout(robo->sih, robo->ss, robo->ss, GPIO_DRV_PRIORITY);
251 OSL_DELAY(SS_SETUP_TIME);
255 /* Select chip and page */
256 static void
257 spi_goto(robo_info_t *robo, uint8 page)
259 uint8 reg8 = REG_SPI_PAGE; /* page select register */
260 uint8 cmd8;
262 /* Issue the command only when we are on a different page */
263 if (robo->page == page)
264 return;
266 robo->page = page;
268 /* Enable SPI access */
269 spi_select(robo, 1);
271 /* Select new page with CID 0 */
272 cmd8 = ((6 << 4) | /* normal SPI */
273 1); /* write */
274 spi_write(robo, &cmd8, 1);
275 spi_write(robo, &reg8, 1);
276 spi_write(robo, &page, 1);
278 /* Disable SPI access */
279 spi_select(robo, 0);
282 /* Write register thru SPI */
283 static int
284 spi_wreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
286 int status = 0;
287 uint8 cmd8;
288 union {
289 uint8 val8;
290 uint16 val16;
291 uint32 val32;
292 } bytes;
294 /* validate value length and buffer address */
295 ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
296 (len == 4 && !((int)val & 3)));
298 /* Select chip and page */
299 spi_goto(robo, page);
301 /* Enable SPI access */
302 spi_select(robo, 1);
304 /* Write with CID 0 */
305 cmd8 = ((6 << 4) | /* normal SPI */
306 1); /* write */
307 spi_write(robo, &cmd8, 1);
308 spi_write(robo, &addr, 1);
309 switch (len) {
310 case 1:
311 bytes.val8 = *(uint8 *)val;
312 break;
313 case 2:
314 bytes.val16 = htol16(*(uint16 *)val);
315 break;
316 case 4:
317 bytes.val32 = htol32(*(uint32 *)val);
318 break;
320 spi_write(robo, (uint8 *)val, len);
322 ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, addr,
323 *(uint16 *)val, len));
324 /* Disable SPI access */
325 spi_select(robo, 0);
326 return status;
329 /* Read register thru SPI in fast SPI mode */
330 static int
331 spi_rreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
333 int status = 0;
334 uint8 cmd8;
335 union {
336 uint8 val8;
337 uint16 val16;
338 uint32 val32;
339 } bytes;
341 /* validate value length and buffer address */
342 ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
343 (len == 4 && !((int)val & 3)));
345 /* Select chip and page */
346 spi_goto(robo, page);
348 /* Enable SPI access */
349 spi_select(robo, 1);
351 /* Fast SPI read with CID 0 and byte offset 0 */
352 cmd8 = (1 << 4); /* fast SPI */
353 spi_write(robo, &cmd8, 1);
354 spi_write(robo, &addr, 1);
355 status = spi_read(robo, (uint8 *)&bytes, len);
356 switch (len) {
357 case 1:
358 *(uint8 *)val = bytes.val8;
359 break;
360 case 2:
361 *(uint16 *)val = ltoh16(bytes.val16);
362 break;
363 case 4:
364 *(uint32 *)val = ltoh32(bytes.val32);
365 break;
368 ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, addr,
369 *(uint16 *)val, len));
371 /* Disable SPI access */
372 spi_select(robo, 0);
373 return status;
376 /* SPI/gpio interface functions */
377 static dev_ops_t spigpio = {
378 gpio_enable,
379 gpio_disable,
380 spi_wreg,
381 spi_rreg,
382 "SPI (GPIO)"
386 /* Access switch registers through MII (MDC/MDIO) */
388 #define MII_MAX_RETRY 100
390 /* Write register thru MDC/MDIO */
391 static int
392 mii_wreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
394 uint16 cmd16, val16;
395 void *h = robo->h;
396 int i;
397 uint8 *ptr = (uint8 *)val;
399 /* validate value length and buffer address */
400 ASSERT(len == 1 || len == 6 || len == 8 ||
401 ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
403 ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, reg,
404 VARG(val, len), len));
406 /* set page number - MII register 0x10 */
407 if (robo->page != page) {
408 cmd16 = ((page << 8) | /* page number */
409 1); /* mdc/mdio access enable */
410 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
411 robo->page = page;
414 switch (len) {
415 case 8:
416 val16 = ptr[7];
417 val16 = ((val16 << 8) | ptr[6]);
418 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA3, val16);
419 /* FALLTHRU */
421 case 6:
422 val16 = ptr[5];
423 val16 = ((val16 << 8) | ptr[4]);
424 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA2, val16);
425 val16 = ptr[3];
426 val16 = ((val16 << 8) | ptr[2]);
427 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
428 val16 = ptr[1];
429 val16 = ((val16 << 8) | ptr[0]);
430 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
431 break;
433 case 4:
434 val16 = (uint16)((*(uint32 *)val) >> 16);
435 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
436 val16 = (uint16)(*(uint32 *)val);
437 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
438 break;
440 case 2:
441 val16 = *(uint16 *)val;
442 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
443 break;
445 case 1:
446 val16 = *(uint8 *)val;
447 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
448 break;
451 /* set register address - MII register 0x11 */
452 cmd16 = ((reg << 8) | /* register address */
453 1); /* opcode write */
454 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
456 /* is operation finished? */
457 for (i = MII_MAX_RETRY; i > 0; i --) {
458 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
459 if ((val16 & 3) == 0)
460 break;
463 /* timed out */
464 if (!i) {
465 ET_ERROR(("mii_wreg: timeout"));
466 return -1;
468 return 0;
471 /* Read register thru MDC/MDIO */
472 static int
473 mii_rreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
475 uint16 cmd16, val16;
476 void *h = robo->h;
477 int i;
478 uint8 *ptr = (uint8 *)val;
480 /* validate value length and buffer address */
481 ASSERT(len == 1 || len == 6 || len == 8 ||
482 ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
484 /* set page number - MII register 0x10 */
485 if (robo->page != page) {
486 cmd16 = ((page << 8) | /* page number */
487 1); /* mdc/mdio access enable */
488 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
489 robo->page = page;
492 /* set register address - MII register 0x11 */
493 cmd16 = ((reg << 8) | /* register address */
494 2); /* opcode read */
495 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
497 /* is operation finished? */
498 for (i = MII_MAX_RETRY; i > 0; i --) {
499 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
500 if ((val16 & 3) == 0)
501 break;
503 /* timed out */
504 if (!i) {
505 ET_ERROR(("mii_rreg: timeout"));
506 return -1;
509 switch (len) {
510 case 8:
511 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA3);
512 ptr[7] = (val16 >> 8);
513 ptr[6] = (val16 & 0xff);
514 /* FALLTHRU */
516 case 6:
517 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA2);
518 ptr[5] = (val16 >> 8);
519 ptr[4] = (val16 & 0xff);
520 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
521 ptr[3] = (val16 >> 8);
522 ptr[2] = (val16 & 0xff);
523 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
524 ptr[1] = (val16 >> 8);
525 ptr[0] = (val16 & 0xff);
526 break;
528 case 4:
529 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
530 *(uint32 *)val = (((uint32)val16) << 16);
531 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
532 *(uint32 *)val |= val16;
533 break;
535 case 2:
536 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
537 *(uint16 *)val = val16;
538 break;
540 case 1:
541 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
542 *(uint8 *)val = (uint8)(val16 & 0xff);
543 break;
546 ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, reg,
547 VARG(val, len), len));
549 return 0;
552 /* MII interface functions */
553 static dev_ops_t mdcmdio = {
554 NULL,
555 NULL,
556 mii_wreg,
557 mii_rreg,
558 "MII (MDC/MDIO)"
561 /* High level switch configuration functions. */
563 /* Get access to the RoboSwitch */
564 robo_info_t *
565 bcm_robo_attach(si_t *sih, void *h, char *vars, miird_f miird, miiwr_f miiwr)
567 robo_info_t *robo;
568 uint32 reset, idx;
569 char *et1port, *et1phyaddr;
570 int mdcport = 0, phyaddr = 0;
572 /* Allocate and init private state */
573 if (!(robo = MALLOC(si_osh(sih), sizeof(robo_info_t)))) {
574 ET_ERROR(("robo_attach: out of memory, malloced %d bytes",
575 MALLOCED(si_osh(sih))));
576 return NULL;
578 bzero(robo, sizeof(robo_info_t));
580 robo->h = h;
581 robo->sih = sih;
582 robo->vars = vars;
583 robo->miird = miird;
584 robo->miiwr = miiwr;
585 robo->page = -1;
587 /* Trigger external reset by nvram variable existance */
588 if ((reset = getgpiopin(robo->vars, "robo_reset", GPIO_PIN_NOTDEFINED)) !=
589 GPIO_PIN_NOTDEFINED) {
591 * Reset sequence: RESET low(50ms)->high(20ms)
593 * We have to perform a full sequence for we don't know how long
594 * it has been from power on till now.
596 ET_MSG(("%s: Using external reset in gpio pin %d\n", __FUNCTION__, reset));
597 reset = 1 << reset;
599 /* Keep RESET low for 50 ms */
600 si_gpioout(sih, reset, 0, GPIO_DRV_PRIORITY);
601 si_gpioouten(sih, reset, reset, GPIO_DRV_PRIORITY);
602 bcm_mdelay(50);
604 /* Keep RESET high for at least 20 ms */
605 si_gpioout(sih, reset, reset, GPIO_DRV_PRIORITY);
606 bcm_mdelay(20);
607 } else {
608 /* In case we need it */
609 idx = si_coreidx(sih);
611 if (si_setcore(sih, ROBO_CORE_ID, 0)) {
612 /* If we have an internal robo core, reset it using si_core_reset */
613 ET_MSG(("%s: Resetting internal robo core\n", __FUNCTION__));
614 si_core_reset(sih, 0, 0);
616 si_setcoreidx(sih, idx);
619 if (miird && miiwr) {
620 uint16 tmp;
621 int rc, retry_count = 0;
623 /* Read the PHY ID */
624 tmp = miird(h, PSEUDO_PHYAD, 2);
626 /* WAR: Enable mdc/mdio access to the switch registers. Unless
627 * a write to bit 0 of pseudo phy register 16 is done we are
628 * unable to talk to the switch on a customer ref design.
630 if (tmp == 0xffff) {
631 miiwr(h, PSEUDO_PHYAD, 16, 1);
632 tmp = miird(h, PSEUDO_PHYAD, 2);
635 if (tmp != 0xffff) {
636 do {
637 rc = mii_rreg(robo, PAGE_MMR, REG_DEVICE_ID,
638 &robo->devid, sizeof(uint16));
639 if (rc != 0)
640 break;
641 retry_count++;
642 } while ((robo->devid == 0) && (retry_count < 10));
644 ET_MSG(("%s: devid read %ssuccesfully via mii: 0x%x\n",
645 __FUNCTION__, rc ? "un" : "", robo->devid));
646 ET_MSG(("%s: mii access to switch works\n", __FUNCTION__));
647 robo->ops = &mdcmdio;
648 if ((rc != 0) || (robo->devid == 0)) {
649 ET_MSG(("%s: error reading devid, assuming 5325e\n",
650 __FUNCTION__));
651 robo->devid = DEVID5325;
654 ET_MSG(("%s: devid: 0x%x\n", __FUNCTION__, robo->devid));
657 if ((robo->devid == DEVID5395) ||
658 (robo->devid == DEVID5397) ||
659 (robo->devid == DEVID5398)) {
660 uint8 srst_ctrl;
662 /* If it is a 539x switch, use the soft reset register */
663 ET_MSG(("%s: Resetting 539x robo switch\n", __FUNCTION__));
665 /* Reset the 539x switch core and register file */
666 srst_ctrl = 0x83;
667 mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
668 srst_ctrl = 0x00;
669 mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
672 if (!robo->ops) {
673 int mosi, miso, ss, sck;
675 robo->ops = &spigpio;
676 robo->devid = DEVID5325;
678 /* Init GPIO mapping. Default 2, 3, 4, 5 */
679 ss = getgpiopin(vars, "robo_ss", 2);
680 if (ss == GPIO_PIN_NOTDEFINED) {
681 ET_ERROR(("robo_attach: robo_ss gpio fail: GPIO 2 in use"));
682 goto error;
684 robo->ss = 1 << ss;
685 sck = getgpiopin(vars, "robo_sck", 3);
686 if (sck == GPIO_PIN_NOTDEFINED) {
687 ET_ERROR(("robo_attach: robo_sck gpio fail: GPIO 3 in use"));
688 goto error;
690 robo->sck = 1 << sck;
691 mosi = getgpiopin(vars, "robo_mosi", 4);
692 if (mosi == GPIO_PIN_NOTDEFINED) {
693 ET_ERROR(("robo_attach: robo_mosi gpio fail: GPIO 4 in use"));
694 goto error;
696 robo->mosi = 1 << mosi;
697 miso = getgpiopin(vars, "robo_miso", 5);
698 if (miso == GPIO_PIN_NOTDEFINED) {
699 ET_ERROR(("robo_attach: robo_miso gpio fail: GPIO 5 in use"));
700 goto error;
702 robo->miso = 1 << miso;
703 ET_MSG(("%s: ss %d sck %d mosi %d miso %d\n", __FUNCTION__,
704 ss, sck, mosi, miso));
707 /* sanity check */
708 ASSERT(robo->ops);
709 ASSERT(robo->ops->write_reg);
710 ASSERT(robo->ops->read_reg);
711 ASSERT((robo->devid == DEVID5325) ||
712 (robo->devid == DEVID5395) ||
713 (robo->devid == DEVID5397) ||
714 (robo->devid == DEVID5398) ||
715 (robo->devid == DEVID53115));
717 /* nvram variable switch_mode controls the power save mode on the switch
718 * set the default value in the beginning
720 robo->pwrsave_mode_manual = getintvar(robo->vars, "switch_mode");
721 robo->pwrsave_mode_auto = getintvar(robo->vars, "switch_mode_auto");
723 /* Determining what all phys need to be included in
724 * power save operation
726 et1port = getvar(vars, "et1mdcport");
727 if (et1port)
728 mdcport = bcm_atoi(et1port);
730 et1phyaddr = getvar(vars, "et1phyaddr");
731 if (et1phyaddr)
732 phyaddr = bcm_atoi(et1phyaddr);
734 if ((mdcport == 0) && (phyaddr == 4))
735 /* For 5325F switch we need to do only phys 0-3 */
736 robo->pwrsave_phys = 0xf;
737 else
738 /* By default all 5 phys are put into power save if there is no link */
739 robo->pwrsave_phys = 0x1f;
741 return robo;
743 error:
744 bcm_robo_detach(robo);
745 return NULL;
748 /* Release access to the RoboSwitch */
749 void
750 bcm_robo_detach(robo_info_t *robo)
752 MFREE(si_osh(robo->sih), robo, sizeof(robo_info_t));
755 /* Enable the device and set it to a known good state */
757 bcm_robo_enable_device(robo_info_t *robo)
759 uint8 reg_offset, reg_val;
760 int ret = 0;
762 /* Enable management interface access */
763 if (robo->ops->enable_mgmtif)
764 robo->ops->enable_mgmtif(robo);
766 if (robo->devid == DEVID5398) {
767 /* Disable unused ports: port 6 and 7 */
768 for (reg_offset = REG_CTRL_PORT6; reg_offset <= REG_CTRL_PORT7; reg_offset ++) {
769 /* Set bits [1:0] to disable RX and TX */
770 reg_val = 0x03;
771 robo->ops->write_reg(robo, PAGE_CTRL, reg_offset, &reg_val,
772 sizeof(reg_val));
776 if (robo->devid == DEVID5325) {
777 /* Must put the switch into Reverse MII mode! */
779 /* MII port state override (page 0 register 14) */
780 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val, sizeof(reg_val));
782 /* Bit 4 enables reverse MII mode */
783 if (!(reg_val & (1 << 4))) {
784 /* Enable RvMII */
785 reg_val |= (1 << 4);
786 robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
787 sizeof(reg_val));
789 /* Read back */
790 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
791 sizeof(reg_val));
792 if (!(reg_val & (1 << 4))) {
793 ET_ERROR(("robo_enable_device: enabling RvMII mode failed\n"));
794 ret = -1;
799 /* Disable management interface access */
800 if (robo->ops->disable_mgmtif)
801 robo->ops->disable_mgmtif(robo);
803 return ret;
806 /* Port flags */
807 #define FLAG_TAGGED 't' /* output tagged (external ports only) */
808 #define FLAG_UNTAG 'u' /* input & output untagged (CPU port only, for OS (linux, ...) */
809 #define FLAG_LAN '*' /* input & output untagged (CPU port only, for CFE */
811 /* port descriptor */
812 typedef struct {
813 uint32 untag; /* untag enable bit (Page 0x05 Address 0x63-0x66 Bit[17:9]) */
814 uint32 member; /* vlan member bit (Page 0x05 Address 0x63-0x66 Bit[7:0]) */
815 uint8 ptagr; /* port tag register address (Page 0x34 Address 0x10-0x1F) */
816 uint8 cpu; /* is this cpu port? */
817 } pdesc_t;
819 pdesc_t pdesc97[] = {
820 /* 5395/5397/5398/53115S is 0 ~ 7. port 8 is IMP port. */
821 /* port 0 */ {1 << 9, 1 << 0, REG_VLAN_PTAG0, 0},
822 /* port 1 */ {1 << 10, 1 << 1, REG_VLAN_PTAG1, 0},
823 /* port 2 */ {1 << 11, 1 << 2, REG_VLAN_PTAG2, 0},
824 /* port 3 */ {1 << 12, 1 << 3, REG_VLAN_PTAG3, 0},
825 /* port 4 */ {1 << 13, 1 << 4, REG_VLAN_PTAG4, 0},
826 /* port 5 */ {1 << 14, 1 << 5, REG_VLAN_PTAG5, 0},
827 /* port 6 */ {1 << 15, 1 << 6, REG_VLAN_PTAG6, 0},
828 /* port 7 */ {1 << 16, 1 << 7, REG_VLAN_PTAG7, 0},
829 /* mii port */ {1 << 17, 1 << 8, REG_VLAN_PTAG8, 1},
832 pdesc_t pdesc25[] = {
833 /* port 0 */ {1 << 6, 1 << 0, REG_VLAN_PTAG0, 0},
834 /* port 1 */ {1 << 7, 1 << 1, REG_VLAN_PTAG1, 0},
835 /* port 2 */ {1 << 8, 1 << 2, REG_VLAN_PTAG2, 0},
836 /* port 3 */ {1 << 9, 1 << 3, REG_VLAN_PTAG3, 0},
837 /* port 4 */ {1 << 10, 1 << 4, REG_VLAN_PTAG4, 0},
838 /* mii port */ {1 << 11, 1 << 5, REG_VLAN_PTAG5, 1},
841 /* Configure the VLANs */
843 bcm_robo_config_vlan(robo_info_t *robo, uint8 *mac_addr)
845 uint8 val8;
846 uint16 val16;
847 uint32 val32;
848 pdesc_t *pdesc;
849 int pdescsz;
850 uint16 vid, vid0;
851 uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 };
853 /* Enable management interface access */
854 if (robo->ops->enable_mgmtif)
855 robo->ops->enable_mgmtif(robo);
857 /* setup global vlan configuration */
858 /* VLAN Control 0 Register (Page 0x34, Address 0) */
859 robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
860 val8 |= ((1 << 7) | /* enable 802.1Q VLAN */
861 (3 << 5)); /* individual VLAN learning mode */
862 if (robo->devid == DEVID5325)
863 val8 &= ~(1 << 1); /* must clear reserved bit 1 */
864 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
866 /* VLAN Control 1 Register (Page 0x34, Address 1) */
867 robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
868 val8 |= ((1 << 2) | /* enable RSV multicast V Fwdmap */
869 (1 << 3)); /* enable RSV multicast V Untagmap */
870 if (robo->devid == DEVID5325)
871 val8 |= (1 << 1); /* enable RSV multicast V Tagging */
872 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
874 /* Jumbo Frame control refister (Page 0x40, Address 0x01 */
875 /* Added by Yen */
876 if (nvram_match("jumbo_frame_enable", "1")) {
877 val8 = (( 1 << 0) |
878 ( 1 << 1) |
879 ( 1 << 2) |
880 ( 1 << 3) |
881 ( 1 << 4)
883 /* Write the size of Packet */
884 // move to router/rc
885 // val8 = bcm_atoe(nvram_get("jumbo_frame_size"));
886 // robo->ops->write_reg(robo, PAGE_JUMBO, REG_JUMBO_SIZE, &val8, sizeof(val8));
888 else
889 val8 = 0;
891 robo->ops->write_reg(robo, PAGE_JUMBO, REG_JUMBO_CTRL, &val8, sizeof(val8));
893 arl_entry[0] = mac_addr[5];
894 arl_entry[1] = mac_addr[4];
895 arl_entry[2] = mac_addr[3];
896 arl_entry[3] = mac_addr[2];
897 arl_entry[4] = mac_addr[1];
898 arl_entry[5] = mac_addr[0];
900 if (robo->devid == DEVID5325) {
901 /* Init the entry 1 of the bin */
902 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1,
903 arl_entry1, sizeof(arl_entry1));
904 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1,
905 arl_entry1, 1);
907 /* Init the entry 0 of the bin */
908 arl_entry[6] = 0x8; /* Port Id: MII */
909 arl_entry[7] = 0xc0; /* Static Entry, Valid */
911 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0,
912 arl_entry, sizeof(arl_entry));
913 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX,
914 arl_entry, ETHER_ADDR_LEN);
916 /* VLAN Control 4 Register (Page 0x34, Address 4) */
917 val8 = (1 << 6); /* drop frame with VID violation */
918 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8));
920 /* VLAN Control 5 Register (Page 0x34, Address 5) */
921 val8 = (1 << 3); /* drop frame when miss V table */
922 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8));
924 pdesc = pdesc25;
925 pdescsz = sizeof(pdesc25) / sizeof(pdesc_t);
926 } else {
927 /* Initialize the MAC Addr Index Register */
928 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX,
929 arl_entry, ETHER_ADDR_LEN);
931 pdesc = pdesc97;
932 pdescsz = sizeof(pdesc97) / sizeof(pdesc_t);
935 vid0 = getintvar(robo->vars, "vlan0tag");
937 /* setup each vlan. max. 16 vlans. */
938 /* force vlan id to be equal to vlan number */
939 for (vid = 0; vid < VLAN_NUMVLANS; vid ++) {
940 char vlanports[] = "vlanXXXXports";
941 char port[] = "XXXX", *ports, *next, *cur;
942 uint32 untag = 0;
943 uint32 member = 0;
944 int pid, len;
946 /* no members if VLAN id is out of limitation */
947 if (vid > VLAN_MAXVID)
948 goto vlan_setup;
950 /* get vlan member ports from nvram */
951 sprintf(vlanports, "vlan%dports", vid);
952 ports = getvar(robo->vars, vlanports);
954 /* In 539x vid == 0 us invalid?? */
955 if ((robo->devid != DEVID5325) && (vid == 0)) {
956 if (ports)
957 ET_ERROR(("VID 0 is set in nvram, Ignoring\n"));
958 continue;
961 /* disable this vlan if not defined */
962 if (!ports)
963 goto vlan_setup;
966 * setup each port in the vlan. cpu port needs special handing
967 * (with or without output tagging) to support linux/pmon/cfe.
969 for (cur = ports; cur; cur = next) {
970 /* tokenize the port list */
971 while (*cur == ' ')
972 cur ++;
973 next = bcmstrstr(cur, " ");
974 len = next ? next - cur : strlen(cur);
975 if (!len)
976 break;
977 if (len > sizeof(port) - 1)
978 len = sizeof(port) - 1;
979 strncpy(port, cur, len);
980 port[len] = 0;
982 /* make sure port # is within the range */
983 pid = bcm_atoi(port);
984 if (pid >= pdescsz) {
985 ET_ERROR(("robo_config_vlan: port %d in vlan%dports is out "
986 "of range[0-%d]\n", pid, vid, pdescsz));
987 continue;
990 /* build VLAN registers values */
991 #ifndef _CFE_
992 if ((!pdesc[pid].cpu && !strchr(port, FLAG_TAGGED)) ||
993 (pdesc[pid].cpu && strchr(port, FLAG_UNTAG)))
994 #endif
995 untag |= pdesc[pid].untag;
997 member |= pdesc[pid].member;
999 /* set port tag - applies to untagged ingress frames */
1000 /* Default Port Tag Register (Page 0x34, Address 0x10-0x1D) */
1001 #ifdef _CFE_
1002 #define FL FLAG_LAN
1003 #else
1004 #define FL FLAG_UNTAG
1005 #endif /* _CFE_ */
1006 if ((!pdesc[pid].cpu && !strchr(port, FLAG_TAGGED)) ||
1007 strchr(port, FL)) {
1008 val16 = ((0 << 13) | /* priority - always 0 */
1009 vid0 | vid); /* vlan id */
1010 robo->ops->write_reg(robo, PAGE_VLAN, pdesc[pid].ptagr,
1011 &val16, sizeof(val16));
1015 /* Add static ARL entries */
1016 if (robo->devid == DEVID5325) {
1017 val8 = vid;
1018 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E0,
1019 &val8, sizeof(val8));
1020 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX,
1021 &val8, sizeof(val8));
1023 /* Write the entry */
1024 val8 = 0x80;
1025 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1026 &val8, sizeof(val8));
1027 /* Wait for write to complete */
1028 SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1029 &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
1030 100 /* usec */);
1031 } else {
1032 /* Set the VLAN Id in VLAN ID Index Register */
1033 val8 = vid;
1034 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX,
1035 &val8, sizeof(val8));
1037 /* Set the MAC addr and VLAN Id in ARL Table MAC/VID Entry 0
1038 * Register.
1040 arl_entry[6] = vid;
1041 arl_entry[7] = 0x0;
1042 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0,
1043 arl_entry, sizeof(arl_entry));
1045 /* Set the Static bit , Valid bit and Port ID fields in
1046 * ARL Table Data Entry 0 Register
1048 val16 = 0xc008;
1049 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_DAT_E0,
1050 &val16, sizeof(val16));
1052 /* Clear the ARL_R/W bit and set the START/DONE bit in
1053 * the ARL Read/Write Control Register.
1055 val8 = 0x80;
1056 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1057 &val8, sizeof(val8));
1058 /* Wait for write to complete */
1059 SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL,
1060 &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
1061 100 /* usec */);
1064 vlan_setup:
1065 /* setup VLAN ID and VLAN memberships */
1067 val32 = (untag | /* untag enable */
1068 member); /* vlan members */
1069 if (robo->sih->chip == BCM5365_CHIP_ID) {
1070 /* VLAN Write Register (Page 0x34, Address 0x0A) */
1071 val32 = ((1 << 14) | /* valid write */
1072 (untag << 1) | /* untag enable */
1073 member); /* vlan members */
1074 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_WRITE_5365, &val32,
1075 sizeof(val32));
1076 /* VLAN Table Access Register (Page 0x34, Address 0x08) */
1077 val16 = ((1 << 13) | /* start command */
1078 (1 << 12) | /* write state */
1079 vid0 | vid); /* vlan id */
1080 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_ACCESS_5365, &val16,
1081 sizeof(val16));
1082 } else if (robo->devid == DEVID5325) {
1083 val32 |= ((1 << 20) | /* valid write */
1084 ((vid0 >> 4) << 12)); /* vlan id bit[11:4] */
1086 /* VLAN Write Register (Page 0x34, Address 0x08-0x0B) */
1087 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_WRITE, &val32,
1088 sizeof(val32));
1089 /* VLAN Table Access Register (Page 0x34, Address 0x06-0x07) */
1090 val16 = ((1 << 13) | /* start command */
1091 (1 << 12) | /* write state */
1092 vid0 | vid); /* vlan id */
1093 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_ACCESS, &val16,
1094 sizeof(val16));
1095 } else {
1096 uint8 vtble, vtbli, vtbla;
1098 if ((robo->devid == DEVID5395) || (robo->devid == DEVID53115)) {
1099 vtble = REG_VTBL_ENTRY_5395;
1100 vtbli = REG_VTBL_INDX_5395;
1101 vtbla = REG_VTBL_ACCESS_5395;
1102 } else {
1103 vtble = REG_VTBL_ENTRY;
1104 vtbli = REG_VTBL_INDX;
1105 vtbla = REG_VTBL_ACCESS;
1108 /* VLAN Table Entry Register (Page 0x05, Address 0x63-0x66/0x83-0x86) */
1109 robo->ops->write_reg(robo, PAGE_VTBL, vtble, &val32,
1110 sizeof(val32));
1111 /* VLAN Table Address Index Reg (Page 0x05, Address 0x61-0x62/0x81-0x82) */
1112 val16 = vid; /* vlan id */
1113 robo->ops->write_reg(robo, PAGE_VTBL, vtbli, &val16,
1114 sizeof(val16));
1116 /* VLAN Table Access Register (Page 0x34, Address 0x60/0x80) */
1117 val8 = ((1 << 7) | /* start command */
1118 0); /* write */
1119 robo->ops->write_reg(robo, PAGE_VTBL, vtbla, &val8,
1120 sizeof(val8));
1124 if (robo->devid == DEVID5325) {
1125 /* setup priority mapping - applies to tagged ingress frames */
1126 /* Priority Re-map Register (Page 0x34, Address 0x20-0x23) */
1127 val32 = ((0 << 0) | /* 0 -> 0 */
1128 (1 << 3) | /* 1 -> 1 */
1129 (2 << 6) | /* 2 -> 2 */
1130 (3 << 9) | /* 3 -> 3 */
1131 (4 << 12) | /* 4 -> 4 */
1132 (5 << 15) | /* 5 -> 5 */
1133 (6 << 18) | /* 6 -> 6 */
1134 (7 << 21)); /* 7 -> 7 */
1135 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_PMAP, &val32, sizeof(val32));
1138 /* Disable management interface access */
1139 if (robo->ops->disable_mgmtif)
1140 robo->ops->disable_mgmtif(robo);
1142 return 0;
1145 /* Enable switching/forwarding */
1147 bcm_robo_enable_switch(robo_info_t *robo)
1149 int i, max_port_ind, ret = 0;
1150 uint8 val8;
1152 /* Enable management interface access */
1153 if (robo->ops->enable_mgmtif)
1154 robo->ops->enable_mgmtif(robo);
1156 /* Switch Mode register (Page 0, Address 0x0B) */
1157 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1159 /* Bit 1 enables switching/forwarding */
1160 if (!(val8 & (1 << 1))) {
1161 /* Set unmanaged mode */
1162 val8 &= (~(1 << 0));
1164 /* Enable forwarding */
1165 val8 |= (1 << 1);
1166 robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1168 /* Read back */
1169 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1170 if (!(val8 & (1 << 1))) {
1171 ET_ERROR(("robo_enable_switch: enabling forwarding failed\n"));
1172 ret = -1;
1175 /* No spanning tree for unmanaged mode */
1176 val8 = 0;
1177 max_port_ind = ((robo->devid == DEVID5398) ? REG_CTRL_PORT7 : REG_CTRL_PORT4);
1178 for (i = REG_CTRL_PORT0; i <= max_port_ind; i++) {
1179 robo->ops->write_reg(robo, PAGE_CTRL, i, &val8, sizeof(val8));
1182 /* No spanning tree on IMP port too */
1183 robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_IMP, &val8, sizeof(val8));
1186 /* Enable WAN port (#0) on the asus wl-500g deluxe boxes */
1187 val8 = 0;
1188 robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_PORT0, &val8, sizeof(val8));
1190 /* Disable management interface access */
1191 if (robo->ops->disable_mgmtif)
1192 robo->ops->disable_mgmtif(robo);
1194 return ret;
1199 * Update the power save configuration for ports that changed link status.
1201 void
1202 robo_power_save_mode_update(robo_info_t *robo, bool allports)
1204 uint phy;
1205 uint16 link_status, update = 0;
1207 /* read the link status of all ports */
1208 robo->ops->read_reg(robo, PAGE_STATUS, REG_STATUS_LINK,
1209 &link_status, sizeof(uint16));
1210 link_status &= 0x1f;
1212 if (!allports) {
1213 /* return if no change in link status */
1214 if (link_status == robo->prev_status)
1215 return;
1217 ET_MSG(("%s: old link status %x new link status %x\n",
1218 __FUNCTION__, robo->prev_status, link_status));
1220 /* get the link status bits that changed */
1221 update = robo->prev_status ^ link_status;
1224 robo->prev_status = link_status;
1226 /* when link status changes update the power save configuration
1227 * for the corresponding ports. ports that moved to down state
1228 * are put in to power save mode. ports that moved to up state
1229 * are taken out of power save mode.
1231 for (phy = 0; phy < MAX_NO_PHYS; phy++) {
1232 if (!allports && !((update & (1 << phy)) &&
1233 (robo->pwrsave_phys & (1 << phy))))
1234 continue;
1236 if (link_status & (1 << phy)) {
1237 /* link is up, put the phy in normal mode */
1238 ET_MSG(("%s: link up, set port %d to normal mode\n",
1239 __FUNCTION__, phy));
1240 robo_power_save_mode(robo, ROBO_PWRSAVE_NORMAL, phy);
1241 } else {
1242 /* link is down, put phys in auto, manual
1243 * or auto+manual mode based on the config.
1245 if (robo->pwrsave_mode_auto & (1 << phy)) {
1246 ET_MSG(("%s: link down, set port %d to auto mode\n",
1247 __FUNCTION__, phy));
1248 robo_power_save_mode(robo, ROBO_PWRSAVE_AUTO, phy);
1250 if (robo->pwrsave_mode_manual & (1 << phy)) {
1251 ET_MSG(("%s: link down, set port %d to man mode\n",
1252 __FUNCTION__, phy));
1253 robo_power_save_mode(robo, ROBO_PWRSAVE_MANUAL, phy);
1258 return;
1261 static int32
1262 robo_power_save_mode_clear_auto(robo_info_t *robo, int32 phy)
1264 uint16 val16;
1266 if (robo->devid == DEVID53115) {
1267 /* For 53115 0x1C is the MII address of the auto power
1268 * down register. Bit 5 is enabling the mode
1269 * bits has the following purpose
1270 * 15 - write enable 10-14 shadow register select 01010 for
1271 * auto power 6-9 reserved 5 auto power mode enable
1272 * 4 sleep timer select : 1 means 5.4 sec
1273 * 0-3 wake up timer select: 0xF 1.26 sec
1275 val16 = 0xa800;
1276 robo->miiwr(robo->h, phy, REG_MII_AUTO_PWRDOWN, val16);
1277 } else
1278 return -1;
1280 robo->pwrsave_mode_phys[phy] &= ~ROBO_PWRSAVE_AUTO;
1282 return 0;
1285 static int32
1286 robo_power_save_mode_clear_manual(robo_info_t *robo, int32 phy)
1288 uint8 val8;
1289 uint16 val16;
1291 if (robo->devid == DEVID53115) {
1292 /* For 53115 0x0 is the MII control register
1293 * Bit 11 is the power down mode bit
1295 val16 = robo->miird(robo->h, phy, REG_MII_CTRL);
1296 val16 &= 0xf7ff;
1297 robo->miiwr(robo->h, phy, REG_MII_CTRL, val16);
1298 } else if (robo->devid == DEVID5325) {
1299 if (phy == 0)
1300 return -1;
1301 /* For 5325 page 0x00 address 0x0F is the power down
1302 * mode register. Bits 1-4 determines which of the
1303 * phys are enabled for this mode
1305 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN,
1306 &val8, sizeof(val8));
1307 val8 &= ~(0x1 << phy);
1308 robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN,
1309 &val8, sizeof(val8));
1310 } else
1311 return -1;
1313 robo->pwrsave_mode_phys[phy] &= ~ROBO_PWRSAVE_MANUAL;
1315 return 0;
1319 * Function which periodically checks the power save mode on the switch
1321 int32
1322 robo_power_save_toggle(robo_info_t *robo, int32 normal)
1324 int32 phy;
1326 /* Put the phys into the normal mode first so that link status
1327 * can be checked. Once in the normal mode check the link status
1328 * and if any of the link is up do not put that phy into
1329 * manual power save mode
1331 for (phy = 0; phy < MAX_NO_PHYS; phy++) {
1332 /* When auto+manual modes are enabled we toggle between
1333 * manual and auto modes. When only manual mode is enabled
1334 * we toggle between manual and normal modes. When only
1335 * auto mode is enabled there is no need to do anything
1336 * here since auto mode is one time config.
1338 if ((robo->pwrsave_phys & (1 << phy)) &&
1339 (robo->pwrsave_mode_manual & (1 << phy))) {
1340 if (!normal) {
1341 if (robo->pwrsave_mode_auto & (1 << phy))
1342 /* auto+manual -> auto */
1343 robo_power_save_mode_clear_manual(robo, phy);
1344 else
1345 /* manual -> normal */
1346 robo_power_save_mode(robo, ROBO_PWRSAVE_NORMAL, phy);
1347 } else
1348 /* normal -> manual / auto+manual */
1349 robo_power_save_mode(robo, ROBO_PWRSAVE_MANUAL, phy);
1353 return 0;
1357 * Switch the ports to normal mode.
1359 static int32
1360 robo_power_save_mode_normal(robo_info_t *robo, int32 phy)
1362 int32 error = 0;
1364 /* If the phy in the power save mode come out of it */
1365 switch (robo->pwrsave_mode_phys[phy]) {
1366 case ROBO_PWRSAVE_AUTO_MANUAL:
1367 case ROBO_PWRSAVE_AUTO:
1368 error = robo_power_save_mode_clear_auto(robo, phy);
1369 if ((error == -1) ||
1370 (robo->pwrsave_mode_phys[phy] == ROBO_PWRSAVE_AUTO))
1371 break;
1373 case ROBO_PWRSAVE_MANUAL:
1374 error = robo_power_save_mode_clear_manual(robo, phy);
1375 break;
1377 default:
1378 break;
1381 return error;
1385 * Switch all the inactive ports to auto power down mode.
1387 static int32
1388 robo_power_save_mode_auto(robo_info_t *robo, int32 phy)
1390 uint16 val16;
1392 /* For both 5325 and 53115 the link status register
1393 * is the same
1395 robo->ops->read_reg(robo, PAGE_STATUS, REG_STATUS_LINK,
1396 &val16, sizeof(val16));
1397 if (val16 & (0x1 << phy))
1398 return 0;
1400 /* If the switch supports auto power down enable that */
1401 if (robo->devid == DEVID53115) {
1402 /* For 53115 0x1C is the MII address of the auto power
1403 * down register. Bit 5 is enabling the mode
1404 * bits has the following purpose
1405 * 15 - write enable 10-14 shadow register select 01010 for
1406 * auto power 6-9 reserved 5 auto power mode enable
1407 * 4 sleep timer select : 1 means 5.4 sec
1408 * 0-3 wake up timer select: 0xF 1.26 sec
1410 robo->miiwr(robo->h, phy, REG_MII_AUTO_PWRDOWN, 0xA83F);
1411 } else
1412 return -1;
1414 robo->pwrsave_mode_phys[phy] |= ROBO_PWRSAVE_AUTO;
1416 return 0;
1420 * Switch all the inactive ports to manual power down mode.
1422 static int32
1423 robo_power_save_mode_manual(robo_info_t *robo, int32 phy)
1425 uint8 val8;
1426 uint16 val16;
1428 /* For both 5325 and 53115 the link status register is the same */
1429 robo->ops->read_reg(robo, PAGE_STATUS, REG_STATUS_LINK,
1430 &val16, sizeof(val16));
1431 if (val16 & (0x1 << phy))
1432 return 0;
1434 /* If the switch supports manual power down enable that */
1435 if (robo->devid == DEVID53115) {
1436 /* For 53115 0x0 is the MII control register bit 11 is the
1437 * power down mode bit
1439 val16 = robo->miird(robo->h, phy, REG_MII_CTRL);
1440 robo->miiwr(robo->h, phy, REG_MII_CTRL, val16 | 0x800);
1441 } else if (robo->devid == DEVID5325) {
1442 if (phy == 0)
1443 return -1;
1444 /* For 5325 page 0x00 address 0x0F is the power down mode
1445 * register. Bits 1-4 determines which of the phys are enabled
1446 * for this mode
1448 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN, &val8,
1449 sizeof(val8));
1450 val8 |= (1 << phy);
1451 robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_PWRDOWN, &val8,
1452 sizeof(val8));
1453 } else
1454 return -1;
1456 robo->pwrsave_mode_phys[phy] |= ROBO_PWRSAVE_MANUAL;
1458 return 0;
1462 * Set power save modes on the robo switch
1464 int32
1465 robo_power_save_mode(robo_info_t *robo, int32 mode, int32 phy)
1467 int32 error = -1;
1469 if (phy > MAX_NO_PHYS) {
1470 ET_ERROR(("Passed parameter phy is out of range\n"));
1471 return -1;
1474 /* Enable management interface access */
1475 if (robo->ops->enable_mgmtif)
1476 robo->ops->enable_mgmtif(robo);
1478 switch (mode) {
1479 case ROBO_PWRSAVE_NORMAL:
1480 /* If the phy in the power save mode come out of it */
1481 error = robo_power_save_mode_normal(robo, phy);
1482 break;
1484 case ROBO_PWRSAVE_AUTO_MANUAL:
1485 /* If the switch supports auto and manual power down
1486 * enable both of them
1488 case ROBO_PWRSAVE_AUTO:
1489 error = robo_power_save_mode_auto(robo, phy);
1490 if ((error == -1) || (mode == ROBO_PWRSAVE_AUTO))
1491 break;
1493 case ROBO_PWRSAVE_MANUAL:
1494 error = robo_power_save_mode_manual(robo, phy);
1495 break;
1497 default:
1498 break;
1501 /* Disable management interface access */
1502 if (robo->ops->disable_mgmtif)
1503 robo->ops->disable_mgmtif(robo);
1505 return error;
1509 * Get the current power save mode of the switch ports.
1511 int32
1512 robo_power_save_mode_get(robo_info_t *robo, int32 phy)
1514 ASSERT(robo);
1516 if (phy >= MAX_NO_PHYS)
1517 return -1;
1519 return robo->pwrsave_mode_phys[phy];
1523 * Configure the power save mode for the switch ports.
1525 int32
1526 robo_power_save_mode_set(robo_info_t *robo, int32 mode, int32 phy)
1528 int32 error;
1530 ASSERT(robo);
1532 if (phy >= MAX_NO_PHYS)
1533 return -1;
1535 error = robo_power_save_mode(robo, mode, phy);
1537 if (error)
1538 return error;
1540 if (mode == ROBO_PWRSAVE_NORMAL) {
1541 robo->pwrsave_mode_manual &= ~(1 << phy);
1542 robo->pwrsave_mode_auto &= ~(1 << phy);
1543 } else if (mode == ROBO_PWRSAVE_AUTO) {
1544 robo->pwrsave_mode_auto |= (1 << phy);
1545 robo->pwrsave_mode_manual &= ~(1 << phy);
1546 robo_power_save_mode_clear_manual(robo, phy);
1547 } else if (mode == ROBO_PWRSAVE_MANUAL) {
1548 robo->pwrsave_mode_manual |= (1 << phy);
1549 robo->pwrsave_mode_auto &= ~(1 << phy);
1550 robo_power_save_mode_clear_auto(robo, phy);
1551 } else {
1552 robo->pwrsave_mode_auto |= (1 << phy);
1553 robo->pwrsave_mode_manual |= (1 << phy);
1556 return 0;