blob: c6c7c13483f44ab69b86e74b67b503b5ab755dd8 [file] [log] [blame]
Stefan Roese5fef24c2020-06-30 12:08:58 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020 Stefan Roese <sr@denx.de>
4 */
5
Stefan Roese63051d62020-09-02 08:29:10 +02006#include <dm.h>
Aaron Williamsf9fa8b82020-12-11 17:06:10 +01007#include <fdt_support.h>
Stefan Roese63051d62020-09-02 08:29:10 +02008#include <ram.h>
Aaron Williamsf9fa8b82020-12-11 17:06:10 +01009#include <asm/gpio.h>
Stefan Roese63051d62020-09-02 08:29:10 +020010
11#include <mach/octeon_ddr.h>
Aaron Williamsf9fa8b82020-12-11 17:06:10 +010012#include <mach/cvmx-qlm.h>
13#include <mach/octeon_qlm.h>
14#include <mach/octeon_fdt.h>
15#include <mach/cvmx-helper.h>
16#include <mach/cvmx-helper-cfg.h>
17#include <mach/cvmx-helper-util.h>
18#include <mach/cvmx-bgxx-defs.h>
Stefan Roese63051d62020-09-02 08:29:10 +020019
20#include "board_ddr.h"
21
Aaron Williamsf9fa8b82020-12-11 17:06:10 +010022#define MAX_MIX_ENV_VARS 4
23
Stefan Roese63051d62020-09-02 08:29:10 +020024#define EBB7304_DEF_DRAM_FREQ 800
25
26static struct ddr_conf board_ddr_conf[] = {
Aaron Williamsf9fa8b82020-12-11 17:06:10 +010027 OCTEON_EBB7304_DDR_CONFIGURATION
Stefan Roese63051d62020-09-02 08:29:10 +020028};
29
Aaron Williamsf9fa8b82020-12-11 17:06:10 +010030static int no_phy[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
31
Stefan Roese63051d62020-09-02 08:29:10 +020032struct ddr_conf *octeon_ddr_conf_table_get(int *count, int *def_ddr_freq)
33{
34 *count = ARRAY_SIZE(board_ddr_conf);
35 *def_ddr_freq = EBB7304_DEF_DRAM_FREQ;
36
37 return board_ddr_conf;
38}
Aaron Williamsf9fa8b82020-12-11 17:06:10 +010039
40/*
41 * parse_env_var: Parse the environment variable ("bgx_for_mix%d") to
42 * extract the lmac it is set to.
43 *
44 * index: Index of environment variable to parse.
45 * environment variable.
46 * env_bgx: Updated with the bgx of the lmac in the environment
47 * variable.
48 * env_lmac: Updated with the index of lmac in the environment
49 * variable.
50 *
51 * returns: Zero on success, error otherwise.
52 */
53static int parse_env_var(int index, int *env_bgx, int *env_lmac)
54{
55 char env_var[20];
56 ulong xipd_port;
57
58 sprintf(env_var, "bgx_for_mix%d", index);
59 xipd_port = env_get_ulong(env_var, 0, 0xffff);
60 if (xipd_port != 0xffff) {
61 int xiface;
62 struct cvmx_xiface xi;
63 struct cvmx_xport xp;
64
65 /*
66 * The environemt variable is set to the xipd port. Convert the
67 * xipd port to numa node, bgx, and lmac.
68 */
69 xiface = cvmx_helper_get_interface_num(xipd_port);
70 xi = cvmx_helper_xiface_to_node_interface(xiface);
71 xp = cvmx_helper_ipd_port_to_xport(xipd_port);
72 *env_bgx = xi.interface;
73 *env_lmac = cvmx_helper_get_interface_index_num(xp.port);
74 return 0;
75 }
76
77 return -1;
78}
79
80/*
81 * get_lmac_fdt_node: Search the device tree for the node corresponding to
82 * a given bgx lmac.
83 *
84 * fdt: Pointer to flat device tree
85 * search_node: Numa node of the lmac to search for.
86 * search_bgx: Bgx of the lmac to search for.
87 * search_lmac: Lmac index to search for.
88 * compat: Compatible string to search for.
89
90 * returns: The device tree node of the lmac if found,
91 * or -1 otherwise.
92 */
93static int get_lmac_fdt_node(const void *fdt, int search_node, int search_bgx, int search_lmac,
94 const char *compat)
95{
96 int node;
97 const fdt32_t *reg;
98 u64 addr;
99 int fdt_node = -1;
100 int fdt_bgx = -1;
101 int fdt_lmac = -1;
102 int len;
103 int parent;
104
105 /* Iterate through all bgx ports */
106 node = -1;
107 while ((node = fdt_node_offset_by_compatible((void *)fdt, node,
108 compat)) >= 0) {
109 /* Get the node and bgx from the physical address */
110 parent = fdt_parent_offset(fdt, node);
111 reg = fdt_getprop(fdt, parent, "reg", &len);
112 if (parent < 0 || !reg)
113 continue;
114
115 addr = fdt_translate_address((void *)fdt, parent, reg);
116 fdt_node = (addr >> 36) & 0x7;
117 fdt_bgx = (addr >> 24) & 0xf;
118
119 /* Get the lmac index from the reg property */
120 reg = fdt_getprop(fdt, node, "reg", &len);
121 if (reg)
122 fdt_lmac = *reg;
123
124 /* Check for a match */
125 if (search_node == fdt_node && search_bgx == fdt_bgx &&
126 search_lmac == fdt_lmac)
127 return node;
128 }
129
130 return -1;
131}
132
133/*
134 * get_mix_fdt_node: Search the device tree for the node corresponding to
135 * a given mix.
136 *
137 * fdt: Pointer to flat device tree
138 * search_node: Mix numa node to search for.
139 * search_index: Mix index to search for.
140 *
141 * returns: The device tree node of the lmac if found,
142 * or -1 otherwise.
143 */
144static int get_mix_fdt_node(const void *fdt, int search_node, int search_index)
145{
146 int node;
147
148 /* Iterate through all the mix fdt nodes */
149 node = -1;
150 while ((node = fdt_node_offset_by_compatible((void *)fdt, node,
151 "cavium,octeon-7890-mix")) >= 0) {
152 int parent;
153 int len;
154 const char *name;
155 int mix_numa_node;
156 const fdt32_t *reg;
157 int mix_index = -1;
158 u64 addr;
159
160 /* Get the numa node of the mix from the parent node name */
161 parent = fdt_parent_offset(fdt, node);
162 if (parent < 0 ||
163 ((name = fdt_get_name(fdt, parent, &len)) == NULL) ||
164 ((name = strchr(name, '@')) == NULL))
165 continue;
166
167 name++;
168 mix_numa_node = simple_strtol(name, NULL, 0) ? 1 : 0;
169
170 /* Get the mix index from the reg property */
171 reg = fdt_getprop(fdt, node, "reg", &len);
172 if (reg) {
173 addr = fdt_translate_address((void *)fdt, parent, reg);
174 mix_index = (addr >> 11) & 1;
175 }
176
177 /* Check for a match */
178 if (mix_numa_node == search_node && mix_index == search_index)
179 return node;
180 }
181
182 return -1;
183}
184
185/*
186 * fdt_fix_mix: Fix the mix nodes in the device tree. Only the mix nodes
187 * configured by the user will be preserved. All other mix
188 * nodes will be trimmed.
189 *
190 * fdt: Pointer to flat device tree
191 *
192 * returns: Zero on success, error otherwise.
193 */
194static int fdt_fix_mix(const void *fdt)
195{
196 int node;
197 int next_node;
198 int len;
199 int i;
200
201 /* Parse all the mix port environment variables */
202 for (i = 0; i < MAX_MIX_ENV_VARS; i++) {
203 int env_node = 0;
204 int env_bgx = -1;
205 int env_lmac = -1;
206 int lmac_fdt_node = -1;
207 int mix_fdt_node = -1;
Marek Behún68a2faa2021-11-26 14:57:06 +0100208 unsigned int lmac_phandle;
Aaron Williamsf9fa8b82020-12-11 17:06:10 +0100209 char *compat;
210
211 /* Get the lmac for this environment variable */
212 if (parse_env_var(i, &env_bgx, &env_lmac))
213 continue;
214
215 /* Get the fdt node for this lmac and add a phandle to it */
216 compat = "cavium,octeon-7890-bgx-port";
217 lmac_fdt_node = get_lmac_fdt_node(fdt, env_node, env_bgx,
218 env_lmac, compat);
219 if (lmac_fdt_node < 0) {
220 /* Must check for the xcv compatible string too */
221 compat = "cavium,octeon-7360-xcv";
222 lmac_fdt_node = get_lmac_fdt_node(fdt, env_node,
223 env_bgx, env_lmac,
224 compat);
225 if (lmac_fdt_node < 0) {
226 printf("WARNING: Failed to get lmac fdt node for %d%d%d\n",
227 env_node, env_bgx, env_lmac);
228 continue;
229 }
230 }
231
Marek Behún68a2faa2021-11-26 14:57:06 +0100232 lmac_phandle = fdt_create_phandle((void *)fdt, lmac_fdt_node);
Aaron Williamsf9fa8b82020-12-11 17:06:10 +0100233
234 /* Get the fdt mix node corresponding to this lmac */
235 mix_fdt_node = get_mix_fdt_node(fdt, env_node, env_lmac);
236 if (mix_fdt_node < 0)
237 continue;
238
239 /* Point the mix to the lmac */
240 fdt_getprop(fdt, mix_fdt_node, "cavium,mac-handle", &len);
241 fdt_setprop_inplace((void *)fdt, mix_fdt_node,
242 "cavium,mac-handle", &lmac_phandle, len);
243 }
244
245 /* Trim unused mix'es from the device tree */
246 for (node = fdt_next_node(fdt, -1, NULL); node >= 0; node = next_node) {
247 const char *compat;
248 const fdt32_t *reg;
249
250 next_node = fdt_next_node(fdt, node, NULL);
251
252 compat = fdt_getprop(fdt, node, "compatible", &len);
253 if (compat) {
254 if (strcmp(compat, "cavium,octeon-7890-mix"))
255 continue;
256
257 reg = fdt_getprop(fdt, node, "cavium,mac-handle", &len);
258 if (reg) {
259 if (*reg == 0xffff)
260 fdt_nop_node((void *)fdt, node);
261 }
262 }
263 }
264
265 return 0;
266}
267
268static void kill_fdt_phy(void *fdt, int offset, void *arg)
269{
270 int len, phy_offset;
271 const fdt32_t *php;
272 u32 phandle;
273
274 php = fdt_getprop(fdt, offset, "phy-handle", &len);
275 if (php && len == sizeof(*php)) {
276 phandle = fdt32_to_cpu(*php);
277 fdt_nop_property(fdt, offset, "phy-handle");
278 phy_offset = fdt_node_offset_by_phandle(fdt, phandle);
279 if (phy_offset > 0)
280 fdt_nop_node(fdt, phy_offset);
281 }
282}
283
284void __fixup_xcv(void)
285{
286 unsigned long bgx = env_get_ulong("bgx_for_rgmii", 10,
287 (unsigned long)-1);
288 char fdt_key[16];
289 int i;
290
291 debug("%s: BGX %d\n", __func__, (int)bgx);
292
293 for (i = 0; i < 3; i++) {
294 snprintf(fdt_key, sizeof(fdt_key),
295 bgx == i ? "%d,xcv" : "%d,not-xcv", i);
296 debug("%s: trimming bgx %lu with key %s\n",
297 __func__, bgx, fdt_key);
298
299 octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key,
300 "cavium,xcv-trim", true, NULL, NULL);
301 }
302}
303
304/* QLM0 - QLM6 */
305void __fixup_fdt(void)
306{
307 int qlm;
308 int speed = 0;
309
310 for (qlm = 0; qlm < 7; qlm++) {
311 enum cvmx_qlm_mode mode;
312 char fdt_key[16];
313 const char *type_str = "none";
314
315 mode = cvmx_qlm_get_mode(qlm);
316 switch (mode) {
317 case CVMX_QLM_MODE_SGMII:
318 case CVMX_QLM_MODE_RGMII_SGMII:
319 case CVMX_QLM_MODE_RGMII_SGMII_1X1:
320 type_str = "sgmii";
321 break;
322 case CVMX_QLM_MODE_XAUI:
323 case CVMX_QLM_MODE_RGMII_XAUI:
324 speed = (cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10) * 4;
325 if (speed == 10000)
326 type_str = "xaui";
327 else
328 type_str = "dxaui";
329 break;
330 case CVMX_QLM_MODE_RXAUI:
331 case CVMX_QLM_MODE_RGMII_RXAUI:
332 type_str = "rxaui";
333 break;
334 case CVMX_QLM_MODE_XLAUI:
335 case CVMX_QLM_MODE_RGMII_XLAUI:
336 type_str = "xlaui";
337 break;
338 case CVMX_QLM_MODE_XFI:
339 case CVMX_QLM_MODE_RGMII_XFI:
340 case CVMX_QLM_MODE_RGMII_XFI_1X1:
Vladimir Oltean77b11f72021-09-18 15:32:34 +0300341 type_str = "10gbase-r";
Aaron Williamsf9fa8b82020-12-11 17:06:10 +0100342 break;
343 case CVMX_QLM_MODE_10G_KR:
344 case CVMX_QLM_MODE_RGMII_10G_KR:
345 type_str = "10G_KR";
346 break;
347 case CVMX_QLM_MODE_40G_KR4:
348 case CVMX_QLM_MODE_RGMII_40G_KR4:
349 type_str = "40G_KR4";
350 break;
351 case CVMX_QLM_MODE_SATA_2X1:
352 type_str = "sata";
353 break;
354 case CVMX_QLM_MODE_SGMII_2X1:
355 case CVMX_QLM_MODE_XFI_1X2:
356 case CVMX_QLM_MODE_10G_KR_1X2:
357 case CVMX_QLM_MODE_RXAUI_1X2:
358 case CVMX_QLM_MODE_MIXED: // special for DLM5 & DLM6
359 {
360 cvmx_bgxx_cmrx_config_t cmr_config;
361 cvmx_bgxx_spux_br_pmd_control_t pmd_control;
362 int mux = cvmx_qlm_mux_interface(2);
363
364 if (mux == 2) { // only dlm6
365 cmr_config.u64 = csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2));
366 pmd_control.u64 =
367 csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2));
368 } else {
369 if (qlm == 5) {
370 cmr_config.u64 =
371 csr_rd(CVMX_BGXX_CMRX_CONFIG(0, 2));
372 pmd_control.u64 =
373 csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(0, 2));
374 } else {
375 cmr_config.u64 =
376 csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2));
377 pmd_control.u64 =
378 csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2));
379 }
380 }
381 switch (cmr_config.s.lmac_type) {
382 case 0:
383 type_str = "sgmii";
384 break;
385 case 1:
386 type_str = "xaui";
387 break;
388 case 2:
389 type_str = "rxaui";
390 break;
391 case 3:
392 if (pmd_control.s.train_en)
393 type_str = "10G_KR";
394 else
Vladimir Oltean77b11f72021-09-18 15:32:34 +0300395 type_str = "10gbase-r";
Aaron Williamsf9fa8b82020-12-11 17:06:10 +0100396 break;
397 case 4:
398 if (pmd_control.s.train_en)
399 type_str = "40G_KR4";
400 else
401 type_str = "xlaui";
402 break;
403 default:
404 type_str = "none";
405 break;
406 }
407 break;
408 }
409 default:
410 type_str = "none";
411 break;
412 }
413 sprintf(fdt_key, "%d,%s", qlm, type_str);
414 debug("Patching qlm %d for %s for mode %d%s\n", qlm, fdt_key, mode,
415 no_phy[qlm] ? ", removing PHY" : "");
416 octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key, NULL, true,
417 no_phy[qlm] ? kill_fdt_phy : NULL, NULL);
418 }
419}
420
421int board_fix_fdt(void)
422{
423 __fixup_fdt();
424 __fixup_xcv();
425
426 /* Fix the mix ports */
427 fdt_fix_mix(gd->fdt_blob);
428
429 return 0;
430}
431
432/*
433 * Here is the description of the parameters that are passed to QLM
434 * configuration:
435 *
436 * param0 : The QLM to configure
437 * param1 : Speed to configure the QLM at
438 * param2 : Mode the QLM to configure
439 * param3 : 1 = RC, 0 = EP
440 * param4 : 0 = GEN1, 1 = GEN2, 2 = GEN3
441 * param5 : ref clock select, 0 = 100Mhz, 1 = 125MHz, 2 = 156MHz
442 * param6 : ref clock input to use:
443 * 0 - external reference (QLMx_REF_CLK)
444 * 1 = common clock 0 (QLMC_REF_CLK0)
445 * 2 = common_clock 1 (QLMC_REF_CLK1)
446 */
447static void board_configure_qlms(void)
448{
449 int speed[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
450 int mode[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
451 int pcie_rc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
452 int pcie_gen[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
453 int ref_clock_sel[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
454 int ref_clock_input[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
455 struct gpio_desc desc;
456 int rbgx, rqlm;
457 char env_var[16];
458 int qlm;
459 int ret;
460
461 /* RGMII PHY reset GPIO */
462 ret = dm_gpio_lookup_name("gpio-controllerA27", &desc);
463 if (ret)
464 debug("gpio ret=%d\n", ret);
465 ret = dm_gpio_request(&desc, "rgmii_phy_reset");
466 if (ret)
467 debug("gpio_request ret=%d\n", ret);
468 ret = dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
469 if (ret)
470 debug("gpio dir ret=%d\n", ret);
471
472 /* Put RGMII PHY in reset */
473 dm_gpio_set_value(&desc, 0);
474
475 octeon_init_qlm(0);
476
477 rbgx = env_get_ulong("bgx_for_rgmii", 10, (unsigned long)-1);
478 switch (rbgx) {
479 case 0:
480 rqlm = 2;
481 break;
482 case 1:
483 rqlm = 3;
484 break;
485 case 2:
486 rqlm = 5;
487 break;
488 default:
489 rqlm = -1;
490 break;
491 }
492
493 for (qlm = 0; qlm < 7; qlm++) {
494 const char *mode_str;
495 char spd_env[16];
496
497 mode[qlm] = CVMX_QLM_MODE_DISABLED;
498 sprintf(env_var, "qlm%d_mode", qlm);
499 mode_str = env_get(env_var);
500 if (!mode_str)
501 continue;
502
503 if (qlm == 4 && mode[4] != -1 &&
504 mode[4] != CVMX_QLM_MODE_SATA_2X1) {
505 printf("Error: DLM 4 can only be configured for SATA\n");
506 continue;
507 }
508
509 if (strstr(mode_str, ",no_phy"))
510 no_phy[qlm] = 1;
511
512 if (!strncmp(mode_str, "sgmii", 5)) {
513 bool rgmii = false;
514
515 speed[qlm] = 1250;
516 if (rqlm == qlm && qlm < 5) {
517 mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII;
518 rgmii = true;
519 } else if (qlm == 6 || qlm == 5) {
520 if (rqlm == qlm && qlm == 5) {
521 mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_1X1;
522 rgmii = true;
523 } else if (rqlm == 5 && qlm == 6 &&
524 mode[5] != CVMX_QLM_MODE_RGMII_SGMII_1X1) {
525 mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_2X1;
526 rgmii = true;
527 } else {
528 mode[qlm] = CVMX_QLM_MODE_SGMII_2X1;
529 }
530 } else {
531 mode[qlm] = CVMX_QLM_MODE_SGMII;
532 }
533 ref_clock_sel[qlm] = 2;
534
535 if (qlm == 5 || qlm == 6)
536 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
537
538 if (no_phy[qlm]) {
539 int i;
540 int start = 0, stop = 2;
541
542 rbgx = 0;
543 switch (qlm) {
544 case 3:
545 rbgx = 1;
546 case 2:
547 for (i = 0; i < 4; i++) {
548 printf("Ignoring PHY for interface: %d, port: %d\n",
549 rbgx, i);
550 cvmx_helper_set_port_force_link_up(rbgx, i, true);
551 }
552 break;
553 case 6:
554 start = 2;
555 stop = 4;
556 case 5:
557 for (i = start; i < stop; i++) {
558 printf("Ignoring PHY for interface: %d, port: %d\n",
559 2, i);
560 cvmx_helper_set_port_force_link_up(2, i, true);
561 }
562 break;
563 default:
564 printf("SGMII not supported for QLM/DLM %d\n",
565 qlm);
566 break;
567 }
568 }
569 printf("QLM %d: SGMII%s\n",
570 qlm, rgmii ? ", RGMII" : "");
571 } else if (!strncmp(mode_str, "xaui", 4)) {
572 speed[qlm] = 3125;
573 mode[qlm] = CVMX_QLM_MODE_XAUI;
574 ref_clock_sel[qlm] = 2;
575 if (qlm == 5 || qlm == 6)
576 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
577 printf("QLM %d: XAUI\n", qlm);
578 } else if (!strncmp(mode_str, "dxaui", 5)) {
579 speed[qlm] = 6250;
580 mode[qlm] = CVMX_QLM_MODE_XAUI;
581 ref_clock_sel[qlm] = 2;
582 if (qlm == 5 || qlm == 6)
583 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
584 printf("QLM %d: DXAUI\n", qlm);
585 } else if (!strncmp(mode_str, "rxaui", 5)) {
586 bool rgmii = false;
587
588 speed[qlm] = 6250;
589 if (qlm == 5 || qlm == 6) {
590 if (rqlm == qlm && qlm == 5) {
591 mode[qlm] = CVMX_QLM_MODE_RGMII_RXAUI;
592 rgmii = true;
593 } else {
594 mode[qlm] = CVMX_QLM_MODE_RXAUI_1X2;
595 }
596 } else {
597 mode[qlm] = CVMX_QLM_MODE_RXAUI;
598 }
599 ref_clock_sel[qlm] = 2;
600 if (qlm == 5 || qlm == 6)
601 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
602 printf("QLM %d: RXAUI%s\n",
603 qlm, rgmii ? ", rgmii" : "");
604 } else if (!strncmp(mode_str, "xlaui", 5)) {
605 speed[qlm] = 103125;
606 mode[qlm] = CVMX_QLM_MODE_XLAUI;
607 ref_clock_sel[qlm] = 2;
608 if (qlm == 5 || qlm == 6)
609 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
610 sprintf(spd_env, "qlm%d_speed", qlm);
611 if (env_get(spd_env)) {
612 int spd = env_get_ulong(spd_env, 0, 8);
613
614 if (spd)
615 speed[qlm] = spd;
616 else
617 speed[qlm] = 103125;
618 }
619 printf("QLM %d: XLAUI\n", qlm);
Vladimir Oltean77b11f72021-09-18 15:32:34 +0300620 } else if (!strncmp(mode_str, "10gbase-r", 3)) {
Aaron Williamsf9fa8b82020-12-11 17:06:10 +0100621 bool rgmii = false;
622
623 speed[qlm] = 103125;
624 if (rqlm == qlm) {
625 mode[qlm] = CVMX_QLM_MODE_RGMII_XFI;
626 rgmii = true;
627 } else if (qlm == 5 || qlm == 6) {
628 mode[qlm] = CVMX_QLM_MODE_XFI_1X2;
629 } else {
630 mode[qlm] = CVMX_QLM_MODE_XFI;
631 }
632 ref_clock_sel[qlm] = 2;
633 if (qlm == 5 || qlm == 6)
634 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
635 printf("QLM %d: XFI%s\n", qlm, rgmii ? ", RGMII" : "");
636 } else if (!strncmp(mode_str, "10G_KR", 6)) {
637 speed[qlm] = 103125;
638 if (rqlm == qlm && qlm == 5)
639 mode[qlm] = CVMX_QLM_MODE_RGMII_10G_KR;
640 else if (qlm == 5 || qlm == 6)
641 mode[qlm] = CVMX_QLM_MODE_10G_KR_1X2;
642 else
643 mode[qlm] = CVMX_QLM_MODE_10G_KR;
644 ref_clock_sel[qlm] = 2;
645 if (qlm == 5 || qlm == 6)
646 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
647 printf("QLM %d: 10G_KR\n", qlm);
648 } else if (!strncmp(mode_str, "40G_KR4", 7)) {
649 speed[qlm] = 103125;
650 mode[qlm] = CVMX_QLM_MODE_40G_KR4;
651 ref_clock_sel[qlm] = 2;
652 if (qlm == 5 || qlm == 6)
653 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
654 printf("QLM %d: 40G_KR4\n", qlm);
655 } else if (!strcmp(mode_str, "pcie")) {
656 char *pmode;
657 int lanes = 0;
658
659 sprintf(env_var, "pcie%d_mode", qlm);
660 pmode = env_get(env_var);
661 if (pmode && !strcmp(pmode, "ep"))
662 pcie_rc[qlm] = 0;
663 else
664 pcie_rc[qlm] = 1;
665 sprintf(env_var, "pcie%d_gen", qlm);
666 pcie_gen[qlm] = env_get_ulong(env_var, 0, 3);
667 sprintf(env_var, "pcie%d_lanes", qlm);
668 lanes = env_get_ulong(env_var, 0, 8);
669 if (lanes == 8) {
670 mode[qlm] = CVMX_QLM_MODE_PCIE_1X8;
671 } else if (qlm == 5 || qlm == 6) {
672 if (lanes != 2) {
673 printf("QLM%d: Invalid lanes selected, defaulting to 2 lanes\n",
674 qlm);
675 }
676 mode[qlm] = CVMX_QLM_MODE_PCIE_1X2;
677 ref_clock_input[qlm] = 1; // use QLMC_REF_CLK0
678 } else {
679 mode[qlm] = CVMX_QLM_MODE_PCIE;
680 }
681 ref_clock_sel[qlm] = 0;
682 printf("QLM %d: PCIe gen%d %s, x%d lanes\n",
683 qlm, pcie_gen[qlm] + 1,
684 pcie_rc[qlm] ? "root complex" : "endpoint",
685 lanes);
686 } else if (!strcmp(mode_str, "sata")) {
687 mode[qlm] = CVMX_QLM_MODE_SATA_2X1;
688 ref_clock_sel[qlm] = 0;
689 ref_clock_input[qlm] = 1;
690 sprintf(spd_env, "qlm%d_speed", qlm);
691 if (env_get(spd_env)) {
692 int spd = env_get_ulong(spd_env, 0, 8);
693
694 if (spd == 1500 || spd == 3000 || spd == 3000)
695 speed[qlm] = spd;
696 else
697 speed[qlm] = 6000;
698 } else {
699 speed[qlm] = 6000;
700 }
701 } else {
702 printf("QLM %d: disabled\n", qlm);
703 }
704 }
705
706 for (qlm = 0; qlm < 7; qlm++) {
707 int rc;
708
709 if (mode[qlm] == -1)
710 continue;
711
712 debug("Configuring qlm%d with speed(%d), mode(%d), RC(%d), Gen(%d), REF_CLK(%d), CLK_SOURCE(%d)\n",
713 qlm, speed[qlm], mode[qlm], pcie_rc[qlm],
714 pcie_gen[qlm] + 1,
715 ref_clock_sel[qlm], ref_clock_input[qlm]);
716 rc = octeon_configure_qlm(qlm, speed[qlm], mode[qlm],
717 pcie_rc[qlm], pcie_gen[qlm],
718 ref_clock_sel[qlm],
719 ref_clock_input[qlm]);
720
721 if (speed[qlm] == 6250) {
722 if (mode[qlm] == CVMX_QLM_MODE_RXAUI) {
723 octeon_qlm_tune_v3(0, qlm, speed[qlm], 0x12,
724 0xa0, -1, -1);
725 } else {
726 octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xa,
727 0xa0, -1, -1);
728 }
729 } else if (speed[qlm] == 103125) {
730 octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xd, 0xd0,
731 -1, -1);
732 }
733
734 if (qlm == 4 && rc != 0)
735 /*
736 * There is a bug with SATA with 73xx. Until it's
737 * fixed we need to strip it from the device tree.
738 */
739 octeon_fdt_patch_rename((void *)gd->fdt_blob, "4,none",
740 NULL, true, NULL, NULL);
741 }
742
743 dm_gpio_set_value(&desc, 0); /* Put RGMII PHY in reset */
744 mdelay(10);
745 dm_gpio_set_value(&desc, 1); /* Take RGMII PHY out of reset */
746}
747
748int board_late_init(void)
749{
750 board_configure_qlms();
751
752 return 0;
753}