1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * K3: System Firmware Loader 4 * 5 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ 6 * Andreas Dannenberg <dannenberg@ti.com> 7 */ 8 9#include <dm.h> 10#include <image.h> 11#include <log.h> 12#include <spl.h> 13#include <malloc.h> 14#include <remoteproc.h> 15#include <asm/cache.h> 16#include <asm/global_data.h> 17#include <linux/soc/ti/ti_sci_protocol.h> 18#include <g_dnl.h> 19#include <usb.h> 20#include <dfu.h> 21#include <dm/uclass-internal.h> 22#include <spi_flash.h> 23 24#include <asm/io.h> 25#include "../common.h" 26 27DECLARE_GLOBAL_DATA_PTR; 28 29/* Name of the FIT image nodes for SYSFW and its config data */ 30#define SYSFW_FIRMWARE "sysfw.bin" 31#define SYSFW_CFG_BOARD "board-cfg.bin" 32#define SYSFW_CFG_PM "pm-cfg.bin" 33#define SYSFW_CFG_RM "rm-cfg.bin" 34#define SYSFW_CFG_SEC "sec-cfg.bin" 35 36/* 37 * It is assumed that remoteproc device 0 is the corresponding 38 * system-controller that runs SYSFW. Make sure DT reflects the same. 39 */ 40#define K3_SYSTEM_CONTROLLER_RPROC_ID 0 41 42#define COMMON_HEADER_ADDRESS 0x41cffb00 43#define BOARDCFG_ADDRESS 0x41c80000 44 45#define COMP_TYPE_SBL_DATA 0x11 46#define DESC_TYPE_BOARDCFG_PM_INDEX 0x2 47#define DESC_TYPE_BOARDCFG_RM_INDEX 0x3 48 49#define BOARD_CONFIG_RM_DESC_TYPE 0x000c 50#define BOARD_CONFIG_PM_DESC_TYPE 0x000e 51 52struct extboot_comp { 53 u32 comp_type; 54 u32 boot_core; 55 u32 comp_opts; 56 u64 dest_addr; 57 u32 comp_size; 58}; 59 60struct extboot_header { 61 u8 magic[8]; 62 u32 num_comps; 63 struct extboot_comp comps[5]; 64 u32 reserved; 65}; 66 67struct bcfg_desc { 68 u16 type; 69 u16 offset; 70 u16 size; 71 u8 devgrp; 72 u8 reserved; 73} __packed; 74 75struct bcfg_header { 76 u8 num_elems; 77 u8 sw_rev; 78 struct bcfg_desc descs[4]; 79 u16 reserved; 80} __packed; 81 82static bool sysfw_loaded; 83static void *sysfw_load_address; 84 85/* 86 * Populate SPL hook to override the default load address used by the SPL 87 * loader function with a custom address for SYSFW loading. 88 */ 89struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) 90{ 91 if (sysfw_loaded) 92 return (struct legacy_img_hdr *)(CONFIG_TEXT_BASE + offset); 93 else if (sysfw_load_address) 94 return sysfw_load_address; 95 else 96 panic("SYSFW load address not defined!"); 97} 98 99/* 100 * Populate SPL hook to skip the default SPL loader FIT post-processing steps 101 * during SYSFW loading and return to the calling function so we can perform 102 * our own custom processing. 103 */ 104bool spl_load_simple_fit_skip_processing(void) 105{ 106 return !sysfw_loaded; 107} 108 109static int fit_get_data_by_name(const void *fit, int images, const char *name, 110 const void **addr, size_t *size) 111{ 112 int node_offset; 113 114 node_offset = fdt_subnode_offset(fit, images, name); 115 if (node_offset < 0) 116 return -ENOENT; 117 118 return fit_image_get_data(fit, node_offset, addr, size); 119} 120 121static void k3_start_system_controller(int rproc_id, bool rproc_loaded, 122 ulong addr, ulong size) 123{ 124 int ret; 125 126 ret = rproc_dev_init(rproc_id); 127 if (ret) 128 panic("rproc failed to be initialized (%d)\n", ret); 129 130 if (!rproc_loaded) { 131 ret = rproc_load(rproc_id, addr, size); 132 if (ret) 133 panic("Firmware failed to start on rproc (%d)\n", ret); 134 } 135 136 ret = rproc_start(0); 137 if (ret) 138 panic("Firmware init failed on rproc (%d)\n", ret); 139} 140 141static void k3_sysfw_load_using_fit(void *fit) 142{ 143 int images; 144 const void *sysfw_addr; 145 size_t sysfw_size; 146 int ret; 147 148 /* Find the node holding the images information */ 149 images = fdt_path_offset(fit, FIT_IMAGES_PATH); 150 if (images < 0) 151 panic("Cannot find /images node (%d)\n", images); 152 153 /* Extract System Firmware (SYSFW) image from FIT */ 154 ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE, 155 &sysfw_addr, &sysfw_size); 156 if (ret < 0) 157 panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE, 158 ret); 159 160 /* Start up system controller firmware */ 161 k3_start_system_controller(K3_SYSTEM_CONTROLLER_RPROC_ID, false, 162 (ulong)sysfw_addr, (ulong)sysfw_size); 163} 164 165static void k3_sysfw_configure_using_fit(void *fit, 166 struct ti_sci_handle *ti_sci) 167{ 168 struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops; 169 int images; 170 const void *cfg_fragment_addr; 171 size_t cfg_fragment_size; 172 int ret; 173 u8 *buf; 174 struct extboot_header *common_header; 175 struct bcfg_header *bcfg_header; 176 struct extboot_comp *comp; 177 struct bcfg_desc *desc; 178 u32 addr; 179 bool copy_bcfg = false; 180 181 /* Find the node holding the images information */ 182 images = fdt_path_offset(fit, FIT_IMAGES_PATH); 183 if (images < 0) 184 panic("Cannot find /images node (%d)\n", images); 185 186 /* Extract board configuration from FIT */ 187 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD, 188 &cfg_fragment_addr, &cfg_fragment_size); 189 if (ret < 0) 190 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD, 191 ret); 192 193 /* Apply board configuration to SYSFW */ 194 ret = board_ops->board_config(ti_sci, 195 (u64)(u32)cfg_fragment_addr, 196 (u32)cfg_fragment_size); 197 if (ret) 198 panic("Failed to set board configuration (%d)\n", ret); 199 200 /* Extract power/clock (PM) specific configuration from FIT */ 201 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM, 202 &cfg_fragment_addr, &cfg_fragment_size); 203 if (ret < 0) 204 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM, 205 ret); 206 207 /* Apply power/clock (PM) specific configuration to SYSFW */ 208 if (!IS_ENABLED(CONFIG_K3_DM_FW)) { 209 ret = board_ops->board_config_pm(ti_sci, 210 (u64)(u32)cfg_fragment_addr, 211 (u32)cfg_fragment_size); 212 if (ret) 213 panic("Failed to set board PM configuration (%d)\n", ret); 214 } else { 215 /* Initialize shared memory boardconfig buffer */ 216 buf = (u8 *)COMMON_HEADER_ADDRESS; 217 common_header = (struct extboot_header *)buf; 218 219 /* Check if we have a struct populated by ROM in memory already */ 220 if (strcmp((char *)common_header->magic, "EXTBOOT")) 221 copy_bcfg = true; 222 223 if (copy_bcfg) { 224 strcpy((char *)common_header->magic, "EXTBOOT"); 225 common_header->num_comps = 1; 226 227 comp = &common_header->comps[0]; 228 229 comp->comp_type = COMP_TYPE_SBL_DATA; 230 comp->boot_core = 0x10; 231 comp->comp_opts = 0; 232 addr = (u32)BOARDCFG_ADDRESS; 233 comp->dest_addr = addr; 234 comp->comp_size = sizeof(*bcfg_header); 235 236 bcfg_header = (struct bcfg_header *)addr; 237 238 bcfg_header->num_elems = 2; 239 bcfg_header->sw_rev = 0; 240 241 desc = &bcfg_header->descs[0]; 242 243 desc->type = BOARD_CONFIG_PM_DESC_TYPE; 244 desc->offset = sizeof(*bcfg_header); 245 desc->size = cfg_fragment_size; 246 comp->comp_size += desc->size; 247 desc->devgrp = 0; 248 desc->reserved = 0; 249 memcpy((u8 *)bcfg_header + desc->offset, 250 cfg_fragment_addr, cfg_fragment_size); 251 252 bcfg_header->descs[1].offset = desc->offset + desc->size; 253 } 254 } 255 256 /* Extract resource management (RM) specific configuration from FIT */ 257 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM, 258 &cfg_fragment_addr, &cfg_fragment_size); 259 if (ret < 0) 260 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM, 261 ret); 262 263 if (copy_bcfg) { 264 desc = &bcfg_header->descs[1]; 265 266 desc->type = BOARD_CONFIG_RM_DESC_TYPE; 267 desc->size = cfg_fragment_size; 268 comp->comp_size += desc->size; 269 desc->devgrp = 0; 270 desc->reserved = 0; 271 memcpy((u8 *)bcfg_header + desc->offset, cfg_fragment_addr, 272 cfg_fragment_size); 273 } 274 275 /* Apply resource management (RM) configuration to SYSFW */ 276 ret = board_ops->board_config_rm(ti_sci, 277 (u64)(u32)cfg_fragment_addr, 278 (u32)cfg_fragment_size); 279 if (ret) 280 panic("Failed to set board RM configuration (%d)\n", ret); 281 282 /* Extract security specific configuration from FIT */ 283 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC, 284 &cfg_fragment_addr, &cfg_fragment_size); 285 if (ret < 0) 286 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC, 287 ret); 288 289 /* Apply security configuration to SYSFW */ 290 ret = board_ops->board_config_security(ti_sci, 291 (u64)(u32)cfg_fragment_addr, 292 (u32)cfg_fragment_size); 293 if (ret) 294 panic("Failed to set board security configuration (%d)\n", 295 ret); 296} 297 298#if CONFIG_IS_ENABLED(DFU) 299static int k3_sysfw_dfu_download(void *addr) 300{ 301 char dfu_str[50]; 302 int ret; 303 304 sprintf(dfu_str, "sysfw.itb ram 0x%p 0x%x", addr, 305 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); 306 ret = dfu_config_entities(dfu_str, "ram", "0"); 307 if (ret) { 308 dfu_free_entities(); 309 goto exit; 310 } 311 312 run_usb_dnl_gadget(0, "usb_dnl_dfu"); 313exit: 314 dfu_free_entities(); 315 return ret; 316} 317#endif 318 319#if CONFIG_IS_ENABLED(SPI_LOAD) 320static void *k3_sysfw_get_spi_addr(void) 321{ 322 struct udevice *dev; 323 void *addr; 324 int ret; 325 unsigned int sf_bus = spl_spi_boot_bus(); 326 327 ret = uclass_find_device_by_seq(UCLASS_SPI, sf_bus, &dev); 328 if (ret) 329 return NULL; 330 331 addr = dev_read_addr_index_ptr(dev, 1); 332 if (!addr) 333 return NULL; 334 335 return addr + CONFIG_K3_SYSFW_IMAGE_SPI_OFFS; 336} 337 338static void k3_sysfw_spi_copy(u32 *dst, u32 *src, size_t len) 339{ 340 size_t i; 341 342 for (i = 0; i < len / sizeof(*dst); i++) 343 *dst++ = *src++; 344} 345#endif 346 347#if CONFIG_IS_ENABLED(NOR_SUPPORT) 348static void *get_sysfw_hf_addr(void) 349{ 350 struct udevice *dev; 351 void *addr; 352 int ret; 353 354 ret = uclass_find_first_device(UCLASS_MTD, &dev); 355 if (ret) 356 return NULL; 357 358 addr = dev_read_addr_index_ptr(dev, 1); 359 if (!addr) 360 return NULL; 361 362 return addr + CONFIG_K3_SYSFW_IMAGE_SPI_OFFS; 363} 364#endif 365 366void k3_sysfw_loader(bool rom_loaded_sysfw, 367 void (*config_pm_pre_callback)(void), 368 void (*config_pm_done_callback)(void)) 369{ 370 struct spl_image_info spl_image = { 0 }; 371 struct spl_boot_device bootdev = { 0 }; 372 struct ti_sci_handle *ti_sci; 373#if CONFIG_IS_ENABLED(SPI_LOAD) 374 void *sysfw_spi_base; 375#endif 376 int ret = 0; 377 378 if (rom_loaded_sysfw) { 379 k3_start_system_controller(K3_SYSTEM_CONTROLLER_RPROC_ID, 380 rom_loaded_sysfw, 0, 0); 381 sysfw_loaded = true; 382 return; 383 } 384 385 /* Reserve a block of aligned memory for loading the SYSFW image */ 386 sysfw_load_address = memalign(ARCH_DMA_MINALIGN, 387 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); 388 if (!sysfw_load_address) 389 panic("Error allocating %u bytes of memory for SYSFW image\n", 390 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); 391 392 debug("%s: allocated %u bytes at 0x%p\n", __func__, 393 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, sysfw_load_address); 394 395 /* Set load address for legacy modes that bypass spl_get_load_buffer */ 396 spl_image.load_addr = (uintptr_t)sysfw_load_address; 397 398 bootdev.boot_device = spl_boot_device(); 399 400 /* Load combined System Controller firmware and config data image */ 401 switch (bootdev.boot_device) { 402#if CONFIG_IS_ENABLED(MMC) 403 case BOOT_DEVICE_MMC1: 404 case BOOT_DEVICE_MMC2: 405 case BOOT_DEVICE_MMC2_2: 406 ret = spl_mmc_load(&spl_image, &bootdev, 407#ifdef CONFIG_K3_SYSFW_IMAGE_NAME 408 CONFIG_K3_SYSFW_IMAGE_NAME, 409#else 410 NULL, 411#endif 412#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART 413 CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART, 414#else 415 0, 416#endif 417#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT 418 CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT); 419#else 420 0); 421#endif 422 break; 423#endif 424#if CONFIG_IS_ENABLED(SPI_LOAD) 425 case BOOT_DEVICE_SPI: 426 sysfw_spi_base = k3_sysfw_get_spi_addr(); 427 if (!sysfw_spi_base) 428 ret = -ENODEV; 429 k3_sysfw_spi_copy(sysfw_load_address, sysfw_spi_base, 430 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); 431 break; 432#endif 433#if CONFIG_IS_ENABLED(NOR_SUPPORT) 434 case BOOT_DEVICE_HYPERFLASH: 435 sysfw_spi_base = get_sysfw_hf_addr(); 436 if (!sysfw_spi_base) 437 ret = -ENODEV; 438 k3_sysfw_spi_copy(sysfw_load_address, sysfw_spi_base, 439 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); 440 break; 441#endif 442#if CONFIG_IS_ENABLED(YMODEM_SUPPORT) 443 case BOOT_DEVICE_UART: 444#ifdef CONFIG_K3_EARLY_CONS 445 /* 446 * Establish a serial console if not yet available as required 447 * for UART-based boot. For this use the early console feature 448 * that allows setting up a UART for use before SYSFW has been 449 * brought up. Note that the associated UART module's clocks 450 * must have gotten enabled by the ROM bootcode which will be 451 * the case when continuing to boot serially from the same 452 * UART that the ROM loaded the initial bootloader from. 453 */ 454 if (!gd->have_console) 455 early_console_init(); 456#endif 457 ret = spl_ymodem_load_image(&spl_image, &bootdev); 458 break; 459#endif 460#if CONFIG_IS_ENABLED(DFU) 461 case BOOT_DEVICE_DFU: 462 ret = k3_sysfw_dfu_download(sysfw_load_address); 463 break; 464#endif 465#if CONFIG_IS_ENABLED(USB_STORAGE) 466 case BOOT_DEVICE_USB: 467 ret = spl_usb_load(&spl_image, &bootdev, 468 CONFIG_SYS_USB_FAT_BOOT_PARTITION, 469#ifdef CONFIG_K3_SYSFW_IMAGE_NAME 470 CONFIG_K3_SYSFW_IMAGE_NAME); 471#else 472 NULL); 473#endif 474#endif 475 break; 476 default: 477 panic("Loading SYSFW image from device %u not supported!\n", 478 bootdev.boot_device); 479 } 480 481 if (ret) 482 panic("Error %d occurred during loading SYSFW image!\n", ret); 483 484 /* 485 * Now that SYSFW got loaded set helper flag to restore regular SPL 486 * loader behavior so we can later boot into the next stage as expected. 487 */ 488 sysfw_loaded = true; 489 490 /* Ensure the SYSFW image is in FIT format */ 491 if (image_get_magic((const struct legacy_img_hdr *)sysfw_load_address) != 492 FDT_MAGIC) 493 panic("SYSFW image not in FIT format!\n"); 494 495 /* Extract and start SYSFW */ 496 k3_sysfw_load_using_fit(sysfw_load_address); 497 498 /* Get handle for accessing SYSFW services */ 499 ti_sci = get_ti_sci_handle(); 500 501 if (config_pm_pre_callback) 502 config_pm_pre_callback(); 503 504 /* Parse and apply the different SYSFW configuration fragments */ 505 k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci); 506 507 /* 508 * Now that all clocks and PM aspects are setup, invoke a user- 509 * provided callback function. Usually this callback would be used 510 * to setup or re-configure the U-Boot console UART. 511 */ 512 if (config_pm_done_callback) 513 config_pm_done_callback(); 514} 515