sysfw-loader.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * K3: System Firmware Loader
  4. *
  5. * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
  6. * Andreas Dannenberg <dannenberg@ti.com>
  7. */
  8. #include <common.h>
  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. #include <asm/arch/sys_proto.h>
  24. #include "common.h"
  25. DECLARE_GLOBAL_DATA_PTR;
  26. /* Name of the FIT image nodes for SYSFW and its config data */
  27. #define SYSFW_FIRMWARE "sysfw.bin"
  28. #define SYSFW_CFG_BOARD "board-cfg.bin"
  29. #define SYSFW_CFG_PM "pm-cfg.bin"
  30. #define SYSFW_CFG_RM "rm-cfg.bin"
  31. #define SYSFW_CFG_SEC "sec-cfg.bin"
  32. /*
  33. * It is assumed that remoteproc device 0 is the corresponding
  34. * system-controller that runs SYSFW. Make sure DT reflects the same.
  35. */
  36. #define K3_SYSTEM_CONTROLLER_RPROC_ID 0
  37. static bool sysfw_loaded;
  38. static void *sysfw_load_address;
  39. /*
  40. * Populate SPL hook to override the default load address used by the SPL
  41. * loader function with a custom address for SYSFW loading.
  42. */
  43. struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
  44. {
  45. if (sysfw_loaded)
  46. return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
  47. else if (sysfw_load_address)
  48. return sysfw_load_address;
  49. else
  50. panic("SYSFW load address not defined!");
  51. }
  52. /*
  53. * Populate SPL hook to skip the default SPL loader FIT post-processing steps
  54. * during SYSFW loading and return to the calling function so we can perform
  55. * our own custom processing.
  56. */
  57. bool spl_load_simple_fit_skip_processing(void)
  58. {
  59. return !sysfw_loaded;
  60. }
  61. static int fit_get_data_by_name(const void *fit, int images, const char *name,
  62. const void **addr, size_t *size)
  63. {
  64. int node_offset;
  65. node_offset = fdt_subnode_offset(fit, images, name);
  66. if (node_offset < 0)
  67. return -ENOENT;
  68. return fit_image_get_data(fit, node_offset, addr, size);
  69. }
  70. static void k3_start_system_controller(int rproc_id, bool rproc_loaded,
  71. ulong addr, ulong size)
  72. {
  73. int ret;
  74. ret = rproc_dev_init(rproc_id);
  75. if (ret)
  76. panic("rproc failed to be initialized (%d)\n", ret);
  77. if (!rproc_loaded) {
  78. ret = rproc_load(rproc_id, addr, size);
  79. if (ret)
  80. panic("Firmware failed to start on rproc (%d)\n", ret);
  81. }
  82. ret = rproc_start(0);
  83. if (ret)
  84. panic("Firmware init failed on rproc (%d)\n", ret);
  85. }
  86. static void k3_sysfw_load_using_fit(void *fit)
  87. {
  88. int images;
  89. const void *sysfw_addr;
  90. size_t sysfw_size;
  91. int ret;
  92. /* Find the node holding the images information */
  93. images = fdt_path_offset(fit, FIT_IMAGES_PATH);
  94. if (images < 0)
  95. panic("Cannot find /images node (%d)\n", images);
  96. /* Extract System Firmware (SYSFW) image from FIT */
  97. ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE,
  98. &sysfw_addr, &sysfw_size);
  99. if (ret < 0)
  100. panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE,
  101. ret);
  102. /* Start up system controller firmware */
  103. k3_start_system_controller(K3_SYSTEM_CONTROLLER_RPROC_ID, false,
  104. (ulong)sysfw_addr, (ulong)sysfw_size);
  105. }
  106. static void k3_sysfw_configure_using_fit(void *fit,
  107. struct ti_sci_handle *ti_sci)
  108. {
  109. struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops;
  110. int images;
  111. const void *cfg_fragment_addr;
  112. size_t cfg_fragment_size;
  113. int ret;
  114. /* Find the node holding the images information */
  115. images = fdt_path_offset(fit, FIT_IMAGES_PATH);
  116. if (images < 0)
  117. panic("Cannot find /images node (%d)\n", images);
  118. /* Extract board configuration from FIT */
  119. ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD,
  120. &cfg_fragment_addr, &cfg_fragment_size);
  121. if (ret < 0)
  122. panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD,
  123. ret);
  124. /* Apply board configuration to SYSFW */
  125. ret = board_ops->board_config(ti_sci,
  126. (u64)(u32)cfg_fragment_addr,
  127. (u32)cfg_fragment_size);
  128. if (ret)
  129. panic("Failed to set board configuration (%d)\n", ret);
  130. /* Extract power/clock (PM) specific configuration from FIT */
  131. ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM,
  132. &cfg_fragment_addr, &cfg_fragment_size);
  133. if (ret < 0)
  134. panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM,
  135. ret);
  136. /* Apply power/clock (PM) specific configuration to SYSFW */
  137. ret = board_ops->board_config_pm(ti_sci,
  138. (u64)(u32)cfg_fragment_addr,
  139. (u32)cfg_fragment_size);
  140. if (ret)
  141. panic("Failed to set board PM configuration (%d)\n", ret);
  142. /* Extract resource management (RM) specific configuration from FIT */
  143. ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM,
  144. &cfg_fragment_addr, &cfg_fragment_size);
  145. if (ret < 0)
  146. panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM,
  147. ret);
  148. /* Apply resource management (RM) configuration to SYSFW */
  149. ret = board_ops->board_config_rm(ti_sci,
  150. (u64)(u32)cfg_fragment_addr,
  151. (u32)cfg_fragment_size);
  152. if (ret)
  153. panic("Failed to set board RM configuration (%d)\n", ret);
  154. /* Extract security specific configuration from FIT */
  155. ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC,
  156. &cfg_fragment_addr, &cfg_fragment_size);
  157. if (ret < 0)
  158. panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC,
  159. ret);
  160. /* Apply security configuration to SYSFW */
  161. ret = board_ops->board_config_security(ti_sci,
  162. (u64)(u32)cfg_fragment_addr,
  163. (u32)cfg_fragment_size);
  164. if (ret)
  165. panic("Failed to set board security configuration (%d)\n",
  166. ret);
  167. }
  168. #if CONFIG_IS_ENABLED(DFU)
  169. static int k3_sysfw_dfu_download(void *addr)
  170. {
  171. char dfu_str[50];
  172. int ret;
  173. sprintf(dfu_str, "sysfw.itb ram 0x%p 0x%x", addr,
  174. CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
  175. ret = dfu_config_entities(dfu_str, "ram", "0");
  176. if (ret) {
  177. dfu_free_entities();
  178. goto exit;
  179. }
  180. run_usb_dnl_gadget(0, "usb_dnl_dfu");
  181. exit:
  182. dfu_free_entities();
  183. return ret;
  184. }
  185. #endif
  186. #if CONFIG_IS_ENABLED(SPI_LOAD)
  187. static void *k3_sysfw_get_spi_addr(void)
  188. {
  189. struct udevice *dev;
  190. fdt_addr_t addr;
  191. int ret;
  192. ret = uclass_find_device_by_seq(UCLASS_SPI, CONFIG_SF_DEFAULT_BUS,
  193. &dev);
  194. if (ret)
  195. return NULL;
  196. addr = dev_read_addr_index(dev, 1);
  197. if (addr == FDT_ADDR_T_NONE)
  198. return NULL;
  199. return (void *)(addr + CONFIG_K3_SYSFW_IMAGE_SPI_OFFS);
  200. }
  201. #endif
  202. void k3_sysfw_loader(bool rom_loaded_sysfw,
  203. void (*config_pm_pre_callback)(void),
  204. void (*config_pm_done_callback)(void))
  205. {
  206. struct spl_image_info spl_image = { 0 };
  207. struct spl_boot_device bootdev = { 0 };
  208. struct ti_sci_handle *ti_sci;
  209. int ret = 0;
  210. if (rom_loaded_sysfw) {
  211. k3_start_system_controller(K3_SYSTEM_CONTROLLER_RPROC_ID,
  212. rom_loaded_sysfw, 0, 0);
  213. sysfw_loaded = true;
  214. return;
  215. }
  216. /* Reserve a block of aligned memory for loading the SYSFW image */
  217. sysfw_load_address = memalign(ARCH_DMA_MINALIGN,
  218. CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
  219. if (!sysfw_load_address)
  220. panic("Error allocating %u bytes of memory for SYSFW image\n",
  221. CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
  222. debug("%s: allocated %u bytes at 0x%p\n", __func__,
  223. CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, sysfw_load_address);
  224. /* Set load address for legacy modes that bypass spl_get_load_buffer */
  225. spl_image.load_addr = (uintptr_t)sysfw_load_address;
  226. bootdev.boot_device = spl_boot_device();
  227. /* Load combined System Controller firmware and config data image */
  228. switch (bootdev.boot_device) {
  229. #if CONFIG_IS_ENABLED(MMC_SUPPORT)
  230. case BOOT_DEVICE_MMC1:
  231. case BOOT_DEVICE_MMC2:
  232. case BOOT_DEVICE_MMC2_2:
  233. ret = spl_mmc_load(&spl_image, &bootdev,
  234. #ifdef CONFIG_K3_SYSFW_IMAGE_NAME
  235. CONFIG_K3_SYSFW_IMAGE_NAME,
  236. #else
  237. NULL,
  238. #endif
  239. #ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART
  240. CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART,
  241. #else
  242. 0,
  243. #endif
  244. #ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT
  245. CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT);
  246. #else
  247. 0);
  248. #endif
  249. break;
  250. #endif
  251. #if CONFIG_IS_ENABLED(SPI_LOAD)
  252. case BOOT_DEVICE_SPI:
  253. sysfw_load_address = k3_sysfw_get_spi_addr();
  254. if (!sysfw_load_address)
  255. ret = -ENODEV;
  256. break;
  257. #endif
  258. #if CONFIG_IS_ENABLED(YMODEM_SUPPORT)
  259. case BOOT_DEVICE_UART:
  260. #ifdef CONFIG_K3_EARLY_CONS
  261. /*
  262. * Establish a serial console if not yet available as required
  263. * for UART-based boot. For this use the early console feature
  264. * that allows setting up a UART for use before SYSFW has been
  265. * brought up. Note that the associated UART module's clocks
  266. * must have gotten enabled by the ROM bootcode which will be
  267. * the case when continuing to boot serially from the same
  268. * UART that the ROM loaded the initial bootloader from.
  269. */
  270. if (!gd->have_console)
  271. early_console_init();
  272. #endif
  273. ret = spl_ymodem_load_image(&spl_image, &bootdev);
  274. break;
  275. #endif
  276. #if CONFIG_IS_ENABLED(DFU)
  277. case BOOT_DEVICE_DFU:
  278. ret = k3_sysfw_dfu_download(sysfw_load_address);
  279. break;
  280. #endif
  281. #if CONFIG_IS_ENABLED(USB_STORAGE)
  282. case BOOT_DEVICE_USB:
  283. ret = spl_usb_load(&spl_image, &bootdev,
  284. CONFIG_SYS_USB_FAT_BOOT_PARTITION,
  285. #ifdef CONFIG_K3_SYSFW_IMAGE_NAME
  286. CONFIG_K3_SYSFW_IMAGE_NAME);
  287. #else
  288. NULL);
  289. #endif
  290. #endif
  291. break;
  292. default:
  293. panic("Loading SYSFW image from device %u not supported!\n",
  294. bootdev.boot_device);
  295. }
  296. if (ret)
  297. panic("Error %d occurred during loading SYSFW image!\n", ret);
  298. /*
  299. * Now that SYSFW got loaded set helper flag to restore regular SPL
  300. * loader behavior so we can later boot into the next stage as expected.
  301. */
  302. sysfw_loaded = true;
  303. /* Ensure the SYSFW image is in FIT format */
  304. if (image_get_magic((const image_header_t *)sysfw_load_address) !=
  305. FDT_MAGIC)
  306. panic("SYSFW image not in FIT format!\n");
  307. /* Extract and start SYSFW */
  308. k3_sysfw_load_using_fit(sysfw_load_address);
  309. /* Get handle for accessing SYSFW services */
  310. ti_sci = get_ti_sci_handle();
  311. if (config_pm_pre_callback)
  312. config_pm_pre_callback();
  313. /* Parse and apply the different SYSFW configuration fragments */
  314. k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci);
  315. /*
  316. * Now that all clocks and PM aspects are setup, invoke a user-
  317. * provided callback function. Usually this callback would be used
  318. * to setup or re-configure the U-Boot console UART.
  319. */
  320. if (config_pm_done_callback)
  321. config_pm_done_callback();
  322. }