cvmx-helper-board.c revision 216476
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 >= 0) && (ipd_port < 4)) 276 return ipd_port; 277 return -1; 278 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 279 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 280 /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell 281 88E1111 interfaces. */ 282 switch (ipd_port) { 283 case 0: 284 return 16; 285 case 1: 286 return 1; 287 case 2: 288 return 2; 289 default: 290 return -1; 291 } 292#endif 293 } 294 295 /* Some unknown board. Somebody forgot to update this function... */ 296 cvmx_dprintf("%s: Unknown board type %d\n", 297 __FUNCTION__, cvmx_sysinfo_get()->board_type); 298 return -1; 299} 300#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 301EXPORT_SYMBOL(cvmx_helper_board_get_mii_address); 302#endif 303 304 305/** 306 * @INTERNAL 307 * This function is the board specific method of determining an 308 * ethernet ports link speed. Most Octeon boards have Marvell PHYs 309 * and are handled by the fall through case. This function must be 310 * updated for boards that don't have the normal Marvell PHYs. 311 * 312 * This function must be modified for every new Octeon board. 313 * Internally it uses switch statements based on the cvmx_sysinfo 314 * data to determine board types and revisions. It relies on the 315 * fact that every Octeon board receives a unique board type 316 * enumeration from the bootloader. 317 * 318 * @param ipd_port IPD input port associated with the port we want to get link 319 * status for. 320 * 321 * @return The ports link status. If the link isn't fully resolved, this must 322 * return zero. 323 */ 324cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 325{ 326 cvmx_helper_link_info_t result; 327 int phy_addr; 328 int is_broadcom_phy = 0; 329 330 /* Give the user a chance to override the processing of this function */ 331 if (cvmx_override_board_link_get) 332 return cvmx_override_board_link_get(ipd_port); 333 334 /* Unless we fix it later, all links are defaulted to down */ 335 result.u64 = 0; 336 337#if !defined(OCTEON_BOARD_CAPK_0100ND) 338 /* This switch statement should handle all ports that either don't use 339 Marvell PHYS, or don't support in-band status */ 340 switch (cvmx_sysinfo_get()->board_type) 341 { 342 case CVMX_BOARD_TYPE_SIM: 343 /* The simulator gives you a simulated 1Gbps full duplex link */ 344 result.s.link_up = 1; 345 result.s.full_duplex = 1; 346 result.s.speed = 1000; 347 return result; 348 case CVMX_BOARD_TYPE_LANAI2_A: 349 case CVMX_BOARD_TYPE_LANAI2_U: 350 case CVMX_BOARD_TYPE_LANAI2_G: 351 break; 352 case CVMX_BOARD_TYPE_EBH3100: 353 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 354 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 355 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 356 /* Port 1 on these boards is always Gigabit */ 357 if (ipd_port == 1) 358 { 359 result.s.link_up = 1; 360 result.s.full_duplex = 1; 361 result.s.speed = 1000; 362 return result; 363 } 364 /* Fall through to the generic code below */ 365 break; 366 case CVMX_BOARD_TYPE_EBH5600: 367 case CVMX_BOARD_TYPE_EBH5601: 368 case CVMX_BOARD_TYPE_EBH5610: 369 /* Board has 1 management ports */ 370 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 371 is_broadcom_phy = 1; 372 break; 373 case CVMX_BOARD_TYPE_EBH5200: 374 case CVMX_BOARD_TYPE_EBH5201: 375 case CVMX_BOARD_TYPE_EBT5200: 376 /* Board has 2 management ports */ 377 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 378 is_broadcom_phy = 1; 379 break; 380 case CVMX_BOARD_TYPE_EBB6300: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 381 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)) 382 && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1) 383 is_broadcom_phy = 1; 384 break; 385 case CVMX_BOARD_TYPE_CUST_NB5: 386 /* Port 1 on these boards is always Gigabit */ 387 if (ipd_port == 1) 388 { 389 result.s.link_up = 1; 390 result.s.full_duplex = 1; 391 result.s.speed = 1000; 392 return result; 393 } 394 else /* The other port uses a broadcom PHY */ 395 is_broadcom_phy = 1; 396 break; 397 case CVMX_BOARD_TYPE_BBGW_REF: 398 /* Port 1 on these boards is always Gigabit */ 399 if (ipd_port == 2) 400 { 401 /* Port 2 is not hooked up */ 402 result.u64 = 0; 403 return result; 404 } 405 else 406 { 407 /* Ports 0 and 1 connect to the switch */ 408 result.s.link_up = 1; 409 result.s.full_duplex = 1; 410 result.s.speed = 1000; 411 return result; 412 } 413 break; 414 /* Private vendor-defined boards. */ 415#if defined(OCTEON_VENDOR_LANNER) 416 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 417 /* Ports are BCM5482S */ 418 is_broadcom_phy = 1; 419 break; 420 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 421 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 422 /* Port 0 connects to the switch */ 423 if (ipd_port == 0) 424 { 425 result.s.link_up = 1; 426 result.s.full_duplex = 1; 427 result.s.speed = 1000; 428 return result; 429 } 430 break; 431#endif 432 } 433#endif 434 435 phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 436 if (phy_addr != -1) 437 { 438 if (is_broadcom_phy) 439 { 440 /* Below we are going to read SMI/MDIO register 0x19 which works 441 on Broadcom parts */ 442 int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 443 switch ((phy_status>>8) & 0x7) 444 { 445 case 0: 446 result.u64 = 0; 447 break; 448 case 1: 449 result.s.link_up = 1; 450 result.s.full_duplex = 0; 451 result.s.speed = 10; 452 break; 453 case 2: 454 result.s.link_up = 1; 455 result.s.full_duplex = 1; 456 result.s.speed = 10; 457 break; 458 case 3: 459 result.s.link_up = 1; 460 result.s.full_duplex = 0; 461 result.s.speed = 100; 462 break; 463 case 4: 464 result.s.link_up = 1; 465 result.s.full_duplex = 1; 466 result.s.speed = 100; 467 break; 468 case 5: 469 result.s.link_up = 1; 470 result.s.full_duplex = 1; 471 result.s.speed = 100; 472 break; 473 case 6: 474 result.s.link_up = 1; 475 result.s.full_duplex = 0; 476 result.s.speed = 1000; 477 break; 478 case 7: 479 result.s.link_up = 1; 480 result.s.full_duplex = 1; 481 result.s.speed = 1000; 482 break; 483 } 484 } 485 else 486 { 487 /* This code assumes we are using a Marvell Gigabit PHY. All the 488 speed information can be read from register 17 in one go. Somebody 489 using a different PHY will need to handle it above in the board 490 specific area */ 491 int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 492 493 /* If the resolve bit 11 isn't set, see if autoneg is turned off 494 (bit 12, reg 0). The resolve bit doesn't get set properly when 495 autoneg is off, so force it */ 496 if ((phy_status & (1<<11)) == 0) 497 { 498 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 499 if ((auto_status & (1<<12)) == 0) 500 phy_status |= 1<<11; 501 } 502 503 /* Only return a link if the PHY has finished auto negotiation 504 and set the resolved bit (bit 11) */ 505 if (phy_status & (1<<11)) 506 { 507#if defined(OCTEON_BOARD_CAPK_0100ND) 508 result.s.link_up = (phy_status>>10)&1; 509#else 510 result.s.link_up = 1; 511#endif 512 result.s.full_duplex = ((phy_status>>13)&1); 513 switch ((phy_status>>14)&3) 514 { 515 case 0: /* 10 Mbps */ 516 result.s.speed = 10; 517 break; 518 case 1: /* 100 Mbps */ 519 result.s.speed = 100; 520 break; 521 case 2: /* 1 Gbps */ 522 result.s.speed = 1000; 523 break; 524 case 3: /* Illegal */ 525 result.u64 = 0; 526 break; 527 } 528 } 529 } 530 } 531 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 532 { 533 /* We don't have a PHY address, so attempt to use in-band status. It is 534 really important that boards not supporting in-band status never get 535 here. Reading broken in-band status tends to do bad things */ 536 cvmx_gmxx_rxx_rx_inbnd_t inband_status; 537 int interface = cvmx_helper_get_interface_num(ipd_port); 538 int index = cvmx_helper_get_interface_index_num(ipd_port); 539 inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 540 541 result.s.link_up = inband_status.s.status; 542 result.s.full_duplex = inband_status.s.duplex; 543 switch (inband_status.s.speed) 544 { 545 case 0: /* 10 Mbps */ 546 result.s.speed = 10; 547 break; 548 case 1: /* 100 Mbps */ 549 result.s.speed = 100; 550 break; 551 case 2: /* 1 Gbps */ 552 result.s.speed = 1000; 553 break; 554 case 3: /* Illegal */ 555 result.u64 = 0; 556 break; 557 } 558 } 559 else 560 { 561 /* We don't have a PHY address and we don't have in-band status. There 562 is no way to determine the link speed. Return down assuming this 563 port isn't wired */ 564 result.u64 = 0; 565 } 566 567 /* If link is down, return all fields as zero. */ 568 if (!result.s.link_up) 569 result.u64 = 0; 570 571 return result; 572} 573 574 575/** 576 * This function as a board specific method of changing the PHY 577 * speed, duplex, and autonegotiation. This programs the PHY and 578 * not Octeon. This can be used to force Octeon's links to 579 * specific settings. 580 * 581 * @param phy_addr The address of the PHY to program 582 * @param link_flags 583 * Flags to control autonegotiation. Bit 0 is autonegotiation 584 * enable/disable to maintain backward compatibility. 585 * @param link_info Link speed to program. If the speed is zero and autonegotiation 586 * is enabled, all possible negotiation speeds are advertised. 587 * 588 * @return Zero on success, negative on failure 589 */ 590int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags, 591 cvmx_helper_link_info_t link_info) 592{ 593 594 /* Set the flow control settings based on link_flags */ 595 if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch) 596 { 597 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 598 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 599 reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 600 reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 601 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 602 } 603 604 /* If speed isn't set and autoneg is on advertise all supported modes */ 605 if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0)) 606 { 607 cvmx_mdio_phy_reg_control_t reg_control; 608 cvmx_mdio_phy_reg_status_t reg_status; 609 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 610 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 611 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 612 613 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 614 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 615 reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4; 616 reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full; 617 reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half; 618 reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full; 619 reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half; 620 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 621 if (reg_status.s.capable_extended_status) 622 { 623 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 624 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 625 reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full; 626 reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half; 627 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 628 } 629 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 630 reg_control.s.autoneg_enable = 1; 631 reg_control.s.restart_autoneg = 1; 632 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 633 } 634 else if ((link_flags & set_phy_link_flags_autoneg)) 635 { 636 cvmx_mdio_phy_reg_control_t reg_control; 637 cvmx_mdio_phy_reg_status_t reg_status; 638 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 639 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 640 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 641 642 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 643 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 644 reg_autoneg_adver.s.advert_100base_t4 = 0; 645 reg_autoneg_adver.s.advert_10base_tx_full = 0; 646 reg_autoneg_adver.s.advert_10base_tx_half = 0; 647 reg_autoneg_adver.s.advert_100base_tx_full = 0; 648 reg_autoneg_adver.s.advert_100base_tx_half = 0; 649 if (reg_status.s.capable_extended_status) 650 { 651 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 652 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 653 reg_control_1000.s.advert_1000base_t_full = 0; 654 reg_control_1000.s.advert_1000base_t_half = 0; 655 } 656 switch (link_info.s.speed) 657 { 658 case 10: 659 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex; 660 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex; 661 break; 662 case 100: 663 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex; 664 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex; 665 break; 666 case 1000: 667 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex; 668 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex; 669 break; 670 } 671 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 672 if (reg_status.s.capable_extended_status) 673 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 674 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 675 reg_control.s.autoneg_enable = 1; 676 reg_control.s.restart_autoneg = 1; 677 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 678 } 679 else 680 { 681 cvmx_mdio_phy_reg_control_t reg_control; 682 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 683 reg_control.s.autoneg_enable = 0; 684 reg_control.s.restart_autoneg = 1; 685 reg_control.s.duplex = link_info.s.full_duplex; 686 if (link_info.s.speed == 1000) 687 { 688 reg_control.s.speed_msb = 1; 689 reg_control.s.speed_lsb = 0; 690 } 691 else if (link_info.s.speed == 100) 692 { 693 reg_control.s.speed_msb = 0; 694 reg_control.s.speed_lsb = 1; 695 } 696 else if (link_info.s.speed == 10) 697 { 698 reg_control.s.speed_msb = 0; 699 reg_control.s.speed_lsb = 0; 700 } 701 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 702 } 703 return 0; 704} 705 706 707/** 708 * @INTERNAL 709 * This function is called by cvmx_helper_interface_probe() after it 710 * determines the number of ports Octeon can support on a specific 711 * interface. This function is the per board location to override 712 * this value. It is called with the number of ports Octeon might 713 * support and should return the number of actual ports on the 714 * board. 715 * 716 * This function must be modified for every new Octeon board. 717 * Internally it uses switch statements based on the cvmx_sysinfo 718 * data to determine board types and revisions. It relies on the 719 * fact that every Octeon board receives a unique board type 720 * enumeration from the bootloader. 721 * 722 * @param interface Interface to probe 723 * @param supported_ports 724 * Number of ports Octeon supports. 725 * 726 * @return Number of ports the actual board supports. Many times this will 727 * simple be "support_ports". 728 */ 729int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 730{ 731 switch (cvmx_sysinfo_get()->board_type) 732 { 733 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 734 case CVMX_BOARD_TYPE_LANAI2_A: 735 case CVMX_BOARD_TYPE_LANAI2_U: 736 case CVMX_BOARD_TYPE_LANAI2_G: 737 if (interface == 0) 738 return 2; 739 break; 740 case CVMX_BOARD_TYPE_BBGW_REF: 741 if (interface == 0) 742 return 2; 743 break; 744 case CVMX_BOARD_TYPE_NIC_XLE_4G: 745 if (interface == 0) 746 return 0; 747 break; 748 /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 749 which we don't support. Disable ports connected to it */ 750 case CVMX_BOARD_TYPE_EBH5600: 751 if (interface == 1) 752 return 0; 753 break; 754 case CVMX_BOARD_TYPE_EBB5600: 755#ifdef CVMX_ENABLE_PKO_FUNCTIONS 756 if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG) 757 return 0; 758#endif 759 break; 760 case CVMX_BOARD_TYPE_EBT5810: 761 return 1; /* Two ports on each SPI: 1 hooked to MAC, 1 loopback 762 ** Loopback disabled by default. */ 763#if defined(OCTEON_VENDOR_LANNER) 764 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 765 if (interface == 1) 766 return 12; 767 break; 768#endif 769 } 770#ifdef CVMX_BUILD_FOR_UBOOT 771 if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) 772 return 0; 773#endif 774 return supported_ports; 775} 776 777 778/** 779 * @INTERNAL 780 * Enable packet input/output from the hardware. This function is 781 * called after by cvmx_helper_packet_hardware_enable() to 782 * perform board specific initialization. For most boards 783 * nothing is needed. 784 * 785 * @param interface Interface to enable 786 * 787 * @return Zero on success, negative on failure 788 */ 789int __cvmx_helper_board_hardware_enable(int interface) 790{ 791 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) 792 { 793 if (interface == 0) 794 { 795 /* Different config for switch port */ 796 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 797 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 798 /* Boards with gigabit WAN ports need a different setting that is 799 compatible with 100 Mbit settings */ 800 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc); 801 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); 802 } 803 } 804 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U) 805 { 806 if (interface == 0) 807 { 808 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16); 809 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16); 810 } 811 } 812 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5) 813 { 814 /* Broadcom PHYs require different ASX clocks. Unfortunately 815 many customer don't define a new board Id and simply 816 mangle the CN3010_EVB_HS5 */ 817 if (interface == 0) 818 { 819 /* Some customers boards use a hacked up bootloader that identifies them as 820 ** CN3010_EVB_HS5 evaluation boards. This leads to all kinds of configuration 821 ** problems. Detect one case, and print warning, while trying to do the right thing. 822 */ 823 int phy_addr = cvmx_helper_board_get_mii_address(0); 824 if (phy_addr != -1) 825 { 826 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2); 827 /* Is it a Broadcom PHY? */ 828 if (phy_identifier == 0x0143) 829 { 830 cvmx_dprintf("\n"); 831 cvmx_dprintf("ERROR:\n"); 832 cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 833 cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 834 cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n"); 835 cvmx_dprintf("ERROR:\n"); 836 cvmx_dprintf("\n"); 837 cvmx_wait(1000000000); 838 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5); 839 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5); 840 } 841 } 842 } 843 } 844 return 0; 845} 846 847 848/** 849 * @INTERNAL 850 * Gets the clock type used for the USB block based on board type. 851 * Used by the USB code for auto configuration of clock type. 852 * 853 * @return USB clock type enumeration 854 */ 855cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) 856{ 857 switch (cvmx_sysinfo_get()->board_type) 858 { 859 case CVMX_BOARD_TYPE_BBGW_REF: 860 case CVMX_BOARD_TYPE_LANAI2_A: 861 case CVMX_BOARD_TYPE_LANAI2_U: 862 case CVMX_BOARD_TYPE_LANAI2_G: 863#if defined(OCTEON_VENDOR_LANNER) 864 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 865 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 866#endif 867 return USB_CLOCK_TYPE_CRYSTAL_12; 868 } 869 return USB_CLOCK_TYPE_REF_48; 870} 871 872 873/** 874 * @INTERNAL 875 * Adjusts the number of available USB ports on Octeon based on board 876 * specifics. 877 * 878 * @param supported_ports expected number of ports based on chip type; 879 * 880 * 881 * @return number of available usb ports, based on board specifics. 882 * Return value is supported_ports if function does not 883 * override. 884 */ 885int __cvmx_helper_board_usb_get_num_ports(int supported_ports) 886{ 887 switch (cvmx_sysinfo_get()->board_type) 888 { 889 case CVMX_BOARD_TYPE_NIC_XLE_4G: 890 return 0; 891 } 892 893 return supported_ports; 894} 895 896 897