1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 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 * Functions for SGMII initialization, configuration, 50210284Sjmallett * and monitoring. 51210284Sjmallett * 52232812Sjmallett * <hr>$Revision: 70030 $<hr> 53210284Sjmallett */ 54215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 55215990Sjmallett#include <asm/octeon/cvmx.h> 56215990Sjmallett#include <asm/octeon/cvmx-config.h> 57215990Sjmallett#include <asm/octeon/cvmx-clock.h> 58232812Sjmallett#include <asm/octeon/cvmx-qlm.h> 59215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 60215990Sjmallett#include <asm/octeon/cvmx-helper.h> 61215990Sjmallett#include <asm/octeon/cvmx-helper-board.h> 62232812Sjmallett#include <asm/octeon/cvmx-helper-cfg.h> 63215990Sjmallett#endif 64215990Sjmallett#include <asm/octeon/cvmx-pcsx-defs.h> 65215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h> 66215990Sjmallett#include <asm/octeon/cvmx-ciu-defs.h> 67215990Sjmallett#else 68215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 69215990Sjmallett#include "executive-config.h" 70215990Sjmallett#include "cvmx-config.h" 71215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 72215990Sjmallett 73210284Sjmallett#include "cvmx.h" 74210284Sjmallett#include "cvmx-sysinfo.h" 75210284Sjmallett#include "cvmx-mdio.h" 76210284Sjmallett#include "cvmx-helper.h" 77210284Sjmallett#include "cvmx-helper-board.h" 78232812Sjmallett#include "cvmx-helper-cfg.h" 79232812Sjmallett#include "cvmx-qlm.h" 80215990Sjmallett#endif 81215990Sjmallett#else 82215990Sjmallett#include "cvmx.h" 83215990Sjmallett#include "cvmx-sysinfo.h" 84215990Sjmallett#include "cvmx-mdio.h" 85215990Sjmallett#include "cvmx-helper.h" 86215990Sjmallett#include "cvmx-helper-board.h" 87232812Sjmallett#include "cvmx-qlm.h" 88215990Sjmallett#endif 89215990Sjmallett#endif 90210284Sjmallett 91210311Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 92215990Sjmallett 93210284Sjmallett/** 94210284Sjmallett * @INTERNAL 95210284Sjmallett * Perform initialization required only once for an SGMII port. 96210284Sjmallett * 97210284Sjmallett * @param interface Interface to init 98210284Sjmallett * @param index Index of prot on the interface 99210284Sjmallett * 100210284Sjmallett * @return Zero on success, negative on failure 101210284Sjmallett */ 102210284Sjmallettstatic int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index) 103210284Sjmallett{ 104215990Sjmallett const uint64_t clock_mhz = cvmx_clock_get_rate(CVMX_CLOCK_SCLK) / 1000000; 105215990Sjmallett cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg; 106210284Sjmallett cvmx_pcsx_linkx_timer_count_reg_t pcsx_linkx_timer_count_reg; 107210284Sjmallett cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg; 108210284Sjmallett 109210284Sjmallett /* Disable GMX */ 110210284Sjmallett gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 111210284Sjmallett gmxx_prtx_cfg.s.en = 0; 112210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); 113210284Sjmallett 114210284Sjmallett /* Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the appropriate 115210284Sjmallett value. 1000BASE-X specifies a 10ms interval. SGMII specifies a 1.6ms 116210284Sjmallett interval. */ 117215990Sjmallett pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 118210284Sjmallett pcsx_linkx_timer_count_reg.u64 = cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface)); 119250428Simp if (pcsx_miscx_ctl_reg.s.mode 120250428Simp#if defined(OCTEON_VENDOR_GEFES) 121250428Simp /* GEF Fiber SFP testing on W5650 showed this to cause link issues for 1000BASE-X*/ 122250428Simp && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CUST_W5650) 123250428Simp && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CUST_W63XX) 124250428Simp#endif 125250428Simp ) 126210284Sjmallett { 127210284Sjmallett /* 1000BASE-X */ 128210284Sjmallett pcsx_linkx_timer_count_reg.s.count = (10000ull * clock_mhz) >> 10; 129210284Sjmallett } 130210284Sjmallett else 131210284Sjmallett { 132210284Sjmallett /* SGMII */ 133210284Sjmallett pcsx_linkx_timer_count_reg.s.count = (1600ull * clock_mhz) >> 10; 134210284Sjmallett } 135210284Sjmallett cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface), pcsx_linkx_timer_count_reg.u64); 136210284Sjmallett 137210284Sjmallett /* Write the advertisement register to be used as the 138210284Sjmallett tx_Config_Reg<D15:D0> of the autonegotiation. 139210284Sjmallett In 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG. 140210284Sjmallett In SGMII PHY mode, tx_Config_Reg<D15:D0> is PCS*_SGM*_AN_ADV_REG. 141210284Sjmallett In SGMII MAC mode, tx_Config_Reg<D15:D0> is the fixed value 0x4001, so 142210284Sjmallett this step can be skipped. */ 143215990Sjmallett if (pcsx_miscx_ctl_reg.s.mode) 144210284Sjmallett { 145210284Sjmallett /* 1000BASE-X */ 146210284Sjmallett cvmx_pcsx_anx_adv_reg_t pcsx_anx_adv_reg; 147210284Sjmallett pcsx_anx_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface)); 148210284Sjmallett pcsx_anx_adv_reg.s.rem_flt = 0; 149210284Sjmallett pcsx_anx_adv_reg.s.pause = 3; 150210284Sjmallett pcsx_anx_adv_reg.s.hfd = 1; 151210284Sjmallett pcsx_anx_adv_reg.s.fd = 1; 152210284Sjmallett cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface), pcsx_anx_adv_reg.u64); 153210284Sjmallett } 154210284Sjmallett else 155210284Sjmallett { 156232812Sjmallett#ifdef CVMX_HELPER_CONFIG_NO_PHY 157232812Sjmallett /* If the interface does not have PHY, then set explicitly in PHY mode 158232812Sjmallett so that link will be set during auto negotiation. */ 159232812Sjmallett if (!pcsx_miscx_ctl_reg.s.mac_phy) 160232812Sjmallett { 161232812Sjmallett cvmx_dprintf("SGMII%d%d: Forcing PHY mode as PHY address is not set\n", interface, index); 162232812Sjmallett pcsx_miscx_ctl_reg.s.mac_phy = 1; 163232812Sjmallett cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64); 164232812Sjmallett } 165232812Sjmallett#endif 166210284Sjmallett if (pcsx_miscx_ctl_reg.s.mac_phy) 167210284Sjmallett { 168210284Sjmallett /* PHY Mode */ 169210284Sjmallett cvmx_pcsx_sgmx_an_adv_reg_t pcsx_sgmx_an_adv_reg; 170210284Sjmallett pcsx_sgmx_an_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface)); 171210284Sjmallett pcsx_sgmx_an_adv_reg.s.dup = 1; 172210284Sjmallett pcsx_sgmx_an_adv_reg.s.speed= 2; 173210284Sjmallett cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface), pcsx_sgmx_an_adv_reg.u64); 174210284Sjmallett } 175210284Sjmallett else 176210284Sjmallett { 177210284Sjmallett /* MAC Mode - Nothing to do */ 178210284Sjmallett } 179210284Sjmallett } 180210284Sjmallett return 0; 181210284Sjmallett} 182210284Sjmallett 183232812Sjmallettstatic int __cvmx_helper_need_g15618(void) 184232812Sjmallett{ 185232812Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM 186232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) 187232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) 188232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1) 189232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X) 190232812Sjmallett || OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X)) 191232812Sjmallett return 1; 192232812Sjmallett else 193232812Sjmallett return 0; 194232812Sjmallett } 195210284Sjmallett 196210284Sjmallett/** 197210284Sjmallett * @INTERNAL 198210284Sjmallett * Initialize the SERTES link for the first time or after a loss 199210284Sjmallett * of link. 200210284Sjmallett * 201210284Sjmallett * @param interface Interface to init 202210284Sjmallett * @param index Index of prot on the interface 203210284Sjmallett * 204210284Sjmallett * @return Zero on success, negative on failure 205210284Sjmallett */ 206210284Sjmallettstatic int __cvmx_helper_sgmii_hardware_init_link(int interface, int index) 207210284Sjmallett{ 208210284Sjmallett cvmx_pcsx_mrx_control_reg_t control_reg; 209250428Simp uint64_t link_timeout; 210210284Sjmallett 211250428Simp#if defined(OCTEON_VENDOR_GEFES) 212250428Simp if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_TNPA5651X) { 213250428Simp return 0; /* no auto-negotiation */ 214250428Simp } 215250428Simp#endif 216250428Simp 217250428Simp 218210284Sjmallett /* Take PCS through a reset sequence. 219210284Sjmallett PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero. 220210284Sjmallett Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the value of 221210284Sjmallett the other PCS*_MR*_CONTROL_REG bits). 222210284Sjmallett Read PCS*_MR*_CONTROL_REG[RESET] until it changes value to zero. */ 223210284Sjmallett control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); 224232812Sjmallett 225232812Sjmallett /* Errata G-15618 requires disabling PCS soft reset in CN63XX pass upto 2.1. */ 226232812Sjmallett if (!__cvmx_helper_need_g15618()) 227210284Sjmallett { 228250428Simp link_timeout = 200000; 229250428Simp#if defined(OCTEON_VENDOR_GEFES) 230250428Simp if( (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_TNPA56X4) && (interface == 0) ) 231250428Simp { 232250428Simp link_timeout = 5000000; 233250428Simp } 234250428Simp#endif 235210284Sjmallett control_reg.s.reset = 1; 236210284Sjmallett cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64); 237250428Simp if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_CONTROL_REG(index, interface), cvmx_pcsx_mrx_control_reg_t, reset, ==, 0, link_timeout)) 238210284Sjmallett { 239210284Sjmallett cvmx_dprintf("SGMII%d: Timeout waiting for port %d to finish reset\n", interface, index); 240210284Sjmallett return -1; 241210284Sjmallett } 242210284Sjmallett } 243210284Sjmallett 244210284Sjmallett /* Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh sgmii negotiation starts. */ 245210284Sjmallett control_reg.s.rst_an = 1; 246210284Sjmallett control_reg.s.an_en = 1; 247210284Sjmallett control_reg.s.pwr_dn = 0; 248210284Sjmallett cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64); 249210284Sjmallett 250210284Sjmallett /* Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating that 251210284Sjmallett sgmii autonegotiation is complete. In MAC mode this isn't an ethernet 252210284Sjmallett link, but a link between Octeon and the PHY */ 253210284Sjmallett if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && 254210284Sjmallett CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface), cvmx_pcsx_mrx_status_reg_t, an_cpt, ==, 1, 10000)) 255210284Sjmallett { 256210284Sjmallett //cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); 257210284Sjmallett return -1; 258210284Sjmallett } 259210284Sjmallett return 0; 260210284Sjmallett} 261210284Sjmallett 262210284Sjmallett 263210284Sjmallett/** 264210284Sjmallett * @INTERNAL 265210284Sjmallett * Configure an SGMII link to the specified speed after the SERTES 266210284Sjmallett * link is up. 267210284Sjmallett * 268210284Sjmallett * @param interface Interface to init 269210284Sjmallett * @param index Index of prot on the interface 270210284Sjmallett * @param link_info Link state to configure 271210284Sjmallett * 272210284Sjmallett * @return Zero on success, negative on failure 273210284Sjmallett */ 274210284Sjmallettstatic int __cvmx_helper_sgmii_hardware_init_link_speed(int interface, int index, cvmx_helper_link_info_t link_info) 275210284Sjmallett{ 276210284Sjmallett int is_enabled; 277210284Sjmallett cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg; 278210284Sjmallett cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg; 279210284Sjmallett 280250428Simp#if defined(OCTEON_VENDOR_GEFES) 281250428Simp if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_TNPA5651X) 282250428Simp return 0; /* no auto-negotiation */ 283250428Simp#endif 284250428Simp 285210284Sjmallett /* Disable GMX before we make any changes. Remember the enable state */ 286210284Sjmallett gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 287210284Sjmallett is_enabled = gmxx_prtx_cfg.s.en; 288210284Sjmallett gmxx_prtx_cfg.s.en = 0; 289210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); 290210284Sjmallett 291210284Sjmallett /* Wait for GMX to be idle */ 292210284Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000) || 293210284Sjmallett CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000)) 294210284Sjmallett { 295210284Sjmallett cvmx_dprintf("SGMII%d: Timeout waiting for port %d to be idle\n", interface, index); 296210284Sjmallett return -1; 297210284Sjmallett } 298210284Sjmallett 299210284Sjmallett /* Read GMX CFG again to make sure the disable completed */ 300210284Sjmallett gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 301210284Sjmallett 302210284Sjmallett /* Get the misc control for PCS. We will need to set the duplication amount */ 303210284Sjmallett pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 304210284Sjmallett 305210284Sjmallett /* Use GMXENO to force the link down if the status we get says it should be down */ 306210284Sjmallett pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up; 307210284Sjmallett 308210284Sjmallett /* Only change the duplex setting if the link is up */ 309210284Sjmallett if (link_info.s.link_up) 310210284Sjmallett gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex; 311210284Sjmallett 312210284Sjmallett /* Do speed based setting for GMX */ 313210284Sjmallett switch (link_info.s.speed) 314210284Sjmallett { 315210284Sjmallett case 10: 316210284Sjmallett gmxx_prtx_cfg.s.speed = 0; 317210284Sjmallett gmxx_prtx_cfg.s.speed_msb = 1; 318210284Sjmallett gmxx_prtx_cfg.s.slottime = 0; 319210284Sjmallett pcsx_miscx_ctl_reg.s.samp_pt = 25; /* Setting from GMX-603 */ 320210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64); 321210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 322210284Sjmallett break; 323210284Sjmallett case 100: 324210284Sjmallett gmxx_prtx_cfg.s.speed = 0; 325210284Sjmallett gmxx_prtx_cfg.s.speed_msb = 0; 326210284Sjmallett gmxx_prtx_cfg.s.slottime = 0; 327210284Sjmallett pcsx_miscx_ctl_reg.s.samp_pt = 0x5; 328210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64); 329210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 330210284Sjmallett break; 331210284Sjmallett case 1000: 332210284Sjmallett gmxx_prtx_cfg.s.speed = 1; 333210284Sjmallett gmxx_prtx_cfg.s.speed_msb = 0; 334210284Sjmallett gmxx_prtx_cfg.s.slottime = 1; 335210284Sjmallett pcsx_miscx_ctl_reg.s.samp_pt = 1; 336210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512); 337215990Sjmallett if (gmxx_prtx_cfg.s.duplex) 338215990Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); // full duplex 339215990Sjmallett else 340215990Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192); // half duplex 341210284Sjmallett break; 342210284Sjmallett default: 343210284Sjmallett break; 344210284Sjmallett } 345210284Sjmallett 346210284Sjmallett /* Write the new misc control for PCS */ 347210284Sjmallett cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64); 348210284Sjmallett 349210284Sjmallett /* Write the new GMX settings with the port still disabled */ 350210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); 351210284Sjmallett 352210284Sjmallett /* Read GMX CFG again to make sure the config completed */ 353210284Sjmallett gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 354210284Sjmallett 355210284Sjmallett /* Restore the enabled / disabled state */ 356210284Sjmallett gmxx_prtx_cfg.s.en = is_enabled; 357210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); 358210284Sjmallett 359210284Sjmallett return 0; 360210284Sjmallett} 361210284Sjmallett 362210284Sjmallett 363210284Sjmallett/** 364210284Sjmallett * @INTERNAL 365210284Sjmallett * Bring up the SGMII interface to be ready for packet I/O but 366210284Sjmallett * leave I/O disabled using the GMX override. This function 367210284Sjmallett * follows the bringup documented in 10.6.3 of the manual. 368210284Sjmallett * 369210284Sjmallett * @param interface Interface to bringup 370210284Sjmallett * @param num_ports Number of ports on the interface 371210284Sjmallett * 372210284Sjmallett * @return Zero on success, negative on failure 373210284Sjmallett */ 374210284Sjmallettstatic int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports) 375210284Sjmallett{ 376210284Sjmallett int index; 377232812Sjmallett int do_link_set = 1; 378210284Sjmallett 379215990Sjmallett /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ 380215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) 381215990Sjmallett { 382215990Sjmallett cvmx_ciu_qlm2_t ciu_qlm; 383215990Sjmallett ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2); 384215990Sjmallett ciu_qlm.s.txbypass = 1; 385215990Sjmallett ciu_qlm.s.txdeemph = 0xf; 386215990Sjmallett ciu_qlm.s.txmargin = 0xd; 387215990Sjmallett cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64); 388215990Sjmallett } 389215990Sjmallett 390232812Sjmallett /* CN63XX Pass 2.0 and 2.1 errata G-15273 requires the QLM De-emphasis be 391232812Sjmallett programmed when using a 156.25Mhz ref clock */ 392232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) || 393232812Sjmallett OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1)) 394232812Sjmallett { 395232812Sjmallett /* Read the QLM speed pins */ 396232812Sjmallett cvmx_mio_rst_boot_t mio_rst_boot; 397232812Sjmallett mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT); 398232812Sjmallett 399232812Sjmallett if (mio_rst_boot.cn63xx.qlm2_spd == 4) 400232812Sjmallett { 401232812Sjmallett cvmx_ciu_qlm2_t ciu_qlm; 402232812Sjmallett ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2); 403232812Sjmallett ciu_qlm.s.txbypass = 1; 404232812Sjmallett ciu_qlm.s.txdeemph = 0x0; 405232812Sjmallett ciu_qlm.s.txmargin = 0xf; 406232812Sjmallett cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64); 407232812Sjmallett } 408232812Sjmallett } 409232812Sjmallett 410210284Sjmallett __cvmx_helper_setup_gmx(interface, num_ports); 411210284Sjmallett 412210284Sjmallett for (index=0; index<num_ports; index++) 413210284Sjmallett { 414210284Sjmallett int ipd_port = cvmx_helper_get_ipd_port(interface, index); 415210284Sjmallett __cvmx_helper_sgmii_hardware_init_one_time(interface, index); 416232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 417232812Sjmallett /* Linux kernel driver will call ....link_set with the proper link 418232812Sjmallett state. In the simulator there is no link state polling and 419232812Sjmallett hence it is set from here. */ 420232812Sjmallett if (!(cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)) 421232812Sjmallett do_link_set = 0; 422232812Sjmallett#endif 423232812Sjmallett if (do_link_set) 424232812Sjmallett __cvmx_helper_sgmii_link_set(ipd_port, __cvmx_helper_sgmii_link_get(ipd_port)); 425210284Sjmallett } 426210284Sjmallett 427210284Sjmallett return 0; 428210284Sjmallett} 429210284Sjmallett 430232812Sjmallettint __cvmx_helper_sgmii_enumerate(int interface) 431232812Sjmallett{ 432232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CNF71XX)) 433232812Sjmallett return 2; 434210284Sjmallett 435232812Sjmallett return 4; 436232812Sjmallett} 437232812Sjmallett 438210284Sjmallett/** 439210284Sjmallett * @INTERNAL 440210284Sjmallett * Probe a SGMII interface and determine the number of ports 441210284Sjmallett * connected to it. The SGMII interface should still be down after 442210284Sjmallett * this call. 443210284Sjmallett * 444210284Sjmallett * @param interface Interface to probe 445210284Sjmallett * 446210284Sjmallett * @return Number of ports on the interface. Zero to disable. 447210284Sjmallett */ 448210284Sjmallettint __cvmx_helper_sgmii_probe(int interface) 449210284Sjmallett{ 450210284Sjmallett cvmx_gmxx_inf_mode_t mode; 451210284Sjmallett 452232812Sjmallett /* Check if QLM is configured correct for SGMII, verify the speed 453232812Sjmallett as well as mode */ 454232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 455232812Sjmallett { 456232812Sjmallett int qlm = cvmx_qlm_interface(interface); 457232812Sjmallett 458232812Sjmallett if (cvmx_qlm_get_status(qlm) != 1) 459232812Sjmallett return 0; 460232812Sjmallett } 461232812Sjmallett 462210284Sjmallett /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface 463232812Sjmallett needs to be enabled before IPD otherwise per port backpressure 464232812Sjmallett may not work properly */ 465210284Sjmallett mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 466210284Sjmallett mode.s.en = 1; 467210284Sjmallett cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); 468232812Sjmallett 469232812Sjmallett return __cvmx_helper_sgmii_enumerate(interface); 470210284Sjmallett} 471210284Sjmallett 472210284Sjmallett 473210284Sjmallett/** 474210284Sjmallett * @INTERNAL 475210284Sjmallett * Bringup and enable a SGMII interface. After this call packet 476210284Sjmallett * I/O should be fully functional. This is called with IPD 477210284Sjmallett * enabled but PKO disabled. 478210284Sjmallett * 479210284Sjmallett * @param interface Interface to bring up 480210284Sjmallett * 481210284Sjmallett * @return Zero on success, negative on failure 482210284Sjmallett */ 483210284Sjmallettint __cvmx_helper_sgmii_enable(int interface) 484210284Sjmallett{ 485210284Sjmallett int num_ports = cvmx_helper_ports_on_interface(interface); 486210284Sjmallett int index; 487210284Sjmallett 488232812Sjmallett /* Setup PKND and BPID */ 489232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 490232812Sjmallett { 491232812Sjmallett for (index = 0; index < num_ports; index++) 492232812Sjmallett { 493232812Sjmallett cvmx_gmxx_bpid_msk_t bpid_msk; 494232812Sjmallett cvmx_gmxx_bpid_mapx_t bpid_map; 495232812Sjmallett cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg; 496232812Sjmallett 497232812Sjmallett /* Setup PKIND */ 498232812Sjmallett gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 499232812Sjmallett gmxx_prtx_cfg.s.pknd = cvmx_helper_get_pknd(interface, index); 500232812Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); 501232812Sjmallett 502232812Sjmallett /* Setup BPID */ 503232812Sjmallett bpid_map.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MAPX(index, interface)); 504232812Sjmallett bpid_map.s.val = 1; 505232812Sjmallett bpid_map.s.bpid = cvmx_helper_get_bpid(interface, index); 506232812Sjmallett cvmx_write_csr(CVMX_GMXX_BPID_MAPX(index, interface), bpid_map.u64); 507232812Sjmallett 508232812Sjmallett bpid_msk.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MSK(interface)); 509232812Sjmallett bpid_msk.s.msk_or |= (1<<index); 510232812Sjmallett bpid_msk.s.msk_and &= ~(1<<index); 511232812Sjmallett cvmx_write_csr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64); 512232812Sjmallett } 513232812Sjmallett } 514232812Sjmallett 515210284Sjmallett __cvmx_helper_sgmii_hardware_init(interface, num_ports); 516210284Sjmallett 517232812Sjmallett /* CN68XX adds the padding and FCS in PKO, not GMX */ 518232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 519232812Sjmallett { 520232812Sjmallett cvmx_gmxx_txx_append_t gmxx_txx_append_cfg; 521232812Sjmallett 522232812Sjmallett for (index = 0; index < num_ports; index++) 523232812Sjmallett { 524232812Sjmallett gmxx_txx_append_cfg.u64 = cvmx_read_csr( 525232812Sjmallett CVMX_GMXX_TXX_APPEND(index, interface)); 526232812Sjmallett gmxx_txx_append_cfg.s.fcs = 0; 527232812Sjmallett gmxx_txx_append_cfg.s.pad = 0; 528232812Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_APPEND(index, interface), 529232812Sjmallett gmxx_txx_append_cfg.u64); 530232812Sjmallett } 531232812Sjmallett } 532232812Sjmallett 533210284Sjmallett for (index=0; index<num_ports; index++) 534210284Sjmallett { 535232812Sjmallett cvmx_gmxx_txx_append_t append_cfg; 536232812Sjmallett cvmx_gmxx_txx_sgmii_ctl_t sgmii_ctl; 537210284Sjmallett cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg; 538232812Sjmallett 539232812Sjmallett /* Clear the align bit if preamble is set to attain maximum tx rate. */ 540232812Sjmallett append_cfg.u64 = cvmx_read_csr(CVMX_GMXX_TXX_APPEND(index, interface)); 541232812Sjmallett sgmii_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TXX_SGMII_CTL(index, interface)); 542232812Sjmallett sgmii_ctl.s.align = append_cfg.s.preamble ? 0 : 1; 543232812Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SGMII_CTL(index, interface), sgmii_ctl.u64); 544232812Sjmallett 545210284Sjmallett gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 546210284Sjmallett gmxx_prtx_cfg.s.en = 1; 547210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); 548210284Sjmallett } 549210284Sjmallett return 0; 550210284Sjmallett} 551210284Sjmallett 552210284Sjmallett 553210284Sjmallett/** 554210284Sjmallett * @INTERNAL 555210284Sjmallett * Return the link state of an IPD/PKO port as returned by 556210284Sjmallett * auto negotiation. The result of this function may not match 557210284Sjmallett * Octeon's link config if auto negotiation has changed since 558210284Sjmallett * the last call to cvmx_helper_link_set(). 559210284Sjmallett * 560210284Sjmallett * @param ipd_port IPD/PKO port to query 561210284Sjmallett * 562210284Sjmallett * @return Link state 563210284Sjmallett */ 564210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port) 565210284Sjmallett{ 566210284Sjmallett cvmx_helper_link_info_t result; 567215990Sjmallett cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg; 568210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 569210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 570210284Sjmallett cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg; 571232812Sjmallett int speed = 1000; 572232812Sjmallett int qlm; 573210284Sjmallett 574210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 575210284Sjmallett { 576210284Sjmallett /* The simulator gives you a simulated 1Gbps full duplex link */ 577210284Sjmallett result.s.link_up = 1; 578210284Sjmallett result.s.full_duplex = 1; 579232812Sjmallett result.s.speed = speed; 580210284Sjmallett return result; 581210284Sjmallett } 582210284Sjmallett 583232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN66XX)) 584232812Sjmallett { 585232812Sjmallett cvmx_gmxx_inf_mode_t inf_mode; 586232812Sjmallett inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 587232812Sjmallett if (inf_mode.s.rate & (1<<index)) 588232812Sjmallett speed = 2500; 589232812Sjmallett else 590232812Sjmallett speed = 1000; 591232812Sjmallett } 592232812Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 593232812Sjmallett { 594232812Sjmallett qlm = cvmx_qlm_interface(interface); 595232812Sjmallett 596232812Sjmallett speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10; 597232812Sjmallett } 598232812Sjmallett 599232812Sjmallett result.u64 = 0; 600232812Sjmallett 601210284Sjmallett pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); 602210284Sjmallett if (pcsx_mrx_control_reg.s.loopbck1) 603210284Sjmallett { 604210284Sjmallett /* Force 1Gbps full duplex link for internal loopback */ 605210284Sjmallett result.s.link_up = 1; 606210284Sjmallett result.s.full_duplex = 1; 607232812Sjmallett result.s.speed = speed; 608210284Sjmallett return result; 609210284Sjmallett } 610210284Sjmallett 611210284Sjmallett 612215990Sjmallett pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 613215990Sjmallett if (pcsx_miscx_ctl_reg.s.mode) 614210284Sjmallett { 615250428Simp#if defined(OCTEON_VENDOR_GEFES) 616210284Sjmallett /* 1000BASE-X */ 617250428Simp int interface = cvmx_helper_get_interface_num(ipd_port); 618250428Simp int index = cvmx_helper_get_interface_index_num(ipd_port); 619250428Simp cvmx_pcsx_miscx_ctl_reg_t mode_type; 620250428Simp cvmx_pcsx_anx_results_reg_t inband_status; 621250428Simp cvmx_pcsx_mrx_status_reg_t mrx_status; 622250428Simp cvmx_pcsx_anx_adv_reg_t anxx_adv; 623250428Simp 624250428Simp anxx_adv.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface)); 625250428Simp mrx_status.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface)); 626250428Simp mode_type.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 627250428Simp 628250428Simp /* Read Octeon's inband status */ 629250428Simp inband_status.u64 = cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface)); 630250428Simp 631250428Simp result.s.link_up = inband_status.s.link_ok;/* this is only accurate for 1000-base x */ 632250428Simp 633250428Simp result.s.full_duplex = inband_status.s.dup; 634250428Simp switch (inband_status.s.spd) 635250428Simp { 636250428Simp case 0: /* 10 Mbps */ 637250428Simp result.s.speed = 10; 638250428Simp break; 639250428Simp case 1: /* 100 Mbps */ 640250428Simp result.s.speed = 100; 641250428Simp break; 642250428Simp case 2: /* 1 Gbps */ 643250428Simp result.s.speed = 1000; 644250428Simp break; 645250428Simp case 3: /* Illegal */ 646250428Simp result.s.speed = 0; 647250428Simp result.s.link_up = 0; 648250428Simp break; 649250428Simp } 650250428Simp#endif /* Actually not 100% this is GEFES specific */ 651210284Sjmallett } 652210284Sjmallett else 653210284Sjmallett { 654210284Sjmallett if (pcsx_miscx_ctl_reg.s.mac_phy) 655210284Sjmallett { 656210284Sjmallett /* PHY Mode */ 657210284Sjmallett cvmx_pcsx_mrx_status_reg_t pcsx_mrx_status_reg; 658210284Sjmallett cvmx_pcsx_anx_results_reg_t pcsx_anx_results_reg; 659210284Sjmallett 660210284Sjmallett /* Don't bother continuing if the SERTES low level link is down */ 661210284Sjmallett pcsx_mrx_status_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface)); 662210284Sjmallett if (pcsx_mrx_status_reg.s.lnk_st == 0) 663210284Sjmallett { 664210284Sjmallett if (__cvmx_helper_sgmii_hardware_init_link(interface, index) != 0) 665210284Sjmallett return result; 666210284Sjmallett } 667210284Sjmallett 668210284Sjmallett /* Read the autoneg results */ 669210284Sjmallett pcsx_anx_results_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface)); 670210284Sjmallett if (pcsx_anx_results_reg.s.an_cpt) 671210284Sjmallett { 672210284Sjmallett /* Auto negotiation is complete. Set status accordingly */ 673210284Sjmallett result.s.full_duplex = pcsx_anx_results_reg.s.dup; 674210284Sjmallett result.s.link_up = pcsx_anx_results_reg.s.link_ok; 675210284Sjmallett switch (pcsx_anx_results_reg.s.spd) 676210284Sjmallett { 677210284Sjmallett case 0: 678232812Sjmallett result.s.speed = speed / 100; 679210284Sjmallett break; 680210284Sjmallett case 1: 681232812Sjmallett result.s.speed = speed / 10; 682210284Sjmallett break; 683210284Sjmallett case 2: 684232812Sjmallett result.s.speed = speed; 685210284Sjmallett break; 686210284Sjmallett default: 687210284Sjmallett result.s.speed = 0; 688210284Sjmallett result.s.link_up = 0; 689210284Sjmallett break; 690210284Sjmallett } 691210284Sjmallett } 692210284Sjmallett else 693210284Sjmallett { 694210284Sjmallett /* Auto negotiation isn't complete. Return link down */ 695210284Sjmallett result.s.speed = 0; 696210284Sjmallett result.s.link_up = 0; 697210284Sjmallett } 698210284Sjmallett } 699210284Sjmallett else /* MAC Mode */ 700210284Sjmallett { 701210284Sjmallett result = __cvmx_helper_board_link_get(ipd_port); 702210284Sjmallett } 703210284Sjmallett } 704210284Sjmallett return result; 705210284Sjmallett} 706210284Sjmallett 707210284Sjmallett 708210284Sjmallett/** 709210284Sjmallett * @INTERNAL 710210284Sjmallett * Configure an IPD/PKO port for the specified link state. This 711210284Sjmallett * function does not influence auto negotiation at the PHY level. 712210284Sjmallett * The passed link state must always match the link state returned 713210284Sjmallett * by cvmx_helper_link_get(). It is normally best to use 714210284Sjmallett * cvmx_helper_link_autoconf() instead. 715210284Sjmallett * 716210284Sjmallett * @param ipd_port IPD/PKO port to configure 717210284Sjmallett * @param link_info The new link state 718210284Sjmallett * 719210284Sjmallett * @return Zero on success, negative on failure 720210284Sjmallett */ 721210284Sjmallettint __cvmx_helper_sgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 722210284Sjmallett{ 723210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 724210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 725232812Sjmallett 726232812Sjmallett if (link_info.s.link_up || !__cvmx_helper_need_g15618()) { 727232812Sjmallett __cvmx_helper_sgmii_hardware_init_link(interface, index); 728232812Sjmallett } else { 729232812Sjmallett cvmx_pcsx_mrx_control_reg_t control_reg; 730232812Sjmallett cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg; 731232812Sjmallett 732232812Sjmallett control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); 733232812Sjmallett control_reg.s.an_en = 0; 734232812Sjmallett cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64); 735232812Sjmallett cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); 736232812Sjmallett /* Use GMXENO to force the link down it will get reenabled later... */ 737232812Sjmallett pcsx_miscx_ctl_reg.s.gmxeno = 1; 738232812Sjmallett cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64); 739232812Sjmallett cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 740232812Sjmallett return 0; 741232812Sjmallett } 742210284Sjmallett return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, link_info); 743210284Sjmallett} 744210284Sjmallett 745210284Sjmallett/** 746210284Sjmallett * @INTERNAL 747210284Sjmallett * Configure a port for internal and/or external loopback. Internal loopback 748210284Sjmallett * causes packets sent by the port to be received by Octeon. External loopback 749210284Sjmallett * causes packets received from the wire to sent out again. 750210284Sjmallett * 751210284Sjmallett * @param ipd_port IPD/PKO port to loopback. 752210284Sjmallett * @param enable_internal 753210284Sjmallett * Non zero if you want internal loopback 754210284Sjmallett * @param enable_external 755210284Sjmallett * Non zero if you want external loopback 756210284Sjmallett * 757210284Sjmallett * @return Zero on success, negative on failure. 758210284Sjmallett */ 759210284Sjmallettint __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external) 760210284Sjmallett{ 761210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 762210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 763210284Sjmallett cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg; 764210284Sjmallett cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg; 765210284Sjmallett 766210284Sjmallett pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); 767210284Sjmallett pcsx_mrx_control_reg.s.loopbck1 = enable_internal; 768210284Sjmallett cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), pcsx_mrx_control_reg.u64); 769210284Sjmallett 770210284Sjmallett pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); 771210284Sjmallett pcsx_miscx_ctl_reg.s.loopbck2 = enable_external; 772210284Sjmallett cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64); 773210284Sjmallett 774210284Sjmallett __cvmx_helper_sgmii_hardware_init_link(interface, index); 775210284Sjmallett return 0; 776210284Sjmallett} 777210284Sjmallett 778210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 779