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