blob: 78c158c63f71f3220dc57507f344d2428a3c3199 [file] [log] [blame]
Andreas Dannenberg6df87062019-06-04 17:55:47 -05001// 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
9#include <common.h>
Simon Glassa00867b2020-07-19 10:15:40 -060010#include <dm.h>
Simon Glass4d72caa2020-05-10 11:40:01 -060011#include <image.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060012#include <log.h>
Andreas Dannenberg6df87062019-06-04 17:55:47 -050013#include <spl.h>
14#include <malloc.h>
15#include <remoteproc.h>
Simon Glass90526e92020-05-10 11:39:56 -060016#include <asm/cache.h>
Andreas Dannenberg6df87062019-06-04 17:55:47 -050017#include <linux/soc/ti/ti_sci_protocol.h>
Vignesh Raghavendrae15b6e32020-01-27 17:59:24 +053018#include <g_dnl.h>
19#include <usb.h>
20#include <dfu.h>
Lokesh Vutla7d0866b2020-02-04 11:09:50 +053021#include <dm/uclass-internal.h>
22#include <spi_flash.h>
Vignesh Raghavendrae15b6e32020-01-27 17:59:24 +053023
Andreas Dannenberg6df87062019-06-04 17:55:47 -050024#include <asm/arch/sys_proto.h>
Andreas Dannenberg921b3252019-08-15 15:55:29 -050025#include "common.h"
26
27DECLARE_GLOBAL_DATA_PTR;
Andreas Dannenberg6df87062019-06-04 17:55:47 -050028
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
Lokesh Vutladc57a552020-08-05 22:44:18 +053036/*
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
Andreas Dannenberg6df87062019-06-04 17:55:47 -050042static bool sysfw_loaded;
43static void *sysfw_load_address;
44
45/*
46 * Populate SPL hook to override the default load address used by the SPL
47 * loader function with a custom address for SYSFW loading.
48 */
49struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
50{
51 if (sysfw_loaded)
52 return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
53 else if (sysfw_load_address)
54 return sysfw_load_address;
55 else
56 panic("SYSFW load address not defined!");
57}
58
59/*
60 * Populate SPL hook to skip the default SPL loader FIT post-processing steps
61 * during SYSFW loading and return to the calling function so we can perform
62 * our own custom processing.
63 */
64bool spl_load_simple_fit_skip_processing(void)
65{
66 return !sysfw_loaded;
67}
68
69static int fit_get_data_by_name(const void *fit, int images, const char *name,
70 const void **addr, size_t *size)
71{
72 int node_offset;
73
74 node_offset = fdt_subnode_offset(fit, images, name);
75 if (node_offset < 0)
76 return -ENOENT;
77
78 return fit_image_get_data(fit, node_offset, addr, size);
79}
80
Lokesh Vutladc57a552020-08-05 22:44:18 +053081static void k3_start_system_controller(int rproc_id, bool rproc_loaded,
82 ulong addr, ulong size)
83{
84 int ret;
85
86 ret = rproc_dev_init(rproc_id);
87 if (ret)
88 panic("rproc failed to be initialized (%d)\n", ret);
89
90 if (!rproc_loaded) {
91 ret = rproc_load(rproc_id, addr, size);
92 if (ret)
93 panic("Firmware failed to start on rproc (%d)\n", ret);
94 }
95
96 ret = rproc_start(0);
97 if (ret)
98 panic("Firmware init failed on rproc (%d)\n", ret);
99}
100
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500101static void k3_sysfw_load_using_fit(void *fit)
102{
103 int images;
104 const void *sysfw_addr;
105 size_t sysfw_size;
106 int ret;
107
108 /* Find the node holding the images information */
109 images = fdt_path_offset(fit, FIT_IMAGES_PATH);
110 if (images < 0)
111 panic("Cannot find /images node (%d)\n", images);
112
113 /* Extract System Firmware (SYSFW) image from FIT */
114 ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE,
115 &sysfw_addr, &sysfw_size);
116 if (ret < 0)
117 panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE,
118 ret);
119
Lokesh Vutladc57a552020-08-05 22:44:18 +0530120 /* Start up system controller firmware */
121 k3_start_system_controller(K3_SYSTEM_CONTROLLER_RPROC_ID, false,
122 (ulong)sysfw_addr, (ulong)sysfw_size);
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500123}
124
125static void k3_sysfw_configure_using_fit(void *fit,
126 struct ti_sci_handle *ti_sci)
127{
128 struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops;
129 int images;
130 const void *cfg_fragment_addr;
131 size_t cfg_fragment_size;
132 int ret;
133
134 /* Find the node holding the images information */
135 images = fdt_path_offset(fit, FIT_IMAGES_PATH);
136 if (images < 0)
137 panic("Cannot find /images node (%d)\n", images);
138
139 /* Extract board configuration from FIT */
140 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD,
141 &cfg_fragment_addr, &cfg_fragment_size);
142 if (ret < 0)
143 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD,
144 ret);
145
146 /* Apply board configuration to SYSFW */
147 ret = board_ops->board_config(ti_sci,
148 (u64)(u32)cfg_fragment_addr,
149 (u32)cfg_fragment_size);
150 if (ret)
151 panic("Failed to set board configuration (%d)\n", ret);
152
153 /* Extract power/clock (PM) specific configuration from FIT */
154 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM,
155 &cfg_fragment_addr, &cfg_fragment_size);
156 if (ret < 0)
157 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM,
158 ret);
159
160 /* Apply power/clock (PM) specific configuration to SYSFW */
161 ret = board_ops->board_config_pm(ti_sci,
162 (u64)(u32)cfg_fragment_addr,
163 (u32)cfg_fragment_size);
164 if (ret)
165 panic("Failed to set board PM configuration (%d)\n", ret);
166
167 /* Extract resource management (RM) specific configuration from FIT */
168 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM,
169 &cfg_fragment_addr, &cfg_fragment_size);
170 if (ret < 0)
171 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM,
172 ret);
173
174 /* Apply resource management (RM) configuration to SYSFW */
175 ret = board_ops->board_config_rm(ti_sci,
176 (u64)(u32)cfg_fragment_addr,
177 (u32)cfg_fragment_size);
178 if (ret)
179 panic("Failed to set board RM configuration (%d)\n", ret);
180
181 /* Extract security specific configuration from FIT */
182 ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC,
183 &cfg_fragment_addr, &cfg_fragment_size);
184 if (ret < 0)
185 panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC,
186 ret);
187
188 /* Apply security configuration to SYSFW */
189 ret = board_ops->board_config_security(ti_sci,
190 (u64)(u32)cfg_fragment_addr,
191 (u32)cfg_fragment_size);
192 if (ret)
193 panic("Failed to set board security configuration (%d)\n",
194 ret);
195}
196
Vignesh Raghavendrae15b6e32020-01-27 17:59:24 +0530197#if CONFIG_IS_ENABLED(DFU)
198static int k3_sysfw_dfu_download(void *addr)
199{
200 char dfu_str[50];
201 int ret;
202
203 sprintf(dfu_str, "sysfw.itb ram 0x%p 0x%x", addr,
204 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
205 ret = dfu_config_entities(dfu_str, "ram", "0");
206 if (ret) {
207 dfu_free_entities();
208 goto exit;
209 }
210
211 run_usb_dnl_gadget(0, "usb_dnl_dfu");
212exit:
213 dfu_free_entities();
214 return ret;
215}
216#endif
217
Lokesh Vutla7d0866b2020-02-04 11:09:50 +0530218#if CONFIG_IS_ENABLED(SPI_LOAD)
219static void *k3_sysfw_get_spi_addr(void)
220{
221 struct udevice *dev;
222 fdt_addr_t addr;
223 int ret;
224
225 ret = uclass_find_device_by_seq(UCLASS_SPI, CONFIG_SF_DEFAULT_BUS,
226 true, &dev);
227 if (ret)
228 return NULL;
229
230 addr = dev_read_addr_index(dev, 1);
231 if (addr == FDT_ADDR_T_NONE)
232 return NULL;
233
234 return (void *)(addr + CONFIG_K3_SYSFW_IMAGE_SPI_OFFS);
235}
236#endif
237
Lokesh Vutladc57a552020-08-05 22:44:18 +0530238void k3_sysfw_loader(bool rom_loaded_sysfw,
239 void (*config_pm_pre_callback)(void),
Faiz Abbasd45ffb72020-02-26 13:44:36 +0530240 void (*config_pm_done_callback)(void))
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500241{
242 struct spl_image_info spl_image = { 0 };
243 struct spl_boot_device bootdev = { 0 };
244 struct ti_sci_handle *ti_sci;
Lokesh Vutla7d0866b2020-02-04 11:09:50 +0530245 int ret = 0;
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500246
Lokesh Vutladc57a552020-08-05 22:44:18 +0530247 if (rom_loaded_sysfw) {
248 k3_start_system_controller(K3_SYSTEM_CONTROLLER_RPROC_ID,
249 rom_loaded_sysfw, 0, 0);
250 sysfw_loaded = true;
251 return;
252 }
253
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500254 /* Reserve a block of aligned memory for loading the SYSFW image */
255 sysfw_load_address = memalign(ARCH_DMA_MINALIGN,
256 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
257 if (!sysfw_load_address)
258 panic("Error allocating %u bytes of memory for SYSFW image\n",
259 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
260
261 debug("%s: allocated %u bytes at 0x%p\n", __func__,
262 CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, sysfw_load_address);
263
264 /* Set load address for legacy modes that bypass spl_get_load_buffer */
265 spl_image.load_addr = (uintptr_t)sysfw_load_address;
266
267 bootdev.boot_device = spl_boot_device();
268
269 /* Load combined System Controller firmware and config data image */
270 switch (bootdev.boot_device) {
271#if CONFIG_IS_ENABLED(MMC_SUPPORT)
272 case BOOT_DEVICE_MMC1:
273 case BOOT_DEVICE_MMC2:
274 case BOOT_DEVICE_MMC2_2:
275 ret = spl_mmc_load(&spl_image, &bootdev,
276#ifdef CONFIG_K3_SYSFW_IMAGE_NAME
277 CONFIG_K3_SYSFW_IMAGE_NAME,
278#else
279 NULL,
280#endif
281#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART
282 CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART,
283#else
284 0,
285#endif
286#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT
287 CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT);
288#else
289 0);
290#endif
291 break;
292#endif
Lokesh Vutla7d0866b2020-02-04 11:09:50 +0530293#if CONFIG_IS_ENABLED(SPI_LOAD)
294 case BOOT_DEVICE_SPI:
295 sysfw_load_address = k3_sysfw_get_spi_addr();
296 if (!sysfw_load_address)
297 ret = -ENODEV;
298 break;
299#endif
Andreas Dannenberg921b3252019-08-15 15:55:29 -0500300#if CONFIG_IS_ENABLED(YMODEM_SUPPORT)
301 case BOOT_DEVICE_UART:
302#ifdef CONFIG_K3_EARLY_CONS
303 /*
304 * Establish a serial console if not yet available as required
305 * for UART-based boot. For this use the early console feature
306 * that allows setting up a UART for use before SYSFW has been
307 * brought up. Note that the associated UART module's clocks
308 * must have gotten enabled by the ROM bootcode which will be
309 * the case when continuing to boot serially from the same
310 * UART that the ROM loaded the initial bootloader from.
311 */
312 if (!gd->have_console)
313 early_console_init();
314#endif
315 ret = spl_ymodem_load_image(&spl_image, &bootdev);
316 break;
317#endif
Vignesh Raghavendrae15b6e32020-01-27 17:59:24 +0530318#if CONFIG_IS_ENABLED(DFU)
319 case BOOT_DEVICE_DFU:
320 ret = k3_sysfw_dfu_download(sysfw_load_address);
321 break;
322#endif
Faiz Abbasf5838b12020-08-03 11:35:07 +0530323#if CONFIG_IS_ENABLED(USB_STORAGE)
324 case BOOT_DEVICE_USB:
325 ret = spl_usb_load(&spl_image, &bootdev,
326 CONFIG_SYS_USB_FAT_BOOT_PARTITION,
327#ifdef CONFIG_K3_SYSFW_IMAGE_NAME
328 CONFIG_K3_SYSFW_IMAGE_NAME);
329#else
330 NULL);
331#endif
332#endif
333 break;
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500334 default:
335 panic("Loading SYSFW image from device %u not supported!\n",
336 bootdev.boot_device);
337 }
338
339 if (ret)
340 panic("Error %d occurred during loading SYSFW image!\n", ret);
341
342 /*
343 * Now that SYSFW got loaded set helper flag to restore regular SPL
344 * loader behavior so we can later boot into the next stage as expected.
345 */
346 sysfw_loaded = true;
347
348 /* Ensure the SYSFW image is in FIT format */
349 if (image_get_magic((const image_header_t *)sysfw_load_address) !=
350 FDT_MAGIC)
351 panic("SYSFW image not in FIT format!\n");
352
353 /* Extract and start SYSFW */
354 k3_sysfw_load_using_fit(sysfw_load_address);
355
356 /* Get handle for accessing SYSFW services */
357 ti_sci = get_ti_sci_handle();
358
Faiz Abbasd45ffb72020-02-26 13:44:36 +0530359 if (config_pm_pre_callback)
360 config_pm_pre_callback();
361
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500362 /* Parse and apply the different SYSFW configuration fragments */
363 k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci);
364
365 /*
366 * Now that all clocks and PM aspects are setup, invoke a user-
367 * provided callback function. Usually this callback would be used
368 * to setup or re-configure the U-Boot console UART.
369 */
370 if (config_pm_done_callback)
371 config_pm_done_callback();
Andreas Dannenberg6df87062019-06-04 17:55:47 -0500372}