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