xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/bdk/libbdk-hal/qlm/bdk-qlm-common.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /***********************license start***********************************
2 * Copyright (c) 2003-2017  Cavium Inc. ([email protected]). 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 Inc. 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
24 * control laws, including the U.S. Export Administration Act and its
25 * associated regulations, and may be subject to export or import
26 * regulations in other countries.
27 *
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
31 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK
37 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39 #include <bdk.h>
40 #include "libbdk-hal/if/bdk-if.h"
41 #include "libbdk-hal/bdk-qlm.h"
42 #include "libbdk-hal/qlm/bdk-qlm-common.h"
43 #include "libbdk-arch/bdk-csrs-gser.h"
44 #include "libbdk-arch/bdk-csrs-pem.h"
45 #include "libbdk-hal/bdk-config.h"
46 #include "libbdk-hal/bdk-utils.h"
47 #include "libbdk-hal/bdk-twsi.h"
48 
49 /* Indexed by QLM number and lane */
50 static uint64_t prbs_errors[14][4];
51 
52 /**
53  * Figure out which lane mode to use for a given reference clock and GBaud
54  *
55  * @param mode_name String name for error messages
56  * @param qlm       QlM being configured
57  * @param ref_clk   Reference clock in hertz
58  * @param baud_mhz  Baud rate in Mhz
59  *
60  * @return Lane mode or -1 on failure
61  */
__bdk_qlm_get_lane_mode_for_speed_and_ref_clk(const char * mode_name,int qlm,int ref_clk,int baud_mhz)62 int __bdk_qlm_get_lane_mode_for_speed_and_ref_clk(const char *mode_name, int qlm, int ref_clk, int baud_mhz)
63 {
64     if (baud_mhz <= 1250)
65     {
66         if ((ref_clk == REF_156MHZ) || (ref_clk == REF_100MHZ))
67             return BDK_GSER_LMODE_E_R_125G_REFCLK15625_SGMII;
68         else
69         {
70             bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
71             return -1;
72         }
73     }
74     else if (baud_mhz <= 2500)
75     {
76         if (ref_clk == REF_100MHZ)
77             return BDK_GSER_LMODE_E_R_25G_REFCLK100;
78         else if (ref_clk == REF_125MHZ)
79             return BDK_GSER_LMODE_E_R_25G_REFCLK125;
80         else
81         {
82             bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
83             return -1;
84         }
85     }
86     else if (baud_mhz <= 3125)
87     {
88         if (ref_clk == REF_156MHZ)
89             return BDK_GSER_LMODE_E_R_3125G_REFCLK15625_XAUI;
90         else
91         {
92             bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
93             return -1;
94         }
95     }
96     else if (baud_mhz <= 5000)
97     {
98         if (ref_clk == REF_100MHZ)
99             return BDK_GSER_LMODE_E_R_5G_REFCLK100;
100         else if (ref_clk == REF_125MHZ)
101             return BDK_GSER_LMODE_E_R_5G_REFCLK125;
102         else
103             return BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII;
104     }
105     else if (baud_mhz <= 6250)
106     {
107         if (ref_clk == REF_156MHZ)
108             return BDK_GSER_LMODE_E_R_625G_REFCLK15625_RXAUI;
109         else
110         {
111             bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
112             return -1;
113         }
114     }
115     else if (baud_mhz <= 8000)
116     {
117         if (ref_clk == REF_100MHZ)
118             return BDK_GSER_LMODE_E_R_8G_REFCLK100;
119         else if (ref_clk == REF_125MHZ)
120             return BDK_GSER_LMODE_E_R_8G_REFCLK125;
121         else
122         {
123             bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
124             return -1;
125         }
126     }
127     else /* Baud 10312.5 */
128     {
129         if (ref_clk == REF_156MHZ)
130             return BDK_GSER_LMODE_E_R_103125G_REFCLK15625_KR;
131         else
132         {
133             bdk_error("Invalid reference clock for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
134             return -1;
135         }
136     }
137     bdk_error("Invalid speed for %s on QLM%d with speed %d, ref %d Mhz\n", mode_name, qlm, baud_mhz, ref_clk / 1000000);
138     return -1;
139 }
140 
141 /**
142  * Setup the PEM to either driver or receive reset from PRST based on RC or EP
143  *
144  * @param node   Node to use in a Numa setup
145  * @param pem    Which PEM to setuo
146  * @param is_endpoint
147  *               Non zero if PEM is a EP
148  */
__bdk_qlm_setup_pem_reset(bdk_node_t node,int pem,int is_endpoint)149 void __bdk_qlm_setup_pem_reset(bdk_node_t node, int pem, int is_endpoint)
150 {
151     /* Make sure is_endpoint is either 0 or 1 */
152     is_endpoint = (is_endpoint != 0);
153     BDK_CSR_MODIFY(c, node, BDK_RST_CTLX(pem),
154         c.s.prst_link = 0;          /* Link down doesn't automatically assert PERST */
155         c.s.rst_link = is_endpoint; /* Link down automatically assert soft reset for EP */
156         c.s.rst_drv = !is_endpoint; /* PERST is output for RC, input for EP */
157         c.s.rst_rcv = is_endpoint;  /* Only read PERST in EP mode */
158         c.s.rst_chip = 0);          /* PERST doesn't pull CHIP_RESET */
159 
160     if (is_endpoint)
161     {
162         /* If we're configuring an endpoint manually the PEM will not
163            be turned on by default by the hardware. Turn it on now */
164         BDK_CSR_INIT(pemx_on, node, BDK_PEMX_ON(pem));
165         if (!pemx_on.s.pemon)
166         {
167             BDK_CSR_MODIFY(c, node, BDK_PEMX_CLK_EN(pem),
168                 c.cn83xx.pceclk_gate = 0;
169                 c.cn83xx.csclk_gate = 0);
170             BDK_CSR_MODIFY(c, node, BDK_PEMX_ON(pem),
171                 c.s.pemon = 1);
172         }
173     }
174 }
175 
176 /**
177  * Measure the reference clock of a QLM
178  *
179  * @param qlm    QLM to measure
180  *
181  * @return Clock rate in Hz
182  */
__bdk_qlm_measure_refclock(bdk_node_t node,int qlm)183 int __bdk_qlm_measure_refclock(bdk_node_t node, int qlm)
184 {
185     /* Clear the counter */
186     BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_EVT_CTRL(qlm),
187         c.s.enb = 0;
188         c.s.clr = 1);
189     bdk_wait_usec(1); /* Give counter a chance to clear */
190     if (BDK_CSR_READ(node, BDK_GSERX_REFCLK_EVT_CNTR(qlm)))
191         bdk_error("GSER%d: Ref clock counter not zero\n", qlm);
192     /* Start counting */
193     uint64_t start = bdk_clock_get_count(BDK_CLOCK_TIME);
194     BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_EVT_CTRL(qlm),
195         c.s.enb = 1;
196         c.s.clr = 0);
197     /* Wait for a short time to get a number of counts */
198     bdk_wait_usec(20000); /* 20ms */
199     /* Stop counting */
200     BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_EVT_CTRL(qlm),
201         c.s.enb = 0);
202     uint64_t stop = bdk_clock_get_count(BDK_CLOCK_TIME);
203     bdk_wait_usec(1); /* Give counter a chance to stabalize */
204 
205     /* Calculate the rate */
206     uint64_t count = BDK_CSR_READ(node, BDK_GSERX_REFCLK_EVT_CNTR(qlm));
207     count *= bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME);
208     count /= stop - start;
209     return count;
210 }
211 
212 /**
213  * Put a QLM into hardware reset
214  *
215  * @param node   Node to use in a numa setup
216  * @param qlm    QLM to use
217  *
218  * @return Zero on success, negative on failure
219  */
__bdk_qlm_reset(bdk_node_t node,int qlm)220 int __bdk_qlm_reset(bdk_node_t node, int qlm)
221 {
222     BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
223         c.s.phy_reset = 1);
224     return 0;
225 }
226 
227 /**
228  * Enable PRBS on a QLM
229  *
230  * @param node   Node to use in a numa setup
231  * @param qlm    QLM to use
232  * @param prbs   PRBS mode (31, etc)
233  * @param dir    Directions to enable. This is so you can enable TX and later
234  *               enable RX after TX has run for a time
235  *
236  * @return Zero on success, negative on failure
237  */
__bdk_qlm_enable_prbs(bdk_node_t node,int qlm,int prbs,bdk_qlm_direction_t dir)238 int __bdk_qlm_enable_prbs(bdk_node_t node, int qlm, int prbs, bdk_qlm_direction_t dir)
239 {
240     const int NUM_LANES = bdk_qlm_get_lanes(node, qlm);
241     int mode;
242     switch (prbs)
243     {
244         case 31:
245             mode = 1;
246             break;
247         case 23:
248             mode = 2; /* Or 3? */
249             break;
250         case 16:
251             mode = 4;
252             break;
253         case 15:
254             mode = 5;
255             break;
256         case 11:
257             mode = 6;
258             break;
259         case 7:
260             mode = 7;
261             break;
262         default:
263             mode = prbs & 0xff;
264             for (int lane = 0; lane < NUM_LANES; lane++)
265                 BDK_CSR_WRITE(node, BDK_GSERX_LANEX_LBERT_PAT_CFG(qlm, lane), prbs >> 8);
266             BDK_TRACE(QLM, "Using mode 0x%x with custom pattern 0x%x\n", mode, prbs >> 8);
267             break;
268     }
269 
270     /* For some reason PRBS doesn't work if GSER is configured for PCIe.
271        Disconnect PCIe when we start PRBS */
272     BDK_CSR_INIT(gserx_cfg, node, BDK_GSERX_CFG(qlm));
273     if (gserx_cfg.s.pcie)
274     {
275         gserx_cfg.s.pcie = 0;
276         BDK_CSR_WRITE(node, BDK_GSERX_CFG(qlm), gserx_cfg.u);
277         bdk_warn("N%d.QLM%d: Disabling PCIe for PRBS/pattern generation\n", node, qlm);
278     }
279     /* For some reason PRBS doesn't work if GSER is configured for SATA.
280        Disconnect SATA when we start PRBS */
281     if (gserx_cfg.s.sata)
282     {
283         gserx_cfg.s.sata = 0;
284         BDK_CSR_WRITE(node, BDK_GSERX_CFG(qlm), gserx_cfg.u);
285         bdk_warn("N%d.QLM%d: Disabling SATA for PRBS/pattern generation\n", node, qlm);
286         bdk_warn("N%d.QLM%d: SATA PRBS/patterns always run at 6G\n", node, qlm);
287     }
288 
289     BDK_CSR_MODIFY(c, node, BDK_GSERX_PHY_CTL(qlm),
290         c.s.phy_reset = 0);
291 
292     if (dir & BDK_QLM_DIRECTION_TX)
293     {
294         /* Disable first in case already running */
295         for (int lane = 0; lane < NUM_LANES; lane++)
296             BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
297                 c.s.lbert_pg_en = 0);
298         for (int lane = 0; lane < NUM_LANES; lane++)
299             BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
300                 c.s.lbert_pg_en = 1; /* Enable generator */
301                 c.s.lbert_pg_width = 3; /* 20 bit */
302                 c.s.lbert_pg_mode = mode);
303     }
304 
305     if (dir & BDK_QLM_DIRECTION_RX)
306     {
307         /* Clear the error counter and Disable the matcher */
308         for (int lane = 0; lane < NUM_LANES; lane++)
309         {
310             prbs_errors[qlm][lane] = 0;
311             BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
312                 c.s.lbert_pm_en = 0);
313         }
314         for (int lane = 0; lane < NUM_LANES; lane++)
315         {
316             BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
317                 c.s.lbert_pm_en = 1; /* Enable matcher */
318                 c.s.lbert_pm_width = 3; /* 20 bit */
319                 c.s.lbert_pm_mode = mode);
320         }
321         /* Tell the matcher to start sync */
322         for (int retry=0; retry < 4; retry++)
323         {
324             for (int lane = 0; lane < NUM_LANES; lane++)
325             {
326                 BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
327                     c.s.lbert_pm_sync_start = 1);
328             }
329             /* Wait 10ms */
330             bdk_wait_usec(10000);
331         }
332     }
333     return 0;
334 }
335 
336 /**
337  * Disable PRBS on a QLM
338  *
339  * @param node   Node to use in a numa setup
340  * @param qlm    QLM to use
341  *
342  * @return Zero on success, negative on failure
343  */
__bdk_qlm_disable_prbs(bdk_node_t node,int qlm)344 int __bdk_qlm_disable_prbs(bdk_node_t node, int qlm)
345 {
346     const int NUM_LANES = bdk_qlm_get_lanes(node, qlm);
347     BDK_CSR_INIT(phy_ctl, node, BDK_GSERX_PHY_CTL(qlm));
348     if (phy_ctl.s.phy_reset)
349         return -1;
350 
351     for (int lane = 0; lane < NUM_LANES; lane++)
352     {
353         prbs_errors[qlm][lane] = 0;
354         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
355             c.s.lbert_pg_en = 0;
356             c.s.lbert_pm_en = 0);
357     }
358     return 0;
359 }
360 
361 /**
362  * Return the number of PRBS errors since PRBS started running
363  *
364  * @param node   Node to use in numa setup
365  * @param qlm    QLM to use
366  * @param lane   Which lane
367  * @param clear  Clear counter after return the current value
368  *
369  * @return Number of errors
370  */
__bdk_qlm_get_prbs_errors(bdk_node_t node,int qlm,int lane,int clear)371 uint64_t __bdk_qlm_get_prbs_errors(bdk_node_t node, int qlm, int lane, int clear)
372 {
373     /* Restart synchronization */
374     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
375         c.s.lbert_pm_sync_start = 1);
376     /* This CSR is self clearing per the CSR description, but it doesn't
377        seem to do that. Instead it clears when we trigger sync again */
378     BDK_CSR_INIT(rx, node, BDK_GSERX_LANEX_LBERT_ECNT(qlm, lane));
379     uint64_t errors = rx.s.lbert_err_cnt;
380     if (rx.s.lbert_err_ovbit14)
381         errors <<= 7;
382     prbs_errors[qlm][lane] += errors;
383     uint64_t result = prbs_errors[qlm][lane];
384     if (clear)
385         prbs_errors[qlm][lane] = 0;
386     return result;
387 }
388 
389 /**
390  * Inject an error into PRBS
391  *
392  * @param node   Node to use in numa setup
393  * @param qlm    QLM to use
394  * @param lane   Which lane
395  */
__bdk_qlm_inject_prbs_error(bdk_node_t node,int qlm,int lane)396 void __bdk_qlm_inject_prbs_error(bdk_node_t node, int qlm, int lane)
397 {
398     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_LBERT_CFG(qlm, lane),
399         c.s.lbert_pg_err_insert = 1);
400 }
401 
402 /**
403  * Enable shallow loopback on a QLM
404  *
405  * @param node   Node to use in a numa setup
406  * @param qlm    QLM to use
407  * @param loop   Type of loopback. Not all QLMs support all modes
408  *
409  * @return Zero on success, negative on failure
410  */
__bdk_qlm_enable_loop(bdk_node_t node,int qlm,bdk_qlm_loop_t loop)411 int __bdk_qlm_enable_loop(bdk_node_t node, int qlm, bdk_qlm_loop_t loop)
412 {
413     bdk_error("Chip doesn't support shallow QLM loopback\n");
414     return -1;
415 }
416 
417 /**
418  * Initialize the QLM mode table
419  *
420  * @param node    Node to initialize
421  * @param qlm     Which QLM
422  * @param ref_clk Reference clock of the QLM in Hz
423  */
__bdk_qlm_init_mode_table(bdk_node_t node,int qlm,int ref_clk)424 void __bdk_qlm_init_mode_table(bdk_node_t node, int qlm, int ref_clk)
425 {
426     /* The QLM PLLs are controlled by an array of parameters indexed
427        by the QLM mode for each QLM. We need to fill in these tables.
428        Also each lane has some mode parameters, again in a array index
429        by the lane_mode */
430     for (int lane_mode = 0; lane_mode < 12; lane_mode++)
431     {
432         /* The values used below are all from
433            http://mawiki.caveonetworks.com/wiki/78xx/GSER_WEST */
434         BDK_CSR_INIT(pll_mode_0 , node, BDK_GSERX_PLL_PX_MODE_0(qlm, lane_mode));
435         BDK_CSR_INIT(pll_mode_1 , node, BDK_GSERX_PLL_PX_MODE_1(qlm, lane_mode));
436         BDK_CSR_INIT(lane_mode_0, node, BDK_GSERX_LANE_PX_MODE_0(qlm, lane_mode));
437         BDK_CSR_INIT(lane_mode_1, node, BDK_GSERX_LANE_PX_MODE_1(qlm, lane_mode));
438         switch (lane_mode)
439         {
440             case BDK_GSER_LMODE_E_R_25G_REFCLK100:
441             case BDK_GSER_LMODE_E_R_5G_REFCLK100:
442             case BDK_GSER_LMODE_E_R_8G_REFCLK100:
443                 /* These modes are used for PCIe where the defaults are
444                    correct. Skip programming these */
445                 continue;
446             case BDK_GSER_LMODE_E_R_125G_REFCLK15625_KX:
447                 pll_mode_0.s.pll_icp = 0x1;
448                 pll_mode_0.s.pll_rloop = 0x3;
449                 pll_mode_0.s.pll_pcs_div = 0x28;
450 
451                 pll_mode_1.s.pll_16p5en = 0x1;
452                 pll_mode_1.s.pll_cpadj = 0x3;
453                 pll_mode_1.s.pll_pcie3en = 0x0;
454                 pll_mode_1.s.pll_opr = 0x0;
455                 pll_mode_1.s.pll_div = 0x10;
456 
457                 lane_mode_0.s.ctle = 0x0;
458                 lane_mode_0.s.pcie = 0x0;
459                 lane_mode_0.s.tx_ldiv = 0x2;
460                 lane_mode_0.s.rx_ldiv = 0x2;
461                 lane_mode_0.s.srate = 0x0;
462                 lane_mode_0.s.tx_mode = 0x3;
463                 lane_mode_0.s.rx_mode = 0x3;
464 
465                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
466                 lane_mode_1.s.vma_mm = 0x1;
467                 lane_mode_1.s.cdr_fgain = 0xc;
468                 lane_mode_1.s.ph_acc_adj = 0x1e;
469                 break;
470             case BDK_GSER_LMODE_E_R_3125G_REFCLK15625_XAUI:
471                 pll_mode_0.s.pll_icp = 0x1;
472                 pll_mode_0.s.pll_rloop = 0x3;
473                 pll_mode_0.s.pll_pcs_div = 0x14;
474 
475                 pll_mode_1.s.pll_16p5en = 0x1;
476                 pll_mode_1.s.pll_cpadj = 0x2;
477                 pll_mode_1.s.pll_pcie3en = 0x0;
478                 pll_mode_1.s.pll_opr = 0x0;
479                 pll_mode_1.s.pll_div = 0x14;
480 
481                 lane_mode_0.s.ctle = 0x0;
482                 lane_mode_0.s.pcie = 0x0;
483                 lane_mode_0.s.tx_ldiv = 0x1;
484                 lane_mode_0.s.rx_ldiv = 0x1;
485                 lane_mode_0.s.srate = 0x0;
486                 lane_mode_0.s.tx_mode = 0x3;
487                 lane_mode_0.s.rx_mode = 0x3;
488 
489                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
490                 lane_mode_1.s.vma_mm = 0x1;
491                 lane_mode_1.s.cdr_fgain = 0xc;
492                 lane_mode_1.s.ph_acc_adj = 0x1e;
493                 break;
494             case BDK_GSER_LMODE_E_R_103125G_REFCLK15625_KR:
495                 pll_mode_0.s.pll_icp = 0x1;
496                 pll_mode_0.s.pll_rloop = 0x5;
497                 pll_mode_0.s.pll_pcs_div = 0xa;
498 
499                 pll_mode_1.s.pll_16p5en = 0x1;
500                 pll_mode_1.s.pll_cpadj = 0x2;
501                 pll_mode_1.s.pll_pcie3en = 0x0;
502                 pll_mode_1.s.pll_opr = 0x1;
503                 pll_mode_1.s.pll_div = 0x21;
504 
505                 lane_mode_0.s.ctle = 0x3;
506                 lane_mode_0.s.pcie = 0x0;
507                 lane_mode_0.s.tx_ldiv = 0x0;
508                 lane_mode_0.s.rx_ldiv = 0x0;
509                 lane_mode_0.s.srate = 0x0;
510                 lane_mode_0.s.tx_mode = 0x3;
511                 lane_mode_0.s.rx_mode = 0x3;
512 
513                 lane_mode_1.s.vma_fine_cfg_sel = 0x1;
514                 lane_mode_1.s.vma_mm = 0x0;
515                 lane_mode_1.s.cdr_fgain = 0xa;
516                 lane_mode_1.s.ph_acc_adj = 0xf;
517                 break;
518             case BDK_GSER_LMODE_E_R_125G_REFCLK15625_SGMII:
519                 pll_mode_0.s.pll_icp = 0x1;
520                 pll_mode_0.s.pll_rloop = 0x3;
521                 pll_mode_0.s.pll_pcs_div = 0x28;
522 
523                 pll_mode_1.s.pll_16p5en = 0x1;
524                 pll_mode_1.s.pll_cpadj = 0x3;
525                 pll_mode_1.s.pll_pcie3en = 0x0;
526                 pll_mode_1.s.pll_opr = 0x0;
527                 pll_mode_1.s.pll_div = 0x10;
528 
529                 lane_mode_0.s.ctle = 0x0;
530                 lane_mode_0.s.pcie = 0x0;
531                 lane_mode_0.s.tx_ldiv = 0x2;
532                 lane_mode_0.s.rx_ldiv = 0x2;
533                 lane_mode_0.s.srate = 0x0;
534                 lane_mode_0.s.tx_mode = 0x3;
535                 lane_mode_0.s.rx_mode = 0x3;
536 
537                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
538                 lane_mode_1.s.vma_mm = 0x1;
539                 lane_mode_1.s.cdr_fgain = 0xc;
540                 lane_mode_1.s.ph_acc_adj = 0x1e;
541                 if(ref_clk == REF_100MHZ)
542                 {
543                     pll_mode_0.s.pll_pcs_div = 0x28;
544                     pll_mode_1.s.pll_div = 0x19;
545                     pll_mode_1.s.pll_cpadj = 0x2;
546                 }
547                 break;
548             case BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII:
549                 pll_mode_0.s.pll_icp = 0x1; /* Per Scott McIlhenny 5/17/2016 (t81) */
550                 pll_mode_0.s.pll_rloop = 0x3;
551                 pll_mode_0.s.pll_pcs_div = 0xa;
552 
553                 pll_mode_1.s.pll_16p5en = 0x0;
554                 pll_mode_1.s.pll_cpadj = 0x2;
555                 pll_mode_1.s.pll_pcie3en = 0x0;
556                 pll_mode_1.s.pll_opr = 0x0;
557                 /* QSGMII is a special case. We use the same table entry for
558                    100Mhz and 125Mhz clocks as the normal 156Mhz */
559                 switch (ref_clk)
560                 {
561                     case REF_100MHZ:
562                         pll_mode_1.s.pll_div = 0x19;
563                         break;
564                     case REF_125MHZ:
565                         pll_mode_1.s.pll_div = 0x14;
566                         break;
567                     default: /* REF_156MHZ */
568                         pll_mode_1.s.pll_div = 0x10;
569                         break;
570                 }
571 
572                 lane_mode_0.s.ctle = 0x0;
573                 lane_mode_0.s.pcie = 0x0;
574                 lane_mode_0.s.tx_ldiv = 0x0;
575                 lane_mode_0.s.rx_ldiv = 0x0;
576                 lane_mode_0.s.srate = 0x0;
577                 lane_mode_0.s.tx_mode = 0x3;
578                 lane_mode_0.s.rx_mode = 0x3;
579 
580                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
581                 lane_mode_1.s.vma_mm = 0x1; /* Per Scott McIlhenny 5/17/2016 (t81) */
582                 lane_mode_1.s.cdr_fgain = 0xc;
583                 lane_mode_1.s.ph_acc_adj = 0x1e;
584                 break;
585             case BDK_GSER_LMODE_E_R_625G_REFCLK15625_RXAUI:
586                 pll_mode_0.s.pll_icp = 0x1;
587                 pll_mode_0.s.pll_rloop = 0x3;
588                 pll_mode_0.s.pll_pcs_div = 0xa;
589 
590                 pll_mode_1.s.pll_16p5en = 0x0;
591                 pll_mode_1.s.pll_cpadj = 0x2;
592                 pll_mode_1.s.pll_pcie3en = 0x0;
593                 pll_mode_1.s.pll_opr = 0x0;
594                 pll_mode_1.s.pll_div = 0x14;
595 
596                 lane_mode_0.s.ctle = 0x0;
597                 lane_mode_0.s.pcie = 0x0;
598                 lane_mode_0.s.tx_ldiv = 0x0;
599                 lane_mode_0.s.rx_ldiv = 0x0;
600                 lane_mode_0.s.srate = 0x0;
601                 lane_mode_0.s.tx_mode = 0x3;
602                 lane_mode_0.s.rx_mode = 0x3;
603 
604                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
605                 lane_mode_1.s.vma_mm = 0x0;
606                 lane_mode_1.s.cdr_fgain = 0xa;
607                 lane_mode_1.s.ph_acc_adj = 0x14;
608                 break;
609             case BDK_GSER_LMODE_E_R_25G_REFCLK125:
610                 pll_mode_0.s.pll_icp = 0x3;
611                 pll_mode_0.s.pll_rloop = 0x3;
612                 pll_mode_0.s.pll_pcs_div = 0x5;
613 
614                 pll_mode_1.s.pll_16p5en = 0x0;
615                 pll_mode_1.s.pll_cpadj = 0x1;
616                 pll_mode_1.s.pll_pcie3en = 0x0;
617                 pll_mode_1.s.pll_opr = 0x0;
618                 pll_mode_1.s.pll_div = 0x14;
619 
620                 lane_mode_0.s.ctle = 0x0;
621                 lane_mode_0.s.pcie = 0x1;
622                 lane_mode_0.s.tx_ldiv = 0x1;
623                 lane_mode_0.s.rx_ldiv = 0x1;
624                 lane_mode_0.s.srate = 0x0;
625                 lane_mode_0.s.tx_mode = 0x3;
626                 lane_mode_0.s.rx_mode = 0x3;
627 
628                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
629                 lane_mode_1.s.vma_mm = 0x1;
630                 lane_mode_1.s.cdr_fgain = 0xa;
631                 lane_mode_1.s.ph_acc_adj = 0x14;
632                 break;
633             case BDK_GSER_LMODE_E_R_5G_REFCLK125:
634                 pll_mode_0.s.pll_icp = 0x3;
635                 pll_mode_0.s.pll_rloop = 0x3;
636                 pll_mode_0.s.pll_pcs_div = 0xa;
637 
638                 pll_mode_1.s.pll_16p5en = 0x0;
639                 pll_mode_1.s.pll_cpadj = 0x1;
640                 pll_mode_1.s.pll_pcie3en = 0x0;
641                 pll_mode_1.s.pll_opr = 0x0;
642                 pll_mode_1.s.pll_div = 0x14;
643 
644                 lane_mode_0.s.ctle = 0x0;
645                 lane_mode_0.s.pcie = 0x1;
646                 lane_mode_0.s.tx_ldiv = 0x0;
647                 lane_mode_0.s.rx_ldiv = 0x0;
648                 lane_mode_0.s.srate = 0x0;
649                 lane_mode_0.s.tx_mode = 0x3;
650                 lane_mode_0.s.rx_mode = 0x3;
651 
652                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
653                 lane_mode_1.s.vma_mm = 0x0;
654                 lane_mode_1.s.cdr_fgain = 0xa;
655                 lane_mode_1.s.ph_acc_adj = 0x14;
656                 break;
657             case BDK_GSER_LMODE_E_R_8G_REFCLK125:
658                 pll_mode_0.s.pll_icp = 0x2;
659                 pll_mode_0.s.pll_rloop = 0x5;
660                 pll_mode_0.s.pll_pcs_div = 0xa;
661 
662                 pll_mode_1.s.pll_16p5en = 0x0;
663                 pll_mode_1.s.pll_cpadj = 0x1;
664                 pll_mode_1.s.pll_pcie3en = 0x1;
665                 pll_mode_1.s.pll_opr = 0x1;
666                 pll_mode_1.s.pll_div = 0x20;
667 
668                 lane_mode_0.s.ctle = 0x3;
669                 lane_mode_0.s.pcie = 0x0;
670                 lane_mode_0.s.tx_ldiv = 0x0;
671                 lane_mode_0.s.rx_ldiv = 0x0;
672                 lane_mode_0.s.srate = 0x0;
673                 lane_mode_0.s.tx_mode = 0x2;
674                 lane_mode_0.s.rx_mode = 0x2;
675 
676                 lane_mode_1.s.vma_fine_cfg_sel = 0x0;
677                 lane_mode_1.s.vma_mm = 0x0;
678                 lane_mode_1.s.cdr_fgain = 0xb;
679                 lane_mode_1.s.ph_acc_adj = 0x23;
680                 break;
681         }
682         BDK_CSR_WRITE(node, BDK_GSERX_PLL_PX_MODE_0(qlm, lane_mode), pll_mode_0.u);
683         BDK_CSR_WRITE(node, BDK_GSERX_PLL_PX_MODE_1(qlm, lane_mode), pll_mode_1.u);
684         BDK_CSR_WRITE(node, BDK_GSERX_LANE_PX_MODE_0(qlm, lane_mode), lane_mode_0.u);
685         BDK_CSR_WRITE(node, BDK_GSERX_LANE_PX_MODE_1(qlm, lane_mode), lane_mode_1.u);
686     }
687 }
688 
689 /**
690  * Given a valid PEM number, return its speed in Gbaud
691  *
692  * @param node   Node to use in numa setup
693  * @param pem    PEM to get speed of
694  *
695  * @return Speed in Gbaud. Zero if disabled
696  */
__bdk_qlm_get_gbaud_mhz_pem(bdk_node_t node,int pem)697 int __bdk_qlm_get_gbaud_mhz_pem(bdk_node_t node, int pem)
698 {
699     BDK_CSR_INIT(pem_cfg, node, BDK_PEMX_CFG(pem));
700     switch (pem_cfg.cn83xx.md)
701     {
702         case 0: /* Gen 1 */
703             return 2500;
704         case 1: /* Gen 2 */
705             return 5000;
706         case 2: /* Gen 3 */
707             return 8000;
708         default:
709             return 0;
710     }
711 }
712 
713 /**
714  * Get the speed of a QLM using its LMODE. This can't be used on PCIe QLMs.
715  *
716  * @param node   Node to use in numa setup
717  * @param qlm    Which QLM
718  *
719  * @return QLM speed on Gbaud
720  */
__bdk_qlm_get_gbaud_mhz_lmode(bdk_node_t node,int qlm)721 int __bdk_qlm_get_gbaud_mhz_lmode(bdk_node_t node, int qlm)
722 {
723     /* QLM is not in PCIe, assume LMODE is good enough for determining
724        the speed */
725     BDK_CSR_INIT(lane_mode, node, BDK_GSERX_LANE_MODE(qlm));
726     switch (lane_mode.s.lmode)
727     {
728         case BDK_GSER_LMODE_E_R_25G_REFCLK100:
729             return 2500;
730         case BDK_GSER_LMODE_E_R_5G_REFCLK100:
731             return 5000;
732         case BDK_GSER_LMODE_E_R_8G_REFCLK100:
733             return 8000;
734         case BDK_GSER_LMODE_E_R_125G_REFCLK15625_KX:
735             return 1250;
736         case BDK_GSER_LMODE_E_R_3125G_REFCLK15625_XAUI:
737             return 3125;
738         case BDK_GSER_LMODE_E_R_103125G_REFCLK15625_KR:
739             return 10312;
740         case BDK_GSER_LMODE_E_R_125G_REFCLK15625_SGMII:
741             return 1250;
742         case BDK_GSER_LMODE_E_R_5G_REFCLK15625_QSGMII:
743             return 5000;
744         case BDK_GSER_LMODE_E_R_625G_REFCLK15625_RXAUI:
745             return 6250;
746         case BDK_GSER_LMODE_E_R_25G_REFCLK125:
747             return 2500;
748         case BDK_GSER_LMODE_E_R_5G_REFCLK125:
749             return 5000;
750         case BDK_GSER_LMODE_E_R_8G_REFCLK125:
751             return 8000;
752         default:
753             return 0;
754     }
755 }
756 
757 /**
758  * Converts a measured reference clock to a likely ideal value. Rounds
759  * clock speed to the nearest REF_*Mhz define.
760  *
761  * @param node   Node to use in numa setup
762  * @param qlm    Which QLM
763  * @param measured_hz
764  *               Measured value
765  *
766  * @return Value exactly matching a define
767  */
__bdk_qlm_round_refclock(bdk_node_t node,int qlm,int measured_hz)768 int __bdk_qlm_round_refclock(bdk_node_t node, int qlm, int measured_hz)
769 {
770     int ref_clk;
771     if ((measured_hz > REF_100MHZ - REF_100MHZ / 10) && (measured_hz < REF_100MHZ + REF_100MHZ / 10))
772     {
773         ref_clk = REF_100MHZ;
774     }
775     else if ((measured_hz > REF_125MHZ - REF_125MHZ / 10) && (measured_hz < REF_125MHZ + REF_125MHZ / 10))
776     {
777         ref_clk = REF_125MHZ;
778     }
779     else if ((measured_hz > REF_156MHZ - REF_156MHZ / 10) && (measured_hz < REF_156MHZ + REF_156MHZ / 10))
780     {
781         ref_clk = REF_156MHZ;
782     }
783     else if (measured_hz < 1000000)
784     {
785         ref_clk = 0; /* Used for disabled QLMs */
786     }
787     else
788     {
789         ref_clk = measured_hz;
790         bdk_error("N%d.QLM%d: Unexpected reference clock speed of %d Mhz\n", node, qlm, measured_hz / 1000000);
791     }
792     return ref_clk;
793 }
794 
795 /**
796  * TWSI reads from the MCU randomly timeout. Retry a few times on
797  * failure to try and recover
798  *
799  * @param node      Node to use in a Numa setup. Can be an exact ID or a special
800  *                  value.
801  * @param twsi_id   which TWSI bus to use
802  * @param dev_addr  Device address (7 bit)
803  * @param internal_addr
804  *                  Internal address.  Can be 0, 1 or 2 bytes in width
805  * @param num_bytes Number of data bytes to read (1-4)
806  * @param ia_width_bytes
807  *                  Internal address size in bytes (0, 1, or 2)
808  *
809  * @return Read data, or -1 on failure
810  */
mcu_read(bdk_node_t node,int twsi_id,uint8_t dev_addr,uint16_t internal_addr,int num_bytes,int ia_width_bytes)811 static int64_t mcu_read(bdk_node_t node, int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes)
812 {
813     int read_tries = 0;
814     int64_t result;
815     do
816     {
817         result = bdk_twsix_read_ia(node, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes);
818         read_tries++;
819         if (result < 0)
820         {
821             BDK_TRACE(QLM, "Timeout %d reading from MCU\n", read_tries);
822             bdk_wait_usec(100000);
823         }
824     } while ((result < 0) && (read_tries < 3));
825     return result;
826 }
827 
__bdk_qlm_set_reference(bdk_node_t node,int qlm,int ref_clk)828 static void __bdk_qlm_set_reference(bdk_node_t node, int qlm, int ref_clk)
829 {
830     int use_clock;
831     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX) || CAVIUM_IS_MODEL(CAVIUM_CN83XX) || CAVIUM_IS_MODEL(CAVIUM_CN81XX))
832     {
833         switch (ref_clk)
834         {
835             case REF_156MHZ:
836                 use_clock = 0; /* Common clock 0 */
837                 BDK_TRACE(QLM, "Setting N%d.QLM%d to use common clock 0\n", node, qlm);
838                 break;
839             case REF_100MHZ:
840                 use_clock = 1; /* Common clock 1 */
841                 BDK_TRACE(QLM, "Setting N%d.QLM%d to use common clock 1\n", node, qlm);
842                 break;
843             default:
844                 use_clock = 2; /* External clock */
845                 BDK_TRACE(QLM, "Setting N%d.QLM%d to use external clock\n", node, qlm);
846                 break;
847         }
848     }
849     else
850     {
851         bdk_error("Update __bdk_qlm_set_reference() for qlm auto config of this chip\n");
852         return;
853     }
854     BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
855         c.s.com_clk_sel = (use_clock != 2);
856         c.s.use_com1 = (use_clock == 1));
857 }
858 
859 /**
860  * For Cavium EVB and EBB board, query the MCU to determine the QLM setup. Applying
861  * any configuration found.
862  *
863  * @param node   Node to configure
864  *
865  * @return Zero on success, negative on failure
866  */
bdk_qlm_mcu_auto_config(bdk_node_t node)867 int bdk_qlm_mcu_auto_config(bdk_node_t node)
868 {
869     const int MCU_TWSI_BUS = 0;
870     const int MCU_TWSI_ADDRESS = 0x60;
871     int64_t data;
872 
873     /* Check the two magic number bytes the MCU should return */
874     data = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x00, 1, 1);
875     if (data != 0xa5)
876     {
877         printf("QLM Config: MCU not found, skipping auto configuration\n");
878         return -1;
879     }
880     data = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x01, 1, 1);
881     if (data != 0x5a)
882     {
883         bdk_error("QLM Config: MCU magic number incorrect\n");
884         return -1;
885     }
886 
887     /* Read the MCU version */
888     int mcu_major = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x02, 1, 1);
889     int mcu_minor = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x03, 1, 1);
890     BDK_TRACE(QLM, "MCU version %d.%d\n", mcu_major, mcu_minor);
891     if ((mcu_major < 2) || ((mcu_major == 2) && (mcu_minor < 30)))
892     {
893         bdk_error("QLM Config: Unexpected MCU version %d.%d\n", mcu_major, mcu_minor);
894         return -1;
895     }
896 
897     /* Find out how many lanes the MCU thinks are available */
898     int lanes = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x16, 1, 1);
899     BDK_TRACE(QLM, "MCU says board has %d lanes\n", lanes);
900     int correct_lanes = 0;
901     if (cavium_is_altpkg(CAVIUM_CN88XX))
902         correct_lanes = 22;
903     else if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
904         correct_lanes = 32;
905     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
906         correct_lanes = 22;
907     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
908         correct_lanes = 8;
909     if (lanes != correct_lanes)
910     {
911         bdk_error("QLM Config: Unexpected number of lanes (%d) from MCU\n", lanes);
912         return -1;
913     }
914 
915     int lane = 0;
916     int qlm = 0;
917     while (lane < lanes)
918     {
919         int write_status;
920         int width;
921         int mode;
922         int speed;
923         int refclk;
924         /* TWSI reads from the MCU randomly timeout. Retry a few times on
925            failure to try and recover */
926         int read_tries = 0;
927         do
928         {
929             read_tries++;
930             if (read_tries > 3)
931             {
932                 bdk_error("QLM Config: Timeouts reading from MCU\n");
933                 return -1;
934             }
935             /* Space request out 20ms */
936             bdk_wait_usec(20000);
937             /* Select the lane we are interested in */
938             write_status = bdk_twsix_write_ia(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x16, 1, 1, lane);
939             /* Space request out 20ms */
940             bdk_wait_usec(20000);
941             /* Get the mode */
942             width = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x17, 1, 1);
943             mode = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x18, 2, 1);
944             speed = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x19, 2, 1);
945             refclk = mcu_read(node, MCU_TWSI_BUS, MCU_TWSI_ADDRESS, 0x1a, 1, 1);
946         } while ((write_status < 0) || (width < 0) || (mode < 0) || (speed < 0) || (refclk < 0));
947 
948         BDK_TRACE(QLM, "MCU lane %d, width %d, mode 0x%x, speed 0x%x, ref 0x%x\n",
949             lane, width, mode, speed, refclk);
950         if ((width != 0) && (width != 1) && (width != 2) && (width != 4) && (width != 8))
951         {
952             bdk_error("QLM Config: Unexpected interface width (%d) from MCU\n", width);
953             return -1;
954         }
955         /* MCU reports a width of 0 for unconfigured QLMs. It reports a width
956            of 1 for some combinations on CN80XX, and two on others. Convert
957            either 0 or 1 to the actual width, or 2 for CN80XX. Yuck */
958         if ((width == 0) || (width == 1))
959         {
960             if (cavium_is_altpkg(CAVIUM_CN81XX) && (qlm < 2))
961                 width = 2;
962             else
963                 width = bdk_qlm_get_lanes(node, qlm);
964         }
965         bdk_qlm_modes_t qlm_mode;
966         int qlm_speed = (speed >> 8) * 1000 + (speed & 0xff) * 1000 / 256;
967         int use_ref = 0;
968         bdk_qlm_mode_flags_t qlm_flags = 0;
969         if (mode < 0x4000)
970         {
971             switch (mode)
972             {
973                 case 0x0000: /* No Configuration */
974                     qlm_mode = BDK_QLM_MODE_DISABLED;
975                     break;
976                 case 0x0101: /* PCIe Host */
977                     qlm_mode = (width == 8) ? BDK_QLM_MODE_PCIE_1X8 :
978                                (width == 4) ? BDK_QLM_MODE_PCIE_1X4 :
979                                BDK_QLM_MODE_PCIE_1X2;
980                     use_ref = REF_100MHZ;
981                     break;
982                 case 0x0102: /* PCIe Endpoint */
983                     qlm_mode = (width == 8) ? BDK_QLM_MODE_PCIE_1X8 :
984                                (width == 4) ? BDK_QLM_MODE_PCIE_1X4 :
985                                BDK_QLM_MODE_PCIE_1X2;
986                     qlm_flags = BDK_QLM_MODE_FLAG_ENDPOINT;
987                     use_ref = 0; /* Use the external reference for EP mode */
988                     break;
989                 case 0x1000: /* SGMII */
990                     qlm_mode = (width == 4) ? BDK_QLM_MODE_SGMII_4X1 :
991                                (width == 2) ? BDK_QLM_MODE_SGMII_2X1 :
992                                BDK_QLM_MODE_SGMII_1X1;
993                     use_ref = REF_156MHZ;
994                     /* CN80XX parts on EBBs use phy port 2 for SGMII, while QSGMII
995                        uses the correct port. Fix this for DLM1 and DLM3 */
996                     if (cavium_is_altpkg(CAVIUM_CN81XX))
997                     {
998                         int bgx = (qlm == 3) ? 1 : 0;
999                         uint64_t phy = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0, bgx, 2);
1000                         bdk_config_set_int(phy, BDK_CONFIG_PHY_ADDRESS, 0, bgx, 1);
1001                     }
1002                     break;
1003                 case 0x1100: /* QSGMII */
1004                     qlm_mode = BDK_QLM_MODE_QSGMII_4X1;
1005                     use_ref = REF_100MHZ;
1006                     break;
1007                 case 0x2000: /* XAUI */
1008                     qlm_mode = BDK_QLM_MODE_XAUI_1X4;
1009                     use_ref = REF_156MHZ;
1010                     break;
1011                 case 0x2100: /* RXAUI */
1012                     qlm_mode = (width == 2) ? BDK_QLM_MODE_RXAUI_1X2 : BDK_QLM_MODE_RXAUI_2X2;
1013                     use_ref = REF_156MHZ;
1014                     break;
1015                 case 0x2200: /* DXAUI */
1016                     qlm_mode = BDK_QLM_MODE_XAUI_1X4;
1017                     use_ref = REF_156MHZ;
1018                     break;
1019                 case 0x3001: /* Interlaken */
1020                     qlm_mode = BDK_QLM_MODE_ILK;
1021                     use_ref = REF_156MHZ;
1022                     break;
1023                 default:
1024                     bdk_error("QLM Config: Unexpected interface mode (0x%x) from MCU\n", mode);
1025                     qlm_mode = BDK_QLM_MODE_DISABLED;
1026                     break;
1027             }
1028         }
1029         else
1030         {
1031             switch (mode)
1032             {
1033                 case 0x4000: /* SATA */
1034                     qlm_mode = (width == 2) ? BDK_QLM_MODE_SATA_2X1 : BDK_QLM_MODE_SATA_4X1;
1035                     use_ref = REF_100MHZ;
1036                     break;
1037                 case 0x5001: /* XFI */
1038                     qlm_mode = (width == 4) ? BDK_QLM_MODE_XFI_4X1 :
1039                                (width == 2) ? BDK_QLM_MODE_XFI_2X1 :
1040                                BDK_QLM_MODE_XFI_1X1;
1041                     use_ref = REF_156MHZ;
1042                     break;
1043                 case 0x5002: /* 10G-KR */
1044                     qlm_mode = (width == 4) ? BDK_QLM_MODE_10G_KR_4X1 :
1045                                (width == 2) ? BDK_QLM_MODE_10G_KR_2X1 :
1046                                BDK_QLM_MODE_10G_KR_1X1;
1047                     use_ref = REF_156MHZ;
1048                     break;
1049                 case 0x6001: /* XLAUI */
1050                     qlm_mode = BDK_QLM_MODE_XLAUI_1X4;
1051                     use_ref = REF_156MHZ;
1052                     break;
1053                 case 0x6002: /* 40G-KR4 */
1054                     qlm_mode = BDK_QLM_MODE_40G_KR4_1X4;
1055                     use_ref = REF_156MHZ;
1056                     break;
1057                 default:
1058                     bdk_error("QLM Config: Unexpected interface mode (0x%x) from MCU\n", mode);
1059                     qlm_mode = BDK_QLM_MODE_DISABLED;
1060                     break;
1061             }
1062         }
1063         lane += width;
1064         do
1065         {
1066             int internal_qlm = qlm;
1067             /* Alternate package parts have different QLM numbers for internal
1068                versus external. The MCU uses the external numbers */
1069             if (cavium_is_altpkg(CAVIUM_CN88XX))
1070             {
1071                 switch (qlm)
1072                 {
1073                     case 0: /* QLM0 -> QLM4 */
1074                         internal_qlm = 4;
1075                         break;
1076                     case 1: /* QLM1 -> QLM5 */
1077                         internal_qlm = 5;
1078                         break;
1079                     case 2: /* QLM2 -> QLM0 */
1080                         internal_qlm = 0;
1081                         break;
1082                     case 3: /* QLM3 -> QLM1 */
1083                         internal_qlm = 1;
1084                         break;
1085                     case 4: /* DLM4 -> QLM2 */
1086                         internal_qlm = 2;
1087                         break;
1088                     case 5: /* DLM5 -> QLM6 */
1089                         internal_qlm = 6;
1090                         break;
1091                     case 6: /* DLM6 -> QLM7 */
1092                         internal_qlm = 7;
1093                         break;
1094                     default:
1095                         bdk_error("Invalid external QLM%d from MCU\n", qlm);
1096                         return -1;
1097                 }
1098             }
1099             if (qlm_flags & BDK_QLM_MODE_FLAG_ENDPOINT)
1100             {
1101                 BDK_TRACE(QLM, "Skipping N%d.QLM%d mode %s(%d), speed %d, flags 0x%x (EP should already be setup)\n",
1102                     node, internal_qlm,  bdk_qlm_mode_tostring(qlm_mode), qlm_mode, qlm_speed, qlm_flags);
1103             }
1104             else
1105             {
1106                 BDK_TRACE(QLM, "Setting N%d.QLM%d mode %s(%d), speed %d, flags 0x%x\n",
1107                     node, internal_qlm,  bdk_qlm_mode_tostring(qlm_mode), qlm_mode, qlm_speed, qlm_flags);
1108                 /* Set the reference clock for this QLM */
1109                 __bdk_qlm_set_reference(node, internal_qlm, use_ref);
1110                 if (bdk_qlm_set_mode(node, internal_qlm, qlm_mode, qlm_speed, qlm_flags))
1111                     return -1;
1112             }
1113             int num_lanes = bdk_qlm_get_lanes(node, internal_qlm);
1114             /* CN86XX looks like two lanes each for DLM4-7 */
1115             if (cavium_is_altpkg(CAVIUM_CN88XX) && (qlm >= 4))
1116                 num_lanes = 2;
1117             if (qlm_mode == BDK_QLM_MODE_PCIE_1X8)
1118             {
1119                 /* PCIe x8 is a special case as the QLM config function
1120                    actually configures both QLMs in one go */
1121                 qlm++;
1122                 width -= 8;
1123             }
1124             else if ((qlm_mode == BDK_QLM_MODE_PCIE_1X4) && (width > num_lanes))
1125             {
1126                 /* PCIe x4 is a special case as the QLM config function
1127                    actually configures both QLMs in one go */
1128                 qlm++;
1129                 width -= 4;
1130             }
1131             else if (width >= num_lanes)
1132             {
1133                 if (num_lanes == 1)
1134                     width -= 2; /* Special case for CN80XX */
1135                 else
1136                     width -= num_lanes;
1137             }
1138             else
1139                 width = 0;
1140             qlm++;
1141         } while (width > 0);
1142     }
1143     return 0;
1144 }
1145 
1146 /**
1147  * Display the current settings of a QLM lane
1148  *
1149  * @param node     Node the QLM is on
1150  * @param qlm      QLM to display
1151  * @param qlm_lane Lane to use
1152  * @param show_tx  Display TX parameters
1153  * @param show_rx  Display RX parameters
1154  */
bdk_qlm_display_settings(bdk_node_t node,int qlm,int qlm_lane,bool show_tx,bool show_rx)1155 void bdk_qlm_display_settings(bdk_node_t node, int qlm, int qlm_lane, bool show_tx, bool show_rx)
1156 {
1157     const char *dir_label[] = {"Hold", "Inc", "Dec", "Hold"};
1158 
1159     uint64_t rx_aeq_out_0 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_AEQ_OUT_0(qlm, qlm_lane));
1160     uint64_t rx_aeq_out_1 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_AEQ_OUT_1(qlm, qlm_lane));
1161     uint64_t rx_aeq_out_2 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_AEQ_OUT_2(qlm, qlm_lane));
1162     uint64_t rx_vma_status_0 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_VMA_STATUS_0(qlm, qlm_lane));
1163     uint64_t rx_vma_status_1 = BDK_CSR_READ(node, BDK_GSERX_LANEX_RX_VMA_STATUS_1(qlm, qlm_lane));
1164     uint64_t sds_pin_mon_1 = BDK_CSR_READ(node, BDK_GSERX_LANEX_SDS_PIN_MON_1(qlm, qlm_lane));
1165     uint64_t sds_pin_mon_2 = BDK_CSR_READ(node, BDK_GSERX_LANEX_SDS_PIN_MON_2(qlm, qlm_lane));
1166     uint64_t br_rxx_eer = BDK_CSR_READ(node, BDK_GSERX_BR_RXX_EER(qlm, qlm_lane));
1167 
1168     printf("N%d.QLM%d Lane %d:\n", node, qlm, qlm_lane);
1169     if (show_rx)
1170     {
1171         printf("    DFE Tap 1: %llu, Tap 2: %lld, Tap 3: %lld, Tap 4: %lld, Tap 5: %lld\n",
1172             bdk_extract(rx_aeq_out_1, 0, 5),
1173             bdk_extract_smag(rx_aeq_out_1, 5, 9),
1174             bdk_extract_smag(rx_aeq_out_1, 10, 14),
1175             bdk_extract_smag(rx_aeq_out_0, 0, 4),
1176             bdk_extract_smag(rx_aeq_out_0, 5, 9));
1177         printf("    Pre-CTLE Gain: %llu, Post-CTLE Gain: %llu, CTLE Peak: %llu, CTLE Pole: %llu\n",
1178             bdk_extract(rx_aeq_out_2, 4, 4),
1179             bdk_extract(rx_aeq_out_2, 0, 4),
1180             bdk_extract(rx_vma_status_0, 2, 4),
1181             bdk_extract(rx_vma_status_0, 0, 2));
1182         printf("    RX Equalization Tx Directions Hints TXPRE: %s, TXMAIN: %s, TXPOST: %s, Figure of Merit: %llu\n",
1183             dir_label[bdk_extract(br_rxx_eer, 0, 2)],
1184             dir_label[bdk_extract(br_rxx_eer, 2, 2)],
1185             dir_label[bdk_extract(br_rxx_eer, 4, 2)],
1186             bdk_extract(br_rxx_eer, 6, 8));
1187     }
1188     if (show_tx)
1189     {
1190         printf("    TX Swing: %llu, Pre-emphasis Pre-cursor: %llu, Post-cursor: %llu\n",
1191             bdk_extract(sds_pin_mon_1, 1, 5),
1192             bdk_extract(sds_pin_mon_2, 0, 4),
1193             bdk_extract(sds_pin_mon_2, 4, 5));
1194         printf("    TX Boost Enable: %llu, TX Turbo Mode: %llu\n",
1195             bdk_extract(sds_pin_mon_2, 10, 1),
1196             bdk_extract(sds_pin_mon_2, 9, 1));
1197     }
1198     printf("    Training-done: %llu\n",
1199            bdk_extract(rx_vma_status_1, 7, 1));
1200 }
1201 
1202 /**
1203  * Perform RX equalization on a QLM
1204  *
1205  * @param node     Node the QLM is on
1206  * @param qlm      QLM to perform RX equalization on
1207  * @param qlm_lane Lane to use, or -1 for all lanes
1208  *
1209  * @return Zero on success, negative if any lane failed RX equalization
1210  */
__bdk_qlm_rx_equalization(bdk_node_t node,int qlm,int qlm_lane)1211 int __bdk_qlm_rx_equalization(bdk_node_t node, int qlm, int qlm_lane)
1212 {
1213     /* Don't touch QLMs is reset or powered down */
1214     BDK_CSR_INIT(phy_ctl, node, BDK_GSERX_PHY_CTL(qlm));
1215     if (phy_ctl.s.phy_pd || phy_ctl.s.phy_reset)
1216         return -1;
1217     /* Don't run on PCIe links */
1218     if (bdk_qlm_get_mode(node, qlm) <= BDK_QLM_MODE_PCIE_1X8)
1219         return -1;
1220 
1221     int fail = 0; /* Bitmask of lanes that failed CDR Lock or Eltrical Idle check */
1222     int pending = 0; /* Bitmask of lanes that we're waiting for */
1223     int MAX_LANES = bdk_qlm_get_lanes(node, qlm);
1224 
1225     BDK_TRACE(QLM, "N%d.QLM%d: Starting RX equalization on lane %d\n", node, qlm, qlm_lane);
1226     for (int lane = 0; lane < MAX_LANES; lane++)
1227     {
1228         /* Skip lanes we don't care about */
1229         if ((qlm_lane != -1) && (qlm_lane != lane))
1230             continue;
1231         /* Check that the lane has completed CDR lock */
1232         BDK_CSR_INIT(eie_detsts, node, BDK_GSERX_RX_EIE_DETSTS(qlm));
1233         if (((1 << lane) & eie_detsts.s.cdrlock) == 0)
1234         {
1235             /* Mark bad so we skip this lane below */
1236             fail |= 1 << lane;
1237             continue;
1238         }
1239         /* Enable software control */
1240         BDK_CSR_MODIFY(c, node, BDK_GSERX_BR_RXX_CTL(qlm, lane),
1241             c.s.rxt_swm = 1);
1242         /* Clear the completion flag and initiate a new request */
1243         BDK_CSR_MODIFY(c, node, BDK_GSERX_BR_RXX_EER(qlm, lane),
1244             c.s.rxt_esv = 0;
1245             c.s.rxt_eer = 1);
1246         /* Remember that we have to wait for this lane */
1247         pending |= 1 << lane;
1248     }
1249 
1250     /* Timing a few of these over XFI on CN73XX, each takes 21-23ms. XLAUI
1251        was about the same time. DXAUI and RXAUI both took 2-3ms. Put the
1252        timeout at 250ms, which is roughly 10x my measurements. */
1253     uint64_t timeout = bdk_clock_get_count(BDK_CLOCK_TIME) + bdk_clock_get_rate(node, BDK_CLOCK_TIME) / 4;
1254     while (pending)
1255     {
1256         for (int lane = 0; lane < MAX_LANES; lane++)
1257         {
1258             int lane_mask = 1 << lane;
1259             /* Only check lanes that are pending */
1260             if (!(pending & lane_mask))
1261                 continue;
1262             /* Read the registers for checking Electrical Idle / CDR lock and
1263                the status of the RX equalization */
1264             BDK_CSR_INIT(eie_detsts, node, BDK_GSERX_RX_EIE_DETSTS(qlm));
1265             BDK_CSR_INIT(gserx_br_rxx_eer, node, BDK_GSERX_BR_RXX_EER(qlm, lane));
1266             /* Mark failure if lane entered Electrical Idle or lost CDR Lock. The
1267                bit for the lane will have cleared in either EIESTS or CDRLOCK */
1268             if (!(eie_detsts.s.eiests & eie_detsts.s.cdrlock & lane_mask))
1269             {
1270                 fail |= lane_mask;
1271                 pending &= ~lane_mask;
1272             }
1273             else if (gserx_br_rxx_eer.s.rxt_esv)
1274             {
1275                 /* Clear pending if RX equalization finished */
1276                 pending &= ~lane_mask;
1277             }
1278         }
1279         /* Break out of the loop on timeout */
1280         if (bdk_clock_get_count(BDK_CLOCK_TIME) > timeout)
1281             break;
1282     }
1283 
1284     /* Cleanup and report status */
1285     for (int lane = 0; lane < MAX_LANES; lane++)
1286     {
1287         /* Skip lanes we don't care about */
1288         if ((qlm_lane != -1) && (qlm_lane != lane))
1289             continue;
1290         int lane_mask = 1 << lane;
1291         /* Get the final RX equalization status */
1292         BDK_CSR_INIT(gserx_br_rxx_eer, node, BDK_GSERX_BR_RXX_EER(qlm, lane));
1293         /* Disable software control */
1294         BDK_CSR_MODIFY(c, node, BDK_GSERX_BR_RXX_CTL(qlm, lane),
1295             c.s.rxt_swm = 0);
1296         /* Report status */
1297         if (fail & lane_mask)
1298         {
1299             BDK_TRACE(QLM, "N%d.QLM%d: Lane %d RX equalization lost CDR Lock or entered Electrical Idle\n", node, qlm, lane);
1300         }
1301         else if ((pending & lane_mask) || !gserx_br_rxx_eer.s.rxt_esv)
1302         {
1303             BDK_TRACE(QLM, "N%d.QLM%d: Lane %d RX equalization timeout\n", node, qlm, lane);
1304             fail |= 1 << lane;
1305         }
1306         else
1307         {
1308             bdk_qlm_display_settings(node, qlm, lane, false, true);
1309         }
1310     }
1311 
1312     return (fail) ? -1 : 0;
1313 }
1314 
1315 /**
1316  * Configure the TX tuning parameters for a QLM lane. The tuning parameters can
1317  * be specified as -1 to maintain their current value
1318  *
1319  * @param node      Node to configure
1320  * @param qlm       QLM to configure
1321  * @param lane      Lane to configure
1322  * @param tx_swing  Transmit swing (coef 0) Range 0-31
1323  * @param tx_pre    Pre cursor emphasis (Coef -1). Range 0-15
1324  * @param tx_post   Post cursor emphasis (Coef +1). Range 0-31
1325  * @param tx_gain   Transmit gain. Range 0-7
1326  * @param tx_vboost Transmit voltage boost. Range 0-1
1327  *
1328  * @return Zero on success, negative on failure
1329  */
__bdk_qlm_tune_lane_tx(bdk_node_t node,int qlm,int lane,int tx_swing,int tx_pre,int tx_post,int tx_gain,int tx_vboost)1330 int __bdk_qlm_tune_lane_tx(bdk_node_t node, int qlm, int lane, int tx_swing, int tx_pre, int tx_post, int tx_gain, int tx_vboost)
1331 {
1332     /* Check tuning constraints */
1333     if ((tx_swing < -1) || (tx_swing > 25))
1334     {
1335         bdk_error("N%d.QLM%d: Lane %d: Invalid TX_SWING(%d)\n", node, qlm, lane, tx_swing);
1336         return -1;
1337     }
1338     if ((tx_pre < -1) || (tx_pre > 10))
1339     {
1340         bdk_error("N%d.QLM%d: Lane %d: Invalid TX_PRE(%d)\n", node, qlm, lane, tx_pre);
1341         return -1;
1342     }
1343     if ((tx_post < -1) || (tx_post > 15))
1344     {
1345         bdk_error("N%d.QLM%d: Lane %d: Invalid TX_POST(%d)\n", node, qlm, lane, tx_post);
1346         return -1;
1347     }
1348     if ((tx_pre >= 0) && (tx_post >= 0) && (tx_swing >= 0) && (tx_pre + tx_post - tx_swing > 2))
1349     {
1350         bdk_error("N%d.QLM%d: Lane %d: TX_PRE(%d) + TX_POST(%d) - TX_SWING(%d) must be less than or equal to 2\n", node, qlm, lane, tx_pre, tx_post, tx_swing);
1351         return -1;
1352     }
1353     if ((tx_pre >= 0) && (tx_post >= 0) && (tx_swing >= 0) && (tx_pre + tx_post + tx_swing > 35))
1354     {
1355         bdk_error("N%d.QLM%d: Lane %d: TX_PRE(%d) + TX_POST(%d) + TX_SWING(%d) must be less than or equal to 35\n", node, qlm, lane, tx_pre, tx_post, tx_swing);
1356         return -1;
1357     }
1358 
1359     if ((tx_gain < -1) || (tx_gain > 7))
1360     {
1361         bdk_error("N%d.QLM%d: Lane %d: Invalid TX_GAIN(%d). TX_GAIN must be between 0 and 7\n", node, qlm, lane, tx_gain);
1362         return -1;
1363     }
1364 
1365     if ((tx_vboost < -1) || (tx_vboost > 1))
1366     {
1367         bdk_error("N%d.QLM%d: Lane %d: Invalid TX_VBOOST(%d).  TX_VBOOST must be 0 or 1.\n", node, qlm, lane, tx_vboost);
1368         return -1;
1369     }
1370 
1371     if ((tx_pre != -1) && (tx_post == -1))
1372     {
1373         BDK_CSR_INIT(emphasis, node, BDK_GSERX_LANEX_TX_PRE_EMPHASIS(qlm, lane));
1374         tx_post = emphasis.s.cfg_tx_premptap >> 4;
1375     }
1376 
1377     if ((tx_post != -1) && (tx_pre == -1))
1378     {
1379         BDK_CSR_INIT(emphasis, node, BDK_GSERX_LANEX_TX_PRE_EMPHASIS(qlm, lane));
1380         tx_pre = emphasis.s.cfg_tx_premptap & 0xf;
1381     }
1382 
1383     BDK_TRACE(QLM, "N%d.QLM%d: Lane %d: TX_SWING=%d, TX_PRE=%d, TX_POST=%d, TX_GAIN=%d, TX_VBOOST=%d\n",
1384         node, qlm, lane, tx_swing, tx_pre, tx_post, tx_gain, tx_vboost);
1385 
1386     /* Manual Tx Swing and Tx Equalization Programming Steps */
1387 
1388     /* 1) Enable Tx swing and Tx emphasis overrides */
1389     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_1(qlm, lane),
1390         c.s.tx_swing_ovrrd_en = (tx_swing != -1);
1391         c.s.tx_premptap_ovrrd_val = (tx_pre != -1) && (tx_post != -1);
1392         c.s.tx_vboost_en_ovrrd_en = (tx_vboost != -1)); /* Vboost override */
1393     /* 2) Program the Tx swing and Tx emphasis Pre-cursor and Post-cursor values */
1394     if (tx_swing != -1)
1395         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_0(qlm, lane),
1396             c.s.cfg_tx_swing = tx_swing);
1397     if ((tx_pre != -1) && (tx_post != -1))
1398         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_PRE_EMPHASIS(qlm, lane),
1399             c.s.cfg_tx_premptap = (tx_post << 4) | tx_pre);
1400     /* Apply TX gain settings */
1401     if (tx_gain != -1)
1402         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_3(qlm, lane),
1403             c.s.pcs_sds_tx_gain = tx_gain);
1404     /* Apply TX vboost settings */
1405     if (tx_vboost != -1)
1406         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_TX_CFG_3(qlm, lane),
1407             c.s.cfg_tx_vboost_en = tx_vboost);
1408     /* 3) Program override for the Tx coefficient request */
1409     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_0(qlm, lane),
1410 	 if (((tx_pre != -1) && (tx_post != -1)) || (tx_swing != -1))
1411 	     c.s.cfg_tx_coeff_req_ovrrd_val = 1;
1412         if (tx_vboost != -1)
1413             c.s.cfg_tx_vboost_en_ovrrd_val = 1;
1414         );
1415     /* 4) Enable the Tx coefficient request override enable */
1416     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
1417 	 if (((tx_pre != -1) && (tx_post != -1)) || (tx_swing != -1))
1418 	     c.s.cfg_tx_coeff_req_ovrrd_en = 1;
1419         if (tx_vboost != -1)
1420             c.s.cfg_tx_vboost_en_ovrrd_en = 1
1421         );
1422     /* 5) Issue a Control Interface Configuration Override request to start
1423         the Tx equalizer Optimization cycle which applies the new Tx swing
1424         and equalization settings */
1425     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
1426         c.s.ctlifc_ovrrd_req = 1);
1427 
1428     /* 6) Prepare for a subsequent Tx swing and Tx equalization adjustment:
1429         a) Disable the Tx coefficient request override enable */
1430     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
1431         c.s.cfg_tx_coeff_req_ovrrd_en = 0);
1432     /* b) Issue a Control Interface Configuration Override request */
1433     BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_PCS_CTLIFC_2(qlm, lane),
1434         c.s.ctlifc_ovrrd_req = 1);
1435     /* The new Tx swing and Pre-cursor and Post-cursor settings will now take
1436        effect. */
1437     return 0;
1438 }
1439 
1440 /**
1441  * Some QLM speeds need to override the default tuning parameters
1442  *
1443  * @param node     Node to use in a Numa setup
1444  * @param qlm      QLM to configure
1445  * @param mode     Desired mode
1446  * @param baud_mhz Desired speed
1447  */
__bdk_qlm_tune(bdk_node_t node,int qlm,bdk_qlm_modes_t mode,int baud_mhz)1448 void __bdk_qlm_tune(bdk_node_t node, int qlm, bdk_qlm_modes_t mode, int baud_mhz)
1449 {
1450     /* Note: This function is not called for CCPI. For CCPI tuning, see
1451        bdk-init-nz-node.c */
1452     /* Tuning parameters override the KR training. Don't apply them for KR links */
1453     switch (mode)
1454     {
1455         case BDK_QLM_MODE_10G_KR_1X1:
1456         case BDK_QLM_MODE_10G_KR_2X1:
1457         case BDK_QLM_MODE_10G_KR_4X1:
1458         case BDK_QLM_MODE_40G_KR4_1X4:
1459             return;
1460         case BDK_QLM_MODE_PCIE_1X1:
1461         case BDK_QLM_MODE_PCIE_2X1:
1462         case BDK_QLM_MODE_PCIE_1X2:
1463         case BDK_QLM_MODE_PCIE_1X4:
1464         case BDK_QLM_MODE_PCIE_1X8:
1465             /* Don't tune PCIe Gen3 as it has its own builtin, similar to KR */
1466             if (baud_mhz > 5000)
1467                 return;
1468             break;
1469         default:
1470             break;
1471     }
1472 
1473     /* We're apply tuning for all lanes on this QLM */
1474     int num_lanes = bdk_qlm_get_lanes(node, qlm);
1475     for (int lane = 0; lane < num_lanes; lane++)
1476     {
1477         /* TX Swing: First read any board specific setting from the environment */
1478         int swing = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_SWING, node, qlm, lane);
1479         /* If no setting, use hard coded generic defaults */
1480         if (swing == -1)
1481         {
1482             if (baud_mhz == 6250)
1483             {
1484                 /* Email from Brendan Metzner about RXAUI around 2/7/2016 */
1485                 swing = 0x12;
1486             }
1487             else if (baud_mhz == 10312)
1488             {
1489                 /* From lab measurements of EBB8800 at 10.3125G */
1490                 swing = 0xd;
1491             }
1492         }
1493 
1494         /* TX Premptap: First read any board specific setting from the environment */
1495         int premptap = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_PREMPTAP, node, qlm, lane);
1496         /* If no setting, use hard coded generic defaults */
1497         if (premptap == -1)
1498         {
1499             if (baud_mhz == 6250)
1500             {
1501                 /* From lab measurements of EBB8800 at 6.25G */
1502                 premptap = 0xa0;
1503             }
1504             else if (baud_mhz == 10312)
1505             {
1506                 /* From lab measurements of EBB8800 at 10.3125G */
1507                 premptap = 0xd0;
1508             }
1509         }
1510 
1511         int tx_pre = (premptap == -1) ? -1 : premptap & 0xf;
1512         int tx_post = (premptap == -1) ? -1 : premptap >> 4;
1513         int gain = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_GAIN, node, qlm, lane);
1514         int vboost = bdk_config_get_int(BDK_CONFIG_QLM_TUNING_TX_VBOOST, node, qlm, lane);
1515 
1516         __bdk_qlm_tune_lane_tx(node, qlm, lane, swing, tx_pre, tx_post, gain, vboost);
1517 
1518         /* Email from Brendan Metzner about RXAUI around 2/7/2016 suggested the
1519            following setting for RXAUI at 6.25G with both PHY or cable. I'm
1520            applying it to all lanes running at 6.25G */
1521         if (baud_mhz == 6250)
1522         {
1523             /* This is changing the Q/QB error sampler 0 threshold from 0xD
1524                 to 0xF */
1525             BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_CFG_4(qlm, lane),
1526                 c.s.cfg_rx_errdet_ctrl = 0xcf6f);
1527         }
1528     }
1529 }
1530 
1531 /**
1532  * Disables DFE for the specified QLM lane(s).
1533  * This function should only be called for low-loss channels.
1534  *
1535  * @param node   Node to configure
1536  * @param qlm    QLM to configure
1537  * @param lane   Lane to configure, or -1 for all lanes
1538  */
__bdk_qlm_dfe_disable(int node,int qlm,int lane)1539 void __bdk_qlm_dfe_disable(int node, int qlm, int lane)
1540 {
1541     int num_lanes = bdk_qlm_get_lanes(node, qlm);
1542     int l;
1543 
1544     for (l = 0; l < num_lanes; l++) {
1545         if ((lane != -1) && (lane != l))
1546 	    continue;
1547         /* 1. Write GSERX_LANEx_RX_LOOP_CTRL = 0x0270 (var "loop_ctrl" with bits 8 & 1 cleared).
1548          * bit<1> dfe_en_byp = 1'b0 */
1549         BDK_CSR_MODIFY(c, node,  BDK_GSERX_LANEX_RX_LOOP_CTRL(qlm, l),
1550             c.s.cfg_rx_lctrl = c.s.cfg_rx_lctrl & 0x3fd);
1551 
1552         /* 2. Write GSERX_LANEx_RX_VALBBD_CTRL_1 = 0x0000 (var "ctrl1" with all bits cleared)
1553          * bits<14:11> CFG_RX_DFE_C3_MVAL = 4'b0000
1554          * bit<10> CFG_RX_DFE_C3_MSGN = 1'b0
1555          * bits<9:6> CFG_RX_DFE_C2_MVAL = 4'b0000
1556          * bit<5> CFG_RX_DFE_C2_MSGN = 1'b0
1557          * bits<4:1> CFG_RX_DFE_C1_MVAL = 5'b0000
1558          * bits<0> CFG_RX_DFE_C1_MSGN = 1'b0 */
1559         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_1(qlm, l),
1560             c.s.dfe_c3_mval = 0;
1561             c.s.dfe_c3_msgn = 0;
1562             c.s.dfe_c2_mval = 0;
1563             c.s.dfe_c2_msgn = 0;
1564             c.s.dfe_c1_mval = 0;
1565             c.s.dfe_c1_msgn = 0);
1566 
1567         /* 3. Write GSERX_LANEx_RX_VALBBD_CTRL_0 = 0x2400 (var "ctrl0" with following bits set/cleared)
1568          * bits<11:10> CFG_RX_DFE_GAIN = 0x1
1569          * bits<9:6> CFG_RX_DFE_C5_MVAL = 4'b0000
1570          * bit<5> CFG_RX_DFE_C5_MSGN = 1'b0
1571          * bits<4:1> CFG_RX_DFE_C4_MVAL = 4'b0000
1572          * bit<0> CFG_RX_DFE_C4_MSGN = 1'b0 */
1573         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_0(qlm, l),
1574             c.s.dfe_gain = 0x1;
1575             c.s.dfe_c5_mval = 0;
1576             c.s.dfe_c5_msgn = 0;
1577             c.s.dfe_c4_mval = 0;
1578             c.s.dfe_c4_msgn = 0);
1579 
1580         /* 4. Write GSER(0..13)_LANE(0..3)_RX_VALBBD_CTRL_2 = 0x003F  //enable DFE tap overrides
1581          * bit<5> dfe_ovrd_en = 1
1582          * bit<4> dfe_c5_ovrd_val = 1
1583          * bit<3> dfe_c4_ovrd_val = 1
1584          * bit<2> dfe_c3_ovrd_val = 1
1585          * bit<1> dfe_c2_ovrd_val = 1
1586          * bit<0> dfe_c1_ovrd_val = 1
1587          */
1588         BDK_CSR_MODIFY(c, node, BDK_GSERX_LANEX_RX_VALBBD_CTRL_2(qlm, l),
1589             c.s.dfe_ovrd_en = 0x1;
1590             c.s.dfe_c5_ovrd_val = 0x1;
1591             c.s.dfe_c4_ovrd_val = 0x1;
1592             c.s.dfe_c3_ovrd_val = 0x1;
1593             c.s.dfe_c2_ovrd_val = 0x1;
1594             c.s.dfe_c1_ovrd_val = 0x1);
1595 
1596     }
1597 }
1598 
1599 /**
1600  * Check if a specific lane is using KR training. This is used by low level GSER
1601  * code to remember which QLMs and lanes need to support KR training for BGX. The
1602  * hardware doesn't have a bit set aside to record this, so we repurpose the
1603  * register GSERX_SCRATCH.
1604  *
1605  * @param node   Node to check
1606  * @param qlm    QLM to check
1607  * @param lane   Lane to check
1608  *
1609  * @return True if this lane uses KR with BGX, false otherwise
1610  */
__bdk_qlm_is_lane_kr(bdk_node_t node,int qlm,int lane)1611 bool __bdk_qlm_is_lane_kr(bdk_node_t node, int qlm, int lane)
1612 {
1613     uint64_t mask = BDK_CSR_READ(node, BDK_GSERX_SCRATCH(qlm));
1614     return 1 & (mask >> lane);
1615 }
1616 
1617 /**
1618  * Set if a specific lane is using KR training. This is used by low level GSER
1619  * code to remember which QLMs and lanes need to support KR training for BGX. The
1620  * hardware doesn't have a bit set aside to record this, so we repurpose the
1621  * register GSERX_SCRATCH.
1622  *
1623  * @param node   Node to set
1624  * @param qlm    QLM to set
1625  * @param lane   Lane to set
1626  * @param is_kr  KR (true) or XFI/XLAUI (false)
1627  */
__bdk_qlm_set_lane_kr(bdk_node_t node,int qlm,int lane,bool is_kr)1628 void __bdk_qlm_set_lane_kr(bdk_node_t node, int qlm, int lane, bool is_kr)
1629 {
1630     uint64_t mask = BDK_CSR_READ(node, BDK_GSERX_SCRATCH(qlm));
1631     if (is_kr)
1632         mask |= 1 << lane;
1633     else
1634         mask &= ~(1 << lane);
1635     BDK_CSR_WRITE(node, BDK_GSERX_SCRATCH(qlm), mask);
1636 }
1637