xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/bdk/libbdk-hal/bdk-qlm.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 <stdlib.h>
41 #include <string.h>
42 #include "libbdk-arch/bdk-csrs-gser.h"
43 #include "libbdk-arch/bdk-csrs-gsern.h"
44 #include "libbdk-hal/if/bdk-if.h"
45 #include "libbdk-hal/bdk-qlm.h"
46 #include "libbdk-hal/qlm/bdk-qlm-common.h"
47 
48 /* This code is an optional part of the BDK. It is only linked in
49     if BDK_REQUIRE() needs it */
50 BDK_REQUIRE_DEFINE(QLM);
51 
52 /**
53  * Convert a mode into a configuration variable string value
54  *
55  * @param mode   Mode to convert
56  *
57  * @return configuration value string
58  */
bdk_qlm_mode_to_cfg_str(bdk_qlm_modes_t mode)59 const char *bdk_qlm_mode_to_cfg_str(bdk_qlm_modes_t mode)
60 {
61 #define MODE_CASE(m) case (m): return (#m)+13
62     switch (mode)
63     {
64         MODE_CASE(BDK_QLM_MODE_DISABLED);
65         MODE_CASE(BDK_QLM_MODE_PCIE_1X1);
66         MODE_CASE(BDK_QLM_MODE_PCIE_2X1);
67         MODE_CASE(BDK_QLM_MODE_PCIE_1X2);
68         MODE_CASE(BDK_QLM_MODE_PCIE_1X4);
69         MODE_CASE(BDK_QLM_MODE_PCIE_1X8);
70         MODE_CASE(BDK_QLM_MODE_PCIE_1X16);
71 
72         MODE_CASE(BDK_QLM_MODE_SATA_4X1);
73         MODE_CASE(BDK_QLM_MODE_SATA_2X1);
74 
75         MODE_CASE(BDK_QLM_MODE_ILK);
76         MODE_CASE(BDK_QLM_MODE_SGMII_4X1);
77         MODE_CASE(BDK_QLM_MODE_SGMII_2X1);
78         MODE_CASE(BDK_QLM_MODE_SGMII_1X1);
79         MODE_CASE(BDK_QLM_MODE_XAUI_1X4);
80         MODE_CASE(BDK_QLM_MODE_RXAUI_2X2);
81         MODE_CASE(BDK_QLM_MODE_RXAUI_1X2);
82         MODE_CASE(BDK_QLM_MODE_OCI);
83         MODE_CASE(BDK_QLM_MODE_XFI_4X1);
84         MODE_CASE(BDK_QLM_MODE_XFI_2X1);
85         MODE_CASE(BDK_QLM_MODE_XFI_1X1);
86         MODE_CASE(BDK_QLM_MODE_XLAUI_1X4);
87         MODE_CASE(BDK_QLM_MODE_10G_KR_4X1);
88         MODE_CASE(BDK_QLM_MODE_10G_KR_2X1);
89         MODE_CASE(BDK_QLM_MODE_10G_KR_1X1);
90         MODE_CASE(BDK_QLM_MODE_40G_KR4_1X4);
91         MODE_CASE(BDK_QLM_MODE_QSGMII_4X1);
92         MODE_CASE(BDK_QLM_MODE_25G_4X1);
93         MODE_CASE(BDK_QLM_MODE_25G_2X1);
94         MODE_CASE(BDK_QLM_MODE_50G_2X2);
95         MODE_CASE(BDK_QLM_MODE_50G_1X2);
96         MODE_CASE(BDK_QLM_MODE_100G_1X4);
97         MODE_CASE(BDK_QLM_MODE_25G_KR_4X1);
98         MODE_CASE(BDK_QLM_MODE_25G_KR_2X1);
99         MODE_CASE(BDK_QLM_MODE_50G_KR_2X2);
100         MODE_CASE(BDK_QLM_MODE_50G_KR_1X2);
101         MODE_CASE(BDK_QLM_MODE_100G_KR4_1X4);
102         MODE_CASE(BDK_QLM_MODE_USXGMII_4X1);
103         MODE_CASE(BDK_QLM_MODE_USXGMII_2X1);
104 
105         case BDK_QLM_MODE_LAST: break; /* fall through error */
106     }
107     return "INVALID_QLM_MODE_VALUE";
108 }
109 
110 /**
111  * Convert a configuration variable value string into a mode
112  *
113  * @param val  Configuration variable value
114  *
115  * @return mode
116  */
bdk_qlm_cfg_string_to_mode(const char * val)117 bdk_qlm_modes_t bdk_qlm_cfg_string_to_mode(const char *val)
118 {
119     bdk_qlm_modes_t mode;
120 
121     for (mode = 0; mode < BDK_QLM_MODE_LAST; mode++)
122     {
123         if (0 == strcmp(val, bdk_qlm_mode_to_cfg_str(mode)))
124         {
125             return mode;
126         }
127     }
128     return -1;
129 }
130 
131 /**
132  * Convert a mode into a human understandable string
133  *
134  * @param mode   Mode to convert
135  *
136  * @return Easy to read string
137  */
bdk_qlm_mode_tostring(bdk_qlm_modes_t mode)138 const char *bdk_qlm_mode_tostring(bdk_qlm_modes_t mode)
139 {
140     const char *result = "Unknown, update bdk_qlm_mode_tostring()";
141     switch (mode)
142     {
143         case BDK_QLM_MODE_DISABLED:
144             result = "Disabled";
145             break;
146         case BDK_QLM_MODE_PCIE_1X1:
147             result = "1 PCIe, 1 lane";
148             break;
149         case BDK_QLM_MODE_PCIE_2X1:
150             result = "2 PCIe, 1 lane each";
151             break;
152         case BDK_QLM_MODE_PCIE_1X2:
153             result = "1 PCIe, 2 lanes";
154             break;
155         case BDK_QLM_MODE_PCIE_1X4:
156             result = "1 PCIe, 4 lanes";
157             break;
158         case BDK_QLM_MODE_PCIE_1X8:
159             result = "1 PCIe, 8 lanes";
160             break;
161         case BDK_QLM_MODE_PCIE_1X16:
162             result = "1 PCIe, 16 lanes";
163             break;
164 
165         case BDK_QLM_MODE_SATA_4X1:
166             result = "4 SATA, one lane each";
167             break;
168         case BDK_QLM_MODE_SATA_2X1:
169             result = "2 SATA, one lane each";
170             break;
171 
172         case BDK_QLM_MODE_ILK:
173             result = "Interlaken";
174             break;
175         case BDK_QLM_MODE_SGMII_4X1:
176             result = "4 SGMII, 1 lane each";
177             break;
178         case BDK_QLM_MODE_SGMII_2X1:
179             result = "2 SGMII, 1 lane each";
180             break;
181         case BDK_QLM_MODE_SGMII_1X1:
182             result = "1 SGMII, 1 lane";
183             break;
184         case BDK_QLM_MODE_XAUI_1X4:
185             result = "1 XAUI, 4 lanes";
186             break;
187         case BDK_QLM_MODE_RXAUI_2X2:
188             result = "2 RXAUI, 2 lanes each";
189             break;
190         case BDK_QLM_MODE_RXAUI_1X2:
191             result = "1 RXAUI, 2 lanes each";
192             break;
193         case BDK_QLM_MODE_OCI:
194             result = "Cavium Coherent Processor Interconnect";
195             break;
196         case BDK_QLM_MODE_XFI_4X1:
197             result = "4 XFI, 1 lane each";
198             break;
199         case BDK_QLM_MODE_XFI_2X1:
200             result = "2 XFI, 1 lane each";
201             break;
202         case BDK_QLM_MODE_XFI_1X1:
203             result = "1 XFI, 1 lane";
204             break;
205         case BDK_QLM_MODE_XLAUI_1X4:
206             result = "1 XLAUI, 4 lanes";
207             break;
208         case BDK_QLM_MODE_10G_KR_4X1:
209             result = "4 10GBASE-KR, 1 lane each";
210             break;
211         case BDK_QLM_MODE_10G_KR_2X1:
212             result = "2 10GBASE-KR, 1 lane each";
213             break;
214         case BDK_QLM_MODE_10G_KR_1X1:
215             result = "1 10GBASE-KR, 1 lane";
216             break;
217         case BDK_QLM_MODE_40G_KR4_1X4:
218             result = "1 40GBASE-KR4, 4 lanes";
219             break;
220         case BDK_QLM_MODE_QSGMII_4X1:
221             result = "4 QSGMII, 1 lane";
222             break;
223         case BDK_QLM_MODE_25G_4X1:
224             result = "4 25G, 1 lane each";
225             break;
226         case BDK_QLM_MODE_25G_2X1:
227             result = "2 25G, 1 lane each";
228             break;
229         case BDK_QLM_MODE_50G_2X2:
230             result = "2 50G, 2 lanes each";
231             break;
232         case BDK_QLM_MODE_50G_1X2:
233             result = "1 50G, 2 lanes";
234             break;
235         case BDK_QLM_MODE_100G_1X4:
236             result = "1 100G, 4 lanes";
237             break;
238         case BDK_QLM_MODE_25G_KR_4X1:
239             result = "4 25G, 1 lane each";
240             break;
241         case BDK_QLM_MODE_25G_KR_2X1:
242             result = "2 25G, 1 lane each";
243             break;
244         case BDK_QLM_MODE_50G_KR_2X2:
245             result = "2 50G, 2 lanes each";
246             break;
247         case BDK_QLM_MODE_50G_KR_1X2:
248             result = "1 50G, 2 lanes";
249             break;
250         case BDK_QLM_MODE_100G_KR4_1X4:
251             result = "1 100G, 4 lanes";
252             break;
253         case BDK_QLM_MODE_USXGMII_4X1:
254             result = "4 USXGMII, 1 lane each";
255             break;
256         case BDK_QLM_MODE_USXGMII_2X1:
257             result = "2 USXGMII, 1 lane each";
258             break;
259 
260         case BDK_QLM_MODE_LAST:
261             break; /* fallthrough error */
262     }
263     return result;
264 }
265 
bdk_qlm_measure_clock(bdk_node_t node,int qlm)266 int bdk_qlm_measure_clock(bdk_node_t node, int qlm)
267 {
268     int ref_clock = __bdk_qlm_measure_refclock(node, qlm);
269     BDK_TRACE(QLM, "N%d.QLM%d: Ref clock %d Hz\n", node, qlm, ref_clock);
270 
271     return ref_clock;
272 }
273 
274 /**
275  * Set the QLM's clock source.
276  *
277  * @param node     Node to use in a Numa setup
278  * @param qlm      QLM to configure
279  * @param clk      Clock source for QLM
280  *
281  * @return Zero on success, negative on failure
282  */
bdk_qlm_set_clock(bdk_node_t node,int qlm,bdk_qlm_clock_t clk)283 int bdk_qlm_set_clock(bdk_node_t node, int qlm, bdk_qlm_clock_t clk)
284 {
285     if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
286     {
287         int sel;
288         int com1;
289         switch (clk)
290         {
291             case BDK_QLM_CLK_COMMON_0:
292                 sel = 1;
293                 com1 = 0;
294                 break;
295             case BDK_QLM_CLK_COMMON_1:
296                 sel = 1;
297                 com1 = 1;
298                 break;
299             case BDK_QLM_CLK_EXTERNAL:
300                 sel = 0;
301                 com1 = 0;
302                 break;
303             default:
304                 bdk_warn("Unrecognized clock mode %d for QLM%d on node %d.\n",
305                      clk, qlm, node);
306                 return -1;
307         }
308 
309         BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
310             c.s.com_clk_sel = sel;
311             c.s.use_com1 = com1);
312     }
313     else
314     {
315         int cclksel;
316         switch (clk)
317         {
318             case BDK_QLM_CLK_COMMON_0:
319                 cclksel = 0;
320                 break;
321             case BDK_QLM_CLK_COMMON_1:
322                 cclksel = 1;
323                 break;
324             case BDK_QLM_CLK_COMMON_2:
325                 cclksel = 2;
326                 break;
327             case BDK_QLM_CLK_EXTERNAL:
328                 cclksel = 3;
329                 break;
330             default:
331                 bdk_warn("Unrecognized clock mode %d for QLM%d on node %d.\n",
332                      clk, qlm, node);
333                 return -1;
334         }
335         BDK_CSR_MODIFY(c, node, BDK_GSERNX_COMMON_REFCLK_BCFG(qlm),
336             c.s.pwdn = (clk == BDK_QLM_CLK_EXTERNAL) ? 0 : 1;
337             c.s.cclksel = cclksel);
338     }
339     return 0;
340 }
341 
342 /**
343  * Display an eye diagram for the given QLM lane. The eye data can be in "eye", or
344  * captured during the call if "eye" is NULL.
345  *
346  * @param node     Node to use in numa setup
347  * @param qlm      QLM to use
348  * @param qlm_lane Which lane
349  * @param format   Display format. 0 = raw, 1 = Color ASCII
350  * @param eye      Eye data to display, or NULL if the data should be captured.
351  *
352  * @return Zero on success, negative on failure
353  */
bdk_qlm_eye_display(bdk_node_t node,int qlm,int qlm_lane,int format,const bdk_qlm_eye_t * eye)354 int bdk_qlm_eye_display(bdk_node_t node, int qlm, int qlm_lane, int format, const bdk_qlm_eye_t *eye)
355 {
356     int result;
357     int need_free = 0;
358     if (eye == NULL)
359     {
360         bdk_qlm_eye_t *eye_data = malloc(sizeof(bdk_qlm_eye_t));
361         if (eye_data == NULL)
362         {
363             bdk_error("Failed to allocate space for eye\n");
364             return -1;
365         }
366         if (bdk_qlm_eye_capture(node, qlm, qlm_lane, eye_data)) {
367 	    free(eye_data);
368 	    return -1;
369 	}
370         eye = eye_data;
371 	need_free = 1;
372     }
373 
374     /* Calculate the max eye width */
375     int eye_width = 0;
376     for (int y = 0; y < eye->height; y++)
377     {
378         int width = 0;
379         for (int x = 0; x < eye->width; x++)
380         {
381             if (eye->data[y][x] == 0)
382             {
383                 width++;
384             }
385         }
386         if (width > eye_width)
387             eye_width = width;
388     }
389 
390     /* Calculate the max eye height */
391     int eye_height = 0;
392     for (int x = 0; x < eye->width; x++)
393     {
394         int height = 0;
395         for (int y = 0; y < eye->height; y++)
396         {
397             if (eye->data[y][x] == 0)
398             {
399                 height++;
400             }
401         }
402         if (height > eye_height)
403             eye_height = height;
404     }
405 
406     printf("\nEye Diagram for Node %d, QLM %d, Lane %d\n", node, qlm, qlm_lane);
407 
408     if (format == 0) /* Raw */
409     {
410         for (int y = 0; y < eye->height; y++)
411         {
412             for (int x = 0; x < eye->width; x++)
413                 printf("%u\t", eye->data[y][x]);
414             printf("\n");
415         }
416         result = 0;
417     }
418     else
419         result = -1;
420 
421     if (need_free)
422         free((void*)eye);
423     return result;
424 }
425