cvmx-helper-sgmii.c revision 215990
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 SGMII initialization, configuration,
50 * and monitoring.
51 *
52 * <hr>$Revision: 52004 $<hr>
53 */
54#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55#include <asm/octeon/cvmx.h>
56#include <asm/octeon/cvmx-config.h>
57#include <asm/octeon/cvmx-clock.h>
58#ifdef CVMX_ENABLE_PKO_FUNCTIONS
59#include <asm/octeon/cvmx-helper.h>
60#include <asm/octeon/cvmx-helper-board.h>
61#endif
62#include <asm/octeon/cvmx-pcsx-defs.h>
63#include <asm/octeon/cvmx-gmxx-defs.h>
64#include <asm/octeon/cvmx-ciu-defs.h>
65#else
66#if !defined(__FreeBSD__) || !defined(_KERNEL)
67#include "executive-config.h"
68#include "cvmx-config.h"
69#ifdef CVMX_ENABLE_PKO_FUNCTIONS
70
71#include "cvmx.h"
72#include "cvmx-sysinfo.h"
73#include "cvmx-mdio.h"
74#include "cvmx-helper.h"
75#include "cvmx-helper-board.h"
76#endif
77#else
78#include "cvmx.h"
79#include "cvmx-sysinfo.h"
80#include "cvmx-mdio.h"
81#include "cvmx-helper.h"
82#include "cvmx-helper-board.h"
83#endif
84#endif
85
86#ifdef CVMX_ENABLE_PKO_FUNCTIONS
87
88/**
89 * @INTERNAL
90 * Perform initialization required only once for an SGMII port.
91 *
92 * @param interface Interface to init
93 * @param index     Index of prot on the interface
94 *
95 * @return Zero on success, negative on failure
96 */
97static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
98{
99    const uint64_t clock_mhz = cvmx_clock_get_rate(CVMX_CLOCK_SCLK) / 1000000;
100    cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
101    cvmx_pcsx_linkx_timer_count_reg_t pcsx_linkx_timer_count_reg;
102    cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
103
104    /* Disable GMX */
105    gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
106    gmxx_prtx_cfg.s.en = 0;
107    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
108
109    /* Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the appropriate
110        value. 1000BASE-X specifies a 10ms interval. SGMII specifies a 1.6ms
111        interval. */
112    pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
113    pcsx_linkx_timer_count_reg.u64 = cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
114    if (pcsx_miscx_ctl_reg.s.mode)
115    {
116        /* 1000BASE-X */
117        pcsx_linkx_timer_count_reg.s.count = (10000ull * clock_mhz) >> 10;
118    }
119    else
120    {
121        /* SGMII */
122        pcsx_linkx_timer_count_reg.s.count = (1600ull * clock_mhz) >> 10;
123    }
124    cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface), pcsx_linkx_timer_count_reg.u64);
125
126    /* Write the advertisement register to be used as the
127        tx_Config_Reg<D15:D0> of the autonegotiation.
128        In 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
129        In SGMII PHY mode, tx_Config_Reg<D15:D0> is PCS*_SGM*_AN_ADV_REG.
130        In SGMII MAC mode, tx_Config_Reg<D15:D0> is the fixed value 0x4001, so
131        this step can be skipped. */
132    if (pcsx_miscx_ctl_reg.s.mode)
133    {
134        /* 1000BASE-X */
135        cvmx_pcsx_anx_adv_reg_t pcsx_anx_adv_reg;
136        pcsx_anx_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
137        pcsx_anx_adv_reg.s.rem_flt = 0;
138        pcsx_anx_adv_reg.s.pause = 3;
139        pcsx_anx_adv_reg.s.hfd = 1;
140        pcsx_anx_adv_reg.s.fd = 1;
141        cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface), pcsx_anx_adv_reg.u64);
142    }
143    else
144    {
145        if (pcsx_miscx_ctl_reg.s.mac_phy)
146        {
147            /* PHY Mode */
148            cvmx_pcsx_sgmx_an_adv_reg_t pcsx_sgmx_an_adv_reg;
149            pcsx_sgmx_an_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface));
150            pcsx_sgmx_an_adv_reg.s.link = 1;
151            pcsx_sgmx_an_adv_reg.s.dup = 1;
152            pcsx_sgmx_an_adv_reg.s.speed= 2;
153            cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface), pcsx_sgmx_an_adv_reg.u64);
154        }
155        else
156        {
157            /* MAC Mode - Nothing to do */
158        }
159    }
160    return 0;
161}
162
163
164/**
165 * @INTERNAL
166 * Initialize the SERTES link for the first time or after a loss
167 * of link.
168 *
169 * @param interface Interface to init
170 * @param index     Index of prot on the interface
171 *
172 * @return Zero on success, negative on failure
173 */
174static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
175{
176    cvmx_pcsx_mrx_control_reg_t control_reg;
177
178    /* Take PCS through a reset sequence.
179        PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
180        Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the value of
181            the other PCS*_MR*_CONTROL_REG bits).
182        Read PCS*_MR*_CONTROL_REG[RESET] until it changes value to zero. */
183    control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
184    if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
185    {
186        control_reg.s.reset = 1;
187        cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
188        if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_CONTROL_REG(index, interface), cvmx_pcsx_mrx_control_reg_t, reset, ==, 0, 10000))
189        {
190            cvmx_dprintf("SGMII%d: Timeout waiting for port %d to finish reset\n", interface, index);
191            return -1;
192        }
193    }
194
195    /* Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh sgmii negotiation starts. */
196    control_reg.s.rst_an = 1;
197    control_reg.s.an_en = 1;
198    control_reg.s.pwr_dn = 0;
199    cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
200
201    /* Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating that
202        sgmii autonegotiation is complete. In MAC mode this isn't an ethernet
203        link, but a link between Octeon and the PHY */
204    if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
205        CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface), cvmx_pcsx_mrx_status_reg_t, an_cpt, ==, 1, 10000))
206    {
207        //cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index);
208        return -1;
209    }
210    return 0;
211}
212
213
214/**
215 * @INTERNAL
216 * Configure an SGMII link to the specified speed after the SERTES
217 * link is up.
218 *
219 * @param interface Interface to init
220 * @param index     Index of prot on the interface
221 * @param link_info Link state to configure
222 *
223 * @return Zero on success, negative on failure
224 */
225static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface, int index, cvmx_helper_link_info_t link_info)
226{
227    int is_enabled;
228    cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
229    cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
230
231    /* Disable GMX before we make any changes. Remember the enable state */
232    gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
233    is_enabled = gmxx_prtx_cfg.s.en;
234    gmxx_prtx_cfg.s.en = 0;
235    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
236
237    /* Wait for GMX to be idle */
238    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000) ||
239        CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
240    {
241        cvmx_dprintf("SGMII%d: Timeout waiting for port %d to be idle\n", interface, index);
242        return -1;
243    }
244
245    /* Read GMX CFG again to make sure the disable completed */
246    gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
247
248    /* Get the misc control for PCS. We will need to set the duplication amount */
249    pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
250
251    /* Use GMXENO to force the link down if the status we get says it should be down */
252    pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
253
254    /* Only change the duplex setting if the link is up */
255    if (link_info.s.link_up)
256        gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
257
258    /* Do speed based setting for GMX */
259    switch (link_info.s.speed)
260    {
261        case 10:
262            gmxx_prtx_cfg.s.speed = 0;
263            gmxx_prtx_cfg.s.speed_msb = 1;
264            gmxx_prtx_cfg.s.slottime = 0;
265            pcsx_miscx_ctl_reg.s.samp_pt = 25; /* Setting from GMX-603 */
266            cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
267            cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
268            break;
269        case 100:
270            gmxx_prtx_cfg.s.speed = 0;
271            gmxx_prtx_cfg.s.speed_msb = 0;
272            gmxx_prtx_cfg.s.slottime = 0;
273            pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
274            cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
275            cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
276            break;
277        case 1000:
278            gmxx_prtx_cfg.s.speed = 1;
279            gmxx_prtx_cfg.s.speed_msb = 0;
280            gmxx_prtx_cfg.s.slottime = 1;
281            pcsx_miscx_ctl_reg.s.samp_pt = 1;
282            cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
283	    if (gmxx_prtx_cfg.s.duplex)
284                cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); // full duplex
285	    else
286                cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192); // half duplex
287            break;
288        default:
289            break;
290    }
291
292    /* Write the new misc control for PCS */
293    cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64);
294
295    /* Write the new GMX settings with the port still disabled */
296    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
297
298    /* Read GMX CFG again to make sure the config completed */
299    gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
300
301    /* Restore the enabled / disabled state */
302    gmxx_prtx_cfg.s.en = is_enabled;
303    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
304
305    return 0;
306}
307
308
309/**
310 * @INTERNAL
311 * Bring up the SGMII interface to be ready for packet I/O but
312 * leave I/O disabled using the GMX override. This function
313 * follows the bringup documented in 10.6.3 of the manual.
314 *
315 * @param interface Interface to bringup
316 * @param num_ports Number of ports on the interface
317 *
318 * @return Zero on success, negative on failure
319 */
320static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
321{
322    int index;
323
324    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
325    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
326    {
327        cvmx_ciu_qlm2_t ciu_qlm;
328        ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2);
329        ciu_qlm.s.txbypass = 1;
330        ciu_qlm.s.txdeemph = 0xf;
331        ciu_qlm.s.txmargin = 0xd;
332        cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64);
333    }
334
335    __cvmx_helper_setup_gmx(interface, num_ports);
336
337    for (index=0; index<num_ports; index++)
338    {
339        int ipd_port = cvmx_helper_get_ipd_port(interface, index);
340        __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
341        __cvmx_helper_sgmii_link_set(ipd_port, __cvmx_helper_sgmii_link_get(ipd_port));
342
343    }
344
345    return 0;
346}
347
348
349/**
350 * @INTERNAL
351 * Probe a SGMII interface and determine the number of ports
352 * connected to it. The SGMII interface should still be down after
353 * this call.
354 *
355 * @param interface Interface to probe
356 *
357 * @return Number of ports on the interface. Zero to disable.
358 */
359int __cvmx_helper_sgmii_probe(int interface)
360{
361    cvmx_gmxx_inf_mode_t mode;
362
363    /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
364        needs to be enabled before IPD otherwise per port backpressure
365        may not work properly */
366    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
367    mode.s.en = 1;
368    cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
369    return 4;
370}
371
372
373/**
374 * @INTERNAL
375 * Bringup and enable a SGMII interface. After this call packet
376 * I/O should be fully functional. This is called with IPD
377 * enabled but PKO disabled.
378 *
379 * @param interface Interface to bring up
380 *
381 * @return Zero on success, negative on failure
382 */
383int __cvmx_helper_sgmii_enable(int interface)
384{
385    int num_ports = cvmx_helper_ports_on_interface(interface);
386    int index;
387
388    __cvmx_helper_sgmii_hardware_init(interface, num_ports);
389
390    for (index=0; index<num_ports; index++)
391    {
392        cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
393        gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
394        gmxx_prtx_cfg.s.en = 1;
395        cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
396    }
397    return 0;
398}
399
400
401/**
402 * @INTERNAL
403 * Return the link state of an IPD/PKO port as returned by
404 * auto negotiation. The result of this function may not match
405 * Octeon's link config if auto negotiation has changed since
406 * the last call to cvmx_helper_link_set().
407 *
408 * @param ipd_port IPD/PKO port to query
409 *
410 * @return Link state
411 */
412cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
413{
414    cvmx_helper_link_info_t result;
415    cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
416    int interface = cvmx_helper_get_interface_num(ipd_port);
417    int index = cvmx_helper_get_interface_index_num(ipd_port);
418    cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg;
419
420    result.u64 = 0;
421
422    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
423    {
424        /* The simulator gives you a simulated 1Gbps full duplex link */
425        result.s.link_up = 1;
426        result.s.full_duplex = 1;
427        result.s.speed = 1000;
428        return result;
429    }
430
431    pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
432    if (pcsx_mrx_control_reg.s.loopbck1)
433    {
434        /* Force 1Gbps full duplex link for internal loopback */
435        result.s.link_up = 1;
436        result.s.full_duplex = 1;
437        result.s.speed = 1000;
438        return result;
439    }
440
441
442    pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
443    if (pcsx_miscx_ctl_reg.s.mode)
444    {
445        /* 1000BASE-X */
446        // FIXME
447    }
448    else
449    {
450        if (pcsx_miscx_ctl_reg.s.mac_phy)
451        {
452            /* PHY Mode */
453            cvmx_pcsx_mrx_status_reg_t pcsx_mrx_status_reg;
454            cvmx_pcsx_anx_results_reg_t pcsx_anx_results_reg;
455
456            /* Don't bother continuing if the SERTES low level link is down */
457            pcsx_mrx_status_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface));
458            if (pcsx_mrx_status_reg.s.lnk_st == 0)
459            {
460                if (__cvmx_helper_sgmii_hardware_init_link(interface, index) != 0)
461                    return result;
462            }
463
464            /* Read the autoneg results */
465            pcsx_anx_results_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface));
466            if (pcsx_anx_results_reg.s.an_cpt)
467            {
468                /* Auto negotiation is complete. Set status accordingly */
469                result.s.full_duplex = pcsx_anx_results_reg.s.dup;
470                result.s.link_up = pcsx_anx_results_reg.s.link_ok;
471                switch (pcsx_anx_results_reg.s.spd)
472                {
473                    case 0:
474                        result.s.speed = 10;
475                        break;
476                    case 1:
477                        result.s.speed = 100;
478                        break;
479                    case 2:
480                        result.s.speed = 1000;
481                        break;
482                    default:
483                        result.s.speed = 0;
484                        result.s.link_up = 0;
485                        break;
486                }
487            }
488            else
489            {
490                /* Auto negotiation isn't complete. Return link down */
491                result.s.speed = 0;
492                result.s.link_up = 0;
493            }
494        }
495        else /* MAC Mode */
496        {
497            result = __cvmx_helper_board_link_get(ipd_port);
498        }
499    }
500    return result;
501}
502
503
504/**
505 * @INTERNAL
506 * Configure an IPD/PKO port for the specified link state. This
507 * function does not influence auto negotiation at the PHY level.
508 * The passed link state must always match the link state returned
509 * by cvmx_helper_link_get(). It is normally best to use
510 * cvmx_helper_link_autoconf() instead.
511 *
512 * @param ipd_port  IPD/PKO port to configure
513 * @param link_info The new link state
514 *
515 * @return Zero on success, negative on failure
516 */
517int __cvmx_helper_sgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
518{
519    int interface = cvmx_helper_get_interface_num(ipd_port);
520    int index = cvmx_helper_get_interface_index_num(ipd_port);
521    __cvmx_helper_sgmii_hardware_init_link(interface, index);
522    return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, link_info);
523}
524
525/**
526 * @INTERNAL
527 * Configure a port for internal and/or external loopback. Internal loopback
528 * causes packets sent by the port to be received by Octeon. External loopback
529 * causes packets received from the wire to sent out again.
530 *
531 * @param ipd_port IPD/PKO port to loopback.
532 * @param enable_internal
533 *                 Non zero if you want internal loopback
534 * @param enable_external
535 *                 Non zero if you want external loopback
536 *
537 * @return Zero on success, negative on failure.
538 */
539int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
540{
541    int interface = cvmx_helper_get_interface_num(ipd_port);
542    int index = cvmx_helper_get_interface_index_num(ipd_port);
543    cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg;
544    cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
545
546    pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
547    pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
548    cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), pcsx_mrx_control_reg.u64);
549
550    pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
551    pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
552    cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64);
553
554    __cvmx_helper_sgmii_hardware_init_link(interface, index);
555    return 0;
556}
557
558#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
559