cvmx-helper-rgmii.c revision 216476
1210284Sjmallett/***********************license start*************** 2215990Sjmallett * Copyright (c) 2003-2010 Cavium Networks (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 18215990Sjmallett * * Neither the name of Cavium Networks 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" 29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM NETWORKS 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 RGMII/GMII/MII initialization, configuration, 50210284Sjmallett * and monitoring. 51210284Sjmallett * 52215990Sjmallett * <hr>$Revision: 49448 $<hr> 53210284Sjmallett */ 54215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 55215990Sjmallett#include <asm/octeon/cvmx.h> 56215990Sjmallett#include <asm/octeon/cvmx-config.h> 57215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 58215990Sjmallett#include <asm/octeon/cvmx-pko.h> 59215990Sjmallett#include <asm/octeon/cvmx-helper.h> 60215990Sjmallett#include <asm/octeon/cvmx-helper-board.h> 61215990Sjmallett#endif 62215990Sjmallett#include <asm/octeon/cvmx-asxx-defs.h> 63215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h> 64215990Sjmallett#include <asm/octeon/cvmx-pko-defs.h> 65215990Sjmallett#include <asm/octeon/cvmx-npi-defs.h> 66215990Sjmallett#include <asm/octeon/cvmx-dbg-defs.h> 67215990Sjmallett 68215990Sjmallett#else 69215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 70215990Sjmallett#include "executive-config.h" 71215990Sjmallett#include "cvmx-config.h" 72215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 73215990Sjmallett 74210284Sjmallett#include "cvmx.h" 75210284Sjmallett#include "cvmx-sysinfo.h" 76210284Sjmallett#include "cvmx-mdio.h" 77210284Sjmallett#include "cvmx-pko.h" 78210284Sjmallett#include "cvmx-helper.h" 79210284Sjmallett#include "cvmx-helper-board.h" 80215990Sjmallett#endif 81215990Sjmallett#else 82215990Sjmallett#include "cvmx.h" 83215990Sjmallett#include "cvmx-sysinfo.h" 84215990Sjmallett#include "cvmx-mdio.h" 85215990Sjmallett#include "cvmx-pko.h" 86215990Sjmallett#include "cvmx-helper.h" 87215990Sjmallett#include "cvmx-helper-board.h" 88215990Sjmallett#endif 89215990Sjmallett#endif 90210284Sjmallett 91210311Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 92215990Sjmallett 93210284Sjmallett/** 94210284Sjmallett * @INTERNAL 95210284Sjmallett * Probe RGMII ports and determine the number present 96210284Sjmallett * 97210284Sjmallett * @param interface Interface to probe 98210284Sjmallett * 99210284Sjmallett * @return Number of RGMII/GMII/MII ports (0-4). 100210284Sjmallett */ 101210284Sjmallettint __cvmx_helper_rgmii_probe(int interface) 102210284Sjmallett{ 103210284Sjmallett int num_ports = 0; 104210284Sjmallett cvmx_gmxx_inf_mode_t mode; 105210284Sjmallett mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 106210284Sjmallett 107210284Sjmallett if (mode.s.type) 108210284Sjmallett { 109210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 110210284Sjmallett { 111210284Sjmallett cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n"); 112210284Sjmallett } 113210284Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 114210284Sjmallett { 115210284Sjmallett /* On these chips "type" says we're in GMII/MII mode. This 116210284Sjmallett limits us to 2 ports */ 117210284Sjmallett num_ports = 2; 118210284Sjmallett } 119210284Sjmallett else 120210284Sjmallett { 121210284Sjmallett cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__); 122210284Sjmallett } 123210284Sjmallett } 124210284Sjmallett else 125210284Sjmallett { 126210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 127210284Sjmallett { 128210284Sjmallett num_ports = 4; 129210284Sjmallett } 130210284Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 131210284Sjmallett { 132210284Sjmallett num_ports = 3; 133210284Sjmallett } 134210284Sjmallett else 135210284Sjmallett { 136210284Sjmallett cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__); 137210284Sjmallett } 138210284Sjmallett } 139210284Sjmallett return num_ports; 140210284Sjmallett} 141210284Sjmallett 142210284Sjmallett 143210284Sjmallett/** 144210284Sjmallett * Put an RGMII interface in loopback mode. Internal packets sent 145210284Sjmallett * out will be received back again on the same port. Externally 146210284Sjmallett * received packets will echo back out. 147210284Sjmallett * 148210284Sjmallett * @param port IPD port number to loop. 149210284Sjmallett */ 150210284Sjmallettvoid cvmx_helper_rgmii_internal_loopback(int port) 151210284Sjmallett{ 152210284Sjmallett int interface = (port >> 4) & 1; 153210284Sjmallett int index = port & 0xf; 154210284Sjmallett uint64_t tmp; 155210284Sjmallett 156210284Sjmallett cvmx_gmxx_prtx_cfg_t gmx_cfg; 157210284Sjmallett gmx_cfg.u64 = 0; 158210284Sjmallett gmx_cfg.s.duplex = 1; 159210284Sjmallett gmx_cfg.s.slottime = 1; 160210284Sjmallett gmx_cfg.s.speed = 1; 161210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 162210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 163210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 164210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 165210284Sjmallett tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 166210284Sjmallett cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp); 167210284Sjmallett tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); 168210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); 169210284Sjmallett tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); 170210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); 171210284Sjmallett gmx_cfg.s.en = 1; 172210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 173210284Sjmallett} 174210284Sjmallett 175210284Sjmallett 176210284Sjmallett/** 177210284Sjmallett * @INTERNAL 178210284Sjmallett * Configure all of the ASX, GMX, and PKO regsiters required 179210284Sjmallett * to get RGMII to function on the supplied interface. 180210284Sjmallett * 181210284Sjmallett * @param interface PKO Interface to configure (0 or 1) 182210284Sjmallett * 183210284Sjmallett * @return Zero on success 184210284Sjmallett */ 185210284Sjmallettint __cvmx_helper_rgmii_enable(int interface) 186210284Sjmallett{ 187210284Sjmallett int num_ports = cvmx_helper_ports_on_interface(interface); 188210284Sjmallett int port; 189210284Sjmallett cvmx_gmxx_inf_mode_t mode; 190210284Sjmallett cvmx_asxx_tx_prt_en_t asx_tx; 191210284Sjmallett cvmx_asxx_rx_prt_en_t asx_rx; 192210284Sjmallett 193210284Sjmallett mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 194210284Sjmallett 195210284Sjmallett if (mode.s.en == 0) 196210284Sjmallett return -1; 197210284Sjmallett if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1) /* Ignore SPI interfaces */ 198210284Sjmallett return -1; 199210284Sjmallett 200210284Sjmallett /* Configure the ASX registers needed to use the RGMII ports */ 201210284Sjmallett asx_tx.u64 = 0; 202210284Sjmallett asx_tx.s.prt_en = cvmx_build_mask(num_ports); 203210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64); 204210284Sjmallett 205210284Sjmallett asx_rx.u64 = 0; 206210284Sjmallett asx_rx.s.prt_en = cvmx_build_mask(num_ports); 207210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64); 208210284Sjmallett 209210284Sjmallett /* Configure the GMX registers needed to use the RGMII ports */ 210210284Sjmallett for (port=0; port<num_ports; port++) 211210284Sjmallett { 212210284Sjmallett /* Setting of CVMX_GMXX_TXX_THRESH has been moved to 213210284Sjmallett __cvmx_helper_setup_gmx() */ 214210284Sjmallett 215215990Sjmallett /* Configure more flexible RGMII preamble checking. Pass 1 doesn't 216215990Sjmallett support this feature. */ 217215990Sjmallett cvmx_gmxx_rxx_frm_ctl_t frm_ctl; 218215990Sjmallett frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface)); 219215990Sjmallett frm_ctl.s.pre_free = 1; /* New field, so must be compile time */ 220215990Sjmallett cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), frm_ctl.u64); 221210284Sjmallett 222210284Sjmallett /* Each pause frame transmitted will ask for about 10M bit times 223210284Sjmallett before resume. If buffer space comes available before that time 224210284Sjmallett has expired, an XON pause frame (0 time) will be transmitted to 225210284Sjmallett restart the flow. */ 226210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), 20000); 227210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(port, interface), 19000); 228210284Sjmallett 229210311Sjmallett /* 230210311Sjmallett * Board types we have to know at compile-time. 231210311Sjmallett */ 232210311Sjmallett#if defined(OCTEON_BOARD_CAPK_0100ND) 233210311Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 26); 234210311Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 26); 235210311Sjmallett#else 236210311Sjmallett /* 237210311Sjmallett * Vendor-defined board types. 238210311Sjmallett */ 239210311Sjmallett#if defined(OCTEON_VENDOR_LANNER) 240210311Sjmallett switch (cvmx_sysinfo_get()->board_type) { 241210311Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 242216476Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 243210311Sjmallett if (port == 0) { 244210311Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 4); 245210311Sjmallett } else { 246210311Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 7); 247210311Sjmallett } 248210311Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0); 249210311Sjmallett break; 250210311Sjmallett } 251210311Sjmallett#else 252210311Sjmallett /* 253210311Sjmallett * For board types we can determine at runtime. 254210311Sjmallett */ 255210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 256210284Sjmallett { 257210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16); 258210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16); 259210284Sjmallett } 260210284Sjmallett else 261210284Sjmallett { 262210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24); 263210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24); 264210284Sjmallett } 265210311Sjmallett#endif 266210311Sjmallett#endif 267210284Sjmallett } 268210284Sjmallett 269210284Sjmallett __cvmx_helper_setup_gmx(interface, num_ports); 270210284Sjmallett 271210284Sjmallett /* enable the ports now */ 272210284Sjmallett for (port=0; port<num_ports; port++) 273210284Sjmallett { 274210284Sjmallett cvmx_gmxx_prtx_cfg_t gmx_cfg; 275210284Sjmallett cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, port)); 276210284Sjmallett gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface)); 277210284Sjmallett gmx_cfg.s.en = 1; 278210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64); 279210284Sjmallett } 280210284Sjmallett return 0; 281210284Sjmallett} 282210284Sjmallett 283210284Sjmallett 284210284Sjmallett/** 285210284Sjmallett * @INTERNAL 286210284Sjmallett * Return the link state of an IPD/PKO port as returned by 287210284Sjmallett * auto negotiation. The result of this function may not match 288210284Sjmallett * Octeon's link config if auto negotiation has changed since 289210284Sjmallett * the last call to cvmx_helper_link_set(). 290210284Sjmallett * 291210284Sjmallett * @param ipd_port IPD/PKO port to query 292210284Sjmallett * 293210284Sjmallett * @return Link state 294210284Sjmallett */ 295210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port) 296210284Sjmallett{ 297210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 298210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 299210284Sjmallett cvmx_asxx_prt_loop_t asxx_prt_loop; 300210284Sjmallett 301210284Sjmallett asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 302210284Sjmallett if (asxx_prt_loop.s.int_loop & (1<<index)) 303210284Sjmallett { 304210284Sjmallett /* Force 1Gbps full duplex on internal loopback */ 305210284Sjmallett cvmx_helper_link_info_t result; 306210284Sjmallett result.u64 = 0; 307210284Sjmallett result.s.full_duplex = 1; 308210284Sjmallett result.s.link_up = 1; 309210284Sjmallett result.s.speed = 1000; 310210284Sjmallett return result; 311210284Sjmallett } 312210284Sjmallett else 313210284Sjmallett return __cvmx_helper_board_link_get(ipd_port); 314210284Sjmallett} 315210284Sjmallett 316210284Sjmallett 317210284Sjmallett/** 318210284Sjmallett * @INTERNAL 319210284Sjmallett * Configure an IPD/PKO port for the specified link state. This 320210284Sjmallett * function does not influence auto negotiation at the PHY level. 321210284Sjmallett * The passed link state must always match the link state returned 322210284Sjmallett * by cvmx_helper_link_get(). It is normally best to use 323210284Sjmallett * cvmx_helper_link_autoconf() instead. 324210284Sjmallett * 325210284Sjmallett * @param ipd_port IPD/PKO port to configure 326210284Sjmallett * @param link_info The new link state 327210284Sjmallett * 328210284Sjmallett * @return Zero on success, negative on failure 329210284Sjmallett */ 330210284Sjmallettint __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 331210284Sjmallett{ 332210284Sjmallett int result = 0; 333210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 334210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 335210284Sjmallett cvmx_gmxx_prtx_cfg_t original_gmx_cfg; 336210284Sjmallett cvmx_gmxx_prtx_cfg_t new_gmx_cfg; 337210284Sjmallett cvmx_pko_mem_queue_qos_t pko_mem_queue_qos; 338210284Sjmallett cvmx_pko_mem_queue_qos_t pko_mem_queue_qos_save[16]; 339210284Sjmallett cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp; 340210284Sjmallett cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp_save; 341210284Sjmallett int i; 342210284Sjmallett 343210284Sjmallett /* Ignore speed sets in the simulator */ 344210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 345210284Sjmallett return 0; 346210284Sjmallett 347210284Sjmallett /* Read the current settings so we know the current enable state */ 348210284Sjmallett original_gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 349210284Sjmallett new_gmx_cfg = original_gmx_cfg; 350210284Sjmallett 351210284Sjmallett /* Disable the lowest level RX */ 352210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 353210284Sjmallett cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1<<index)); 354210284Sjmallett 355210284Sjmallett /* Disable all queues so that TX should become idle */ 356210284Sjmallett for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++) 357210284Sjmallett { 358210284Sjmallett int queue = cvmx_pko_get_base_queue(ipd_port) + i; 359210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); 360210284Sjmallett pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS); 361210284Sjmallett pko_mem_queue_qos.s.pid = ipd_port; 362210284Sjmallett pko_mem_queue_qos.s.qid = queue; 363210284Sjmallett pko_mem_queue_qos_save[i] = pko_mem_queue_qos; 364210284Sjmallett pko_mem_queue_qos.s.qos_mask = 0; 365210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64); 366210284Sjmallett } 367210284Sjmallett 368210284Sjmallett /* Disable backpressure */ 369210284Sjmallett gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); 370210284Sjmallett gmx_tx_ovr_bp_save = gmx_tx_ovr_bp; 371210284Sjmallett gmx_tx_ovr_bp.s.bp &= ~(1<<index); 372210284Sjmallett gmx_tx_ovr_bp.s.en |= 1<<index; 373210284Sjmallett cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64); 374210284Sjmallett cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); 375210284Sjmallett 376210284Sjmallett /* Poll the GMX state machine waiting for it to become idle. Preferably we 377210284Sjmallett should only change speed when it is idle. If it doesn't become idle we 378210284Sjmallett will still do the speed change, but there is a slight chance that GMX 379210284Sjmallett will lockup */ 380210284Sjmallett cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880); 381210284Sjmallett CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000); 382210284Sjmallett CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000); 383210284Sjmallett 384210284Sjmallett /* Disable the port before we make any changes */ 385210284Sjmallett new_gmx_cfg.s.en = 0; 386210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 387210284Sjmallett cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 388210284Sjmallett 389210284Sjmallett /* Set full/half duplex */ 390215990Sjmallett if (!link_info.s.link_up) 391210284Sjmallett new_gmx_cfg.s.duplex = 1; /* Force full duplex on down links */ 392210284Sjmallett else 393210284Sjmallett new_gmx_cfg.s.duplex = link_info.s.full_duplex; 394210284Sjmallett 395210284Sjmallett /* Set the link speed. Anything unknown is set to 1Gbps */ 396210284Sjmallett if (link_info.s.speed == 10) 397210284Sjmallett { 398210284Sjmallett new_gmx_cfg.s.slottime = 0; 399210284Sjmallett new_gmx_cfg.s.speed = 0; 400210284Sjmallett } 401210284Sjmallett else if (link_info.s.speed == 100) 402210284Sjmallett { 403210284Sjmallett new_gmx_cfg.s.slottime = 0; 404210284Sjmallett new_gmx_cfg.s.speed = 0; 405210284Sjmallett } 406210284Sjmallett else 407210284Sjmallett { 408210284Sjmallett new_gmx_cfg.s.slottime = 1; 409210284Sjmallett new_gmx_cfg.s.speed = 1; 410210284Sjmallett } 411210284Sjmallett 412210284Sjmallett /* Adjust the clocks */ 413210284Sjmallett if (link_info.s.speed == 10) 414210284Sjmallett { 415210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50); 416210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); 417210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 418210284Sjmallett } 419210284Sjmallett else if (link_info.s.speed == 100) 420210284Sjmallett { 421210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5); 422210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); 423210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 424210284Sjmallett } 425210284Sjmallett else 426210284Sjmallett { 427210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 428210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 429210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 430210284Sjmallett } 431210284Sjmallett 432210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 433210284Sjmallett { 434210284Sjmallett if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) 435210284Sjmallett { 436210284Sjmallett cvmx_gmxx_inf_mode_t mode; 437210284Sjmallett mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 438210284Sjmallett 439210284Sjmallett /* 440210284Sjmallett ** Port .en .type .p0mii Configuration 441210284Sjmallett ** ---- --- ----- ------ ----------------------------------------- 442210284Sjmallett ** X 0 X X All links are disabled. 443210284Sjmallett ** 0 1 X 0 Port 0 is RGMII 444210284Sjmallett ** 0 1 X 1 Port 0 is MII 445210284Sjmallett ** 1 1 0 X Ports 1 and 2 are configured as RGMII ports. 446210284Sjmallett ** 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or 447210284Sjmallett ** MII port is selected by GMX_PRT1_CFG[SPEED]. 448210284Sjmallett */ 449210284Sjmallett 450210284Sjmallett /* In MII mode, CLK_CNT = 1. */ 451210284Sjmallett if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1))) 452210284Sjmallett { 453210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 454210284Sjmallett } 455210284Sjmallett } 456210284Sjmallett } 457210284Sjmallett 458210284Sjmallett /* Do a read to make sure all setup stuff is complete */ 459210284Sjmallett cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 460210284Sjmallett 461210284Sjmallett /* Save the new GMX setting without enabling the port */ 462210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 463210284Sjmallett 464210284Sjmallett /* Enable the lowest level RX */ 465210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 466210284Sjmallett cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index)); 467210284Sjmallett 468210284Sjmallett /* Re-enable the TX path */ 469210284Sjmallett for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++) 470210284Sjmallett { 471210284Sjmallett int queue = cvmx_pko_get_base_queue(ipd_port) + i; 472210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); 473210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64); 474210284Sjmallett } 475210284Sjmallett 476210284Sjmallett /* Restore backpressure */ 477210284Sjmallett cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64); 478210284Sjmallett 479210284Sjmallett /* Restore the GMX enable state. Port config is complete */ 480210284Sjmallett new_gmx_cfg.s.en = original_gmx_cfg.s.en; 481210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 482210284Sjmallett 483210284Sjmallett return result; 484210284Sjmallett} 485210284Sjmallett 486210284Sjmallett 487210284Sjmallett/** 488210284Sjmallett * @INTERNAL 489210284Sjmallett * Configure a port for internal and/or external loopback. Internal loopback 490210284Sjmallett * causes packets sent by the port to be received by Octeon. External loopback 491210284Sjmallett * causes packets received from the wire to sent out again. 492210284Sjmallett * 493210284Sjmallett * @param ipd_port IPD/PKO port to loopback. 494210284Sjmallett * @param enable_internal 495210284Sjmallett * Non zero if you want internal loopback 496210284Sjmallett * @param enable_external 497210284Sjmallett * Non zero if you want external loopback 498210284Sjmallett * 499210284Sjmallett * @return Zero on success, negative on failure. 500210284Sjmallett */ 501210284Sjmallettint __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external) 502210284Sjmallett{ 503210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 504210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 505210284Sjmallett int original_enable; 506210284Sjmallett cvmx_gmxx_prtx_cfg_t gmx_cfg; 507210284Sjmallett cvmx_asxx_prt_loop_t asxx_prt_loop; 508210284Sjmallett 509210284Sjmallett /* Read the current enable state and save it */ 510210284Sjmallett gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 511210284Sjmallett original_enable = gmx_cfg.s.en; 512210284Sjmallett /* Force port to be disabled */ 513210284Sjmallett gmx_cfg.s.en = 0; 514210284Sjmallett if (enable_internal) 515210284Sjmallett { 516210284Sjmallett /* Force speed if we're doing internal loopback */ 517210284Sjmallett gmx_cfg.s.duplex = 1; 518210284Sjmallett gmx_cfg.s.slottime = 1; 519210284Sjmallett gmx_cfg.s.speed = 1; 520210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 521210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 522210284Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 523210284Sjmallett } 524210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 525210284Sjmallett 526210284Sjmallett /* Set the loopback bits */ 527210284Sjmallett asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 528210284Sjmallett if (enable_internal) 529210284Sjmallett asxx_prt_loop.s.int_loop |= 1<<index; 530210284Sjmallett else 531210284Sjmallett asxx_prt_loop.s.int_loop &= ~(1<<index); 532210284Sjmallett if (enable_external) 533210284Sjmallett asxx_prt_loop.s.ext_loop |= 1<<index; 534210284Sjmallett else 535210284Sjmallett asxx_prt_loop.s.ext_loop &= ~(1<<index); 536210284Sjmallett cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64); 537210284Sjmallett 538210284Sjmallett /* Force enables in internal loopback */ 539210284Sjmallett if (enable_internal) 540210284Sjmallett { 541210284Sjmallett uint64_t tmp; 542210284Sjmallett tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); 543210284Sjmallett cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); 544210284Sjmallett tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); 545210284Sjmallett cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); 546210284Sjmallett original_enable = 1; 547210284Sjmallett } 548210284Sjmallett 549210284Sjmallett /* Restore the enable state */ 550210284Sjmallett gmx_cfg.s.en = original_enable; 551210284Sjmallett cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 552210284Sjmallett return 0; 553210284Sjmallett} 554210284Sjmallett 555210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 556210284Sjmallett 557