1 /***********************license start***************
2 * Copyright (c) 2003-2008 Cavium Networks (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 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
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.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
47 * Functions for SGMII initialization, configuration,
50 * <hr>$Revision: 42417 $<hr>
53 #include "cvmx-sysinfo.h"
54 #include "cvmx-mdio.h"
55 #include "cvmx-helper.h"
56 #include "cvmx-helper-board.h"
58 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
61 * Perform initialization required only once for an SGMII port.
63 * @param interface Interface to init
64 * @param index Index of prot on the interface
66 * @return Zero on success, negative on failure
68 static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
70 const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
71 cvmx_pcsx_miscx_ctl_reg_t pcs_misc_ctl_reg;
72 cvmx_pcsx_linkx_timer_count_reg_t pcsx_linkx_timer_count_reg;
73 cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
76 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
77 gmxx_prtx_cfg.s.en = 0;
78 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
80 /* Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the appropriate
81 value. 1000BASE-X specifies a 10ms interval. SGMII specifies a 1.6ms
83 pcs_misc_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
84 pcsx_linkx_timer_count_reg.u64 = cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
85 if (pcs_misc_ctl_reg.s.mode)
88 pcsx_linkx_timer_count_reg.s.count = (10000ull * clock_mhz) >> 10;
93 pcsx_linkx_timer_count_reg.s.count = (1600ull * clock_mhz) >> 10;
95 cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface), pcsx_linkx_timer_count_reg.u64);
97 /* Write the advertisement register to be used as the
98 tx_Config_Reg<D15:D0> of the autonegotiation.
99 In 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
100 In SGMII PHY mode, tx_Config_Reg<D15:D0> is PCS*_SGM*_AN_ADV_REG.
101 In SGMII MAC mode, tx_Config_Reg<D15:D0> is the fixed value 0x4001, so
102 this step can be skipped. */
103 if (pcs_misc_ctl_reg.s.mode)
106 cvmx_pcsx_anx_adv_reg_t pcsx_anx_adv_reg;
107 pcsx_anx_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
108 pcsx_anx_adv_reg.s.rem_flt = 0;
109 pcsx_anx_adv_reg.s.pause = 3;
110 pcsx_anx_adv_reg.s.hfd = 1;
111 pcsx_anx_adv_reg.s.fd = 1;
112 cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface), pcsx_anx_adv_reg.u64);
116 cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
117 pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
118 if (pcsx_miscx_ctl_reg.s.mac_phy)
121 cvmx_pcsx_sgmx_an_adv_reg_t pcsx_sgmx_an_adv_reg;
122 pcsx_sgmx_an_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface));
123 pcsx_sgmx_an_adv_reg.s.link = 1;
124 pcsx_sgmx_an_adv_reg.s.dup = 1;
125 pcsx_sgmx_an_adv_reg.s.speed= 2;
126 cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface), pcsx_sgmx_an_adv_reg.u64);
130 /* MAC Mode - Nothing to do */
139 * Initialize the SERTES link for the first time or after a loss
142 * @param interface Interface to init
143 * @param index Index of prot on the interface
145 * @return Zero on success, negative on failure
147 static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
149 cvmx_pcsx_mrx_control_reg_t control_reg;
151 /* Take PCS through a reset sequence.
152 PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
153 Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the value of
154 the other PCS*_MR*_CONTROL_REG bits).
155 Read PCS*_MR*_CONTROL_REG[RESET] until it changes value to zero. */
156 control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
157 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
159 control_reg.s.reset = 1;
160 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
161 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_CONTROL_REG(index, interface), cvmx_pcsx_mrx_control_reg_t, reset, ==, 0, 10000))
163 cvmx_dprintf("SGMII%d: Timeout waiting for port %d to finish reset\n", interface, index);
168 /* Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh sgmii negotiation starts. */
169 control_reg.s.rst_an = 1;
170 control_reg.s.an_en = 1;
171 control_reg.s.pwr_dn = 0;
172 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
174 /* Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating that
175 sgmii autonegotiation is complete. In MAC mode this isn't an ethernet
176 link, but a link between Octeon and the PHY */
177 if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
178 CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface), cvmx_pcsx_mrx_status_reg_t, an_cpt, ==, 1, 10000))
180 //cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index);
189 * Configure an SGMII link to the specified speed after the SERTES
192 * @param interface Interface to init
193 * @param index Index of prot on the interface
194 * @param link_info Link state to configure
196 * @return Zero on success, negative on failure
198 static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface, int index, cvmx_helper_link_info_t link_info)
201 cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
202 cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
204 /* Disable GMX before we make any changes. Remember the enable state */
205 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
206 is_enabled = gmxx_prtx_cfg.s.en;
207 gmxx_prtx_cfg.s.en = 0;
208 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
210 /* Wait for GMX to be idle */
211 if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000) ||
212 CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
214 cvmx_dprintf("SGMII%d: Timeout waiting for port %d to be idle\n", interface, index);
218 /* Read GMX CFG again to make sure the disable completed */
219 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
221 /* Get the misc control for PCS. We will need to set the duplication amount */
222 pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
224 /* Use GMXENO to force the link down if the status we get says it should be down */
225 pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
227 /* Only change the duplex setting if the link is up */
228 if (link_info.s.link_up)
229 gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
231 /* Do speed based setting for GMX */
232 switch (link_info.s.speed)
235 gmxx_prtx_cfg.s.speed = 0;
236 gmxx_prtx_cfg.s.speed_msb = 1;
237 gmxx_prtx_cfg.s.slottime = 0;
238 pcsx_miscx_ctl_reg.s.samp_pt = 25; /* Setting from GMX-603 */
239 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
240 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
243 gmxx_prtx_cfg.s.speed = 0;
244 gmxx_prtx_cfg.s.speed_msb = 0;
245 gmxx_prtx_cfg.s.slottime = 0;
246 pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
247 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
248 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
251 gmxx_prtx_cfg.s.speed = 1;
252 gmxx_prtx_cfg.s.speed_msb = 0;
253 gmxx_prtx_cfg.s.slottime = 1;
254 pcsx_miscx_ctl_reg.s.samp_pt = 1;
255 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
256 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
262 /* Write the new misc control for PCS */
263 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64);
265 /* Write the new GMX settings with the port still disabled */
266 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
268 /* Read GMX CFG again to make sure the config completed */
269 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
271 /* Restore the enabled / disabled state */
272 gmxx_prtx_cfg.s.en = is_enabled;
273 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
281 * Bring up the SGMII interface to be ready for packet I/O but
282 * leave I/O disabled using the GMX override. This function
283 * follows the bringup documented in 10.6.3 of the manual.
285 * @param interface Interface to bringup
286 * @param num_ports Number of ports on the interface
288 * @return Zero on success, negative on failure
290 static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
294 __cvmx_helper_setup_gmx(interface, num_ports);
296 for (index=0; index<num_ports; index++)
298 int ipd_port = cvmx_helper_get_ipd_port(interface, index);
299 __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
300 __cvmx_helper_sgmii_link_set(ipd_port, __cvmx_helper_sgmii_link_get(ipd_port));
310 * Probe a SGMII interface and determine the number of ports
311 * connected to it. The SGMII interface should still be down after
314 * @param interface Interface to probe
316 * @return Number of ports on the interface. Zero to disable.
318 int __cvmx_helper_sgmii_probe(int interface)
320 cvmx_gmxx_inf_mode_t mode;
322 /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
323 needs to be enabled before IPD otherwise per port backpressure
324 may not work properly */
325 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
327 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
334 * Bringup and enable a SGMII interface. After this call packet
335 * I/O should be fully functional. This is called with IPD
336 * enabled but PKO disabled.
338 * @param interface Interface to bring up
340 * @return Zero on success, negative on failure
342 int __cvmx_helper_sgmii_enable(int interface)
344 int num_ports = cvmx_helper_ports_on_interface(interface);
347 __cvmx_helper_sgmii_hardware_init(interface, num_ports);
349 for (index=0; index<num_ports; index++)
351 cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
352 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
353 gmxx_prtx_cfg.s.en = 1;
354 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
362 * Return the link state of an IPD/PKO port as returned by
363 * auto negotiation. The result of this function may not match
364 * Octeon's link config if auto negotiation has changed since
365 * the last call to cvmx_helper_link_set().
367 * @param ipd_port IPD/PKO port to query
371 cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
373 cvmx_helper_link_info_t result;
374 cvmx_pcsx_miscx_ctl_reg_t pcs_misc_ctl_reg;
375 int interface = cvmx_helper_get_interface_num(ipd_port);
376 int index = cvmx_helper_get_interface_index_num(ipd_port);
377 cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg;
381 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
383 /* The simulator gives you a simulated 1Gbps full duplex link */
384 result.s.link_up = 1;
385 result.s.full_duplex = 1;
386 result.s.speed = 1000;
390 pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
391 if (pcsx_mrx_control_reg.s.loopbck1)
393 /* Force 1Gbps full duplex link for internal loopback */
394 result.s.link_up = 1;
395 result.s.full_duplex = 1;
396 result.s.speed = 1000;
401 pcs_misc_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
402 if (pcs_misc_ctl_reg.s.mode)
409 cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
410 pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
411 if (pcsx_miscx_ctl_reg.s.mac_phy)
414 cvmx_pcsx_mrx_status_reg_t pcsx_mrx_status_reg;
415 cvmx_pcsx_anx_results_reg_t pcsx_anx_results_reg;
417 /* Don't bother continuing if the SERTES low level link is down */
418 pcsx_mrx_status_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface));
419 if (pcsx_mrx_status_reg.s.lnk_st == 0)
421 if (__cvmx_helper_sgmii_hardware_init_link(interface, index) != 0)
425 /* Read the autoneg results */
426 pcsx_anx_results_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface));
427 if (pcsx_anx_results_reg.s.an_cpt)
429 /* Auto negotiation is complete. Set status accordingly */
430 result.s.full_duplex = pcsx_anx_results_reg.s.dup;
431 result.s.link_up = pcsx_anx_results_reg.s.link_ok;
432 switch (pcsx_anx_results_reg.s.spd)
438 result.s.speed = 100;
441 result.s.speed = 1000;
445 result.s.link_up = 0;
451 /* Auto negotiation isn't complete. Return link down */
453 result.s.link_up = 0;
458 result = __cvmx_helper_board_link_get(ipd_port);
467 * Configure an IPD/PKO port for the specified link state. This
468 * function does not influence auto negotiation at the PHY level.
469 * The passed link state must always match the link state returned
470 * by cvmx_helper_link_get(). It is normally best to use
471 * cvmx_helper_link_autoconf() instead.
473 * @param ipd_port IPD/PKO port to configure
474 * @param link_info The new link state
476 * @return Zero on success, negative on failure
478 int __cvmx_helper_sgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
480 int interface = cvmx_helper_get_interface_num(ipd_port);
481 int index = cvmx_helper_get_interface_index_num(ipd_port);
482 __cvmx_helper_sgmii_hardware_init_link(interface, index);
483 return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, link_info);
488 * Configure a port for internal and/or external loopback. Internal loopback
489 * causes packets sent by the port to be received by Octeon. External loopback
490 * causes packets received from the wire to sent out again.
492 * @param ipd_port IPD/PKO port to loopback.
493 * @param enable_internal
494 * Non zero if you want internal loopback
495 * @param enable_external
496 * Non zero if you want external loopback
498 * @return Zero on success, negative on failure.
500 int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
502 int interface = cvmx_helper_get_interface_num(ipd_port);
503 int index = cvmx_helper_get_interface_index_num(ipd_port);
504 cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg;
505 cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
507 pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
508 pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
509 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), pcsx_mrx_control_reg.u64);
511 pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
512 pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
513 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64);
515 __cvmx_helper_sgmii_hardware_init_link(interface, index);
519 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */