blob: 85cb999f17fcea1ae53867dfb86c9545a741b089 [file] [log] [blame]
Jan Kiszka8ff2ff82021-09-18 08:17:53 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Board specific initialization for IOT2050
Jan Kiszkab2d24f92023-07-27 06:34:54 +02004 * Copyright (c) Siemens AG, 2018-2023
Jan Kiszka8ff2ff82021-09-18 08:17:53 +02005 *
6 * Authors:
7 * Le Jin <le.jin@siemens.com>
8 * Jan Kiszka <jan.kiszka@siemens.com>
9 */
10
Tom Rinidec7ea02024-05-20 13:35:03 -060011#include <config.h>
Jan Kiszka8ff2ff82021-09-18 08:17:53 +020012#include <bootstage.h>
13#include <dm.h>
Jan Kiszkae31f16c2023-02-28 19:19:23 +010014#include <fdt_support.h>
Jan Kiszka8ff2ff82021-09-18 08:17:53 +020015#include <i2c.h>
16#include <led.h>
17#include <malloc.h>
Jan Kiszkae31f16c2023-02-28 19:19:23 +010018#include <mapmem.h>
Jan Kiszka8ff2ff82021-09-18 08:17:53 +020019#include <net.h>
20#include <phy.h>
21#include <spl.h>
22#include <version.h>
23#include <linux/delay.h>
Jan Kiszka8ff2ff82021-09-18 08:17:53 +020024#include <asm/arch/hardware.h>
25#include <asm/gpio.h>
26#include <asm/io.h>
27
28#define IOT2050_INFO_MAGIC 0x20502050
29
30struct iot2050_info {
31 u32 magic;
32 u16 size;
33 char name[20 + 1];
34 char serial[16 + 1];
35 char mlfb[18 + 1];
36 char uuid[32 + 1];
37 char a5e[18 + 1];
38 u8 mac_addr_cnt;
39 u8 mac_addr[8][ARP_HLEN];
40 char seboot_version[40 + 1];
41} __packed;
42
43/*
44 * Scratch SRAM (available before DDR RAM) contains extracted EEPROM data.
45 */
46#define IOT2050_INFO_DATA ((struct iot2050_info *) \
47 TI_SRAM_SCRATCH_BOARD_EEPROM_START)
48
49DECLARE_GLOBAL_DATA_PTR;
50
Jan Kiszkae31f16c2023-02-28 19:19:23 +010051struct gpio_config {
52 const char *gpio_name;
53 const char *label;
54};
55
56enum m2_connector_mode {
57 BKEY_PCIEX2 = 0,
58 BKEY_PCIE_EKEY_PCIE,
59 BKEY_USB30_EKEY_PCIE,
60 CONNECTOR_MODE_INVALID
61};
62
63struct m2_config_pins {
64 int config[4];
65};
66
67struct serdes_mux_control {
68 int ctrl_usb30_pcie0_lane0;
69 int ctrl_pcie1_pcie0;
70 int ctrl_usb30_pcie0_lane1;
71};
72
73struct m2_config_table {
74 struct m2_config_pins config_pins;
75 enum m2_connector_mode mode;
76};
77
78static const struct gpio_config serdes_mux_ctl_pin_info[] = {
79 {"gpio@600000_88", "CTRL_USB30_PCIE0_LANE0"},
80 {"gpio@600000_82", "CTRL_PCIE1_PCIE0"},
81 {"gpio@600000_89", "CTRL_USB30_PCIE0_LANE1"},
82};
83
84static const struct gpio_config m2_bkey_cfg_pin_info[] = {
85 {"gpio@601000_18", "KEY_CONFIG_0"},
86 {"gpio@601000_19", "KEY_CONFIG_1"},
87 {"gpio@601000_88", "KEY_CONFIG_2"},
88 {"gpio@601000_89", "KEY_CONFIG_3"},
89};
90
91static const struct m2_config_table m2_config_table[] = {
92 {{{0, 1, 0, 0}}, BKEY_PCIEX2},
93 {{{0, 0, 1, 0}}, BKEY_PCIE_EKEY_PCIE},
94 {{{0, 1, 1, 0}}, BKEY_PCIE_EKEY_PCIE},
95 {{{1, 0, 0, 1}}, BKEY_PCIE_EKEY_PCIE},
96 {{{1, 1, 0, 1}}, BKEY_PCIE_EKEY_PCIE},
97 {{{0, 0, 0, 1}}, BKEY_USB30_EKEY_PCIE},
98 {{{0, 1, 0, 1}}, BKEY_USB30_EKEY_PCIE},
99 {{{0, 0, 1, 1}}, BKEY_USB30_EKEY_PCIE},
100 {{{0, 1, 1, 1}}, BKEY_USB30_EKEY_PCIE},
101 {{{1, 0, 1, 1}}, BKEY_USB30_EKEY_PCIE},
102};
103
104static const struct serdes_mux_control serdes_mux_ctrl[] = {
105 [BKEY_PCIEX2] = {0, 0, 1},
106 [BKEY_PCIE_EKEY_PCIE] = {0, 1, 0},
107 [BKEY_USB30_EKEY_PCIE] = {1, 1, 0},
108};
109
110static const char *m2_connector_mode_name[] = {
111 [BKEY_PCIEX2] = "PCIe x2 (key B)",
112 [BKEY_PCIE_EKEY_PCIE] = "PCIe (key B) / PCIe (key E)",
113 [BKEY_USB30_EKEY_PCIE] = "USB 3.0 (key B) / PCIe (key E)",
114};
115
116static enum m2_connector_mode connector_mode;
117
118#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
119static void *connector_overlay;
120static u32 connector_overlay_size;
121#endif
122
123static int get_pinvalue(const char *gpio_name, const char *label)
124{
125 struct gpio_desc gpio;
126
127 if (dm_gpio_lookup_name(gpio_name, &gpio) < 0 ||
128 dm_gpio_request(&gpio, label) < 0 ||
129 dm_gpio_set_dir_flags(&gpio, GPIOD_IS_IN) < 0) {
130 pr_err("Cannot get pin %s for M.2 configuration\n", gpio_name);
131 return 0;
132 }
133
134 return dm_gpio_get_value(&gpio);
135}
136
137static void set_pinvalue(const char *gpio_name, const char *label, int value)
138{
139 struct gpio_desc gpio;
140
141 if (dm_gpio_lookup_name(gpio_name, &gpio) < 0 ||
142 dm_gpio_request(&gpio, label) < 0 ||
143 dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT) < 0) {
144 pr_err("Cannot set pin %s for M.2 configuration\n", gpio_name);
145 return;
146 }
147 dm_gpio_set_value(&gpio, value);
148}
149
Jan Kiszkab2d24f92023-07-27 06:34:54 +0200150static bool board_is_advanced(void)
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100151{
152 struct iot2050_info *info = IOT2050_INFO_DATA;
153
Jan Kiszkab2d24f92023-07-27 06:34:54 +0200154 return info->magic == IOT2050_INFO_MAGIC &&
155 strstr((char *)info->name, "IOT2050-ADVANCED") != NULL;
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100156}
157
Jan Kiszka80085052023-10-17 07:20:14 +0200158static bool board_is_pg1(void)
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200159{
160 struct iot2050_info *info = IOT2050_INFO_DATA;
161
162 return info->magic == IOT2050_INFO_MAGIC &&
Jan Kiszka80085052023-10-17 07:20:14 +0200163 (strcmp((char *)info->name, "IOT2050-BASIC") == 0 ||
164 strcmp((char *)info->name, "IOT2050-ADVANCED") == 0);
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200165}
166
Jan Kiszkab2d24f92023-07-27 06:34:54 +0200167static bool board_is_m2(void)
168{
169 struct iot2050_info *info = IOT2050_INFO_DATA;
170
Jan Kiszka80085052023-10-17 07:20:14 +0200171 return info->magic == IOT2050_INFO_MAGIC &&
Jan Kiszkab2d24f92023-07-27 06:34:54 +0200172 strcmp((char *)info->name, "IOT2050-ADVANCED-M2") == 0;
173}
174
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200175static void remove_mmc1_target(void)
176{
177 char *boot_targets = strdup(env_get("boot_targets"));
178 char *mmc1 = strstr(boot_targets, "mmc1");
179
180 if (mmc1) {
181 memmove(mmc1, mmc1 + 4, strlen(mmc1 + 4) + 1);
182 env_set("boot_targets", boot_targets);
183 }
184
185 free(boot_targets);
186}
187
Baocheng Su6e8b7162024-10-22 08:04:20 +0200188static void enable_pcie_connector_power(void)
189{
190 set_pinvalue("gpio@601000_17", "P3V3_PCIE_CON_EN", 1);
191 udelay(4 * 100);
192}
193
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200194void set_board_info_env(void)
195{
196 struct iot2050_info *info = IOT2050_INFO_DATA;
197 u8 __maybe_unused mac_cnt;
198 const char *fdtfile;
199
200 if (info->magic != IOT2050_INFO_MAGIC) {
201 pr_err("IOT2050: Board info parsing error!\n");
202 return;
203 }
204
205 if (env_get("board_uuid"))
206 return;
207
208 env_set("board_name", info->name);
209 env_set("board_serial", info->serial);
210 env_set("mlfb", info->mlfb);
211 env_set("board_uuid", info->uuid);
212 env_set("board_a5e", info->a5e);
213 env_set("fw_version", PLAIN_VERSION);
214 env_set("seboot_version", info->seboot_version);
215
216 if (IS_ENABLED(CONFIG_NET)) {
217 /* set MAC addresses to ensure forwarding to the OS */
218 for (mac_cnt = 0; mac_cnt < info->mac_addr_cnt; mac_cnt++) {
219 if (is_valid_ethaddr(info->mac_addr[mac_cnt]))
220 eth_env_set_enetaddr_by_index("eth",
221 mac_cnt + 1,
222 info->mac_addr[mac_cnt]);
223 }
224 }
225
226 if (board_is_advanced()) {
Jan Kiszka80085052023-10-17 07:20:14 +0200227 if (board_is_pg1())
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200228 fdtfile = "ti/k3-am6548-iot2050-advanced.dtb";
Baocheng Succdeb5b2024-10-22 08:04:19 +0200229 else if (board_is_m2())
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100230 fdtfile = "ti/k3-am6548-iot2050-advanced-m2.dtb";
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200231 else
232 fdtfile = "ti/k3-am6548-iot2050-advanced-pg2.dtb";
233 } else {
Jan Kiszka80085052023-10-17 07:20:14 +0200234 if (board_is_pg1())
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200235 fdtfile = "ti/k3-am6528-iot2050-basic.dtb";
236 else
237 fdtfile = "ti/k3-am6528-iot2050-basic-pg2.dtb";
238 /* remove the unavailable eMMC (mmc1) from the list */
239 remove_mmc1_target();
240 }
241 env_set("fdtfile", fdtfile);
242
243 env_save();
244}
245
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100246static void m2_overlay_prepare(void)
247{
248#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
249 const char *overlay_path;
250 void *overlay;
251 u64 loadaddr;
252 ofnode node;
253 int ret;
254
255 if (connector_mode == BKEY_PCIEX2)
256 return;
257
258 if (connector_mode == BKEY_PCIE_EKEY_PCIE)
259 overlay_path = "/fit-images/bkey-ekey-pcie-overlay";
260 else
261 overlay_path = "/fit-images/bkey-usb3-overlay";
262
263 node = ofnode_path(overlay_path);
264 if (!ofnode_valid(node))
265 goto fit_error;
266
267 ret = ofnode_read_u64(node, "load", &loadaddr);
268 if (ret)
269 goto fit_error;
270
271 ret = ofnode_read_u32(node, "size", &connector_overlay_size);
272 if (ret)
273 goto fit_error;
274
275 overlay = map_sysmem(loadaddr, connector_overlay_size);
276
277 connector_overlay = malloc(connector_overlay_size);
278 if (!connector_overlay)
279 goto fit_error;
280
281 memcpy(connector_overlay, overlay, connector_overlay_size);
282 return;
283
284fit_error:
285 pr_err("M.2 device tree overlay %s not available,\n", overlay_path);
286#endif
287}
288
289static void m2_connector_setup(void)
290{
291 ulong m2_manual_config = env_get_ulong("m2_manual_config", 10,
292 CONNECTOR_MODE_INVALID);
293 const char *mode_info = "";
294 struct m2_config_pins config_pins;
295 unsigned int n;
296
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100297 if (m2_manual_config < CONNECTOR_MODE_INVALID) {
298 mode_info = " [manual mode]";
299 connector_mode = m2_manual_config;
300 } else { /* auto detection */
301 for (n = 0; n < ARRAY_SIZE(config_pins.config); n++)
302 config_pins.config[n] =
303 get_pinvalue(m2_bkey_cfg_pin_info[n].gpio_name,
304 m2_bkey_cfg_pin_info[n].label);
305 connector_mode = CONNECTOR_MODE_INVALID;
306 for (n = 0; n < ARRAY_SIZE(m2_config_table); n++) {
307 if (!memcmp(config_pins.config,
308 m2_config_table[n].config_pins.config,
309 sizeof(config_pins.config))) {
310 connector_mode = m2_config_table[n].mode;
311 break;
312 }
313 }
314 if (connector_mode == CONNECTOR_MODE_INVALID) {
315 mode_info = " [fallback, card unknown/unsupported]";
316 connector_mode = BKEY_USB30_EKEY_PCIE;
317 }
318 }
319
320 printf("M.2: %s%s\n", m2_connector_mode_name[connector_mode],
321 mode_info);
322
323 /* configure serdes mux */
324 set_pinvalue(serdes_mux_ctl_pin_info[0].gpio_name,
325 serdes_mux_ctl_pin_info[0].label,
326 serdes_mux_ctrl[connector_mode].ctrl_usb30_pcie0_lane0);
327 set_pinvalue(serdes_mux_ctl_pin_info[1].gpio_name,
328 serdes_mux_ctl_pin_info[1].label,
329 serdes_mux_ctrl[connector_mode].ctrl_pcie1_pcie0);
330 set_pinvalue(serdes_mux_ctl_pin_info[2].gpio_name,
331 serdes_mux_ctl_pin_info[2].label,
332 serdes_mux_ctrl[connector_mode].ctrl_usb30_pcie0_lane1);
333
334 m2_overlay_prepare();
335}
336
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200337int board_init(void)
338{
339 return 0;
340}
341
342int dram_init(void)
343{
344 if (board_is_advanced())
345 gd->ram_size = SZ_2G;
346 else
347 gd->ram_size = SZ_1G;
348
349 return 0;
350}
351
352int dram_init_banksize(void)
353{
354 dram_init();
355
356 /* Bank 0 declares the memory available in the DDR low region */
Tom Rinibb4dd962022-11-16 13:10:37 -0500357 gd->bd->bi_dram[0].start = CFG_SYS_SDRAM_BASE;
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200358 gd->bd->bi_dram[0].size = gd->ram_size;
359
360 /* Bank 1 declares the memory available in the DDR high region */
361 gd->bd->bi_dram[1].start = 0;
362 gd->bd->bi_dram[1].size = 0;
363
364 return 0;
365}
366
367#ifdef CONFIG_SPL_LOAD_FIT
368int board_fit_config_name_match(const char *name)
369{
370 struct iot2050_info *info = IOT2050_INFO_DATA;
371 char upper_name[32];
372
Su Baocheng8999cc52023-02-28 19:19:10 +0100373 /* skip the prefix "k3-am65x8-" */
374 name += 10;
375
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200376 if (info->magic != IOT2050_INFO_MAGIC ||
377 strlen(name) >= sizeof(upper_name))
378 return -1;
379
380 str_to_upper(name, upper_name, sizeof(upper_name));
381 if (!strcmp(upper_name, (char *)info->name))
382 return 0;
383
384 return -1;
385}
386#endif
387
388int do_board_detect(void)
389{
390 return 0;
391}
392
393#ifdef CONFIG_IOT2050_BOOT_SWITCH
394static bool user_button_pressed(void)
395{
396 struct udevice *red_led = NULL;
397 unsigned long count = 0;
398 struct gpio_desc gpio;
399
400 memset(&gpio, 0, sizeof(gpio));
401
chao zeng7d933ad2023-02-28 19:19:20 +0100402 if (dm_gpio_lookup_name("gpio@42110000_25", &gpio) < 0 ||
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200403 dm_gpio_request(&gpio, "USER button") < 0 ||
404 dm_gpio_set_dir_flags(&gpio, GPIOD_IS_IN) < 0)
405 return false;
406
407 if (dm_gpio_get_value(&gpio) == 1)
408 return false;
409
410 printf("USER button pressed - booting from external media only\n");
411
412 led_get_by_label("status-led-red", &red_led);
413
414 if (red_led)
415 led_set_state(red_led, LEDST_ON);
416
417 while (dm_gpio_get_value(&gpio) == 0 && count++ < 10000)
418 mdelay(1);
419
420 if (red_led)
421 led_set_state(red_led, LEDST_OFF);
422
423 return true;
424}
425#endif
426
427#define SERDES0_LANE_SELECT 0x00104080
428
429int board_late_init(void)
430{
431 /* change CTRL_MMR register to let serdes0 not output USB3.0 signals. */
432 writel(0x3, SERDES0_LANE_SELECT);
433
Baocheng Su6e8b7162024-10-22 08:04:20 +0200434 enable_pcie_connector_power();
435
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100436 if (board_is_m2())
437 m2_connector_setup();
438
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200439 set_board_info_env();
440
441 /* remove the eMMC if requested via button */
442 if (IS_ENABLED(CONFIG_IOT2050_BOOT_SWITCH) && board_is_advanced() &&
443 user_button_pressed())
444 remove_mmc1_target();
445
446 return 0;
447}
448
449#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100450static void m2_fdt_fixup(void *blob)
451{
452 void *overlay_copy = NULL;
453 void *fdt_copy = NULL;
454 u32 fdt_size;
455 int err;
456
457 if (!connector_overlay)
458 return;
459
460 /*
461 * We need to work with temporary copies here because fdt_overlay_apply
462 * is destructive to the overlay and also to the target blob, even if
463 * application fails.
464 */
465 fdt_size = fdt_totalsize(blob);
466 fdt_copy = malloc(fdt_size);
467 if (!fdt_copy)
468 goto fixup_error;
469
470 memcpy(fdt_copy, blob, fdt_size);
471
472 overlay_copy = malloc(connector_overlay_size);
473 if (!overlay_copy)
474 goto fixup_error;
475
476 memcpy(overlay_copy, connector_overlay, connector_overlay_size);
477
478 err = fdt_overlay_apply_verbose(fdt_copy, overlay_copy);
479 if (err)
480 goto fixup_error;
481
482 memcpy(blob, fdt_copy, fdt_size);
483
484cleanup:
485 free(fdt_copy);
486 free(overlay_copy);
487 return;
488
489fixup_error:
490 pr_err("Could not apply M.2 device tree overlay\n");
491 goto cleanup;
492}
493
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200494int ft_board_setup(void *blob, struct bd_info *bd)
495{
Jan Kiszkae31f16c2023-02-28 19:19:23 +0100496 if (board_is_m2())
497 m2_fdt_fixup(blob);
498
Andrew Davisb1c29792023-04-06 11:38:10 -0500499 return 0;
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200500}
501#endif
502
503void spl_board_init(void)
504{
505}
506
Marek Vasut98154342021-10-23 03:06:03 +0200507#if CONFIG_IS_ENABLED(LED) && CONFIG_IS_ENABLED(SHOW_BOOT_PROGRESS)
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200508/*
509 * Indicate any error or (accidental?) entering of CLI via the red status LED.
510 */
511void show_boot_progress(int progress)
512{
513 struct udevice *dev;
514 int ret;
515
Jan Kiszkaa8ea4f42021-11-03 15:12:30 +0100516 if ((progress < 0 && progress != -BOOTSTAGE_ID_NET_ETH_START) ||
517 progress == BOOTSTAGE_ID_ENTER_CLI_LOOP) {
Jan Kiszka8ff2ff82021-09-18 08:17:53 +0200518 ret = led_get_by_label("status-led-green", &dev);
519 if (ret == 0)
520 led_set_state(dev, LEDST_OFF);
521
522 ret = led_get_by_label("status-led-red", &dev);
523 if (ret == 0)
524 led_set_state(dev, LEDST_ON);
525 }
526}
527#endif