blob: b789ad5d1913a8336d12b0f6f1886415e6d10fae [file] [log] [blame]
Aaron Williams3a019d02022-04-07 09:11:23 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2022 Marvell International Ltd.
4 *
5 * Functions for SGMII initialization, configuration,
6 * and monitoring.
7 */
8
9#include <time.h>
10#include <log.h>
11#include <linux/delay.h>
12
13#include <mach/cvmx-regs.h>
14#include <mach/cvmx-csr.h>
15#include <mach/cvmx-bootmem.h>
16#include <mach/octeon-model.h>
17#include <mach/cvmx-fuse.h>
18#include <mach/octeon-feature.h>
19#include <mach/cvmx-qlm.h>
20#include <mach/octeon_qlm.h>
21#include <mach/cvmx-pcie.h>
22#include <mach/cvmx-coremask.h>
23
24#include <mach/cvmx-agl-defs.h>
25#include <mach/cvmx-bgxx-defs.h>
26#include <mach/cvmx-ciu-defs.h>
27#include <mach/cvmx-gmxx-defs.h>
28#include <mach/cvmx-ipd-defs.h>
29#include <mach/cvmx-pcsx-defs.h>
30#include <mach/cvmx-pki-defs.h>
31#include <mach/cvmx-xcv-defs.h>
32
33#include <mach/cvmx-helper.h>
34#include <mach/cvmx-helper-board.h>
35#include <mach/cvmx-helper-cfg.h>
36
37/**
38 * @INTERNAL
39 * Perform initialization required only once for an SGMII port.
40 *
41 * @param interface to init
42 * @param index Index of prot on the interface
43 *
44 * @return Zero on success, negative on failure
45 */
46static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
47{
48 const u64 clock_mhz = 1200; /* todo: fixme */
49 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
50 union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
51 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
52
53 if (!cvmx_helper_is_port_valid(interface, index))
54 return 0;
55
56 /* Disable GMX */
57 gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
58 gmxx_prtx_cfg.s.en = 0;
59 csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
60
61 /*
62 * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
63 * appropriate value. 1000BASE-X specifies a 10ms
64 * interval. SGMII specifies a 1.6ms interval.
65 */
66 pcsx_miscx_ctl_reg.u64 =
67 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
68 /* Adjust the MAC mode if requested by device tree */
69 pcsx_miscx_ctl_reg.s.mac_phy =
70 cvmx_helper_get_mac_phy_mode(interface, index);
71 pcsx_miscx_ctl_reg.s.mode =
72 cvmx_helper_get_1000x_mode(interface, index);
73 csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
74 pcsx_miscx_ctl_reg.u64);
75
76 pcsx_linkx_timer_count_reg.u64 =
77 csr_rd(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
78 if (pcsx_miscx_ctl_reg.s.mode)
79 /* 1000BASE-X */
80 pcsx_linkx_timer_count_reg.s.count =
81 (10000ull * clock_mhz) >> 10;
82 else
83 /* SGMII */
84 pcsx_linkx_timer_count_reg.s.count =
85 (1600ull * clock_mhz) >> 10;
86
87 csr_wr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
88 pcsx_linkx_timer_count_reg.u64);
89
90 /*
91 * Write the advertisement register to be used as the
92 * tx_Config_Reg<D15:D0> of the autonegotiation. In
93 * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
94 * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
95 * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode,
96 * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
97 * step can be skipped.
98 */
99 if (pcsx_miscx_ctl_reg.s.mode) {
100 /* 1000BASE-X */
101 union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
102
103 pcsx_anx_adv_reg.u64 =
104 csr_rd(CVMX_PCSX_ANX_ADV_REG(index, interface));
105 pcsx_anx_adv_reg.s.rem_flt = 0;
106 pcsx_anx_adv_reg.s.pause = 3;
107 pcsx_anx_adv_reg.s.hfd = 1;
108 pcsx_anx_adv_reg.s.fd = 1;
109 csr_wr(CVMX_PCSX_ANX_ADV_REG(index, interface),
110 pcsx_anx_adv_reg.u64);
111 } else {
112 if (pcsx_miscx_ctl_reg.s.mac_phy) {
113 /* PHY Mode */
114 union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
115
116 pcsx_sgmx_an_adv_reg.u64 = csr_rd(
117 CVMX_PCSX_SGMX_AN_ADV_REG(index, interface));
118 pcsx_sgmx_an_adv_reg.s.dup = 1;
119 pcsx_sgmx_an_adv_reg.s.speed = 2;
120 csr_wr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface),
121 pcsx_sgmx_an_adv_reg.u64);
122 } else {
123 /* MAC Mode - Nothing to do */
124 }
125 }
126 return 0;
127}
128
129static int __cvmx_helper_need_g15618(void)
130{
131 if (OCTEON_IS_MODEL(OCTEON_CN63XX) ||
132 OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X) ||
133 OCTEON_IS_MODEL(OCTEON_CN68XX))
134 return 1;
135 else
136 return 0;
137}
138
139/**
140 * @INTERNAL
141 * Initialize the SERTES link for the first time or after a loss
142 * of link.
143 *
144 * @param interface to init
145 * @param index Index of prot on the interface
146 *
147 * @return Zero on success, negative on failure
148 */
149static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
150{
151 union cvmx_pcsx_mrx_control_reg control_reg;
152 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
153 bool phy_mode;
154 bool an_disable; /** Disable autonegotiation */
155 bool mode_1000x; /** 1000Base-X mode */
156
157 if (!cvmx_helper_is_port_valid(interface, index))
158 return 0;
159
160 /*
161 * Take PCS through a reset sequence.
162 * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
163 * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
164 * value of the other PCS*_MR*_CONTROL_REG bits). Read
165 * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
166 * zero.
167 */
168 control_reg.u64 = csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
169
170 /*
171 * Errata G-15618 requires disabling PCS soft reset in CN63XX
172 * pass upto 2.1.
173 */
174 if (!__cvmx_helper_need_g15618()) {
175 control_reg.s.reset = 1;
176 csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
177 control_reg.u64);
178 if (CVMX_WAIT_FOR_FIELD64(
179 CVMX_PCSX_MRX_CONTROL_REG(index, interface),
180 cvmx_pcsx_mrx_control_reg_t, reset, ==, 0, 10000)) {
181 debug("SGMII%x: Timeout waiting for port %d to finish reset\n",
182 interface, index);
183 return -1;
184 }
185 }
186
187 /*
188 * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
189 * sgmii negotiation starts.
190 */
191 phy_mode = cvmx_helper_get_mac_phy_mode(interface, index);
192 an_disable = (phy_mode ||
193 !cvmx_helper_get_port_autonegotiation(interface, index));
194
195 control_reg.s.an_en = !an_disable;
196
197 /* Force a PCS reset by powering down the PCS interface
198 * This is needed to deal with broken Qualcomm/Atheros PHYs and switches
199 * which never recover if PCS is not power cycled. The alternative
200 * is to power cycle or hardware reset the Qualcomm devices whenever
201 * SGMII is initialized.
202 *
203 * This is needed for the QCA8033 PHYs as well as the QCA833X switches
204 * to work. The QCA8337 switch has additional SGMII problems and is
205 * best avoided if at all possible. Failure to power cycle PCS prevents
206 * any traffic from flowing between Octeon and Qualcomm devices if there
207 * is a warm reset. Even a software reset to the Qualcomm device will
208 * not work.
209 *
210 * Note that this problem has been reported between Qualcomm and other
211 * vendor's processors as well so this problem is not unique to
212 * Qualcomm and Octeon.
213 *
214 * Power cycling PCS doesn't hurt anything with non-Qualcomm devices
215 * other than adding a 25ms delay during initialization.
216 */
217 control_reg.s.pwr_dn = 1;
218 csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
219 csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
220
221 /* 25ms should be enough, 10ms is too short */
222 mdelay(25);
223
224 control_reg.s.pwr_dn = 0;
225 csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
226
227 /* The Cortina PHY runs in 1000base-X mode */
228 mode_1000x = cvmx_helper_get_1000x_mode(interface, index);
229 pcsx_miscx_ctl_reg.u64 =
230 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
231 pcsx_miscx_ctl_reg.s.mode = mode_1000x;
232 pcsx_miscx_ctl_reg.s.mac_phy = phy_mode;
233 csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
234 pcsx_miscx_ctl_reg.u64);
235 if (an_disable)
236 /* In PHY mode we can't query the link status so we just
237 * assume that the link is up.
238 */
239 return 0;
240
241 /*
242 * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
243 * that sgmii autonegotiation is complete. In MAC mode this
244 * isn't an ethernet link, but a link between Octeon and the
245 * PHY.
246 */
247 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
248 union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
249 10000)) {
250 debug("SGMII%x: Port %d link timeout\n", interface, index);
251 return -1;
252 }
253 return 0;
254}
255
256/**
257 * @INTERNAL
258 * Configure an SGMII link to the specified speed after the SERTES
259 * link is up.
260 *
261 * @param interface to init
262 * @param index Index of prot on the interface
263 * @param link_info Link state to configure
264 *
265 * @return Zero on success, negative on failure
266 */
267static int
268__cvmx_helper_sgmii_hardware_init_link_speed(int interface, int index,
269 cvmx_helper_link_info_t link_info)
270{
271 int is_enabled;
272 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
273 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
274
275 if (!cvmx_helper_is_port_valid(interface, index))
276 return 0;
277
278 /* Disable GMX before we make any changes. Remember the enable state */
279 gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
280 is_enabled = gmxx_prtx_cfg.s.en;
281 gmxx_prtx_cfg.s.en = 0;
282 csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
283
284 /* Wait for GMX to be idle */
285 if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
286 cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1,
287 10000) ||
288 CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
289 cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1,
290 10000)) {
291 debug("SGMII%d: Timeout waiting for port %d to be idle\n",
292 interface, index);
293 return -1;
294 }
295
296 /* Read GMX CFG again to make sure the disable completed */
297 gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
298
299 /*
300 * Get the misc control for PCS. We will need to set the
301 * duplication amount.
302 */
303 pcsx_miscx_ctl_reg.u64 =
304 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
305
306 /*
307 * Use GMXENO to force the link down if the status we get says
308 * it should be down.
309 */
310 pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
311
312 /* Only change the duplex setting if the link is up */
313 if (link_info.s.link_up)
314 gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
315
316 /* Do speed based setting for GMX */
317 switch (link_info.s.speed) {
318 case 10:
319 gmxx_prtx_cfg.s.speed = 0;
320 gmxx_prtx_cfg.s.speed_msb = 1;
321 gmxx_prtx_cfg.s.slottime = 0;
322 /* Setting from GMX-603 */
323 pcsx_miscx_ctl_reg.s.samp_pt = 25;
324 csr_wr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
325 csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 0);
326 break;
327 case 100:
328 gmxx_prtx_cfg.s.speed = 0;
329 gmxx_prtx_cfg.s.speed_msb = 0;
330 gmxx_prtx_cfg.s.slottime = 0;
331 pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
332 csr_wr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
333 csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 0);
334 break;
335 case 1000:
336 gmxx_prtx_cfg.s.speed = 1;
337 gmxx_prtx_cfg.s.speed_msb = 0;
338 gmxx_prtx_cfg.s.slottime = 1;
339 pcsx_miscx_ctl_reg.s.samp_pt = 1;
340 csr_wr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
341 if (gmxx_prtx_cfg.s.duplex)
342 /* full duplex */
343 csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 0);
344 else
345 /* half duplex */
346 csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
347 break;
348 default:
349 break;
350 }
351
352 /* Write the new misc control for PCS */
353 csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
354 pcsx_miscx_ctl_reg.u64);
355
356 /* Write the new GMX settings with the port still disabled */
357 csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
358
359 /* Read GMX CFG again to make sure the config completed */
360 gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
361
362 /* Restore the enabled / disabled state */
363 gmxx_prtx_cfg.s.en = is_enabled;
364 csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
365
366 return 0;
367}
368
369/**
370 * @INTERNAL
371 * Bring up the SGMII interface to be ready for packet I/O but
372 * leave I/O disabled using the GMX override. This function
373 * follows the bringup documented in 10.6.3 of the manual.
374 *
375 * @param interface to bringup
376 * @param num_ports Number of ports on the interface
377 *
378 * @return Zero on success, negative on failure
379 */
380static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
381{
382 int index;
383 int do_link_set = 1;
384
385 /*
386 * CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis
387 * be programmed.
388 */
389 if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) {
390 union cvmx_ciu_qlm2 ciu_qlm;
391
392 ciu_qlm.u64 = csr_rd(CVMX_CIU_QLM2);
393 ciu_qlm.s.txbypass = 1;
394 ciu_qlm.s.txdeemph = 0xf;
395 ciu_qlm.s.txmargin = 0xd;
396 csr_wr(CVMX_CIU_QLM2, ciu_qlm.u64);
397 }
398
399 /*
400 * CN63XX Pass 2.x errata G-15273 requires the QLM De-emphasis
401 * be programmed when using a 156.25Mhz ref clock.
402 */
403 if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_X)) {
404 /* Read the QLM speed pins */
405 union cvmx_mio_rst_boot mio_rst_boot;
406
407 mio_rst_boot.u64 = csr_rd(CVMX_MIO_RST_BOOT);
408
409 if (mio_rst_boot.cn63xx.qlm2_spd == 4) {
410 union cvmx_ciu_qlm2 ciu_qlm;
411
412 ciu_qlm.u64 = csr_rd(CVMX_CIU_QLM2);
413 ciu_qlm.s.txbypass = 1;
414 ciu_qlm.s.txdeemph = 0x0;
415 ciu_qlm.s.txmargin = 0xf;
416 csr_wr(CVMX_CIU_QLM2, ciu_qlm.u64);
417 }
418 }
419
420 __cvmx_helper_setup_gmx(interface, num_ports);
421
422 for (index = 0; index < num_ports; index++) {
423 int ipd_port = cvmx_helper_get_ipd_port(interface, index);
424
425 if (!cvmx_helper_is_port_valid(interface, index))
426 continue;
427 __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
428 if (do_link_set)
429 __cvmx_helper_sgmii_link_set(ipd_port,
430 __cvmx_helper_sgmii_link_get(ipd_port));
431 }
432
433 return 0;
434}
435
436int __cvmx_helper_sgmii_enumerate(int xiface)
437{
438 if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
439 return 2;
440 if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
441 struct cvmx_xiface xi =
442 cvmx_helper_xiface_to_node_interface(xiface);
443 enum cvmx_qlm_mode qlm_mode =
444 cvmx_qlm_get_dlm_mode(0, xi.interface);
445
446 if (qlm_mode == CVMX_QLM_MODE_SGMII)
447 return 1;
448 else if (qlm_mode == CVMX_QLM_MODE_QSGMII)
449 return 4;
450 return 0;
451 }
452 return 4;
453}
454
455/**
456 * @INTERNAL
457 * Probe a SGMII interface and determine the number of ports
458 * connected to it. The SGMII interface should still be down after
459 * this call.
460 *
461 * @param xiface Interface to probe
462 *
463 * @return Number of ports on the interface. Zero to disable.
464 */
465int __cvmx_helper_sgmii_probe(int xiface)
466{
467 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
468 int interface = xi.interface;
469 union cvmx_gmxx_inf_mode mode;
470 int ports;
471
472 /*
473 * Check if QLM is configured correct for SGMII, verify the
474 * speed as well as mode.
475 */
476 if (OCTEON_IS_OCTEON2()) {
477 int qlm = cvmx_qlm_interface(xiface);
478
479 if (cvmx_qlm_get_mode(qlm) != CVMX_QLM_MODE_SGMII)
480 return 0;
481 }
482
483 /* Do not enable the interface if is not in SGMII mode */
484 ports = __cvmx_helper_sgmii_enumerate(xiface);
485
486 if (ports <= 0)
487 return 0;
488
489 /*
490 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
491 * interface needs to be enabled before IPD otherwise per port
492 * backpressure may not work properly.
493 */
494 mode.u64 = csr_rd(CVMX_GMXX_INF_MODE(interface));
495 mode.s.en = 1;
496 csr_wr(CVMX_GMXX_INF_MODE(interface), mode.u64);
497
498 return ports;
499}
500
501/**
502 * @INTERNAL
503 * Bringup and enable a SGMII interface. After this call packet
504 * I/O should be fully functional. This is called with IPD
505 * enabled but PKO disabled.
506 *
507 * @param xiface Interface to bring up
508 *
509 * @return Zero on success, negative on failure
510 */
511int __cvmx_helper_sgmii_enable(int xiface)
512{
513 int num_ports = cvmx_helper_ports_on_interface(xiface);
514 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
515 int interface = xi.interface;
516 int index;
517
518 /* Setup PKND and BPID */
519 if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
520 for (index = 0; index < num_ports; index++) {
521 union cvmx_gmxx_bpid_msk bpid_msk;
522 union cvmx_gmxx_bpid_mapx bpid_map;
523 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
524
525 if (!cvmx_helper_is_port_valid(interface, index))
526 continue;
527 /* Setup PKIND */
528 gmxx_prtx_cfg.u64 =
529 csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
530 gmxx_prtx_cfg.s.pknd =
531 cvmx_helper_get_pknd(interface, index);
532 csr_wr(CVMX_GMXX_PRTX_CFG(index, interface),
533 gmxx_prtx_cfg.u64);
534
535 /* Setup BPID */
536 bpid_map.u64 =
537 csr_rd(CVMX_GMXX_BPID_MAPX(index, interface));
538 bpid_map.s.val = 1;
539 bpid_map.s.bpid =
540 cvmx_helper_get_bpid(interface, index);
541 csr_wr(CVMX_GMXX_BPID_MAPX(index, interface),
542 bpid_map.u64);
543
544 bpid_msk.u64 = csr_rd(CVMX_GMXX_BPID_MSK(interface));
545 bpid_msk.s.msk_or |= (1 << index);
546 bpid_msk.s.msk_and &= ~(1 << index);
547 csr_wr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64);
548 }
549 }
550
551 __cvmx_helper_sgmii_hardware_init(interface, num_ports);
552
553 /* CN68XX adds the padding and FCS in PKO, not GMX */
554 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
555 union cvmx_gmxx_txx_append gmxx_txx_append_cfg;
556
557 for (index = 0; index < num_ports; index++) {
558 if (!cvmx_helper_is_port_valid(interface, index))
559 continue;
560 gmxx_txx_append_cfg.u64 =
561 csr_rd(CVMX_GMXX_TXX_APPEND(index, interface));
562 gmxx_txx_append_cfg.s.fcs = 0;
563 gmxx_txx_append_cfg.s.pad = 0;
564 csr_wr(CVMX_GMXX_TXX_APPEND(index, interface),
565 gmxx_txx_append_cfg.u64);
566 }
567 }
568
569 /* Enable running disparity check for QSGMII interface */
570 if (OCTEON_IS_MODEL(OCTEON_CN70XX) && num_ports > 1) {
571 union cvmx_gmxx_qsgmii_ctl qsgmii_ctl;
572
573 qsgmii_ctl.u64 = 0;
574 qsgmii_ctl.s.disparity = 1;
575 csr_wr(CVMX_GMXX_QSGMII_CTL(interface), qsgmii_ctl.u64);
576 }
577
578 for (index = 0; index < num_ports; index++) {
579 union cvmx_gmxx_txx_append append_cfg;
580 union cvmx_gmxx_txx_sgmii_ctl sgmii_ctl;
581 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
582
583 if (!cvmx_helper_is_port_valid(interface, index))
584 continue;
585 /*
586 * Clear the align bit if preamble is set to attain
587 * maximum tx rate.
588 */
589 append_cfg.u64 = csr_rd(CVMX_GMXX_TXX_APPEND(index, interface));
590 sgmii_ctl.u64 =
591 csr_rd(CVMX_GMXX_TXX_SGMII_CTL(index, interface));
592 sgmii_ctl.s.align = append_cfg.s.preamble ? 0 : 1;
593 csr_wr(CVMX_GMXX_TXX_SGMII_CTL(index, interface),
594 sgmii_ctl.u64);
595
596 gmxx_prtx_cfg.u64 =
597 csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
598 gmxx_prtx_cfg.s.en = 1;
599 csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
600 }
601 return 0;
602}
603
604/**
605 * @INTERNAL
606 * Return the link state of an IPD/PKO port as returned by
607 * auto negotiation. The result of this function may not match
608 * Octeon's link config if auto negotiation has changed since
609 * the last call to cvmx_helper_link_set().
610 *
611 * @param ipd_port IPD/PKO port to query
612 *
613 * @return Link state
614 */
615cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
616{
617 cvmx_helper_link_info_t result;
618 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
619 int interface = cvmx_helper_get_interface_num(ipd_port);
620 int index = cvmx_helper_get_interface_index_num(ipd_port);
621 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
622 int speed = 1000;
623 int qlm;
624
625 result.u64 = 0;
626
627 if (!cvmx_helper_is_port_valid(interface, index))
628 return result;
629
630 if (OCTEON_IS_MODEL(OCTEON_CN66XX)) {
631 union cvmx_gmxx_inf_mode inf_mode;
632
633 inf_mode.u64 = csr_rd(CVMX_GMXX_INF_MODE(interface));
634 if (inf_mode.s.rate & (1 << index))
635 speed = 2500;
636 else
637 speed = 1000;
638 } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
639 qlm = cvmx_qlm_interface(interface);
640 speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
641 } else if (OCTEON_IS_MODEL(OCTEON_CNF71XX)) {
642 speed = cvmx_qlm_get_gbaud_mhz(0) * 8 / 10;
643 } else if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
644 speed = cvmx_qlm_get_gbaud_mhz(0) * 8 / 10;
645 if (cvmx_qlm_get_dlm_mode(0, interface) == CVMX_QLM_MODE_SGMII)
646 speed >>= 1;
647 else
648 speed >>= 2;
649 }
650
651 pcsx_mrx_control_reg.u64 =
652 csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
653 if (pcsx_mrx_control_reg.s.loopbck1) {
654 /* Force 1Gbps full duplex link for internal loopback */
655 result.s.link_up = 1;
656 result.s.full_duplex = 1;
657 result.s.speed = speed;
658 return result;
659 }
660
661 pcsx_miscx_ctl_reg.u64 =
662 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
663 if (pcsx_miscx_ctl_reg.s.mac_phy ||
664 cvmx_helper_get_port_force_link_up(interface, index)) {
665 /* PHY Mode */
666 /* Note that this also works for 1000base-X mode */
667
668 result.s.speed = speed;
669 result.s.full_duplex = 1;
670 result.s.link_up = 1;
671 return result;
672 }
673
674 /* MAC Mode */
675 return __cvmx_helper_board_link_get(ipd_port);
676}
677
678/**
679 * @INTERNAL
680 * Configure an IPD/PKO port for the specified link state. This
681 * function does not influence auto negotiation at the PHY level.
682 * The passed link state must always match the link state returned
683 * by cvmx_helper_link_get(). It is normally best to use
684 * cvmx_helper_link_autoconf() instead.
685 *
686 * @param ipd_port IPD/PKO port to configure
687 * @param link_info The new link state
688 *
689 * @return Zero on success, negative on failure
690 */
691int __cvmx_helper_sgmii_link_set(int ipd_port,
692 cvmx_helper_link_info_t link_info)
693{
694 union cvmx_pcsx_mrx_control_reg control_reg;
695 int interface = cvmx_helper_get_interface_num(ipd_port);
696 int index = cvmx_helper_get_interface_index_num(ipd_port);
697
698 if (!cvmx_helper_is_port_valid(interface, index))
699 return 0;
700
701 /* For some devices, i.e. the Qualcomm QCA8337 switch we need to power
702 * down the PCS interface when the link goes down and power it back
703 * up when the link returns.
704 */
705 if (link_info.s.link_up || !__cvmx_helper_need_g15618()) {
706 __cvmx_helper_sgmii_hardware_init_link(interface, index);
707 } else {
708 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
709
710 pcsx_miscx_ctl_reg.u64 =
711 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
712
713 /* Disable autonegotiation when MAC mode is enabled or
714 * autonegotiation is disabled.
715 */
716 control_reg.u64 =
717 csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
718 if (pcsx_miscx_ctl_reg.s.mac_phy == 0 ||
719 !cvmx_helper_get_port_autonegotiation(interface, index)) {
720 control_reg.s.an_en = 0;
721 control_reg.s.spdmsb = 1;
722 control_reg.s.spdlsb = 0;
723 control_reg.s.dup = 1;
724 }
725 csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
726 control_reg.u64);
727 csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
728 /*
729 * Use GMXENO to force the link down it will get
730 * reenabled later...
731 */
732 pcsx_miscx_ctl_reg.s.gmxeno = 1;
733 csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
734 pcsx_miscx_ctl_reg.u64);
735 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
736 return 0;
737 }
738 return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
739 link_info);
740}
741
742/**
743 * @INTERNAL
744 * Configure a port for internal and/or external loopback. Internal loopback
745 * causes packets sent by the port to be received by Octeon. External loopback
746 * causes packets received from the wire to sent out again.
747 *
748 * @param ipd_port IPD/PKO port to loopback.
749 * @param enable_internal
750 * Non zero if you want internal loopback
751 * @param enable_external
752 * Non zero if you want external loopback
753 *
754 * @return Zero on success, negative on failure.
755 */
756int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal,
757 int enable_external)
758{
759 int interface = cvmx_helper_get_interface_num(ipd_port);
760 int index = cvmx_helper_get_interface_index_num(ipd_port);
761 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
762 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
763
764 if (!cvmx_helper_is_port_valid(interface, index))
765 return 0;
766
767 pcsx_mrx_control_reg.u64 =
768 csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
769 pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
770 csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
771 pcsx_mrx_control_reg.u64);
772
773 pcsx_miscx_ctl_reg.u64 =
774 csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
775 pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
776 csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
777 pcsx_miscx_ctl_reg.u64);
778
779 __cvmx_helper_sgmii_hardware_init_link(interface, index);
780 return 0;
781}