1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Functions for XAUI initialization, configuration,
50210284Sjmallett * and monitoring.
51210284Sjmallett *
52232812Sjmallett * <hr>$Revision: 70030 $<hr>
53210284Sjmallett */
54215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55215990Sjmallett#include <asm/octeon/cvmx.h>
56215990Sjmallett#include <asm/octeon/cvmx-config.h>
57215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
58232812Sjmallett#include <asm/octeon/cvmx-qlm.h>
59215990Sjmallett#include <asm/octeon/cvmx-helper.h>
60232812Sjmallett#include <asm/octeon/cvmx-helper-cfg.h>
61215990Sjmallett#endif
62215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h>
63215990Sjmallett#include <asm/octeon/cvmx-pko-defs.h>
64232812Sjmallett#include <asm/octeon/cvmx-pcsx-defs.h>
65215990Sjmallett#include <asm/octeon/cvmx-pcsxx-defs.h>
66215990Sjmallett#include <asm/octeon/cvmx-ciu-defs.h>
67215990Sjmallett#else
68215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
69215990Sjmallett#include "executive-config.h"
70215990Sjmallett#include "cvmx-config.h"
71215990Sjmallett
72215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
73215990Sjmallett
74210284Sjmallett#include "cvmx.h"
75210284Sjmallett#include "cvmx-helper.h"
76232812Sjmallett#include "cvmx-helper-cfg.h"
77232812Sjmallett#include "cvmx-qlm.h"
78215990Sjmallett#endif
79215990Sjmallett#else
80215990Sjmallett#include "cvmx.h"
81215990Sjmallett#include "cvmx-helper.h"
82232812Sjmallett#include "cvmx-qlm.h"
83215990Sjmallett#endif
84215990Sjmallett#endif
85210284Sjmallett
86210311Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
87215990Sjmallett
88232812Sjmallettint __cvmx_helper_xaui_enumerate(int interface)
89232812Sjmallett{
90232812Sjmallett	union cvmx_gmxx_hg2_control gmx_hg2_control;
91215990Sjmallett
92232812Sjmallett	/* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
93232812Sjmallett	gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
94232812Sjmallett	if (gmx_hg2_control.s.hg2tx_en)
95232812Sjmallett		return 16;
96232812Sjmallett	else
97232812Sjmallett		return 1;
98232812Sjmallett}
99232812Sjmallett
100210284Sjmallett/**
101210284Sjmallett * @INTERNAL
102210284Sjmallett * Probe a XAUI interface and determine the number of ports
103210284Sjmallett * connected to it. The XAUI interface should still be down
104210284Sjmallett * after this call.
105210284Sjmallett *
106210284Sjmallett * @param interface Interface to probe
107210284Sjmallett *
108210284Sjmallett * @return Number of ports on the interface. Zero to disable.
109210284Sjmallett */
110210284Sjmallettint __cvmx_helper_xaui_probe(int interface)
111210284Sjmallett{
112210284Sjmallett    int i;
113210284Sjmallett    cvmx_gmxx_inf_mode_t mode;
114210284Sjmallett
115215990Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
116215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
117215990Sjmallett    {
118215990Sjmallett        cvmx_ciu_qlm2_t ciu_qlm;
119215990Sjmallett        ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
120215990Sjmallett        ciu_qlm.s.txbypass = 1;
121215990Sjmallett        ciu_qlm.s.txdeemph = 0x5;
122215990Sjmallett        ciu_qlm.s.txmargin = 0x1a;
123215990Sjmallett        cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
124215990Sjmallett    }
125215990Sjmallett
126232812Sjmallett    /* CN63XX Pass 2.0 and 2.1 errata G-15273 requires the QLM De-emphasis be
127232812Sjmallett        programmed when using a 156.25Mhz ref clock */
128232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) ||
129232812Sjmallett        OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1))
130232812Sjmallett    {
131232812Sjmallett        /* Read the QLM speed pins */
132232812Sjmallett        cvmx_mio_rst_boot_t mio_rst_boot;
133232812Sjmallett        mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
134232812Sjmallett
135232812Sjmallett        if (mio_rst_boot.cn63xx.qlm2_spd == 0xb)
136232812Sjmallett        {
137232812Sjmallett            cvmx_ciu_qlm2_t ciu_qlm;
138232812Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
139232812Sjmallett            ciu_qlm.s.txbypass = 1;
140232812Sjmallett            ciu_qlm.s.txdeemph = 0xa;
141232812Sjmallett            ciu_qlm.s.txmargin = 0x1f;
142232812Sjmallett            cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
143232812Sjmallett        }
144232812Sjmallett    }
145232812Sjmallett
146232812Sjmallett    /* Check if QLM is configured correct for XAUI/RXAUI, verify the
147232812Sjmallett       speed as well as mode */
148232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
149232812Sjmallett    {
150232812Sjmallett        int qlm, status;
151232812Sjmallett
152232812Sjmallett        qlm = cvmx_qlm_interface(interface);
153232812Sjmallett        status = cvmx_qlm_get_status(qlm);
154232812Sjmallett        if (status != 2 && status != 10)
155232812Sjmallett            return 0;
156232812Sjmallett    }
157232812Sjmallett
158210284Sjmallett    /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
159210284Sjmallett        needs to be enabled before IPD otherwise per port backpressure
160210284Sjmallett        may not work properly */
161210284Sjmallett    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
162210284Sjmallett    mode.s.en = 1;
163210284Sjmallett    cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
164210284Sjmallett
165210284Sjmallett    __cvmx_helper_setup_gmx(interface, 1);
166210284Sjmallett
167232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
168210284Sjmallett    {
169232812Sjmallett	/* Setup PKO to support 16 ports for HiGig2 virtual ports. We're pointing
170232812Sjmallett	    all of the PKO packet ports for this interface to the XAUI. This allows
171232812Sjmallett	    us to use HiGig2 backpressure per port */
172232812Sjmallett	for (i=0; i<16; i++)
173232812Sjmallett	{
174232812Sjmallett	    cvmx_pko_mem_port_ptrs_t pko_mem_port_ptrs;
175232812Sjmallett	    pko_mem_port_ptrs.u64 = 0;
176232812Sjmallett	    /* We set each PKO port to have equal priority in a round robin
177232812Sjmallett	        fashion */
178232812Sjmallett	    pko_mem_port_ptrs.s.static_p = 0;
179232812Sjmallett	    pko_mem_port_ptrs.s.qos_mask = 0xff;
180232812Sjmallett	    /* All PKO ports map to the same XAUI hardware port */
181232812Sjmallett	    pko_mem_port_ptrs.s.eid = interface*4;
182232812Sjmallett	    pko_mem_port_ptrs.s.pid = interface*16 + i;
183232812Sjmallett	    cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
184232812Sjmallett	}
185210284Sjmallett    }
186210284Sjmallett
187232812Sjmallett    return __cvmx_helper_xaui_enumerate(interface);
188210284Sjmallett}
189210284Sjmallett
190210284Sjmallett/**
191210284Sjmallett * @INTERNAL
192232812Sjmallett * Bringup XAUI interface. After this call packet I/O should be
193232812Sjmallett * fully functional.
194210284Sjmallett *
195210284Sjmallett * @param interface Interface to bring up
196210284Sjmallett *
197210284Sjmallett * @return Zero on success, negative on failure
198210284Sjmallett */
199232812Sjmallettstatic int __cvmx_helper_xaui_link_init(int interface)
200210284Sjmallett{
201210284Sjmallett    cvmx_gmxx_prtx_cfg_t          gmx_cfg;
202210284Sjmallett    cvmx_pcsxx_control1_reg_t     xauiCtl;
203210284Sjmallett    cvmx_pcsxx_misc_ctl_reg_t     xauiMiscCtl;
204210284Sjmallett    cvmx_gmxx_tx_xaui_ctl_t       gmxXauiTxCtl;
205210284Sjmallett
206210284Sjmallett    /* (1) Interface has already been enabled. */
207210284Sjmallett
208210284Sjmallett    /* (2) Disable GMX. */
209210284Sjmallett    xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
210210284Sjmallett    xauiMiscCtl.s.gmxeno = 1;
211210284Sjmallett    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
212210284Sjmallett
213210284Sjmallett    /* (3) Disable GMX and PCSX interrupts. */
214210284Sjmallett    cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
215210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
216210284Sjmallett    cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
217210284Sjmallett
218210284Sjmallett    /* (4) Bring up the PCSX and GMX reconciliation layer. */
219210284Sjmallett    /* (4)a Set polarity and lane swapping. */
220210284Sjmallett    /* (4)b */
221210284Sjmallett    gmxXauiTxCtl.u64 = cvmx_read_csr (CVMX_GMXX_TX_XAUI_CTL(interface));
222210284Sjmallett    gmxXauiTxCtl.s.dic_en = 1; /* Enable better IFG packing and improves performance */
223210284Sjmallett    gmxXauiTxCtl.s.uni_en = 0;
224210284Sjmallett    cvmx_write_csr (CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
225210284Sjmallett
226210284Sjmallett    /* (4)c Aply reset sequence */
227210284Sjmallett    xauiCtl.u64 = cvmx_read_csr (CVMX_PCSXX_CONTROL1_REG(interface));
228210284Sjmallett    xauiCtl.s.lo_pwr = 0;
229232812Sjmallett
230232812Sjmallett    /* Errata G-15618 requires disabling PCS soft reset in some OCTEON II models. */
231232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)
232232812Sjmallett        && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)
233232812Sjmallett        && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1)
234232812Sjmallett        && !OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X)
235232812Sjmallett        && !OCTEON_IS_MODEL(OCTEON_CN68XX))
236232812Sjmallett        xauiCtl.s.reset  = 1;
237210284Sjmallett    cvmx_write_csr (CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
238210284Sjmallett
239210284Sjmallett    /* Wait for PCS to come out of reset */
240210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_CONTROL1_REG(interface), cvmx_pcsxx_control1_reg_t, reset, ==, 0, 10000))
241210284Sjmallett        return -1;
242210284Sjmallett    /* Wait for PCS to be aligned */
243210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_10GBX_STATUS_REG(interface), cvmx_pcsxx_10gbx_status_reg_t, alignd, ==, 1, 10000))
244210284Sjmallett        return -1;
245210284Sjmallett    /* Wait for RX to be ready */
246210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_RX_XAUI_CTL(interface), cvmx_gmxx_rx_xaui_ctl_t, status, ==, 0, 10000))
247210284Sjmallett        return -1;
248210284Sjmallett
249210284Sjmallett    /* (6) Configure GMX */
250210284Sjmallett
251210284Sjmallett    /* Wait for GMX RX to be idle */
252210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000))
253210284Sjmallett        return -1;
254210284Sjmallett    /* Wait for GMX TX to be idle */
255210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
256210284Sjmallett        return -1;
257210284Sjmallett
258210284Sjmallett    /* GMX configure */
259210284Sjmallett    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
260210284Sjmallett    gmx_cfg.s.speed = 1;
261210284Sjmallett    gmx_cfg.s.speed_msb = 0;
262210284Sjmallett    gmx_cfg.s.slottime = 1;
263210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
264210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
265210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
266210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
267210284Sjmallett
268210284Sjmallett    /* Wait for receive link */
269210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS1_REG(interface), cvmx_pcsxx_status1_reg_t, rcv_lnk, ==, 1, 10000))
270210284Sjmallett        return -1;
271210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, xmtflt, ==, 0, 10000))
272210284Sjmallett        return -1;
273210284Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, rcvflt, ==, 0, 10000))
274210284Sjmallett        return -1;
275210284Sjmallett
276210284Sjmallett    /* (8) Enable packet reception */
277210284Sjmallett    xauiMiscCtl.s.gmxeno = 0;
278210284Sjmallett    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
279210284Sjmallett
280232812Sjmallett    /* Clear all error interrupts before enabling the interface. */
281232812Sjmallett    cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0,interface), ~0x0ull);
282232812Sjmallett    cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), ~0x0ull);
283232812Sjmallett    cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), ~0x0ull);
284232812Sjmallett
285232812Sjmallett    /* Enable GMX */
286210284Sjmallett    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
287210284Sjmallett    gmx_cfg.s.en = 1;
288210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
289215990Sjmallett
290232812Sjmallett    return 0;
291232812Sjmallett}
292215990Sjmallett
293232812Sjmallett/**
294232812Sjmallett * @INTERNAL
295232812Sjmallett * Bringup and enable a XAUI interface. After this call packet
296232812Sjmallett * I/O should be fully functional. This is called with IPD
297232812Sjmallett * enabled but PKO disabled.
298232812Sjmallett *
299232812Sjmallett * @param interface Interface to bring up
300232812Sjmallett *
301232812Sjmallett * @return Zero on success, negative on failure
302232812Sjmallett */
303232812Sjmallettint __cvmx_helper_xaui_enable(int interface)
304232812Sjmallett{
305232812Sjmallett    /* Setup PKND and BPID */
306232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
307232812Sjmallett    {
308232812Sjmallett        cvmx_gmxx_bpid_msk_t bpid_msk;
309232812Sjmallett        cvmx_gmxx_bpid_mapx_t bpid_map;
310232812Sjmallett        cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
311232812Sjmallett        cvmx_gmxx_txx_append_t gmxx_txx_append_cfg;
312232812Sjmallett
313232812Sjmallett        /* Setup PKIND */
314232812Sjmallett        gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
315232812Sjmallett        gmxx_prtx_cfg.s.pknd = cvmx_helper_get_pknd(interface, 0);
316232812Sjmallett        cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmxx_prtx_cfg.u64);
317232812Sjmallett
318232812Sjmallett        /* Setup BPID */
319232812Sjmallett        bpid_map.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MAPX(0, interface));
320232812Sjmallett        bpid_map.s.val = 1;
321232812Sjmallett        bpid_map.s.bpid = cvmx_helper_get_bpid(interface, 0);
322232812Sjmallett        cvmx_write_csr(CVMX_GMXX_BPID_MAPX(0, interface), bpid_map.u64);
323232812Sjmallett
324232812Sjmallett        bpid_msk.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MSK(interface));
325232812Sjmallett        bpid_msk.s.msk_or |= 1;
326232812Sjmallett        bpid_msk.s.msk_and &= ~1;
327232812Sjmallett        cvmx_write_csr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64);
328232812Sjmallett
329232812Sjmallett        /* CN68XX adds the padding and FCS in PKO, not GMX */
330232812Sjmallett        gmxx_txx_append_cfg.u64 = cvmx_read_csr(CVMX_GMXX_TXX_APPEND(0, interface));
331232812Sjmallett        gmxx_txx_append_cfg.s.fcs = 0;
332232812Sjmallett        gmxx_txx_append_cfg.s.pad = 0;
333232812Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_APPEND(0, interface), gmxx_txx_append_cfg.u64);
334232812Sjmallett    }
335232812Sjmallett
336232812Sjmallett    __cvmx_helper_xaui_link_init(interface);
337232812Sjmallett
338210284Sjmallett    return 0;
339210284Sjmallett}
340210284Sjmallett
341210284Sjmallett/**
342210284Sjmallett * @INTERNAL
343210284Sjmallett * Return the link state of an IPD/PKO port as returned by
344210284Sjmallett * auto negotiation. The result of this function may not match
345210284Sjmallett * Octeon's link config if auto negotiation has changed since
346210284Sjmallett * the last call to cvmx_helper_link_set().
347210284Sjmallett *
348210284Sjmallett * @param ipd_port IPD/PKO port to query
349210284Sjmallett *
350210284Sjmallett * @return Link state
351210284Sjmallett */
352210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
353210284Sjmallett{
354210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
355210284Sjmallett    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
356210284Sjmallett    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
357210284Sjmallett    cvmx_pcsxx_status1_reg_t pcsxx_status1_reg;
358210284Sjmallett    cvmx_helper_link_info_t result;
359210284Sjmallett
360210284Sjmallett    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
361210284Sjmallett    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
362210284Sjmallett    pcsxx_status1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
363210284Sjmallett    result.u64 = 0;
364210284Sjmallett
365210284Sjmallett    /* Only return a link if both RX and TX are happy */
366210284Sjmallett    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
367210284Sjmallett        (pcsxx_status1_reg.s.rcv_lnk == 1))
368210284Sjmallett    {
369232812Sjmallett        cvmx_pcsxx_misc_ctl_reg_t misc_ctl;
370210284Sjmallett        result.s.link_up = 1;
371210284Sjmallett        result.s.full_duplex = 1;
372232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
373232812Sjmallett        {
374232812Sjmallett            cvmx_mio_qlmx_cfg_t qlm_cfg;
375232812Sjmallett            int lanes;
376232812Sjmallett            int qlm = (interface == 1) ? 0 : interface;
377232812Sjmallett
378232812Sjmallett            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
379232812Sjmallett            result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
380232812Sjmallett            lanes = (qlm_cfg.s.qlm_cfg == 7) ? 2 : 4;
381232812Sjmallett            result.s.speed *= lanes;
382232812Sjmallett        }
383232812Sjmallett        else if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
384232812Sjmallett        {
385232812Sjmallett            int qlm = cvmx_qlm_interface(interface);
386232812Sjmallett            result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
387232812Sjmallett            result.s.speed *= 4;
388232812Sjmallett        }
389232812Sjmallett        else
390232812Sjmallett            result.s.speed = 10000;
391232812Sjmallett        misc_ctl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
392232812Sjmallett        if (misc_ctl.s.gmxeno)
393232812Sjmallett            __cvmx_helper_xaui_link_init(interface);
394210284Sjmallett    }
395210284Sjmallett    else
396210284Sjmallett    {
397210284Sjmallett        /* Disable GMX and PCSX interrupts. */
398210284Sjmallett        cvmx_write_csr (CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
399210284Sjmallett        cvmx_write_csr (CVMX_GMXX_TX_INT_EN(interface), 0x0);
400210284Sjmallett        cvmx_write_csr (CVMX_PCSXX_INT_EN_REG(interface), 0x0);
401210284Sjmallett    }
402210284Sjmallett    return result;
403210284Sjmallett}
404210284Sjmallett
405210284Sjmallett
406210284Sjmallett/**
407210284Sjmallett * @INTERNAL
408210284Sjmallett * Configure an IPD/PKO port for the specified link state. This
409210284Sjmallett * function does not influence auto negotiation at the PHY level.
410210284Sjmallett * The passed link state must always match the link state returned
411210284Sjmallett * by cvmx_helper_link_get(). It is normally best to use
412210284Sjmallett * cvmx_helper_link_autoconf() instead.
413210284Sjmallett *
414210284Sjmallett * @param ipd_port  IPD/PKO port to configure
415210284Sjmallett * @param link_info The new link state
416210284Sjmallett *
417210284Sjmallett * @return Zero on success, negative on failure
418210284Sjmallett */
419210284Sjmallettint __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
420210284Sjmallett{
421210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
422210284Sjmallett    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
423210284Sjmallett    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
424210284Sjmallett
425210284Sjmallett    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
426210284Sjmallett    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
427210284Sjmallett
428210284Sjmallett    /* If the link shouldn't be up, then just return */
429210284Sjmallett    if (!link_info.s.link_up)
430210284Sjmallett        return 0;
431210284Sjmallett
432210284Sjmallett    /* Do nothing if both RX and TX are happy */
433210284Sjmallett    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
434210284Sjmallett        return 0;
435232812Sjmallett
436210284Sjmallett    /* Bring the link up */
437232812Sjmallett    return __cvmx_helper_xaui_link_init(interface);
438210284Sjmallett}
439210284Sjmallett
440210284Sjmallett
441210284Sjmallett/**
442210284Sjmallett * @INTERNAL
443210284Sjmallett * Configure a port for internal and/or external loopback. Internal loopback
444210284Sjmallett * causes packets sent by the port to be received by Octeon. External loopback
445210284Sjmallett * causes packets received from the wire to sent out again.
446210284Sjmallett *
447210284Sjmallett * @param ipd_port IPD/PKO port to loopback.
448210284Sjmallett * @param enable_internal
449210284Sjmallett *                 Non zero if you want internal loopback
450210284Sjmallett * @param enable_external
451210284Sjmallett *                 Non zero if you want external loopback
452210284Sjmallett *
453210284Sjmallett * @return Zero on success, negative on failure.
454210284Sjmallett */
455210284Sjmallettextern int __cvmx_helper_xaui_configure_loopback(int ipd_port, int enable_internal, int enable_external)
456210284Sjmallett{
457210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
458210284Sjmallett    cvmx_pcsxx_control1_reg_t pcsxx_control1_reg;
459210284Sjmallett    cvmx_gmxx_xaui_ext_loopback_t gmxx_xaui_ext_loopback;
460210284Sjmallett
461210284Sjmallett    /* Set the internal loop */
462210284Sjmallett    pcsxx_control1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
463210284Sjmallett    pcsxx_control1_reg.s.loopbck1 = enable_internal;
464210284Sjmallett    cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), pcsxx_control1_reg.u64);
465210284Sjmallett
466210284Sjmallett    /* Set the external loop */
467210284Sjmallett    gmxx_xaui_ext_loopback.u64 = cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
468210284Sjmallett    gmxx_xaui_ext_loopback.s.en = enable_external;
469210284Sjmallett    cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), gmxx_xaui_ext_loopback.u64);
470210284Sjmallett
471210284Sjmallett    /* Take the link through a reset */
472232812Sjmallett    return __cvmx_helper_xaui_link_init(interface);
473210284Sjmallett}
474210284Sjmallett
475210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
476210284Sjmallett
477