1139749Simp/***********************license start***************
2119853Scg * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
364064Scg * reserved.
464064Scg *
564064Scg *
664064Scg * Redistribution and use in source and binary forms, with or without
764064Scg * modification, are permitted provided that the following conditions are
864064Scg * met:
964064Scg *
1064064Scg *   * Redistributions of source code must retain the above copyright
1164064Scg *     notice, this list of conditions and the following disclaimer.
1264064Scg *
1364064Scg *   * Redistributions in binary form must reproduce the above
1464064Scg *     copyright notice, this list of conditions and the following
1564064Scg *     disclaimer in the documentation and/or other materials provided
1664064Scg *     with the distribution.
1764064Scg
1864064Scg *   * Neither the name of Cavium Inc. nor the names of
1964064Scg *     its contributors may be used to endorse or promote products
2064064Scg *     derived from this software without specific prior written
2164064Scg *     permission.
2264064Scg
2364064Scg * This Software, including technical data, may be subject to U.S. export  control
2464064Scg * laws, including the U.S. Export Administration Act and its  associated
2564064Scg * regulations, and may be subject to export or import  regulations in other
26193640Sariff * countries.
27193640Sariff
28193640Sariff * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29193640Sariff * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
3064064Scg * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
3164064Scg * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32119287Simp * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33119287Simp * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
3464064Scg * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
3564064Scg * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
3664064Scg * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
3764064Scg * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
3870134Scg ***********************license end**************************************/
3970134Scg
4082180Scg
4182180Scg
4284658Scg
4364064Scg
4464064Scg
4564163Snsayer
46154881Sariff/**
4764064Scg * @file
4864064Scg *
4964064Scg * Functions for XAUI initialization, configuration,
5064064Scg * and monitoring.
51154066Sariff *
52154066Sariff * <hr>$Revision: 70030 $<hr>
53154066Sariff */
5464881Scg#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55193640Sariff#include <asm/octeon/cvmx.h>
56193640Sariff#include <asm/octeon/cvmx-config.h>
57193640Sariff#ifdef CVMX_ENABLE_PKO_FUNCTIONS
58193640Sariff#include <asm/octeon/cvmx-qlm.h>
59193640Sariff#include <asm/octeon/cvmx-helper.h>
60193640Sariff#include <asm/octeon/cvmx-helper-cfg.h>
61193640Sariff#endif
62193640Sariff#include <asm/octeon/cvmx-gmxx-defs.h>
6364881Scg#include <asm/octeon/cvmx-pko-defs.h>
6464064Scg#include <asm/octeon/cvmx-pcsx-defs.h>
65154024Sariff#include <asm/octeon/cvmx-pcsxx-defs.h>
6664064Scg#include <asm/octeon/cvmx-ciu-defs.h>
6764163Snsayer#else
6864163Snsayer#if !defined(__FreeBSD__) || !defined(_KERNEL)
6964163Snsayer#include "executive-config.h"
7064881Scg#include "cvmx-config.h"
71193640Sariff
72193640Sariff#ifdef CVMX_ENABLE_PKO_FUNCTIONS
73193640Sariff
74193640Sariff#include "cvmx.h"
75193640Sariff#include "cvmx-helper.h"
76193640Sariff#include "cvmx-helper-cfg.h"
77193640Sariff#include "cvmx-qlm.h"
78193640Sariff#endif
7964881Scg#else
8064064Scg#include "cvmx.h"
81154024Sariff#include "cvmx-helper.h"
8264064Scg#include "cvmx-qlm.h"
8364064Scg#endif
8464064Scg#endif
8564064Scg
8664064Scg#ifdef CVMX_ENABLE_PKO_FUNCTIONS
8774763Scg
8874763Scgint __cvmx_helper_xaui_enumerate(int interface)
8964064Scg{
9070291Scg	union cvmx_gmxx_hg2_control gmx_hg2_control;
9164064Scg
9264064Scg	/* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
9364064Scg	gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
9464064Scg	if (gmx_hg2_control.s.hg2tx_en)
9564064Scg		return 16;
9665644Scg	else
9764064Scg		return 1;
9864064Scg}
99170032Sariff
100170032Sariff/**
10184658Scg * @INTERNAL
10284658Scg * Probe a XAUI interface and determine the number of ports
10364064Scg * connected to it. The XAUI interface should still be down
104154066Sariff * after this call.
105154066Sariff *
106154066Sariff * @param interface Interface to probe
10764064Scg *
10864064Scg * @return Number of ports on the interface. Zero to disable.
109154066Sariff */
110154066Sariffint __cvmx_helper_xaui_probe(int interface)
111154066Sariff{
112154066Sariff    int i;
113154066Sariff    cvmx_gmxx_inf_mode_t mode;
114154066Sariff
115154066Sariff    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
116154066Sariff    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
117154066Sariff    {
118154066Sariff        cvmx_ciu_qlm2_t ciu_qlm;
11964064Scg        ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
12064064Scg        ciu_qlm.s.txbypass = 1;
12164064Scg        ciu_qlm.s.txdeemph = 0x5;
12264064Scg        ciu_qlm.s.txmargin = 0x1a;
12364064Scg        cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
12464064Scg    }
12564064Scg
12664064Scg    /* CN63XX Pass 2.0 and 2.1 errata G-15273 requires the QLM De-emphasis be
12764064Scg        programmed when using a 156.25Mhz ref clock */
12864064Scg    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) ||
12964064Scg        OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1))
13064064Scg    {
13164064Scg        /* Read the QLM speed pins */
13264064Scg        cvmx_mio_rst_boot_t mio_rst_boot;
13364064Scg        mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
13464064Scg
13564064Scg        if (mio_rst_boot.cn63xx.qlm2_spd == 0xb)
13664064Scg        {
13764064Scg            cvmx_ciu_qlm2_t ciu_qlm;
13864064Scg            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
13964064Scg            ciu_qlm.s.txbypass = 1;
14064064Scg            ciu_qlm.s.txdeemph = 0xa;
14164064Scg            ciu_qlm.s.txmargin = 0x1f;
14264064Scg            cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
14364064Scg        }
14464064Scg    }
14564064Scg
14664064Scg    /* Check if QLM is configured correct for XAUI/RXAUI, verify the
14764064Scg       speed as well as mode */
14864064Scg    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
14964064Scg    {
15064064Scg        int qlm, status;
15164064Scg
15264064Scg        qlm = cvmx_qlm_interface(interface);
15364064Scg        status = cvmx_qlm_get_status(qlm);
15464064Scg        if (status != 2 && status != 10)
15564064Scg            return 0;
15664064Scg    }
15764064Scg
15864064Scg    /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
15964064Scg        needs to be enabled before IPD otherwise per port backpressure
16064064Scg        may not work properly */
16164064Scg    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
16264064Scg    mode.s.en = 1;
16364064Scg    cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
16464064Scg
16564064Scg    __cvmx_helper_setup_gmx(interface, 1);
16664064Scg
16764064Scg    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
16864064Scg    {
16964064Scg	/* Setup PKO to support 16 ports for HiGig2 virtual ports. We're pointing
17064064Scg	    all of the PKO packet ports for this interface to the XAUI. This allows
17164064Scg	    us to use HiGig2 backpressure per port */
17264064Scg	for (i=0; i<16; i++)
17364064Scg	{
17464064Scg	    cvmx_pko_mem_port_ptrs_t pko_mem_port_ptrs;
17564064Scg	    pko_mem_port_ptrs.u64 = 0;
17664064Scg	    /* We set each PKO port to have equal priority in a round robin
17764064Scg	        fashion */
17864064Scg	    pko_mem_port_ptrs.s.static_p = 0;
17964064Scg	    pko_mem_port_ptrs.s.qos_mask = 0xff;
18064064Scg	    /* All PKO ports map to the same XAUI hardware port */
18164064Scg	    pko_mem_port_ptrs.s.eid = interface*4;
18264064Scg	    pko_mem_port_ptrs.s.pid = interface*16 + i;
18364064Scg	    cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
18464064Scg	}
18564064Scg    }
18664064Scg
18764064Scg    return __cvmx_helper_xaui_enumerate(interface);
18864064Scg}
18964064Scg
19064064Scg/**
19164064Scg * @INTERNAL
19264064Scg * Bringup XAUI interface. After this call packet I/O should be
19364064Scg * fully functional.
19464064Scg *
19564064Scg * @param interface Interface to bring up
19664064Scg *
19764064Scg * @return Zero on success, negative on failure
19864064Scg */
19964064Scgstatic int __cvmx_helper_xaui_link_init(int interface)
20064064Scg{
20164064Scg    cvmx_gmxx_prtx_cfg_t          gmx_cfg;
20264064Scg    cvmx_pcsxx_control1_reg_t     xauiCtl;
20364064Scg    cvmx_pcsxx_misc_ctl_reg_t     xauiMiscCtl;
20464064Scg    cvmx_gmxx_tx_xaui_ctl_t       gmxXauiTxCtl;
20564064Scg
20664064Scg    /* (1) Interface has already been enabled. */
20764064Scg
20864064Scg    /* (2) Disable GMX. */
20964064Scg    xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
21064064Scg    xauiMiscCtl.s.gmxeno = 1;
21164064Scg    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
21264064Scg
21364064Scg    /* (3) Disable GMX and PCSX interrupts. */
21464064Scg    cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
21564064Scg    cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
21664064Scg    cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
21764064Scg
21864064Scg    /* (4) Bring up the PCSX and GMX reconciliation layer. */
21964064Scg    /* (4)a Set polarity and lane swapping. */
22064064Scg    /* (4)b */
22164064Scg    gmxXauiTxCtl.u64 = cvmx_read_csr (CVMX_GMXX_TX_XAUI_CTL(interface));
22264064Scg    gmxXauiTxCtl.s.dic_en = 1; /* Enable better IFG packing and improves performance */
22364064Scg    gmxXauiTxCtl.s.uni_en = 0;
22464064Scg    cvmx_write_csr (CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
22564064Scg
22664064Scg    /* (4)c Aply reset sequence */
22764140Snsayer    xauiCtl.u64 = cvmx_read_csr (CVMX_PCSXX_CONTROL1_REG(interface));
22864064Scg    xauiCtl.s.lo_pwr = 0;
22964064Scg
23064064Scg    /* Errata G-15618 requires disabling PCS soft reset in some OCTEON II models. */
23164064Scg    if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)
23264064Scg        && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)
23364064Scg        && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1)
23464140Snsayer        && !OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X)
23564064Scg        && !OCTEON_IS_MODEL(OCTEON_CN68XX))
23664064Scg        xauiCtl.s.reset  = 1;
23764064Scg    cvmx_write_csr (CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
23864064Scg
23964064Scg    /* Wait for PCS to come out of reset */
24064064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_CONTROL1_REG(interface), cvmx_pcsxx_control1_reg_t, reset, ==, 0, 10000))
24164064Scg        return -1;
24264064Scg    /* Wait for PCS to be aligned */
24364064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_10GBX_STATUS_REG(interface), cvmx_pcsxx_10gbx_status_reg_t, alignd, ==, 1, 10000))
24464064Scg        return -1;
24564064Scg    /* Wait for RX to be ready */
24664064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_RX_XAUI_CTL(interface), cvmx_gmxx_rx_xaui_ctl_t, status, ==, 0, 10000))
24764064Scg        return -1;
24864064Scg
24964064Scg    /* (6) Configure GMX */
25064064Scg
25164064Scg    /* Wait for GMX RX to be idle */
25264064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000))
25364064Scg        return -1;
25464064Scg    /* Wait for GMX TX to be idle */
25564064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
25664064Scg        return -1;
25764064Scg
25864064Scg    /* GMX configure */
25964064Scg    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
26064064Scg    gmx_cfg.s.speed = 1;
26164064Scg    gmx_cfg.s.speed_msb = 0;
26264064Scg    gmx_cfg.s.slottime = 1;
26364064Scg    cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
26464064Scg    cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
26564064Scg    cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
26664064Scg    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
26764064Scg
26864064Scg    /* Wait for receive link */
26964447Snsayer    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS1_REG(interface), cvmx_pcsxx_status1_reg_t, rcv_lnk, ==, 1, 10000))
27064064Scg        return -1;
27164064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, xmtflt, ==, 0, 10000))
27264064Scg        return -1;
27364064Scg    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, rcvflt, ==, 0, 10000))
27464064Scg        return -1;
27564064Scg
27664064Scg    /* (8) Enable packet reception */
27764064Scg    xauiMiscCtl.s.gmxeno = 0;
27864064Scg    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
27964064Scg
28064064Scg    /* Clear all error interrupts before enabling the interface. */
28164064Scg    cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0,interface), ~0x0ull);
28264064Scg    cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), ~0x0ull);
28364064Scg    cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), ~0x0ull);
28464064Scg
28564064Scg    /* Enable GMX */
28664064Scg    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
28764064Scg    gmx_cfg.s.en = 1;
28864064Scg    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
28964064Scg
29064064Scg    return 0;
29164064Scg}
29264140Snsayer
29364064Scg/**
29464064Scg * @INTERNAL
29564064Scg * Bringup and enable a XAUI interface. After this call packet
29664064Scg * I/O should be fully functional. This is called with IPD
29764140Snsayer * enabled but PKO disabled.
29864140Snsayer *
29964064Scg * @param interface Interface to bring up
30064140Snsayer *
30164064Scg * @return Zero on success, negative on failure
30264064Scg */
30364064Scgint __cvmx_helper_xaui_enable(int interface)
30464064Scg{
30564064Scg    /* Setup PKND and BPID */
30664064Scg    if (octeon_has_feature(OCTEON_FEATURE_PKND))
30764064Scg    {
30864064Scg        cvmx_gmxx_bpid_msk_t bpid_msk;
30964064Scg        cvmx_gmxx_bpid_mapx_t bpid_map;
31064064Scg        cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
31164163Snsayer        cvmx_gmxx_txx_append_t gmxx_txx_append_cfg;
31264064Scg
313154066Sariff        /* Setup PKIND */
31464064Scg        gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
31564064Scg        gmxx_prtx_cfg.s.pknd = cvmx_helper_get_pknd(interface, 0);
31664064Scg        cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmxx_prtx_cfg.u64);
31764064Scg
31864064Scg        /* Setup BPID */
31964064Scg        bpid_map.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MAPX(0, interface));
320160127Syongari        bpid_map.s.val = 1;
321160127Syongari        bpid_map.s.bpid = cvmx_helper_get_bpid(interface, 0);
32264846Scg        cvmx_write_csr(CVMX_GMXX_BPID_MAPX(0, interface), bpid_map.u64);
323160127Syongari
32464846Scg        bpid_msk.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MSK(interface));
32564163Snsayer        bpid_msk.s.msk_or |= 1;
32664163Snsayer        bpid_msk.s.msk_and &= ~1;
32764163Snsayer        cvmx_write_csr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64);
32864163Snsayer
32964163Snsayer        /* CN68XX adds the padding and FCS in PKO, not GMX */
33064163Snsayer        gmxx_txx_append_cfg.u64 = cvmx_read_csr(CVMX_GMXX_TXX_APPEND(0, interface));
33164163Snsayer        gmxx_txx_append_cfg.s.fcs = 0;
33264163Snsayer        gmxx_txx_append_cfg.s.pad = 0;
33364163Snsayer        cvmx_write_csr(CVMX_GMXX_TXX_APPEND(0, interface), gmxx_txx_append_cfg.u64);
33464163Snsayer    }
33564163Snsayer
33664064Scg    __cvmx_helper_xaui_link_init(interface);
33764140Snsayer
33864140Snsayer    return 0;
33964064Scg}
34064064Scg
34164064Scg/**
34264064Scg * @INTERNAL
34364064Scg * Return the link state of an IPD/PKO port as returned by
34464064Scg * auto negotiation. The result of this function may not match
34564064Scg * Octeon's link config if auto negotiation has changed since
34664064Scg * the last call to cvmx_helper_link_set().
34764064Scg *
348154066Sariff * @param ipd_port IPD/PKO port to query
34964064Scg *
350154066Sariff * @return Link state
35164064Scg */
35264064Scgcvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
35364064Scg{
35464064Scg    int interface = cvmx_helper_get_interface_num(ipd_port);
35564064Scg    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
35664064Scg    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
35764064Scg    cvmx_pcsxx_status1_reg_t pcsxx_status1_reg;
35864064Scg    cvmx_helper_link_info_t result;
35964064Scg
360154066Sariff    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
36164064Scg    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
362154066Sariff    pcsxx_status1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
36364064Scg    result.u64 = 0;
36464064Scg
36564064Scg    /* Only return a link if both RX and TX are happy */
36664064Scg    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
36764064Scg        (pcsxx_status1_reg.s.rcv_lnk == 1))
36864064Scg    {
369154066Sariff        cvmx_pcsxx_misc_ctl_reg_t misc_ctl;
370154066Sariff        result.s.link_up = 1;
37164064Scg        result.s.full_duplex = 1;
37264064Scg        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
37364064Scg        {
37464064Scg            cvmx_mio_qlmx_cfg_t qlm_cfg;
37564064Scg            int lanes;
37664064Scg            int qlm = (interface == 1) ? 0 : interface;
37764064Scg
37864064Scg            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
37964064Scg            result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
38064064Scg            lanes = (qlm_cfg.s.qlm_cfg == 7) ? 2 : 4;
38164064Scg            result.s.speed *= lanes;
38264064Scg        }
38364064Scg        else if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
38464064Scg        {
38564064Scg            int qlm = cvmx_qlm_interface(interface);
38664064Scg            result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
38764064Scg            result.s.speed *= 4;
38864064Scg        }
38964064Scg        else
39064064Scg            result.s.speed = 10000;
39164064Scg        misc_ctl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
39264064Scg        if (misc_ctl.s.gmxeno)
39364064Scg            __cvmx_helper_xaui_link_init(interface);
39464064Scg    }
39564064Scg    else
39664064Scg    {
39764064Scg        /* Disable GMX and PCSX interrupts. */
39864064Scg        cvmx_write_csr (CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
39964064Scg        cvmx_write_csr (CVMX_GMXX_TX_INT_EN(interface), 0x0);
40064064Scg        cvmx_write_csr (CVMX_PCSXX_INT_EN_REG(interface), 0x0);
40164064Scg    }
40264064Scg    return result;
40364064Scg}
40464064Scg
40564064Scg
40664064Scg/**
40764064Scg * @INTERNAL
40864064Scg * Configure an IPD/PKO port for the specified link state. This
40964064Scg * function does not influence auto negotiation at the PHY level.
41064064Scg * The passed link state must always match the link state returned
41164064Scg * by cvmx_helper_link_get(). It is normally best to use
41264064Scg * cvmx_helper_link_autoconf() instead.
41364064Scg *
41464064Scg * @param ipd_port  IPD/PKO port to configure
41564064Scg * @param link_info The new link state
41664064Scg *
41764064Scg * @return Zero on success, negative on failure
41864064Scg */
41964064Scgint __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
42064064Scg{
42164064Scg    int interface = cvmx_helper_get_interface_num(ipd_port);
42264064Scg    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
42364064Scg    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
42464064Scg
42564064Scg    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
42664064Scg    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
42764064Scg
42864064Scg    /* If the link shouldn't be up, then just return */
42964064Scg    if (!link_info.s.link_up)
43064064Scg        return 0;
431193640Sariff
432193640Sariff    /* Do nothing if both RX and TX are happy */
43364064Scg    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
43464064Scg        return 0;
43564140Snsayer
43664064Scg    /* Bring the link up */
43764064Scg    return __cvmx_helper_xaui_link_init(interface);
43864163Snsayer}
43964163Snsayer
44064064Scg
44164064Scg/**
44264064Scg * @INTERNAL
44364064Scg * Configure a port for internal and/or external loopback. Internal loopback
44464064Scg * causes packets sent by the port to be received by Octeon. External loopback
44564064Scg * causes packets received from the wire to sent out again.
44664064Scg *
44764064Scg * @param ipd_port IPD/PKO port to loopback.
44864140Snsayer * @param enable_internal
44964064Scg *                 Non zero if you want internal loopback
45064064Scg * @param enable_external
45164064Scg *                 Non zero if you want external loopback
45264064Scg *
45364064Scg * @return Zero on success, negative on failure.
45464064Scg */
45564064Scgextern int __cvmx_helper_xaui_configure_loopback(int ipd_port, int enable_internal, int enable_external)
45664064Scg{
45764064Scg    int interface = cvmx_helper_get_interface_num(ipd_port);
45864064Scg    cvmx_pcsxx_control1_reg_t pcsxx_control1_reg;
45964064Scg    cvmx_gmxx_xaui_ext_loopback_t gmxx_xaui_ext_loopback;
46064064Scg
46164064Scg    /* Set the internal loop */
46264064Scg    pcsxx_control1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
46364064Scg    pcsxx_control1_reg.s.loopbck1 = enable_internal;
46464064Scg    cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), pcsxx_control1_reg.u64);
46564064Scg
46664064Scg    /* Set the external loop */
46764140Snsayer    gmxx_xaui_ext_loopback.u64 = cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
46864064Scg    gmxx_xaui_ext_loopback.s.en = enable_external;
46964064Scg    cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), gmxx_xaui_ext_loopback.u64);
47064064Scg
47164064Scg    /* Take the link through a reset */
47264064Scg    return __cvmx_helper_xaui_link_init(interface);
47364064Scg}
47464064Scg
47564064Scg#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
47664064Scg
47764064Scg