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