blob: b821fb17a1d66edaee6a400af3aa5826d466ec32 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Calvin Johnson781b8382018-03-08 15:30:25 +05302/*
3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +08004 * Copyright 2017,2021 NXP
Calvin Johnson781b8382018-03-08 15:30:25 +05305 */
6
7/*
8 * @file
9 * Contains all the functions to handle parsing and loading of PE firmware
10 * files.
11 */
12
Biwen Lib9eeb082020-11-05 19:28:12 +080013#include <dm.h>
14#include <dm/device-internal.h>
Tom Rinic31301c2025-05-15 17:31:50 -060015#include <env.h>
Simon Glass2dc9c342020-05-10 11:40:01 -060016#include <image.h>
Simon Glass0f2af882020-05-10 11:40:05 -060017#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070018#include <malloc.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060019#include <linux/bitops.h>
Calvin Johnson781b8382018-03-08 15:30:25 +053020#include <net/pfe_eth/pfe_eth.h>
21#include <net/pfe_eth/pfe_firmware.h>
Kuldeep Singh14e956f2020-05-28 11:42:53 +053022#include <spi_flash.h>
Vinitha V Pillaiad698c32018-05-23 11:03:31 +053023#ifdef CONFIG_CHAIN_OF_TRUST
24#include <fsl_validate.h>
25#endif
Calvin Johnson781b8382018-03-08 15:30:25 +053026
Thomas Hebb1dbd3d12019-11-10 08:23:15 -080027#define PFE_FIRMWARE_FIT_CNF_NAME "config@1"
Calvin Johnson781b8382018-03-08 15:30:25 +053028
Kuldeep Singh14e956f2020-05-28 11:42:53 +053029static const void *pfe_fit_addr;
Biwen Lib9eeb082020-11-05 19:28:12 +080030#ifdef CONFIG_CHAIN_OF_TRUST
31static const void *pfe_esbc_hdr_addr;
32#endif
Calvin Johnson781b8382018-03-08 15:30:25 +053033
34/*
35 * PFE elf firmware loader.
36 * Loads an elf firmware image into a list of PE's (specified using a bitmask)
37 *
38 * @param pe_mask Mask of PE id's to load firmware to
39 * @param pfe_firmware Pointer to the firmware image
40 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010041 * Return: 0 on success, a negative value on error
Calvin Johnson781b8382018-03-08 15:30:25 +053042 */
43static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
44{
45 Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
46 Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
47 Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
48 be32_to_cpu(elf_hdr->e_shoff));
49 int id, section;
50 int ret;
51
52 debug("%s: no of sections: %d\n", __func__, sections);
53
54 /* Some sanity checks */
55 if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
56 printf("%s: incorrect elf magic number\n", __func__);
57 return -1;
58 }
59
60 if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
61 printf("%s: incorrect elf class(%x)\n", __func__,
62 elf_hdr->e_ident[EI_CLASS]);
63 return -1;
64 }
65
66 if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
67 printf("%s: incorrect elf data(%x)\n", __func__,
68 elf_hdr->e_ident[EI_DATA]);
69 return -1;
70 }
71
72 if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
73 printf("%s: incorrect elf file type(%x)\n", __func__,
74 be16_to_cpu(elf_hdr->e_type));
75 return -1;
76 }
77
78 for (section = 0; section < sections; section++, shdr++) {
79 if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
80 SHF_EXECINSTR)))
81 continue;
82 for (id = 0; id < MAX_PE; id++)
83 if (pe_mask & BIT(id)) {
84 ret = pe_load_elf_section(id,
85 pfe_firmware, shdr);
86 if (ret < 0)
87 goto err;
88 }
89 }
90 return 0;
91
92err:
93 return ret;
94}
95
96/*
97 * Get PFE firmware from FIT image
98 *
99 * @param data pointer to PFE firmware
100 * @param size pointer to size of the firmware
101 * @param fw_name pfe firmware name, either class or tmu
102 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100103 * Return: 0 on success, a negative value on error
Calvin Johnson781b8382018-03-08 15:30:25 +0530104 */
105static int pfe_get_fw(const void **data,
106 size_t *size, char *fw_name)
107{
Sean Anderson4b2c94f2022-08-16 11:16:06 -0400108 return fit_get_data_conf_prop(pfe_fit_addr, fw_name, data, size);
Calvin Johnson781b8382018-03-08 15:30:25 +0530109}
110
111/*
112 * Check PFE FIT image
113 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100114 * Return: 0 on success, a negative value on error
Calvin Johnson781b8382018-03-08 15:30:25 +0530115 */
116static int pfe_fit_check(void)
117{
118 int ret = 0;
119
120 ret = fdt_check_header(pfe_fit_addr);
121 if (ret) {
122 printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
123 return ret;
124 }
125
Simon Glassd563c252021-02-15 17:08:09 -0700126 if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) {
Calvin Johnson781b8382018-03-08 15:30:25 +0530127 printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
128 ret = -1;
129 return ret;
130 }
131
132 return ret;
133}
134
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530135int pfe_spi_flash_init(void)
136{
137 struct spi_flash *pfe_flash;
138 int ret = 0;
Biwen Lib9eeb082020-11-05 19:28:12 +0800139 void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530140
Kuldeep Singhb363eca2020-09-11 16:36:48 +0530141 if (!addr)
142 return -ENOMEM;
143
Patrice Chotard05b1aa62022-03-30 09:33:14 +0200144 pfe_flash = spi_flash_probe(CONFIG_SYS_FSL_PFE_SPI_BUS,
145 CONFIG_SYS_FSL_PFE_SPI_CS,
146 CONFIG_SYS_FSL_PFE_SPI_MAX_HZ,
147 CONFIG_SYS_FSL_PFE_SPI_MODE);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530148
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530149 if (!pfe_flash) {
150 printf("SF: probe for pfe failed\n");
Kuldeep Singhb363eca2020-09-11 16:36:48 +0530151 free(addr);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530152 return -ENODEV;
153 }
154
155 ret = spi_flash_read(pfe_flash,
156 CONFIG_SYS_LS_PFE_FW_ADDR,
Biwen Lib9eeb082020-11-05 19:28:12 +0800157 CONFIG_SYS_LS_PFE_FW_LENGTH,
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530158 addr);
Biwen Lib9eeb082020-11-05 19:28:12 +0800159 if (ret) {
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530160 printf("SF: read for pfe failed\n");
Biwen Lib9eeb082020-11-05 19:28:12 +0800161 free(addr);
162 spi_flash_free(pfe_flash);
163 return ret;
164 }
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530165
Biwen Lib9eeb082020-11-05 19:28:12 +0800166#ifdef CONFIG_CHAIN_OF_TRUST
167 void *hdr_addr = malloc(CONFIG_SYS_LS_PFE_ESBC_LENGTH);
168
169 if (!hdr_addr) {
170 free(addr);
171 spi_flash_free(pfe_flash);
172 return -ENOMEM;
173 }
174
175 ret = spi_flash_read(pfe_flash,
176 CONFIG_SYS_LS_PFE_ESBC_ADDR,
177 CONFIG_SYS_LS_PFE_ESBC_LENGTH,
178 hdr_addr);
179 if (ret) {
180 printf("SF: failed to read pfe esbc header\n");
181 free(addr);
182 free(hdr_addr);
183 spi_flash_free(pfe_flash);
184 return ret;
185 }
186
187 pfe_esbc_hdr_addr = hdr_addr;
188#endif
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530189 pfe_fit_addr = addr;
190 spi_flash_free(pfe_flash);
191
192 return ret;
193}
194
Calvin Johnson781b8382018-03-08 15:30:25 +0530195/*
196 * PFE firmware initialization.
197 * Loads different firmware files from FIT image.
198 * Initializes PE IMEM/DMEM and UTIL-PE DDR
199 * Initializes control path symbol addresses (by looking them up in the elf
200 * firmware files
201 * Takes PE's out of reset
202 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100203 * Return: 0 on success, a negative value on error
Calvin Johnson781b8382018-03-08 15:30:25 +0530204 */
205int pfe_firmware_init(void)
206{
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530207#define PFE_KEY_HASH NULL
Calvin Johnson781b8382018-03-08 15:30:25 +0530208 char *pfe_firmware_name;
209 const void *raw_image_addr;
210 size_t raw_image_size = 0;
211 u8 *pfe_firmware;
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530212#ifdef CONFIG_CHAIN_OF_TRUST
213 uintptr_t pfe_esbc_hdr = 0;
214 uintptr_t pfe_img_addr = 0;
215#endif
Calvin Johnson781b8382018-03-08 15:30:25 +0530216 int ret = 0;
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +0800217 int fw_count, max_fw_count;
218 const char *p;
Calvin Johnson781b8382018-03-08 15:30:25 +0530219
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530220 ret = pfe_spi_flash_init();
221 if (ret)
222 goto err;
223
Calvin Johnson781b8382018-03-08 15:30:25 +0530224 ret = pfe_fit_check();
225 if (ret)
226 goto err;
227
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530228#ifdef CONFIG_CHAIN_OF_TRUST
Biwen Lib9eeb082020-11-05 19:28:12 +0800229 pfe_esbc_hdr = (uintptr_t)pfe_esbc_hdr_addr;
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530230 pfe_img_addr = (uintptr_t)pfe_fit_addr;
231 if (fsl_check_boot_mode_secure() != 0) {
232 /*
233 * In case of failure in validation, fsl_secboot_validate
234 * would not return back in case of Production environment
235 * with ITS=1. In Development environment (ITS=0 and
236 * SB_EN=1), the function may return back in case of
237 * non-fatal failures.
238 */
239 ret = fsl_secboot_validate(pfe_esbc_hdr,
240 PFE_KEY_HASH,
241 &pfe_img_addr);
242 if (ret != 0)
243 printf("PFE firmware(s) validation failed\n");
244 else
245 printf("PFE firmware(s) validation Successful\n");
246 }
247#endif
248
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +0800249 p = env_get("load_util");
250 if (!p) {
251 max_fw_count = 2;
252 } else {
Simon Glassff9b9032021-07-24 09:03:30 -0600253 max_fw_count = dectoul(p, NULL);
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +0800254 if (max_fw_count)
255 max_fw_count = 3;
256 else
257 max_fw_count = 2;
258 }
259
260 for (fw_count = 0; fw_count < max_fw_count; fw_count++) {
261 switch (fw_count) {
262 case 0:
263 pfe_firmware_name = "class_slowpath";
264 break;
265 case 1:
266 pfe_firmware_name = "tmu_slowpath";
267 break;
268 case 2:
269 pfe_firmware_name = "util_slowpath";
270 break;
271 }
272
273 if (pfe_get_fw(&raw_image_addr, &raw_image_size,
274 pfe_firmware_name)) {
275 printf("%s firmware couldn't be found in FIT image\n",
276 pfe_firmware_name);
277 break;
278 }
279 pfe_firmware = malloc(raw_image_size);
280 if (!pfe_firmware)
281 return -ENOMEM;
282 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
283 raw_image_size);
284
285 switch (fw_count) {
286 case 0:
287 env_set_addr("class_elf_firmware", pfe_firmware);
288 env_set_addr("class_elf_size", (void *)raw_image_size);
289 break;
290 case 1:
291 env_set_addr("tmu_elf_firmware", pfe_firmware);
292 env_set_addr("tmu_elf_size", (void *)raw_image_size);
293 break;
294 case 2:
295 env_set_addr("util_elf_firmware", pfe_firmware);
296 env_set_addr("util_elf_size", (void *)raw_image_size);
297 break;
298 }
299 }
300
301 raw_image_addr = NULL;
302 pfe_firmware = NULL;
303 raw_image_size = 0;
Calvin Johnson781b8382018-03-08 15:30:25 +0530304 for (fw_count = 0; fw_count < 2; fw_count++) {
305 if (fw_count == 0)
306 pfe_firmware_name = "class";
307 else if (fw_count == 1)
308 pfe_firmware_name = "tmu";
309
310 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
311 pfe_firmware = malloc(raw_image_size);
312 if (!pfe_firmware)
313 return -ENOMEM;
314 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
315 raw_image_size);
316
317 if (fw_count == 0)
318 ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
319 else if (fw_count == 1)
320 ret = pfe_load_elf(TMU_MASK, pfe_firmware);
321
322 if (ret < 0) {
323 printf("%s: %s firmware load failed\n", __func__,
324 pfe_firmware_name);
325 goto err;
326 }
327 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
328 free(pfe_firmware);
329 }
330
331 tmu_enable(0xb);
332 class_enable();
333 gpi_enable(HGPI_BASE_ADDR);
334
335err:
336 return ret;
337}
338
339/*
340 * PFE firmware cleanup
341 * Puts PE's in reset
342 */
343void pfe_firmware_exit(void)
344{
345 debug("%s\n", __func__);
346
347 class_disable();
348 tmu_disable(0xf);
349 hif_tx_disable();
350 hif_rx_disable();
351}