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#if !defined(OCTEON_VENDOR_GEFES) 389 case CVMX_BOARD_TYPE_EBT5800: 390 case CVMX_BOARD_TYPE_NICPRO2: 391#endif 392 case CVMX_BOARD_TYPE_EBT3000: 393 case CVMX_BOARD_TYPE_THUNDER: 394 /* Interface 0 is SPI4, interface 1 is RGMII */ 395 if ((ipd_port >= 16) && (ipd_port < 20)) 396 return ipd_port - 16; 397 else 398 return -1; 399 case CVMX_BOARD_TYPE_LANAI2_A: 400 if (ipd_port == 0) 401 return 0; 402 else 403 return -1; 404 case CVMX_BOARD_TYPE_LANAI2_U: 405 case CVMX_BOARD_TYPE_LANAI2_G: 406 if (ipd_port == 0) 407 return 0x1c; 408 else 409 return -1; 410 case CVMX_BOARD_TYPE_KODAMA: 411 case CVMX_BOARD_TYPE_EBH3100: 412 case CVMX_BOARD_TYPE_HIKARI: 413 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 414 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 415#if !defined(OCTEON_VENDOR_GEFES) 416 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 417#endif 418 /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a 419 switch */ 420 if (ipd_port == 0) 421 return 4; 422 else if (ipd_port == 1) 423 return 9; 424 else 425 return -1; 426 case CVMX_BOARD_TYPE_EBH3000: 427 /* Board has dual SPI4 and no PHYs */ 428 return -1; 429 case CVMX_BOARD_TYPE_EBT5810: 430 /* Board has 10g PHYs hooked up to the MII controller on the 431 ** IXF18201 MAC. The 10G PHYS use clause 45 MDIO which the CN58XX 432 ** does not support. All MII accesses go through the IXF part. */ 433 return -1; 434 case CVMX_BOARD_TYPE_EBH5200: 435 case CVMX_BOARD_TYPE_EBH5201: 436 case CVMX_BOARD_TYPE_EBT5200: 437 /* Board has 2 management ports */ 438 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 439 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 440 /* Board has 4 SGMII ports. The PHYs start right after the MII 441 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */ 442 if ((ipd_port >= 0) && (ipd_port < 4)) 443 return ipd_port+2; 444 else 445 return -1; 446 case CVMX_BOARD_TYPE_EBH5600: 447 case CVMX_BOARD_TYPE_EBH5601: 448 case CVMX_BOARD_TYPE_EBH5610: 449 /* Board has 1 management port */ 450 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 451 return 0; 452 /* Board has 8 SGMII ports. 4 connect out, two connect to a switch, 453 and 2 loop to each other */ 454 if ((ipd_port >= 0) && (ipd_port < 4)) 455 return ipd_port+1; 456 else 457 return -1; 458 case CVMX_BOARD_TYPE_EBT5600: 459 /* Board has 1 management port */ 460 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 461 return 0; 462 /* Board has 1 XAUI port connected to a switch. */ 463 return -1; 464 case CVMX_BOARD_TYPE_EBB5600: 465 { 466 static unsigned char qlm_switch_addr = 0; 467 468 /* Board has 1 management port */ 469 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 470 return 0; 471 472 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 473 if ((ipd_port >= 0) && (ipd_port < 4)) 474 { 475 if (qlm_switch_addr != 0x3) 476 { 477 qlm_switch_addr = 0x3; /* QLM1 */ 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+1 + (1<<8); 482 } 483 else if ((ipd_port >= 16) && (ipd_port < 20)) 484 { 485 if (qlm_switch_addr != 0xC) 486 { 487 qlm_switch_addr = 0xC; /* QLM3 */ 488 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 489 cvmx_wait_usec(11000); /* Let the write complete */ 490 } 491 return ipd_port-16+1 + (1<<8); 492 } 493 else 494 return -1; 495 } 496 case CVMX_BOARD_TYPE_EBB6300: 497 /* Board has 2 management ports */ 498 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 499 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 500 if ((ipd_port >= 0) && (ipd_port < 4)) 501 return ipd_port + 1 + (1<<8); 502 else 503 return -1; 504 case CVMX_BOARD_TYPE_EBB6800: 505 /* Board has 1 management ports */ 506 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 507 return 6; 508 if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/ 509 return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/ 510 if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/ 511 return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/ 512 if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/ 513 return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/ 514 if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/ 515 return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/ 516 return -1; 517 case CVMX_BOARD_TYPE_EP6300C: 518 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 519 return 0x01; 520 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1) 521 return 0x02; 522#ifdef CVMX_ENABLE_PKO_FUNCTIONS 523 { 524 int interface = cvmx_helper_get_interface_num(ipd_port); 525 int mode = cvmx_helper_interface_get_mode(interface); 526 if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI) 527 return ipd_port; 528 else if ((ipd_port >= 0) && (ipd_port < 4)) 529 return ipd_port + 3; 530 else 531 return -1; 532 } 533#endif 534 break; 535 case CVMX_BOARD_TYPE_CUST_NB5: 536 if (ipd_port == 2) 537 return 4; 538 else 539 return -1; 540 case CVMX_BOARD_TYPE_NIC_XLE_4G: 541 /* Board has 4 SGMII ports. connected QLM3(interface 1) */ 542 if ((ipd_port >= 16) && (ipd_port < 20)) 543 return ipd_port - 16 + 1; 544 else 545 return -1; 546 case CVMX_BOARD_TYPE_NIC_XLE_10G: 547 case CVMX_BOARD_TYPE_NIC10E: 548 return -1; /* We don't use clause 45 MDIO for anything */ 549 case CVMX_BOARD_TYPE_NIC4E: 550 if (ipd_port >= 0 && ipd_port <= 3) 551 return (ipd_port + 0x1f) & 0x1f; 552 else 553 return -1; 554 case CVMX_BOARD_TYPE_NIC2E: 555 if (ipd_port >= 0 && ipd_port <= 1) 556 return (ipd_port + 1); 557 else 558 return -1; 559 case CVMX_BOARD_TYPE_REDWING: 560 return -1; /* No PHYs connected to Octeon */ 561 case CVMX_BOARD_TYPE_BBGW_REF: 562 return -1; /* No PHYs are connected to Octeon, everything is through switch */ 563 case CVMX_BOARD_TYPE_CUST_WSX16: 564 if (ipd_port >= 0 && ipd_port <= 3) 565 return ipd_port; 566 else if (ipd_port >= 16 && ipd_port <= 19) 567 return ipd_port - 16 + 4; 568 else 569 return -1; 570 571 /* Private vendor-defined boards. */ 572#if defined(OCTEON_VENDOR_LANNER) 573 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 574 /* Interface 1 is 12 BCM5482S PHYs. */ 575 if ((ipd_port >= 16) && (ipd_port < 28)) 576 return ipd_port - 16; 577 return -1; 578 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 579 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 580 return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81; 581 if ((ipd_port >= 0) && (ipd_port < 4)) 582 return ipd_port; 583 return -1; 584 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 585 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 586 /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell 587 88E1111 interfaces. */ 588 switch (ipd_port) { 589 case 0: 590 return 16; 591 case 1: 592 return 1; 593 case 2: 594 return 2; 595 default: 596 return -1; 597 } 598#endif 599#if defined(OCTEON_VENDOR_UBIQUITI) 600 case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100: 601 case CVMX_BOARD_TYPE_CUST_UBIQUITI_USG: 602 if (ipd_port > 2) 603 return -1; 604 return (7 - ipd_port); 605#endif 606#if defined(OCTEON_VENDOR_RADISYS) 607 case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: 608 /* No MII. */ 609 return -1; 610#endif 611#if defined(OCTEON_VENDOR_GEFES) 612 case CVMX_BOARD_TYPE_AT5810: 613 return -1; 614 case CVMX_BOARD_TYPE_TNPA3804: 615 case CVMX_BOARD_TYPE_CUST_TNPA5804: 616 case CVMX_BOARD_TYPE_CUST_W5800: 617 case CVMX_BOARD_TYPE_WNPA3850: 618 case CVMX_BOARD_TYPE_W3860: 619 return -1;// RGMII boards should use inbad status 620 case CVMX_BOARD_TYPE_CUST_W5651X: 621 case CVMX_BOARD_TYPE_CUST_W5650: 622 case CVMX_BOARD_TYPE_CUST_TNPA56X4: 623 case CVMX_BOARD_TYPE_CUST_TNPA5651X: 624 case CVMX_BOARD_TYPE_CUST_W63XX: 625 return -1; /* No PHYs are connected to Octeon, PHYs inside of SFPs which is accessed over TWSI */ 626 case CVMX_BOARD_TYPE_CUST_W5434: 627 /* Board has 4 SGMII ports. 4 connect out 628 * must return the MII address of the PHY connected to each IPD port 629 */ 630 if ((ipd_port >= 16) && (ipd_port < 20)) 631 return ipd_port - 16 + 0x40; 632 else 633 return -1; 634#endif 635 } 636 637 /* Some unknown board. Somebody forgot to update this function... */ 638 cvmx_dprintf("%s: Unknown board type %d\n", 639 __FUNCTION__, cvmx_sysinfo_get()->board_type); 640 return -1; 641} 642#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 643EXPORT_SYMBOL(cvmx_helper_board_get_mii_address); 644#endif 645 646/** 647 * @INTERNAL 648 * Get link state of marvell PHY 649 */ 650static cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr) 651{ 652 cvmx_helper_link_info_t result; 653 int phy_status; 654 655 result.u64 = 0; 656 /*All the speed information can be read from register 17 in one go.*/ 657 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 658 659 /* If the resolve bit 11 isn't set, see if autoneg is turned off 660 (bit 12, reg 0). The resolve bit doesn't get set properly when 661 autoneg is off, so force it */ 662 if ((phy_status & (1<<11)) == 0) 663 { 664 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 665 if ((auto_status & (1<<12)) == 0) 666 phy_status |= 1<<11; 667 } 668 669 /* Only return a link if the PHY has finished auto negotiation 670 and set the resolved bit (bit 11) */ 671 if (phy_status & (1<<11)) 672 { 673 result.s.link_up = 1; 674 result.s.full_duplex = ((phy_status>>13)&1); 675 switch ((phy_status>>14)&3) 676 { 677 case 0: /* 10 Mbps */ 678 result.s.speed = 10; 679 break; 680 case 1: /* 100 Mbps */ 681 result.s.speed = 100; 682 break; 683 case 2: /* 1 Gbps */ 684 result.s.speed = 1000; 685 break; 686 case 3: /* Illegal */ 687 result.u64 = 0; 688 break; 689 } 690 } 691 return result; 692} 693 694/** 695 * @INTERNAL 696 * Get link state of broadcom PHY 697 */ 698static cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr) 699{ 700 cvmx_helper_link_info_t result; 701 int phy_status; 702 703 result.u64 = 0; 704 /* Below we are going to read SMI/MDIO register 0x19 which works 705 on Broadcom parts */ 706 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 707 switch ((phy_status>>8) & 0x7) 708 { 709 case 0: 710 result.u64 = 0; 711 break; 712 case 1: 713 result.s.link_up = 1; 714 result.s.full_duplex = 0; 715 result.s.speed = 10; 716 break; 717 case 2: 718 result.s.link_up = 1; 719 result.s.full_duplex = 1; 720 result.s.speed = 10; 721 break; 722 case 3: 723 result.s.link_up = 1; 724 result.s.full_duplex = 0; 725 result.s.speed = 100; 726 break; 727 case 4: 728 result.s.link_up = 1; 729 result.s.full_duplex = 1; 730 result.s.speed = 100; 731 break; 732 case 5: 733 result.s.link_up = 1; 734 result.s.full_duplex = 1; 735 result.s.speed = 100; 736 break; 737 case 6: 738 result.s.link_up = 1; 739 result.s.full_duplex = 0; 740 result.s.speed = 1000; 741 break; 742 case 7: 743 result.s.link_up = 1; 744 result.s.full_duplex = 1; 745 result.s.speed = 1000; 746 break; 747 } 748 return result; 749} 750 751 752/** 753 * @INTERNAL 754 * Get link state using inband status 755 */ 756static cvmx_helper_link_info_t __get_inband_link_state(int ipd_port) 757{ 758 cvmx_helper_link_info_t result; 759 cvmx_gmxx_rxx_rx_inbnd_t inband_status; 760 int interface = cvmx_helper_get_interface_num(ipd_port); 761 int index = cvmx_helper_get_interface_index_num(ipd_port); 762 763 result.u64 = 0; 764 inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 765 result.s.link_up = inband_status.s.status; 766 result.s.full_duplex = inband_status.s.duplex; 767 switch (inband_status.s.speed) 768 { 769 case 0: /* 10 Mbps */ 770 result.s.speed = 10; 771 break; 772 case 1: /* 100 Mbps */ 773 result.s.speed = 100; 774 break; 775 case 2: /* 1 Gbps */ 776 result.s.speed = 1000; 777 break; 778 case 3: /* Illegal */ 779 result.u64 = 0; 780 break; 781 } 782 return result; 783} 784 785#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 786/** 787 * @INTERNAL 788 * Switch MDIO mux to the specified port. 789 */ 790static int __switch_mdio_mux(int ipd_port) 791{ 792 /* This method is board specific and doesn't use the device tree 793 information as SE doesn't implement MDIO MUX abstration */ 794 switch (cvmx_sysinfo_get()->board_type) 795 { 796 case CVMX_BOARD_TYPE_EBB5600: 797 { 798 static unsigned char qlm_switch_addr = 0; 799 /* Board has 1 management port */ 800 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 801 return 0; 802 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 803 if ((ipd_port >= 0) && (ipd_port < 4)) 804 { 805 if (qlm_switch_addr != 0x3) 806 { 807 qlm_switch_addr = 0x3; /* QLM1 */ 808 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 809 cvmx_wait_usec(11000); /* Let the write complete */ 810 } 811 return ipd_port+1 + (1<<8); 812 } 813 else if ((ipd_port >= 16) && (ipd_port < 20)) 814 { 815 if (qlm_switch_addr != 0xC) 816 { 817 qlm_switch_addr = 0xC; /* QLM3 */ 818 cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 819 cvmx_wait_usec(11000); /* Let the write complete */ 820 } 821 return ipd_port-16+1 + (1<<8); 822 } 823 else 824 return -1; 825 } 826 case CVMX_BOARD_TYPE_EBB6600: 827 { 828 static unsigned char qlm_switch_addr = 0; 829 int old_twsi_switch_reg; 830 /* Board has 2 management ports */ 831 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 832 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 833 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 834 if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */ 835 { 836 if (qlm_switch_addr != 2) 837 { 838 int tries; 839 qlm_switch_addr = 2; 840 tries = 3; 841 do { 842 old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0); 843 } while (tries-- > 0 && old_twsi_switch_reg < 0); 844 /* Set I2C MUX to enable port expander */ 845 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8); 846 /* Set selecter to QLM 1 */ 847 cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff); 848 /* disable port expander */ 849 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg); 850 } 851 return 0x101 + ipd_port; 852 } 853 else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */ 854 { 855 if (qlm_switch_addr != 1) 856 { 857 int tries; 858 qlm_switch_addr = 1; 859 tries = 3; 860 do { 861 old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0); 862 } while (tries-- > 0 && old_twsi_switch_reg < 0); 863 /* Set I2C MUX to enable port expander */ 864 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8); 865 /* Set selecter to QLM 2 */ 866 cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7); 867 /* disable port expander */ 868 cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg); 869 } 870 return 0x101 + (ipd_port - 16); 871 } else 872 return -1; 873 } 874 case CVMX_BOARD_TYPE_EBB6100: 875 { 876 static char gpio_configured = 0; 877 878 if (!gpio_configured) 879 { 880 cvmx_gpio_cfg(3, 1); 881 gpio_configured = 1; 882 } 883 /* Board has 2 management ports */ 884 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 885 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 886 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 887 if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */ 888 { 889 cvmx_gpio_set(1ull << 3); 890 return 0x101 + ipd_port; 891 } 892 else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */ 893 { 894 cvmx_gpio_clear(1ull << 3); 895 return 0x101 + (ipd_port - 16); 896 } 897 else 898 { 899 printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port); 900 return -1; 901 } 902 } 903 default: 904 { 905 cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n", 906 cvmx_sysinfo_get()->board_type); 907 return -1; 908 } 909 } 910 /* should never get here */ 911 return -1; 912} 913 914/** 915 * @INTERNAL 916 * This function is used ethernet ports link speed. This functions uses the 917 * device tree information to determine the phy address and type of PHY. 918 * The only supproted PHYs are Marvell and Broadcom. 919 * 920 * @param ipd_port IPD input port associated with the port we want to get link 921 * status for. 922 * 923 * @return The ports link status. If the link isn't fully resolved, this must 924 * return zero. 925 */ 926 927cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port) 928{ 929 cvmx_helper_link_info_t result; 930 cvmx_phy_info_t phy_info; 931 932 result.u64 = 0; 933 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 934 { 935 /* The simulator gives you a simulated 1Gbps full duplex link */ 936 result.s.link_up = 1; 937 result.s.full_duplex = 1; 938 result.s.speed = 1000; 939 return result; 940 } 941 phy_info = __get_phy_info_from_dt(ipd_port); 942 //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port, 943 // phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type); 944 if (phy_info.phy_addr < 0) return result; 945 946 if (phy_info.direct_connect == 0) 947 __switch_mdio_mux(ipd_port); 948 switch(phy_info.phy_type) 949 { 950 case BROADCOM_GENERIC_PHY: 951 result = __get_broadcom_phy_link_state(phy_info.phy_addr); 952 break; 953 case MARVELL_GENERIC_PHY: 954 result = __get_marvell_phy_link_state(phy_info.phy_addr); 955 break; 956 default: 957 result = __get_inband_link_state(ipd_port); 958 } 959 return result; 960 961} 962#endif 963 964/** 965 * @INTERNAL 966 * This function invokes __cvmx_helper_board_link_get_from_dt when device tree 967 * info is available. When the device tree information is not available then 968 * this function is the board specific method of determining an 969 * ethernet ports link speed. Most Octeon boards have Marvell PHYs 970 * and are handled by the fall through case. This function must be 971 * updated for boards that don't have the normal Marvell PHYs. 972 * 973 * This function must be modified for every new Octeon board. 974 * Internally it uses switch statements based on the cvmx_sysinfo 975 * data to determine board types and revisions. It relies on the 976 * fact that every Octeon board receives a unique board type 977 * enumeration from the bootloader. 978 * 979 * @param ipd_port IPD input port associated with the port we want to get link 980 * status for. 981 * 982 * @return The ports link status. If the link isn't fully resolved, this must 983 * return zero. 984 */ 985cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 986{ 987 cvmx_helper_link_info_t result; 988 int phy_addr; 989 int is_broadcom_phy = 0; 990 991#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 992 if (cvmx_sysinfo_get()->fdt_addr) 993 { 994 return __cvmx_helper_board_link_get_from_dt(ipd_port); 995 } 996#endif 997 998 /* Give the user a chance to override the processing of this function */ 999 if (cvmx_override_board_link_get) 1000 return cvmx_override_board_link_get(ipd_port); 1001 1002 /* Unless we fix it later, all links are defaulted to down */ 1003 result.u64 = 0; 1004 1005#if !defined(OCTEON_BOARD_CAPK_0100ND) 1006 /* This switch statement should handle all ports that either don't use 1007 Marvell PHYS, or don't support in-band status */ 1008 switch (cvmx_sysinfo_get()->board_type) 1009 { 1010 case CVMX_BOARD_TYPE_SIM: 1011 /* The simulator gives you a simulated 1Gbps full duplex link */ 1012 result.s.link_up = 1; 1013 result.s.full_duplex = 1; 1014 result.s.speed = 1000; 1015 return result; 1016 case CVMX_BOARD_TYPE_LANAI2_A: 1017 case CVMX_BOARD_TYPE_LANAI2_U: 1018 case CVMX_BOARD_TYPE_LANAI2_G: 1019 break; 1020 case CVMX_BOARD_TYPE_EBH3100: 1021 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 1022 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 1023#if !defined(OCTEON_VENDOR_GEFES) 1024 case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 1025#endif 1026 /* Port 1 on these boards is always Gigabit */ 1027 if (ipd_port == 1) 1028 { 1029 result.s.link_up = 1; 1030 result.s.full_duplex = 1; 1031 result.s.speed = 1000; 1032 return result; 1033 } 1034 /* Fall through to the generic code below */ 1035 break; 1036 case CVMX_BOARD_TYPE_EBT5600: 1037 case CVMX_BOARD_TYPE_EBH5600: 1038 case CVMX_BOARD_TYPE_EBH5601: 1039 case CVMX_BOARD_TYPE_EBH5610: 1040 /* Board has 1 management ports */ 1041 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 1042 is_broadcom_phy = 1; 1043 break; 1044 case CVMX_BOARD_TYPE_EBH5200: 1045 case CVMX_BOARD_TYPE_EBH5201: 1046 case CVMX_BOARD_TYPE_EBT5200: 1047 /* Board has 2 management ports */ 1048 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 1049 is_broadcom_phy = 1; 1050 break; 1051 case CVMX_BOARD_TYPE_EBB6100: 1052 case CVMX_BOARD_TYPE_EBB6300: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 1053 case CVMX_BOARD_TYPE_EBB6600: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 1054 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)) 1055 && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1) 1056 is_broadcom_phy = 1; 1057 break; 1058 case CVMX_BOARD_TYPE_EP6300C: 1059 is_broadcom_phy = 1; 1060 break; 1061 case CVMX_BOARD_TYPE_CUST_NB5: 1062 /* Port 1 on these boards is always Gigabit */ 1063 if (ipd_port == 1) 1064 { 1065 result.s.link_up = 1; 1066 result.s.full_duplex = 1; 1067 result.s.speed = 1000; 1068 return result; 1069 } 1070 else /* The other port uses a broadcom PHY */ 1071 is_broadcom_phy = 1; 1072 break; 1073 case CVMX_BOARD_TYPE_BBGW_REF: 1074 /* Port 1 on these boards is always Gigabit */ 1075 if (ipd_port == 2) 1076 { 1077 /* Port 2 is not hooked up */ 1078 result.u64 = 0; 1079 return result; 1080 } 1081 else 1082 { 1083 /* Ports 0 and 1 connect to the switch */ 1084 result.s.link_up = 1; 1085 result.s.full_duplex = 1; 1086 result.s.speed = 1000; 1087 return result; 1088 } 1089 case CVMX_BOARD_TYPE_NIC4E: 1090 case CVMX_BOARD_TYPE_NIC2E: 1091 is_broadcom_phy = 1; 1092 break; 1093 /* Private vendor-defined boards. */ 1094#if defined(OCTEON_VENDOR_LANNER) 1095 case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 1096 /* Ports are BCM5482S */ 1097 is_broadcom_phy = 1; 1098 break; 1099 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 1100 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 1101 /* Port 0 connects to the switch */ 1102 if (ipd_port == 0) 1103 { 1104 result.s.link_up = 1; 1105 result.s.full_duplex = 1; 1106 result.s.speed = 1000; 1107 return result; 1108 } 1109 break; 1110#endif 1111#if defined(OCTEON_VENDOR_GEFES) 1112 case CVMX_BOARD_TYPE_CUST_TNPA5651X: 1113 /* Since we don't auto-negotiate... 1Gbps full duplex link */ 1114 result.s.link_up = 1; 1115 result.s.full_duplex = 1; 1116 result.s.speed = 1000; 1117 return result; 1118 break; 1119#endif 1120 } 1121#endif 1122 1123 phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 1124 //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n", 1125 // ipd_port, phy_addr, is_broadcom_phy); 1126 if (phy_addr != -1) 1127 { 1128 if (is_broadcom_phy) 1129 { 1130 result = __get_broadcom_phy_link_state(phy_addr); 1131 } 1132 else 1133 { 1134 /* This code assumes we are using a Marvell Gigabit PHY. */ 1135 result = __get_marvell_phy_link_state(phy_addr); 1136 } 1137 } 1138 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) 1139 || OCTEON_IS_MODEL(OCTEON_CN50XX)) 1140 { 1141 /* We don't have a PHY address, so attempt to use in-band status. It is 1142 really important that boards not supporting in-band status never get 1143 here. Reading broken in-band status tends to do bad things */ 1144 result = __get_inband_link_state(ipd_port); 1145 } 1146#if defined(OCTEON_VENDOR_GEFES) 1147 else if( (OCTEON_IS_MODEL(OCTEON_CN56XX)) || (OCTEON_IS_MODEL(OCTEON_CN63XX)) ) 1148 { 1149 int interface = cvmx_helper_get_interface_num(ipd_port); 1150 int index = cvmx_helper_get_interface_index_num(ipd_port); 1151 cvmx_pcsx_miscx_ctl_reg_t mode_type; 1152 cvmx_pcsx_mrx_status_reg_t mrx_status; 1153 cvmx_pcsx_anx_adv_reg_t anxx_adv; 1154 cvmx_pcsx_sgmx_lp_adv_reg_t sgmii_inband_status; 1155 1156 anxx_adv.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface)); 1157 mrx_status.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface)); 1158 1159 mode_type.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 1160 1161 /* Read Octeon's inband status */ 1162 sgmii_inband_status.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_LP_ADV_REG(index, interface)); 1163 1164 result.s.link_up = sgmii_inband_status.s.link; 1165 result.s.full_duplex = sgmii_inband_status.s.dup; 1166 switch (sgmii_inband_status.s.speed) 1167 { 1168 case 0: /* 10 Mbps */ 1169 result.s.speed = 10; 1170 break; 1171 case 1: /* 100 Mbps */ 1172 result.s.speed = 100; 1173 break; 1174 case 2: /* 1 Gbps */ 1175 result.s.speed = 1000; 1176 break; 1177 case 3: /* Illegal */ 1178 result.s.speed = 0; 1179 result.s.link_up = 0; 1180 break; 1181 } 1182 } 1183#endif 1184 else 1185 { 1186 /* We don't have a PHY address and we don't have in-band status. There 1187 is no way to determine the link speed. Return down assuming this 1188 port isn't wired */ 1189 result.u64 = 0; 1190 } 1191 1192 /* If link is down, return all fields as zero. */ 1193 if (!result.s.link_up) 1194 result.u64 = 0; 1195 1196 return result; 1197} 1198 1199 1200/** 1201 * This function as a board specific method of changing the PHY 1202 * speed, duplex, and autonegotiation. This programs the PHY and 1203 * not Octeon. This can be used to force Octeon's links to 1204 * specific settings. 1205 * 1206 * @param phy_addr The address of the PHY to program 1207 * @param link_flags 1208 * Flags to control autonegotiation. Bit 0 is autonegotiation 1209 * enable/disable to maintain backward compatibility. 1210 * @param link_info Link speed to program. If the speed is zero and autonegotiation 1211 * is enabled, all possible negotiation speeds are advertised. 1212 * 1213 * @return Zero on success, negative on failure 1214 */ 1215int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags, 1216 cvmx_helper_link_info_t link_info) 1217{ 1218 1219 /* Set the flow control settings based on link_flags */ 1220 if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch) 1221 { 1222 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1223 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1224 reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 1225 reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 1226 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1227 } 1228 1229 /* If speed isn't set and autoneg is on advertise all supported modes */ 1230 if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0)) 1231 { 1232 cvmx_mdio_phy_reg_control_t reg_control; 1233 cvmx_mdio_phy_reg_status_t reg_status; 1234 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1235 cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 1236 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 1237 1238 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 1239 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1240 reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4; 1241 reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full; 1242 reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half; 1243 reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full; 1244 reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half; 1245 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1246 if (reg_status.s.capable_extended_status) 1247 { 1248 reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 1249 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 1250 reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full; 1251 reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half; 1252 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 1253 } 1254 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1255 reg_control.s.autoneg_enable = 1; 1256 reg_control.s.restart_autoneg = 1; 1257 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1258 } 1259 else if ((link_flags & set_phy_link_flags_autoneg)) 1260 { 1261 cvmx_mdio_phy_reg_control_t reg_control; 1262 cvmx_mdio_phy_reg_status_t reg_status; 1263 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1264 cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 1265 1266 reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 1267 reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1268 reg_autoneg_adver.s.advert_100base_t4 = 0; 1269 reg_autoneg_adver.s.advert_10base_tx_full = 0; 1270 reg_autoneg_adver.s.advert_10base_tx_half = 0; 1271 reg_autoneg_adver.s.advert_100base_tx_full = 0; 1272 reg_autoneg_adver.s.advert_100base_tx_half = 0; 1273 if (reg_status.s.capable_extended_status) 1274 { 1275 reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 1276 reg_control_1000.s.advert_1000base_t_full = 0; 1277 reg_control_1000.s.advert_1000base_t_half = 0; 1278 } 1279 switch (link_info.s.speed) 1280 { 1281 case 10: 1282 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex; 1283 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex; 1284 break; 1285 case 100: 1286 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex; 1287 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex; 1288 break; 1289 case 1000: 1290 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex; 1291 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex; 1292 break; 1293 } 1294 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1295 if (reg_status.s.capable_extended_status) 1296 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 1297 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1298 reg_control.s.autoneg_enable = 1; 1299 reg_control.s.restart_autoneg = 1; 1300 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1301 } 1302 else 1303 { 1304 cvmx_mdio_phy_reg_control_t reg_control; 1305 reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1306 reg_control.s.autoneg_enable = 0; 1307 reg_control.s.restart_autoneg = 1; 1308 reg_control.s.duplex = link_info.s.full_duplex; 1309 if (link_info.s.speed == 1000) 1310 { 1311 reg_control.s.speed_msb = 1; 1312 reg_control.s.speed_lsb = 0; 1313 } 1314 else if (link_info.s.speed == 100) 1315 { 1316 reg_control.s.speed_msb = 0; 1317 reg_control.s.speed_lsb = 1; 1318 } 1319 else if (link_info.s.speed == 10) 1320 { 1321 reg_control.s.speed_msb = 0; 1322 reg_control.s.speed_lsb = 0; 1323 } 1324 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1325 } 1326 return 0; 1327} 1328 1329 1330/** 1331 * @INTERNAL 1332 * This function is called by cvmx_helper_interface_probe() after it 1333 * determines the number of ports Octeon can support on a specific 1334 * interface. This function is the per board location to override 1335 * this value. It is called with the number of ports Octeon might 1336 * support and should return the number of actual ports on the 1337 * board. 1338 * 1339 * This function must be modified for every new Octeon board. 1340 * Internally it uses switch statements based on the cvmx_sysinfo 1341 * data to determine board types and revisions. It relies on the 1342 * fact that every Octeon board receives a unique board type 1343 * enumeration from the bootloader. 1344 * 1345 * @param interface Interface to probe 1346 * @param supported_ports 1347 * Number of ports Octeon supports. 1348 * 1349 * @return Number of ports the actual board supports. Many times this will 1350 * simple be "support_ports". 1351 */ 1352int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 1353{ 1354 switch (cvmx_sysinfo_get()->board_type) 1355 { 1356 case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 1357 case CVMX_BOARD_TYPE_LANAI2_A: 1358 case CVMX_BOARD_TYPE_LANAI2_U: 1359 case CVMX_BOARD_TYPE_LANAI2_G: 1360 if (interface == 0) 1361 return 2; 1362 break; 1363 case CVMX_BOARD_TYPE_BBGW_REF: 1364 if (interface == 0) 1365 return 2; 1366 break; 1367 case CVMX_BOARD_TYPE_NIC_XLE_4G: 1368 if (interface == 0) 1369 return 0; 1370 break; 1371 /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 1372 which we don't support. Disable ports connected to it */ 1373 case CVMX_BOARD_TYPE_EBH5600: 1374 if (interface == 1) 1375 return 0; 1376 break; 1377 case CVMX_BOARD_TYPE_EBB5600: 1378#ifdef CVMX_ENABLE_PKO_FUNCTIONS 1379 if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG) 1380 return 0; 1381#endif 1382 break; 1383 case CVMX_BOARD_TYPE_EBT5600: 1384 /* Disable loopback. */ 1385 if (interface == 3) 1386 return 0; 1387 break; 1388 case CVMX_BOARD_TYPE_EBT5810: 1389 return 1; /* Two ports on each SPI: 1 hooked to MAC, 1 loopback 1390 ** Loopback disabled by default. */ 1391 case CVMX_BOARD_TYPE_NIC2E: 1392 if (interface == 0) 1393 return 2; 1394#if defined(OCTEON_VENDOR_LANNER) 1395 case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 1396 if (interface == 1) 1397 return 12; 1398 break; 1399#endif 1400#if defined(OCTEON_VENDOR_GEFES) 1401 case CVMX_BOARD_TYPE_CUST_TNPA5651X: 1402 if (interface < 2) /* interface can be EITHER 0 or 1 */ 1403 return 1;//always return 1 for XAUI and SGMII mode. 1404 break; 1405 case CVMX_BOARD_TYPE_CUST_TNPA56X4: 1406 if ((interface == 0) && 1407 (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_SGMII)) 1408 { 1409 cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg; 1410 1411 /* For this port we need to set the mode to 1000BaseX */ 1412 pcsx_miscx_ctl_reg.u64 = 1413 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface)); 1414 pcsx_miscx_ctl_reg.cn56xx.mode = 1; 1415 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface), 1416 pcsx_miscx_ctl_reg.u64); 1417 pcsx_miscx_ctl_reg.u64 = 1418 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface)); 1419 pcsx_miscx_ctl_reg.cn56xx.mode = 1; 1420 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface), 1421 pcsx_miscx_ctl_reg.u64); 1422 1423 return 2; 1424 } 1425 break; 1426#endif 1427 } 1428#ifdef CVMX_BUILD_FOR_UBOOT 1429 if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) 1430 return 0; 1431#endif 1432 return supported_ports; 1433} 1434 1435 1436/** 1437 * @INTERNAL 1438 * Enable packet input/output from the hardware. This function is 1439 * called after by cvmx_helper_packet_hardware_enable() to 1440 * perform board specific initialization. For most boards 1441 * nothing is needed. 1442 * 1443 * @param interface Interface to enable 1444 * 1445 * @return Zero on success, negative on failure 1446 */ 1447int __cvmx_helper_board_hardware_enable(int interface) 1448{ 1449 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) 1450 { 1451 if (interface == 0) 1452 { 1453 /* Different config for switch port */ 1454 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 1455 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 1456 /* Boards with gigabit WAN ports need a different setting that is 1457 compatible with 100 Mbit settings */ 1458 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc); 1459 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); 1460 } 1461 } 1462 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U) 1463 { 1464 if (interface == 0) 1465 { 1466 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16); 1467 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16); 1468 } 1469 } 1470 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5) 1471 { 1472 /* Broadcom PHYs require different ASX clocks. Unfortunately 1473 many customer don't define a new board Id and simply 1474 mangle the CN3010_EVB_HS5 */ 1475 if (interface == 0) 1476 { 1477 /* Some customers boards use a hacked up bootloader that identifies them as 1478 ** CN3010_EVB_HS5 evaluation boards. This leads to all kinds of configuration 1479 ** problems. Detect one case, and print warning, while trying to do the right thing. 1480 */ 1481 int phy_addr = cvmx_helper_board_get_mii_address(0); 1482 if (phy_addr != -1) 1483 { 1484 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2); 1485 /* Is it a Broadcom PHY? */ 1486 if (phy_identifier == 0x0143) 1487 { 1488 cvmx_dprintf("\n"); 1489 cvmx_dprintf("ERROR:\n"); 1490 cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 1491 cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 1492 cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n"); 1493 cvmx_dprintf("ERROR:\n"); 1494 cvmx_dprintf("\n"); 1495 cvmx_wait(1000000000); 1496 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5); 1497 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5); 1498 } 1499 } 1500 } 1501 } 1502#if defined(OCTEON_VENDOR_UBIQUITI) 1503 else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_E100 || 1504 cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_USG) 1505 { 1506 /* Configure ASX cloks for all ports on interface 0. */ 1507 if (interface == 0) 1508 { 1509 int port; 1510 1511 for (port = 0; port < 3; port++) { 1512 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16); 1513 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0); 1514 } 1515 } 1516 } 1517#endif 1518 return 0; 1519} 1520 1521 1522/** 1523 * @INTERNAL 1524 * Gets the clock type used for the USB block based on board type. 1525 * Used by the USB code for auto configuration of clock type. 1526 * 1527 * @return USB clock type enumeration 1528 */ 1529cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) 1530{ 1531#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 1532 const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr); 1533 int nodeoffset; 1534 const void *nodep; 1535 int len; 1536 uint32_t speed = 0; 1537 const char *type = NULL; 1538 1539 if (fdt_addr) 1540 { 1541 nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl"); 1542 if (nodeoffset < 0) 1543 nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn"); 1544 1545 if (nodeoffset >= 0) 1546 { 1547 nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len); 1548 if (nodep != NULL && len > 0) 1549 type = (const char *)nodep; 1550 else 1551 type = "unknown"; 1552 nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len); 1553 if (nodep != NULL && len == sizeof(uint32_t)) 1554 speed = fdt32_to_cpu(*(int *)nodep); 1555 else 1556 speed = 0; 1557 if (!strcmp(type, "crystal")) 1558 { 1559 if (speed == 0 || speed == 12000000) 1560 return USB_CLOCK_TYPE_CRYSTAL_12; 1561 else 1562 printf("Warning: invalid crystal speed for USB clock type in FDT\n"); 1563 } 1564 else if (!strcmp(type, "external")) 1565 { 1566 switch (speed) { 1567 case 12000000: 1568 return USB_CLOCK_TYPE_REF_12; 1569 case 24000000: 1570 return USB_CLOCK_TYPE_REF_24; 1571 case 0: 1572 case 48000000: 1573 return USB_CLOCK_TYPE_REF_48; 1574 default: 1575 printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed); 1576 } 1577 } 1578 else 1579 printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL"); 1580 } 1581 } 1582#endif 1583 switch (cvmx_sysinfo_get()->board_type) 1584 { 1585 case CVMX_BOARD_TYPE_BBGW_REF: 1586 case CVMX_BOARD_TYPE_LANAI2_A: 1587 case CVMX_BOARD_TYPE_LANAI2_U: 1588 case CVMX_BOARD_TYPE_LANAI2_G: 1589#if defined(OCTEON_VENDOR_LANNER) 1590 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 1591 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 1592#endif 1593#if defined(OCTEON_VENDOR_UBIQUITI) 1594 case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100: 1595 case CVMX_BOARD_TYPE_CUST_UBIQUITI_USG: 1596#endif 1597#if defined(OCTEON_BOARD_CAPK_0100ND) 1598 case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 1599#endif 1600#if defined(OCTEON_VENDOR_GEFES) /* All GEFES' boards use same xtal type */ 1601 case CVMX_BOARD_TYPE_TNPA3804: 1602 case CVMX_BOARD_TYPE_AT5810: 1603 case CVMX_BOARD_TYPE_WNPA3850: 1604 case CVMX_BOARD_TYPE_W3860: 1605 case CVMX_BOARD_TYPE_CUST_TNPA5804: 1606 case CVMX_BOARD_TYPE_CUST_W5434: 1607 case CVMX_BOARD_TYPE_CUST_W5650: 1608 case CVMX_BOARD_TYPE_CUST_W5800: 1609 case CVMX_BOARD_TYPE_CUST_W5651X: 1610 case CVMX_BOARD_TYPE_CUST_TNPA5651X: 1611 case CVMX_BOARD_TYPE_CUST_TNPA56X4: 1612 case CVMX_BOARD_TYPE_CUST_W63XX: 1613#endif 1614 case CVMX_BOARD_TYPE_NIC10E_66: 1615 return USB_CLOCK_TYPE_CRYSTAL_12; 1616 case CVMX_BOARD_TYPE_NIC10E: 1617 return USB_CLOCK_TYPE_REF_12; 1618 default: 1619 break; 1620 } 1621 if (OCTEON_IS_MODEL(OCTEON_CN6XXX) /* Most boards except NIC10e use a 12MHz crystal */ 1622 || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) 1623 return USB_CLOCK_TYPE_CRYSTAL_12; 1624 return USB_CLOCK_TYPE_REF_48; 1625} 1626 1627 1628/** 1629 * @INTERNAL 1630 * Adjusts the number of available USB ports on Octeon based on board 1631 * specifics. 1632 * 1633 * @param supported_ports expected number of ports based on chip type; 1634 * 1635 * 1636 * @return number of available usb ports, based on board specifics. 1637 * Return value is supported_ports if function does not 1638 * override. 1639 */ 1640int __cvmx_helper_board_usb_get_num_ports(int supported_ports) 1641{ 1642 switch (cvmx_sysinfo_get()->board_type) 1643 { 1644 case CVMX_BOARD_TYPE_NIC_XLE_4G: 1645 case CVMX_BOARD_TYPE_NIC2E: 1646 return 0; 1647 } 1648 1649 return supported_ports; 1650} 1651 1652 1653