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, ®8, 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, ®_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, ®_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, ®_val, 957 sizeof(reg_val)); 958 959 /* Read back */ 960 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, ®_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, ®_link, sizeof(reg_link)); 2221 2222 /* Read port speed summary register */ 2223 robo->ops->read_reg(robo, PAGE_STATUS, REG_SPEED_SUM, ®_speed, sizeof(reg_speed)); 2224 2225 /* Read duplex status summary register */ 2226 robo->ops->read_reg(robo, PAGE_STATUS, REG_DUPLEX_SUM, ®_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