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