blob: d414c750d42313f331797b459744dbc9423dc84a [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.
4 * Copyright 2017 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
Simon Glass2dc9c342020-05-10 11:40:01 -060013#include <image.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070015#include <malloc.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Calvin Johnson781b8382018-03-08 15:30:25 +053017#include <net/pfe_eth/pfe_eth.h>
18#include <net/pfe_eth/pfe_firmware.h>
Kuldeep Singh14e956f2020-05-28 11:42:53 +053019#include <spi_flash.h>
Vinitha V Pillaiad698c32018-05-23 11:03:31 +053020#ifdef CONFIG_CHAIN_OF_TRUST
21#include <fsl_validate.h>
22#endif
Calvin Johnson781b8382018-03-08 15:30:25 +053023
Thomas Hebb1dbd3d12019-11-10 08:23:15 -080024#define PFE_FIRMWARE_FIT_CNF_NAME "config@1"
Calvin Johnson781b8382018-03-08 15:30:25 +053025
Kuldeep Singh14e956f2020-05-28 11:42:53 +053026static const void *pfe_fit_addr;
Calvin Johnson781b8382018-03-08 15:30:25 +053027
28/*
29 * PFE elf firmware loader.
30 * Loads an elf firmware image into a list of PE's (specified using a bitmask)
31 *
32 * @param pe_mask Mask of PE id's to load firmware to
33 * @param pfe_firmware Pointer to the firmware image
34 *
35 * @return 0 on success, a negative value on error
36 */
37static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
38{
39 Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
40 Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
41 Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
42 be32_to_cpu(elf_hdr->e_shoff));
43 int id, section;
44 int ret;
45
46 debug("%s: no of sections: %d\n", __func__, sections);
47
48 /* Some sanity checks */
49 if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
50 printf("%s: incorrect elf magic number\n", __func__);
51 return -1;
52 }
53
54 if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
55 printf("%s: incorrect elf class(%x)\n", __func__,
56 elf_hdr->e_ident[EI_CLASS]);
57 return -1;
58 }
59
60 if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
61 printf("%s: incorrect elf data(%x)\n", __func__,
62 elf_hdr->e_ident[EI_DATA]);
63 return -1;
64 }
65
66 if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
67 printf("%s: incorrect elf file type(%x)\n", __func__,
68 be16_to_cpu(elf_hdr->e_type));
69 return -1;
70 }
71
72 for (section = 0; section < sections; section++, shdr++) {
73 if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
74 SHF_EXECINSTR)))
75 continue;
76 for (id = 0; id < MAX_PE; id++)
77 if (pe_mask & BIT(id)) {
78 ret = pe_load_elf_section(id,
79 pfe_firmware, shdr);
80 if (ret < 0)
81 goto err;
82 }
83 }
84 return 0;
85
86err:
87 return ret;
88}
89
90/*
91 * Get PFE firmware from FIT image
92 *
93 * @param data pointer to PFE firmware
94 * @param size pointer to size of the firmware
95 * @param fw_name pfe firmware name, either class or tmu
96 *
97 * @return 0 on success, a negative value on error
98 */
99static int pfe_get_fw(const void **data,
100 size_t *size, char *fw_name)
101{
102 int conf_node_off, fw_node_off;
103 char *conf_node_name = NULL;
104 char *desc;
105 int ret = 0;
106
Thomas Hebb1dbd3d12019-11-10 08:23:15 -0800107 conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
Calvin Johnson781b8382018-03-08 15:30:25 +0530108
109 conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name);
110 if (conf_node_off < 0) {
111 printf("PFE Firmware: %s: no such config\n", conf_node_name);
112 return -ENOENT;
113 }
114
115 fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off,
116 fw_name);
117 if (fw_node_off < 0) {
118 printf("PFE Firmware: No '%s' in config\n",
119 fw_name);
120 return -ENOLINK;
121 }
122
123 if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) {
124 printf("PFE Firmware: Bad firmware image (bad CRC)\n");
125 return -EINVAL;
126 }
127
128 if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) {
129 printf("PFE Firmware: Can't get %s subimage data/size",
130 fw_name);
131 return -ENOENT;
132 }
133
134 ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc);
135 if (ret)
136 printf("PFE Firmware: Can't get description\n");
137 else
138 printf("%s\n", desc);
139
140 return ret;
141}
142
143/*
144 * Check PFE FIT image
145 *
146 * @return 0 on success, a negative value on error
147 */
148static int pfe_fit_check(void)
149{
150 int ret = 0;
151
152 ret = fdt_check_header(pfe_fit_addr);
153 if (ret) {
154 printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
155 return ret;
156 }
157
158 if (!fit_check_format(pfe_fit_addr)) {
159 printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
160 ret = -1;
161 return ret;
162 }
163
164 return ret;
165}
166
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530167int pfe_spi_flash_init(void)
168{
169 struct spi_flash *pfe_flash;
Kuldeep Singha009ab32020-09-11 16:36:49 +0530170 struct udevice *new;
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530171 int ret = 0;
172 void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
173
Kuldeep Singhb363eca2020-09-11 16:36:48 +0530174 if (!addr)
175 return -ENOMEM;
176
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530177 ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
Kuldeep Singha009ab32020-09-11 16:36:49 +0530178 CONFIG_ENV_SPI_CS,
179 CONFIG_ENV_SPI_MAX_HZ,
180 CONFIG_ENV_SPI_MODE,
181 &new);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530182
183 pfe_flash = dev_get_uclass_priv(new);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530184 if (!pfe_flash) {
185 printf("SF: probe for pfe failed\n");
Kuldeep Singhb363eca2020-09-11 16:36:48 +0530186 free(addr);
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530187 return -ENODEV;
188 }
189
190 ret = spi_flash_read(pfe_flash,
191 CONFIG_SYS_LS_PFE_FW_ADDR,
192 CONFIG_SYS_QE_FMAN_FW_LENGTH,
193 addr);
194 if (ret)
195 printf("SF: read for pfe failed\n");
196
197 pfe_fit_addr = addr;
198 spi_flash_free(pfe_flash);
199
200 return ret;
201}
202
Calvin Johnson781b8382018-03-08 15:30:25 +0530203/*
204 * PFE firmware initialization.
205 * Loads different firmware files from FIT image.
206 * Initializes PE IMEM/DMEM and UTIL-PE DDR
207 * Initializes control path symbol addresses (by looking them up in the elf
208 * firmware files
209 * Takes PE's out of reset
210 *
211 * @return 0 on success, a negative value on error
212 */
213int pfe_firmware_init(void)
214{
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530215#define PFE_KEY_HASH NULL
Calvin Johnson781b8382018-03-08 15:30:25 +0530216 char *pfe_firmware_name;
217 const void *raw_image_addr;
218 size_t raw_image_size = 0;
219 u8 *pfe_firmware;
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530220#ifdef CONFIG_CHAIN_OF_TRUST
221 uintptr_t pfe_esbc_hdr = 0;
222 uintptr_t pfe_img_addr = 0;
223#endif
Calvin Johnson781b8382018-03-08 15:30:25 +0530224 int ret = 0;
225 int fw_count;
226
Kuldeep Singh14e956f2020-05-28 11:42:53 +0530227 ret = pfe_spi_flash_init();
228 if (ret)
229 goto err;
230
Calvin Johnson781b8382018-03-08 15:30:25 +0530231 ret = pfe_fit_check();
232 if (ret)
233 goto err;
234
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530235#ifdef CONFIG_CHAIN_OF_TRUST
236 pfe_esbc_hdr = CONFIG_SYS_LS_PFE_ESBC_ADDR;
237 pfe_img_addr = (uintptr_t)pfe_fit_addr;
238 if (fsl_check_boot_mode_secure() != 0) {
239 /*
240 * In case of failure in validation, fsl_secboot_validate
241 * would not return back in case of Production environment
242 * with ITS=1. In Development environment (ITS=0 and
243 * SB_EN=1), the function may return back in case of
244 * non-fatal failures.
245 */
246 ret = fsl_secboot_validate(pfe_esbc_hdr,
247 PFE_KEY_HASH,
248 &pfe_img_addr);
249 if (ret != 0)
250 printf("PFE firmware(s) validation failed\n");
251 else
252 printf("PFE firmware(s) validation Successful\n");
253 }
254#endif
255
Calvin Johnson781b8382018-03-08 15:30:25 +0530256 for (fw_count = 0; fw_count < 2; fw_count++) {
257 if (fw_count == 0)
258 pfe_firmware_name = "class";
259 else if (fw_count == 1)
260 pfe_firmware_name = "tmu";
261
262 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
263 pfe_firmware = malloc(raw_image_size);
264 if (!pfe_firmware)
265 return -ENOMEM;
266 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
267 raw_image_size);
268
269 if (fw_count == 0)
270 ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
271 else if (fw_count == 1)
272 ret = pfe_load_elf(TMU_MASK, pfe_firmware);
273
274 if (ret < 0) {
275 printf("%s: %s firmware load failed\n", __func__,
276 pfe_firmware_name);
277 goto err;
278 }
279 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
280 free(pfe_firmware);
281 }
282
283 tmu_enable(0xb);
284 class_enable();
285 gpi_enable(HGPI_BASE_ADDR);
286
287err:
288 return ret;
289}
290
291/*
292 * PFE firmware cleanup
293 * Puts PE's in reset
294 */
295void pfe_firmware_exit(void)
296{
297 debug("%s\n", __func__);
298
299 class_disable();
300 tmu_disable(0xf);
301 hif_tx_disable();
302 hif_rx_disable();
303}