1/***********************license start*************** 2 * Author: Cavium Networks 3 * 4 * Contact: support@caviumnetworks.com 5 * This file is part of the OCTEON SDK 6 * 7 * Copyright (c) 2003-2008 Cavium Networks 8 * 9 * This file is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License, Version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This file is distributed in the hope that it will be useful, but 14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 16 * NONINFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this file; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * or visit http://www.gnu.org/licenses/. 23 * 24 * This file may also be available under a different license from Cavium. 25 * Contact Cavium Networks for more information 26 ***********************license end**************************************/ 27 28/* 29 * Functions for XAUI initialization, configuration, 30 * and monitoring. 31 * 32 */ 33 34#include <asm/octeon/octeon.h> 35 36#include "cvmx-config.h" 37 38#include "cvmx-helper.h" 39 40#include "cvmx-pko-defs.h" 41#include "cvmx-gmxx-defs.h" 42#include "cvmx-pcsxx-defs.h" 43 44void __cvmx_interrupt_gmxx_enable(int interface); 45void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); 46void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); 47/** 48 * Probe a XAUI interface and determine the number of ports 49 * connected to it. The XAUI interface should still be down 50 * after this call. 51 * 52 * @interface: Interface to probe 53 * 54 * Returns Number of ports on the interface. Zero to disable. 55 */ 56int __cvmx_helper_xaui_probe(int interface) 57{ 58 int i; 59 union cvmx_gmxx_hg2_control gmx_hg2_control; 60 union cvmx_gmxx_inf_mode mode; 61 62 /* 63 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the 64 * interface needs to be enabled before IPD otherwise per port 65 * backpressure may not work properly. 66 */ 67 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 68 mode.s.en = 1; 69 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); 70 71 __cvmx_helper_setup_gmx(interface, 1); 72 73 /* 74 * Setup PKO to support 16 ports for HiGig2 virtual 75 * ports. We're pointing all of the PKO packet ports for this 76 * interface to the XAUI. This allows us to use HiGig2 77 * backpressure per port. 78 */ 79 for (i = 0; i < 16; i++) { 80 union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs; 81 pko_mem_port_ptrs.u64 = 0; 82 /* 83 * We set each PKO port to have equal priority in a 84 * round robin fashion. 85 */ 86 pko_mem_port_ptrs.s.static_p = 0; 87 pko_mem_port_ptrs.s.qos_mask = 0xff; 88 /* All PKO ports map to the same XAUI hardware port */ 89 pko_mem_port_ptrs.s.eid = interface * 4; 90 pko_mem_port_ptrs.s.pid = interface * 16 + i; 91 cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64); 92 } 93 94 /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ 95 gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); 96 if (gmx_hg2_control.s.hg2tx_en) 97 return 16; 98 else 99 return 1; 100} 101 102/** 103 * Bringup and enable a XAUI interface. After this call packet 104 * I/O should be fully functional. This is called with IPD 105 * enabled but PKO disabled. 106 * 107 * @interface: Interface to bring up 108 * 109 * Returns Zero on success, negative on failure 110 */ 111int __cvmx_helper_xaui_enable(int interface) 112{ 113 union cvmx_gmxx_prtx_cfg gmx_cfg; 114 union cvmx_pcsxx_control1_reg xauiCtl; 115 union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl; 116 union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl; 117 union cvmx_gmxx_rxx_int_en gmx_rx_int_en; 118 union cvmx_gmxx_tx_int_en gmx_tx_int_en; 119 union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; 120 121 /* (1) Interface has already been enabled. */ 122 123 /* (2) Disable GMX. */ 124 xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface)); 125 xauiMiscCtl.s.gmxeno = 1; 126 cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); 127 128 /* (3) Disable GMX and PCSX interrupts. */ 129 gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface)); 130 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); 131 gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface)); 132 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); 133 pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface)); 134 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); 135 136 /* (4) Bring up the PCSX and GMX reconciliation layer. */ 137 /* (4)a Set polarity and lane swapping. */ 138 /* (4)b */ 139 gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); 140 /* Enable better IFG packing and improves performance */ 141 gmxXauiTxCtl.s.dic_en = 1; 142 gmxXauiTxCtl.s.uni_en = 0; 143 cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64); 144 145 /* (4)c Aply reset sequence */ 146 xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); 147 xauiCtl.s.lo_pwr = 0; 148 xauiCtl.s.reset = 1; 149 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); 150 151 /* Wait for PCS to come out of reset */ 152 if (CVMX_WAIT_FOR_FIELD64 153 (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg, 154 reset, ==, 0, 10000)) 155 return -1; 156 /* Wait for PCS to be aligned */ 157 if (CVMX_WAIT_FOR_FIELD64 158 (CVMX_PCSXX_10GBX_STATUS_REG(interface), 159 union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000)) 160 return -1; 161 /* Wait for RX to be ready */ 162 if (CVMX_WAIT_FOR_FIELD64 163 (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl, 164 status, ==, 0, 10000)) 165 return -1; 166 167 /* (6) Configure GMX */ 168 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); 169 gmx_cfg.s.en = 0; 170 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); 171 172 /* Wait for GMX RX to be idle */ 173 if (CVMX_WAIT_FOR_FIELD64 174 (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, 175 rx_idle, ==, 1, 10000)) 176 return -1; 177 /* Wait for GMX TX to be idle */ 178 if (CVMX_WAIT_FOR_FIELD64 179 (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, 180 tx_idle, ==, 1, 10000)) 181 return -1; 182 183 /* GMX configure */ 184 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); 185 gmx_cfg.s.speed = 1; 186 gmx_cfg.s.speed_msb = 0; 187 gmx_cfg.s.slottime = 1; 188 cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1); 189 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512); 190 cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192); 191 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); 192 193 /* (7) Clear out any error state */ 194 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface), 195 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface))); 196 cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), 197 cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface))); 198 cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), 199 cvmx_read_csr(CVMX_PCSXX_INT_REG(interface))); 200 201 /* Wait for receive link */ 202 if (CVMX_WAIT_FOR_FIELD64 203 (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg, 204 rcv_lnk, ==, 1, 10000)) 205 return -1; 206 if (CVMX_WAIT_FOR_FIELD64 207 (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, 208 xmtflt, ==, 0, 10000)) 209 return -1; 210 if (CVMX_WAIT_FOR_FIELD64 211 (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, 212 rcvflt, ==, 0, 10000)) 213 return -1; 214 215 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64); 216 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); 217 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64); 218 219 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0)); 220 221 /* (8) Enable packet reception */ 222 xauiMiscCtl.s.gmxeno = 0; 223 cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); 224 225 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); 226 gmx_cfg.s.en = 1; 227 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); 228 229 __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface); 230 __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface); 231 __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface); 232 __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface); 233 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface); 234 __cvmx_interrupt_gmxx_enable(interface); 235 236 return 0; 237} 238 239/** 240 * Return the link state of an IPD/PKO port as returned by 241 * auto negotiation. The result of this function may not match 242 * Octeon's link config if auto negotiation has changed since 243 * the last call to cvmx_helper_link_set(). 244 * 245 * @ipd_port: IPD/PKO port to query 246 * 247 * Returns Link state 248 */ 249cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port) 250{ 251 int interface = cvmx_helper_get_interface_num(ipd_port); 252 union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; 253 union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; 254 union cvmx_pcsxx_status1_reg pcsxx_status1_reg; 255 cvmx_helper_link_info_t result; 256 257 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); 258 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); 259 pcsxx_status1_reg.u64 = 260 cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface)); 261 result.u64 = 0; 262 263 /* Only return a link if both RX and TX are happy */ 264 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) && 265 (pcsxx_status1_reg.s.rcv_lnk == 1)) { 266 result.s.link_up = 1; 267 result.s.full_duplex = 1; 268 result.s.speed = 10000; 269 } else { 270 /* Disable GMX and PCSX interrupts. */ 271 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); 272 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); 273 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); 274 } 275 return result; 276} 277 278/** 279 * Configure an IPD/PKO port for the specified link state. This 280 * function does not influence auto negotiation at the PHY level. 281 * The passed link state must always match the link state returned 282 * by cvmx_helper_link_get(). It is normally best to use 283 * cvmx_helper_link_autoconf() instead. 284 * 285 * @ipd_port: IPD/PKO port to configure 286 * @link_info: The new link state 287 * 288 * Returns Zero on success, negative on failure 289 */ 290int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 291{ 292 int interface = cvmx_helper_get_interface_num(ipd_port); 293 union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; 294 union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; 295 296 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); 297 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); 298 299 /* If the link shouldn't be up, then just return */ 300 if (!link_info.s.link_up) 301 return 0; 302 303 /* Do nothing if both RX and TX are happy */ 304 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0)) 305 return 0; 306 307 /* Bring the link up */ 308 return __cvmx_helper_xaui_enable(interface); 309} 310 311/** 312 * Configure a port for internal and/or external loopback. Internal loopback 313 * causes packets sent by the port to be received by Octeon. External loopback 314 * causes packets received from the wire to sent out again. 315 * 316 * @ipd_port: IPD/PKO port to loopback. 317 * @enable_internal: 318 * Non zero if you want internal loopback 319 * @enable_external: 320 * Non zero if you want external loopback 321 * 322 * Returns Zero on success, negative on failure. 323 */ 324extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, 325 int enable_internal, 326 int enable_external) 327{ 328 int interface = cvmx_helper_get_interface_num(ipd_port); 329 union cvmx_pcsxx_control1_reg pcsxx_control1_reg; 330 union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback; 331 332 /* Set the internal loop */ 333 pcsxx_control1_reg.u64 = 334 cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); 335 pcsxx_control1_reg.s.loopbck1 = enable_internal; 336 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), 337 pcsxx_control1_reg.u64); 338 339 /* Set the external loop */ 340 gmxx_xaui_ext_loopback.u64 = 341 cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface)); 342 gmxx_xaui_ext_loopback.s.en = enable_external; 343 cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), 344 gmxx_xaui_ext_loopback.u64); 345 346 /* Take the link through a reset */ 347 return __cvmx_helper_xaui_enable(interface); 348} 349