linux/drivers/staging/octeon/cvmx-helper-xaui.c
<<
>>
Prefs
   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