1 /***********************license start***************
2 * Author: Cavium Networks
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
7 * Copyright (c) 2003-2008 Cavium Networks
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
29 * Functions for SGMII initialization, configuration,
33 #include <asm/octeon/octeon.h>
35 #include <asm/octeon/cvmx-config.h>
37 #include <asm/octeon/cvmx-helper.h>
38 #include <asm/octeon/cvmx-helper-board.h>
40 #include <asm/octeon/cvmx-gmxx-defs.h>
41 #include <asm/octeon/cvmx-pcsx-defs.h>
43 void __cvmx_interrupt_gmxx_enable(int interface
);
44 void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index
, int block
);
45 void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index
);
48 * Perform initialization required only once for an SGMII port.
50 * @interface: Interface to init
51 * @index: Index of prot on the interface
53 * Returns Zero on success, negative on failure
55 static int __cvmx_helper_sgmii_hardware_init_one_time(int interface
, int index
)
57 const uint64_t clock_mhz
= cvmx_sysinfo_get()->cpu_clock_hz
/ 1000000;
58 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg
;
59 union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg
;
60 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg
;
63 gmxx_prtx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
64 gmxx_prtx_cfg
.s
.en
= 0;
65 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmxx_prtx_cfg
.u64
);
68 * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
69 * appropriate value. 1000BASE-X specifies a 10ms
70 * interval. SGMII specifies a 1.6ms interval.
72 pcs_misc_ctl_reg
.u64
=
73 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
));
74 pcsx_linkx_timer_count_reg
.u64
=
75 cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index
, interface
));
76 if (pcs_misc_ctl_reg
.s
.mode
) {
78 pcsx_linkx_timer_count_reg
.s
.count
=
79 (10000ull * clock_mhz
) >> 10;
82 pcsx_linkx_timer_count_reg
.s
.count
=
83 (1600ull * clock_mhz
) >> 10;
85 cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index
, interface
),
86 pcsx_linkx_timer_count_reg
.u64
);
89 * Write the advertisement register to be used as the
90 * tx_Config_Reg<D15:D0> of the autonegotiation. In
91 * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
92 * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
93 * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode,
94 * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
95 * step can be skipped.
97 if (pcs_misc_ctl_reg
.s
.mode
) {
99 union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg
;
100 pcsx_anx_adv_reg
.u64
=
101 cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index
, interface
));
102 pcsx_anx_adv_reg
.s
.rem_flt
= 0;
103 pcsx_anx_adv_reg
.s
.pause
= 3;
104 pcsx_anx_adv_reg
.s
.hfd
= 1;
105 pcsx_anx_adv_reg
.s
.fd
= 1;
106 cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index
, interface
),
107 pcsx_anx_adv_reg
.u64
);
109 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg
;
110 pcsx_miscx_ctl_reg
.u64
=
111 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
));
112 if (pcsx_miscx_ctl_reg
.s
.mac_phy
) {
114 union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg
;
115 pcsx_sgmx_an_adv_reg
.u64
=
116 cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
118 pcsx_sgmx_an_adv_reg
.s
.link
= 1;
119 pcsx_sgmx_an_adv_reg
.s
.dup
= 1;
120 pcsx_sgmx_an_adv_reg
.s
.speed
= 2;
121 cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
123 pcsx_sgmx_an_adv_reg
.u64
);
125 /* MAC Mode - Nothing to do */
132 * Initialize the SERTES link for the first time or after a loss
135 * @interface: Interface to init
136 * @index: Index of prot on the interface
138 * Returns Zero on success, negative on failure
140 static int __cvmx_helper_sgmii_hardware_init_link(int interface
, int index
)
142 union cvmx_pcsx_mrx_control_reg control_reg
;
145 * Take PCS through a reset sequence.
146 * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
147 * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
148 * value of the other PCS*_MR*_CONTROL_REG bits). Read
149 * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
153 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index
, interface
));
154 if (cvmx_sysinfo_get()->board_type
!= CVMX_BOARD_TYPE_SIM
) {
155 control_reg
.s
.reset
= 1;
156 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index
, interface
),
158 if (CVMX_WAIT_FOR_FIELD64
159 (CVMX_PCSX_MRX_CONTROL_REG(index
, interface
),
160 union cvmx_pcsx_mrx_control_reg
, reset
, ==, 0, 10000)) {
161 cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
169 * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
170 * sgmii negotiation starts.
172 control_reg
.s
.rst_an
= 1;
173 control_reg
.s
.an_en
= 1;
174 control_reg
.s
.pwr_dn
= 0;
175 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index
, interface
),
179 * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
180 * that sgmii autonegotiation is complete. In MAC mode this
181 * isn't an ethernet link, but a link between Octeon and the
184 if ((cvmx_sysinfo_get()->board_type
!= CVMX_BOARD_TYPE_SIM
) &&
185 CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index
, interface
),
186 union cvmx_pcsx_mrx_status_reg
, an_cpt
, ==, 1,
188 /* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */
195 * Configure an SGMII link to the specified speed after the SERTES
198 * @interface: Interface to init
199 * @index: Index of prot on the interface
200 * @link_info: Link state to configure
202 * Returns Zero on success, negative on failure
204 static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface
,
206 cvmx_helper_link_info_t
210 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg
;
211 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg
;
213 /* Disable GMX before we make any changes. Remember the enable state */
214 gmxx_prtx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
215 is_enabled
= gmxx_prtx_cfg
.s
.en
;
216 gmxx_prtx_cfg
.s
.en
= 0;
217 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmxx_prtx_cfg
.u64
);
219 /* Wait for GMX to be idle */
220 if (CVMX_WAIT_FOR_FIELD64
221 (CVMX_GMXX_PRTX_CFG(index
, interface
), union cvmx_gmxx_prtx_cfg
,
222 rx_idle
, ==, 1, 10000)
223 || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index
, interface
),
224 union cvmx_gmxx_prtx_cfg
, tx_idle
, ==, 1,
227 ("SGMII%d: Timeout waiting for port %d to be idle\n",
232 /* Read GMX CFG again to make sure the disable completed */
233 gmxx_prtx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
236 * Get the misc control for PCS. We will need to set the
237 * duplication amount.
239 pcsx_miscx_ctl_reg
.u64
=
240 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
));
243 * Use GMXENO to force the link down if the status we get says
246 pcsx_miscx_ctl_reg
.s
.gmxeno
= !link_info
.s
.link_up
;
248 /* Only change the duplex setting if the link is up */
249 if (link_info
.s
.link_up
)
250 gmxx_prtx_cfg
.s
.duplex
= link_info
.s
.full_duplex
;
252 /* Do speed based setting for GMX */
253 switch (link_info
.s
.speed
) {
255 gmxx_prtx_cfg
.s
.speed
= 0;
256 gmxx_prtx_cfg
.s
.speed_msb
= 1;
257 gmxx_prtx_cfg
.s
.slottime
= 0;
258 /* Setting from GMX-603 */
259 pcsx_miscx_ctl_reg
.s
.samp_pt
= 25;
260 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index
, interface
), 64);
261 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index
, interface
), 0);
264 gmxx_prtx_cfg
.s
.speed
= 0;
265 gmxx_prtx_cfg
.s
.speed_msb
= 0;
266 gmxx_prtx_cfg
.s
.slottime
= 0;
267 pcsx_miscx_ctl_reg
.s
.samp_pt
= 0x5;
268 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index
, interface
), 64);
269 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index
, interface
), 0);
272 gmxx_prtx_cfg
.s
.speed
= 1;
273 gmxx_prtx_cfg
.s
.speed_msb
= 0;
274 gmxx_prtx_cfg
.s
.slottime
= 1;
275 pcsx_miscx_ctl_reg
.s
.samp_pt
= 1;
276 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index
, interface
), 512);
277 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index
, interface
), 8192);
283 /* Write the new misc control for PCS */
284 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
),
285 pcsx_miscx_ctl_reg
.u64
);
287 /* Write the new GMX settings with the port still disabled */
288 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmxx_prtx_cfg
.u64
);
290 /* Read GMX CFG again to make sure the config completed */
291 gmxx_prtx_cfg
.u64
= cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
293 /* Restore the enabled / disabled state */
294 gmxx_prtx_cfg
.s
.en
= is_enabled
;
295 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
), gmxx_prtx_cfg
.u64
);
301 * Bring up the SGMII interface to be ready for packet I/O but
302 * leave I/O disabled using the GMX override. This function
303 * follows the bringup documented in 10.6.3 of the manual.
305 * @interface: Interface to bringup
306 * @num_ports: Number of ports on the interface
308 * Returns Zero on success, negative on failure
310 static int __cvmx_helper_sgmii_hardware_init(int interface
, int num_ports
)
314 __cvmx_helper_setup_gmx(interface
, num_ports
);
316 for (index
= 0; index
< num_ports
; index
++) {
317 int ipd_port
= cvmx_helper_get_ipd_port(interface
, index
);
318 __cvmx_helper_sgmii_hardware_init_one_time(interface
, index
);
319 /* Linux kernel driver will call ....link_set with the
320 * proper link state. In the simulator there is no
321 * link state polling and hence it is set from
324 if (cvmx_sysinfo_get()->board_type
== CVMX_BOARD_TYPE_SIM
)
325 __cvmx_helper_sgmii_link_set(ipd_port
,
326 __cvmx_helper_sgmii_link_get(ipd_port
));
332 int __cvmx_helper_sgmii_enumerate(int interface
)
337 * Probe a SGMII interface and determine the number of ports
338 * connected to it. The SGMII interface should still be down after
341 * @interface: Interface to probe
343 * Returns Number of ports on the interface. Zero to disable.
345 int __cvmx_helper_sgmii_probe(int interface
)
347 union cvmx_gmxx_inf_mode mode
;
350 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
351 * interface needs to be enabled before IPD otherwise per port
352 * backpressure may not work properly
354 mode
.u64
= cvmx_read_csr(CVMX_GMXX_INF_MODE(interface
));
356 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface
), mode
.u64
);
357 return __cvmx_helper_sgmii_enumerate(interface
);
361 * Bringup and enable a SGMII interface. After this call packet
362 * I/O should be fully functional. This is called with IPD
363 * enabled but PKO disabled.
365 * @interface: Interface to bring up
367 * Returns Zero on success, negative on failure
369 int __cvmx_helper_sgmii_enable(int interface
)
371 int num_ports
= cvmx_helper_ports_on_interface(interface
);
374 __cvmx_helper_sgmii_hardware_init(interface
, num_ports
);
376 for (index
= 0; index
< num_ports
; index
++) {
377 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg
;
379 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index
, interface
));
380 gmxx_prtx_cfg
.s
.en
= 1;
381 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index
, interface
),
383 __cvmx_interrupt_pcsx_intx_en_reg_enable(index
, interface
);
385 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface
);
386 __cvmx_interrupt_gmxx_enable(interface
);
391 * Return the link state of an IPD/PKO port as returned by
392 * auto negotiation. The result of this function may not match
393 * Octeon's link config if auto negotiation has changed since
394 * the last call to cvmx_helper_link_set().
396 * @ipd_port: IPD/PKO port to query
400 cvmx_helper_link_info_t
__cvmx_helper_sgmii_link_get(int ipd_port
)
402 cvmx_helper_link_info_t result
;
403 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg
;
404 int interface
= cvmx_helper_get_interface_num(ipd_port
);
405 int index
= cvmx_helper_get_interface_index_num(ipd_port
);
406 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg
;
410 if (cvmx_sysinfo_get()->board_type
== CVMX_BOARD_TYPE_SIM
) {
411 /* The simulator gives you a simulated 1Gbps full duplex link */
412 result
.s
.link_up
= 1;
413 result
.s
.full_duplex
= 1;
414 result
.s
.speed
= 1000;
418 pcsx_mrx_control_reg
.u64
=
419 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index
, interface
));
420 if (pcsx_mrx_control_reg
.s
.loopbck1
) {
421 /* Force 1Gbps full duplex link for internal loopback */
422 result
.s
.link_up
= 1;
423 result
.s
.full_duplex
= 1;
424 result
.s
.speed
= 1000;
428 pcs_misc_ctl_reg
.u64
=
429 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
));
430 if (pcs_misc_ctl_reg
.s
.mode
) {
434 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg
;
435 pcsx_miscx_ctl_reg
.u64
=
436 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
));
437 if (pcsx_miscx_ctl_reg
.s
.mac_phy
) {
439 union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg
;
440 union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg
;
443 * Don't bother continuing if the SERTES low
446 pcsx_mrx_status_reg
.u64
=
447 cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
449 if (pcsx_mrx_status_reg
.s
.lnk_st
== 0) {
450 if (__cvmx_helper_sgmii_hardware_init_link
451 (interface
, index
) != 0)
455 /* Read the autoneg results */
456 pcsx_anx_results_reg
.u64
=
457 cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
459 if (pcsx_anx_results_reg
.s
.an_cpt
) {
461 * Auto negotiation is complete. Set
462 * status accordingly.
464 result
.s
.full_duplex
=
465 pcsx_anx_results_reg
.s
.dup
;
467 pcsx_anx_results_reg
.s
.link_ok
;
468 switch (pcsx_anx_results_reg
.s
.spd
) {
473 result
.s
.speed
= 100;
476 result
.s
.speed
= 1000;
480 result
.s
.link_up
= 0;
485 * Auto negotiation isn't
486 * complete. Return link down.
489 result
.s
.link_up
= 0;
491 } else { /* MAC Mode */
493 result
= __cvmx_helper_board_link_get(ipd_port
);
500 * Configure an IPD/PKO port for the specified link state. This
501 * function does not influence auto negotiation at the PHY level.
502 * The passed link state must always match the link state returned
503 * by cvmx_helper_link_get().
505 * @ipd_port: IPD/PKO port to configure
506 * @link_info: The new link state
508 * Returns Zero on success, negative on failure
510 int __cvmx_helper_sgmii_link_set(int ipd_port
,
511 cvmx_helper_link_info_t link_info
)
513 int interface
= cvmx_helper_get_interface_num(ipd_port
);
514 int index
= cvmx_helper_get_interface_index_num(ipd_port
);
515 __cvmx_helper_sgmii_hardware_init_link(interface
, index
);
516 return __cvmx_helper_sgmii_hardware_init_link_speed(interface
, index
,
521 * Configure a port for internal and/or external loopback. Internal
522 * loopback causes packets sent by the port to be received by
523 * Octeon. External loopback causes packets received from the wire to
526 * @ipd_port: IPD/PKO port to loopback.
528 * Non zero if you want internal loopback
530 * Non zero if you want external loopback
532 * Returns Zero on success, negative on failure.
534 int __cvmx_helper_sgmii_configure_loopback(int ipd_port
, int enable_internal
,
537 int interface
= cvmx_helper_get_interface_num(ipd_port
);
538 int index
= cvmx_helper_get_interface_index_num(ipd_port
);
539 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg
;
540 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg
;
542 pcsx_mrx_control_reg
.u64
=
543 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index
, interface
));
544 pcsx_mrx_control_reg
.s
.loopbck1
= enable_internal
;
545 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index
, interface
),
546 pcsx_mrx_control_reg
.u64
);
548 pcsx_miscx_ctl_reg
.u64
=
549 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
));
550 pcsx_miscx_ctl_reg
.s
.loopbck2
= enable_external
;
551 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index
, interface
),
552 pcsx_miscx_ctl_reg
.u64
);
554 __cvmx_helper_sgmii_hardware_init_link(interface
, index
);