1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2020 Stefan Roese <sr@denx.de>
4 */
5
6 #include <dm.h>
7 #include <fdt_support.h>
8 #include <ram.h>
9 #include <asm/gpio.h>
10
11 #include <mach/octeon_ddr.h>
12 #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>
19
20 #include "board_ddr.h"
21
22 #define MAX_MIX_ENV_VARS 4
23
24 #define EBB7304_DEF_DRAM_FREQ 800
25
26 static struct ddr_conf board_ddr_conf[] = {
27 OCTEON_EBB7304_DDR_CONFIGURATION
28 };
29
30 static int no_phy[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
31
octeon_ddr_conf_table_get(int * count,int * def_ddr_freq)32 struct 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 }
39
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 */
parse_env_var(int index,int * env_bgx,int * env_lmac)53 static 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 */
get_lmac_fdt_node(const void * fdt,int search_node,int search_bgx,int search_lmac,const char * compat)93 static 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 */
get_mix_fdt_node(const void * fdt,int search_node,int search_index)144 static 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 */
fdt_fix_mix(const void * fdt)194 static 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;
208 int lmac_phandle;
209 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
232 lmac_phandle = fdt_alloc_phandle((void *)fdt);
233 fdt_set_phandle((void *)fdt, lmac_fdt_node, lmac_phandle);
234
235 /* Get the fdt mix node corresponding to this lmac */
236 mix_fdt_node = get_mix_fdt_node(fdt, env_node, env_lmac);
237 if (mix_fdt_node < 0)
238 continue;
239
240 /* Point the mix to the lmac */
241 fdt_getprop(fdt, mix_fdt_node, "cavium,mac-handle", &len);
242 fdt_setprop_inplace((void *)fdt, mix_fdt_node,
243 "cavium,mac-handle", &lmac_phandle, len);
244 }
245
246 /* Trim unused mix'es from the device tree */
247 for (node = fdt_next_node(fdt, -1, NULL); node >= 0; node = next_node) {
248 const char *compat;
249 const fdt32_t *reg;
250
251 next_node = fdt_next_node(fdt, node, NULL);
252
253 compat = fdt_getprop(fdt, node, "compatible", &len);
254 if (compat) {
255 if (strcmp(compat, "cavium,octeon-7890-mix"))
256 continue;
257
258 reg = fdt_getprop(fdt, node, "cavium,mac-handle", &len);
259 if (reg) {
260 if (*reg == 0xffff)
261 fdt_nop_node((void *)fdt, node);
262 }
263 }
264 }
265
266 return 0;
267 }
268
kill_fdt_phy(void * fdt,int offset,void * arg)269 static void kill_fdt_phy(void *fdt, int offset, void *arg)
270 {
271 int len, phy_offset;
272 const fdt32_t *php;
273 u32 phandle;
274
275 php = fdt_getprop(fdt, offset, "phy-handle", &len);
276 if (php && len == sizeof(*php)) {
277 phandle = fdt32_to_cpu(*php);
278 fdt_nop_property(fdt, offset, "phy-handle");
279 phy_offset = fdt_node_offset_by_phandle(fdt, phandle);
280 if (phy_offset > 0)
281 fdt_nop_node(fdt, phy_offset);
282 }
283 }
284
__fixup_xcv(void)285 void __fixup_xcv(void)
286 {
287 unsigned long bgx = env_get_ulong("bgx_for_rgmii", 10,
288 (unsigned long)-1);
289 char fdt_key[16];
290 int i;
291
292 debug("%s: BGX %d\n", __func__, (int)bgx);
293
294 for (i = 0; i < 3; i++) {
295 snprintf(fdt_key, sizeof(fdt_key),
296 bgx == i ? "%d,xcv" : "%d,not-xcv", i);
297 debug("%s: trimming bgx %lu with key %s\n",
298 __func__, bgx, fdt_key);
299
300 octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key,
301 "cavium,xcv-trim", true, NULL, NULL);
302 }
303 }
304
305 /* QLM0 - QLM6 */
__fixup_fdt(void)306 void __fixup_fdt(void)
307 {
308 int qlm;
309 int speed = 0;
310
311 for (qlm = 0; qlm < 7; qlm++) {
312 enum cvmx_qlm_mode mode;
313 char fdt_key[16];
314 const char *type_str = "none";
315
316 mode = cvmx_qlm_get_mode(qlm);
317 switch (mode) {
318 case CVMX_QLM_MODE_SGMII:
319 case CVMX_QLM_MODE_RGMII_SGMII:
320 case CVMX_QLM_MODE_RGMII_SGMII_1X1:
321 type_str = "sgmii";
322 break;
323 case CVMX_QLM_MODE_XAUI:
324 case CVMX_QLM_MODE_RGMII_XAUI:
325 speed = (cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10) * 4;
326 if (speed == 10000)
327 type_str = "xaui";
328 else
329 type_str = "dxaui";
330 break;
331 case CVMX_QLM_MODE_RXAUI:
332 case CVMX_QLM_MODE_RGMII_RXAUI:
333 type_str = "rxaui";
334 break;
335 case CVMX_QLM_MODE_XLAUI:
336 case CVMX_QLM_MODE_RGMII_XLAUI:
337 type_str = "xlaui";
338 break;
339 case CVMX_QLM_MODE_XFI:
340 case CVMX_QLM_MODE_RGMII_XFI:
341 case CVMX_QLM_MODE_RGMII_XFI_1X1:
342 type_str = "xfi";
343 break;
344 case CVMX_QLM_MODE_10G_KR:
345 case CVMX_QLM_MODE_RGMII_10G_KR:
346 type_str = "10G_KR";
347 break;
348 case CVMX_QLM_MODE_40G_KR4:
349 case CVMX_QLM_MODE_RGMII_40G_KR4:
350 type_str = "40G_KR4";
351 break;
352 case CVMX_QLM_MODE_SATA_2X1:
353 type_str = "sata";
354 break;
355 case CVMX_QLM_MODE_SGMII_2X1:
356 case CVMX_QLM_MODE_XFI_1X2:
357 case CVMX_QLM_MODE_10G_KR_1X2:
358 case CVMX_QLM_MODE_RXAUI_1X2:
359 case CVMX_QLM_MODE_MIXED: // special for DLM5 & DLM6
360 {
361 cvmx_bgxx_cmrx_config_t cmr_config;
362 cvmx_bgxx_spux_br_pmd_control_t pmd_control;
363 int mux = cvmx_qlm_mux_interface(2);
364
365 if (mux == 2) { // only dlm6
366 cmr_config.u64 = csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2));
367 pmd_control.u64 =
368 csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2));
369 } else {
370 if (qlm == 5) {
371 cmr_config.u64 =
372 csr_rd(CVMX_BGXX_CMRX_CONFIG(0, 2));
373 pmd_control.u64 =
374 csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(0, 2));
375 } else {
376 cmr_config.u64 =
377 csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2));
378 pmd_control.u64 =
379 csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2));
380 }
381 }
382 switch (cmr_config.s.lmac_type) {
383 case 0:
384 type_str = "sgmii";
385 break;
386 case 1:
387 type_str = "xaui";
388 break;
389 case 2:
390 type_str = "rxaui";
391 break;
392 case 3:
393 if (pmd_control.s.train_en)
394 type_str = "10G_KR";
395 else
396 type_str = "xfi";
397 break;
398 case 4:
399 if (pmd_control.s.train_en)
400 type_str = "40G_KR4";
401 else
402 type_str = "xlaui";
403 break;
404 default:
405 type_str = "none";
406 break;
407 }
408 break;
409 }
410 default:
411 type_str = "none";
412 break;
413 }
414 sprintf(fdt_key, "%d,%s", qlm, type_str);
415 debug("Patching qlm %d for %s for mode %d%s\n", qlm, fdt_key, mode,
416 no_phy[qlm] ? ", removing PHY" : "");
417 octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key, NULL, true,
418 no_phy[qlm] ? kill_fdt_phy : NULL, NULL);
419 }
420 }
421
board_fix_fdt(void)422 int board_fix_fdt(void)
423 {
424 __fixup_fdt();
425 __fixup_xcv();
426
427 /* Fix the mix ports */
428 fdt_fix_mix(gd->fdt_blob);
429
430 return 0;
431 }
432
433 /*
434 * Here is the description of the parameters that are passed to QLM
435 * configuration:
436 *
437 * param0 : The QLM to configure
438 * param1 : Speed to configure the QLM at
439 * param2 : Mode the QLM to configure
440 * param3 : 1 = RC, 0 = EP
441 * param4 : 0 = GEN1, 1 = GEN2, 2 = GEN3
442 * param5 : ref clock select, 0 = 100Mhz, 1 = 125MHz, 2 = 156MHz
443 * param6 : ref clock input to use:
444 * 0 - external reference (QLMx_REF_CLK)
445 * 1 = common clock 0 (QLMC_REF_CLK0)
446 * 2 = common_clock 1 (QLMC_REF_CLK1)
447 */
board_configure_qlms(void)448 static void board_configure_qlms(void)
449 {
450 int speed[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
451 int mode[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
452 int pcie_rc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
453 int pcie_gen[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
454 int ref_clock_sel[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
455 int ref_clock_input[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
456 struct gpio_desc desc;
457 int rbgx, rqlm;
458 char env_var[16];
459 int qlm;
460 int ret;
461
462 /* RGMII PHY reset GPIO */
463 ret = dm_gpio_lookup_name("gpio-controllerA27", &desc);
464 if (ret)
465 debug("gpio ret=%d\n", ret);
466 ret = dm_gpio_request(&desc, "rgmii_phy_reset");
467 if (ret)
468 debug("gpio_request ret=%d\n", ret);
469 ret = dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
470 if (ret)
471 debug("gpio dir ret=%d\n", ret);
472
473 /* Put RGMII PHY in reset */
474 dm_gpio_set_value(&desc, 0);
475
476 octeon_init_qlm(0);
477
478 rbgx = env_get_ulong("bgx_for_rgmii", 10, (unsigned long)-1);
479 switch (rbgx) {
480 case 0:
481 rqlm = 2;
482 break;
483 case 1:
484 rqlm = 3;
485 break;
486 case 2:
487 rqlm = 5;
488 break;
489 default:
490 rqlm = -1;
491 break;
492 }
493
494 for (qlm = 0; qlm < 7; qlm++) {
495 const char *mode_str;
496 char spd_env[16];
497
498 mode[qlm] = CVMX_QLM_MODE_DISABLED;
499 sprintf(env_var, "qlm%d_mode", qlm);
500 mode_str = env_get(env_var);
501 if (!mode_str)
502 continue;
503
504 if (qlm == 4 && mode[4] != -1 &&
505 mode[4] != CVMX_QLM_MODE_SATA_2X1) {
506 printf("Error: DLM 4 can only be configured for SATA\n");
507 continue;
508 }
509
510 if (strstr(mode_str, ",no_phy"))
511 no_phy[qlm] = 1;
512
513 if (!strncmp(mode_str, "sgmii", 5)) {
514 bool rgmii = false;
515
516 speed[qlm] = 1250;
517 if (rqlm == qlm && qlm < 5) {
518 mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII;
519 rgmii = true;
520 } else if (qlm == 6 || qlm == 5) {
521 if (rqlm == qlm && qlm == 5) {
522 mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_1X1;
523 rgmii = true;
524 } else if (rqlm == 5 && qlm == 6 &&
525 mode[5] != CVMX_QLM_MODE_RGMII_SGMII_1X1) {
526 mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_2X1;
527 rgmii = true;
528 } else {
529 mode[qlm] = CVMX_QLM_MODE_SGMII_2X1;
530 }
531 } else {
532 mode[qlm] = CVMX_QLM_MODE_SGMII;
533 }
534 ref_clock_sel[qlm] = 2;
535
536 if (qlm == 5 || qlm == 6)
537 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
538
539 if (no_phy[qlm]) {
540 int i;
541 int start = 0, stop = 2;
542
543 rbgx = 0;
544 switch (qlm) {
545 case 3:
546 rbgx = 1;
547 case 2:
548 for (i = 0; i < 4; i++) {
549 printf("Ignoring PHY for interface: %d, port: %d\n",
550 rbgx, i);
551 cvmx_helper_set_port_force_link_up(rbgx, i, true);
552 }
553 break;
554 case 6:
555 start = 2;
556 stop = 4;
557 case 5:
558 for (i = start; i < stop; i++) {
559 printf("Ignoring PHY for interface: %d, port: %d\n",
560 2, i);
561 cvmx_helper_set_port_force_link_up(2, i, true);
562 }
563 break;
564 default:
565 printf("SGMII not supported for QLM/DLM %d\n",
566 qlm);
567 break;
568 }
569 }
570 printf("QLM %d: SGMII%s\n",
571 qlm, rgmii ? ", RGMII" : "");
572 } else if (!strncmp(mode_str, "xaui", 4)) {
573 speed[qlm] = 3125;
574 mode[qlm] = CVMX_QLM_MODE_XAUI;
575 ref_clock_sel[qlm] = 2;
576 if (qlm == 5 || qlm == 6)
577 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
578 printf("QLM %d: XAUI\n", qlm);
579 } else if (!strncmp(mode_str, "dxaui", 5)) {
580 speed[qlm] = 6250;
581 mode[qlm] = CVMX_QLM_MODE_XAUI;
582 ref_clock_sel[qlm] = 2;
583 if (qlm == 5 || qlm == 6)
584 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
585 printf("QLM %d: DXAUI\n", qlm);
586 } else if (!strncmp(mode_str, "rxaui", 5)) {
587 bool rgmii = false;
588
589 speed[qlm] = 6250;
590 if (qlm == 5 || qlm == 6) {
591 if (rqlm == qlm && qlm == 5) {
592 mode[qlm] = CVMX_QLM_MODE_RGMII_RXAUI;
593 rgmii = true;
594 } else {
595 mode[qlm] = CVMX_QLM_MODE_RXAUI_1X2;
596 }
597 } else {
598 mode[qlm] = CVMX_QLM_MODE_RXAUI;
599 }
600 ref_clock_sel[qlm] = 2;
601 if (qlm == 5 || qlm == 6)
602 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
603 printf("QLM %d: RXAUI%s\n",
604 qlm, rgmii ? ", rgmii" : "");
605 } else if (!strncmp(mode_str, "xlaui", 5)) {
606 speed[qlm] = 103125;
607 mode[qlm] = CVMX_QLM_MODE_XLAUI;
608 ref_clock_sel[qlm] = 2;
609 if (qlm == 5 || qlm == 6)
610 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
611 sprintf(spd_env, "qlm%d_speed", qlm);
612 if (env_get(spd_env)) {
613 int spd = env_get_ulong(spd_env, 0, 8);
614
615 if (spd)
616 speed[qlm] = spd;
617 else
618 speed[qlm] = 103125;
619 }
620 printf("QLM %d: XLAUI\n", qlm);
621 } else if (!strncmp(mode_str, "xfi", 3)) {
622 bool rgmii = false;
623
624 speed[qlm] = 103125;
625 if (rqlm == qlm) {
626 mode[qlm] = CVMX_QLM_MODE_RGMII_XFI;
627 rgmii = true;
628 } else if (qlm == 5 || qlm == 6) {
629 mode[qlm] = CVMX_QLM_MODE_XFI_1X2;
630 } else {
631 mode[qlm] = CVMX_QLM_MODE_XFI;
632 }
633 ref_clock_sel[qlm] = 2;
634 if (qlm == 5 || qlm == 6)
635 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
636 printf("QLM %d: XFI%s\n", qlm, rgmii ? ", RGMII" : "");
637 } else if (!strncmp(mode_str, "10G_KR", 6)) {
638 speed[qlm] = 103125;
639 if (rqlm == qlm && qlm == 5)
640 mode[qlm] = CVMX_QLM_MODE_RGMII_10G_KR;
641 else if (qlm == 5 || qlm == 6)
642 mode[qlm] = CVMX_QLM_MODE_10G_KR_1X2;
643 else
644 mode[qlm] = CVMX_QLM_MODE_10G_KR;
645 ref_clock_sel[qlm] = 2;
646 if (qlm == 5 || qlm == 6)
647 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
648 printf("QLM %d: 10G_KR\n", qlm);
649 } else if (!strncmp(mode_str, "40G_KR4", 7)) {
650 speed[qlm] = 103125;
651 mode[qlm] = CVMX_QLM_MODE_40G_KR4;
652 ref_clock_sel[qlm] = 2;
653 if (qlm == 5 || qlm == 6)
654 ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
655 printf("QLM %d: 40G_KR4\n", qlm);
656 } else if (!strcmp(mode_str, "pcie")) {
657 char *pmode;
658 int lanes = 0;
659
660 sprintf(env_var, "pcie%d_mode", qlm);
661 pmode = env_get(env_var);
662 if (pmode && !strcmp(pmode, "ep"))
663 pcie_rc[qlm] = 0;
664 else
665 pcie_rc[qlm] = 1;
666 sprintf(env_var, "pcie%d_gen", qlm);
667 pcie_gen[qlm] = env_get_ulong(env_var, 0, 3);
668 sprintf(env_var, "pcie%d_lanes", qlm);
669 lanes = env_get_ulong(env_var, 0, 8);
670 if (lanes == 8) {
671 mode[qlm] = CVMX_QLM_MODE_PCIE_1X8;
672 } else if (qlm == 5 || qlm == 6) {
673 if (lanes != 2) {
674 printf("QLM%d: Invalid lanes selected, defaulting to 2 lanes\n",
675 qlm);
676 }
677 mode[qlm] = CVMX_QLM_MODE_PCIE_1X2;
678 ref_clock_input[qlm] = 1; // use QLMC_REF_CLK0
679 } else {
680 mode[qlm] = CVMX_QLM_MODE_PCIE;
681 }
682 ref_clock_sel[qlm] = 0;
683 printf("QLM %d: PCIe gen%d %s, x%d lanes\n",
684 qlm, pcie_gen[qlm] + 1,
685 pcie_rc[qlm] ? "root complex" : "endpoint",
686 lanes);
687 } else if (!strcmp(mode_str, "sata")) {
688 mode[qlm] = CVMX_QLM_MODE_SATA_2X1;
689 ref_clock_sel[qlm] = 0;
690 ref_clock_input[qlm] = 1;
691 sprintf(spd_env, "qlm%d_speed", qlm);
692 if (env_get(spd_env)) {
693 int spd = env_get_ulong(spd_env, 0, 8);
694
695 if (spd == 1500 || spd == 3000 || spd == 3000)
696 speed[qlm] = spd;
697 else
698 speed[qlm] = 6000;
699 } else {
700 speed[qlm] = 6000;
701 }
702 } else {
703 printf("QLM %d: disabled\n", qlm);
704 }
705 }
706
707 for (qlm = 0; qlm < 7; qlm++) {
708 int rc;
709
710 if (mode[qlm] == -1)
711 continue;
712
713 debug("Configuring qlm%d with speed(%d), mode(%d), RC(%d), Gen(%d), REF_CLK(%d), CLK_SOURCE(%d)\n",
714 qlm, speed[qlm], mode[qlm], pcie_rc[qlm],
715 pcie_gen[qlm] + 1,
716 ref_clock_sel[qlm], ref_clock_input[qlm]);
717 rc = octeon_configure_qlm(qlm, speed[qlm], mode[qlm],
718 pcie_rc[qlm], pcie_gen[qlm],
719 ref_clock_sel[qlm],
720 ref_clock_input[qlm]);
721
722 if (speed[qlm] == 6250) {
723 if (mode[qlm] == CVMX_QLM_MODE_RXAUI) {
724 octeon_qlm_tune_v3(0, qlm, speed[qlm], 0x12,
725 0xa0, -1, -1);
726 } else {
727 octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xa,
728 0xa0, -1, -1);
729 }
730 } else if (speed[qlm] == 103125) {
731 octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xd, 0xd0,
732 -1, -1);
733 }
734
735 if (qlm == 4 && rc != 0)
736 /*
737 * There is a bug with SATA with 73xx. Until it's
738 * fixed we need to strip it from the device tree.
739 */
740 octeon_fdt_patch_rename((void *)gd->fdt_blob, "4,none",
741 NULL, true, NULL, NULL);
742 }
743
744 dm_gpio_set_value(&desc, 0); /* Put RGMII PHY in reset */
745 mdelay(10);
746 dm_gpio_set_value(&desc, 1); /* Take RGMII PHY out of reset */
747 }
748
board_late_init(void)749 int board_late_init(void)
750 {
751 board_configure_qlms();
752
753 return 0;
754 }
755