cvmx-helper-rgmii.c revision 210284
1/***********************license start***************
2 *  Copyright (c) 2003-2008 Cavium Networks (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 Networks 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 *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32 *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33 *
34 *
35 *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36 *
37 ***********************license end**************************************/
38
39
40
41
42
43
44/**
45 * @file
46 *
47 * Functions for RGMII/GMII/MII initialization, configuration,
48 * and monitoring.
49 *
50 * <hr>$Revision: 42417 $<hr>
51 */
52#include "executive-config.h"
53#include "cvmx-config.h"
54#ifdef CVMX_ENABLE_PKO_FUNCTIONS
55
56#include "cvmx.h"
57#include "cvmx-sysinfo.h"
58#include "cvmx-mdio.h"
59#include "cvmx-pko.h"
60#include "cvmx-helper.h"
61#include "cvmx-helper-board.h"
62
63/**
64 * @INTERNAL
65 * Probe RGMII ports and determine the number present
66 *
67 * @param interface Interface to probe
68 *
69 * @return Number of RGMII/GMII/MII ports (0-4).
70 */
71int __cvmx_helper_rgmii_probe(int interface)
72{
73    int num_ports = 0;
74    cvmx_gmxx_inf_mode_t mode;
75    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
76
77    if (mode.s.type)
78    {
79        if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
80        {
81            cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n");
82        }
83        else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
84        {
85            /* On these chips "type" says we're in GMII/MII mode. This
86                limits us to 2 ports */
87            num_ports = 2;
88        }
89        else
90        {
91            cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
92        }
93    }
94    else
95    {
96        if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
97        {
98            num_ports = 4;
99        }
100        else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
101        {
102            num_ports = 3;
103        }
104        else
105        {
106            cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
107        }
108    }
109    return num_ports;
110}
111
112
113/**
114 * Put an RGMII interface in loopback mode. Internal packets sent
115 * out will be received back again on the same port. Externally
116 * received packets will echo back out.
117 *
118 * @param port   IPD port number to loop.
119 */
120void cvmx_helper_rgmii_internal_loopback(int port)
121{
122    int interface = (port >> 4) & 1;
123    int index = port & 0xf;
124    uint64_t tmp;
125
126    cvmx_gmxx_prtx_cfg_t gmx_cfg;
127    gmx_cfg.u64 = 0;
128    gmx_cfg.s.duplex = 1;
129    gmx_cfg.s.slottime = 1;
130    gmx_cfg.s.speed = 1;
131    cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
132    cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
133    cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
134    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
135    tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
136    cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp);
137    tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
138    cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
139    tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
140    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
141    gmx_cfg.s.en = 1;
142    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
143}
144
145
146/**
147 * @INTERNAL
148 * Configure all of the ASX, GMX, and PKO regsiters required
149 * to get RGMII to function on the supplied interface.
150 *
151 * @param interface PKO Interface to configure (0 or 1)
152 *
153 * @return Zero on success
154 */
155int __cvmx_helper_rgmii_enable(int interface)
156{
157    int num_ports = cvmx_helper_ports_on_interface(interface);
158    int port;
159    cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
160    cvmx_gmxx_inf_mode_t mode;
161    cvmx_asxx_tx_prt_en_t asx_tx;
162    cvmx_asxx_rx_prt_en_t asx_rx;
163
164    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
165
166    if (mode.s.en == 0)
167        return -1;
168    if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1)   /* Ignore SPI interfaces */
169        return -1;
170
171    /* Configure the ASX registers needed to use the RGMII ports */
172    asx_tx.u64 = 0;
173    asx_tx.s.prt_en = cvmx_build_mask(num_ports);
174    cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64);
175
176    asx_rx.u64 = 0;
177    asx_rx.s.prt_en = cvmx_build_mask(num_ports);
178    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64);
179
180    /* Configure the GMX registers needed to use the RGMII ports */
181    for (port=0; port<num_ports; port++)
182    {
183        /* Setting of CVMX_GMXX_TXX_THRESH has been moved to
184            __cvmx_helper_setup_gmx() */
185
186        if (cvmx_octeon_is_pass1())
187            __cvmx_helper_errata_asx_pass1(interface, port, sys_info_ptr->cpu_clock_hz);
188        else
189        {
190            /* Configure more flexible RGMII preamble checking. Pass 1 doesn't
191                support this feature. */
192            cvmx_gmxx_rxx_frm_ctl_t frm_ctl;
193            frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface));
194            frm_ctl.s.pre_free = 1;  /* New field, so must be compile time */
195            cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), frm_ctl.u64);
196        }
197
198        /* Each pause frame transmitted will ask for about 10M bit times
199            before resume.  If buffer space comes available before that time
200            has expired, an XON pause frame (0 time) will be transmitted to
201            restart the flow. */
202        cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), 20000);
203        cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(port, interface), 19000);
204
205        if (OCTEON_IS_MODEL(OCTEON_CN50XX))
206        {
207            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
208            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16);
209        }
210        else
211        {
212            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24);
213            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24);
214        }
215    }
216
217    __cvmx_helper_setup_gmx(interface, num_ports);
218
219    /* enable the ports now */
220    for (port=0; port<num_ports; port++)
221    {
222        cvmx_gmxx_prtx_cfg_t gmx_cfg;
223        cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, port));
224        gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface));
225        gmx_cfg.s.en = 1;
226        cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64);
227    }
228
229    return 0;
230}
231
232
233/**
234 * @INTERNAL
235 * Return the link state of an IPD/PKO port as returned by
236 * auto negotiation. The result of this function may not match
237 * Octeon's link config if auto negotiation has changed since
238 * the last call to cvmx_helper_link_set().
239 *
240 * @param ipd_port IPD/PKO port to query
241 *
242 * @return Link state
243 */
244cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
245{
246    int interface = cvmx_helper_get_interface_num(ipd_port);
247    int index = cvmx_helper_get_interface_index_num(ipd_port);
248    cvmx_asxx_prt_loop_t asxx_prt_loop;
249
250    asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
251    if (asxx_prt_loop.s.int_loop & (1<<index))
252    {
253        /* Force 1Gbps full duplex on internal loopback */
254        cvmx_helper_link_info_t result;
255        result.u64 = 0;
256        result.s.full_duplex = 1;
257        result.s.link_up = 1;
258        result.s.speed = 1000;
259        return result;
260    }
261    else
262        return __cvmx_helper_board_link_get(ipd_port);
263}
264
265
266/**
267 * @INTERNAL
268 * Configure an IPD/PKO port for the specified link state. This
269 * function does not influence auto negotiation at the PHY level.
270 * The passed link state must always match the link state returned
271 * by cvmx_helper_link_get(). It is normally best to use
272 * cvmx_helper_link_autoconf() instead.
273 *
274 * @param ipd_port  IPD/PKO port to configure
275 * @param link_info The new link state
276 *
277 * @return Zero on success, negative on failure
278 */
279int __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
280{
281    int result = 0;
282    int interface = cvmx_helper_get_interface_num(ipd_port);
283    int index = cvmx_helper_get_interface_index_num(ipd_port);
284    cvmx_gmxx_prtx_cfg_t original_gmx_cfg;
285    cvmx_gmxx_prtx_cfg_t new_gmx_cfg;
286    cvmx_pko_mem_queue_qos_t pko_mem_queue_qos;
287    cvmx_pko_mem_queue_qos_t pko_mem_queue_qos_save[16];
288    cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp;
289    cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp_save;
290    int i;
291
292    /* Ignore speed sets in the simulator */
293    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
294        return 0;
295
296    /* Read the current settings so we know the current enable state */
297    original_gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
298    new_gmx_cfg = original_gmx_cfg;
299
300    /* Disable the lowest level RX */
301    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
302                   cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1<<index));
303
304    /* Disable all queues so that TX should become idle */
305    for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
306    {
307        int queue = cvmx_pko_get_base_queue(ipd_port) + i;
308        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
309        pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS);
310        pko_mem_queue_qos.s.pid = ipd_port;
311        pko_mem_queue_qos.s.qid = queue;
312        pko_mem_queue_qos_save[i] = pko_mem_queue_qos;
313        pko_mem_queue_qos.s.qos_mask = 0;
314        cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64);
315    }
316
317    /* Disable backpressure */
318    gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
319    gmx_tx_ovr_bp_save = gmx_tx_ovr_bp;
320    gmx_tx_ovr_bp.s.bp &= ~(1<<index);
321    gmx_tx_ovr_bp.s.en |= 1<<index;
322    cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64);
323    cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
324
325    /* Poll the GMX state machine waiting for it to become idle. Preferably we
326        should only change speed when it is idle. If it doesn't become idle we
327        will still do the speed change, but there is a slight chance that GMX
328        will lockup */
329    cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880);
330    CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000);
331    CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000);
332
333    /* Disable the port before we make any changes */
334    new_gmx_cfg.s.en = 0;
335    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
336    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
337
338    /* Set full/half duplex */
339    if (cvmx_octeon_is_pass1())
340        new_gmx_cfg.s.duplex = 1;   /* Half duplex is broken for 38XX Pass 1 */
341    else if (!link_info.s.link_up)
342        new_gmx_cfg.s.duplex = 1;   /* Force full duplex on down links */
343    else
344        new_gmx_cfg.s.duplex = link_info.s.full_duplex;
345
346    /* Set the link speed. Anything unknown is set to 1Gbps */
347    if (link_info.s.speed == 10)
348    {
349        new_gmx_cfg.s.slottime = 0;
350        new_gmx_cfg.s.speed = 0;
351    }
352    else if (link_info.s.speed == 100)
353    {
354        new_gmx_cfg.s.slottime = 0;
355        new_gmx_cfg.s.speed = 0;
356    }
357    else
358    {
359        new_gmx_cfg.s.slottime = 1;
360        new_gmx_cfg.s.speed = 1;
361    }
362
363    /* Adjust the clocks */
364    if (link_info.s.speed == 10)
365    {
366        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50);
367        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
368        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
369    }
370    else if (link_info.s.speed == 100)
371    {
372        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5);
373        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
374        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
375    }
376    else
377    {
378        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
379        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
380        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
381    }
382
383    if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
384    {
385        if ((link_info.s.speed == 10) || (link_info.s.speed == 100))
386        {
387            cvmx_gmxx_inf_mode_t mode;
388            mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
389
390            /*
391            ** Port  .en  .type  .p0mii  Configuration
392            ** ----  ---  -----  ------  -----------------------------------------
393            **  X      0     X      X    All links are disabled.
394            **  0      1     X      0    Port 0 is RGMII
395            **  0      1     X      1    Port 0 is MII
396            **  1      1     0      X    Ports 1 and 2 are configured as RGMII ports.
397            **  1      1     1      X    Port 1: GMII/MII; Port 2: disabled. GMII or
398            **                           MII port is selected by GMX_PRT1_CFG[SPEED].
399            */
400
401            /* In MII mode, CLK_CNT = 1. */
402            if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1)))
403            {
404                cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
405            }
406        }
407    }
408
409    /* Do a read to make sure all setup stuff is complete */
410    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
411
412    /* Save the new GMX setting without enabling the port */
413    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
414
415    /* Enable the lowest level RX */
416    cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
417                   cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index));
418
419    /* Re-enable the TX path */
420    for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
421    {
422        int queue = cvmx_pko_get_base_queue(ipd_port) + i;
423        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
424        cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64);
425    }
426
427    /* Restore backpressure */
428    cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64);
429
430    /* Restore the GMX enable state. Port config is complete */
431    new_gmx_cfg.s.en = original_gmx_cfg.s.en;
432    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
433
434    return result;
435}
436
437
438/**
439 * @INTERNAL
440 * Configure a port for internal and/or external loopback. Internal loopback
441 * causes packets sent by the port to be received by Octeon. External loopback
442 * causes packets received from the wire to sent out again.
443 *
444 * @param ipd_port IPD/PKO port to loopback.
445 * @param enable_internal
446 *                 Non zero if you want internal loopback
447 * @param enable_external
448 *                 Non zero if you want external loopback
449 *
450 * @return Zero on success, negative on failure.
451 */
452int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
453{
454    int interface = cvmx_helper_get_interface_num(ipd_port);
455    int index = cvmx_helper_get_interface_index_num(ipd_port);
456    int original_enable;
457    cvmx_gmxx_prtx_cfg_t gmx_cfg;
458    cvmx_asxx_prt_loop_t asxx_prt_loop;
459
460    /* Read the current enable state and save it */
461    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
462    original_enable = gmx_cfg.s.en;
463    /* Force port to be disabled */
464    gmx_cfg.s.en = 0;
465    if (enable_internal)
466    {
467        /* Force speed if we're doing internal loopback */
468        gmx_cfg.s.duplex = 1;
469        gmx_cfg.s.slottime = 1;
470        gmx_cfg.s.speed = 1;
471        cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
472        cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
473        cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
474    }
475    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
476
477    /* Set the loopback bits */
478    asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
479    if (enable_internal)
480        asxx_prt_loop.s.int_loop |= 1<<index;
481    else
482        asxx_prt_loop.s.int_loop &= ~(1<<index);
483    if (enable_external)
484        asxx_prt_loop.s.ext_loop |= 1<<index;
485    else
486        asxx_prt_loop.s.ext_loop &= ~(1<<index);
487    cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64);
488
489    /* Force enables in internal loopback */
490    if (enable_internal)
491    {
492        uint64_t tmp;
493        tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
494        cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
495        tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
496        cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
497        original_enable = 1;
498    }
499
500    /* Restore the enable state */
501    gmx_cfg.s.en = original_enable;
502    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
503    return 0;
504}
505
506#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
507
508