1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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
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
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**************************************/
49 * Functions for RGMII/GMII/MII initialization, configuration,
52 * <hr>$Revision: 70030 $<hr>
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-pko.h>
59 #include <asm/octeon/cvmx-helper.h>
60 #include <asm/octeon/cvmx-helper-board.h>
62 #include <asm/octeon/cvmx-asxx-defs.h>
63 #include <asm/octeon/cvmx-gmxx-defs.h>
64 #include <asm/octeon/cvmx-pko-defs.h>
65 #include <asm/octeon/cvmx-npi-defs.h>
66 #include <asm/octeon/cvmx-dbg-defs.h>
69 #if !defined(__FreeBSD__) || !defined(_KERNEL)
70 #include "executive-config.h"
71 #include "cvmx-config.h"
72 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
75 #include "cvmx-sysinfo.h"
76 #include "cvmx-mdio.h"
78 #include "cvmx-helper.h"
79 #include "cvmx-helper-board.h"
83 #include "cvmx-sysinfo.h"
84 #include "cvmx-mdio.h"
86 #include "cvmx-helper.h"
87 #include "cvmx-helper-board.h"
91 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
95 * Probe RGMII ports and determine the number present
97 * @param interface Interface to probe
99 * @return Number of RGMII/GMII/MII ports (0-4).
101 int __cvmx_helper_rgmii_probe(int interface)
104 cvmx_gmxx_inf_mode_t mode;
105 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
109 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
111 cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n");
113 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
115 /* On these chips "type" says we're in GMII/MII mode. This
116 limits us to 2 ports */
121 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
126 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
130 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
136 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
144 * Put an RGMII interface in loopback mode. Internal packets sent
145 * out will be received back again on the same port. Externally
146 * received packets will echo back out.
148 * @param port IPD port number to loop.
150 void cvmx_helper_rgmii_internal_loopback(int port)
152 int interface = (port >> 4) & 1;
153 int index = port & 0xf;
156 cvmx_gmxx_prtx_cfg_t gmx_cfg;
158 gmx_cfg.s.duplex = 1;
159 gmx_cfg.s.slottime = 1;
161 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
162 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
163 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
164 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
165 tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
166 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp);
167 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
168 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
169 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
170 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
172 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
178 * Configure all of the ASX, GMX, and PKO regsiters required
179 * to get RGMII to function on the supplied interface.
181 * @param interface PKO Interface to configure (0 or 1)
183 * @return Zero on success
185 int __cvmx_helper_rgmii_enable(int interface)
187 int num_ports = cvmx_helper_ports_on_interface(interface);
189 cvmx_gmxx_inf_mode_t mode;
190 cvmx_asxx_tx_prt_en_t asx_tx;
191 cvmx_asxx_rx_prt_en_t asx_rx;
193 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
197 if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1) /* Ignore SPI interfaces */
200 /* Configure the ASX registers needed to use the RGMII ports */
202 asx_tx.s.prt_en = cvmx_build_mask(num_ports);
203 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64);
206 asx_rx.s.prt_en = cvmx_build_mask(num_ports);
207 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64);
209 /* Configure the GMX registers needed to use the RGMII ports */
210 for (port=0; port<num_ports; port++)
212 /* Setting of CVMX_GMXX_TXX_THRESH has been moved to
213 __cvmx_helper_setup_gmx() */
215 /* Configure more flexible RGMII preamble checking. Pass 1 doesn't
216 support this feature. */
217 cvmx_gmxx_rxx_frm_ctl_t frm_ctl;
218 frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface));
219 frm_ctl.s.pre_free = 1; /* New field, so must be compile time */
220 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), frm_ctl.u64);
222 /* Each pause frame transmitted will ask for about 10M bit times
223 before resume. If buffer space comes available before that time
224 has expired, an XON pause frame (0 time) will be transmitted to
226 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), 20000);
227 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(port, interface), 19000);
230 * Board types we have to know at compile-time.
232 #if defined(OCTEON_BOARD_CAPK_0100ND)
233 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 26);
234 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 26);
237 * Vendor-defined board types.
239 #if defined(OCTEON_VENDOR_LANNER)
240 switch (cvmx_sysinfo_get()->board_type) {
241 case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
242 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
244 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 4);
246 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 7);
248 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0);
253 * For board types we can determine at runtime.
255 if (OCTEON_IS_MODEL(OCTEON_CN50XX))
257 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
258 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16);
262 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24);
263 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24);
269 __cvmx_helper_setup_gmx(interface, num_ports);
271 /* enable the ports now */
272 for (port=0; port<num_ports; port++)
274 cvmx_gmxx_prtx_cfg_t gmx_cfg;
275 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, port));
276 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface));
278 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64);
286 * Return the link state of an IPD/PKO port as returned by
287 * auto negotiation. The result of this function may not match
288 * Octeon's link config if auto negotiation has changed since
289 * the last call to cvmx_helper_link_set().
291 * @param ipd_port IPD/PKO port to query
295 cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
297 int interface = cvmx_helper_get_interface_num(ipd_port);
298 int index = cvmx_helper_get_interface_index_num(ipd_port);
299 cvmx_asxx_prt_loop_t asxx_prt_loop;
301 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
302 if (asxx_prt_loop.s.int_loop & (1<<index))
304 /* Force 1Gbps full duplex on internal loopback */
305 cvmx_helper_link_info_t result;
307 result.s.full_duplex = 1;
308 result.s.link_up = 1;
309 result.s.speed = 1000;
313 return __cvmx_helper_board_link_get(ipd_port);
319 * Configure an IPD/PKO port for the specified link state. This
320 * function does not influence auto negotiation at the PHY level.
321 * The passed link state must always match the link state returned
322 * by cvmx_helper_link_get(). It is normally best to use
323 * cvmx_helper_link_autoconf() instead.
325 * @param ipd_port IPD/PKO port to configure
326 * @param link_info The new link state
328 * @return Zero on success, negative on failure
330 int __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
333 int interface = cvmx_helper_get_interface_num(ipd_port);
334 int index = cvmx_helper_get_interface_index_num(ipd_port);
335 cvmx_gmxx_prtx_cfg_t original_gmx_cfg;
336 cvmx_gmxx_prtx_cfg_t new_gmx_cfg;
337 cvmx_pko_mem_queue_qos_t pko_mem_queue_qos;
338 cvmx_pko_mem_queue_qos_t pko_mem_queue_qos_save[16];
339 cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp;
340 cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp_save;
343 /* Ignore speed sets in the simulator */
344 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
347 /* Read the current settings so we know the current enable state */
348 original_gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
349 new_gmx_cfg = original_gmx_cfg;
351 /* Disable the lowest level RX */
352 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
353 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1<<index));
355 memset(pko_mem_queue_qos_save, 0, sizeof(pko_mem_queue_qos_save));
356 /* Disable all queues so that TX should become idle */
357 for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
359 int queue = cvmx_pko_get_base_queue(ipd_port) + i;
360 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
361 pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS);
362 pko_mem_queue_qos.s.pid = ipd_port;
363 pko_mem_queue_qos.s.qid = queue;
364 pko_mem_queue_qos_save[i] = pko_mem_queue_qos;
365 pko_mem_queue_qos.s.qos_mask = 0;
366 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64);
369 /* Disable backpressure */
370 gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
371 gmx_tx_ovr_bp_save = gmx_tx_ovr_bp;
372 gmx_tx_ovr_bp.s.bp &= ~(1<<index);
373 gmx_tx_ovr_bp.s.en |= 1<<index;
374 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64);
375 cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
377 /* Poll the GMX state machine waiting for it to become idle. Preferably we
378 should only change speed when it is idle. If it doesn't become idle we
379 will still do the speed change, but there is a slight chance that GMX
381 cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880);
382 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000);
383 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000);
385 /* Disable the port before we make any changes */
386 new_gmx_cfg.s.en = 0;
387 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
388 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
390 /* Set full/half duplex */
391 if (!link_info.s.link_up)
392 new_gmx_cfg.s.duplex = 1; /* Force full duplex on down links */
394 new_gmx_cfg.s.duplex = link_info.s.full_duplex;
396 /* Set the link speed. Anything unknown is set to 1Gbps */
397 if (link_info.s.speed == 10)
399 new_gmx_cfg.s.slottime = 0;
400 new_gmx_cfg.s.speed = 0;
402 else if (link_info.s.speed == 100)
404 new_gmx_cfg.s.slottime = 0;
405 new_gmx_cfg.s.speed = 0;
409 new_gmx_cfg.s.slottime = 1;
410 new_gmx_cfg.s.speed = 1;
413 /* Adjust the clocks */
414 if (link_info.s.speed == 10)
416 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50);
417 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
418 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
420 else if (link_info.s.speed == 100)
422 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5);
423 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
424 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
428 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
429 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
430 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
433 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
435 if ((link_info.s.speed == 10) || (link_info.s.speed == 100))
437 cvmx_gmxx_inf_mode_t mode;
438 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
441 ** Port .en .type .p0mii Configuration
442 ** ---- --- ----- ------ -----------------------------------------
443 ** X 0 X X All links are disabled.
444 ** 0 1 X 0 Port 0 is RGMII
445 ** 0 1 X 1 Port 0 is MII
446 ** 1 1 0 X Ports 1 and 2 are configured as RGMII ports.
447 ** 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or
448 ** MII port is selected by GMX_PRT1_CFG[SPEED].
451 /* In MII mode, CLK_CNT = 1. */
452 if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1)))
454 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
459 /* Do a read to make sure all setup stuff is complete */
460 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
462 /* Save the new GMX setting without enabling the port */
463 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
465 /* Enable the lowest level RX */
466 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
467 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index));
469 /* Re-enable the TX path */
470 for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
472 int queue = cvmx_pko_get_base_queue(ipd_port) + i;
473 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
474 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64);
477 /* Restore backpressure */
478 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64);
480 /* Restore the GMX enable state. Port config is complete */
481 new_gmx_cfg.s.en = original_gmx_cfg.s.en;
482 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
490 * Configure a port for internal and/or external loopback. Internal loopback
491 * causes packets sent by the port to be received by Octeon. External loopback
492 * causes packets received from the wire to sent out again.
494 * @param ipd_port IPD/PKO port to loopback.
495 * @param enable_internal
496 * Non zero if you want internal loopback
497 * @param enable_external
498 * Non zero if you want external loopback
500 * @return Zero on success, negative on failure.
502 int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
504 int interface = cvmx_helper_get_interface_num(ipd_port);
505 int index = cvmx_helper_get_interface_index_num(ipd_port);
507 cvmx_gmxx_prtx_cfg_t gmx_cfg;
508 cvmx_asxx_prt_loop_t asxx_prt_loop;
510 /* Read the current enable state and save it */
511 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
512 original_enable = gmx_cfg.s.en;
513 /* Force port to be disabled */
517 /* Force speed if we're doing internal loopback */
518 gmx_cfg.s.duplex = 1;
519 gmx_cfg.s.slottime = 1;
521 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
522 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
523 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
525 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
527 /* Set the loopback bits */
528 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
530 asxx_prt_loop.s.int_loop |= 1<<index;
532 asxx_prt_loop.s.int_loop &= ~(1<<index);
534 asxx_prt_loop.s.ext_loop |= 1<<index;
536 asxx_prt_loop.s.ext_loop &= ~(1<<index);
537 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64);
539 /* Force enables in internal loopback */
543 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
544 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
545 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
546 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
550 /* Restore the enable state */
551 gmx_cfg.s.en = original_enable;
552 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
556 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */