1 /***********************license start*************** 2 * Author: Cavium Networks 3 * 4 * Contact: support@caviumnetworks.com 5 * This file is part of the OCTEON SDK 6 * 7 * Copyright (c) 2003-2008 Cavium Networks 8 * 9 * This file is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License, Version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This file is distributed in the hope that it will be useful, but 14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 16 * NONINFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this file; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * or visit http://www.gnu.org/licenses/. 23 * 24 * This file may also be available under a different license from Cavium. 25 * Contact Cavium Networks for more information 26 ***********************license end**************************************/ 27 28 /* 29 * 30 * Helper functions to abstract board specific data about 31 * network ports from the rest of the cvmx-helper files. 32 */ 33 34 #include <asm/octeon/octeon.h> 35 #include <asm/octeon/cvmx-bootinfo.h> 36 37 #include <asm/octeon/cvmx-config.h> 38 39 #include <asm/octeon/cvmx-mdio.h> 40 41 #include <asm/octeon/cvmx-helper.h> 42 #include <asm/octeon/cvmx-helper-util.h> 43 #include <asm/octeon/cvmx-helper-board.h> 44 45 #include <asm/octeon/cvmx-gmxx-defs.h> 46 #include <asm/octeon/cvmx-asxx-defs.h> 47 48 /** 49 * cvmx_override_board_link_get(int ipd_port) is a function 50 * pointer. It is meant to allow customization of the process of 51 * talking to a PHY to determine link speed. It is called every 52 * time a PHY must be polled for link status. Users should set 53 * this pointer to a function before calling any cvmx-helper 54 * operations. 55 */ 56 cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port) = 57 NULL; 58 59 /** 60 * Return the MII PHY address associated with the given IPD 61 * port. A result of -1 means there isn't a MII capable PHY 62 * connected to this port. On chips supporting multiple MII 63 * busses the bus number is encoded in bits <15:8>. 64 * 65 * This function must be modified for every new Octeon board. 66 * Internally it uses switch statements based on the cvmx_sysinfo 67 * data to determine board types and revisions. It replies on the 68 * fact that every Octeon board receives a unique board type 69 * enumeration from the bootloader. 70 * 71 * @ipd_port: Octeon IPD port to get the MII address for. 72 * 73 * Returns MII PHY address and bus number or -1. 74 */ 75 int cvmx_helper_board_get_mii_address(int ipd_port) 76 { 77 switch (cvmx_sysinfo_get()->board_type) { 78 case CVMX_BOARD_TYPE_SIM: 79 /* Simulator doesn't have MII */ 80 return -1; 81 case CVMX_BOARD_TYPE_EBT3000: 82 case CVMX_BOARD_TYPE_EBT5800: 83 case CVMX_BOARD_TYPE_THUNDER: 84 case CVMX_BOARD_TYPE_NICPRO2: 85 /* Interface 0 is SPI4, interface 1 is RGMII */ 86 if ((ipd_port >= 16) && (ipd_port < 20)) 87 return ipd_port - 16; 88 else 89 return -1; 90 case CVMX_BOARD_TYPE_KODAMA: 91 case CVMX_BOARD_TYPE_EBH3100: 92 case CVMX_BOARD_TYPE_HIKARI: 93 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 94 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 95 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 96 /* 97 * Port 0 is WAN connected to a PHY, Port 1 is GMII 98 * connected to a switch 99 */ 100 if (ipd_port == 0) 101 return 4; 102 else if (ipd_port == 1) 103 return 9; 104 else 105 return -1; 106 case CVMX_BOARD_TYPE_NAC38: 107 /* Board has 8 RGMII ports PHYs are 0-7 */ 108 if ((ipd_port >= 0) && (ipd_port < 4)) 109 return ipd_port; 110 else if ((ipd_port >= 16) && (ipd_port < 20)) 111 return ipd_port - 16 + 4; 112 else 113 return -1; 114 case CVMX_BOARD_TYPE_EBH3000: 115 /* Board has dual SPI4 and no PHYs */ 116 return -1; 117 case CVMX_BOARD_TYPE_EBH5200: 118 case CVMX_BOARD_TYPE_EBH5201: 119 case CVMX_BOARD_TYPE_EBT5200: 120 /* Board has 2 management ports */ 121 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 122 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 123 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 124 /* 125 * Board has 4 SGMII ports. The PHYs start right after the MII 126 * ports MII0 = 0, MII1 = 1, SGMII = 2-5. 127 */ 128 if ((ipd_port >= 0) && (ipd_port < 4)) 129 return ipd_port + 2; 130 else 131 return -1; 132 case CVMX_BOARD_TYPE_EBH5600: 133 case CVMX_BOARD_TYPE_EBH5601: 134 case CVMX_BOARD_TYPE_EBH5610: 135 /* Board has 1 management port */ 136 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 137 return 0; 138 /* 139 * Board has 8 SGMII ports. 4 connect out, two connect 140 * to a switch, and 2 loop to each other 141 */ 142 if ((ipd_port >= 0) && (ipd_port < 4)) 143 return ipd_port + 1; 144 else 145 return -1; 146 case CVMX_BOARD_TYPE_CUST_NB5: 147 if (ipd_port == 2) 148 return 4; 149 else 150 return -1; 151 case CVMX_BOARD_TYPE_NIC_XLE_4G: 152 /* Board has 4 SGMII ports. connected QLM3(interface 1) */ 153 if ((ipd_port >= 16) && (ipd_port < 20)) 154 return ipd_port - 16 + 1; 155 else 156 return -1; 157 case CVMX_BOARD_TYPE_NIC_XLE_10G: 158 case CVMX_BOARD_TYPE_NIC10E: 159 return -1; 160 case CVMX_BOARD_TYPE_NIC4E: 161 if (ipd_port >= 0 && ipd_port <= 3) 162 return (ipd_port + 0x1f) & 0x1f; 163 else 164 return -1; 165 case CVMX_BOARD_TYPE_NIC2E: 166 if (ipd_port >= 0 && ipd_port <= 1) 167 return ipd_port + 1; 168 else 169 return -1; 170 case CVMX_BOARD_TYPE_BBGW_REF: 171 /* 172 * No PHYs are connected to Octeon, everything is 173 * through switch. 174 */ 175 return -1; 176 177 case CVMX_BOARD_TYPE_CUST_WSX16: 178 if (ipd_port >= 0 && ipd_port <= 3) 179 return ipd_port; 180 else if (ipd_port >= 16 && ipd_port <= 19) 181 return ipd_port - 16 + 4; 182 else 183 return -1; 184 } 185 186 /* Some unknown board. Somebody forgot to update this function... */ 187 cvmx_dprintf 188 ("cvmx_helper_board_get_mii_address: Unknown board type %d\n", 189 cvmx_sysinfo_get()->board_type); 190 return -1; 191 } 192 193 /** 194 * This function is the board specific method of determining an 195 * ethernet ports link speed. Most Octeon boards have Marvell PHYs 196 * and are handled by the fall through case. This function must be 197 * updated for boards that don't have the normal Marvell PHYs. 198 * 199 * This function must be modified for every new Octeon board. 200 * Internally it uses switch statements based on the cvmx_sysinfo 201 * data to determine board types and revisions. It relies on the 202 * fact that every Octeon board receives a unique board type 203 * enumeration from the bootloader. 204 * 205 * @ipd_port: IPD input port associated with the port we want to get link 206 * status for. 207 * 208 * Returns The ports link status. If the link isn't fully resolved, this must 209 * return zero. 210 */ 211 cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 212 { 213 cvmx_helper_link_info_t result; 214 int phy_addr; 215 int is_broadcom_phy = 0; 216 217 /* Give the user a chance to override the processing of this function */ 218 if (cvmx_override_board_link_get) 219 return cvmx_override_board_link_get(ipd_port); 220 221 /* Unless we fix it later, all links are defaulted to down */ 222 result.u64 = 0; 223 224 /* 225 * This switch statement should handle all ports that either don't use 226 * Marvell PHYS, or don't support in-band status. 227 */ 228 switch (cvmx_sysinfo_get()->board_type) { 229 case CVMX_BOARD_TYPE_SIM: 230 /* The simulator gives you a simulated 1Gbps full duplex link */ 231 result.s.link_up = 1; 232 result.s.full_duplex = 1; 233 result.s.speed = 1000; 234 return result; 235 case CVMX_BOARD_TYPE_EBH3100: 236 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 237 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 238 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 239 /* Port 1 on these boards is always Gigabit */ 240 if (ipd_port == 1) { 241 result.s.link_up = 1; 242 result.s.full_duplex = 1; 243 result.s.speed = 1000; 244 return result; 245 } 246 /* Fall through to the generic code below */ 247 break; 248 case CVMX_BOARD_TYPE_CUST_NB5: 249 /* Port 1 on these boards is always Gigabit */ 250 if (ipd_port == 1) { 251 result.s.link_up = 1; 252 result.s.full_duplex = 1; 253 result.s.speed = 1000; 254 return result; 255 } else /* The other port uses a broadcom PHY */ 256 is_broadcom_phy = 1; 257 break; 258 case CVMX_BOARD_TYPE_BBGW_REF: 259 /* Port 1 on these boards is always Gigabit */ 260 if (ipd_port == 2) { 261 /* Port 2 is not hooked up */ 262 result.u64 = 0; 263 return result; 264 } else { 265 /* Ports 0 and 1 connect to the switch */ 266 result.s.link_up = 1; 267 result.s.full_duplex = 1; 268 result.s.speed = 1000; 269 return result; 270 } 271 break; 272 } 273 274 phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 275 if (phy_addr != -1) { 276 if (is_broadcom_phy) { 277 /* 278 * Below we are going to read SMI/MDIO 279 * register 0x19 which works on Broadcom 280 * parts 281 */ 282 int phy_status = 283 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 284 0x19); 285 switch ((phy_status >> 8) & 0x7) { 286 case 0: 287 result.u64 = 0; 288 break; 289 case 1: 290 result.s.link_up = 1; 291 result.s.full_duplex = 0; 292 result.s.speed = 10; 293 break; 294 case 2: 295 result.s.link_up = 1; 296 result.s.full_duplex = 1; 297 result.s.speed = 10; 298 break; 299 case 3: 300 result.s.link_up = 1; 301 result.s.full_duplex = 0; 302 result.s.speed = 100; 303 break; 304 case 4: 305 result.s.link_up = 1; 306 result.s.full_duplex = 1; 307 result.s.speed = 100; 308 break; 309 case 5: 310 result.s.link_up = 1; 311 result.s.full_duplex = 1; 312 result.s.speed = 100; 313 break; 314 case 6: 315 result.s.link_up = 1; 316 result.s.full_duplex = 0; 317 result.s.speed = 1000; 318 break; 319 case 7: 320 result.s.link_up = 1; 321 result.s.full_duplex = 1; 322 result.s.speed = 1000; 323 break; 324 } 325 } else { 326 /* 327 * This code assumes we are using a Marvell 328 * Gigabit PHY. All the speed information can 329 * be read from register 17 in one 330 * go. Somebody using a different PHY will 331 * need to handle it above in the board 332 * specific area. 333 */ 334 int phy_status = 335 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 336 337 /* 338 * If the resolve bit 11 isn't set, see if 339 * autoneg is turned off (bit 12, reg 0). The 340 * resolve bit doesn't get set properly when 341 * autoneg is off, so force it. 342 */ 343 if ((phy_status & (1 << 11)) == 0) { 344 int auto_status = 345 cvmx_mdio_read(phy_addr >> 8, 346 phy_addr & 0xff, 0); 347 if ((auto_status & (1 << 12)) == 0) 348 phy_status |= 1 << 11; 349 } 350 351 /* 352 * Only return a link if the PHY has finished 353 * auto negotiation and set the resolved bit 354 * (bit 11) 355 */ 356 if (phy_status & (1 << 11)) { 357 result.s.link_up = 1; 358 result.s.full_duplex = ((phy_status >> 13) & 1); 359 switch ((phy_status >> 14) & 3) { 360 case 0: /* 10 Mbps */ 361 result.s.speed = 10; 362 break; 363 case 1: /* 100 Mbps */ 364 result.s.speed = 100; 365 break; 366 case 2: /* 1 Gbps */ 367 result.s.speed = 1000; 368 break; 369 case 3: /* Illegal */ 370 result.u64 = 0; 371 break; 372 } 373 } 374 } 375 } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) 376 || OCTEON_IS_MODEL(OCTEON_CN58XX) 377 || OCTEON_IS_MODEL(OCTEON_CN50XX)) { 378 /* 379 * We don't have a PHY address, so attempt to use 380 * in-band status. It is really important that boards 381 * not supporting in-band status never get 382 * here. Reading broken in-band status tends to do bad 383 * things 384 */ 385 union cvmx_gmxx_rxx_rx_inbnd inband_status; 386 int interface = cvmx_helper_get_interface_num(ipd_port); 387 int index = cvmx_helper_get_interface_index_num(ipd_port); 388 inband_status.u64 = 389 cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 390 391 result.s.link_up = inband_status.s.status; 392 result.s.full_duplex = inband_status.s.duplex; 393 switch (inband_status.s.speed) { 394 case 0: /* 10 Mbps */ 395 result.s.speed = 10; 396 break; 397 case 1: /* 100 Mbps */ 398 result.s.speed = 100; 399 break; 400 case 2: /* 1 Gbps */ 401 result.s.speed = 1000; 402 break; 403 case 3: /* Illegal */ 404 result.u64 = 0; 405 break; 406 } 407 } else { 408 /* 409 * We don't have a PHY address and we don't have 410 * in-band status. There is no way to determine the 411 * link speed. Return down assuming this port isn't 412 * wired 413 */ 414 result.u64 = 0; 415 } 416 417 /* If link is down, return all fields as zero. */ 418 if (!result.s.link_up) 419 result.u64 = 0; 420 421 return result; 422 } 423 424 /** 425 * This function as a board specific method of changing the PHY 426 * speed, duplex, and auto-negotiation. This programs the PHY and 427 * not Octeon. This can be used to force Octeon's links to 428 * specific settings. 429 * 430 * @phy_addr: The address of the PHY to program 431 * @enable_autoneg: 432 * Non zero if you want to enable auto-negotiation. 433 * @link_info: Link speed to program. If the speed is zero and auto-negotiation 434 * is enabled, all possible negotiation speeds are advertised. 435 * 436 * Returns Zero on success, negative on failure 437 */ 438 int cvmx_helper_board_link_set_phy(int phy_addr, 439 cvmx_helper_board_set_phy_link_flags_types_t 440 link_flags, 441 cvmx_helper_link_info_t link_info) 442 { 443 444 /* Set the flow control settings based on link_flags */ 445 if ((link_flags & set_phy_link_flags_flow_control_mask) != 446 set_phy_link_flags_flow_control_dont_touch) { 447 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 448 reg_autoneg_adver.u16 = 449 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 450 CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 451 reg_autoneg_adver.s.asymmetric_pause = 452 (link_flags & set_phy_link_flags_flow_control_mask) == 453 set_phy_link_flags_flow_control_enable; 454 reg_autoneg_adver.s.pause = 455 (link_flags & set_phy_link_flags_flow_control_mask) == 456 set_phy_link_flags_flow_control_enable; 457 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 458 CVMX_MDIO_PHY_REG_AUTONEG_ADVER, 459 reg_autoneg_adver.u16); 460 } 461 462 /* If speed isn't set and autoneg is on advertise all supported modes */ 463 if ((link_flags & set_phy_link_flags_autoneg) 464 && (link_info.s.speed == 0)) { 465 cvmx_mdio_phy_reg_control_t reg_control; 466 cvmx_mdio_phy_reg_status_t reg_status; 467 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 468 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 469 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 470 471 reg_status.u16 = 472 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 473 CVMX_MDIO_PHY_REG_STATUS); 474 reg_autoneg_adver.u16 = 475 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 476 CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 477 reg_autoneg_adver.s.advert_100base_t4 = 478 reg_status.s.capable_100base_t4; 479 reg_autoneg_adver.s.advert_10base_tx_full = 480 reg_status.s.capable_10_full; 481 reg_autoneg_adver.s.advert_10base_tx_half = 482 reg_status.s.capable_10_half; 483 reg_autoneg_adver.s.advert_100base_tx_full = 484 reg_status.s.capable_100base_x_full; 485 reg_autoneg_adver.s.advert_100base_tx_half = 486 reg_status.s.capable_100base_x_half; 487 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 488 CVMX_MDIO_PHY_REG_AUTONEG_ADVER, 489 reg_autoneg_adver.u16); 490 if (reg_status.s.capable_extended_status) { 491 reg_extended_status.u16 = 492 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 493 CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 494 reg_control_1000.u16 = 495 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 496 CVMX_MDIO_PHY_REG_CONTROL_1000); 497 reg_control_1000.s.advert_1000base_t_full = 498 reg_extended_status.s.capable_1000base_t_full; 499 reg_control_1000.s.advert_1000base_t_half = 500 reg_extended_status.s.capable_1000base_t_half; 501 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 502 CVMX_MDIO_PHY_REG_CONTROL_1000, 503 reg_control_1000.u16); 504 } 505 reg_control.u16 = 506 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 507 CVMX_MDIO_PHY_REG_CONTROL); 508 reg_control.s.autoneg_enable = 1; 509 reg_control.s.restart_autoneg = 1; 510 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 511 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 512 } else if ((link_flags & set_phy_link_flags_autoneg)) { 513 cvmx_mdio_phy_reg_control_t reg_control; 514 cvmx_mdio_phy_reg_status_t reg_status; 515 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 516 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 517 518 reg_status.u16 = 519 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 520 CVMX_MDIO_PHY_REG_STATUS); 521 reg_autoneg_adver.u16 = 522 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 523 CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 524 reg_autoneg_adver.s.advert_100base_t4 = 0; 525 reg_autoneg_adver.s.advert_10base_tx_full = 0; 526 reg_autoneg_adver.s.advert_10base_tx_half = 0; 527 reg_autoneg_adver.s.advert_100base_tx_full = 0; 528 reg_autoneg_adver.s.advert_100base_tx_half = 0; 529 if (reg_status.s.capable_extended_status) { 530 reg_control_1000.u16 = 531 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 532 CVMX_MDIO_PHY_REG_CONTROL_1000); 533 reg_control_1000.s.advert_1000base_t_full = 0; 534 reg_control_1000.s.advert_1000base_t_half = 0; 535 } 536 switch (link_info.s.speed) { 537 case 10: 538 reg_autoneg_adver.s.advert_10base_tx_full = 539 link_info.s.full_duplex; 540 reg_autoneg_adver.s.advert_10base_tx_half = 541 !link_info.s.full_duplex; 542 break; 543 case 100: 544 reg_autoneg_adver.s.advert_100base_tx_full = 545 link_info.s.full_duplex; 546 reg_autoneg_adver.s.advert_100base_tx_half = 547 !link_info.s.full_duplex; 548 break; 549 case 1000: 550 reg_control_1000.s.advert_1000base_t_full = 551 link_info.s.full_duplex; 552 reg_control_1000.s.advert_1000base_t_half = 553 !link_info.s.full_duplex; 554 break; 555 } 556 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 557 CVMX_MDIO_PHY_REG_AUTONEG_ADVER, 558 reg_autoneg_adver.u16); 559 if (reg_status.s.capable_extended_status) 560 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 561 CVMX_MDIO_PHY_REG_CONTROL_1000, 562 reg_control_1000.u16); 563 reg_control.u16 = 564 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 565 CVMX_MDIO_PHY_REG_CONTROL); 566 reg_control.s.autoneg_enable = 1; 567 reg_control.s.restart_autoneg = 1; 568 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 569 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 570 } else { 571 cvmx_mdio_phy_reg_control_t reg_control; 572 reg_control.u16 = 573 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 574 CVMX_MDIO_PHY_REG_CONTROL); 575 reg_control.s.autoneg_enable = 0; 576 reg_control.s.restart_autoneg = 1; 577 reg_control.s.duplex = link_info.s.full_duplex; 578 if (link_info.s.speed == 1000) { 579 reg_control.s.speed_msb = 1; 580 reg_control.s.speed_lsb = 0; 581 } else if (link_info.s.speed == 100) { 582 reg_control.s.speed_msb = 0; 583 reg_control.s.speed_lsb = 1; 584 } else if (link_info.s.speed == 10) { 585 reg_control.s.speed_msb = 0; 586 reg_control.s.speed_lsb = 0; 587 } 588 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 589 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 590 } 591 return 0; 592 } 593 594 /** 595 * This function is called by cvmx_helper_interface_probe() after it 596 * determines the number of ports Octeon can support on a specific 597 * interface. This function is the per board location to override 598 * this value. It is called with the number of ports Octeon might 599 * support and should return the number of actual ports on the 600 * board. 601 * 602 * This function must be modifed for every new Octeon board. 603 * Internally it uses switch statements based on the cvmx_sysinfo 604 * data to determine board types and revisions. It relys on the 605 * fact that every Octeon board receives a unique board type 606 * enumeration from the bootloader. 607 * 608 * @interface: Interface to probe 609 * @supported_ports: 610 * Number of ports Octeon supports. 611 * 612 * Returns Number of ports the actual board supports. Many times this will 613 * simple be "support_ports". 614 */ 615 int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 616 { 617 switch (cvmx_sysinfo_get()->board_type) { 618 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 619 if (interface == 0) 620 return 2; 621 break; 622 case CVMX_BOARD_TYPE_BBGW_REF: 623 if (interface == 0) 624 return 2; 625 break; 626 case CVMX_BOARD_TYPE_NIC_XLE_4G: 627 if (interface == 0) 628 return 0; 629 break; 630 /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 631 which we don't support. Disable ports connected to it */ 632 case CVMX_BOARD_TYPE_EBH5600: 633 if (interface == 1) 634 return 0; 635 break; 636 } 637 return supported_ports; 638 } 639 640 /** 641 * Enable packet input/output from the hardware. This function is 642 * called after by cvmx_helper_packet_hardware_enable() to 643 * perform board specific initialization. For most boards 644 * nothing is needed. 645 * 646 * @interface: Interface to enable 647 * 648 * Returns Zero on success, negative on failure 649 */ 650 int __cvmx_helper_board_hardware_enable(int interface) 651 { 652 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) { 653 if (interface == 0) { 654 /* Different config for switch port */ 655 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 656 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 657 /* 658 * Boards with gigabit WAN ports need a 659 * different setting that is compatible with 660 * 100 Mbit settings 661 */ 662 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 663 0xc); 664 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 665 0xc); 666 } 667 } else if (cvmx_sysinfo_get()->board_type == 668 CVMX_BOARD_TYPE_CN3010_EVB_HS5) { 669 /* 670 * Broadcom PHYs require differnet ASX 671 * clocks. Unfortunately many boards don't define a 672 * new board Id and simply mangle the 673 * CN3010_EVB_HS5 674 */ 675 if (interface == 0) { 676 /* 677 * Some boards use a hacked up bootloader that 678 * identifies them as CN3010_EVB_HS5 679 * evaluation boards. This leads to all kinds 680 * of configuration problems. Detect one 681 * case, and print warning, while trying to do 682 * the right thing. 683 */ 684 int phy_addr = cvmx_helper_board_get_mii_address(0); 685 if (phy_addr != -1) { 686 int phy_identifier = 687 cvmx_mdio_read(phy_addr >> 8, 688 phy_addr & 0xff, 0x2); 689 /* Is it a Broadcom PHY? */ 690 if (phy_identifier == 0x0143) { 691 cvmx_dprintf("\n"); 692 cvmx_dprintf("ERROR:\n"); 693 cvmx_dprintf 694 ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 695 cvmx_dprintf 696 ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 697 cvmx_dprintf 698 ("ERROR: All boards require a unique board type to identify them.\n"); 699 cvmx_dprintf("ERROR:\n"); 700 cvmx_dprintf("\n"); 701 cvmx_wait(1000000000); 702 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX 703 (0, interface), 5); 704 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX 705 (0, interface), 5); 706 } 707 } 708 } 709 } 710 return 0; 711 } 712