cvmx-helper-board.c revision 229070
1/***********************license start*************** 2 * Copyright (c) 2003-2010 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 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40 41 42 43 44 45 46/** 47 * @file 48 * 49 * Helper functions to abstract board specific data about 50 * network ports from the rest of the cvmx-helper files. 51 * 52 * <hr>$Revision: 49627 $<hr> 53 */ 54#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 55#include <linux/module.h> 56#include <asm/octeon/cvmx.h> 57#include <asm/octeon/cvmx-bootinfo.h> 58#include <asm/octeon/cvmx-smix-defs.h> 59#include <asm/octeon/cvmx-gmxx-defs.h> 60#include <asm/octeon/cvmx-asxx-defs.h> 61#include <asm/octeon/cvmx-mdio.h> 62#include <asm/octeon/cvmx-helper.h> 63#include <asm/octeon/cvmx-helper-util.h> 64#include <asm/octeon/cvmx-helper-board.h> 65#include <asm/octeon/cvmx-twsi.h> 66#else 67#include "cvmx.h" 68#include "cvmx-app-init.h" 69#include "cvmx-sysinfo.h" 70#include "cvmx-twsi.h" 71#include "cvmx-mdio.h" 72#include "cvmx-helper.h" 73#include "cvmx-helper-util.h" 74#include "cvmx-helper-board.h" 75#endif 76 77/** 78 * cvmx_override_board_link_get(int ipd_port) is a function 79 * pointer. It is meant to allow customization of the process of 80 * talking to a PHY to determine link speed. It is called every 81 * time a PHY must be polled for link status. Users should set 82 * this pointer to a function before calling any cvmx-helper 83 * operations. 84 */ 85CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL; 86 87/** 88 * Return the MII PHY address associated with the given IPD 89 * port. A result of -1 means there isn't a MII capable PHY 90 * connected to this port. On chips supporting multiple MII 91 * busses the bus number is encoded in bits <15:8>. 92 * 93 * This function must be modified for every new Octeon board. 94 * Internally it uses switch statements based on the cvmx_sysinfo 95 * data to determine board types and revisions. It replies on the 96 * fact that every Octeon board receives a unique board type 97 * enumeration from the bootloader. 98 * 99 * @param ipd_port Octeon IPD port to get the MII address for. 100 * 101 * @return MII PHY address and bus number or -1. 102 */ 103int cvmx_helper_board_get_mii_address(int ipd_port) 104{ 105 /* 106 * Board types we have to know at compile-time. 107 */ 108#ifdef OCTEON_BOARD_CAPK_0100ND 109 switch (ipd_port) { 110 case 0: 111 return 2; 112 case 1: 113 return 3; 114 case 2: 115 /* XXX Switch PHY? */ 116 return -1; 117 default: 118 return -1; 119 } 120#endif 121 122 /* 123 * For board types we can determine at runtime. 124 */ 125 switch (cvmx_sysinfo_get()->board_type) 126 { 127 case CVMX_BOARD_TYPE_SIM: 128 /* Simulator doesn't have MII */ 129 return -1; 130 case CVMX_BOARD_TYPE_EBT3000: 131 case CVMX_BOARD_TYPE_EBT5800: 132 case CVMX_BOARD_TYPE_THUNDER: 133 case CVMX_BOARD_TYPE_NICPRO2: 134 /* Interface 0 is SPI4, interface 1 is RGMII */ 135 if ((ipd_port >= 16) && (ipd_port < 20)) 136 return ipd_port - 16; 137 else 138 return -1; 139 case CVMX_BOARD_TYPE_LANAI2_A: 140 if (ipd_port == 0) 141 return 0; 142 else 143 return -1; 144 case CVMX_BOARD_TYPE_LANAI2_U: 145 case CVMX_BOARD_TYPE_LANAI2_G: 146 if (ipd_port == 0) 147 return 0x1c; 148 else 149 return -1; 150 case CVMX_BOARD_TYPE_KODAMA: 151 case CVMX_BOARD_TYPE_EBH3100: 152 case CVMX_BOARD_TYPE_HIKARI: 153 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 154 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 155 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 156 /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a 157 switch */ 158 if (ipd_port == 0) 159 return 4; 160 else if (ipd_port == 1) 161 return 9; 162 else 163 return -1; 164 case CVMX_BOARD_TYPE_NAC38: 165 /* Board has 8 RGMII ports PHYs are 0-7 */ 166 if ((ipd_port >= 0) && (ipd_port < 4)) 167 return ipd_port; 168 else if ((ipd_port >= 16) && (ipd_port < 20)) 169 return ipd_port - 16 + 4; 170 else 171 return -1; 172 case CVMX_BOARD_TYPE_EBH3000: 173 /* Board has dual SPI4 and no PHYs */ 174 return -1; 175 case CVMX_BOARD_TYPE_EBT5810: 176 /* Board has 10g PHYs hooked up to the MII controller on the 177 ** IXF18201 MAC. The 10G PHYS use clause 45 MDIO which the CN58XX 178 ** does not support. All MII accesses go through the IXF part. */ 179 return -1; 180 case CVMX_BOARD_TYPE_EBH5200: 181 case CVMX_BOARD_TYPE_EBH5201: 182 case CVMX_BOARD_TYPE_EBT5200: 183 /* Board has 2 management ports */ 184 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 185 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 186 /* Board has 4 SGMII ports. The PHYs start right after the MII 187 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */ 188 if ((ipd_port >= 0) && (ipd_port < 4)) 189 return ipd_port+2; 190 else 191 return -1; 192 case CVMX_BOARD_TYPE_EBH5600: 193 case CVMX_BOARD_TYPE_EBH5601: 194 case CVMX_BOARD_TYPE_EBH5610: 195 /* Board has 1 management port */ 196 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 197 return 0; 198 /* Board has 8 SGMII ports. 4 connect out, two connect to a switch, 199 and 2 loop to each other */ 200 if ((ipd_port >= 0) && (ipd_port < 4)) 201 return ipd_port+1; 202 else 203 return -1; 204 case CVMX_BOARD_TYPE_EBB5600: 205 { 206 static unsigned char qlm_switch_addr = 0; 207 208 /* Board has 1 management port */ 209 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 210 return 0; 211 212 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 213 if ((ipd_port >= 0) && (ipd_port < 4)) 214 { 215 if (qlm_switch_addr != 0x3) 216 { 217 qlm_switch_addr = 0x3; /* QLM1 */ 218 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 219 cvmx_wait_usec(11000); /* Let the write complete */ 220 } 221 return ipd_port+1 + (1<<8); 222 } 223 else if ((ipd_port >= 16) && (ipd_port < 20)) 224 { 225 if (qlm_switch_addr != 0xC) 226 { 227 qlm_switch_addr = 0xC; /* QLM3 */ 228 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 229 cvmx_wait_usec(11000); /* Let the write complete */ 230 } 231 return ipd_port-16+1 + (1<<8); 232 } 233 else 234 return -1; 235 } 236 case CVMX_BOARD_TYPE_EBB6300: 237 /* Board has 2 management ports */ 238 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 239 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 240 if ((ipd_port >= 0) && (ipd_port < 4)) 241 return ipd_port + 1 + (1<<8); 242 else 243 return -1; 244 case CVMX_BOARD_TYPE_CUST_NB5: 245 if (ipd_port == 2) 246 return 4; 247 else 248 return -1; 249 case CVMX_BOARD_TYPE_NIC_XLE_4G: 250 /* Board has 4 SGMII ports. connected QLM3(interface 1) */ 251 if ((ipd_port >= 16) && (ipd_port < 20)) 252 return ipd_port - 16 + 1; 253 else 254 return -1; 255 case CVMX_BOARD_TYPE_NIC_XLE_10G: 256 return -1; /* We don't use clause 45 MDIO for anything */ 257 case CVMX_BOARD_TYPE_BBGW_REF: 258 return -1; /* No PHYs are connected to Octeon, everything is through switch */ 259 case CVMX_BOARD_TYPE_CUST_WSX16: 260 if (ipd_port >= 0 && ipd_port <= 3) 261 return ipd_port; 262 else if (ipd_port >= 16 && ipd_port <= 19) 263 return ipd_port - 16 + 4; 264 else 265 return -1; 266 267 /* Private vendor-defined boards. */ 268#if defined(OCTEON_VENDOR_LANNER) 269 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 270 /* Interface 1 is 12 BCM5482S PHYs. */ 271 if ((ipd_port >= 16) && (ipd_port < 28)) 272 return ipd_port - 16; 273 return -1; 274 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 275 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 276 return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81; 277 if ((ipd_port >= 0) && (ipd_port < 4)) 278 return ipd_port; 279 return -1; 280 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 281 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 282 /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell 283 88E1111 interfaces. */ 284 switch (ipd_port) { 285 case 0: 286 return 16; 287 case 1: 288 return 1; 289 case 2: 290 return 2; 291 default: 292 return -1; 293 } 294#endif 295 } 296 297 /* Some unknown board. Somebody forgot to update this function... */ 298 cvmx_dprintf("%s: Unknown board type %d\n", 299 __FUNCTION__, cvmx_sysinfo_get()->board_type); 300 return -1; 301} 302#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 303EXPORT_SYMBOL(cvmx_helper_board_get_mii_address); 304#endif 305 306 307/** 308 * @INTERNAL 309 * This function is the board specific method of determining an 310 * ethernet ports link speed. Most Octeon boards have Marvell PHYs 311 * and are handled by the fall through case. This function must be 312 * updated for boards that don't have the normal Marvell PHYs. 313 * 314 * This function must be modified for every new Octeon board. 315 * Internally it uses switch statements based on the cvmx_sysinfo 316 * data to determine board types and revisions. It relies on the 317 * fact that every Octeon board receives a unique board type 318 * enumeration from the bootloader. 319 * 320 * @param ipd_port IPD input port associated with the port we want to get link 321 * status for. 322 * 323 * @return The ports link status. If the link isn't fully resolved, this must 324 * return zero. 325 */ 326cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 327{ 328 cvmx_helper_link_info_t result; 329 int phy_addr; 330 int is_broadcom_phy = 0; 331 332 /* Give the user a chance to override the processing of this function */ 333 if (cvmx_override_board_link_get) 334 return cvmx_override_board_link_get(ipd_port); 335 336 /* Unless we fix it later, all links are defaulted to down */ 337 result.u64 = 0; 338 339#if !defined(OCTEON_BOARD_CAPK_0100ND) 340 /* This switch statement should handle all ports that either don't use 341 Marvell PHYS, or don't support in-band status */ 342 switch (cvmx_sysinfo_get()->board_type) 343 { 344 case CVMX_BOARD_TYPE_SIM: 345 /* The simulator gives you a simulated 1Gbps full duplex link */ 346 result.s.link_up = 1; 347 result.s.full_duplex = 1; 348 result.s.speed = 1000; 349 return result; 350 case CVMX_BOARD_TYPE_LANAI2_A: 351 case CVMX_BOARD_TYPE_LANAI2_U: 352 case CVMX_BOARD_TYPE_LANAI2_G: 353 break; 354 case CVMX_BOARD_TYPE_EBH3100: 355 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 356 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 357 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 358 /* Port 1 on these boards is always Gigabit */ 359 if (ipd_port == 1) 360 { 361 result.s.link_up = 1; 362 result.s.full_duplex = 1; 363 result.s.speed = 1000; 364 return result; 365 } 366 /* Fall through to the generic code below */ 367 break; 368 case CVMX_BOARD_TYPE_EBH5600: 369 case CVMX_BOARD_TYPE_EBH5601: 370 case CVMX_BOARD_TYPE_EBH5610: 371 /* Board has 1 management ports */ 372 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 373 is_broadcom_phy = 1; 374 break; 375 case CVMX_BOARD_TYPE_EBH5200: 376 case CVMX_BOARD_TYPE_EBH5201: 377 case CVMX_BOARD_TYPE_EBT5200: 378 /* Board has 2 management ports */ 379 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 380 is_broadcom_phy = 1; 381 break; 382 case CVMX_BOARD_TYPE_EBB6300: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 383 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)) 384 && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1) 385 is_broadcom_phy = 1; 386 break; 387 case CVMX_BOARD_TYPE_CUST_NB5: 388 /* Port 1 on these boards is always Gigabit */ 389 if (ipd_port == 1) 390 { 391 result.s.link_up = 1; 392 result.s.full_duplex = 1; 393 result.s.speed = 1000; 394 return result; 395 } 396 else /* The other port uses a broadcom PHY */ 397 is_broadcom_phy = 1; 398 break; 399 case CVMX_BOARD_TYPE_BBGW_REF: 400 /* Port 1 on these boards is always Gigabit */ 401 if (ipd_port == 2) 402 { 403 /* Port 2 is not hooked up */ 404 result.u64 = 0; 405 return result; 406 } 407 else 408 { 409 /* Ports 0 and 1 connect to the switch */ 410 result.s.link_up = 1; 411 result.s.full_duplex = 1; 412 result.s.speed = 1000; 413 return result; 414 } 415 break; 416 /* Private vendor-defined boards. */ 417#if defined(OCTEON_VENDOR_LANNER) 418 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 419 /* Ports are BCM5482S */ 420 is_broadcom_phy = 1; 421 break; 422 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 423 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 424 /* Port 0 connects to the switch */ 425 if (ipd_port == 0) 426 { 427 result.s.link_up = 1; 428 result.s.full_duplex = 1; 429 result.s.speed = 1000; 430 return result; 431 } 432 break; 433#endif 434 } 435#endif 436 437 phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 438 if (phy_addr != -1) 439 { 440 if (is_broadcom_phy) 441 { 442 /* Below we are going to read SMI/MDIO register 0x19 which works 443 on Broadcom parts */ 444 int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 445 switch ((phy_status>>8) & 0x7) 446 { 447 case 0: 448 result.u64 = 0; 449 break; 450 case 1: 451 result.s.link_up = 1; 452 result.s.full_duplex = 0; 453 result.s.speed = 10; 454 break; 455 case 2: 456 result.s.link_up = 1; 457 result.s.full_duplex = 1; 458 result.s.speed = 10; 459 break; 460 case 3: 461 result.s.link_up = 1; 462 result.s.full_duplex = 0; 463 result.s.speed = 100; 464 break; 465 case 4: 466 result.s.link_up = 1; 467 result.s.full_duplex = 1; 468 result.s.speed = 100; 469 break; 470 case 5: 471 result.s.link_up = 1; 472 result.s.full_duplex = 1; 473 result.s.speed = 100; 474 break; 475 case 6: 476 result.s.link_up = 1; 477 result.s.full_duplex = 0; 478 result.s.speed = 1000; 479 break; 480 case 7: 481 result.s.link_up = 1; 482 result.s.full_duplex = 1; 483 result.s.speed = 1000; 484 break; 485 } 486 } 487 else 488 { 489 /* This code assumes we are using a Marvell Gigabit PHY. All the 490 speed information can be read from register 17 in one go. Somebody 491 using a different PHY will need to handle it above in the board 492 specific area */ 493 int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 494 495 /* If the resolve bit 11 isn't set, see if autoneg is turned off 496 (bit 12, reg 0). The resolve bit doesn't get set properly when 497 autoneg is off, so force it */ 498 if ((phy_status & (1<<11)) == 0) 499 { 500 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 501 if ((auto_status & (1<<12)) == 0) 502 phy_status |= 1<<11; 503 } 504 505 /* Only return a link if the PHY has finished auto negotiation 506 and set the resolved bit (bit 11) */ 507 if (phy_status & (1<<11)) 508 { 509#if defined(OCTEON_BOARD_CAPK_0100ND) 510 result.s.link_up = (phy_status>>10)&1; 511#else 512 result.s.link_up = 1; 513#endif 514 result.s.full_duplex = ((phy_status>>13)&1); 515 switch ((phy_status>>14)&3) 516 { 517 case 0: /* 10 Mbps */ 518 result.s.speed = 10; 519 break; 520 case 1: /* 100 Mbps */ 521 result.s.speed = 100; 522 break; 523 case 2: /* 1 Gbps */ 524 result.s.speed = 1000; 525 break; 526 case 3: /* Illegal */ 527 result.u64 = 0; 528 break; 529 } 530 } 531 } 532 } 533 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 534 { 535 /* We don't have a PHY address, so attempt to use in-band status. It is 536 really important that boards not supporting in-band status never get 537 here. Reading broken in-band status tends to do bad things */ 538 cvmx_gmxx_rxx_rx_inbnd_t inband_status; 539 int interface = cvmx_helper_get_interface_num(ipd_port); 540 int index = cvmx_helper_get_interface_index_num(ipd_port); 541 inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 542 543 result.s.link_up = inband_status.s.status; 544 result.s.full_duplex = inband_status.s.duplex; 545 switch (inband_status.s.speed) 546 { 547 case 0: /* 10 Mbps */ 548 result.s.speed = 10; 549 break; 550 case 1: /* 100 Mbps */ 551 result.s.speed = 100; 552 break; 553 case 2: /* 1 Gbps */ 554 result.s.speed = 1000; 555 break; 556 case 3: /* Illegal */ 557 result.u64 = 0; 558 break; 559 } 560 } 561 else 562 { 563 /* We don't have a PHY address and we don't have in-band status. There 564 is no way to determine the link speed. Return down assuming this 565 port isn't wired */ 566 result.u64 = 0; 567 } 568 569 /* If link is down, return all fields as zero. */ 570 if (!result.s.link_up) 571 result.u64 = 0; 572 573 return result; 574} 575 576 577/** 578 * This function as a board specific method of changing the PHY 579 * speed, duplex, and autonegotiation. This programs the PHY and 580 * not Octeon. This can be used to force Octeon's links to 581 * specific settings. 582 * 583 * @param phy_addr The address of the PHY to program 584 * @param link_flags 585 * Flags to control autonegotiation. Bit 0 is autonegotiation 586 * enable/disable to maintain backward compatibility. 587 * @param link_info Link speed to program. If the speed is zero and autonegotiation 588 * is enabled, all possible negotiation speeds are advertised. 589 * 590 * @return Zero on success, negative on failure 591 */ 592int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags, 593 cvmx_helper_link_info_t link_info) 594{ 595 596 /* Set the flow control settings based on link_flags */ 597 if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch) 598 { 599 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 600 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 601 reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 602 reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 603 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 604 } 605 606 /* If speed isn't set and autoneg is on advertise all supported modes */ 607 if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0)) 608 { 609 cvmx_mdio_phy_reg_control_t reg_control; 610 cvmx_mdio_phy_reg_status_t reg_status; 611 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 612 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 613 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 614 615 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 616 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 617 reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4; 618 reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full; 619 reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half; 620 reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full; 621 reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half; 622 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 623 if (reg_status.s.capable_extended_status) 624 { 625 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 626 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 627 reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full; 628 reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half; 629 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 630 } 631 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 632 reg_control.s.autoneg_enable = 1; 633 reg_control.s.restart_autoneg = 1; 634 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 635 } 636 else if ((link_flags & set_phy_link_flags_autoneg)) 637 { 638 cvmx_mdio_phy_reg_control_t reg_control; 639 cvmx_mdio_phy_reg_status_t reg_status; 640 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 641 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 642 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 643 644 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 645 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 646 reg_autoneg_adver.s.advert_100base_t4 = 0; 647 reg_autoneg_adver.s.advert_10base_tx_full = 0; 648 reg_autoneg_adver.s.advert_10base_tx_half = 0; 649 reg_autoneg_adver.s.advert_100base_tx_full = 0; 650 reg_autoneg_adver.s.advert_100base_tx_half = 0; 651 if (reg_status.s.capable_extended_status) 652 { 653 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 654 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 655 reg_control_1000.s.advert_1000base_t_full = 0; 656 reg_control_1000.s.advert_1000base_t_half = 0; 657 } 658 switch (link_info.s.speed) 659 { 660 case 10: 661 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex; 662 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex; 663 break; 664 case 100: 665 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex; 666 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex; 667 break; 668 case 1000: 669 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex; 670 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex; 671 break; 672 } 673 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 674 if (reg_status.s.capable_extended_status) 675 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 676 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 677 reg_control.s.autoneg_enable = 1; 678 reg_control.s.restart_autoneg = 1; 679 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 680 } 681 else 682 { 683 cvmx_mdio_phy_reg_control_t reg_control; 684 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 685 reg_control.s.autoneg_enable = 0; 686 reg_control.s.restart_autoneg = 1; 687 reg_control.s.duplex = link_info.s.full_duplex; 688 if (link_info.s.speed == 1000) 689 { 690 reg_control.s.speed_msb = 1; 691 reg_control.s.speed_lsb = 0; 692 } 693 else if (link_info.s.speed == 100) 694 { 695 reg_control.s.speed_msb = 0; 696 reg_control.s.speed_lsb = 1; 697 } 698 else if (link_info.s.speed == 10) 699 { 700 reg_control.s.speed_msb = 0; 701 reg_control.s.speed_lsb = 0; 702 } 703 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 704 } 705 return 0; 706} 707 708 709/** 710 * @INTERNAL 711 * This function is called by cvmx_helper_interface_probe() after it 712 * determines the number of ports Octeon can support on a specific 713 * interface. This function is the per board location to override 714 * this value. It is called with the number of ports Octeon might 715 * support and should return the number of actual ports on the 716 * board. 717 * 718 * This function must be modified for every new Octeon board. 719 * Internally it uses switch statements based on the cvmx_sysinfo 720 * data to determine board types and revisions. It relies on the 721 * fact that every Octeon board receives a unique board type 722 * enumeration from the bootloader. 723 * 724 * @param interface Interface to probe 725 * @param supported_ports 726 * Number of ports Octeon supports. 727 * 728 * @return Number of ports the actual board supports. Many times this will 729 * simple be "support_ports". 730 */ 731int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 732{ 733 switch (cvmx_sysinfo_get()->board_type) 734 { 735 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 736 case CVMX_BOARD_TYPE_LANAI2_A: 737 case CVMX_BOARD_TYPE_LANAI2_U: 738 case CVMX_BOARD_TYPE_LANAI2_G: 739 if (interface == 0) 740 return 2; 741 break; 742 case CVMX_BOARD_TYPE_BBGW_REF: 743 if (interface == 0) 744 return 2; 745 break; 746 case CVMX_BOARD_TYPE_NIC_XLE_4G: 747 if (interface == 0) 748 return 0; 749 break; 750 /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 751 which we don't support. Disable ports connected to it */ 752 case CVMX_BOARD_TYPE_EBH5600: 753 if (interface == 1) 754 return 0; 755 break; 756 case CVMX_BOARD_TYPE_EBB5600: 757#ifdef CVMX_ENABLE_PKO_FUNCTIONS 758 if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG) 759 return 0; 760#endif 761 break; 762 case CVMX_BOARD_TYPE_EBT5810: 763 return 1; /* Two ports on each SPI: 1 hooked to MAC, 1 loopback 764 ** Loopback disabled by default. */ 765#if defined(OCTEON_VENDOR_LANNER) 766 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 767 if (interface == 1) 768 return 12; 769 break; 770#endif 771 } 772#ifdef CVMX_BUILD_FOR_UBOOT 773 if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) 774 return 0; 775#endif 776 return supported_ports; 777} 778 779 780/** 781 * @INTERNAL 782 * Enable packet input/output from the hardware. This function is 783 * called after by cvmx_helper_packet_hardware_enable() to 784 * perform board specific initialization. For most boards 785 * nothing is needed. 786 * 787 * @param interface Interface to enable 788 * 789 * @return Zero on success, negative on failure 790 */ 791int __cvmx_helper_board_hardware_enable(int interface) 792{ 793 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) 794 { 795 if (interface == 0) 796 { 797 /* Different config for switch port */ 798 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 799 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 800 /* Boards with gigabit WAN ports need a different setting that is 801 compatible with 100 Mbit settings */ 802 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc); 803 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); 804 } 805 } 806 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U) 807 { 808 if (interface == 0) 809 { 810 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16); 811 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16); 812 } 813 } 814 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5) 815 { 816 /* Broadcom PHYs require different ASX clocks. Unfortunately 817 many customer don't define a new board Id and simply 818 mangle the CN3010_EVB_HS5 */ 819 if (interface == 0) 820 { 821 /* Some customers boards use a hacked up bootloader that identifies them as 822 ** CN3010_EVB_HS5 evaluation boards. This leads to all kinds of configuration 823 ** problems. Detect one case, and print warning, while trying to do the right thing. 824 */ 825 int phy_addr = cvmx_helper_board_get_mii_address(0); 826 if (phy_addr != -1) 827 { 828 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2); 829 /* Is it a Broadcom PHY? */ 830 if (phy_identifier == 0x0143) 831 { 832 cvmx_dprintf("\n"); 833 cvmx_dprintf("ERROR:\n"); 834 cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 835 cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 836 cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n"); 837 cvmx_dprintf("ERROR:\n"); 838 cvmx_dprintf("\n"); 839 cvmx_wait(1000000000); 840 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5); 841 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5); 842 } 843 } 844 } 845 } 846 return 0; 847} 848 849 850/** 851 * @INTERNAL 852 * Gets the clock type used for the USB block based on board type. 853 * Used by the USB code for auto configuration of clock type. 854 * 855 * @return USB clock type enumeration 856 */ 857cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) 858{ 859 switch (cvmx_sysinfo_get()->board_type) 860 { 861 case CVMX_BOARD_TYPE_BBGW_REF: 862 case CVMX_BOARD_TYPE_LANAI2_A: 863 case CVMX_BOARD_TYPE_LANAI2_U: 864 case CVMX_BOARD_TYPE_LANAI2_G: 865#if defined(OCTEON_VENDOR_LANNER) 866 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 867 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 868#endif 869#if defined(OCTEON_BOARD_CAPK_0100ND) 870 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 871#endif 872 return USB_CLOCK_TYPE_CRYSTAL_12; 873 } 874 return USB_CLOCK_TYPE_REF_48; 875} 876 877 878/** 879 * @INTERNAL 880 * Adjusts the number of available USB ports on Octeon based on board 881 * specifics. 882 * 883 * @param supported_ports expected number of ports based on chip type; 884 * 885 * 886 * @return number of available usb ports, based on board specifics. 887 * Return value is supported_ports if function does not 888 * override. 889 */ 890int __cvmx_helper_board_usb_get_num_ports(int supported_ports) 891{ 892 switch (cvmx_sysinfo_get()->board_type) 893 { 894 case CVMX_BOARD_TYPE_NIC_XLE_4G: 895 return 0; 896 } 897 898 return supported_ports; 899} 900 901 902