cvmx-helper-board.c revision 215014
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_MR955: 181 /* Interface 1 is 12 BCM5482S PHYs. */ 182 if ((ipd_port >= 16) && (ipd_port < 28)) 183 return ipd_port - 16; 184 return -1; 185 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 186 if ((ipd_port >= 0) && (ipd_port < 4)) 187 return ipd_port; 188 return -1; 189 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 190 /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell 191 88E1111 interfaces. */ 192 switch (ipd_port) { 193 case 0: 194 return 16; 195 case 1: 196 return 1; 197 case 2: 198 return 2; 199 default: 200 return -1; 201 } 202#endif 203 } 204 205 /* Some unknown board. Somebody forgot to update this function... */ 206 cvmx_dprintf("cvmx_helper_board_get_mii_address: Unknown board type %d\n", 207 cvmx_sysinfo_get()->board_type); 208 return -1; 209} 210 211 212/** 213 * @INTERNAL 214 * This function is the board specific method of determining an 215 * ethernet ports link speed. Most Octeon boards have Marvell PHYs 216 * and are handled by the fall through case. This function must be 217 * updated for boards that don't have the normal Marvell PHYs. 218 * 219 * This function must be modified for every new Octeon board. 220 * Internally it uses switch statements based on the cvmx_sysinfo 221 * data to determine board types and revisions. It relies on the 222 * fact that every Octeon board receives a unique board type 223 * enumeration from the bootloader. 224 * 225 * @param ipd_port IPD input port associated with the port we want to get link 226 * status for. 227 * 228 * @return The ports link status. If the link isn't fully resolved, this must 229 * return zero. 230 */ 231cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 232{ 233 cvmx_helper_link_info_t result; 234 int phy_addr; 235 int is_broadcom_phy = 0; 236 237 /* Give the user a chance to override the processing of this function */ 238 if (cvmx_override_board_link_get) 239 return cvmx_override_board_link_get(ipd_port); 240 241 /* Unless we fix it later, all links are defaulted to down */ 242 result.u64 = 0; 243 244#if !defined(OCTEON_BOARD_CAPK_0100ND) 245 /* This switch statement should handle all ports that either don't use 246 Marvell PHYS, or don't support in-band status */ 247 switch (cvmx_sysinfo_get()->board_type) 248 { 249 case CVMX_BOARD_TYPE_SIM: 250 /* The simulator gives you a simulated 1Gbps full duplex link */ 251 result.s.link_up = 1; 252 result.s.full_duplex = 1; 253 result.s.speed = 1000; 254 return result; 255 case CVMX_BOARD_TYPE_EBH3100: 256 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 257 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 258 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 259 /* Port 1 on these boards is always Gigabit */ 260 if (ipd_port == 1) 261 { 262 result.s.link_up = 1; 263 result.s.full_duplex = 1; 264 result.s.speed = 1000; 265 return result; 266 } 267 /* Fall through to the generic code below */ 268 break; 269 case CVMX_BOARD_TYPE_CUST_NB5: 270 /* Port 1 on these boards is always Gigabit */ 271 if (ipd_port == 1) 272 { 273 result.s.link_up = 1; 274 result.s.full_duplex = 1; 275 result.s.speed = 1000; 276 return result; 277 } 278 else /* The other port uses a broadcom PHY */ 279 is_broadcom_phy = 1; 280 break; 281 case CVMX_BOARD_TYPE_BBGW_REF: 282 /* Port 1 on these boards is always Gigabit */ 283 if (ipd_port == 2) 284 { 285 /* Port 2 is not hooked up */ 286 result.u64 = 0; 287 return result; 288 } 289 else 290 { 291 /* Ports 0 and 1 connect to the switch */ 292 result.s.link_up = 1; 293 result.s.full_duplex = 1; 294 result.s.speed = 1000; 295 return result; 296 } 297 break; 298 /* Private vendor-defined boards. */ 299#if defined(OCTEON_VENDOR_LANNER) 300 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 301 /* Ports are BCM5482S */ 302 is_broadcom_phy = 1; 303 break; 304 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 305 /* Port 0 connects to the switch */ 306 if (ipd_port == 0) 307 { 308 result.s.link_up = 1; 309 result.s.full_duplex = 1; 310 result.s.speed = 1000; 311 return result; 312 } 313 break; 314#endif 315 } 316#endif 317 318 phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 319 if (phy_addr != -1) 320 { 321 if (is_broadcom_phy) 322 { 323 /* Below we are going to read SMI/MDIO register 0x19 which works 324 on Broadcom parts */ 325 int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 326 switch ((phy_status>>8) & 0x7) 327 { 328 case 0: 329 result.u64 = 0; 330 break; 331 case 1: 332 result.s.link_up = 1; 333 result.s.full_duplex = 0; 334 result.s.speed = 10; 335 break; 336 case 2: 337 result.s.link_up = 1; 338 result.s.full_duplex = 1; 339 result.s.speed = 10; 340 break; 341 case 3: 342 result.s.link_up = 1; 343 result.s.full_duplex = 0; 344 result.s.speed = 100; 345 break; 346 case 4: 347 result.s.link_up = 1; 348 result.s.full_duplex = 1; 349 result.s.speed = 100; 350 break; 351 case 5: 352 result.s.link_up = 1; 353 result.s.full_duplex = 1; 354 result.s.speed = 100; 355 break; 356 case 6: 357 result.s.link_up = 1; 358 result.s.full_duplex = 0; 359 result.s.speed = 1000; 360 break; 361 case 7: 362 result.s.link_up = 1; 363 result.s.full_duplex = 1; 364 result.s.speed = 1000; 365 break; 366 } 367 } 368 else 369 { 370 /* This code assumes we are using a Marvell Gigabit PHY. All the 371 speed information can be read from register 17 in one go. Somebody 372 using a different PHY will need to handle it above in the board 373 specific area */ 374 int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 375 376 /* If the resolve bit 11 isn't set, see if autoneg is turned off 377 (bit 12, reg 0). The resolve bit doesn't get set properly when 378 autoneg is off, so force it */ 379 if ((phy_status & (1<<11)) == 0) 380 { 381 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 382 if ((auto_status & (1<<12)) == 0) 383 phy_status |= 1<<11; 384 } 385 386 /* Only return a link if the PHY has finished auto negotiation 387 and set the resolved bit (bit 11) */ 388 if (phy_status & (1<<11)) 389 { 390#if defined(OCTEON_BOARD_CAPK_0100ND) 391 result.s.link_up = (phy_status>>10)&1; 392#else 393 result.s.link_up = 1; 394#endif 395 result.s.full_duplex = ((phy_status>>13)&1); 396 switch ((phy_status>>14)&3) 397 { 398 case 0: /* 10 Mbps */ 399 result.s.speed = 10; 400 break; 401 case 1: /* 100 Mbps */ 402 result.s.speed = 100; 403 break; 404 case 2: /* 1 Gbps */ 405 result.s.speed = 1000; 406 break; 407 case 3: /* Illegal */ 408 result.u64 = 0; 409 break; 410 } 411 } 412 } 413 } 414 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 415 { 416 /* We don't have a PHY address, so attempt to use in-band status. It is 417 really important that boards not supporting in-band status never get 418 here. Reading broken in-band status tends to do bad things */ 419 cvmx_gmxx_rxx_rx_inbnd_t inband_status; 420 int interface = cvmx_helper_get_interface_num(ipd_port); 421 int index = cvmx_helper_get_interface_index_num(ipd_port); 422 inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 423 424 result.s.link_up = inband_status.s.status; 425 result.s.full_duplex = inband_status.s.duplex; 426 switch (inband_status.s.speed) 427 { 428 case 0: /* 10 Mbps */ 429 result.s.speed = 10; 430 break; 431 case 1: /* 100 Mbps */ 432 result.s.speed = 100; 433 break; 434 case 2: /* 1 Gbps */ 435 result.s.speed = 1000; 436 break; 437 case 3: /* Illegal */ 438 result.u64 = 0; 439 break; 440 } 441 } 442 else 443 { 444 /* We don't have a PHY address and we don't have in-band status. There 445 is no way to determine the link speed. Return down assuming this 446 port isn't wired */ 447 result.u64 = 0; 448 } 449 450 /* If link is down, return all fields as zero. */ 451 if (!result.s.link_up) 452 result.u64 = 0; 453 454 return result; 455} 456 457 458/** 459 * This function as a board specific method of changing the PHY 460 * speed, duplex, and auto-negotiation. This programs the PHY and 461 * not Octeon. This can be used to force Octeon's links to 462 * specific settings. 463 * 464 * @param phy_addr The address of the PHY to program 465 * @param enable_autoneg 466 * Non zero if you want to enable auto-negotiation. 467 * @param link_info Link speed to program. If the speed is zero and auto-negotiation 468 * is enabled, all possible negotiation speeds are advertised. 469 * 470 * @return Zero on success, negative on failure 471 */ 472int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags, 473 cvmx_helper_link_info_t link_info) 474{ 475 476 /* Set the flow control settings based on link_flags */ 477 if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch) 478 { 479 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 480 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 481 reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 482 reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 483 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 484 } 485 486 /* If speed isn't set and autoneg is on advertise all supported modes */ 487 if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0)) 488 { 489 cvmx_mdio_phy_reg_control_t reg_control; 490 cvmx_mdio_phy_reg_status_t reg_status; 491 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 492 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 493 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 494 495 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 496 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 497 reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4; 498 reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full; 499 reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half; 500 reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full; 501 reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half; 502 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 503 if (reg_status.s.capable_extended_status) 504 { 505 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 506 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 507 reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full; 508 reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half; 509 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 510 } 511 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 512 reg_control.s.autoneg_enable = 1; 513 reg_control.s.restart_autoneg = 1; 514 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 515 } 516 else if ((link_flags & set_phy_link_flags_autoneg)) 517 { 518 cvmx_mdio_phy_reg_control_t reg_control; 519 cvmx_mdio_phy_reg_status_t reg_status; 520 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 521 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 522 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 523 524 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 525 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 526 reg_autoneg_adver.s.advert_100base_t4 = 0; 527 reg_autoneg_adver.s.advert_10base_tx_full = 0; 528 reg_autoneg_adver.s.advert_10base_tx_half = 0; 529 reg_autoneg_adver.s.advert_100base_tx_full = 0; 530 reg_autoneg_adver.s.advert_100base_tx_half = 0; 531 if (reg_status.s.capable_extended_status) 532 { 533 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 534 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 535 reg_control_1000.s.advert_1000base_t_full = 0; 536 reg_control_1000.s.advert_1000base_t_half = 0; 537 } 538 switch (link_info.s.speed) 539 { 540 case 10: 541 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex; 542 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex; 543 break; 544 case 100: 545 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex; 546 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex; 547 break; 548 case 1000: 549 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex; 550 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex; 551 break; 552 } 553 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 554 if (reg_status.s.capable_extended_status) 555 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 556 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 557 reg_control.s.autoneg_enable = 1; 558 reg_control.s.restart_autoneg = 1; 559 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 560 } 561 else 562 { 563 cvmx_mdio_phy_reg_control_t reg_control; 564 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 565 reg_control.s.autoneg_enable = 0; 566 reg_control.s.restart_autoneg = 1; 567 reg_control.s.duplex = link_info.s.full_duplex; 568 if (link_info.s.speed == 1000) 569 { 570 reg_control.s.speed_msb = 1; 571 reg_control.s.speed_lsb = 0; 572 } 573 else if (link_info.s.speed == 100) 574 { 575 reg_control.s.speed_msb = 0; 576 reg_control.s.speed_lsb = 1; 577 } 578 else if (link_info.s.speed == 10) 579 { 580 reg_control.s.speed_msb = 0; 581 reg_control.s.speed_lsb = 0; 582 } 583 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 584 } 585 return 0; 586} 587 588 589/** 590 * @INTERNAL 591 * This function is called by cvmx_helper_interface_probe() after it 592 * determines the number of ports Octeon can support on a specific 593 * interface. This function is the per board location to override 594 * this value. It is called with the number of ports Octeon might 595 * support and should return the number of actual ports on the 596 * board. 597 * 598 * This function must be modifed for every new Octeon board. 599 * Internally it uses switch statements based on the cvmx_sysinfo 600 * data to determine board types and revisions. It relys on the 601 * fact that every Octeon board receives a unique board type 602 * enumeration from the bootloader. 603 * 604 * @param interface Interface to probe 605 * @param supported_ports 606 * Number of ports Octeon supports. 607 * 608 * @return Number of ports the actual board supports. Many times this will 609 * simple be "support_ports". 610 */ 611int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 612{ 613 switch (cvmx_sysinfo_get()->board_type) 614 { 615 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 616 if (interface == 0) 617 return 2; 618 break; 619 case CVMX_BOARD_TYPE_BBGW_REF: 620 if (interface == 0) 621 return 2; 622 break; 623 case CVMX_BOARD_TYPE_NIC_XLE_4G: 624 if (interface == 0) 625 return 0; 626 break; 627 /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 628 which we don't support. Disable ports connected to it */ 629 case CVMX_BOARD_TYPE_EBH5600: 630 if (interface == 1) 631 return 0; 632 break; 633#if defined(OCTEON_VENDOR_LANNER) 634 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 635 if (interface == 1) 636 return 12; 637 break; 638#endif 639 } 640#ifdef CVMX_BUILD_FOR_UBOOT 641 if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) 642 return 0; 643#endif 644 return supported_ports; 645} 646 647 648/** 649 * @INTERNAL 650 * Enable packet input/output from the hardware. This function is 651 * called after by cvmx_helper_packet_hardware_enable() to 652 * perform board specific initialization. For most boards 653 * nothing is needed. 654 * 655 * @param interface Interface to enable 656 * 657 * @return Zero on success, negative on failure 658 */ 659int __cvmx_helper_board_hardware_enable(int interface) 660{ 661 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) 662 { 663 if (interface == 0) 664 { 665 /* Different config for switch port */ 666 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 667 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 668 /* Boards with gigabit WAN ports need a different setting that is 669 compatible with 100 Mbit settings */ 670 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc); 671 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); 672 } 673 } 674 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5) 675 { 676 /* Broadcom PHYs require differnet ASX clocks. Unfortunately 677 many customer don't define a new board Id and simply 678 mangle the CN3010_EVB_HS5 */ 679 if (interface == 0) 680 { 681 /* Some customers boards use a hacked up bootloader that identifies them as 682 ** CN3010_EVB_HS5 evaluation boards. This leads to all kinds of configuration 683 ** problems. Detect one case, and print warning, while trying to do the right thing. 684 */ 685 int phy_addr = cvmx_helper_board_get_mii_address(0); 686 if (phy_addr != -1) 687 { 688 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2); 689 /* Is it a Broadcom PHY? */ 690 if (phy_identifier == 0x0143) 691 { 692 cvmx_dprintf("\n"); 693 cvmx_dprintf("ERROR:\n"); 694 cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 695 cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 696 cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n"); 697 cvmx_dprintf("ERROR:\n"); 698 cvmx_dprintf("\n"); 699 cvmx_wait(1000000000); 700 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5); 701 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5); 702 } 703 } 704 } 705 } 706 return 0; 707} 708 709cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) 710{ 711 switch (cvmx_sysinfo_get()->board_type) { 712 case CVMX_BOARD_TYPE_BBGW_REF: 713#if defined(OCTEON_VENDOR_LANNER) 714 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 715#endif 716 return USB_CLOCK_TYPE_CRYSTAL_12; 717 } 718 return USB_CLOCK_TYPE_REF_48; 719} 720 721int __cvmx_helper_board_usb_get_num_ports(int supported_ports) 722{ 723 switch (cvmx_sysinfo_get()->board_type) { 724 case CVMX_BOARD_TYPE_NIC_XLE_4G: 725 return 0; 726 } 727 728 return supported_ports; 729} 730 731 732