blob: 52daae6e24dbe1bd98933f5cdc704f05f142cd42 [file] [log] [blame]
Mathew McBridee605fb12022-01-31 18:34:43 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Traverse Ten64 Family board
4 * Copyright 2017-2018 NXP
5 * Copyright 2019-2021 Traverse Technologies
6 */
7#include <common.h>
Simon Glass1ab16922022-07-31 12:28:48 -06008#include <display_options.h>
Mathew McBridee605fb12022-01-31 18:34:43 +05309#include <dm/uclass.h>
10#include <env.h>
11#include <i2c.h>
12#include <init.h>
13#include <log.h>
14#include <malloc.h>
15#include <errno.h>
16#include <misc.h>
17#include <netdev.h>
18#include <fsl_ifc.h>
19#include <fsl_ddr.h>
20#include <fsl_sec.h>
21#include <asm/global_data.h>
22#include <asm/io.h>
23#include <fdt_support.h>
24#include <linux/delay.h>
25#include <linux/libfdt.h>
26#include <fsl-mc/fsl_mc.h>
27#include <env_internal.h>
28#include <asm/arch-fsl-layerscape/soc.h>
29#include <asm/arch/ppa.h>
30#include <hwconfig.h>
31#include <asm/arch/fsl_serdes.h>
32#include <asm/arch/soc.h>
33#include <asm/arch-fsl-layerscape/fsl_icid.h>
Mathew McBride0710b542023-07-21 04:39:24 +000034#include <nvme.h>
Mathew McBridee605fb12022-01-31 18:34:43 +053035
36#include <fsl_immap.h>
37
38#include "../common/ten64-controller.h"
39
40#define I2C_RETIMER_ADDR 0x27
41
42DECLARE_GLOBAL_DATA_PTR;
43
44static int ten64_read_board_info(struct t64uc_board_info *);
45static void ten64_set_macaddrs_from_board_info(struct t64uc_board_info *);
46static void ten64_board_retimer_ds110df410_init(void);
47
48enum {
49 TEN64_BOARD_REV_A = 0xFF,
50 TEN64_BOARD_REV_B = 0xFE,
Mathew McBride2e4a29e2023-07-21 04:39:16 +000051 TEN64_BOARD_REV_C = 0xFD,
52 TEN64_BOARD_REV_D = 0xFC,
53 TEN64_BOARD_MAX
Mathew McBridee605fb12022-01-31 18:34:43 +053054};
55
56#define RESV_MEM_IN_BANK(b) (gd->arch.resv_ram >= base[b] && \
57 gd->arch.resv_ram < base[b] + size[b])
58
59int board_early_init_f(void)
60{
61 fsl_lsch3_early_init_f();
62 return 0;
63}
64
65static u32 ten64_get_board_rev(void)
66{
Tom Rini376b88a2022-10-28 20:27:13 -040067 struct ccsr_gur *dcfg = (void *)CFG_SYS_FSL_GUTS_ADDR;
Mathew McBridee605fb12022-01-31 18:34:43 +053068 u32 board_rev_in = in_le32(&dcfg->gpporcr1);
69 return board_rev_in;
70}
71
72int checkboard(void)
73{
74 enum boot_src src = get_boot_src();
75 char boardmodel[32];
76 struct t64uc_board_info boardinfo;
77 u32 board_rev = ten64_get_board_rev();
78
79 switch (board_rev) {
80 case TEN64_BOARD_REV_A:
Mathew McBride2e4a29e2023-07-21 04:39:16 +000081 snprintf(boardmodel, 32, "A (Alpha)");
Mathew McBridee605fb12022-01-31 18:34:43 +053082 break;
83 case TEN64_BOARD_REV_B:
Mathew McBride2e4a29e2023-07-21 04:39:16 +000084 snprintf(boardmodel, 32, "B (Beta)");
Mathew McBridee605fb12022-01-31 18:34:43 +053085 break;
86 case TEN64_BOARD_REV_C:
Mathew McBride2e4a29e2023-07-21 04:39:16 +000087 snprintf(boardmodel, 32, "C");
88 break;
89 case TEN64_BOARD_REV_D:
90 snprintf(boardmodel, 32, "D");
Mathew McBridee605fb12022-01-31 18:34:43 +053091 break;
92 default:
Mathew McBride2e4a29e2023-07-21 04:39:16 +000093 snprintf(boardmodel, 32, " Revision %X", (0xFF - board_rev));
Mathew McBridee605fb12022-01-31 18:34:43 +053094 break;
95 }
96
Mathew McBride2e4a29e2023-07-21 04:39:16 +000097 printf("Board: 1064-0201%s, boot from ", boardmodel);
98
Mathew McBridee605fb12022-01-31 18:34:43 +053099 if (src == BOOT_SOURCE_SD_MMC)
100 puts("SD card\n");
101 else if (src == BOOT_SOURCE_QSPI_NOR)
102 puts("QSPI\n");
103 else
104 printf("Unknown boot source %d\n", src);
105
106 puts("Controller: ");
Simon Glassf7e33a02023-02-05 17:55:21 -0700107 if (IS_ENABLED(CONFIG_TEN64_CONTROLLER)) {
Mathew McBridee605fb12022-01-31 18:34:43 +0530108 /* Driver not compatible with alpha/beta board MCU firmware */
109 if (board_rev <= TEN64_BOARD_REV_C) {
110 if (ten64_read_board_info(&boardinfo)) {
111 puts("ERROR: unable to communicate\n");
112 } else {
113 printf("firmware %d.%d.%d\n",
114 boardinfo.fwversion_major,
115 boardinfo.fwversion_minor,
116 boardinfo.fwversion_patch);
117 ten64_set_macaddrs_from_board_info(&boardinfo);
118 }
119 } else {
120 puts("not supported on this board revision\n");
121 }
122 } else {
123 puts("driver not enabled (no MAC addresses or other information will be read)\n");
124 }
125
126 return 0;
127}
128
129int board_init(void)
130{
131 init_final_memctl_regs();
132
Simon Glass8b374d62023-02-05 15:39:59 -0700133 if (IS_ENABLED(CONFIG_FSL_CAAM))
Mathew McBridee605fb12022-01-31 18:34:43 +0530134 sec_init();
135
136 return 0;
137}
138
139int fsl_initdram(void)
140{
141 gd->ram_size = tfa_get_dram_size();
142
143 if (!gd->ram_size)
144 gd->ram_size = fsl_ddr_sdram_size();
145
146 return 0;
147}
148
149void detail_board_ddr_info(void)
150{
151 puts("\nDDR ");
152 print_size(gd->bd->bi_dram[0].size + gd->bd->bi_dram[1].size, "");
153 print_ddr_info(0);
154}
155
156void board_quiesce_devices(void)
157{
158 if (IS_ENABLED(CONFIG_FSL_MC_ENET))
159 fsl_mc_ldpaa_exit(gd->bd);
160}
161
162void fdt_fixup_board_enet(void *fdt)
163{
164 int offset;
165
166 offset = fdt_path_offset(fdt, "/fsl-mc");
167
168 if (offset < 0)
169 offset = fdt_path_offset(fdt, "/soc/fsl-mc");
170
171 if (offset < 0) {
172 printf("%s: ERROR: fsl-mc node not found in device tree (error %d)\n",
173 __func__, offset);
174 return;
175 }
176
Mathew McBride715091b2023-07-21 04:39:31 +0000177 /* In the U-Boot FDT, a 'simple-mfd' compatible is added.
178 * Remove this as FreeBSD will only match "fsl,qoriq-mc"
179 * exactly on the DPAA2 bus/MC node.
180 */
181 fdt_setprop(fdt, offset, "compatible", "fsl,qoriq-mc", 12);
182
Mathew McBridee605fb12022-01-31 18:34:43 +0530183 if (get_mc_boot_status() == 0 &&
184 (is_lazy_dpl_addr_valid() || get_dpl_apply_status() == 0))
185 fdt_status_okay(fdt, offset);
186 else
187 fdt_status_fail(fdt, offset);
188}
189
190/* Called after SoC board_late_init in fsl-layerscape/soc.c */
191int fsl_board_late_init(void)
192{
193 ten64_board_retimer_ds110df410_init();
Mathew McBride0710b542023-07-21 04:39:24 +0000194
195 /* Ensure nvme storage devices are available to bootflow */
196 if (IS_ENABLED(CONFIG_NVME))
197 nvme_scan_namespace();
198
Mathew McBridee605fb12022-01-31 18:34:43 +0530199 return 0;
200}
201
202int ft_board_setup(void *blob, struct bd_info *bd)
203{
204 int i;
205 u16 mc_memory_bank = 0;
206
207 u64 *base;
208 u64 *size;
209 u64 mc_memory_base = 0;
210 u64 mc_memory_size = 0;
211 u16 total_memory_banks;
212
213 debug("%s blob=0x%p\n", __func__, blob);
214
215 ft_cpu_setup(blob, bd);
216
217 fdt_fixup_mc_ddr(&mc_memory_base, &mc_memory_size);
218
219 if (mc_memory_base != 0)
220 mc_memory_bank++;
221
222 total_memory_banks = CONFIG_NR_DRAM_BANKS + mc_memory_bank;
223
224 base = calloc(total_memory_banks, sizeof(u64));
225 size = calloc(total_memory_banks, sizeof(u64));
226
227 /* fixup DT for the two GPP DDR banks */
228 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
229 base[i] = gd->bd->bi_dram[i].start;
230 size[i] = gd->bd->bi_dram[i].size;
231 /* reduce size if reserved memory is within this bank */
Simon Glassb2fb3c62023-02-05 15:40:39 -0700232 if (IS_ENABLED(CONFIG_RESV_RAM) && RESV_MEM_IN_BANK(i))
Mathew McBridee605fb12022-01-31 18:34:43 +0530233 size[i] = gd->arch.resv_ram - base[i];
234 }
235
236 if (mc_memory_base != 0) {
237 for (i = 0; i <= total_memory_banks; i++) {
238 if (base[i] == 0 && size[i] == 0) {
239 base[i] = mc_memory_base;
240 size[i] = mc_memory_size;
241 break;
242 }
243 }
244 }
245
246 fdt_fixup_memory_banks(blob, base, size, total_memory_banks);
247
248 fdt_fsl_mc_fixup_iommu_map_entry(blob);
249
Simon Glass44459d52023-02-05 15:40:01 -0700250 if (IS_ENABLED(CONFIG_FSL_MC_ENET))
Mathew McBridee605fb12022-01-31 18:34:43 +0530251 fdt_fixup_board_enet(blob);
252
253 fdt_fixup_icid(blob);
254
255 return 0;
256}
257
258#define MACADDRBITS(a, b) (u8)(((a) >> (b)) & 0xFF)
259
260/** Probe and return a udevice for the Ten64 board microcontroller.
261 * Optionally, return the I2C bus the microcontroller resides on
262 * @i2c_bus_out: return I2C bus device handle in this pointer
263 */
264static int ten64_get_micro_udevice(struct udevice **ucdev, struct udevice **i2c_bus_out)
265{
266 int ret;
267 struct udevice *i2cbus;
268
269 ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &i2cbus);
270 if (ret) {
271 printf("%s: Could not get I2C UCLASS", __func__);
272 return ret;
273 }
274 if (i2c_bus_out)
275 *i2c_bus_out = i2cbus;
276
277 ret = dm_i2c_probe(i2cbus, 0x7E, DM_I2C_CHIP_RD_ADDRESS, ucdev);
278 if (ret) {
279 printf("%s: Could not get microcontroller device\n", __func__);
280 return ret;
281 }
282 return ret;
283}
284
285static int ten64_read_board_info(struct t64uc_board_info *boardinfo)
286{
287 struct udevice *ucdev;
288 int ret;
289
290 ret = ten64_get_micro_udevice(&ucdev, NULL);
291 if (ret)
292 return ret;
293
294 ret = misc_call(ucdev, TEN64_CNTRL_GET_BOARD_INFO, NULL, 0, (void *)boardinfo, 0);
295 if (ret)
296 return ret;
297
298 return 0;
299}
300
301static void ten64_set_macaddrs_from_board_info(struct t64uc_board_info *boardinfo)
302{
303 char ethaddr[18];
304 char enetvar[10];
Mathew McBridee6cbacf2023-07-21 04:39:26 +0000305 char serial[18];
Mathew McBridee605fb12022-01-31 18:34:43 +0530306 u8 intfidx, this_dpmac_num;
307 u64 macaddr = 0;
308 /* We will copy the MAC address returned from the
309 * uC (48 bits) into the u64 macaddr
310 */
311 u8 *macaddr_bytes = (u8 *)&macaddr + 2;
312
313 /** MAC addresses are allocated in order of the physical port numbers,
314 * DPMAC7->10 is "eth0" through "eth3"
315 * DPMAC3->6 is "eth4" through "eth7"
316 * DPMAC2 and 1 are "eth8" and "eth9" respectively
317 */
318 int allocation_order[10] = {7, 8, 9, 10, 3, 4, 5, 6, 2, 1};
319
320 memcpy(macaddr_bytes, boardinfo->mac, 6);
321 /* MAC address bytes from uC are in big endian,
322 * convert to CPU
323 */
324 macaddr = __be64_to_cpu(macaddr);
325
Mathew McBridee6cbacf2023-07-21 04:39:26 +0000326 /* Set serial# to GE0/DPMAC7 MAC address
327 * (Matches the labels on the board and appliance)
328 */
329 snprintf(serial, 18, "%02X%02X%02X%02X%02X%02X",
330 MACADDRBITS(macaddr, 40),
331 MACADDRBITS(macaddr, 32),
332 MACADDRBITS(macaddr, 24),
333 MACADDRBITS(macaddr, 16),
334 MACADDRBITS(macaddr, 8),
335 MACADDRBITS(macaddr, 0));
336 if (!env_get("serial#"))
337 env_set("serial#", serial);
338
Mathew McBridee605fb12022-01-31 18:34:43 +0530339 for (intfidx = 0; intfidx < 10; intfidx++) {
340 snprintf(ethaddr, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
341 MACADDRBITS(macaddr, 40),
342 MACADDRBITS(macaddr, 32),
343 MACADDRBITS(macaddr, 24),
344 MACADDRBITS(macaddr, 16),
345 MACADDRBITS(macaddr, 8),
346 MACADDRBITS(macaddr, 0));
347
348 this_dpmac_num = allocation_order[intfidx];
349 printf("DPMAC%d: %s\n", this_dpmac_num, ethaddr);
350 snprintf(enetvar, 10,
Mathew McBride24b0ab02023-07-21 04:39:25 +0000351 (intfidx != 0) ? "eth%daddr" : "ethaddr",
352 intfidx);
Mathew McBridee605fb12022-01-31 18:34:43 +0530353 macaddr++;
354
355 if (!env_get(enetvar))
356 env_set(enetvar, ethaddr);
357 }
358}
359
360/* The retimer (DS110DF410) is one of the devices without
361 * a RESET line, but a power switch is on the board
362 * allowing it to be reset via uC command
363 */
364static int board_cycle_retimer(struct udevice **retim_dev)
365{
366 int ret;
367 u8 loop;
368 struct udevice *uc_dev;
369 struct udevice *i2cbus;
Mathew McBride22879432023-07-21 04:39:17 +0000370 u32 board_rev = ten64_get_board_rev();
Mathew McBridee605fb12022-01-31 18:34:43 +0530371
372 ret = ten64_get_micro_udevice(&uc_dev, &i2cbus);
373 if (ret)
374 return ret;
375
Mathew McBride22879432023-07-21 04:39:17 +0000376 /* Retimer power cycle not implemented on early board
377 * revisions/controller firmwares
378 */
379 if (IS_ENABLED(CONFIG_TEN64_CONTROLLER) &&
380 board_rev <= TEN64_BOARD_REV_C) {
381 ret = dm_i2c_probe(i2cbus, I2C_RETIMER_ADDR, 0, retim_dev);
382 if (ret == 0) {
383 puts("(retimer on, resetting...) ");
Mathew McBridee605fb12022-01-31 18:34:43 +0530384
Mathew McBride22879432023-07-21 04:39:17 +0000385 ret = misc_call(uc_dev, TEN64_CNTRL_10G_OFF, NULL, 0, NULL, 0);
386 mdelay(1000);
387 }
Mathew McBridee605fb12022-01-31 18:34:43 +0530388
Mathew McBride22879432023-07-21 04:39:17 +0000389 ret = misc_call(uc_dev, TEN64_CNTRL_10G_ON, NULL, 0, NULL, 0);
390 }
Mathew McBridee605fb12022-01-31 18:34:43 +0530391
392 // Wait for retimer to come back
393 for (loop = 0; loop < 5; loop++) {
394 ret = dm_i2c_probe(i2cbus, I2C_RETIMER_ADDR, 0, retim_dev);
395 if (ret == 0)
396 return 0;
397 mdelay(500);
398 }
399
400 return -ENOSYS;
401}
402
403/* ten64_board_retimer_ds110df410_init() - Configure the 10G retimer
404 * Adopted from the t102xqds board file
405 */
406static void ten64_board_retimer_ds110df410_init(void)
407{
408 u8 reg;
409 int ret;
410 struct udevice *retim_dev;
Mathew McBridee605fb12022-01-31 18:34:43 +0530411
412 puts("Retimer: ");
Mathew McBride22879432023-07-21 04:39:17 +0000413
414 ret = board_cycle_retimer(&retim_dev);
415 if (ret) {
416 puts("Retimer power on failed\n");
417 return;
Mathew McBridee605fb12022-01-31 18:34:43 +0530418 }
419
420 /* Access to Control/Shared register */
421 reg = 0x0;
422
423 ret = dm_i2c_write(retim_dev, 0xff, &reg, 1);
424 if (ret) {
425 printf("Error writing to retimer register (error %d)\n", ret);
426 return;
427 }
428
429 /* Read device revision and ID */
430 dm_i2c_read(retim_dev, 1, &reg, 1);
431 if (reg == 0xF0)
432 puts("DS110DF410 found\n");
433 else
434 printf("Unknown retimer 0x%xn\n", reg);
435
436 /* Enable Broadcast */
437 reg = 0x0c;
438 dm_i2c_write(retim_dev, 0xff, &reg, 1);
439
440 /* Perform a full reset (state, channel and clock)
441 * for all channels
442 * as the DS110DF410 does not have a RESET line
443 */
444 dm_i2c_read(retim_dev, 0, &reg, 1);
445 reg |= 0x7;
446 dm_i2c_write(retim_dev, 0, &reg, 1);
447
448 /* Set rate/subrate = 0 */
449 reg = 0x6;
450 dm_i2c_write(retim_dev, 0x2F, &reg, 1);
451
452 /* Set data rate as 10.3125 Gbps */
453 reg = 0x0;
454 dm_i2c_write(retim_dev, 0x60, &reg, 1);
455 reg = 0xb2;
456 dm_i2c_write(retim_dev, 0x61, &reg, 1);
457 reg = 0x90;
458 dm_i2c_write(retim_dev, 0x62, &reg, 1);
459 reg = 0xb3;
460 dm_i2c_write(retim_dev, 0x63, &reg, 1);
461 reg = 0xff;
462 dm_i2c_write(retim_dev, 0x64, &reg, 1);
463
464 /* Invert channel 2 (Lower SFP TX to CPU) due to the SFP being inverted */
465 reg = 0x05;
466 dm_i2c_write(retim_dev, 0xFF, &reg, 1);
467 dm_i2c_read(retim_dev, 0x1F, &reg, 1);
468 reg |= 0x80;
469 dm_i2c_write(retim_dev, 0x1F, &reg, 1);
470
471 puts("OK\n");
472}
Mathew McBride0710b542023-07-21 04:39:24 +0000473
Mathew McBride9f55a3d2023-07-21 04:39:30 +0000474/* Opt out of the fsl_setenv_bootcmd
475 * in arch/arm/cpu/armv8/fsl-layerscape/soc.c
476 * which is invoked by board_late_init.
477 */
478int fsl_setenv_bootcmd(void)
479{
480 return 0;
481}
482