1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Board specific initialization for IOT2050 4 * Copyright (c) Siemens AG, 2018-2023 5 * 6 * Authors: 7 * Le Jin <le.jin@siemens.com> 8 * Jan Kiszka <jan.kiszka@siemens.com> 9 */ 10 11#include <common.h> 12#include <bootstage.h> 13#include <dm.h> 14#include <fdt_support.h> 15#include <i2c.h> 16#include <led.h> 17#include <malloc.h> 18#include <mapmem.h> 19#include <net.h> 20#include <phy.h> 21#include <spl.h> 22#include <version.h> 23#include <linux/delay.h> 24#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 51struct 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 150static bool board_is_advanced(void) 151{ 152 struct iot2050_info *info = IOT2050_INFO_DATA; 153 154 return info->magic == IOT2050_INFO_MAGIC && 155 strstr((char *)info->name, "IOT2050-ADVANCED") != NULL; 156} 157 158static bool board_is_pg1(void) 159{ 160 struct iot2050_info *info = IOT2050_INFO_DATA; 161 162 return info->magic == IOT2050_INFO_MAGIC && 163 (strcmp((char *)info->name, "IOT2050-BASIC") == 0 || 164 strcmp((char *)info->name, "IOT2050-ADVANCED") == 0); 165} 166 167static bool board_is_m2(void) 168{ 169 struct iot2050_info *info = IOT2050_INFO_DATA; 170 171 return info->magic == IOT2050_INFO_MAGIC && 172 strcmp((char *)info->name, "IOT2050-ADVANCED-M2") == 0; 173} 174 175static 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 188void set_board_info_env(void) 189{ 190 struct iot2050_info *info = IOT2050_INFO_DATA; 191 u8 __maybe_unused mac_cnt; 192 const char *fdtfile; 193 194 if (info->magic != IOT2050_INFO_MAGIC) { 195 pr_err("IOT2050: Board info parsing error!\n"); 196 return; 197 } 198 199 if (env_get("board_uuid")) 200 return; 201 202 env_set("board_name", info->name); 203 env_set("board_serial", info->serial); 204 env_set("mlfb", info->mlfb); 205 env_set("board_uuid", info->uuid); 206 env_set("board_a5e", info->a5e); 207 env_set("fw_version", PLAIN_VERSION); 208 env_set("seboot_version", info->seboot_version); 209 210 if (IS_ENABLED(CONFIG_NET)) { 211 /* set MAC addresses to ensure forwarding to the OS */ 212 for (mac_cnt = 0; mac_cnt < info->mac_addr_cnt; mac_cnt++) { 213 if (is_valid_ethaddr(info->mac_addr[mac_cnt])) 214 eth_env_set_enetaddr_by_index("eth", 215 mac_cnt + 1, 216 info->mac_addr[mac_cnt]); 217 } 218 } 219 220 if (board_is_advanced()) { 221 if (board_is_pg1()) 222 fdtfile = "ti/k3-am6548-iot2050-advanced.dtb"; 223 else if(board_is_m2()) 224 fdtfile = "ti/k3-am6548-iot2050-advanced-m2.dtb"; 225 else 226 fdtfile = "ti/k3-am6548-iot2050-advanced-pg2.dtb"; 227 } else { 228 if (board_is_pg1()) 229 fdtfile = "ti/k3-am6528-iot2050-basic.dtb"; 230 else 231 fdtfile = "ti/k3-am6528-iot2050-basic-pg2.dtb"; 232 /* remove the unavailable eMMC (mmc1) from the list */ 233 remove_mmc1_target(); 234 } 235 env_set("fdtfile", fdtfile); 236 237 env_save(); 238} 239 240static void m2_overlay_prepare(void) 241{ 242#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) 243 const char *overlay_path; 244 void *overlay; 245 u64 loadaddr; 246 ofnode node; 247 int ret; 248 249 if (connector_mode == BKEY_PCIEX2) 250 return; 251 252 if (connector_mode == BKEY_PCIE_EKEY_PCIE) 253 overlay_path = "/fit-images/bkey-ekey-pcie-overlay"; 254 else 255 overlay_path = "/fit-images/bkey-usb3-overlay"; 256 257 node = ofnode_path(overlay_path); 258 if (!ofnode_valid(node)) 259 goto fit_error; 260 261 ret = ofnode_read_u64(node, "load", &loadaddr); 262 if (ret) 263 goto fit_error; 264 265 ret = ofnode_read_u32(node, "size", &connector_overlay_size); 266 if (ret) 267 goto fit_error; 268 269 overlay = map_sysmem(loadaddr, connector_overlay_size); 270 271 connector_overlay = malloc(connector_overlay_size); 272 if (!connector_overlay) 273 goto fit_error; 274 275 memcpy(connector_overlay, overlay, connector_overlay_size); 276 return; 277 278fit_error: 279 pr_err("M.2 device tree overlay %s not available,\n", overlay_path); 280#endif 281} 282 283static void m2_connector_setup(void) 284{ 285 ulong m2_manual_config = env_get_ulong("m2_manual_config", 10, 286 CONNECTOR_MODE_INVALID); 287 const char *mode_info = ""; 288 struct m2_config_pins config_pins; 289 unsigned int n; 290 291 /* enable M.2 connector power */ 292 set_pinvalue("gpio@601000_17", "P3V3_M2_EN", 1); 293 udelay(4 * 100); 294 295 if (m2_manual_config < CONNECTOR_MODE_INVALID) { 296 mode_info = " [manual mode]"; 297 connector_mode = m2_manual_config; 298 } else { /* auto detection */ 299 for (n = 0; n < ARRAY_SIZE(config_pins.config); n++) 300 config_pins.config[n] = 301 get_pinvalue(m2_bkey_cfg_pin_info[n].gpio_name, 302 m2_bkey_cfg_pin_info[n].label); 303 connector_mode = CONNECTOR_MODE_INVALID; 304 for (n = 0; n < ARRAY_SIZE(m2_config_table); n++) { 305 if (!memcmp(config_pins.config, 306 m2_config_table[n].config_pins.config, 307 sizeof(config_pins.config))) { 308 connector_mode = m2_config_table[n].mode; 309 break; 310 } 311 } 312 if (connector_mode == CONNECTOR_MODE_INVALID) { 313 mode_info = " [fallback, card unknown/unsupported]"; 314 connector_mode = BKEY_USB30_EKEY_PCIE; 315 } 316 } 317 318 printf("M.2: %s%s\n", m2_connector_mode_name[connector_mode], 319 mode_info); 320 321 /* configure serdes mux */ 322 set_pinvalue(serdes_mux_ctl_pin_info[0].gpio_name, 323 serdes_mux_ctl_pin_info[0].label, 324 serdes_mux_ctrl[connector_mode].ctrl_usb30_pcie0_lane0); 325 set_pinvalue(serdes_mux_ctl_pin_info[1].gpio_name, 326 serdes_mux_ctl_pin_info[1].label, 327 serdes_mux_ctrl[connector_mode].ctrl_pcie1_pcie0); 328 set_pinvalue(serdes_mux_ctl_pin_info[2].gpio_name, 329 serdes_mux_ctl_pin_info[2].label, 330 serdes_mux_ctrl[connector_mode].ctrl_usb30_pcie0_lane1); 331 332 m2_overlay_prepare(); 333} 334 335int board_init(void) 336{ 337 return 0; 338} 339 340int dram_init(void) 341{ 342 if (board_is_advanced()) 343 gd->ram_size = SZ_2G; 344 else 345 gd->ram_size = SZ_1G; 346 347 return 0; 348} 349 350int dram_init_banksize(void) 351{ 352 dram_init(); 353 354 /* Bank 0 declares the memory available in the DDR low region */ 355 gd->bd->bi_dram[0].start = CFG_SYS_SDRAM_BASE; 356 gd->bd->bi_dram[0].size = gd->ram_size; 357 358 /* Bank 1 declares the memory available in the DDR high region */ 359 gd->bd->bi_dram[1].start = 0; 360 gd->bd->bi_dram[1].size = 0; 361 362 return 0; 363} 364 365#ifdef CONFIG_SPL_LOAD_FIT 366int board_fit_config_name_match(const char *name) 367{ 368 struct iot2050_info *info = IOT2050_INFO_DATA; 369 char upper_name[32]; 370 371 /* skip the prefix "k3-am65x8-" */ 372 name += 10; 373 374 if (info->magic != IOT2050_INFO_MAGIC || 375 strlen(name) >= sizeof(upper_name)) 376 return -1; 377 378 str_to_upper(name, upper_name, sizeof(upper_name)); 379 if (!strcmp(upper_name, (char *)info->name)) 380 return 0; 381 382 return -1; 383} 384#endif 385 386int do_board_detect(void) 387{ 388 return 0; 389} 390 391#ifdef CONFIG_IOT2050_BOOT_SWITCH 392static bool user_button_pressed(void) 393{ 394 struct udevice *red_led = NULL; 395 unsigned long count = 0; 396 struct gpio_desc gpio; 397 398 memset(&gpio, 0, sizeof(gpio)); 399 400 if (dm_gpio_lookup_name("gpio@42110000_25", &gpio) < 0 || 401 dm_gpio_request(&gpio, "USER button") < 0 || 402 dm_gpio_set_dir_flags(&gpio, GPIOD_IS_IN) < 0) 403 return false; 404 405 if (dm_gpio_get_value(&gpio) == 1) 406 return false; 407 408 printf("USER button pressed - booting from external media only\n"); 409 410 led_get_by_label("status-led-red", &red_led); 411 412 if (red_led) 413 led_set_state(red_led, LEDST_ON); 414 415 while (dm_gpio_get_value(&gpio) == 0 && count++ < 10000) 416 mdelay(1); 417 418 if (red_led) 419 led_set_state(red_led, LEDST_OFF); 420 421 return true; 422} 423#endif 424 425#define SERDES0_LANE_SELECT 0x00104080 426 427int board_late_init(void) 428{ 429 /* change CTRL_MMR register to let serdes0 not output USB3.0 signals. */ 430 writel(0x3, SERDES0_LANE_SELECT); 431 432 if (board_is_m2()) 433 m2_connector_setup(); 434 435 set_board_info_env(); 436 437 /* remove the eMMC if requested via button */ 438 if (IS_ENABLED(CONFIG_IOT2050_BOOT_SWITCH) && board_is_advanced() && 439 user_button_pressed()) 440 remove_mmc1_target(); 441 442 return 0; 443} 444 445#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) 446static void m2_fdt_fixup(void *blob) 447{ 448 void *overlay_copy = NULL; 449 void *fdt_copy = NULL; 450 u32 fdt_size; 451 int err; 452 453 if (!connector_overlay) 454 return; 455 456 /* 457 * We need to work with temporary copies here because fdt_overlay_apply 458 * is destructive to the overlay and also to the target blob, even if 459 * application fails. 460 */ 461 fdt_size = fdt_totalsize(blob); 462 fdt_copy = malloc(fdt_size); 463 if (!fdt_copy) 464 goto fixup_error; 465 466 memcpy(fdt_copy, blob, fdt_size); 467 468 overlay_copy = malloc(connector_overlay_size); 469 if (!overlay_copy) 470 goto fixup_error; 471 472 memcpy(overlay_copy, connector_overlay, connector_overlay_size); 473 474 err = fdt_overlay_apply_verbose(fdt_copy, overlay_copy); 475 if (err) 476 goto fixup_error; 477 478 memcpy(blob, fdt_copy, fdt_size); 479 480cleanup: 481 free(fdt_copy); 482 free(overlay_copy); 483 return; 484 485fixup_error: 486 pr_err("Could not apply M.2 device tree overlay\n"); 487 goto cleanup; 488} 489 490int ft_board_setup(void *blob, struct bd_info *bd) 491{ 492 if (board_is_m2()) 493 m2_fdt_fixup(blob); 494 495 return 0; 496} 497#endif 498 499void spl_board_init(void) 500{ 501} 502 503#if CONFIG_IS_ENABLED(LED) && CONFIG_IS_ENABLED(SHOW_BOOT_PROGRESS) 504/* 505 * Indicate any error or (accidental?) entering of CLI via the red status LED. 506 */ 507void show_boot_progress(int progress) 508{ 509 struct udevice *dev; 510 int ret; 511 512 if ((progress < 0 && progress != -BOOTSTAGE_ID_NET_ETH_START) || 513 progress == BOOTSTAGE_ID_ENTER_CLI_LOOP) { 514 ret = led_get_by_label("status-led-green", &dev); 515 if (ret == 0) 516 led_set_state(dev, LEDST_OFF); 517 518 ret = led_get_by_label("status-led-red", &dev); 519 if (ret == 0) 520 led_set_state(dev, LEDST_ON); 521 } 522} 523#endif 524