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