blob: ad5bc3c8624e5f02ea613ae05e8463e000a08eea [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>
Simon Glass2dc9c342020-05-10 11:40:01 -060015#include <image.h>
Simon Glass0f2af882020-05-10 11:40:05 -060016#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070017#include <malloc.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060018#include <linux/bitops.h>
Calvin Johnson781b8382018-03-08 15:30:25 +053019#include <net/pfe_eth/pfe_eth.h>
20#include <net/pfe_eth/pfe_firmware.h>
Kuldeep Singh14e956f2020-05-28 11:42:53 +053021#include <spi_flash.h>
Vinitha V Pillaiad698c32018-05-23 11:03:31 +053022#ifdef CONFIG_CHAIN_OF_TRUST
23#include <fsl_validate.h>
24#endif
Calvin Johnson781b8382018-03-08 15:30:25 +053025
Thomas Hebb1dbd3d12019-11-10 08:23:15 -080026#define PFE_FIRMWARE_FIT_CNF_NAME "config@1"
Calvin Johnson781b8382018-03-08 15:30:25 +053027
Kuldeep Singh14e956f2020-05-28 11:42:53 +053028static const void *pfe_fit_addr;
Biwen Lib9eeb082020-11-05 19:28:12 +080029#ifdef CONFIG_CHAIN_OF_TRUST
30static const void *pfe_esbc_hdr_addr;
31#endif
Calvin Johnson781b8382018-03-08 15:30:25 +053032
33/*
34 * PFE elf firmware loader.
35 * Loads an elf firmware image into a list of PE's (specified using a bitmask)
36 *
37 * @param pe_mask Mask of PE id's to load firmware to
38 * @param pfe_firmware Pointer to the firmware image
39 *
40 * @return 0 on success, a negative value on error
41 */
42static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
43{
44 Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
45 Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
46 Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
47 be32_to_cpu(elf_hdr->e_shoff));
48 int id, section;
49 int ret;
50
51 debug("%s: no of sections: %d\n", __func__, sections);
52
53 /* Some sanity checks */
54 if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
55 printf("%s: incorrect elf magic number\n", __func__);
56 return -1;
57 }
58
59 if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
60 printf("%s: incorrect elf class(%x)\n", __func__,
61 elf_hdr->e_ident[EI_CLASS]);
62 return -1;
63 }
64
65 if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
66 printf("%s: incorrect elf data(%x)\n", __func__,
67 elf_hdr->e_ident[EI_DATA]);
68 return -1;
69 }
70
71 if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
72 printf("%s: incorrect elf file type(%x)\n", __func__,
73 be16_to_cpu(elf_hdr->e_type));
74 return -1;
75 }
76
77 for (section = 0; section < sections; section++, shdr++) {
78 if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
79 SHF_EXECINSTR)))
80 continue;
81 for (id = 0; id < MAX_PE; id++)
82 if (pe_mask & BIT(id)) {
83 ret = pe_load_elf_section(id,
84 pfe_firmware, shdr);
85 if (ret < 0)
86 goto err;
87 }
88 }
89 return 0;
90
91err:
92 return ret;
93}
94
95/*
96 * Get PFE firmware from FIT image
97 *
98 * @param data pointer to PFE firmware
99 * @param size pointer to size of the firmware
100 * @param fw_name pfe firmware name, either class or tmu
101 *
102 * @return 0 on success, a negative value on error
103 */
104static int pfe_get_fw(const void **data,
105 size_t *size, char *fw_name)
106{
107 int conf_node_off, fw_node_off;
108 char *conf_node_name = NULL;
109 char *desc;
110 int ret = 0;
111
Thomas Hebb1dbd3d12019-11-10 08:23:15 -0800112 conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
Calvin Johnson781b8382018-03-08 15:30:25 +0530113
114 conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name);
115 if (conf_node_off < 0) {
116 printf("PFE Firmware: %s: no such config\n", conf_node_name);
117 return -ENOENT;
118 }
119
120 fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off,
121 fw_name);
122 if (fw_node_off < 0) {
123 printf("PFE Firmware: No '%s' in config\n",
124 fw_name);
125 return -ENOLINK;
126 }
127
128 if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) {
129 printf("PFE Firmware: Bad firmware image (bad CRC)\n");
130 return -EINVAL;
131 }
132
133 if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) {
134 printf("PFE Firmware: Can't get %s subimage data/size",
135 fw_name);
136 return -ENOENT;
137 }
138
139 ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc);
140 if (ret)
141 printf("PFE Firmware: Can't get description\n");
142 else
143 printf("%s\n", desc);
144
145 return ret;
146}
147
148/*
149 * Check PFE FIT image
150 *
151 * @return 0 on success, a negative value on error
152 */
153static int pfe_fit_check(void)
154{
155 int ret = 0;
156
157 ret = fdt_check_header(pfe_fit_addr);
158 if (ret) {
159 printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
160 return ret;
161 }
162
Simon Glassd563c252021-02-15 17:08:09 -0700163 if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) {
Calvin Johnson781b8382018-03-08 15:30:25 +0530164 printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
165 ret = -1;
166 return ret;
167 }
168
169 return ret;
170}
171
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530172int pfe_spi_flash_init(void)
173{
174 struct spi_flash *pfe_flash;
Kuldeep Singha009ab32020-09-11 16:36:49 +0530175 struct udevice *new;
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530176 int ret = 0;
Biwen Lib9eeb082020-11-05 19:28:12 +0800177 void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530178
Kuldeep Singhb363eca2020-09-11 16:36:48 +0530179 if (!addr)
180 return -ENOMEM;
181
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530182 ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
Kuldeep Singha009ab32020-09-11 16:36:49 +0530183 CONFIG_ENV_SPI_CS,
184 CONFIG_ENV_SPI_MAX_HZ,
185 CONFIG_ENV_SPI_MODE,
186 &new);
Biwen Lib9eeb082020-11-05 19:28:12 +0800187 if (ret) {
188 printf("SF: failed to probe spi\n");
189 free(addr);
190 device_remove(new, DM_REMOVE_NORMAL);
191 return ret;
192 }
193
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530194
195 pfe_flash = dev_get_uclass_priv(new);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530196 if (!pfe_flash) {
197 printf("SF: probe for pfe failed\n");
Kuldeep Singhb363eca2020-09-11 16:36:48 +0530198 free(addr);
Biwen Lib9eeb082020-11-05 19:28:12 +0800199 device_remove(new, DM_REMOVE_NORMAL);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530200 return -ENODEV;
201 }
202
203 ret = spi_flash_read(pfe_flash,
204 CONFIG_SYS_LS_PFE_FW_ADDR,
Biwen Lib9eeb082020-11-05 19:28:12 +0800205 CONFIG_SYS_LS_PFE_FW_LENGTH,
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530206 addr);
Biwen Lib9eeb082020-11-05 19:28:12 +0800207 if (ret) {
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530208 printf("SF: read for pfe failed\n");
Biwen Lib9eeb082020-11-05 19:28:12 +0800209 free(addr);
210 spi_flash_free(pfe_flash);
211 return ret;
212 }
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530213
Biwen Lib9eeb082020-11-05 19:28:12 +0800214#ifdef CONFIG_CHAIN_OF_TRUST
215 void *hdr_addr = malloc(CONFIG_SYS_LS_PFE_ESBC_LENGTH);
216
217 if (!hdr_addr) {
218 free(addr);
219 spi_flash_free(pfe_flash);
220 return -ENOMEM;
221 }
222
223 ret = spi_flash_read(pfe_flash,
224 CONFIG_SYS_LS_PFE_ESBC_ADDR,
225 CONFIG_SYS_LS_PFE_ESBC_LENGTH,
226 hdr_addr);
227 if (ret) {
228 printf("SF: failed to read pfe esbc header\n");
229 free(addr);
230 free(hdr_addr);
231 spi_flash_free(pfe_flash);
232 return ret;
233 }
234
235 pfe_esbc_hdr_addr = hdr_addr;
236#endif
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530237 pfe_fit_addr = addr;
238 spi_flash_free(pfe_flash);
239
240 return ret;
241}
242
Calvin Johnson781b8382018-03-08 15:30:25 +0530243/*
244 * PFE firmware initialization.
245 * Loads different firmware files from FIT image.
246 * Initializes PE IMEM/DMEM and UTIL-PE DDR
247 * Initializes control path symbol addresses (by looking them up in the elf
248 * firmware files
249 * Takes PE's out of reset
250 *
251 * @return 0 on success, a negative value on error
252 */
253int pfe_firmware_init(void)
254{
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530255#define PFE_KEY_HASH NULL
Calvin Johnson781b8382018-03-08 15:30:25 +0530256 char *pfe_firmware_name;
257 const void *raw_image_addr;
258 size_t raw_image_size = 0;
259 u8 *pfe_firmware;
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530260#ifdef CONFIG_CHAIN_OF_TRUST
261 uintptr_t pfe_esbc_hdr = 0;
262 uintptr_t pfe_img_addr = 0;
263#endif
Calvin Johnson781b8382018-03-08 15:30:25 +0530264 int ret = 0;
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +0800265 int fw_count, max_fw_count;
266 const char *p;
Calvin Johnson781b8382018-03-08 15:30:25 +0530267
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530268 ret = pfe_spi_flash_init();
269 if (ret)
270 goto err;
271
Calvin Johnson781b8382018-03-08 15:30:25 +0530272 ret = pfe_fit_check();
273 if (ret)
274 goto err;
275
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530276#ifdef CONFIG_CHAIN_OF_TRUST
Biwen Lib9eeb082020-11-05 19:28:12 +0800277 pfe_esbc_hdr = (uintptr_t)pfe_esbc_hdr_addr;
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530278 pfe_img_addr = (uintptr_t)pfe_fit_addr;
279 if (fsl_check_boot_mode_secure() != 0) {
280 /*
281 * In case of failure in validation, fsl_secboot_validate
282 * would not return back in case of Production environment
283 * with ITS=1. In Development environment (ITS=0 and
284 * SB_EN=1), the function may return back in case of
285 * non-fatal failures.
286 */
287 ret = fsl_secboot_validate(pfe_esbc_hdr,
288 PFE_KEY_HASH,
289 &pfe_img_addr);
290 if (ret != 0)
291 printf("PFE firmware(s) validation failed\n");
292 else
293 printf("PFE firmware(s) validation Successful\n");
294 }
295#endif
296
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +0800297 p = env_get("load_util");
298 if (!p) {
299 max_fw_count = 2;
300 } else {
Simon Glassff9b9032021-07-24 09:03:30 -0600301 max_fw_count = dectoul(p, NULL);
Chaitanya Sakinam811cbcf2021-05-07 12:22:05 +0800302 if (max_fw_count)
303 max_fw_count = 3;
304 else
305 max_fw_count = 2;
306 }
307
308 for (fw_count = 0; fw_count < max_fw_count; fw_count++) {
309 switch (fw_count) {
310 case 0:
311 pfe_firmware_name = "class_slowpath";
312 break;
313 case 1:
314 pfe_firmware_name = "tmu_slowpath";
315 break;
316 case 2:
317 pfe_firmware_name = "util_slowpath";
318 break;
319 }
320
321 if (pfe_get_fw(&raw_image_addr, &raw_image_size,
322 pfe_firmware_name)) {
323 printf("%s firmware couldn't be found in FIT image\n",
324 pfe_firmware_name);
325 break;
326 }
327 pfe_firmware = malloc(raw_image_size);
328 if (!pfe_firmware)
329 return -ENOMEM;
330 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
331 raw_image_size);
332
333 switch (fw_count) {
334 case 0:
335 env_set_addr("class_elf_firmware", pfe_firmware);
336 env_set_addr("class_elf_size", (void *)raw_image_size);
337 break;
338 case 1:
339 env_set_addr("tmu_elf_firmware", pfe_firmware);
340 env_set_addr("tmu_elf_size", (void *)raw_image_size);
341 break;
342 case 2:
343 env_set_addr("util_elf_firmware", pfe_firmware);
344 env_set_addr("util_elf_size", (void *)raw_image_size);
345 break;
346 }
347 }
348
349 raw_image_addr = NULL;
350 pfe_firmware = NULL;
351 raw_image_size = 0;
Calvin Johnson781b8382018-03-08 15:30:25 +0530352 for (fw_count = 0; fw_count < 2; fw_count++) {
353 if (fw_count == 0)
354 pfe_firmware_name = "class";
355 else if (fw_count == 1)
356 pfe_firmware_name = "tmu";
357
358 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
359 pfe_firmware = malloc(raw_image_size);
360 if (!pfe_firmware)
361 return -ENOMEM;
362 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
363 raw_image_size);
364
365 if (fw_count == 0)
366 ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
367 else if (fw_count == 1)
368 ret = pfe_load_elf(TMU_MASK, pfe_firmware);
369
370 if (ret < 0) {
371 printf("%s: %s firmware load failed\n", __func__,
372 pfe_firmware_name);
373 goto err;
374 }
375 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
376 free(pfe_firmware);
377 }
378
379 tmu_enable(0xb);
380 class_enable();
381 gpi_enable(HGPI_BASE_ADDR);
382
383err:
384 return ret;
385}
386
387/*
388 * PFE firmware cleanup
389 * Puts PE's in reset
390 */
391void pfe_firmware_exit(void)
392{
393 debug("%s\n", __func__);
394
395 class_disable();
396 tmu_disable(0xf);
397 hif_tx_disable();
398 hif_rx_disable();
399}