cvmx-helper-board.c revision 242104
1/***********************license start*************** 2 * Copyright (c) 2003-2011 Cavium Inc. (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 Inc. 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 INC. 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: 70030 $<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#include "cvmx-gpio.h" 76#if !defined(__FreeBSD__) || !defined(_KERNEL) 77#ifdef __U_BOOT__ 78# include <libfdt.h> 79#else 80# include "libfdt/libfdt.h" 81#endif 82#endif 83#include "cvmx-swap.h" 84#endif 85 86/** 87 * cvmx_override_board_link_get(int ipd_port) is a function 88 * pointer. It is meant to allow customization of the process of 89 * talking to a PHY to determine link speed. It is called every 90 * time a PHY must be polled for link status. Users should set 91 * this pointer to a function before calling any cvmx-helper 92 * operations. 93 */ 94CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL; 95 96#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 97 98static void cvmx_retry_i2c_write(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t data) 99{ 100 int tries = 3; 101 int r; 102 do { 103 r = cvmx_twsix_write_ia(twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data); 104 } while (tries-- > 0 && r < 0); 105} 106 107static int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port) 108{ 109 char name_buffer[20]; 110 const char*pip_path; 111 int pip, iface, eth; 112 int interface_num = cvmx_helper_get_interface_num(ipd_port); 113 int interface_index = cvmx_helper_get_interface_index_num(ipd_port); 114 115 pip_path = fdt_getprop(fdt_addr, aliases, "pip", NULL); 116 if (!pip_path) 117 { 118 cvmx_dprintf("ERROR: pip path not found in device tree\n"); 119 return -1; 120 } 121 pip = fdt_path_offset(fdt_addr, pip_path); 122 if (pip < 0) 123 { 124 cvmx_dprintf("ERROR: pip not found in device tree\n"); 125 return -1; 126 } 127#ifdef __U_BOOT__ 128 sprintf(name_buffer, "interface@%d", interface_num); 129#else 130 snprintf(name_buffer, sizeof(name_buffer), "interface@%d", interface_num); 131#endif 132 iface = fdt_subnode_offset(fdt_addr, pip, name_buffer); 133 if (iface < 0) 134 { 135 cvmx_dprintf("ERROR : pip intf %d not found in device tree \n", 136 interface_num); 137 return -1; 138 } 139#ifdef __U_BOOT__ 140 sprintf(name_buffer, "ethernet@%x", interface_index); 141#else 142 snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", interface_index); 143#endif 144 eth = fdt_subnode_offset(fdt_addr, iface, name_buffer); 145 if (eth < 0) 146 { 147 cvmx_dprintf("ERROR : pip interface@%d ethernet@%d not found in device " 148 "tree\n", interface_num, interface_index); 149 return -1; 150 } 151 return eth; 152} 153 154static int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index) 155{ 156 char name_buffer[20]; 157 const char*mix_path; 158 int mix; 159 160#ifdef __U_BOOT__ 161 sprintf(name_buffer, "mix%d", interface_index); 162#else 163 snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index); 164#endif 165 mix_path = fdt_getprop(fdt_addr, aliases, name_buffer, NULL); 166 if (!mix_path) 167 { 168 cvmx_dprintf("ERROR: mix%d path not found in device tree\n",interface_index); 169 } 170 mix = fdt_path_offset(fdt_addr, mix_path); 171 if (mix < 0) 172 { 173 cvmx_dprintf("ERROR: %s not found in device tree\n", mix_path); 174 return -1; 175 } 176 return mix; 177} 178 179typedef struct cvmx_phy_info 180{ 181 int phy_addr; 182 int direct_connect; 183 cvmx_phy_type_t phy_type; 184}cvmx_phy_info_t; 185 186 187static int __mdiobus_addr_to_unit(uint32_t addr) 188{ 189 int unit = (addr >> 7) & 3; 190 if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) 191 unit >>= 1; 192 return unit; 193} 194/** 195 * Return the MII PHY address associated with the given IPD 196 * port. The phy address is obtained from the device tree. 197 * 198 * @param ipd_port Octeon IPD port to get the MII address for. 199 * 200 * @return MII PHY address and bus number or -1. 201 */ 202 203static cvmx_phy_info_t __get_phy_info_from_dt(int ipd_port) 204{ 205 const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr); 206 uint32_t *phy_handle; 207 int aliases, eth, phy, phy_parent, phandle, ret; 208 cvmx_phy_info_t phy_info; 209 int mdio_unit=-1; 210 const char *phy_comaptible_str; 211 uint32_t *phy_addr_ptr; 212 213 phy_info.phy_addr = -1; 214 phy_info.direct_connect = -1; 215 phy_info.phy_type = (cvmx_phy_type_t) -1; 216 217 if (!fdt_addr) 218 { 219 cvmx_dprintf("No device tree found.\n"); 220 return phy_info; 221 } 222 aliases = fdt_path_offset(fdt_addr, "/aliases"); 223 if (aliases < 0) { 224 cvmx_dprintf("Error: No /aliases node in device tree.\n"); 225 return phy_info; 226 } 227 if (ipd_port < 0) 228 { 229 int interface_index = ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 230 eth = __mix_eth_node(fdt_addr, aliases, interface_index) ; 231 } 232 else 233 { 234 eth = __pip_eth_node(fdt_addr, aliases, ipd_port); 235 } 236 if (eth < 0 ) 237 { 238 cvmx_dprintf("ERROR : cannot find interface for ipd_port=%d\n", ipd_port); 239 return phy_info; 240 } 241 /* Get handle to phy */ 242 phy_handle = (uint32_t *) fdt_getprop(fdt_addr, eth, "phy-handle", NULL); 243 if (!phy_handle) 244 { 245 cvmx_dprintf("ERROR : phy handle not found in device tree ipd_port=%d" 246 "\n", ipd_port); 247 return phy_info; 248 } 249 phandle = cvmx_be32_to_cpu(*phy_handle); 250 phy = fdt_node_offset_by_phandle(fdt_addr, phandle); 251 if (phy < 0) 252 { 253 cvmx_dprintf("ERROR : cannot find phy for ipd_port=%d ret=%d\n", 254 ipd_port, phy); 255 return phy_info; 256 } 257 phy_comaptible_str = (const char *) fdt_getprop(fdt_addr, phy, 258 "compatible", NULL); 259 if (!phy_comaptible_str) 260 { 261 cvmx_dprintf("ERROR : no compatible prop in phy\n"); 262 return phy_info; 263 } 264 if (memcmp("marvell", phy_comaptible_str, strlen("marvell")) == 0) 265 { 266 phy_info.phy_type = MARVELL_GENERIC_PHY; 267 } 268 else if (memcmp("broadcom", phy_comaptible_str, strlen("broadcom")) == 0) 269 { 270 phy_info.phy_type = BROADCOM_GENERIC_PHY; 271 } 272 else 273 { 274 phy_info.phy_type = -1; 275 } 276 277 /* Check if PHY parent is the octeon MDIO bus. Some boards are connected 278 though a MUX and for them direct_connect_to_phy will be 0 */ 279 phy_parent = fdt_parent_offset(fdt_addr, phy); 280 if (phy_parent < 0) 281 { 282 cvmx_dprintf("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n", 283 ipd_port, phy_parent); 284 return phy_info; 285 } 286 ret = fdt_node_check_compatible(fdt_addr, phy_parent, 287 "cavium,octeon-3860-mdio"); 288 if (ret == 0) 289 { 290 phy_info.direct_connect = 1 ; 291 uint32_t *mdio_reg_base = (uint32_t *) fdt_getprop(fdt_addr, phy_parent,"reg",0); 292 if (mdio_reg_base == 0) 293 { 294 cvmx_dprintf("ERROR : unable to get reg property in phy mdio\n"); 295 return phy_info; 296 } 297 mdio_unit = __mdiobus_addr_to_unit(mdio_reg_base[1]); 298 //cvmx_dprintf("phy parent=%s reg_base=%08x unit=%d \n", 299 // fdt_get_name(fdt_addr,phy_parent, NULL), mdio_reg_base[1], mdio_unit); 300 } 301 else 302 { 303 phy_info.direct_connect = 0; 304 /* The PHY is not directly connected to the Octeon MDIO bus. 305 SE doesn't have abstractions for MDIO MUX or MDIO MUX drivers and 306 hence for the non direct cases code will be needed which is 307 board specific. 308 For now the the MDIO Unit is defaulted to 1. 309 */ 310 mdio_unit = 1; 311 } 312 313 phy_addr_ptr = (uint32_t *) fdt_getprop(fdt_addr, phy, "reg", NULL); 314 phy_info.phy_addr = cvmx_be32_to_cpu(*phy_addr_ptr) | mdio_unit << 8; 315 return phy_info; 316 317} 318 319/** 320 * Return the MII PHY address associated with the given IPD 321 * port. The phy address is obtained from the device tree. 322 * 323 * @param ipd_port Octeon IPD port to get the MII address for. 324 * 325 * @return MII PHY address and bus number or -1. 326 */ 327 328int cvmx_helper_board_get_mii_address_from_dt(int ipd_port) 329{ 330 cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port); 331 return phy_info.phy_addr; 332} 333#endif 334 335/** 336 * Return the MII PHY address associated with the given IPD 337 * port. A result of -1 means there isn't a MII capable PHY 338 * connected to this port. On chips supporting multiple MII 339 * busses the bus number is encoded in bits <15:8>. 340 * 341 * This function must be modified for every new Octeon board. 342 * Internally it uses switch statements based on the cvmx_sysinfo 343 * data to determine board types and revisions. It replies on the 344 * fact that every Octeon board receives a unique board type 345 * enumeration from the bootloader. 346 * 347 * @param ipd_port Octeon IPD port to get the MII address for. 348 * 349 * @return MII PHY address and bus number or -1. 350 */ 351int cvmx_helper_board_get_mii_address(int ipd_port) 352{ 353 /* 354 * Board types we have to know at compile-time. 355 */ 356#ifdef OCTEON_BOARD_CAPK_0100ND 357 switch (ipd_port) { 358 case 0: 359 return 2; 360 case 1: 361 return 3; 362 case 2: 363 /* XXX Switch PHY? */ 364 return -1; 365 default: 366 return -1; 367 } 368#endif 369 370 /* 371 * For board types we can determine at runtime. 372 */ 373 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 374 return -1; 375#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 376 if (cvmx_sysinfo_get()->fdt_addr) 377 { 378 cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port); 379 //cvmx_dprintf("ipd_port=%d phy_addr=%d\n", ipd_port, phy_info.phy_addr); 380 if (phy_info.phy_addr >= 0) return phy_info.phy_addr; 381 } 382#endif 383 switch (cvmx_sysinfo_get()->board_type) 384 { 385 case CVMX_BOARD_TYPE_SIM: 386 /* Simulator doesn't have MII */ 387 return -1; 388 case CVMX_BOARD_TYPE_EBT3000: 389 case CVMX_BOARD_TYPE_EBT5800: 390 case CVMX_BOARD_TYPE_THUNDER: 391 case CVMX_BOARD_TYPE_NICPRO2: 392 /* Interface 0 is SPI4, interface 1 is RGMII */ 393 if ((ipd_port >= 16) && (ipd_port < 20)) 394 return ipd_port - 16; 395 else 396 return -1; 397 case CVMX_BOARD_TYPE_LANAI2_A: 398 if (ipd_port == 0) 399 return 0; 400 else 401 return -1; 402 case CVMX_BOARD_TYPE_LANAI2_U: 403 case CVMX_BOARD_TYPE_LANAI2_G: 404 if (ipd_port == 0) 405 return 0x1c; 406 else 407 return -1; 408 case CVMX_BOARD_TYPE_KODAMA: 409 case CVMX_BOARD_TYPE_EBH3100: 410 case CVMX_BOARD_TYPE_HIKARI: 411 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 412 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 413 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 414 /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a 415 switch */ 416 if (ipd_port == 0) 417 return 4; 418 else if (ipd_port == 1) 419 return 9; 420 else 421 return -1; 422 case CVMX_BOARD_TYPE_EBH3000: 423 /* Board has dual SPI4 and no PHYs */ 424 return -1; 425 case CVMX_BOARD_TYPE_EBT5810: 426 /* Board has 10g PHYs hooked up to the MII controller on the 427 ** IXF18201 MAC. The 10G PHYS use clause 45 MDIO which the CN58XX 428 ** does not support. All MII accesses go through the IXF part. */ 429 return -1; 430 case CVMX_BOARD_TYPE_EBH5200: 431 case CVMX_BOARD_TYPE_EBH5201: 432 case CVMX_BOARD_TYPE_EBT5200: 433 /* Board has 2 management ports */ 434 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 435 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 436 /* Board has 4 SGMII ports. The PHYs start right after the MII 437 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */ 438 if ((ipd_port >= 0) && (ipd_port < 4)) 439 return ipd_port+2; 440 else 441 return -1; 442 case CVMX_BOARD_TYPE_EBH5600: 443 case CVMX_BOARD_TYPE_EBH5601: 444 case CVMX_BOARD_TYPE_EBH5610: 445 /* Board has 1 management port */ 446 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 447 return 0; 448 /* Board has 8 SGMII ports. 4 connect out, two connect to a switch, 449 and 2 loop to each other */ 450 if ((ipd_port >= 0) && (ipd_port < 4)) 451 return ipd_port+1; 452 else 453 return -1; 454 case CVMX_BOARD_TYPE_EBB5600: 455 { 456 static unsigned char qlm_switch_addr = 0; 457 458 /* Board has 1 management port */ 459 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 460 return 0; 461 462 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 463 if ((ipd_port >= 0) && (ipd_port < 4)) 464 { 465 if (qlm_switch_addr != 0x3) 466 { 467 qlm_switch_addr = 0x3; /* QLM1 */ 468 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 469 cvmx_wait_usec(11000); /* Let the write complete */ 470 } 471 return ipd_port+1 + (1<<8); 472 } 473 else if ((ipd_port >= 16) && (ipd_port < 20)) 474 { 475 if (qlm_switch_addr != 0xC) 476 { 477 qlm_switch_addr = 0xC; /* QLM3 */ 478 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 479 cvmx_wait_usec(11000); /* Let the write complete */ 480 } 481 return ipd_port-16+1 + (1<<8); 482 } 483 else 484 return -1; 485 } 486 case CVMX_BOARD_TYPE_EBB6300: 487 /* Board has 2 management ports */ 488 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 489 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 490 if ((ipd_port >= 0) && (ipd_port < 4)) 491 return ipd_port + 1 + (1<<8); 492 else 493 return -1; 494 case CVMX_BOARD_TYPE_EBB6800: 495 /* Board has 1 management ports */ 496 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 497 return 6; 498 if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/ 499 return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/ 500 if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/ 501 return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/ 502 if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/ 503 return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/ 504 if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/ 505 return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/ 506 return -1; 507 case CVMX_BOARD_TYPE_EP6300C: 508 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 509 return 0x01; 510 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1) 511 return 0x02; 512#ifdef CVMX_ENABLE_PKO_FUNCTIONS 513 { 514 int interface = cvmx_helper_get_interface_num(ipd_port); 515 int mode = cvmx_helper_interface_get_mode(interface); 516 if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI) 517 return ipd_port; 518 else if ((ipd_port >= 0) && (ipd_port < 4)) 519 return ipd_port + 3; 520 else 521 return -1; 522 } 523#endif 524 break; 525 case CVMX_BOARD_TYPE_CUST_NB5: 526 if (ipd_port == 2) 527 return 4; 528 else 529 return -1; 530 case CVMX_BOARD_TYPE_NIC_XLE_4G: 531 /* Board has 4 SGMII ports. connected QLM3(interface 1) */ 532 if ((ipd_port >= 16) && (ipd_port < 20)) 533 return ipd_port - 16 + 1; 534 else 535 return -1; 536 case CVMX_BOARD_TYPE_NIC_XLE_10G: 537 case CVMX_BOARD_TYPE_NIC10E: 538 return -1; /* We don't use clause 45 MDIO for anything */ 539 case CVMX_BOARD_TYPE_NIC4E: 540 if (ipd_port >= 0 && ipd_port <= 3) 541 return (ipd_port + 0x1f) & 0x1f; 542 else 543 return -1; 544 case CVMX_BOARD_TYPE_NIC2E: 545 if (ipd_port >= 0 && ipd_port <= 1) 546 return (ipd_port + 1); 547 else 548 return -1; 549 case CVMX_BOARD_TYPE_REDWING: 550 return -1; /* No PHYs connected to Octeon */ 551 case CVMX_BOARD_TYPE_BBGW_REF: 552 return -1; /* No PHYs are connected to Octeon, everything is through switch */ 553 case CVMX_BOARD_TYPE_CUST_WSX16: 554 if (ipd_port >= 0 && ipd_port <= 3) 555 return ipd_port; 556 else if (ipd_port >= 16 && ipd_port <= 19) 557 return ipd_port - 16 + 4; 558 else 559 return -1; 560 561 /* Private vendor-defined boards. */ 562#if defined(OCTEON_VENDOR_LANNER) 563 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 564 /* Interface 1 is 12 BCM5482S PHYs. */ 565 if ((ipd_port >= 16) && (ipd_port < 28)) 566 return ipd_port - 16; 567 return -1; 568 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 569 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 570 return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81; 571 if ((ipd_port >= 0) && (ipd_port < 4)) 572 return ipd_port; 573 return -1; 574 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 575 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 576 /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell 577 88E1111 interfaces. */ 578 switch (ipd_port) { 579 case 0: 580 return 16; 581 case 1: 582 return 1; 583 case 2: 584 return 2; 585 default: 586 return -1; 587 } 588#endif 589 } 590 591 /* Some unknown board. Somebody forgot to update this function... */ 592 cvmx_dprintf("%s: Unknown board type %d\n", 593 __FUNCTION__, cvmx_sysinfo_get()->board_type); 594 return -1; 595} 596#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 597EXPORT_SYMBOL(cvmx_helper_board_get_mii_address); 598#endif 599 600/** 601 * @INTERNAL 602 * Get link state of marvell PHY 603 */ 604static cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr) 605{ 606 cvmx_helper_link_info_t result; 607 int phy_status; 608 609 result.u64 = 0; 610 /*All the speed information can be read from register 17 in one go.*/ 611 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 612 613 /* If the resolve bit 11 isn't set, see if autoneg is turned off 614 (bit 12, reg 0). The resolve bit doesn't get set properly when 615 autoneg is off, so force it */ 616 if ((phy_status & (1<<11)) == 0) 617 { 618 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 619 if ((auto_status & (1<<12)) == 0) 620 phy_status |= 1<<11; 621 } 622 623 /* Only return a link if the PHY has finished auto negotiation 624 and set the resolved bit (bit 11) */ 625 if (phy_status & (1<<11)) 626 { 627 result.s.link_up = 1; 628 result.s.full_duplex = ((phy_status>>13)&1); 629 switch ((phy_status>>14)&3) 630 { 631 case 0: /* 10 Mbps */ 632 result.s.speed = 10; 633 break; 634 case 1: /* 100 Mbps */ 635 result.s.speed = 100; 636 break; 637 case 2: /* 1 Gbps */ 638 result.s.speed = 1000; 639 break; 640 case 3: /* Illegal */ 641 result.u64 = 0; 642 break; 643 } 644 } 645 return result; 646} 647 648/** 649 * @INTERNAL 650 * Get link state of broadcom PHY 651 */ 652static cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr) 653{ 654 cvmx_helper_link_info_t result; 655 int phy_status; 656 657 result.u64 = 0; 658 /* Below we are going to read SMI/MDIO register 0x19 which works 659 on Broadcom parts */ 660 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 661 switch ((phy_status>>8) & 0x7) 662 { 663 case 0: 664 result.u64 = 0; 665 break; 666 case 1: 667 result.s.link_up = 1; 668 result.s.full_duplex = 0; 669 result.s.speed = 10; 670 break; 671 case 2: 672 result.s.link_up = 1; 673 result.s.full_duplex = 1; 674 result.s.speed = 10; 675 break; 676 case 3: 677 result.s.link_up = 1; 678 result.s.full_duplex = 0; 679 result.s.speed = 100; 680 break; 681 case 4: 682 result.s.link_up = 1; 683 result.s.full_duplex = 1; 684 result.s.speed = 100; 685 break; 686 case 5: 687 result.s.link_up = 1; 688 result.s.full_duplex = 1; 689 result.s.speed = 100; 690 break; 691 case 6: 692 result.s.link_up = 1; 693 result.s.full_duplex = 0; 694 result.s.speed = 1000; 695 break; 696 case 7: 697 result.s.link_up = 1; 698 result.s.full_duplex = 1; 699 result.s.speed = 1000; 700 break; 701 } 702 return result; 703} 704 705 706/** 707 * @INTERNAL 708 * Get link state using inband status 709 */ 710static cvmx_helper_link_info_t __get_inband_link_state(int ipd_port) 711{ 712 cvmx_helper_link_info_t result; 713 cvmx_gmxx_rxx_rx_inbnd_t inband_status; 714 int interface = cvmx_helper_get_interface_num(ipd_port); 715 int index = cvmx_helper_get_interface_index_num(ipd_port); 716 717 result.u64 = 0; 718 inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 719 result.s.link_up = inband_status.s.status; 720 result.s.full_duplex = inband_status.s.duplex; 721 switch (inband_status.s.speed) 722 { 723 case 0: /* 10 Mbps */ 724 result.s.speed = 10; 725 break; 726 case 1: /* 100 Mbps */ 727 result.s.speed = 100; 728 break; 729 case 2: /* 1 Gbps */ 730 result.s.speed = 1000; 731 break; 732 case 3: /* Illegal */ 733 result.u64 = 0; 734 break; 735 } 736 return result; 737} 738 739#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 740/** 741 * @INTERNAL 742 * Switch MDIO mux to the specified port. 743 */ 744static int __switch_mdio_mux(int ipd_port) 745{ 746 /* This method is board specific and doesn't use the device tree 747 information as SE doesn't implement MDIO MUX abstration */ 748 switch (cvmx_sysinfo_get()->board_type) 749 { 750 case CVMX_BOARD_TYPE_EBB5600: 751 { 752 static unsigned char qlm_switch_addr = 0; 753 /* Board has 1 management port */ 754 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 755 return 0; 756 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 757 if ((ipd_port >= 0) && (ipd_port < 4)) 758 { 759 if (qlm_switch_addr != 0x3) 760 { 761 qlm_switch_addr = 0x3; /* QLM1 */ 762 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 763 cvmx_wait_usec(11000); /* Let the write complete */ 764 } 765 return ipd_port+1 + (1<<8); 766 } 767 else if ((ipd_port >= 16) && (ipd_port < 20)) 768 { 769 if (qlm_switch_addr != 0xC) 770 { 771 qlm_switch_addr = 0xC; /* QLM3 */ 772 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 773 cvmx_wait_usec(11000); /* Let the write complete */ 774 } 775 return ipd_port-16+1 + (1<<8); 776 } 777 else 778 return -1; 779 } 780 case CVMX_BOARD_TYPE_EBB6600: 781 { 782 static unsigned char qlm_switch_addr = 0; 783 int old_twsi_switch_reg; 784 /* Board has 2 management ports */ 785 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 786 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 787 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 788 if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */ 789 { 790 if (qlm_switch_addr != 2) 791 { 792 int tries; 793 qlm_switch_addr = 2; 794 tries = 3; 795 do { 796 old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0); 797 } while (tries-- > 0 && old_twsi_switch_reg < 0); 798 /* Set I2C MUX to enable port expander */ 799 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8); 800 /* Set selecter to QLM 1 */ 801 cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff); 802 /* disable port expander */ 803 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg); 804 } 805 return 0x101 + ipd_port; 806 } 807 else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */ 808 { 809 if (qlm_switch_addr != 1) 810 { 811 int tries; 812 qlm_switch_addr = 1; 813 tries = 3; 814 do { 815 old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0); 816 } while (tries-- > 0 && old_twsi_switch_reg < 0); 817 /* Set I2C MUX to enable port expander */ 818 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8); 819 /* Set selecter to QLM 2 */ 820 cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7); 821 /* disable port expander */ 822 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg); 823 } 824 return 0x101 + (ipd_port - 16); 825 } else 826 return -1; 827 } 828 case CVMX_BOARD_TYPE_EBB6100: 829 { 830 static char gpio_configured = 0; 831 832 if (!gpio_configured) 833 { 834 cvmx_gpio_cfg(3, 1); 835 gpio_configured = 1; 836 } 837 /* Board has 2 management ports */ 838 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 839 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 840 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 841 if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */ 842 { 843 cvmx_gpio_set(1ull << 3); 844 return 0x101 + ipd_port; 845 } 846 else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */ 847 { 848 cvmx_gpio_clear(1ull << 3); 849 return 0x101 + (ipd_port - 16); 850 } 851 else 852 { 853 printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port); 854 return -1; 855 } 856 } 857 default: 858 { 859 cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n", 860 cvmx_sysinfo_get()->board_type); 861 return -1; 862 } 863 } 864 /* should never get here */ 865 return -1; 866} 867 868/** 869 * @INTERNAL 870 * This function is used ethernet ports link speed. This functions uses the 871 * device tree information to determine the phy address and type of PHY. 872 * The only supproted PHYs are Marvell and Broadcom. 873 * 874 * @param ipd_port IPD input port associated with the port we want to get link 875 * status for. 876 * 877 * @return The ports link status. If the link isn't fully resolved, this must 878 * return zero. 879 */ 880 881cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port) 882{ 883 cvmx_helper_link_info_t result; 884 cvmx_phy_info_t phy_info; 885 886 result.u64 = 0; 887 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 888 { 889 /* The simulator gives you a simulated 1Gbps full duplex link */ 890 result.s.link_up = 1; 891 result.s.full_duplex = 1; 892 result.s.speed = 1000; 893 return result; 894 } 895 phy_info = __get_phy_info_from_dt(ipd_port); 896 //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port, 897 // phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type); 898 if (phy_info.phy_addr < 0) return result; 899 900 if (phy_info.direct_connect == 0) 901 __switch_mdio_mux(ipd_port); 902 switch(phy_info.phy_type) 903 { 904 case BROADCOM_GENERIC_PHY: 905 result = __get_broadcom_phy_link_state(phy_info.phy_addr); 906 break; 907 case MARVELL_GENERIC_PHY: 908 result = __get_marvell_phy_link_state(phy_info.phy_addr); 909 break; 910 default: 911 result = __get_inband_link_state(ipd_port); 912 } 913 return result; 914 915} 916#endif 917 918/** 919 * @INTERNAL 920 * This function invokes __cvmx_helper_board_link_get_from_dt when device tree 921 * info is available. When the device tree information is not available then 922 * this function is the board specific method of determining an 923 * ethernet ports link speed. Most Octeon boards have Marvell PHYs 924 * and are handled by the fall through case. This function must be 925 * updated for boards that don't have the normal Marvell PHYs. 926 * 927 * This function must be modified for every new Octeon board. 928 * Internally it uses switch statements based on the cvmx_sysinfo 929 * data to determine board types and revisions. It relies on the 930 * fact that every Octeon board receives a unique board type 931 * enumeration from the bootloader. 932 * 933 * @param ipd_port IPD input port associated with the port we want to get link 934 * status for. 935 * 936 * @return The ports link status. If the link isn't fully resolved, this must 937 * return zero. 938 */ 939cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 940{ 941 cvmx_helper_link_info_t result; 942 int phy_addr; 943 int is_broadcom_phy = 0; 944 945#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 946 if (cvmx_sysinfo_get()->fdt_addr) 947 { 948 return __cvmx_helper_board_link_get_from_dt(ipd_port); 949 } 950#endif 951 952 /* Give the user a chance to override the processing of this function */ 953 if (cvmx_override_board_link_get) 954 return cvmx_override_board_link_get(ipd_port); 955 956 /* Unless we fix it later, all links are defaulted to down */ 957 result.u64 = 0; 958 959#if !defined(OCTEON_BOARD_CAPK_0100ND) 960 /* This switch statement should handle all ports that either don't use 961 Marvell PHYS, or don't support in-band status */ 962 switch (cvmx_sysinfo_get()->board_type) 963 { 964 case CVMX_BOARD_TYPE_SIM: 965 /* The simulator gives you a simulated 1Gbps full duplex link */ 966 result.s.link_up = 1; 967 result.s.full_duplex = 1; 968 result.s.speed = 1000; 969 return result; 970 case CVMX_BOARD_TYPE_LANAI2_A: 971 case CVMX_BOARD_TYPE_LANAI2_U: 972 case CVMX_BOARD_TYPE_LANAI2_G: 973 break; 974 case CVMX_BOARD_TYPE_EBH3100: 975 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 976 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 977 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 978 /* Port 1 on these boards is always Gigabit */ 979 if (ipd_port == 1) 980 { 981 result.s.link_up = 1; 982 result.s.full_duplex = 1; 983 result.s.speed = 1000; 984 return result; 985 } 986 /* Fall through to the generic code below */ 987 break; 988 case CVMX_BOARD_TYPE_EBH5600: 989 case CVMX_BOARD_TYPE_EBH5601: 990 case CVMX_BOARD_TYPE_EBH5610: 991 /* Board has 1 management ports */ 992 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 993 is_broadcom_phy = 1; 994 break; 995 case CVMX_BOARD_TYPE_EBH5200: 996 case CVMX_BOARD_TYPE_EBH5201: 997 case CVMX_BOARD_TYPE_EBT5200: 998 /* Board has 2 management ports */ 999 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 1000 is_broadcom_phy = 1; 1001 break; 1002 case CVMX_BOARD_TYPE_EBB6100: 1003 case CVMX_BOARD_TYPE_EBB6300: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 1004 case CVMX_BOARD_TYPE_EBB6600: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 1005 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)) 1006 && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1) 1007 is_broadcom_phy = 1; 1008 break; 1009 case CVMX_BOARD_TYPE_EP6300C: 1010 is_broadcom_phy = 1; 1011 break; 1012 case CVMX_BOARD_TYPE_CUST_NB5: 1013 /* Port 1 on these boards is always Gigabit */ 1014 if (ipd_port == 1) 1015 { 1016 result.s.link_up = 1; 1017 result.s.full_duplex = 1; 1018 result.s.speed = 1000; 1019 return result; 1020 } 1021 else /* The other port uses a broadcom PHY */ 1022 is_broadcom_phy = 1; 1023 break; 1024 case CVMX_BOARD_TYPE_BBGW_REF: 1025 /* Port 1 on these boards is always Gigabit */ 1026 if (ipd_port == 2) 1027 { 1028 /* Port 2 is not hooked up */ 1029 result.u64 = 0; 1030 return result; 1031 } 1032 else 1033 { 1034 /* Ports 0 and 1 connect to the switch */ 1035 result.s.link_up = 1; 1036 result.s.full_duplex = 1; 1037 result.s.speed = 1000; 1038 return result; 1039 } 1040 case CVMX_BOARD_TYPE_NIC4E: 1041 case CVMX_BOARD_TYPE_NIC2E: 1042 is_broadcom_phy = 1; 1043 break; 1044 /* Private vendor-defined boards. */ 1045#if defined(OCTEON_VENDOR_LANNER) 1046 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 1047 /* Ports are BCM5482S */ 1048 is_broadcom_phy = 1; 1049 break; 1050 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 1051 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 1052 /* Port 0 connects to the switch */ 1053 if (ipd_port == 0) 1054 { 1055 result.s.link_up = 1; 1056 result.s.full_duplex = 1; 1057 result.s.speed = 1000; 1058 return result; 1059 } 1060 break; 1061#endif 1062 } 1063#endif 1064 1065 phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 1066 //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n", 1067 // ipd_port, phy_addr, is_broadcom_phy); 1068 if (phy_addr != -1) 1069 { 1070 if (is_broadcom_phy) 1071 { 1072 result = __get_broadcom_phy_link_state(phy_addr); 1073 } 1074 else 1075 { 1076 /* This code assumes we are using a Marvell Gigabit PHY. */ 1077 result = __get_marvell_phy_link_state(phy_addr); 1078 } 1079 } 1080 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) 1081 || OCTEON_IS_MODEL(OCTEON_CN50XX)) 1082 { 1083 /* We don't have a PHY address, so attempt to use in-band status. It is 1084 really important that boards not supporting in-band status never get 1085 here. Reading broken in-band status tends to do bad things */ 1086 result = __get_inband_link_state(ipd_port); 1087 } 1088 else 1089 { 1090 /* We don't have a PHY address and we don't have in-band status. There 1091 is no way to determine the link speed. Return down assuming this 1092 port isn't wired */ 1093 result.u64 = 0; 1094 } 1095 1096 /* If link is down, return all fields as zero. */ 1097 if (!result.s.link_up) 1098 result.u64 = 0; 1099 1100 return result; 1101} 1102 1103 1104/** 1105 * This function as a board specific method of changing the PHY 1106 * speed, duplex, and autonegotiation. This programs the PHY and 1107 * not Octeon. This can be used to force Octeon's links to 1108 * specific settings. 1109 * 1110 * @param phy_addr The address of the PHY to program 1111 * @param link_flags 1112 * Flags to control autonegotiation. Bit 0 is autonegotiation 1113 * enable/disable to maintain backward compatibility. 1114 * @param link_info Link speed to program. If the speed is zero and autonegotiation 1115 * is enabled, all possible negotiation speeds are advertised. 1116 * 1117 * @return Zero on success, negative on failure 1118 */ 1119int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags, 1120 cvmx_helper_link_info_t link_info) 1121{ 1122 1123 /* Set the flow control settings based on link_flags */ 1124 if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch) 1125 { 1126 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1127 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1128 reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 1129 reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 1130 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1131 } 1132 1133 /* If speed isn't set and autoneg is on advertise all supported modes */ 1134 if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0)) 1135 { 1136 cvmx_mdio_phy_reg_control_t reg_control; 1137 cvmx_mdio_phy_reg_status_t reg_status; 1138 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1139 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 1140 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 1141 1142 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 1143 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1144 reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4; 1145 reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full; 1146 reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half; 1147 reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full; 1148 reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half; 1149 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1150 if (reg_status.s.capable_extended_status) 1151 { 1152 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 1153 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 1154 reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full; 1155 reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half; 1156 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 1157 } 1158 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1159 reg_control.s.autoneg_enable = 1; 1160 reg_control.s.restart_autoneg = 1; 1161 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1162 } 1163 else if ((link_flags & set_phy_link_flags_autoneg)) 1164 { 1165 cvmx_mdio_phy_reg_control_t reg_control; 1166 cvmx_mdio_phy_reg_status_t reg_status; 1167 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1168 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 1169 1170 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 1171 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1172 reg_autoneg_adver.s.advert_100base_t4 = 0; 1173 reg_autoneg_adver.s.advert_10base_tx_full = 0; 1174 reg_autoneg_adver.s.advert_10base_tx_half = 0; 1175 reg_autoneg_adver.s.advert_100base_tx_full = 0; 1176 reg_autoneg_adver.s.advert_100base_tx_half = 0; 1177 if (reg_status.s.capable_extended_status) 1178 { 1179 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 1180 reg_control_1000.s.advert_1000base_t_full = 0; 1181 reg_control_1000.s.advert_1000base_t_half = 0; 1182 } 1183 switch (link_info.s.speed) 1184 { 1185 case 10: 1186 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex; 1187 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex; 1188 break; 1189 case 100: 1190 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex; 1191 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex; 1192 break; 1193 case 1000: 1194 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex; 1195 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex; 1196 break; 1197 } 1198 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1199 if (reg_status.s.capable_extended_status) 1200 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 1201 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1202 reg_control.s.autoneg_enable = 1; 1203 reg_control.s.restart_autoneg = 1; 1204 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1205 } 1206 else 1207 { 1208 cvmx_mdio_phy_reg_control_t reg_control; 1209 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1210 reg_control.s.autoneg_enable = 0; 1211 reg_control.s.restart_autoneg = 1; 1212 reg_control.s.duplex = link_info.s.full_duplex; 1213 if (link_info.s.speed == 1000) 1214 { 1215 reg_control.s.speed_msb = 1; 1216 reg_control.s.speed_lsb = 0; 1217 } 1218 else if (link_info.s.speed == 100) 1219 { 1220 reg_control.s.speed_msb = 0; 1221 reg_control.s.speed_lsb = 1; 1222 } 1223 else if (link_info.s.speed == 10) 1224 { 1225 reg_control.s.speed_msb = 0; 1226 reg_control.s.speed_lsb = 0; 1227 } 1228 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1229 } 1230 return 0; 1231} 1232 1233 1234/** 1235 * @INTERNAL 1236 * This function is called by cvmx_helper_interface_probe() after it 1237 * determines the number of ports Octeon can support on a specific 1238 * interface. This function is the per board location to override 1239 * this value. It is called with the number of ports Octeon might 1240 * support and should return the number of actual ports on the 1241 * board. 1242 * 1243 * This function must be modified for every new Octeon board. 1244 * Internally it uses switch statements based on the cvmx_sysinfo 1245 * data to determine board types and revisions. It relies on the 1246 * fact that every Octeon board receives a unique board type 1247 * enumeration from the bootloader. 1248 * 1249 * @param interface Interface to probe 1250 * @param supported_ports 1251 * Number of ports Octeon supports. 1252 * 1253 * @return Number of ports the actual board supports. Many times this will 1254 * simple be "support_ports". 1255 */ 1256int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 1257{ 1258 switch (cvmx_sysinfo_get()->board_type) 1259 { 1260 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 1261 case CVMX_BOARD_TYPE_LANAI2_A: 1262 case CVMX_BOARD_TYPE_LANAI2_U: 1263 case CVMX_BOARD_TYPE_LANAI2_G: 1264 if (interface == 0) 1265 return 2; 1266 break; 1267 case CVMX_BOARD_TYPE_BBGW_REF: 1268 if (interface == 0) 1269 return 2; 1270 break; 1271 case CVMX_BOARD_TYPE_NIC_XLE_4G: 1272 if (interface == 0) 1273 return 0; 1274 break; 1275 /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 1276 which we don't support. Disable ports connected to it */ 1277 case CVMX_BOARD_TYPE_EBH5600: 1278 if (interface == 1) 1279 return 0; 1280 break; 1281 case CVMX_BOARD_TYPE_EBB5600: 1282#ifdef CVMX_ENABLE_PKO_FUNCTIONS 1283 if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG) 1284 return 0; 1285#endif 1286 break; 1287 case CVMX_BOARD_TYPE_EBT5810: 1288 return 1; /* Two ports on each SPI: 1 hooked to MAC, 1 loopback 1289 ** Loopback disabled by default. */ 1290 case CVMX_BOARD_TYPE_NIC2E: 1291 if (interface == 0) 1292 return 2; 1293#if defined(OCTEON_VENDOR_LANNER) 1294 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 1295 if (interface == 1) 1296 return 12; 1297 break; 1298#endif 1299#if defined(OCTEON_VENDOR_RADISYS) 1300 case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: 1301 if (interface == 0) 1302 return 13; 1303 if (interface == 1) 1304 return 8; 1305 return 0; 1306#endif 1307 } 1308#ifdef CVMX_BUILD_FOR_UBOOT 1309 if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) 1310 return 0; 1311#endif 1312 return supported_ports; 1313} 1314 1315 1316/** 1317 * @INTERNAL 1318 * Enable packet input/output from the hardware. This function is 1319 * called after by cvmx_helper_packet_hardware_enable() to 1320 * perform board specific initialization. For most boards 1321 * nothing is needed. 1322 * 1323 * @param interface Interface to enable 1324 * 1325 * @return Zero on success, negative on failure 1326 */ 1327int __cvmx_helper_board_hardware_enable(int interface) 1328{ 1329 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) 1330 { 1331 if (interface == 0) 1332 { 1333 /* Different config for switch port */ 1334 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 1335 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 1336 /* Boards with gigabit WAN ports need a different setting that is 1337 compatible with 100 Mbit settings */ 1338 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc); 1339 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); 1340 } 1341 } 1342 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U) 1343 { 1344 if (interface == 0) 1345 { 1346 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16); 1347 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16); 1348 } 1349 } 1350 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5) 1351 { 1352 /* Broadcom PHYs require different ASX clocks. Unfortunately 1353 many customer don't define a new board Id and simply 1354 mangle the CN3010_EVB_HS5 */ 1355 if (interface == 0) 1356 { 1357 /* Some customers boards use a hacked up bootloader that identifies them as 1358 ** CN3010_EVB_HS5 evaluation boards. This leads to all kinds of configuration 1359 ** problems. Detect one case, and print warning, while trying to do the right thing. 1360 */ 1361 int phy_addr = cvmx_helper_board_get_mii_address(0); 1362 if (phy_addr != -1) 1363 { 1364 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2); 1365 /* Is it a Broadcom PHY? */ 1366 if (phy_identifier == 0x0143) 1367 { 1368 cvmx_dprintf("\n"); 1369 cvmx_dprintf("ERROR:\n"); 1370 cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 1371 cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 1372 cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n"); 1373 cvmx_dprintf("ERROR:\n"); 1374 cvmx_dprintf("\n"); 1375 cvmx_wait(1000000000); 1376 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5); 1377 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5); 1378 } 1379 } 1380 } 1381 } 1382 return 0; 1383} 1384 1385 1386/** 1387 * @INTERNAL 1388 * Gets the clock type used for the USB block based on board type. 1389 * Used by the USB code for auto configuration of clock type. 1390 * 1391 * @return USB clock type enumeration 1392 */ 1393cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) 1394{ 1395#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 1396 const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr); 1397 int nodeoffset; 1398 const void *nodep; 1399 int len; 1400 uint32_t speed = 0; 1401 const char *type = NULL; 1402 1403 if (fdt_addr) 1404 { 1405 nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl"); 1406 if (nodeoffset < 0) 1407 nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn"); 1408 1409 if (nodeoffset >= 0) 1410 { 1411 nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len); 1412 if (nodep != NULL && len > 0) 1413 type = (const char *)nodep; 1414 else 1415 type = "unknown"; 1416 nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len); 1417 if (nodep != NULL && len == sizeof(uint32_t)) 1418 speed = fdt32_to_cpu(*(int *)nodep); 1419 else 1420 speed = 0; 1421 if (!strcmp(type, "crystal")) 1422 { 1423 if (speed == 0 || speed == 12000000) 1424 return USB_CLOCK_TYPE_CRYSTAL_12; 1425 else 1426 printf("Warning: invalid crystal speed for USB clock type in FDT\n"); 1427 } 1428 else if (!strcmp(type, "external")) 1429 { 1430 switch (speed) { 1431 case 12000000: 1432 return USB_CLOCK_TYPE_REF_12; 1433 case 24000000: 1434 return USB_CLOCK_TYPE_REF_24; 1435 case 0: 1436 case 48000000: 1437 return USB_CLOCK_TYPE_REF_48; 1438 default: 1439 printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed); 1440 } 1441 } 1442 else 1443 printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL"); 1444 } 1445 } 1446#endif 1447 switch (cvmx_sysinfo_get()->board_type) 1448 { 1449 case CVMX_BOARD_TYPE_BBGW_REF: 1450 case CVMX_BOARD_TYPE_LANAI2_A: 1451 case CVMX_BOARD_TYPE_LANAI2_U: 1452 case CVMX_BOARD_TYPE_LANAI2_G: 1453#if defined(OCTEON_VENDOR_LANNER) 1454 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 1455 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 1456#endif 1457#if defined(OCTEON_BOARD_CAPK_0100ND) 1458 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 1459#endif 1460 case CVMX_BOARD_TYPE_NIC10E_66: 1461 return USB_CLOCK_TYPE_CRYSTAL_12; 1462 case CVMX_BOARD_TYPE_NIC10E: 1463 return USB_CLOCK_TYPE_REF_12; 1464 default: 1465 break; 1466 } 1467 if (OCTEON_IS_MODEL(OCTEON_CN6XXX) /* Most boards except NIC10e use a 12MHz crystal */ 1468 || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) 1469 return USB_CLOCK_TYPE_CRYSTAL_12; 1470 return USB_CLOCK_TYPE_REF_48; 1471} 1472 1473 1474/** 1475 * @INTERNAL 1476 * Adjusts the number of available USB ports on Octeon based on board 1477 * specifics. 1478 * 1479 * @param supported_ports expected number of ports based on chip type; 1480 * 1481 * 1482 * @return number of available usb ports, based on board specifics. 1483 * Return value is supported_ports if function does not 1484 * override. 1485 */ 1486int __cvmx_helper_board_usb_get_num_ports(int supported_ports) 1487{ 1488 switch (cvmx_sysinfo_get()->board_type) 1489 { 1490 case CVMX_BOARD_TYPE_NIC_XLE_4G: 1491 case CVMX_BOARD_TYPE_NIC2E: 1492 return 0; 1493 } 1494 1495 return supported_ports; 1496} 1497 1498 1499