cvmx-helper-rgmii.c revision 216476
190792Sgshapiro/***********************license start*************** 290792Sgshapiro * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 390792Sgshapiro * reserved. 490792Sgshapiro * 590792Sgshapiro * 690792Sgshapiro * Redistribution and use in source and binary forms, with or without 790792Sgshapiro * modification, are permitted provided that the following conditions are 890792Sgshapiro * met: 990792Sgshapiro * 1090792Sgshapiro * * Redistributions of source code must retain the above copyright 1190792Sgshapiro * notice, this list of conditions and the following disclaimer. 1290792Sgshapiro * 1390792Sgshapiro * * Redistributions in binary form must reproduce the above 1490792Sgshapiro * copyright notice, this list of conditions and the following 1590792Sgshapiro * disclaimer in the documentation and/or other materials provided 1690792Sgshapiro * with the distribution. 1790792Sgshapiro 1890792Sgshapiro * * Neither the name of Cavium Networks nor the names of 1990792Sgshapiro * its contributors may be used to endorse or promote products 2090792Sgshapiro * derived from this software without specific prior written 2190792Sgshapiro * permission. 2290792Sgshapiro 2390792Sgshapiro * This Software, including technical data, may be subject to U.S. export control 2490792Sgshapiro * laws, including the U.S. Export Administration Act and its associated 2590792Sgshapiro * regulations, and may be subject to export or import regulations in other 2690792Sgshapiro * countries. 2790792Sgshapiro 2890792Sgshapiro * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 2990792Sgshapiro * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 3090792Sgshapiro * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 3190792Sgshapiro * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 3290792Sgshapiro * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 3390792Sgshapiro * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 3490792Sgshapiro * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 3590792Sgshapiro * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 3690792Sgshapiro * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 3790792Sgshapiro * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 3890792Sgshapiro ***********************license end**************************************/ 3990792Sgshapiro 4090792Sgshapiro 4190792Sgshapiro 4290792Sgshapiro 4390792Sgshapiro 4490792Sgshapiro 4590792Sgshapiro 4690792Sgshapiro/** 4790792Sgshapiro * @file 4890792Sgshapiro * 4990792Sgshapiro * Functions for RGMII/GMII/MII initialization, configuration, 5090792Sgshapiro * and monitoring. 5190792Sgshapiro * 5290792Sgshapiro * <hr>$Revision: 49448 $<hr> 5390792Sgshapiro */ 5490792Sgshapiro#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 5590792Sgshapiro#include <asm/octeon/cvmx.h> 5690792Sgshapiro#include <asm/octeon/cvmx-config.h> 5790792Sgshapiro#ifdef CVMX_ENABLE_PKO_FUNCTIONS 5890792Sgshapiro#include <asm/octeon/cvmx-pko.h> 5990792Sgshapiro#include <asm/octeon/cvmx-helper.h> 6090792Sgshapiro#include <asm/octeon/cvmx-helper-board.h> 61#endif 62#include <asm/octeon/cvmx-asxx-defs.h> 63#include <asm/octeon/cvmx-gmxx-defs.h> 64#include <asm/octeon/cvmx-pko-defs.h> 65#include <asm/octeon/cvmx-npi-defs.h> 66#include <asm/octeon/cvmx-dbg-defs.h> 67 68#else 69#if !defined(__FreeBSD__) || !defined(_KERNEL) 70#include "executive-config.h" 71#include "cvmx-config.h" 72#ifdef CVMX_ENABLE_PKO_FUNCTIONS 73 74#include "cvmx.h" 75#include "cvmx-sysinfo.h" 76#include "cvmx-mdio.h" 77#include "cvmx-pko.h" 78#include "cvmx-helper.h" 79#include "cvmx-helper-board.h" 80#endif 81#else 82#include "cvmx.h" 83#include "cvmx-sysinfo.h" 84#include "cvmx-mdio.h" 85#include "cvmx-pko.h" 86#include "cvmx-helper.h" 87#include "cvmx-helper-board.h" 88#endif 89#endif 90 91#ifdef CVMX_ENABLE_PKO_FUNCTIONS 92 93/** 94 * @INTERNAL 95 * Probe RGMII ports and determine the number present 96 * 97 * @param interface Interface to probe 98 * 99 * @return Number of RGMII/GMII/MII ports (0-4). 100 */ 101int __cvmx_helper_rgmii_probe(int interface) 102{ 103 int num_ports = 0; 104 cvmx_gmxx_inf_mode_t mode; 105 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 106 107 if (mode.s.type) 108 { 109 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 110 { 111 cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n"); 112 } 113 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 114 { 115 /* On these chips "type" says we're in GMII/MII mode. This 116 limits us to 2 ports */ 117 num_ports = 2; 118 } 119 else 120 { 121 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__); 122 } 123 } 124 else 125 { 126 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 127 { 128 num_ports = 4; 129 } 130 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 131 { 132 num_ports = 3; 133 } 134 else 135 { 136 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__); 137 } 138 } 139 return num_ports; 140} 141 142 143/** 144 * Put an RGMII interface in loopback mode. Internal packets sent 145 * out will be received back again on the same port. Externally 146 * received packets will echo back out. 147 * 148 * @param port IPD port number to loop. 149 */ 150void cvmx_helper_rgmii_internal_loopback(int port) 151{ 152 int interface = (port >> 4) & 1; 153 int index = port & 0xf; 154 uint64_t tmp; 155 156 cvmx_gmxx_prtx_cfg_t gmx_cfg; 157 gmx_cfg.u64 = 0; 158 gmx_cfg.s.duplex = 1; 159 gmx_cfg.s.slottime = 1; 160 gmx_cfg.s.speed = 1; 161 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 162 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 163 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 164 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 165 tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 166 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp); 167 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); 168 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); 169 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); 170 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); 171 gmx_cfg.s.en = 1; 172 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 173} 174 175 176/** 177 * @INTERNAL 178 * Configure all of the ASX, GMX, and PKO regsiters required 179 * to get RGMII to function on the supplied interface. 180 * 181 * @param interface PKO Interface to configure (0 or 1) 182 * 183 * @return Zero on success 184 */ 185int __cvmx_helper_rgmii_enable(int interface) 186{ 187 int num_ports = cvmx_helper_ports_on_interface(interface); 188 int port; 189 cvmx_gmxx_inf_mode_t mode; 190 cvmx_asxx_tx_prt_en_t asx_tx; 191 cvmx_asxx_rx_prt_en_t asx_rx; 192 193 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 194 195 if (mode.s.en == 0) 196 return -1; 197 if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1) /* Ignore SPI interfaces */ 198 return -1; 199 200 /* Configure the ASX registers needed to use the RGMII ports */ 201 asx_tx.u64 = 0; 202 asx_tx.s.prt_en = cvmx_build_mask(num_ports); 203 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64); 204 205 asx_rx.u64 = 0; 206 asx_rx.s.prt_en = cvmx_build_mask(num_ports); 207 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64); 208 209 /* Configure the GMX registers needed to use the RGMII ports */ 210 for (port=0; port<num_ports; port++) 211 { 212 /* Setting of CVMX_GMXX_TXX_THRESH has been moved to 213 __cvmx_helper_setup_gmx() */ 214 215 /* Configure more flexible RGMII preamble checking. Pass 1 doesn't 216 support this feature. */ 217 cvmx_gmxx_rxx_frm_ctl_t frm_ctl; 218 frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface)); 219 frm_ctl.s.pre_free = 1; /* New field, so must be compile time */ 220 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), frm_ctl.u64); 221 222 /* Each pause frame transmitted will ask for about 10M bit times 223 before resume. If buffer space comes available before that time 224 has expired, an XON pause frame (0 time) will be transmitted to 225 restart the flow. */ 226 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), 20000); 227 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(port, interface), 19000); 228 229 /* 230 * Board types we have to know at compile-time. 231 */ 232#if defined(OCTEON_BOARD_CAPK_0100ND) 233 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 26); 234 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 26); 235#else 236 /* 237 * Vendor-defined board types. 238 */ 239#if defined(OCTEON_VENDOR_LANNER) 240 switch (cvmx_sysinfo_get()->board_type) { 241 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 242 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 243 if (port == 0) { 244 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 4); 245 } else { 246 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 7); 247 } 248 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0); 249 break; 250 } 251#else 252 /* 253 * For board types we can determine at runtime. 254 */ 255 if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 256 { 257 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16); 258 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16); 259 } 260 else 261 { 262 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24); 263 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24); 264 } 265#endif 266#endif 267 } 268 269 __cvmx_helper_setup_gmx(interface, num_ports); 270 271 /* enable the ports now */ 272 for (port=0; port<num_ports; port++) 273 { 274 cvmx_gmxx_prtx_cfg_t gmx_cfg; 275 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, port)); 276 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface)); 277 gmx_cfg.s.en = 1; 278 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64); 279 } 280 return 0; 281} 282 283 284/** 285 * @INTERNAL 286 * Return the link state of an IPD/PKO port as returned by 287 * auto negotiation. The result of this function may not match 288 * Octeon's link config if auto negotiation has changed since 289 * the last call to cvmx_helper_link_set(). 290 * 291 * @param ipd_port IPD/PKO port to query 292 * 293 * @return Link state 294 */ 295cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port) 296{ 297 int interface = cvmx_helper_get_interface_num(ipd_port); 298 int index = cvmx_helper_get_interface_index_num(ipd_port); 299 cvmx_asxx_prt_loop_t asxx_prt_loop; 300 301 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 302 if (asxx_prt_loop.s.int_loop & (1<<index)) 303 { 304 /* Force 1Gbps full duplex on internal loopback */ 305 cvmx_helper_link_info_t result; 306 result.u64 = 0; 307 result.s.full_duplex = 1; 308 result.s.link_up = 1; 309 result.s.speed = 1000; 310 return result; 311 } 312 else 313 return __cvmx_helper_board_link_get(ipd_port); 314} 315 316 317/** 318 * @INTERNAL 319 * Configure an IPD/PKO port for the specified link state. This 320 * function does not influence auto negotiation at the PHY level. 321 * The passed link state must always match the link state returned 322 * by cvmx_helper_link_get(). It is normally best to use 323 * cvmx_helper_link_autoconf() instead. 324 * 325 * @param ipd_port IPD/PKO port to configure 326 * @param link_info The new link state 327 * 328 * @return Zero on success, negative on failure 329 */ 330int __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 331{ 332 int result = 0; 333 int interface = cvmx_helper_get_interface_num(ipd_port); 334 int index = cvmx_helper_get_interface_index_num(ipd_port); 335 cvmx_gmxx_prtx_cfg_t original_gmx_cfg; 336 cvmx_gmxx_prtx_cfg_t new_gmx_cfg; 337 cvmx_pko_mem_queue_qos_t pko_mem_queue_qos; 338 cvmx_pko_mem_queue_qos_t pko_mem_queue_qos_save[16]; 339 cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp; 340 cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp_save; 341 int i; 342 343 /* Ignore speed sets in the simulator */ 344 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 345 return 0; 346 347 /* Read the current settings so we know the current enable state */ 348 original_gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 349 new_gmx_cfg = original_gmx_cfg; 350 351 /* Disable the lowest level RX */ 352 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 353 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1<<index)); 354 355 /* Disable all queues so that TX should become idle */ 356 for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++) 357 { 358 int queue = cvmx_pko_get_base_queue(ipd_port) + i; 359 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); 360 pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS); 361 pko_mem_queue_qos.s.pid = ipd_port; 362 pko_mem_queue_qos.s.qid = queue; 363 pko_mem_queue_qos_save[i] = pko_mem_queue_qos; 364 pko_mem_queue_qos.s.qos_mask = 0; 365 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64); 366 } 367 368 /* Disable backpressure */ 369 gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); 370 gmx_tx_ovr_bp_save = gmx_tx_ovr_bp; 371 gmx_tx_ovr_bp.s.bp &= ~(1<<index); 372 gmx_tx_ovr_bp.s.en |= 1<<index; 373 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64); 374 cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); 375 376 /* Poll the GMX state machine waiting for it to become idle. Preferably we 377 should only change speed when it is idle. If it doesn't become idle we 378 will still do the speed change, but there is a slight chance that GMX 379 will lockup */ 380 cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880); 381 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000); 382 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000); 383 384 /* Disable the port before we make any changes */ 385 new_gmx_cfg.s.en = 0; 386 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 387 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 388 389 /* Set full/half duplex */ 390 if (!link_info.s.link_up) 391 new_gmx_cfg.s.duplex = 1; /* Force full duplex on down links */ 392 else 393 new_gmx_cfg.s.duplex = link_info.s.full_duplex; 394 395 /* Set the link speed. Anything unknown is set to 1Gbps */ 396 if (link_info.s.speed == 10) 397 { 398 new_gmx_cfg.s.slottime = 0; 399 new_gmx_cfg.s.speed = 0; 400 } 401 else if (link_info.s.speed == 100) 402 { 403 new_gmx_cfg.s.slottime = 0; 404 new_gmx_cfg.s.speed = 0; 405 } 406 else 407 { 408 new_gmx_cfg.s.slottime = 1; 409 new_gmx_cfg.s.speed = 1; 410 } 411 412 /* Adjust the clocks */ 413 if (link_info.s.speed == 10) 414 { 415 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50); 416 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); 417 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 418 } 419 else if (link_info.s.speed == 100) 420 { 421 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5); 422 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); 423 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 424 } 425 else 426 { 427 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 428 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 429 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 430 } 431 432 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 433 { 434 if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) 435 { 436 cvmx_gmxx_inf_mode_t mode; 437 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 438 439 /* 440 ** Port .en .type .p0mii Configuration 441 ** ---- --- ----- ------ ----------------------------------------- 442 ** X 0 X X All links are disabled. 443 ** 0 1 X 0 Port 0 is RGMII 444 ** 0 1 X 1 Port 0 is MII 445 ** 1 1 0 X Ports 1 and 2 are configured as RGMII ports. 446 ** 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or 447 ** MII port is selected by GMX_PRT1_CFG[SPEED]. 448 */ 449 450 /* In MII mode, CLK_CNT = 1. */ 451 if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1))) 452 { 453 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 454 } 455 } 456 } 457 458 /* Do a read to make sure all setup stuff is complete */ 459 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 460 461 /* Save the new GMX setting without enabling the port */ 462 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 463 464 /* Enable the lowest level RX */ 465 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 466 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index)); 467 468 /* Re-enable the TX path */ 469 for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++) 470 { 471 int queue = cvmx_pko_get_base_queue(ipd_port) + i; 472 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); 473 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64); 474 } 475 476 /* Restore backpressure */ 477 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64); 478 479 /* Restore the GMX enable state. Port config is complete */ 480 new_gmx_cfg.s.en = original_gmx_cfg.s.en; 481 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 482 483 return result; 484} 485 486 487/** 488 * @INTERNAL 489 * Configure a port for internal and/or external loopback. Internal loopback 490 * causes packets sent by the port to be received by Octeon. External loopback 491 * causes packets received from the wire to sent out again. 492 * 493 * @param ipd_port IPD/PKO port to loopback. 494 * @param enable_internal 495 * Non zero if you want internal loopback 496 * @param enable_external 497 * Non zero if you want external loopback 498 * 499 * @return Zero on success, negative on failure. 500 */ 501int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external) 502{ 503 int interface = cvmx_helper_get_interface_num(ipd_port); 504 int index = cvmx_helper_get_interface_index_num(ipd_port); 505 int original_enable; 506 cvmx_gmxx_prtx_cfg_t gmx_cfg; 507 cvmx_asxx_prt_loop_t asxx_prt_loop; 508 509 /* Read the current enable state and save it */ 510 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 511 original_enable = gmx_cfg.s.en; 512 /* Force port to be disabled */ 513 gmx_cfg.s.en = 0; 514 if (enable_internal) 515 { 516 /* Force speed if we're doing internal loopback */ 517 gmx_cfg.s.duplex = 1; 518 gmx_cfg.s.slottime = 1; 519 gmx_cfg.s.speed = 1; 520 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 521 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 522 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 523 } 524 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 525 526 /* Set the loopback bits */ 527 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 528 if (enable_internal) 529 asxx_prt_loop.s.int_loop |= 1<<index; 530 else 531 asxx_prt_loop.s.int_loop &= ~(1<<index); 532 if (enable_external) 533 asxx_prt_loop.s.ext_loop |= 1<<index; 534 else 535 asxx_prt_loop.s.ext_loop &= ~(1<<index); 536 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64); 537 538 /* Force enables in internal loopback */ 539 if (enable_internal) 540 { 541 uint64_t tmp; 542 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); 543 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); 544 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); 545 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); 546 original_enable = 1; 547 } 548 549 /* Restore the enable state */ 550 gmx_cfg.s.en = original_enable; 551 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 552 return 0; 553} 554 555#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 556 557