]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/octeon-sdk/cvmx-helper-rgmii.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / octeon-sdk / cvmx-helper-rgmii.c
1 /***********************license start***************
2  * Copyright (c) 2003-2010  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  * 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  NETWORKS 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 RGMII/GMII/MII initialization, configuration,
50  * and monitoring.
51  *
52  * <hr>$Revision: 49448 $<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-pko.h>
59 #include <asm/octeon/cvmx-helper.h>
60 #include <asm/octeon/cvmx-helper-board.h>
61 #endif
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>
67
68 #else
69 #if !defined(__FreeBSD__) || !defined(_KERNEL)
70 #include "executive-config.h"
71 #include "cvmx-config.h"
72 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
73
74 #include "cvmx.h"
75 #include "cvmx-sysinfo.h"
76 #include "cvmx-mdio.h"
77 #include "cvmx-pko.h"
78 #include "cvmx-helper.h"
79 #include "cvmx-helper-board.h"
80 #endif
81 #else
82 #include "cvmx.h"
83 #include "cvmx-sysinfo.h"
84 #include "cvmx-mdio.h"
85 #include "cvmx-pko.h"
86 #include "cvmx-helper.h"
87 #include "cvmx-helper-board.h"
88 #endif
89 #endif
90
91 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
92
93 /**
94  * @INTERNAL
95  * Probe RGMII ports and determine the number present
96  *
97  * @param interface Interface to probe
98  *
99  * @return Number of RGMII/GMII/MII ports (0-4).
100  */
101 int __cvmx_helper_rgmii_probe(int interface)
102 {
103     int num_ports = 0;
104     cvmx_gmxx_inf_mode_t mode;
105     mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
106
107     if (mode.s.type)
108     {
109         if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
110         {
111             cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n");
112         }
113         else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
114         {
115             /* On these chips "type" says we're in GMII/MII mode. This
116                 limits us to 2 ports */
117             num_ports = 2;
118         }
119         else
120         {
121             cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
122         }
123     }
124     else
125     {
126         if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
127         {
128             num_ports = 4;
129         }
130         else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
131         {
132             num_ports = 3;
133         }
134         else
135         {
136             cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__);
137         }
138     }
139     return num_ports;
140 }
141
142
143 /**
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.
147  *
148  * @param port   IPD port number to loop.
149  */
150 void cvmx_helper_rgmii_internal_loopback(int port)
151 {
152     int interface = (port >> 4) & 1;
153     int index = port & 0xf;
154     uint64_t tmp;
155
156     cvmx_gmxx_prtx_cfg_t gmx_cfg;
157     gmx_cfg.u64 = 0;
158     gmx_cfg.s.duplex = 1;
159     gmx_cfg.s.slottime = 1;
160     gmx_cfg.s.speed = 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);
171     gmx_cfg.s.en = 1;
172     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
173 }
174
175
176 /**
177  * @INTERNAL
178  * Configure all of the ASX, GMX, and PKO regsiters required
179  * to get RGMII to function on the supplied interface.
180  *
181  * @param interface PKO Interface to configure (0 or 1)
182  *
183  * @return Zero on success
184  */
185 int __cvmx_helper_rgmii_enable(int interface)
186 {
187     int num_ports = cvmx_helper_ports_on_interface(interface);
188     int port;
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;
192
193     mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
194
195     if (mode.s.en == 0)
196         return -1;
197     if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1)   /* Ignore SPI interfaces */
198         return -1;
199
200     /* Configure the ASX registers needed to use the RGMII ports */
201     asx_tx.u64 = 0;
202     asx_tx.s.prt_en = cvmx_build_mask(num_ports);
203     cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64);
204
205     asx_rx.u64 = 0;
206     asx_rx.s.prt_en = cvmx_build_mask(num_ports);
207     cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64);
208
209     /* Configure the GMX registers needed to use the RGMII ports */
210     for (port=0; port<num_ports; port++)
211     {
212         /* Setting of CVMX_GMXX_TXX_THRESH has been moved to
213             __cvmx_helper_setup_gmx() */
214
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);
221
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
225             restart the flow. */
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);
228
229         /*
230          * Board types we have to know at compile-time.
231          */
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);
235 #else
236         /*
237          * Vendor-defined board types.
238          */
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:
243             if (port == 0) {
244                 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 4);
245             } else {
246                 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 7);
247             }
248             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0);
249             break;
250         }
251 #else
252         /*
253          * For board types we can determine at runtime.
254          */
255         if (OCTEON_IS_MODEL(OCTEON_CN50XX))
256         {
257             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
258             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16);
259         }
260         else
261         {
262             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24);
263             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24);
264         }
265 #endif
266 #endif
267     }
268
269     __cvmx_helper_setup_gmx(interface, num_ports);
270
271     /* enable the ports now */
272     for (port=0; port<num_ports; port++)
273     {
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));
277         gmx_cfg.s.en = 1;
278         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64);
279     }
280     return 0;
281 }
282
283
284 /**
285  * @INTERNAL
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().
290  *
291  * @param ipd_port IPD/PKO port to query
292  *
293  * @return Link state
294  */
295 cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
296 {
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;
300
301     asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
302     if (asxx_prt_loop.s.int_loop & (1<<index))
303     {
304         /* Force 1Gbps full duplex on internal loopback */
305         cvmx_helper_link_info_t result;
306         result.u64 = 0;
307         result.s.full_duplex = 1;
308         result.s.link_up = 1;
309         result.s.speed = 1000;
310         return result;
311     }
312     else
313         return __cvmx_helper_board_link_get(ipd_port);
314 }
315
316
317 /**
318  * @INTERNAL
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.
324  *
325  * @param ipd_port  IPD/PKO port to configure
326  * @param link_info The new link state
327  *
328  * @return Zero on success, negative on failure
329  */
330 int __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
331 {
332     int result = 0;
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;
341     int i;
342
343     /* Ignore speed sets in the simulator */
344     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
345         return 0;
346
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;
350
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));
354
355     /* Disable all queues so that TX should become idle */
356     for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
357     {
358         int queue = cvmx_pko_get_base_queue(ipd_port) + i;
359         cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
360         pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS);
361         pko_mem_queue_qos.s.pid = ipd_port;
362         pko_mem_queue_qos.s.qid = queue;
363         pko_mem_queue_qos_save[i] = pko_mem_queue_qos;
364         pko_mem_queue_qos.s.qos_mask = 0;
365         cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64);
366     }
367
368     /* Disable backpressure */
369     gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
370     gmx_tx_ovr_bp_save = gmx_tx_ovr_bp;
371     gmx_tx_ovr_bp.s.bp &= ~(1<<index);
372     gmx_tx_ovr_bp.s.en |= 1<<index;
373     cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64);
374     cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
375
376     /* Poll the GMX state machine waiting for it to become idle. Preferably we
377         should only change speed when it is idle. If it doesn't become idle we
378         will still do the speed change, but there is a slight chance that GMX
379         will lockup */
380     cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880);
381     CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000);
382     CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000);
383
384     /* Disable the port before we make any changes */
385     new_gmx_cfg.s.en = 0;
386     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
387     cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
388
389     /* Set full/half duplex */
390     if (!link_info.s.link_up)
391         new_gmx_cfg.s.duplex = 1;   /* Force full duplex on down links */
392     else
393         new_gmx_cfg.s.duplex = link_info.s.full_duplex;
394
395     /* Set the link speed. Anything unknown is set to 1Gbps */
396     if (link_info.s.speed == 10)
397     {
398         new_gmx_cfg.s.slottime = 0;
399         new_gmx_cfg.s.speed = 0;
400     }
401     else if (link_info.s.speed == 100)
402     {
403         new_gmx_cfg.s.slottime = 0;
404         new_gmx_cfg.s.speed = 0;
405     }
406     else
407     {
408         new_gmx_cfg.s.slottime = 1;
409         new_gmx_cfg.s.speed = 1;
410     }
411
412     /* Adjust the clocks */
413     if (link_info.s.speed == 10)
414     {
415         cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50);
416         cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
417         cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
418     }
419     else if (link_info.s.speed == 100)
420     {
421         cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5);
422         cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
423         cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
424     }
425     else
426     {
427         cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
428         cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
429         cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
430     }
431
432     if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
433     {
434         if ((link_info.s.speed == 10) || (link_info.s.speed == 100))
435         {
436             cvmx_gmxx_inf_mode_t mode;
437             mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
438
439             /*
440             ** Port  .en  .type  .p0mii  Configuration
441             ** ----  ---  -----  ------  -----------------------------------------
442             **  X      0     X      X    All links are disabled.
443             **  0      1     X      0    Port 0 is RGMII
444             **  0      1     X      1    Port 0 is MII
445             **  1      1     0      X    Ports 1 and 2 are configured as RGMII ports.
446             **  1      1     1      X    Port 1: GMII/MII; Port 2: disabled. GMII or
447             **                           MII port is selected by GMX_PRT1_CFG[SPEED].
448             */
449
450             /* In MII mode, CLK_CNT = 1. */
451             if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1)))
452             {
453                 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
454             }
455         }
456     }
457
458     /* Do a read to make sure all setup stuff is complete */
459     cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
460
461     /* Save the new GMX setting without enabling the port */
462     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
463
464     /* Enable the lowest level RX */
465     cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
466                    cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index));
467
468     /* Re-enable the TX path */
469     for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++)
470     {
471         int queue = cvmx_pko_get_base_queue(ipd_port) + i;
472         cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
473         cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64);
474     }
475
476     /* Restore backpressure */
477     cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64);
478
479     /* Restore the GMX enable state. Port config is complete */
480     new_gmx_cfg.s.en = original_gmx_cfg.s.en;
481     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
482
483     return result;
484 }
485
486
487 /**
488  * @INTERNAL
489  * Configure a port for internal and/or external loopback. Internal loopback
490  * causes packets sent by the port to be received by Octeon. External loopback
491  * causes packets received from the wire to sent out again.
492  *
493  * @param ipd_port IPD/PKO port to loopback.
494  * @param enable_internal
495  *                 Non zero if you want internal loopback
496  * @param enable_external
497  *                 Non zero if you want external loopback
498  *
499  * @return Zero on success, negative on failure.
500  */
501 int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
502 {
503     int interface = cvmx_helper_get_interface_num(ipd_port);
504     int index = cvmx_helper_get_interface_index_num(ipd_port);
505     int original_enable;
506     cvmx_gmxx_prtx_cfg_t gmx_cfg;
507     cvmx_asxx_prt_loop_t asxx_prt_loop;
508
509     /* Read the current enable state and save it */
510     gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
511     original_enable = gmx_cfg.s.en;
512     /* Force port to be disabled */
513     gmx_cfg.s.en = 0;
514     if (enable_internal)
515     {
516         /* Force speed if we're doing internal loopback */
517         gmx_cfg.s.duplex = 1;
518         gmx_cfg.s.slottime = 1;
519         gmx_cfg.s.speed = 1;
520         cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
521         cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
522         cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
523     }
524     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
525
526     /* Set the loopback bits */
527     asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
528     if (enable_internal)
529         asxx_prt_loop.s.int_loop |= 1<<index;
530     else
531         asxx_prt_loop.s.int_loop &= ~(1<<index);
532     if (enable_external)
533         asxx_prt_loop.s.ext_loop |= 1<<index;
534     else
535         asxx_prt_loop.s.ext_loop &= ~(1<<index);
536     cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64);
537
538     /* Force enables in internal loopback */
539     if (enable_internal)
540     {
541         uint64_t tmp;
542         tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
543         cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
544         tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
545         cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
546         original_enable = 1;
547     }
548
549     /* Restore the enable state */
550     gmx_cfg.s.en = original_enable;
551     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
552     return 0;
553 }
554
555 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */
556