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 RGMII/GMII/MII 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
58215990Sjmallett#include <asm/octeon/cvmx-pko.h>
59215990Sjmallett#include <asm/octeon/cvmx-helper.h>
60215990Sjmallett#include <asm/octeon/cvmx-helper-board.h>
61215990Sjmallett#endif
62215990Sjmallett#include <asm/octeon/cvmx-asxx-defs.h>
63215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h>
64215990Sjmallett#include <asm/octeon/cvmx-pko-defs.h>
65215990Sjmallett#include <asm/octeon/cvmx-npi-defs.h>
66215990Sjmallett#include <asm/octeon/cvmx-dbg-defs.h>
67215990Sjmallett
68215990Sjmallett#else
69215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
70215990Sjmallett#include "executive-config.h"
71215990Sjmallett#include "cvmx-config.h"
72215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
73215990Sjmallett
74210284Sjmallett#include "cvmx.h"
75210284Sjmallett#include "cvmx-sysinfo.h"
76210284Sjmallett#include "cvmx-mdio.h"
77210284Sjmallett#include "cvmx-pko.h"
78210284Sjmallett#include "cvmx-helper.h"
79210284Sjmallett#include "cvmx-helper-board.h"
80215990Sjmallett#endif
81215990Sjmallett#else
82215990Sjmallett#include "cvmx.h"
83215990Sjmallett#include "cvmx-sysinfo.h"
84215990Sjmallett#include "cvmx-mdio.h"
85215990Sjmallett#include "cvmx-pko.h"
86215990Sjmallett#include "cvmx-helper.h"
87215990Sjmallett#include "cvmx-helper-board.h"
88215990Sjmallett#endif
89215990Sjmallett#endif
90210284Sjmallett
91210311Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
92215990Sjmallett
93210284Sjmallett/**
94210284Sjmallett * @INTERNAL
95210284Sjmallett * Probe RGMII ports and determine the number present
96210284Sjmallett *
97210284Sjmallett * @param interface Interface to probe
98210284Sjmallett *
99210284Sjmallett * @return Number of RGMII/GMII/MII ports (0-4).
100210284Sjmallett */
101210284Sjmallettint __cvmx_helper_rgmii_probe(int interface)
102210284Sjmallett{
103210284Sjmallett    int num_ports = 0;
104210284Sjmallett    cvmx_gmxx_inf_mode_t mode;
105210284Sjmallett    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
106210284Sjmallett
107210284Sjmallett    if (mode.s.type)
108210284Sjmallett    {
109210284Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
110210284Sjmallett        {
111210284Sjmallett            cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n");
112210284Sjmallett        }
113210284Sjmallett        else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
114210284Sjmallett        {
115210284Sjmallett            /* On these chips "type" says we're in GMII/MII mode. This
116210284Sjmallett                limits us to 2 ports */
117210284Sjmallett            num_ports = 2;
118210284Sjmallett        }
119210284Sjmallett        else
120210284Sjmallett        {
121210284Sjmallett            cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
122210284Sjmallett        }
123210284Sjmallett    }
124210284Sjmallett    else
125210284Sjmallett    {
126210284Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
127210284Sjmallett        {
128210284Sjmallett            num_ports = 4;
129210284Sjmallett        }
130210284Sjmallett        else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
131210284Sjmallett        {
132210284Sjmallett            num_ports = 3;
133210284Sjmallett        }
134210284Sjmallett        else
135210284Sjmallett        {
136210284Sjmallett            cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
137210284Sjmallett        }
138210284Sjmallett    }
139210284Sjmallett    return num_ports;
140210284Sjmallett}
141210284Sjmallett
142210284Sjmallett
143210284Sjmallett/**
144210284Sjmallett * Put an RGMII interface in loopback mode. Internal packets sent
145210284Sjmallett * out will be received back again on the same port. Externally
146210284Sjmallett * received packets will echo back out.
147210284Sjmallett *
148210284Sjmallett * @param port   IPD port number to loop.
149210284Sjmallett */
150210284Sjmallettvoid cvmx_helper_rgmii_internal_loopback(int port)
151210284Sjmallett{
152210284Sjmallett    int interface = (port >> 4) & 1;
153210284Sjmallett    int index = port & 0xf;
154210284Sjmallett    uint64_t tmp;
155210284Sjmallett
156210284Sjmallett    cvmx_gmxx_prtx_cfg_t gmx_cfg;
157210284Sjmallett    gmx_cfg.u64 = 0;
158210284Sjmallett    gmx_cfg.s.duplex = 1;
159210284Sjmallett    gmx_cfg.s.slottime = 1;
160210284Sjmallett    gmx_cfg.s.speed = 1;
161210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
162210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
163210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
164210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
165210284Sjmallett    tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
166210284Sjmallett    cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp);
167210284Sjmallett    tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
168210284Sjmallett    cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
169210284Sjmallett    tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
170210284Sjmallett    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
171210284Sjmallett    gmx_cfg.s.en = 1;
172210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
173210284Sjmallett}
174210284Sjmallett
175210284Sjmallett
176210284Sjmallett/**
177210284Sjmallett * @INTERNAL
178210284Sjmallett * Configure all of the ASX, GMX, and PKO regsiters required
179210284Sjmallett * to get RGMII to function on the supplied interface.
180210284Sjmallett *
181210284Sjmallett * @param interface PKO Interface to configure (0 or 1)
182210284Sjmallett *
183210284Sjmallett * @return Zero on success
184210284Sjmallett */
185210284Sjmallettint __cvmx_helper_rgmii_enable(int interface)
186210284Sjmallett{
187210284Sjmallett    int num_ports = cvmx_helper_ports_on_interface(interface);
188210284Sjmallett    int port;
189210284Sjmallett    cvmx_gmxx_inf_mode_t mode;
190210284Sjmallett    cvmx_asxx_tx_prt_en_t asx_tx;
191210284Sjmallett    cvmx_asxx_rx_prt_en_t asx_rx;
192210284Sjmallett
193210284Sjmallett    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
194210284Sjmallett
195210284Sjmallett    if (mode.s.en == 0)
196210284Sjmallett        return -1;
197210284Sjmallett    if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1)   /* Ignore SPI interfaces */
198210284Sjmallett        return -1;
199210284Sjmallett
200210284Sjmallett    /* Configure the ASX registers needed to use the RGMII ports */
201210284Sjmallett    asx_tx.u64 = 0;
202210284Sjmallett    asx_tx.s.prt_en = cvmx_build_mask(num_ports);
203210284Sjmallett    cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64);
204210284Sjmallett
205210284Sjmallett    asx_rx.u64 = 0;
206210284Sjmallett    asx_rx.s.prt_en = cvmx_build_mask(num_ports);
207210284Sjmallett    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64);
208210284Sjmallett
209210284Sjmallett    /* Configure the GMX registers needed to use the RGMII ports */
210210284Sjmallett    for (port=0; port<num_ports; port++)
211210284Sjmallett    {
212210284Sjmallett        /* Setting of CVMX_GMXX_TXX_THRESH has been moved to
213210284Sjmallett            __cvmx_helper_setup_gmx() */
214210284Sjmallett
215215990Sjmallett        /* Configure more flexible RGMII preamble checking. Pass 1 doesn't
216215990Sjmallett           support this feature. */
217215990Sjmallett        cvmx_gmxx_rxx_frm_ctl_t frm_ctl;
218215990Sjmallett        frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface));
219215990Sjmallett        frm_ctl.s.pre_free = 1;  /* New field, so must be compile time */
220215990Sjmallett        cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), frm_ctl.u64);
221210284Sjmallett
222210284Sjmallett        /* Each pause frame transmitted will ask for about 10M bit times
223210284Sjmallett            before resume.  If buffer space comes available before that time
224210284Sjmallett            has expired, an XON pause frame (0 time) will be transmitted to
225210284Sjmallett            restart the flow. */
226210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), 20000);
227210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(port, interface), 19000);
228210284Sjmallett
229210311Sjmallett        /*
230210311Sjmallett         * Board types we have to know at compile-time.
231210311Sjmallett         */
232210311Sjmallett#if defined(OCTEON_BOARD_CAPK_0100ND)
233210311Sjmallett        cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 26);
234210311Sjmallett        cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 26);
235210311Sjmallett#else
236210311Sjmallett	/*
237210311Sjmallett	 * Vendor-defined board types.
238210311Sjmallett	 */
239210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
240210311Sjmallett	switch (cvmx_sysinfo_get()->board_type) {
241210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
242216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
243210311Sjmallett            if (port == 0) {
244210311Sjmallett                cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 4);
245210311Sjmallett	    } else {
246210311Sjmallett                cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 7);
247210311Sjmallett            }
248210311Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0);
249210311Sjmallett	    break;
250210311Sjmallett	}
251210311Sjmallett#else
252210311Sjmallett        /*
253210311Sjmallett         * For board types we can determine at runtime.
254210311Sjmallett         */
255210284Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN50XX))
256210284Sjmallett        {
257210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
258210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16);
259210284Sjmallett        }
260210284Sjmallett        else
261210284Sjmallett        {
262210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24);
263210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24);
264210284Sjmallett        }
265210311Sjmallett#endif
266210311Sjmallett#endif
267210284Sjmallett    }
268210284Sjmallett
269210284Sjmallett    __cvmx_helper_setup_gmx(interface, num_ports);
270210284Sjmallett
271210284Sjmallett    /* enable the ports now */
272210284Sjmallett    for (port=0; port<num_ports; port++)
273210284Sjmallett    {
274210284Sjmallett        cvmx_gmxx_prtx_cfg_t gmx_cfg;
275210284Sjmallett        cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, port));
276210284Sjmallett        gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface));
277210284Sjmallett        gmx_cfg.s.en = 1;
278210284Sjmallett        cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64);
279210284Sjmallett    }
280210284Sjmallett    return 0;
281210284Sjmallett}
282210284Sjmallett
283210284Sjmallett
284210284Sjmallett/**
285210284Sjmallett * @INTERNAL
286210284Sjmallett * Return the link state of an IPD/PKO port as returned by
287210284Sjmallett * auto negotiation. The result of this function may not match
288210284Sjmallett * Octeon's link config if auto negotiation has changed since
289210284Sjmallett * the last call to cvmx_helper_link_set().
290210284Sjmallett *
291210284Sjmallett * @param ipd_port IPD/PKO port to query
292210284Sjmallett *
293210284Sjmallett * @return Link state
294210284Sjmallett */
295210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
296210284Sjmallett{
297210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
298210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
299210284Sjmallett    cvmx_asxx_prt_loop_t asxx_prt_loop;
300210284Sjmallett
301210284Sjmallett    asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
302210284Sjmallett    if (asxx_prt_loop.s.int_loop & (1<<index))
303210284Sjmallett    {
304210284Sjmallett        /* Force 1Gbps full duplex on internal loopback */
305210284Sjmallett        cvmx_helper_link_info_t result;
306210284Sjmallett        result.u64 = 0;
307210284Sjmallett        result.s.full_duplex = 1;
308210284Sjmallett        result.s.link_up = 1;
309210284Sjmallett        result.s.speed = 1000;
310210284Sjmallett        return result;
311210284Sjmallett    }
312210284Sjmallett    else
313210284Sjmallett        return __cvmx_helper_board_link_get(ipd_port);
314210284Sjmallett}
315210284Sjmallett
316210284Sjmallett
317210284Sjmallett/**
318210284Sjmallett * @INTERNAL
319210284Sjmallett * Configure an IPD/PKO port for the specified link state. This
320210284Sjmallett * function does not influence auto negotiation at the PHY level.
321210284Sjmallett * The passed link state must always match the link state returned
322210284Sjmallett * by cvmx_helper_link_get(). It is normally best to use
323210284Sjmallett * cvmx_helper_link_autoconf() instead.
324210284Sjmallett *
325210284Sjmallett * @param ipd_port  IPD/PKO port to configure
326210284Sjmallett * @param link_info The new link state
327210284Sjmallett *
328210284Sjmallett * @return Zero on success, negative on failure
329210284Sjmallett */
330210284Sjmallettint __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
331210284Sjmallett{
332210284Sjmallett    int result = 0;
333210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
334210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
335210284Sjmallett    cvmx_gmxx_prtx_cfg_t original_gmx_cfg;
336210284Sjmallett    cvmx_gmxx_prtx_cfg_t new_gmx_cfg;
337210284Sjmallett    cvmx_pko_mem_queue_qos_t pko_mem_queue_qos;
338210284Sjmallett    cvmx_pko_mem_queue_qos_t pko_mem_queue_qos_save[16];
339210284Sjmallett    cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp;
340210284Sjmallett    cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp_save;
341210284Sjmallett    int i;
342210284Sjmallett
343210284Sjmallett    /* Ignore speed sets in the simulator */
344210284Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
345210284Sjmallett        return 0;
346210284Sjmallett
347210284Sjmallett    /* Read the current settings so we know the current enable state */
348210284Sjmallett    original_gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
349210284Sjmallett    new_gmx_cfg = original_gmx_cfg;
350210284Sjmallett
351210284Sjmallett    /* Disable the lowest level RX */
352210284Sjmallett    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
353210284Sjmallett                   cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1<<index));
354210284Sjmallett
355232812Sjmallett    memset(pko_mem_queue_qos_save, 0, sizeof(pko_mem_queue_qos_save));
356210284Sjmallett    /* Disable all queues so that TX should become idle */
357210284Sjmallett    for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
358210284Sjmallett    {
359210284Sjmallett        int queue = cvmx_pko_get_base_queue(ipd_port) + i;
360210284Sjmallett        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
361210284Sjmallett        pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS);
362210284Sjmallett        pko_mem_queue_qos.s.pid = ipd_port;
363210284Sjmallett        pko_mem_queue_qos.s.qid = queue;
364210284Sjmallett        pko_mem_queue_qos_save[i] = pko_mem_queue_qos;
365210284Sjmallett        pko_mem_queue_qos.s.qos_mask = 0;
366210284Sjmallett        cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64);
367210284Sjmallett    }
368210284Sjmallett
369210284Sjmallett    /* Disable backpressure */
370210284Sjmallett    gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
371210284Sjmallett    gmx_tx_ovr_bp_save = gmx_tx_ovr_bp;
372210284Sjmallett    gmx_tx_ovr_bp.s.bp &= ~(1<<index);
373210284Sjmallett    gmx_tx_ovr_bp.s.en |= 1<<index;
374210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64);
375210284Sjmallett    cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
376210284Sjmallett
377210284Sjmallett    /* Poll the GMX state machine waiting for it to become idle. Preferably we
378210284Sjmallett        should only change speed when it is idle. If it doesn't become idle we
379210284Sjmallett        will still do the speed change, but there is a slight chance that GMX
380210284Sjmallett        will lockup */
381210284Sjmallett    cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880);
382210284Sjmallett    CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000);
383210284Sjmallett    CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000);
384210284Sjmallett
385210284Sjmallett    /* Disable the port before we make any changes */
386210284Sjmallett    new_gmx_cfg.s.en = 0;
387210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
388210284Sjmallett    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
389210284Sjmallett
390210284Sjmallett    /* Set full/half duplex */
391215990Sjmallett    if (!link_info.s.link_up)
392210284Sjmallett        new_gmx_cfg.s.duplex = 1;   /* Force full duplex on down links */
393210284Sjmallett    else
394210284Sjmallett        new_gmx_cfg.s.duplex = link_info.s.full_duplex;
395210284Sjmallett
396210284Sjmallett    /* Set the link speed. Anything unknown is set to 1Gbps */
397210284Sjmallett    if (link_info.s.speed == 10)
398210284Sjmallett    {
399210284Sjmallett        new_gmx_cfg.s.slottime = 0;
400210284Sjmallett        new_gmx_cfg.s.speed = 0;
401210284Sjmallett    }
402210284Sjmallett    else if (link_info.s.speed == 100)
403210284Sjmallett    {
404210284Sjmallett        new_gmx_cfg.s.slottime = 0;
405210284Sjmallett        new_gmx_cfg.s.speed = 0;
406210284Sjmallett    }
407210284Sjmallett    else
408210284Sjmallett    {
409210284Sjmallett        new_gmx_cfg.s.slottime = 1;
410210284Sjmallett        new_gmx_cfg.s.speed = 1;
411210284Sjmallett    }
412210284Sjmallett
413210284Sjmallett    /* Adjust the clocks */
414210284Sjmallett    if (link_info.s.speed == 10)
415210284Sjmallett    {
416210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50);
417210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
418210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
419210284Sjmallett    }
420210284Sjmallett    else if (link_info.s.speed == 100)
421210284Sjmallett    {
422210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5);
423210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
424210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
425210284Sjmallett    }
426210284Sjmallett    else
427210284Sjmallett    {
428210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
429210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
430210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
431210284Sjmallett    }
432210284Sjmallett
433210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
434210284Sjmallett    {
435210284Sjmallett        if ((link_info.s.speed == 10) || (link_info.s.speed == 100))
436210284Sjmallett        {
437210284Sjmallett            cvmx_gmxx_inf_mode_t mode;
438210284Sjmallett            mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
439210284Sjmallett
440210284Sjmallett            /*
441210284Sjmallett            ** Port  .en  .type  .p0mii  Configuration
442210284Sjmallett            ** ----  ---  -----  ------  -----------------------------------------
443210284Sjmallett            **  X      0     X      X    All links are disabled.
444210284Sjmallett            **  0      1     X      0    Port 0 is RGMII
445210284Sjmallett            **  0      1     X      1    Port 0 is MII
446210284Sjmallett            **  1      1     0      X    Ports 1 and 2 are configured as RGMII ports.
447210284Sjmallett            **  1      1     1      X    Port 1: GMII/MII; Port 2: disabled. GMII or
448210284Sjmallett            **                           MII port is selected by GMX_PRT1_CFG[SPEED].
449210284Sjmallett            */
450210284Sjmallett
451210284Sjmallett            /* In MII mode, CLK_CNT = 1. */
452210284Sjmallett            if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1)))
453210284Sjmallett            {
454210284Sjmallett                cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
455210284Sjmallett            }
456210284Sjmallett        }
457210284Sjmallett    }
458210284Sjmallett
459210284Sjmallett    /* Do a read to make sure all setup stuff is complete */
460210284Sjmallett    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
461210284Sjmallett
462210284Sjmallett    /* Save the new GMX setting without enabling the port */
463210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
464210284Sjmallett
465210284Sjmallett    /* Enable the lowest level RX */
466210284Sjmallett    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
467210284Sjmallett                   cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index));
468210284Sjmallett
469210284Sjmallett    /* Re-enable the TX path */
470210284Sjmallett    for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
471210284Sjmallett    {
472210284Sjmallett        int queue = cvmx_pko_get_base_queue(ipd_port) + i;
473210284Sjmallett        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
474210284Sjmallett        cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64);
475210284Sjmallett    }
476210284Sjmallett
477210284Sjmallett    /* Restore backpressure */
478210284Sjmallett    cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64);
479210284Sjmallett
480210284Sjmallett    /* Restore the GMX enable state. Port config is complete */
481210284Sjmallett    new_gmx_cfg.s.en = original_gmx_cfg.s.en;
482210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
483210284Sjmallett
484210284Sjmallett    return result;
485210284Sjmallett}
486210284Sjmallett
487210284Sjmallett
488210284Sjmallett/**
489210284Sjmallett * @INTERNAL
490210284Sjmallett * Configure a port for internal and/or external loopback. Internal loopback
491210284Sjmallett * causes packets sent by the port to be received by Octeon. External loopback
492210284Sjmallett * causes packets received from the wire to sent out again.
493210284Sjmallett *
494210284Sjmallett * @param ipd_port IPD/PKO port to loopback.
495210284Sjmallett * @param enable_internal
496210284Sjmallett *                 Non zero if you want internal loopback
497210284Sjmallett * @param enable_external
498210284Sjmallett *                 Non zero if you want external loopback
499210284Sjmallett *
500210284Sjmallett * @return Zero on success, negative on failure.
501210284Sjmallett */
502210284Sjmallettint __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
503210284Sjmallett{
504210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
505210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
506210284Sjmallett    int original_enable;
507210284Sjmallett    cvmx_gmxx_prtx_cfg_t gmx_cfg;
508210284Sjmallett    cvmx_asxx_prt_loop_t asxx_prt_loop;
509210284Sjmallett
510210284Sjmallett    /* Read the current enable state and save it */
511210284Sjmallett    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
512210284Sjmallett    original_enable = gmx_cfg.s.en;
513210284Sjmallett    /* Force port to be disabled */
514210284Sjmallett    gmx_cfg.s.en = 0;
515210284Sjmallett    if (enable_internal)
516210284Sjmallett    {
517210284Sjmallett        /* Force speed if we're doing internal loopback */
518210284Sjmallett        gmx_cfg.s.duplex = 1;
519210284Sjmallett        gmx_cfg.s.slottime = 1;
520210284Sjmallett        gmx_cfg.s.speed = 1;
521210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
522210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
523210284Sjmallett        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
524210284Sjmallett    }
525210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
526210284Sjmallett
527210284Sjmallett    /* Set the loopback bits */
528210284Sjmallett    asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
529210284Sjmallett    if (enable_internal)
530210284Sjmallett        asxx_prt_loop.s.int_loop |= 1<<index;
531210284Sjmallett    else
532210284Sjmallett        asxx_prt_loop.s.int_loop &= ~(1<<index);
533210284Sjmallett    if (enable_external)
534210284Sjmallett        asxx_prt_loop.s.ext_loop |= 1<<index;
535210284Sjmallett    else
536210284Sjmallett        asxx_prt_loop.s.ext_loop &= ~(1<<index);
537210284Sjmallett    cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64);
538210284Sjmallett
539210284Sjmallett    /* Force enables in internal loopback */
540210284Sjmallett    if (enable_internal)
541210284Sjmallett    {
542210284Sjmallett        uint64_t tmp;
543210284Sjmallett        tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
544210284Sjmallett        cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
545210284Sjmallett        tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
546210284Sjmallett        cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
547210284Sjmallett        original_enable = 1;
548210284Sjmallett    }
549210284Sjmallett
550210284Sjmallett    /* Restore the enable state */
551210284Sjmallett    gmx_cfg.s.en = original_enable;
552210284Sjmallett    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
553210284Sjmallett    return 0;
554210284Sjmallett}
555210284Sjmallett
556210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
557210284Sjmallett
558