1/***********************license start***************
2 * Copyright (c) 2003-2010  Cavium Inc. (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 Inc. 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 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40
41
42
43
44
45
46/**
47 * @file
48 *
49 * Functions for XAUI initialization, configuration,
50 * and monitoring.
51 *
52 * <hr>$Revision: 70030 $<hr>
53 */
54#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55#include <asm/octeon/cvmx.h>
56#include <asm/octeon/cvmx-config.h>
57#ifdef CVMX_ENABLE_PKO_FUNCTIONS
58#include <asm/octeon/cvmx-qlm.h>
59#include <asm/octeon/cvmx-helper.h>
60#include <asm/octeon/cvmx-helper-cfg.h>
61#endif
62#include <asm/octeon/cvmx-gmxx-defs.h>
63#include <asm/octeon/cvmx-pko-defs.h>
64#include <asm/octeon/cvmx-pcsx-defs.h>
65#include <asm/octeon/cvmx-pcsxx-defs.h>
66#include <asm/octeon/cvmx-ciu-defs.h>
67#else
68#if !defined(__FreeBSD__) || !defined(_KERNEL)
69#include "executive-config.h"
70#include "cvmx-config.h"
71
72#ifdef CVMX_ENABLE_PKO_FUNCTIONS
73
74#include "cvmx.h"
75#include "cvmx-helper.h"
76#include "cvmx-helper-cfg.h"
77#include "cvmx-qlm.h"
78#endif
79#else
80#include "cvmx.h"
81#include "cvmx-helper.h"
82#include "cvmx-qlm.h"
83#endif
84#endif
85
86#ifdef CVMX_ENABLE_PKO_FUNCTIONS
87
88int __cvmx_helper_xaui_enumerate(int interface)
89{
90	union cvmx_gmxx_hg2_control gmx_hg2_control;
91
92	/* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
93	gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
94	if (gmx_hg2_control.s.hg2tx_en)
95		return 16;
96	else
97		return 1;
98}
99
100/**
101 * @INTERNAL
102 * Probe a XAUI interface and determine the number of ports
103 * connected to it. The XAUI interface should still be down
104 * after this call.
105 *
106 * @param interface Interface to probe
107 *
108 * @return Number of ports on the interface. Zero to disable.
109 */
110int __cvmx_helper_xaui_probe(int interface)
111{
112    int i;
113    cvmx_gmxx_inf_mode_t mode;
114
115    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
116    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
117    {
118        cvmx_ciu_qlm2_t ciu_qlm;
119        ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
120        ciu_qlm.s.txbypass = 1;
121        ciu_qlm.s.txdeemph = 0x5;
122        ciu_qlm.s.txmargin = 0x1a;
123        cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
124    }
125
126    /* CN63XX Pass 2.0 and 2.1 errata G-15273 requires the QLM De-emphasis be
127        programmed when using a 156.25Mhz ref clock */
128    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) ||
129        OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1))
130    {
131        /* Read the QLM speed pins */
132        cvmx_mio_rst_boot_t mio_rst_boot;
133        mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
134
135        if (mio_rst_boot.cn63xx.qlm2_spd == 0xb)
136        {
137            cvmx_ciu_qlm2_t ciu_qlm;
138            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
139            ciu_qlm.s.txbypass = 1;
140            ciu_qlm.s.txdeemph = 0xa;
141            ciu_qlm.s.txmargin = 0x1f;
142            cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
143        }
144    }
145
146    /* Check if QLM is configured correct for XAUI/RXAUI, verify the
147       speed as well as mode */
148    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
149    {
150        int qlm, status;
151
152        qlm = cvmx_qlm_interface(interface);
153        status = cvmx_qlm_get_status(qlm);
154        if (status != 2 && status != 10)
155            return 0;
156    }
157
158    /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
159        needs to be enabled before IPD otherwise per port backpressure
160        may not work properly */
161    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
162    mode.s.en = 1;
163    cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
164
165    __cvmx_helper_setup_gmx(interface, 1);
166
167    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
168    {
169	/* Setup PKO to support 16 ports for HiGig2 virtual ports. We're pointing
170	    all of the PKO packet ports for this interface to the XAUI. This allows
171	    us to use HiGig2 backpressure per port */
172	for (i=0; i<16; i++)
173	{
174	    cvmx_pko_mem_port_ptrs_t pko_mem_port_ptrs;
175	    pko_mem_port_ptrs.u64 = 0;
176	    /* We set each PKO port to have equal priority in a round robin
177	        fashion */
178	    pko_mem_port_ptrs.s.static_p = 0;
179	    pko_mem_port_ptrs.s.qos_mask = 0xff;
180	    /* All PKO ports map to the same XAUI hardware port */
181	    pko_mem_port_ptrs.s.eid = interface*4;
182	    pko_mem_port_ptrs.s.pid = interface*16 + i;
183	    cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
184	}
185    }
186
187    return __cvmx_helper_xaui_enumerate(interface);
188}
189
190/**
191 * @INTERNAL
192 * Bringup XAUI interface. After this call packet I/O should be
193 * fully functional.
194 *
195 * @param interface Interface to bring up
196 *
197 * @return Zero on success, negative on failure
198 */
199static int __cvmx_helper_xaui_link_init(int interface)
200{
201    cvmx_gmxx_prtx_cfg_t          gmx_cfg;
202    cvmx_pcsxx_control1_reg_t     xauiCtl;
203    cvmx_pcsxx_misc_ctl_reg_t     xauiMiscCtl;
204    cvmx_gmxx_tx_xaui_ctl_t       gmxXauiTxCtl;
205
206    /* (1) Interface has already been enabled. */
207
208    /* (2) Disable GMX. */
209    xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
210    xauiMiscCtl.s.gmxeno = 1;
211    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
212
213    /* (3) Disable GMX and PCSX interrupts. */
214    cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
215    cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
216    cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
217
218    /* (4) Bring up the PCSX and GMX reconciliation layer. */
219    /* (4)a Set polarity and lane swapping. */
220    /* (4)b */
221    gmxXauiTxCtl.u64 = cvmx_read_csr (CVMX_GMXX_TX_XAUI_CTL(interface));
222    gmxXauiTxCtl.s.dic_en = 1; /* Enable better IFG packing and improves performance */
223    gmxXauiTxCtl.s.uni_en = 0;
224    cvmx_write_csr (CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
225
226    /* (4)c Aply reset sequence */
227    xauiCtl.u64 = cvmx_read_csr (CVMX_PCSXX_CONTROL1_REG(interface));
228    xauiCtl.s.lo_pwr = 0;
229
230    /* Errata G-15618 requires disabling PCS soft reset in some OCTEON II models. */
231    if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)
232        && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)
233        && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1)
234        && !OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X)
235        && !OCTEON_IS_MODEL(OCTEON_CN68XX))
236        xauiCtl.s.reset  = 1;
237    cvmx_write_csr (CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
238
239    /* Wait for PCS to come out of reset */
240    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_CONTROL1_REG(interface), cvmx_pcsxx_control1_reg_t, reset, ==, 0, 10000))
241        return -1;
242    /* Wait for PCS to be aligned */
243    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_10GBX_STATUS_REG(interface), cvmx_pcsxx_10gbx_status_reg_t, alignd, ==, 1, 10000))
244        return -1;
245    /* Wait for RX to be ready */
246    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_RX_XAUI_CTL(interface), cvmx_gmxx_rx_xaui_ctl_t, status, ==, 0, 10000))
247        return -1;
248
249    /* (6) Configure GMX */
250
251    /* Wait for GMX RX to be idle */
252    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000))
253        return -1;
254    /* Wait for GMX TX to be idle */
255    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
256        return -1;
257
258    /* GMX configure */
259    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
260    gmx_cfg.s.speed = 1;
261    gmx_cfg.s.speed_msb = 0;
262    gmx_cfg.s.slottime = 1;
263    cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
264    cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
265    cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
266    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
267
268    /* Wait for receive link */
269    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS1_REG(interface), cvmx_pcsxx_status1_reg_t, rcv_lnk, ==, 1, 10000))
270        return -1;
271    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, xmtflt, ==, 0, 10000))
272        return -1;
273    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, rcvflt, ==, 0, 10000))
274        return -1;
275
276    /* (8) Enable packet reception */
277    xauiMiscCtl.s.gmxeno = 0;
278    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
279
280    /* Clear all error interrupts before enabling the interface. */
281    cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0,interface), ~0x0ull);
282    cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), ~0x0ull);
283    cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), ~0x0ull);
284
285    /* Enable GMX */
286    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
287    gmx_cfg.s.en = 1;
288    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
289
290    return 0;
291}
292
293/**
294 * @INTERNAL
295 * Bringup and enable a XAUI interface. After this call packet
296 * I/O should be fully functional. This is called with IPD
297 * enabled but PKO disabled.
298 *
299 * @param interface Interface to bring up
300 *
301 * @return Zero on success, negative on failure
302 */
303int __cvmx_helper_xaui_enable(int interface)
304{
305    /* Setup PKND and BPID */
306    if (octeon_has_feature(OCTEON_FEATURE_PKND))
307    {
308        cvmx_gmxx_bpid_msk_t bpid_msk;
309        cvmx_gmxx_bpid_mapx_t bpid_map;
310        cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
311        cvmx_gmxx_txx_append_t gmxx_txx_append_cfg;
312
313        /* Setup PKIND */
314        gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
315        gmxx_prtx_cfg.s.pknd = cvmx_helper_get_pknd(interface, 0);
316        cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmxx_prtx_cfg.u64);
317
318        /* Setup BPID */
319        bpid_map.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MAPX(0, interface));
320        bpid_map.s.val = 1;
321        bpid_map.s.bpid = cvmx_helper_get_bpid(interface, 0);
322        cvmx_write_csr(CVMX_GMXX_BPID_MAPX(0, interface), bpid_map.u64);
323
324        bpid_msk.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MSK(interface));
325        bpid_msk.s.msk_or |= 1;
326        bpid_msk.s.msk_and &= ~1;
327        cvmx_write_csr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64);
328
329        /* CN68XX adds the padding and FCS in PKO, not GMX */
330        gmxx_txx_append_cfg.u64 = cvmx_read_csr(CVMX_GMXX_TXX_APPEND(0, interface));
331        gmxx_txx_append_cfg.s.fcs = 0;
332        gmxx_txx_append_cfg.s.pad = 0;
333        cvmx_write_csr(CVMX_GMXX_TXX_APPEND(0, interface), gmxx_txx_append_cfg.u64);
334    }
335
336    __cvmx_helper_xaui_link_init(interface);
337
338    return 0;
339}
340
341/**
342 * @INTERNAL
343 * Return the link state of an IPD/PKO port as returned by
344 * auto negotiation. The result of this function may not match
345 * Octeon's link config if auto negotiation has changed since
346 * the last call to cvmx_helper_link_set().
347 *
348 * @param ipd_port IPD/PKO port to query
349 *
350 * @return Link state
351 */
352cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
353{
354    int interface = cvmx_helper_get_interface_num(ipd_port);
355    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
356    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
357    cvmx_pcsxx_status1_reg_t pcsxx_status1_reg;
358    cvmx_helper_link_info_t result;
359
360    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
361    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
362    pcsxx_status1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
363    result.u64 = 0;
364
365    /* Only return a link if both RX and TX are happy */
366    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
367        (pcsxx_status1_reg.s.rcv_lnk == 1))
368    {
369        cvmx_pcsxx_misc_ctl_reg_t misc_ctl;
370        result.s.link_up = 1;
371        result.s.full_duplex = 1;
372        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
373        {
374            cvmx_mio_qlmx_cfg_t qlm_cfg;
375            int lanes;
376            int qlm = (interface == 1) ? 0 : interface;
377
378            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
379            result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
380            lanes = (qlm_cfg.s.qlm_cfg == 7) ? 2 : 4;
381            result.s.speed *= lanes;
382        }
383        else if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
384        {
385            int qlm = cvmx_qlm_interface(interface);
386            result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
387            result.s.speed *= 4;
388        }
389        else
390            result.s.speed = 10000;
391        misc_ctl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
392        if (misc_ctl.s.gmxeno)
393            __cvmx_helper_xaui_link_init(interface);
394    }
395    else
396    {
397        /* Disable GMX and PCSX interrupts. */
398        cvmx_write_csr (CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
399        cvmx_write_csr (CVMX_GMXX_TX_INT_EN(interface), 0x0);
400        cvmx_write_csr (CVMX_PCSXX_INT_EN_REG(interface), 0x0);
401    }
402    return result;
403}
404
405
406/**
407 * @INTERNAL
408 * Configure an IPD/PKO port for the specified link state. This
409 * function does not influence auto negotiation at the PHY level.
410 * The passed link state must always match the link state returned
411 * by cvmx_helper_link_get(). It is normally best to use
412 * cvmx_helper_link_autoconf() instead.
413 *
414 * @param ipd_port  IPD/PKO port to configure
415 * @param link_info The new link state
416 *
417 * @return Zero on success, negative on failure
418 */
419int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
420{
421    int interface = cvmx_helper_get_interface_num(ipd_port);
422    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
423    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
424
425    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
426    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
427
428    /* If the link shouldn't be up, then just return */
429    if (!link_info.s.link_up)
430        return 0;
431
432    /* Do nothing if both RX and TX are happy */
433    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
434        return 0;
435
436    /* Bring the link up */
437    return __cvmx_helper_xaui_link_init(interface);
438}
439
440
441/**
442 * @INTERNAL
443 * Configure a port for internal and/or external loopback. Internal loopback
444 * causes packets sent by the port to be received by Octeon. External loopback
445 * causes packets received from the wire to sent out again.
446 *
447 * @param ipd_port IPD/PKO port to loopback.
448 * @param enable_internal
449 *                 Non zero if you want internal loopback
450 * @param enable_external
451 *                 Non zero if you want external loopback
452 *
453 * @return Zero on success, negative on failure.
454 */
455extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, int enable_internal, int enable_external)
456{
457    int interface = cvmx_helper_get_interface_num(ipd_port);
458    cvmx_pcsxx_control1_reg_t pcsxx_control1_reg;
459    cvmx_gmxx_xaui_ext_loopback_t gmxx_xaui_ext_loopback;
460
461    /* Set the internal loop */
462    pcsxx_control1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
463    pcsxx_control1_reg.s.loopbck1 = enable_internal;
464    cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), pcsxx_control1_reg.u64);
465
466    /* Set the external loop */
467    gmxx_xaui_ext_loopback.u64 = cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
468    gmxx_xaui_ext_loopback.s.en = enable_external;
469    cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), gmxx_xaui_ext_loopback.u64);
470
471    /* Take the link through a reset */
472    return __cvmx_helper_xaui_link_init(interface);
473}
474
475#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
476
477