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