cvmx-helper-board.c revision 244984
1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2011 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett 42210284Sjmallett 43210284Sjmallett 44210284Sjmallett 45215990Sjmallett 46210284Sjmallett/** 47210284Sjmallett * @file 48210284Sjmallett * 49210284Sjmallett * Helper functions to abstract board specific data about 50210284Sjmallett * network ports from the rest of the cvmx-helper files. 51210284Sjmallett * 52232812Sjmallett * <hr>$Revision: 70030 $<hr> 53210284Sjmallett */ 54215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 55215990Sjmallett#include <linux/module.h> 56215990Sjmallett#include <asm/octeon/cvmx.h> 57215990Sjmallett#include <asm/octeon/cvmx-bootinfo.h> 58215990Sjmallett#include <asm/octeon/cvmx-smix-defs.h> 59215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h> 60215990Sjmallett#include <asm/octeon/cvmx-asxx-defs.h> 61215990Sjmallett#include <asm/octeon/cvmx-mdio.h> 62215990Sjmallett#include <asm/octeon/cvmx-helper.h> 63215990Sjmallett#include <asm/octeon/cvmx-helper-util.h> 64215990Sjmallett#include <asm/octeon/cvmx-helper-board.h> 65215990Sjmallett#include <asm/octeon/cvmx-twsi.h> 66215990Sjmallett#else 67210284Sjmallett#include "cvmx.h" 68210284Sjmallett#include "cvmx-app-init.h" 69215990Sjmallett#include "cvmx-sysinfo.h" 70215990Sjmallett#include "cvmx-twsi.h" 71210284Sjmallett#include "cvmx-mdio.h" 72210284Sjmallett#include "cvmx-helper.h" 73210284Sjmallett#include "cvmx-helper-util.h" 74210284Sjmallett#include "cvmx-helper-board.h" 75232812Sjmallett#include "cvmx-gpio.h" 76232815Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 77232812Sjmallett#ifdef __U_BOOT__ 78232812Sjmallett# include <libfdt.h> 79232812Sjmallett#else 80232812Sjmallett# include "libfdt/libfdt.h" 81215990Sjmallett#endif 82232815Sjmallett#endif 83232812Sjmallett#include "cvmx-swap.h" 84232812Sjmallett#endif 85210284Sjmallett 86210284Sjmallett/** 87210284Sjmallett * cvmx_override_board_link_get(int ipd_port) is a function 88210284Sjmallett * pointer. It is meant to allow customization of the process of 89210284Sjmallett * talking to a PHY to determine link speed. It is called every 90210284Sjmallett * time a PHY must be polled for link status. Users should set 91210284Sjmallett * this pointer to a function before calling any cvmx-helper 92210284Sjmallett * operations. 93210284Sjmallett */ 94210284SjmallettCVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL; 95210284Sjmallett 96232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 97232812Sjmallett 98232812Sjmallettstatic 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) 99232812Sjmallett{ 100232812Sjmallett int tries = 3; 101232812Sjmallett int r; 102232812Sjmallett do { 103232812Sjmallett r = cvmx_twsix_write_ia(twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data); 104232812Sjmallett } while (tries-- > 0 && r < 0); 105232812Sjmallett} 106232812Sjmallett 107232812Sjmallettstatic int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port) 108232812Sjmallett{ 109232812Sjmallett char name_buffer[20]; 110232812Sjmallett const char*pip_path; 111232812Sjmallett int pip, iface, eth; 112232812Sjmallett int interface_num = cvmx_helper_get_interface_num(ipd_port); 113232812Sjmallett int interface_index = cvmx_helper_get_interface_index_num(ipd_port); 114232812Sjmallett 115232812Sjmallett pip_path = fdt_getprop(fdt_addr, aliases, "pip", NULL); 116232812Sjmallett if (!pip_path) 117232812Sjmallett { 118232812Sjmallett cvmx_dprintf("ERROR: pip path not found in device tree\n"); 119232812Sjmallett return -1; 120232812Sjmallett } 121232812Sjmallett pip = fdt_path_offset(fdt_addr, pip_path); 122232812Sjmallett if (pip < 0) 123232812Sjmallett { 124232812Sjmallett cvmx_dprintf("ERROR: pip not found in device tree\n"); 125232812Sjmallett return -1; 126232812Sjmallett } 127232812Sjmallett#ifdef __U_BOOT__ 128232812Sjmallett sprintf(name_buffer, "interface@%d", interface_num); 129232812Sjmallett#else 130232812Sjmallett snprintf(name_buffer, sizeof(name_buffer), "interface@%d", interface_num); 131232812Sjmallett#endif 132232812Sjmallett iface = fdt_subnode_offset(fdt_addr, pip, name_buffer); 133232812Sjmallett if (iface < 0) 134232812Sjmallett { 135232812Sjmallett cvmx_dprintf("ERROR : pip intf %d not found in device tree \n", 136232812Sjmallett interface_num); 137232812Sjmallett return -1; 138232812Sjmallett } 139232812Sjmallett#ifdef __U_BOOT__ 140232812Sjmallett sprintf(name_buffer, "ethernet@%x", interface_index); 141232812Sjmallett#else 142232812Sjmallett snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", interface_index); 143232812Sjmallett#endif 144232812Sjmallett eth = fdt_subnode_offset(fdt_addr, iface, name_buffer); 145232812Sjmallett if (eth < 0) 146232812Sjmallett { 147232812Sjmallett cvmx_dprintf("ERROR : pip interface@%d ethernet@%d not found in device " 148232812Sjmallett "tree\n", interface_num, interface_index); 149232812Sjmallett return -1; 150232812Sjmallett } 151232812Sjmallett return eth; 152232812Sjmallett} 153232812Sjmallett 154232812Sjmallettstatic int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index) 155232812Sjmallett{ 156232812Sjmallett char name_buffer[20]; 157232812Sjmallett const char*mix_path; 158232812Sjmallett int mix; 159232812Sjmallett 160232812Sjmallett#ifdef __U_BOOT__ 161232812Sjmallett sprintf(name_buffer, "mix%d", interface_index); 162232812Sjmallett#else 163232812Sjmallett snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index); 164232812Sjmallett#endif 165232812Sjmallett mix_path = fdt_getprop(fdt_addr, aliases, name_buffer, NULL); 166232812Sjmallett if (!mix_path) 167232812Sjmallett { 168232812Sjmallett cvmx_dprintf("ERROR: mix%d path not found in device tree\n",interface_index); 169232812Sjmallett } 170232812Sjmallett mix = fdt_path_offset(fdt_addr, mix_path); 171232812Sjmallett if (mix < 0) 172232812Sjmallett { 173232812Sjmallett cvmx_dprintf("ERROR: %s not found in device tree\n", mix_path); 174232812Sjmallett return -1; 175232812Sjmallett } 176232812Sjmallett return mix; 177232812Sjmallett} 178232812Sjmallett 179232812Sjmalletttypedef struct cvmx_phy_info 180232812Sjmallett{ 181232812Sjmallett int phy_addr; 182232812Sjmallett int direct_connect; 183232812Sjmallett cvmx_phy_type_t phy_type; 184232812Sjmallett}cvmx_phy_info_t; 185232812Sjmallett 186232812Sjmallett 187232812Sjmallettstatic int __mdiobus_addr_to_unit(uint32_t addr) 188232812Sjmallett{ 189232812Sjmallett int unit = (addr >> 7) & 3; 190232812Sjmallett if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) 191232812Sjmallett unit >>= 1; 192232812Sjmallett return unit; 193232812Sjmallett} 194210284Sjmallett/** 195210284Sjmallett * Return the MII PHY address associated with the given IPD 196232812Sjmallett * port. The phy address is obtained from the device tree. 197232812Sjmallett * 198232812Sjmallett * @param ipd_port Octeon IPD port to get the MII address for. 199232812Sjmallett * 200232812Sjmallett * @return MII PHY address and bus number or -1. 201232812Sjmallett */ 202232812Sjmallett 203232812Sjmallettstatic cvmx_phy_info_t __get_phy_info_from_dt(int ipd_port) 204232812Sjmallett{ 205232812Sjmallett const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr); 206232812Sjmallett uint32_t *phy_handle; 207232812Sjmallett int aliases, eth, phy, phy_parent, phandle, ret; 208232812Sjmallett cvmx_phy_info_t phy_info; 209232812Sjmallett int mdio_unit=-1; 210232812Sjmallett const char *phy_comaptible_str; 211232812Sjmallett uint32_t *phy_addr_ptr; 212232812Sjmallett 213232812Sjmallett phy_info.phy_addr = -1; 214232812Sjmallett phy_info.direct_connect = -1; 215232812Sjmallett phy_info.phy_type = (cvmx_phy_type_t) -1; 216232812Sjmallett 217232812Sjmallett if (!fdt_addr) 218232812Sjmallett { 219232812Sjmallett cvmx_dprintf("No device tree found.\n"); 220232812Sjmallett return phy_info; 221232812Sjmallett } 222232812Sjmallett aliases = fdt_path_offset(fdt_addr, "/aliases"); 223232812Sjmallett if (aliases < 0) { 224232812Sjmallett cvmx_dprintf("Error: No /aliases node in device tree.\n"); 225232812Sjmallett return phy_info; 226232812Sjmallett } 227232812Sjmallett if (ipd_port < 0) 228232812Sjmallett { 229232812Sjmallett int interface_index = ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 230232812Sjmallett eth = __mix_eth_node(fdt_addr, aliases, interface_index) ; 231232812Sjmallett } 232232812Sjmallett else 233232812Sjmallett { 234232812Sjmallett eth = __pip_eth_node(fdt_addr, aliases, ipd_port); 235232812Sjmallett } 236232812Sjmallett if (eth < 0 ) 237232812Sjmallett { 238232812Sjmallett cvmx_dprintf("ERROR : cannot find interface for ipd_port=%d\n", ipd_port); 239232812Sjmallett return phy_info; 240232812Sjmallett } 241232812Sjmallett /* Get handle to phy */ 242232812Sjmallett phy_handle = (uint32_t *) fdt_getprop(fdt_addr, eth, "phy-handle", NULL); 243232812Sjmallett if (!phy_handle) 244232812Sjmallett { 245232812Sjmallett cvmx_dprintf("ERROR : phy handle not found in device tree ipd_port=%d" 246232812Sjmallett "\n", ipd_port); 247232812Sjmallett return phy_info; 248232812Sjmallett } 249232812Sjmallett phandle = cvmx_be32_to_cpu(*phy_handle); 250232812Sjmallett phy = fdt_node_offset_by_phandle(fdt_addr, phandle); 251232812Sjmallett if (phy < 0) 252232812Sjmallett { 253232812Sjmallett cvmx_dprintf("ERROR : cannot find phy for ipd_port=%d ret=%d\n", 254232812Sjmallett ipd_port, phy); 255232812Sjmallett return phy_info; 256232812Sjmallett } 257232812Sjmallett phy_comaptible_str = (const char *) fdt_getprop(fdt_addr, phy, 258232812Sjmallett "compatible", NULL); 259232812Sjmallett if (!phy_comaptible_str) 260232812Sjmallett { 261232812Sjmallett cvmx_dprintf("ERROR : no compatible prop in phy\n"); 262232812Sjmallett return phy_info; 263232812Sjmallett } 264232812Sjmallett if (memcmp("marvell", phy_comaptible_str, strlen("marvell")) == 0) 265232812Sjmallett { 266232812Sjmallett phy_info.phy_type = MARVELL_GENERIC_PHY; 267232812Sjmallett } 268232812Sjmallett else if (memcmp("broadcom", phy_comaptible_str, strlen("broadcom")) == 0) 269232812Sjmallett { 270232812Sjmallett phy_info.phy_type = BROADCOM_GENERIC_PHY; 271232812Sjmallett } 272232812Sjmallett else 273232812Sjmallett { 274232812Sjmallett phy_info.phy_type = -1; 275232812Sjmallett } 276232812Sjmallett 277232812Sjmallett /* Check if PHY parent is the octeon MDIO bus. Some boards are connected 278232812Sjmallett though a MUX and for them direct_connect_to_phy will be 0 */ 279232812Sjmallett phy_parent = fdt_parent_offset(fdt_addr, phy); 280232812Sjmallett if (phy_parent < 0) 281232812Sjmallett { 282232812Sjmallett cvmx_dprintf("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n", 283232812Sjmallett ipd_port, phy_parent); 284232812Sjmallett return phy_info; 285232812Sjmallett } 286232812Sjmallett ret = fdt_node_check_compatible(fdt_addr, phy_parent, 287232812Sjmallett "cavium,octeon-3860-mdio"); 288232812Sjmallett if (ret == 0) 289232812Sjmallett { 290232812Sjmallett phy_info.direct_connect = 1 ; 291232812Sjmallett uint32_t *mdio_reg_base = (uint32_t *) fdt_getprop(fdt_addr, phy_parent,"reg",0); 292232812Sjmallett if (mdio_reg_base == 0) 293232812Sjmallett { 294232812Sjmallett cvmx_dprintf("ERROR : unable to get reg property in phy mdio\n"); 295232812Sjmallett return phy_info; 296232812Sjmallett } 297232812Sjmallett mdio_unit = __mdiobus_addr_to_unit(mdio_reg_base[1]); 298232812Sjmallett //cvmx_dprintf("phy parent=%s reg_base=%08x unit=%d \n", 299232812Sjmallett // fdt_get_name(fdt_addr,phy_parent, NULL), mdio_reg_base[1], mdio_unit); 300232812Sjmallett } 301232812Sjmallett else 302232812Sjmallett { 303232812Sjmallett phy_info.direct_connect = 0; 304232812Sjmallett /* The PHY is not directly connected to the Octeon MDIO bus. 305232812Sjmallett SE doesn't have abstractions for MDIO MUX or MDIO MUX drivers and 306232812Sjmallett hence for the non direct cases code will be needed which is 307232812Sjmallett board specific. 308232812Sjmallett For now the the MDIO Unit is defaulted to 1. 309232812Sjmallett */ 310232812Sjmallett mdio_unit = 1; 311232812Sjmallett } 312232812Sjmallett 313232812Sjmallett phy_addr_ptr = (uint32_t *) fdt_getprop(fdt_addr, phy, "reg", NULL); 314232812Sjmallett phy_info.phy_addr = cvmx_be32_to_cpu(*phy_addr_ptr) | mdio_unit << 8; 315232812Sjmallett return phy_info; 316232812Sjmallett 317232812Sjmallett} 318232812Sjmallett 319232812Sjmallett/** 320232812Sjmallett * Return the MII PHY address associated with the given IPD 321232812Sjmallett * port. The phy address is obtained from the device tree. 322232812Sjmallett * 323232812Sjmallett * @param ipd_port Octeon IPD port to get the MII address for. 324232812Sjmallett * 325232812Sjmallett * @return MII PHY address and bus number or -1. 326232812Sjmallett */ 327232812Sjmallett 328232812Sjmallettint cvmx_helper_board_get_mii_address_from_dt(int ipd_port) 329232812Sjmallett{ 330232812Sjmallett cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port); 331232812Sjmallett return phy_info.phy_addr; 332232812Sjmallett} 333232812Sjmallett#endif 334232812Sjmallett 335232812Sjmallett/** 336232812Sjmallett * Return the MII PHY address associated with the given IPD 337210284Sjmallett * port. A result of -1 means there isn't a MII capable PHY 338210284Sjmallett * connected to this port. On chips supporting multiple MII 339210284Sjmallett * busses the bus number is encoded in bits <15:8>. 340210284Sjmallett * 341210284Sjmallett * This function must be modified for every new Octeon board. 342210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo 343210284Sjmallett * data to determine board types and revisions. It replies on the 344210284Sjmallett * fact that every Octeon board receives a unique board type 345210284Sjmallett * enumeration from the bootloader. 346210284Sjmallett * 347210284Sjmallett * @param ipd_port Octeon IPD port to get the MII address for. 348210284Sjmallett * 349210284Sjmallett * @return MII PHY address and bus number or -1. 350210284Sjmallett */ 351210284Sjmallettint cvmx_helper_board_get_mii_address(int ipd_port) 352210284Sjmallett{ 353210311Sjmallett /* 354210311Sjmallett * Board types we have to know at compile-time. 355210311Sjmallett */ 356210311Sjmallett#ifdef OCTEON_BOARD_CAPK_0100ND 357210311Sjmallett switch (ipd_port) { 358210311Sjmallett case 0: 359210311Sjmallett return 2; 360210311Sjmallett case 1: 361210311Sjmallett return 3; 362210311Sjmallett case 2: 363210311Sjmallett /* XXX Switch PHY? */ 364210311Sjmallett return -1; 365210311Sjmallett default: 366210311Sjmallett return -1; 367210311Sjmallett } 368210311Sjmallett#endif 369210311Sjmallett 370210311Sjmallett /* 371210311Sjmallett * For board types we can determine at runtime. 372210311Sjmallett */ 373232812Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 374232812Sjmallett return -1; 375232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 376232812Sjmallett if (cvmx_sysinfo_get()->fdt_addr) 377232812Sjmallett { 378232812Sjmallett cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port); 379232812Sjmallett //cvmx_dprintf("ipd_port=%d phy_addr=%d\n", ipd_port, phy_info.phy_addr); 380232812Sjmallett if (phy_info.phy_addr >= 0) return phy_info.phy_addr; 381232812Sjmallett } 382232812Sjmallett#endif 383210284Sjmallett switch (cvmx_sysinfo_get()->board_type) 384210284Sjmallett { 385210284Sjmallett case CVMX_BOARD_TYPE_SIM: 386210284Sjmallett /* Simulator doesn't have MII */ 387210284Sjmallett return -1; 388210284Sjmallett case CVMX_BOARD_TYPE_EBT3000: 389210284Sjmallett case CVMX_BOARD_TYPE_EBT5800: 390210284Sjmallett case CVMX_BOARD_TYPE_THUNDER: 391210284Sjmallett case CVMX_BOARD_TYPE_NICPRO2: 392210284Sjmallett /* Interface 0 is SPI4, interface 1 is RGMII */ 393210284Sjmallett if ((ipd_port >= 16) && (ipd_port < 20)) 394210284Sjmallett return ipd_port - 16; 395210284Sjmallett else 396210284Sjmallett return -1; 397215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_A: 398215990Sjmallett if (ipd_port == 0) 399215990Sjmallett return 0; 400215990Sjmallett else 401215990Sjmallett return -1; 402215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_U: 403215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_G: 404215990Sjmallett if (ipd_port == 0) 405215990Sjmallett return 0x1c; 406215990Sjmallett else 407215990Sjmallett return -1; 408210284Sjmallett case CVMX_BOARD_TYPE_KODAMA: 409210284Sjmallett case CVMX_BOARD_TYPE_EBH3100: 410210284Sjmallett case CVMX_BOARD_TYPE_HIKARI: 411210284Sjmallett case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 412210284Sjmallett case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 413210284Sjmallett case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 414210284Sjmallett /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a 415210284Sjmallett switch */ 416210284Sjmallett if (ipd_port == 0) 417210284Sjmallett return 4; 418210284Sjmallett else if (ipd_port == 1) 419210284Sjmallett return 9; 420210284Sjmallett else 421210284Sjmallett return -1; 422210284Sjmallett case CVMX_BOARD_TYPE_EBH3000: 423210284Sjmallett /* Board has dual SPI4 and no PHYs */ 424210284Sjmallett return -1; 425215990Sjmallett case CVMX_BOARD_TYPE_EBT5810: 426215990Sjmallett /* Board has 10g PHYs hooked up to the MII controller on the 427215990Sjmallett ** IXF18201 MAC. The 10G PHYS use clause 45 MDIO which the CN58XX 428215990Sjmallett ** does not support. All MII accesses go through the IXF part. */ 429215990Sjmallett return -1; 430210284Sjmallett case CVMX_BOARD_TYPE_EBH5200: 431210284Sjmallett case CVMX_BOARD_TYPE_EBH5201: 432210284Sjmallett case CVMX_BOARD_TYPE_EBT5200: 433215990Sjmallett /* Board has 2 management ports */ 434215990Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 435215990Sjmallett return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 436210284Sjmallett /* Board has 4 SGMII ports. The PHYs start right after the MII 437210284Sjmallett ports MII0 = 0, MII1 = 1, SGMII = 2-5 */ 438210284Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) 439210284Sjmallett return ipd_port+2; 440210284Sjmallett else 441210284Sjmallett return -1; 442210284Sjmallett case CVMX_BOARD_TYPE_EBH5600: 443210284Sjmallett case CVMX_BOARD_TYPE_EBH5601: 444215990Sjmallett case CVMX_BOARD_TYPE_EBH5610: 445215990Sjmallett /* Board has 1 management port */ 446215990Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 447215990Sjmallett return 0; 448210284Sjmallett /* Board has 8 SGMII ports. 4 connect out, two connect to a switch, 449210284Sjmallett and 2 loop to each other */ 450210284Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) 451210284Sjmallett return ipd_port+1; 452210284Sjmallett else 453210284Sjmallett return -1; 454242423Sjmallett case CVMX_BOARD_TYPE_EBT5600: 455242423Sjmallett /* Board has 1 management port */ 456242423Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 457242423Sjmallett return 0; 458242423Sjmallett /* Board has 1 XAUI port connected to a switch. */ 459242423Sjmallett return -1; 460215990Sjmallett case CVMX_BOARD_TYPE_EBB5600: 461215990Sjmallett { 462215990Sjmallett static unsigned char qlm_switch_addr = 0; 463215990Sjmallett 464215990Sjmallett /* Board has 1 management port */ 465215990Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 466215990Sjmallett return 0; 467215990Sjmallett 468215990Sjmallett /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 469215990Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) 470215990Sjmallett { 471215990Sjmallett if (qlm_switch_addr != 0x3) 472215990Sjmallett { 473215990Sjmallett qlm_switch_addr = 0x3; /* QLM1 */ 474215990Sjmallett cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 475215990Sjmallett cvmx_wait_usec(11000); /* Let the write complete */ 476215990Sjmallett } 477215990Sjmallett return ipd_port+1 + (1<<8); 478215990Sjmallett } 479215990Sjmallett else if ((ipd_port >= 16) && (ipd_port < 20)) 480215990Sjmallett { 481215990Sjmallett if (qlm_switch_addr != 0xC) 482215990Sjmallett { 483215990Sjmallett qlm_switch_addr = 0xC; /* QLM3 */ 484215990Sjmallett cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 485215990Sjmallett cvmx_wait_usec(11000); /* Let the write complete */ 486215990Sjmallett } 487215990Sjmallett return ipd_port-16+1 + (1<<8); 488215990Sjmallett } 489215990Sjmallett else 490215990Sjmallett return -1; 491215990Sjmallett } 492215990Sjmallett case CVMX_BOARD_TYPE_EBB6300: 493215990Sjmallett /* Board has 2 management ports */ 494215990Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 495215990Sjmallett return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 496215990Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) 497215990Sjmallett return ipd_port + 1 + (1<<8); 498215990Sjmallett else 499215990Sjmallett return -1; 500232812Sjmallett case CVMX_BOARD_TYPE_EBB6800: 501232812Sjmallett /* Board has 1 management ports */ 502232812Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 503232812Sjmallett return 6; 504232812Sjmallett if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/ 505232812Sjmallett return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/ 506232812Sjmallett if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/ 507232812Sjmallett return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/ 508232812Sjmallett if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/ 509232812Sjmallett return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/ 510232812Sjmallett if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/ 511232812Sjmallett return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/ 512232812Sjmallett return -1; 513232812Sjmallett case CVMX_BOARD_TYPE_EP6300C: 514232812Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 515232812Sjmallett return 0x01; 516232812Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1) 517232812Sjmallett return 0x02; 518232812Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 519232812Sjmallett { 520232812Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 521232812Sjmallett int mode = cvmx_helper_interface_get_mode(interface); 522232812Sjmallett if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI) 523232812Sjmallett return ipd_port; 524232812Sjmallett else if ((ipd_port >= 0) && (ipd_port < 4)) 525232812Sjmallett return ipd_port + 3; 526232812Sjmallett else 527232812Sjmallett return -1; 528232812Sjmallett } 529232812Sjmallett#endif 530232812Sjmallett break; 531210284Sjmallett case CVMX_BOARD_TYPE_CUST_NB5: 532210284Sjmallett if (ipd_port == 2) 533210284Sjmallett return 4; 534210284Sjmallett else 535210284Sjmallett return -1; 536210284Sjmallett case CVMX_BOARD_TYPE_NIC_XLE_4G: 537210284Sjmallett /* Board has 4 SGMII ports. connected QLM3(interface 1) */ 538210284Sjmallett if ((ipd_port >= 16) && (ipd_port < 20)) 539210284Sjmallett return ipd_port - 16 + 1; 540210284Sjmallett else 541210284Sjmallett return -1; 542215990Sjmallett case CVMX_BOARD_TYPE_NIC_XLE_10G: 543232812Sjmallett case CVMX_BOARD_TYPE_NIC10E: 544215990Sjmallett return -1; /* We don't use clause 45 MDIO for anything */ 545232812Sjmallett case CVMX_BOARD_TYPE_NIC4E: 546232812Sjmallett if (ipd_port >= 0 && ipd_port <= 3) 547232812Sjmallett return (ipd_port + 0x1f) & 0x1f; 548232812Sjmallett else 549232812Sjmallett return -1; 550232812Sjmallett case CVMX_BOARD_TYPE_NIC2E: 551232812Sjmallett if (ipd_port >= 0 && ipd_port <= 1) 552232812Sjmallett return (ipd_port + 1); 553232812Sjmallett else 554232812Sjmallett return -1; 555232812Sjmallett case CVMX_BOARD_TYPE_REDWING: 556232812Sjmallett return -1; /* No PHYs connected to Octeon */ 557210284Sjmallett case CVMX_BOARD_TYPE_BBGW_REF: 558210284Sjmallett return -1; /* No PHYs are connected to Octeon, everything is through switch */ 559215990Sjmallett case CVMX_BOARD_TYPE_CUST_WSX16: 560215990Sjmallett if (ipd_port >= 0 && ipd_port <= 3) 561215990Sjmallett return ipd_port; 562215990Sjmallett else if (ipd_port >= 16 && ipd_port <= 19) 563215990Sjmallett return ipd_port - 16 + 4; 564215990Sjmallett else 565215990Sjmallett return -1; 566210311Sjmallett 567210311Sjmallett /* Private vendor-defined boards. */ 568210311Sjmallett#if defined(OCTEON_VENDOR_LANNER) 569215014Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 570215014Sjmallett /* Interface 1 is 12 BCM5482S PHYs. */ 571215014Sjmallett if ((ipd_port >= 16) && (ipd_port < 28)) 572215014Sjmallett return ipd_port - 16; 573215014Sjmallett return -1; 574215014Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 575217214Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 576217214Sjmallett return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81; 577215014Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) 578215014Sjmallett return ipd_port; 579215014Sjmallett return -1; 580210311Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 581216476Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 582213346Sjmallett /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell 583213346Sjmallett 88E1111 interfaces. */ 584210311Sjmallett switch (ipd_port) { 585210311Sjmallett case 0: 586213346Sjmallett return 16; 587210311Sjmallett case 1: 588210311Sjmallett return 1; 589210311Sjmallett case 2: 590210311Sjmallett return 2; 591210311Sjmallett default: 592210311Sjmallett return -1; 593210311Sjmallett } 594210311Sjmallett#endif 595244984Sjmallett#if defined(OCTEON_VENDOR_UBIQUITI) 596244984Sjmallett case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100: 597244984Sjmallett if (ipd_port > 2) 598244984Sjmallett return -1; 599244984Sjmallett return (7 - ipd_port); 600244984Sjmallett#endif 601242116Sjmallett#if defined(OCTEON_VENDOR_RADISYS) 602242116Sjmallett case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: 603242116Sjmallett /* No MII. */ 604242116Sjmallett return -1; 605242116Sjmallett#endif 606210284Sjmallett } 607210284Sjmallett 608210284Sjmallett /* Some unknown board. Somebody forgot to update this function... */ 609215990Sjmallett cvmx_dprintf("%s: Unknown board type %d\n", 610215990Sjmallett __FUNCTION__, cvmx_sysinfo_get()->board_type); 611210284Sjmallett return -1; 612210284Sjmallett} 613215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 614215990SjmallettEXPORT_SYMBOL(cvmx_helper_board_get_mii_address); 615215990Sjmallett#endif 616210284Sjmallett 617232812Sjmallett/** 618232812Sjmallett * @INTERNAL 619232812Sjmallett * Get link state of marvell PHY 620232812Sjmallett */ 621232812Sjmallettstatic cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr) 622232812Sjmallett{ 623232812Sjmallett cvmx_helper_link_info_t result; 624232812Sjmallett int phy_status; 625210284Sjmallett 626232812Sjmallett result.u64 = 0; 627232812Sjmallett /*All the speed information can be read from register 17 in one go.*/ 628232812Sjmallett phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 629232812Sjmallett 630232812Sjmallett /* If the resolve bit 11 isn't set, see if autoneg is turned off 631232812Sjmallett (bit 12, reg 0). The resolve bit doesn't get set properly when 632232812Sjmallett autoneg is off, so force it */ 633232812Sjmallett if ((phy_status & (1<<11)) == 0) 634232812Sjmallett { 635232812Sjmallett int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 636232812Sjmallett if ((auto_status & (1<<12)) == 0) 637232812Sjmallett phy_status |= 1<<11; 638232812Sjmallett } 639232812Sjmallett 640232812Sjmallett /* Only return a link if the PHY has finished auto negotiation 641232812Sjmallett and set the resolved bit (bit 11) */ 642232812Sjmallett if (phy_status & (1<<11)) 643232812Sjmallett { 644232812Sjmallett result.s.link_up = 1; 645232812Sjmallett result.s.full_duplex = ((phy_status>>13)&1); 646232812Sjmallett switch ((phy_status>>14)&3) 647232812Sjmallett { 648232812Sjmallett case 0: /* 10 Mbps */ 649232812Sjmallett result.s.speed = 10; 650232812Sjmallett break; 651232812Sjmallett case 1: /* 100 Mbps */ 652232812Sjmallett result.s.speed = 100; 653232812Sjmallett break; 654232812Sjmallett case 2: /* 1 Gbps */ 655232812Sjmallett result.s.speed = 1000; 656232812Sjmallett break; 657232812Sjmallett case 3: /* Illegal */ 658232812Sjmallett result.u64 = 0; 659232812Sjmallett break; 660232812Sjmallett } 661232812Sjmallett } 662232812Sjmallett return result; 663232812Sjmallett} 664232812Sjmallett 665210284Sjmallett/** 666210284Sjmallett * @INTERNAL 667232812Sjmallett * Get link state of broadcom PHY 668232812Sjmallett */ 669232812Sjmallettstatic cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr) 670232812Sjmallett{ 671232812Sjmallett cvmx_helper_link_info_t result; 672232812Sjmallett int phy_status; 673232812Sjmallett 674232812Sjmallett result.u64 = 0; 675232812Sjmallett /* Below we are going to read SMI/MDIO register 0x19 which works 676232812Sjmallett on Broadcom parts */ 677232812Sjmallett phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 678232812Sjmallett switch ((phy_status>>8) & 0x7) 679232812Sjmallett { 680232812Sjmallett case 0: 681232812Sjmallett result.u64 = 0; 682232812Sjmallett break; 683232812Sjmallett case 1: 684232812Sjmallett result.s.link_up = 1; 685232812Sjmallett result.s.full_duplex = 0; 686232812Sjmallett result.s.speed = 10; 687232812Sjmallett break; 688232812Sjmallett case 2: 689232812Sjmallett result.s.link_up = 1; 690232812Sjmallett result.s.full_duplex = 1; 691232812Sjmallett result.s.speed = 10; 692232812Sjmallett break; 693232812Sjmallett case 3: 694232812Sjmallett result.s.link_up = 1; 695232812Sjmallett result.s.full_duplex = 0; 696232812Sjmallett result.s.speed = 100; 697232812Sjmallett break; 698232812Sjmallett case 4: 699232812Sjmallett result.s.link_up = 1; 700232812Sjmallett result.s.full_duplex = 1; 701232812Sjmallett result.s.speed = 100; 702232812Sjmallett break; 703232812Sjmallett case 5: 704232812Sjmallett result.s.link_up = 1; 705232812Sjmallett result.s.full_duplex = 1; 706232812Sjmallett result.s.speed = 100; 707232812Sjmallett break; 708232812Sjmallett case 6: 709232812Sjmallett result.s.link_up = 1; 710232812Sjmallett result.s.full_duplex = 0; 711232812Sjmallett result.s.speed = 1000; 712232812Sjmallett break; 713232812Sjmallett case 7: 714232812Sjmallett result.s.link_up = 1; 715232812Sjmallett result.s.full_duplex = 1; 716232812Sjmallett result.s.speed = 1000; 717232812Sjmallett break; 718232812Sjmallett } 719232812Sjmallett return result; 720232812Sjmallett} 721232812Sjmallett 722232812Sjmallett 723232812Sjmallett/** 724232812Sjmallett * @INTERNAL 725232812Sjmallett * Get link state using inband status 726232812Sjmallett */ 727232812Sjmallettstatic cvmx_helper_link_info_t __get_inband_link_state(int ipd_port) 728232812Sjmallett{ 729232812Sjmallett cvmx_helper_link_info_t result; 730232812Sjmallett cvmx_gmxx_rxx_rx_inbnd_t inband_status; 731232812Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 732232812Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 733232812Sjmallett 734232812Sjmallett result.u64 = 0; 735232812Sjmallett inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); 736232812Sjmallett result.s.link_up = inband_status.s.status; 737232812Sjmallett result.s.full_duplex = inband_status.s.duplex; 738232812Sjmallett switch (inband_status.s.speed) 739232812Sjmallett { 740232812Sjmallett case 0: /* 10 Mbps */ 741232812Sjmallett result.s.speed = 10; 742232812Sjmallett break; 743232812Sjmallett case 1: /* 100 Mbps */ 744232812Sjmallett result.s.speed = 100; 745232812Sjmallett break; 746232812Sjmallett case 2: /* 1 Gbps */ 747232812Sjmallett result.s.speed = 1000; 748232812Sjmallett break; 749232812Sjmallett case 3: /* Illegal */ 750232812Sjmallett result.u64 = 0; 751232812Sjmallett break; 752232812Sjmallett } 753232812Sjmallett return result; 754232812Sjmallett} 755232812Sjmallett 756232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 757232812Sjmallett/** 758232812Sjmallett * @INTERNAL 759232812Sjmallett * Switch MDIO mux to the specified port. 760232812Sjmallett */ 761232812Sjmallettstatic int __switch_mdio_mux(int ipd_port) 762232812Sjmallett{ 763232812Sjmallett /* This method is board specific and doesn't use the device tree 764232812Sjmallett information as SE doesn't implement MDIO MUX abstration */ 765232812Sjmallett switch (cvmx_sysinfo_get()->board_type) 766232812Sjmallett { 767232812Sjmallett case CVMX_BOARD_TYPE_EBB5600: 768232812Sjmallett { 769232812Sjmallett static unsigned char qlm_switch_addr = 0; 770232812Sjmallett /* Board has 1 management port */ 771232812Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 772232812Sjmallett return 0; 773232812Sjmallett /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */ 774232812Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) 775232812Sjmallett { 776232812Sjmallett if (qlm_switch_addr != 0x3) 777232812Sjmallett { 778232812Sjmallett qlm_switch_addr = 0x3; /* QLM1 */ 779232812Sjmallett cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 780232812Sjmallett cvmx_wait_usec(11000); /* Let the write complete */ 781232812Sjmallett } 782232812Sjmallett return ipd_port+1 + (1<<8); 783232812Sjmallett } 784232812Sjmallett else if ((ipd_port >= 16) && (ipd_port < 20)) 785232812Sjmallett { 786232812Sjmallett if (qlm_switch_addr != 0xC) 787232812Sjmallett { 788232812Sjmallett qlm_switch_addr = 0xC; /* QLM3 */ 789232812Sjmallett cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr); 790232812Sjmallett cvmx_wait_usec(11000); /* Let the write complete */ 791232812Sjmallett } 792232812Sjmallett return ipd_port-16+1 + (1<<8); 793232812Sjmallett } 794232812Sjmallett else 795232812Sjmallett return -1; 796232812Sjmallett } 797232812Sjmallett case CVMX_BOARD_TYPE_EBB6600: 798232812Sjmallett { 799232812Sjmallett static unsigned char qlm_switch_addr = 0; 800232812Sjmallett int old_twsi_switch_reg; 801232812Sjmallett /* Board has 2 management ports */ 802232812Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 803232812Sjmallett (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 804232812Sjmallett return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 805232812Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */ 806232812Sjmallett { 807232812Sjmallett if (qlm_switch_addr != 2) 808232812Sjmallett { 809232812Sjmallett int tries; 810232812Sjmallett qlm_switch_addr = 2; 811232812Sjmallett tries = 3; 812232812Sjmallett do { 813232812Sjmallett old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0); 814232812Sjmallett } while (tries-- > 0 && old_twsi_switch_reg < 0); 815232812Sjmallett /* Set I2C MUX to enable port expander */ 816232812Sjmallett cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8); 817232812Sjmallett /* Set selecter to QLM 1 */ 818232812Sjmallett cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff); 819232812Sjmallett /* disable port expander */ 820232812Sjmallett cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg); 821232812Sjmallett } 822232812Sjmallett return 0x101 + ipd_port; 823232812Sjmallett } 824232812Sjmallett else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */ 825232812Sjmallett { 826232812Sjmallett if (qlm_switch_addr != 1) 827232812Sjmallett { 828232812Sjmallett int tries; 829232812Sjmallett qlm_switch_addr = 1; 830232812Sjmallett tries = 3; 831232812Sjmallett do { 832232812Sjmallett old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0); 833232812Sjmallett } while (tries-- > 0 && old_twsi_switch_reg < 0); 834232812Sjmallett /* Set I2C MUX to enable port expander */ 835232812Sjmallett cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8); 836232812Sjmallett /* Set selecter to QLM 2 */ 837232812Sjmallett cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7); 838232812Sjmallett /* disable port expander */ 839232812Sjmallett cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg); 840232812Sjmallett } 841232812Sjmallett return 0x101 + (ipd_port - 16); 842232812Sjmallett } else 843232812Sjmallett return -1; 844232812Sjmallett } 845232812Sjmallett case CVMX_BOARD_TYPE_EBB6100: 846232812Sjmallett { 847232812Sjmallett static char gpio_configured = 0; 848232812Sjmallett 849232812Sjmallett if (!gpio_configured) 850232812Sjmallett { 851232812Sjmallett cvmx_gpio_cfg(3, 1); 852232812Sjmallett gpio_configured = 1; 853232812Sjmallett } 854232812Sjmallett /* Board has 2 management ports */ 855232812Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && 856232812Sjmallett (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 857232812Sjmallett return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4; 858232812Sjmallett if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */ 859232812Sjmallett { 860232812Sjmallett cvmx_gpio_set(1ull << 3); 861232812Sjmallett return 0x101 + ipd_port; 862232812Sjmallett } 863232812Sjmallett else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */ 864232812Sjmallett { 865232812Sjmallett cvmx_gpio_clear(1ull << 3); 866232812Sjmallett return 0x101 + (ipd_port - 16); 867232812Sjmallett } 868232812Sjmallett else 869232812Sjmallett { 870232812Sjmallett printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port); 871232812Sjmallett return -1; 872232812Sjmallett } 873232812Sjmallett } 874232812Sjmallett default: 875232812Sjmallett { 876232812Sjmallett cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n", 877232812Sjmallett cvmx_sysinfo_get()->board_type); 878232812Sjmallett return -1; 879232812Sjmallett } 880232812Sjmallett } 881232812Sjmallett /* should never get here */ 882232812Sjmallett return -1; 883232812Sjmallett} 884232812Sjmallett 885232812Sjmallett/** 886232812Sjmallett * @INTERNAL 887232812Sjmallett * This function is used ethernet ports link speed. This functions uses the 888232812Sjmallett * device tree information to determine the phy address and type of PHY. 889232812Sjmallett * The only supproted PHYs are Marvell and Broadcom. 890232812Sjmallett * 891232812Sjmallett * @param ipd_port IPD input port associated with the port we want to get link 892232812Sjmallett * status for. 893232812Sjmallett * 894232812Sjmallett * @return The ports link status. If the link isn't fully resolved, this must 895232812Sjmallett * return zero. 896232812Sjmallett */ 897232812Sjmallett 898232812Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port) 899232812Sjmallett{ 900232812Sjmallett cvmx_helper_link_info_t result; 901232812Sjmallett cvmx_phy_info_t phy_info; 902232812Sjmallett 903232812Sjmallett result.u64 = 0; 904232812Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 905232812Sjmallett { 906232812Sjmallett /* The simulator gives you a simulated 1Gbps full duplex link */ 907232812Sjmallett result.s.link_up = 1; 908232812Sjmallett result.s.full_duplex = 1; 909232812Sjmallett result.s.speed = 1000; 910232812Sjmallett return result; 911232812Sjmallett } 912232812Sjmallett phy_info = __get_phy_info_from_dt(ipd_port); 913232812Sjmallett //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port, 914232812Sjmallett // phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type); 915232812Sjmallett if (phy_info.phy_addr < 0) return result; 916232812Sjmallett 917232812Sjmallett if (phy_info.direct_connect == 0) 918232812Sjmallett __switch_mdio_mux(ipd_port); 919232812Sjmallett switch(phy_info.phy_type) 920232812Sjmallett { 921232812Sjmallett case BROADCOM_GENERIC_PHY: 922232812Sjmallett result = __get_broadcom_phy_link_state(phy_info.phy_addr); 923232812Sjmallett break; 924232812Sjmallett case MARVELL_GENERIC_PHY: 925232812Sjmallett result = __get_marvell_phy_link_state(phy_info.phy_addr); 926232812Sjmallett break; 927232812Sjmallett default: 928232812Sjmallett result = __get_inband_link_state(ipd_port); 929232812Sjmallett } 930232812Sjmallett return result; 931232812Sjmallett 932232812Sjmallett} 933232812Sjmallett#endif 934232812Sjmallett 935232812Sjmallett/** 936232812Sjmallett * @INTERNAL 937232812Sjmallett * This function invokes __cvmx_helper_board_link_get_from_dt when device tree 938232812Sjmallett * info is available. When the device tree information is not available then 939232812Sjmallett * this function is the board specific method of determining an 940210284Sjmallett * ethernet ports link speed. Most Octeon boards have Marvell PHYs 941210284Sjmallett * and are handled by the fall through case. This function must be 942210284Sjmallett * updated for boards that don't have the normal Marvell PHYs. 943210284Sjmallett * 944210284Sjmallett * This function must be modified for every new Octeon board. 945210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo 946210284Sjmallett * data to determine board types and revisions. It relies on the 947210284Sjmallett * fact that every Octeon board receives a unique board type 948210284Sjmallett * enumeration from the bootloader. 949210284Sjmallett * 950210284Sjmallett * @param ipd_port IPD input port associated with the port we want to get link 951210284Sjmallett * status for. 952210284Sjmallett * 953210284Sjmallett * @return The ports link status. If the link isn't fully resolved, this must 954210284Sjmallett * return zero. 955210284Sjmallett */ 956210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 957210284Sjmallett{ 958210284Sjmallett cvmx_helper_link_info_t result; 959210284Sjmallett int phy_addr; 960210284Sjmallett int is_broadcom_phy = 0; 961210284Sjmallett 962232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 963232812Sjmallett if (cvmx_sysinfo_get()->fdt_addr) 964232812Sjmallett { 965232812Sjmallett return __cvmx_helper_board_link_get_from_dt(ipd_port); 966232812Sjmallett } 967232812Sjmallett#endif 968232812Sjmallett 969210284Sjmallett /* Give the user a chance to override the processing of this function */ 970210284Sjmallett if (cvmx_override_board_link_get) 971210284Sjmallett return cvmx_override_board_link_get(ipd_port); 972210284Sjmallett 973210284Sjmallett /* Unless we fix it later, all links are defaulted to down */ 974210284Sjmallett result.u64 = 0; 975210284Sjmallett 976210311Sjmallett#if !defined(OCTEON_BOARD_CAPK_0100ND) 977210284Sjmallett /* This switch statement should handle all ports that either don't use 978210284Sjmallett Marvell PHYS, or don't support in-band status */ 979210284Sjmallett switch (cvmx_sysinfo_get()->board_type) 980210284Sjmallett { 981210284Sjmallett case CVMX_BOARD_TYPE_SIM: 982210284Sjmallett /* The simulator gives you a simulated 1Gbps full duplex link */ 983210284Sjmallett result.s.link_up = 1; 984210284Sjmallett result.s.full_duplex = 1; 985210284Sjmallett result.s.speed = 1000; 986210284Sjmallett return result; 987215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_A: 988215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_U: 989215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_G: 990215990Sjmallett break; 991210284Sjmallett case CVMX_BOARD_TYPE_EBH3100: 992210284Sjmallett case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 993210284Sjmallett case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 994210284Sjmallett case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 995210284Sjmallett /* Port 1 on these boards is always Gigabit */ 996210284Sjmallett if (ipd_port == 1) 997210284Sjmallett { 998210284Sjmallett result.s.link_up = 1; 999210284Sjmallett result.s.full_duplex = 1; 1000210284Sjmallett result.s.speed = 1000; 1001210284Sjmallett return result; 1002210284Sjmallett } 1003210284Sjmallett /* Fall through to the generic code below */ 1004210284Sjmallett break; 1005242423Sjmallett case CVMX_BOARD_TYPE_EBT5600: 1006215990Sjmallett case CVMX_BOARD_TYPE_EBH5600: 1007215990Sjmallett case CVMX_BOARD_TYPE_EBH5601: 1008215990Sjmallett case CVMX_BOARD_TYPE_EBH5610: 1009215990Sjmallett /* Board has 1 management ports */ 1010215990Sjmallett if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) 1011215990Sjmallett is_broadcom_phy = 1; 1012215990Sjmallett break; 1013215990Sjmallett case CVMX_BOARD_TYPE_EBH5200: 1014215990Sjmallett case CVMX_BOARD_TYPE_EBH5201: 1015215990Sjmallett case CVMX_BOARD_TYPE_EBT5200: 1016215990Sjmallett /* Board has 2 management ports */ 1017215990Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) 1018215990Sjmallett is_broadcom_phy = 1; 1019215990Sjmallett break; 1020232812Sjmallett case CVMX_BOARD_TYPE_EBB6100: 1021215990Sjmallett case CVMX_BOARD_TYPE_EBB6300: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 1022232812Sjmallett case CVMX_BOARD_TYPE_EBB6600: /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/ 1023215990Sjmallett if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)) 1024215990Sjmallett && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1) 1025215990Sjmallett is_broadcom_phy = 1; 1026215990Sjmallett break; 1027232812Sjmallett case CVMX_BOARD_TYPE_EP6300C: 1028232812Sjmallett is_broadcom_phy = 1; 1029232812Sjmallett break; 1030210284Sjmallett case CVMX_BOARD_TYPE_CUST_NB5: 1031210284Sjmallett /* Port 1 on these boards is always Gigabit */ 1032210284Sjmallett if (ipd_port == 1) 1033210284Sjmallett { 1034210284Sjmallett result.s.link_up = 1; 1035210284Sjmallett result.s.full_duplex = 1; 1036210284Sjmallett result.s.speed = 1000; 1037210284Sjmallett return result; 1038210284Sjmallett } 1039210284Sjmallett else /* The other port uses a broadcom PHY */ 1040210284Sjmallett is_broadcom_phy = 1; 1041210284Sjmallett break; 1042210284Sjmallett case CVMX_BOARD_TYPE_BBGW_REF: 1043210284Sjmallett /* Port 1 on these boards is always Gigabit */ 1044210284Sjmallett if (ipd_port == 2) 1045215990Sjmallett { 1046210284Sjmallett /* Port 2 is not hooked up */ 1047210284Sjmallett result.u64 = 0; 1048210284Sjmallett return result; 1049210284Sjmallett } 1050210284Sjmallett else 1051210284Sjmallett { 1052210284Sjmallett /* Ports 0 and 1 connect to the switch */ 1053210284Sjmallett result.s.link_up = 1; 1054210284Sjmallett result.s.full_duplex = 1; 1055210284Sjmallett result.s.speed = 1000; 1056210284Sjmallett return result; 1057210284Sjmallett } 1058232812Sjmallett case CVMX_BOARD_TYPE_NIC4E: 1059232812Sjmallett case CVMX_BOARD_TYPE_NIC2E: 1060232812Sjmallett is_broadcom_phy = 1; 1061210284Sjmallett break; 1062210311Sjmallett /* Private vendor-defined boards. */ 1063210311Sjmallett#if defined(OCTEON_VENDOR_LANNER) 1064215014Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR730: 1065215014Sjmallett /* Ports are BCM5482S */ 1066215014Sjmallett is_broadcom_phy = 1; 1067215014Sjmallett break; 1068210311Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 1069216476Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 1070210311Sjmallett /* Port 0 connects to the switch */ 1071210311Sjmallett if (ipd_port == 0) 1072210311Sjmallett { 1073210311Sjmallett result.s.link_up = 1; 1074210311Sjmallett result.s.full_duplex = 1; 1075210311Sjmallett result.s.speed = 1000; 1076210311Sjmallett return result; 1077210311Sjmallett } 1078210311Sjmallett break; 1079210311Sjmallett#endif 1080210284Sjmallett } 1081210311Sjmallett#endif 1082210284Sjmallett 1083210284Sjmallett phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 1084232812Sjmallett //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n", 1085232812Sjmallett // ipd_port, phy_addr, is_broadcom_phy); 1086210284Sjmallett if (phy_addr != -1) 1087210284Sjmallett { 1088210284Sjmallett if (is_broadcom_phy) 1089210284Sjmallett { 1090232812Sjmallett result = __get_broadcom_phy_link_state(phy_addr); 1091210284Sjmallett } 1092210284Sjmallett else 1093210284Sjmallett { 1094232812Sjmallett /* This code assumes we are using a Marvell Gigabit PHY. */ 1095232812Sjmallett result = __get_marvell_phy_link_state(phy_addr); 1096210284Sjmallett } 1097210284Sjmallett } 1098232812Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) 1099232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CN50XX)) 1100210284Sjmallett { 1101210284Sjmallett /* We don't have a PHY address, so attempt to use in-band status. It is 1102210284Sjmallett really important that boards not supporting in-band status never get 1103210284Sjmallett here. Reading broken in-band status tends to do bad things */ 1104232812Sjmallett result = __get_inband_link_state(ipd_port); 1105210284Sjmallett } 1106210284Sjmallett else 1107210284Sjmallett { 1108210284Sjmallett /* We don't have a PHY address and we don't have in-band status. There 1109210284Sjmallett is no way to determine the link speed. Return down assuming this 1110210284Sjmallett port isn't wired */ 1111210284Sjmallett result.u64 = 0; 1112210284Sjmallett } 1113210284Sjmallett 1114210284Sjmallett /* If link is down, return all fields as zero. */ 1115210284Sjmallett if (!result.s.link_up) 1116210284Sjmallett result.u64 = 0; 1117210284Sjmallett 1118210284Sjmallett return result; 1119210284Sjmallett} 1120210284Sjmallett 1121210284Sjmallett 1122210284Sjmallett/** 1123210284Sjmallett * This function as a board specific method of changing the PHY 1124215990Sjmallett * speed, duplex, and autonegotiation. This programs the PHY and 1125210284Sjmallett * not Octeon. This can be used to force Octeon's links to 1126210284Sjmallett * specific settings. 1127210284Sjmallett * 1128210284Sjmallett * @param phy_addr The address of the PHY to program 1129215990Sjmallett * @param link_flags 1130215990Sjmallett * Flags to control autonegotiation. Bit 0 is autonegotiation 1131215990Sjmallett * enable/disable to maintain backward compatibility. 1132215990Sjmallett * @param link_info Link speed to program. If the speed is zero and autonegotiation 1133210284Sjmallett * is enabled, all possible negotiation speeds are advertised. 1134210284Sjmallett * 1135210284Sjmallett * @return Zero on success, negative on failure 1136210284Sjmallett */ 1137210284Sjmallettint cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags, 1138210284Sjmallett cvmx_helper_link_info_t link_info) 1139210284Sjmallett{ 1140210284Sjmallett 1141210284Sjmallett /* Set the flow control settings based on link_flags */ 1142210284Sjmallett if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch) 1143210284Sjmallett { 1144210284Sjmallett cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1145210284Sjmallett reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1146210284Sjmallett reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 1147210284Sjmallett reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable; 1148210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1149210284Sjmallett } 1150210284Sjmallett 1151210284Sjmallett /* If speed isn't set and autoneg is on advertise all supported modes */ 1152210284Sjmallett if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0)) 1153210284Sjmallett { 1154210284Sjmallett cvmx_mdio_phy_reg_control_t reg_control; 1155210284Sjmallett cvmx_mdio_phy_reg_status_t reg_status; 1156210284Sjmallett cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1157210284Sjmallett cvmx_mdio_phy_reg_extended_status_t reg_extended_status; 1158210284Sjmallett cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 1159210284Sjmallett 1160210284Sjmallett reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 1161210284Sjmallett reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1162210284Sjmallett reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4; 1163210284Sjmallett reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full; 1164210284Sjmallett reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half; 1165210284Sjmallett reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full; 1166210284Sjmallett reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half; 1167210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1168210284Sjmallett if (reg_status.s.capable_extended_status) 1169210284Sjmallett { 1170210284Sjmallett reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS); 1171210284Sjmallett reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 1172210284Sjmallett reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full; 1173210284Sjmallett reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half; 1174210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 1175210284Sjmallett } 1176210284Sjmallett reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1177210284Sjmallett reg_control.s.autoneg_enable = 1; 1178210284Sjmallett reg_control.s.restart_autoneg = 1; 1179210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1180210284Sjmallett } 1181210284Sjmallett else if ((link_flags & set_phy_link_flags_autoneg)) 1182210284Sjmallett { 1183210284Sjmallett cvmx_mdio_phy_reg_control_t reg_control; 1184210284Sjmallett cvmx_mdio_phy_reg_status_t reg_status; 1185210284Sjmallett cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; 1186210284Sjmallett cvmx_mdio_phy_reg_control_1000_t reg_control_1000; 1187210284Sjmallett 1188210284Sjmallett reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 1189210284Sjmallett reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER); 1190210284Sjmallett reg_autoneg_adver.s.advert_100base_t4 = 0; 1191210284Sjmallett reg_autoneg_adver.s.advert_10base_tx_full = 0; 1192210284Sjmallett reg_autoneg_adver.s.advert_10base_tx_half = 0; 1193210284Sjmallett reg_autoneg_adver.s.advert_100base_tx_full = 0; 1194210284Sjmallett reg_autoneg_adver.s.advert_100base_tx_half = 0; 1195210284Sjmallett if (reg_status.s.capable_extended_status) 1196210284Sjmallett { 1197210284Sjmallett reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); 1198210284Sjmallett reg_control_1000.s.advert_1000base_t_full = 0; 1199210284Sjmallett reg_control_1000.s.advert_1000base_t_half = 0; 1200210284Sjmallett } 1201210284Sjmallett switch (link_info.s.speed) 1202210284Sjmallett { 1203210284Sjmallett case 10: 1204210284Sjmallett reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex; 1205210284Sjmallett reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex; 1206210284Sjmallett break; 1207210284Sjmallett case 100: 1208210284Sjmallett reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex; 1209210284Sjmallett reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex; 1210210284Sjmallett break; 1211210284Sjmallett case 1000: 1212210284Sjmallett reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex; 1213210284Sjmallett reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex; 1214210284Sjmallett break; 1215210284Sjmallett } 1216210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16); 1217210284Sjmallett if (reg_status.s.capable_extended_status) 1218210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16); 1219210284Sjmallett reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1220210284Sjmallett reg_control.s.autoneg_enable = 1; 1221210284Sjmallett reg_control.s.restart_autoneg = 1; 1222210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1223210284Sjmallett } 1224210284Sjmallett else 1225210284Sjmallett { 1226210284Sjmallett cvmx_mdio_phy_reg_control_t reg_control; 1227210284Sjmallett reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL); 1228210284Sjmallett reg_control.s.autoneg_enable = 0; 1229210284Sjmallett reg_control.s.restart_autoneg = 1; 1230210284Sjmallett reg_control.s.duplex = link_info.s.full_duplex; 1231210284Sjmallett if (link_info.s.speed == 1000) 1232210284Sjmallett { 1233210284Sjmallett reg_control.s.speed_msb = 1; 1234210284Sjmallett reg_control.s.speed_lsb = 0; 1235210284Sjmallett } 1236210284Sjmallett else if (link_info.s.speed == 100) 1237210284Sjmallett { 1238210284Sjmallett reg_control.s.speed_msb = 0; 1239210284Sjmallett reg_control.s.speed_lsb = 1; 1240210284Sjmallett } 1241210284Sjmallett else if (link_info.s.speed == 10) 1242210284Sjmallett { 1243210284Sjmallett reg_control.s.speed_msb = 0; 1244210284Sjmallett reg_control.s.speed_lsb = 0; 1245210284Sjmallett } 1246210284Sjmallett cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); 1247210284Sjmallett } 1248210284Sjmallett return 0; 1249210284Sjmallett} 1250210284Sjmallett 1251210284Sjmallett 1252210284Sjmallett/** 1253210284Sjmallett * @INTERNAL 1254210284Sjmallett * This function is called by cvmx_helper_interface_probe() after it 1255210284Sjmallett * determines the number of ports Octeon can support on a specific 1256210284Sjmallett * interface. This function is the per board location to override 1257210284Sjmallett * this value. It is called with the number of ports Octeon might 1258210284Sjmallett * support and should return the number of actual ports on the 1259210284Sjmallett * board. 1260210284Sjmallett * 1261215990Sjmallett * This function must be modified for every new Octeon board. 1262210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo 1263215990Sjmallett * data to determine board types and revisions. It relies on the 1264210284Sjmallett * fact that every Octeon board receives a unique board type 1265210284Sjmallett * enumeration from the bootloader. 1266210284Sjmallett * 1267210284Sjmallett * @param interface Interface to probe 1268210284Sjmallett * @param supported_ports 1269210284Sjmallett * Number of ports Octeon supports. 1270210284Sjmallett * 1271210284Sjmallett * @return Number of ports the actual board supports. Many times this will 1272210284Sjmallett * simple be "support_ports". 1273210284Sjmallett */ 1274210284Sjmallettint __cvmx_helper_board_interface_probe(int interface, int supported_ports) 1275210284Sjmallett{ 1276210284Sjmallett switch (cvmx_sysinfo_get()->board_type) 1277210284Sjmallett { 1278210284Sjmallett case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 1279215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_A: 1280215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_U: 1281215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_G: 1282210284Sjmallett if (interface == 0) 1283210284Sjmallett return 2; 1284210284Sjmallett break; 1285210284Sjmallett case CVMX_BOARD_TYPE_BBGW_REF: 1286210284Sjmallett if (interface == 0) 1287210284Sjmallett return 2; 1288210284Sjmallett break; 1289210284Sjmallett case CVMX_BOARD_TYPE_NIC_XLE_4G: 1290210284Sjmallett if (interface == 0) 1291210284Sjmallett return 0; 1292210284Sjmallett break; 1293210284Sjmallett /* The 2nd interface on the EBH5600 is connected to the Marvel switch, 1294210284Sjmallett which we don't support. Disable ports connected to it */ 1295210284Sjmallett case CVMX_BOARD_TYPE_EBH5600: 1296210284Sjmallett if (interface == 1) 1297210284Sjmallett return 0; 1298210284Sjmallett break; 1299215990Sjmallett case CVMX_BOARD_TYPE_EBB5600: 1300215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 1301215990Sjmallett if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG) 1302215990Sjmallett return 0; 1303215990Sjmallett#endif 1304215990Sjmallett break; 1305242423Sjmallett case CVMX_BOARD_TYPE_EBT5600: 1306242423Sjmallett /* Disable loopback. */ 1307242423Sjmallett if (interface == 3) 1308242423Sjmallett return 0; 1309242423Sjmallett break; 1310215990Sjmallett case CVMX_BOARD_TYPE_EBT5810: 1311215990Sjmallett return 1; /* Two ports on each SPI: 1 hooked to MAC, 1 loopback 1312215990Sjmallett ** Loopback disabled by default. */ 1313232812Sjmallett case CVMX_BOARD_TYPE_NIC2E: 1314232812Sjmallett if (interface == 0) 1315232812Sjmallett return 2; 1316212844Sjmallett#if defined(OCTEON_VENDOR_LANNER) 1317212844Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 1318212844Sjmallett if (interface == 1) 1319212844Sjmallett return 12; 1320212844Sjmallett break; 1321212844Sjmallett#endif 1322210284Sjmallett } 1323210284Sjmallett#ifdef CVMX_BUILD_FOR_UBOOT 1324210284Sjmallett if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) 1325210284Sjmallett return 0; 1326210284Sjmallett#endif 1327210284Sjmallett return supported_ports; 1328210284Sjmallett} 1329210284Sjmallett 1330210284Sjmallett 1331210284Sjmallett/** 1332210284Sjmallett * @INTERNAL 1333210284Sjmallett * Enable packet input/output from the hardware. This function is 1334210284Sjmallett * called after by cvmx_helper_packet_hardware_enable() to 1335210284Sjmallett * perform board specific initialization. For most boards 1336210284Sjmallett * nothing is needed. 1337210284Sjmallett * 1338210284Sjmallett * @param interface Interface to enable 1339210284Sjmallett * 1340210284Sjmallett * @return Zero on success, negative on failure 1341210284Sjmallett */ 1342210284Sjmallettint __cvmx_helper_board_hardware_enable(int interface) 1343210284Sjmallett{ 1344210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) 1345210284Sjmallett { 1346210284Sjmallett if (interface == 0) 1347210284Sjmallett { 1348210284Sjmallett /* Different config for switch port */ 1349210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); 1350210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); 1351210284Sjmallett /* Boards with gigabit WAN ports need a different setting that is 1352210284Sjmallett compatible with 100 Mbit settings */ 1353210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc); 1354210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc); 1355210284Sjmallett } 1356210284Sjmallett } 1357215990Sjmallett else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U) 1358215990Sjmallett { 1359215990Sjmallett if (interface == 0) 1360215990Sjmallett { 1361215990Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16); 1362215990Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16); 1363215990Sjmallett } 1364215990Sjmallett } 1365210284Sjmallett else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5) 1366210284Sjmallett { 1367215990Sjmallett /* Broadcom PHYs require different ASX clocks. Unfortunately 1368210284Sjmallett many customer don't define a new board Id and simply 1369210284Sjmallett mangle the CN3010_EVB_HS5 */ 1370210284Sjmallett if (interface == 0) 1371210284Sjmallett { 1372210284Sjmallett /* Some customers boards use a hacked up bootloader that identifies them as 1373210284Sjmallett ** CN3010_EVB_HS5 evaluation boards. This leads to all kinds of configuration 1374210284Sjmallett ** problems. Detect one case, and print warning, while trying to do the right thing. 1375210284Sjmallett */ 1376210284Sjmallett int phy_addr = cvmx_helper_board_get_mii_address(0); 1377210284Sjmallett if (phy_addr != -1) 1378210284Sjmallett { 1379210284Sjmallett int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2); 1380210284Sjmallett /* Is it a Broadcom PHY? */ 1381210284Sjmallett if (phy_identifier == 0x0143) 1382210284Sjmallett { 1383210284Sjmallett cvmx_dprintf("\n"); 1384210284Sjmallett cvmx_dprintf("ERROR:\n"); 1385210284Sjmallett cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); 1386210284Sjmallett cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); 1387210284Sjmallett cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n"); 1388210284Sjmallett cvmx_dprintf("ERROR:\n"); 1389210284Sjmallett cvmx_dprintf("\n"); 1390210284Sjmallett cvmx_wait(1000000000); 1391210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5); 1392210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5); 1393210284Sjmallett } 1394210284Sjmallett } 1395210284Sjmallett } 1396210284Sjmallett } 1397210284Sjmallett return 0; 1398210284Sjmallett} 1399210284Sjmallett 1400215990Sjmallett 1401215990Sjmallett/** 1402215990Sjmallett * @INTERNAL 1403215990Sjmallett * Gets the clock type used for the USB block based on board type. 1404215990Sjmallett * Used by the USB code for auto configuration of clock type. 1405215990Sjmallett * 1406215990Sjmallett * @return USB clock type enumeration 1407215990Sjmallett */ 1408210284Sjmallettcvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) 1409210284Sjmallett{ 1410232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL)) 1411232812Sjmallett const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr); 1412232812Sjmallett int nodeoffset; 1413232812Sjmallett const void *nodep; 1414232812Sjmallett int len; 1415232812Sjmallett uint32_t speed = 0; 1416232812Sjmallett const char *type = NULL; 1417232812Sjmallett 1418232812Sjmallett if (fdt_addr) 1419232812Sjmallett { 1420232812Sjmallett nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl"); 1421232812Sjmallett if (nodeoffset < 0) 1422232812Sjmallett nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn"); 1423232812Sjmallett 1424232812Sjmallett if (nodeoffset >= 0) 1425232812Sjmallett { 1426232812Sjmallett nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len); 1427232812Sjmallett if (nodep != NULL && len > 0) 1428232812Sjmallett type = (const char *)nodep; 1429232812Sjmallett else 1430232812Sjmallett type = "unknown"; 1431232812Sjmallett nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len); 1432232812Sjmallett if (nodep != NULL && len == sizeof(uint32_t)) 1433232812Sjmallett speed = fdt32_to_cpu(*(int *)nodep); 1434232812Sjmallett else 1435232812Sjmallett speed = 0; 1436232812Sjmallett if (!strcmp(type, "crystal")) 1437232812Sjmallett { 1438232812Sjmallett if (speed == 0 || speed == 12000000) 1439232812Sjmallett return USB_CLOCK_TYPE_CRYSTAL_12; 1440232812Sjmallett else 1441232812Sjmallett printf("Warning: invalid crystal speed for USB clock type in FDT\n"); 1442232812Sjmallett } 1443232812Sjmallett else if (!strcmp(type, "external")) 1444232812Sjmallett { 1445232812Sjmallett switch (speed) { 1446232812Sjmallett case 12000000: 1447232812Sjmallett return USB_CLOCK_TYPE_REF_12; 1448232812Sjmallett case 24000000: 1449232812Sjmallett return USB_CLOCK_TYPE_REF_24; 1450232812Sjmallett case 0: 1451232812Sjmallett case 48000000: 1452232812Sjmallett return USB_CLOCK_TYPE_REF_48; 1453232812Sjmallett default: 1454232812Sjmallett printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed); 1455232812Sjmallett } 1456232812Sjmallett } 1457232812Sjmallett else 1458232812Sjmallett printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL"); 1459232812Sjmallett } 1460232812Sjmallett } 1461232812Sjmallett#endif 1462215990Sjmallett switch (cvmx_sysinfo_get()->board_type) 1463215990Sjmallett { 1464215990Sjmallett case CVMX_BOARD_TYPE_BBGW_REF: 1465215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_A: 1466215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_U: 1467215990Sjmallett case CVMX_BOARD_TYPE_LANAI2_G: 1468210311Sjmallett#if defined(OCTEON_VENDOR_LANNER) 1469210311Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 1470216476Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 1471210311Sjmallett#endif 1472229070Sgonzo#if defined(OCTEON_BOARD_CAPK_0100ND) 1473229070Sgonzo case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 1474229070Sgonzo#endif 1475232812Sjmallett case CVMX_BOARD_TYPE_NIC10E_66: 1476210284Sjmallett return USB_CLOCK_TYPE_CRYSTAL_12; 1477232812Sjmallett case CVMX_BOARD_TYPE_NIC10E: 1478232812Sjmallett return USB_CLOCK_TYPE_REF_12; 1479232812Sjmallett default: 1480232812Sjmallett break; 1481210284Sjmallett } 1482232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX) /* Most boards except NIC10e use a 12MHz crystal */ 1483232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) 1484232812Sjmallett return USB_CLOCK_TYPE_CRYSTAL_12; 1485210284Sjmallett return USB_CLOCK_TYPE_REF_48; 1486210284Sjmallett} 1487210284Sjmallett 1488215990Sjmallett 1489215990Sjmallett/** 1490215990Sjmallett * @INTERNAL 1491215990Sjmallett * Adjusts the number of available USB ports on Octeon based on board 1492215990Sjmallett * specifics. 1493215990Sjmallett * 1494215990Sjmallett * @param supported_ports expected number of ports based on chip type; 1495215990Sjmallett * 1496215990Sjmallett * 1497215990Sjmallett * @return number of available usb ports, based on board specifics. 1498215990Sjmallett * Return value is supported_ports if function does not 1499215990Sjmallett * override. 1500215990Sjmallett */ 1501210284Sjmallettint __cvmx_helper_board_usb_get_num_ports(int supported_ports) 1502210284Sjmallett{ 1503215990Sjmallett switch (cvmx_sysinfo_get()->board_type) 1504215990Sjmallett { 1505210284Sjmallett case CVMX_BOARD_TYPE_NIC_XLE_4G: 1506232812Sjmallett case CVMX_BOARD_TYPE_NIC2E: 1507210284Sjmallett return 0; 1508210284Sjmallett } 1509210284Sjmallett 1510210284Sjmallett return supported_ports; 1511210284Sjmallett} 1512210284Sjmallett 1513210284Sjmallett 1514