1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
4 * Copyright 2017,2021 NXP
5 */
6
7/*
8 * @file
9 *  Contains all the functions to handle parsing and loading of PE firmware
10 * files.
11 */
12
13#include <dm.h>
14#include <dm/device-internal.h>
15#include <image.h>
16#include <log.h>
17#include <malloc.h>
18#include <linux/bitops.h>
19#include <net/pfe_eth/pfe_eth.h>
20#include <net/pfe_eth/pfe_firmware.h>
21#include <spi_flash.h>
22#ifdef CONFIG_CHAIN_OF_TRUST
23#include <fsl_validate.h>
24#endif
25
26#define PFE_FIRMWARE_FIT_CNF_NAME	"config@1"
27
28static const void *pfe_fit_addr;
29#ifdef CONFIG_CHAIN_OF_TRUST
30static const void *pfe_esbc_hdr_addr;
31#endif
32
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	return fit_get_data_conf_prop(pfe_fit_addr, fw_name, data, size);
108}
109
110/*
111 * Check PFE FIT image
112 *
113 * Return: 0 on success, a negative value on error
114 */
115static int pfe_fit_check(void)
116{
117	int ret = 0;
118
119	ret = fdt_check_header(pfe_fit_addr);
120	if (ret) {
121		printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
122		return ret;
123	}
124
125	if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) {
126		printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
127		ret = -1;
128		return ret;
129	}
130
131	return ret;
132}
133
134int pfe_spi_flash_init(void)
135{
136	struct spi_flash *pfe_flash;
137	int ret = 0;
138	void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH);
139
140	if (!addr)
141		return -ENOMEM;
142
143	pfe_flash = spi_flash_probe(CONFIG_SYS_FSL_PFE_SPI_BUS,
144				    CONFIG_SYS_FSL_PFE_SPI_CS,
145				    CONFIG_SYS_FSL_PFE_SPI_MAX_HZ,
146				    CONFIG_SYS_FSL_PFE_SPI_MODE);
147
148	if (!pfe_flash) {
149		printf("SF: probe for pfe failed\n");
150		free(addr);
151		return -ENODEV;
152	}
153
154	ret = spi_flash_read(pfe_flash,
155			     CONFIG_SYS_LS_PFE_FW_ADDR,
156			     CONFIG_SYS_LS_PFE_FW_LENGTH,
157			     addr);
158	if (ret) {
159		printf("SF: read for pfe failed\n");
160		free(addr);
161		spi_flash_free(pfe_flash);
162		return ret;
163	}
164
165#ifdef CONFIG_CHAIN_OF_TRUST
166	void *hdr_addr = malloc(CONFIG_SYS_LS_PFE_ESBC_LENGTH);
167
168	if (!hdr_addr) {
169		free(addr);
170		spi_flash_free(pfe_flash);
171		return -ENOMEM;
172	}
173
174	ret = spi_flash_read(pfe_flash,
175			     CONFIG_SYS_LS_PFE_ESBC_ADDR,
176			     CONFIG_SYS_LS_PFE_ESBC_LENGTH,
177			     hdr_addr);
178	if (ret) {
179		printf("SF: failed to read pfe esbc header\n");
180		free(addr);
181		free(hdr_addr);
182		spi_flash_free(pfe_flash);
183		return ret;
184	}
185
186	pfe_esbc_hdr_addr = hdr_addr;
187#endif
188	pfe_fit_addr = addr;
189	spi_flash_free(pfe_flash);
190
191	return ret;
192}
193
194/*
195 * PFE firmware initialization.
196 * Loads different firmware files from FIT image.
197 * Initializes PE IMEM/DMEM and UTIL-PE DDR
198 * Initializes control path symbol addresses (by looking them up in the elf
199 * firmware files
200 * Takes PE's out of reset
201 *
202 * Return: 0 on success, a negative value on error
203 */
204int pfe_firmware_init(void)
205{
206#define PFE_KEY_HASH	NULL
207	char *pfe_firmware_name;
208	const void *raw_image_addr;
209	size_t raw_image_size = 0;
210	u8 *pfe_firmware;
211#ifdef CONFIG_CHAIN_OF_TRUST
212	uintptr_t pfe_esbc_hdr = 0;
213	uintptr_t pfe_img_addr = 0;
214#endif
215	int ret = 0;
216	int fw_count, max_fw_count;
217	const char *p;
218
219	ret = pfe_spi_flash_init();
220	if (ret)
221		goto err;
222
223	ret = pfe_fit_check();
224	if (ret)
225		goto err;
226
227#ifdef CONFIG_CHAIN_OF_TRUST
228	pfe_esbc_hdr = (uintptr_t)pfe_esbc_hdr_addr;
229	pfe_img_addr = (uintptr_t)pfe_fit_addr;
230	if (fsl_check_boot_mode_secure() != 0) {
231		/*
232		 * In case of failure in validation, fsl_secboot_validate
233		 * would not return back in case of Production environment
234		 * with ITS=1. In Development environment (ITS=0 and
235		 * SB_EN=1), the function may return back in case of
236		 * non-fatal failures.
237		 */
238		ret = fsl_secboot_validate(pfe_esbc_hdr,
239					   PFE_KEY_HASH,
240					   &pfe_img_addr);
241		if (ret != 0)
242			printf("PFE firmware(s) validation failed\n");
243		else
244			printf("PFE firmware(s) validation Successful\n");
245	}
246#endif
247
248	p = env_get("load_util");
249	if (!p) {
250		max_fw_count = 2;
251	} else {
252		max_fw_count = dectoul(p, NULL);
253		if (max_fw_count)
254			max_fw_count = 3;
255		else
256			max_fw_count = 2;
257	}
258
259	for (fw_count = 0; fw_count < max_fw_count; fw_count++) {
260		switch (fw_count) {
261		case 0:
262			pfe_firmware_name = "class_slowpath";
263			break;
264		case 1:
265			pfe_firmware_name = "tmu_slowpath";
266			break;
267		case 2:
268			pfe_firmware_name = "util_slowpath";
269			break;
270		}
271
272		if (pfe_get_fw(&raw_image_addr, &raw_image_size,
273			       pfe_firmware_name)) {
274			printf("%s firmware couldn't be found in FIT image\n",
275			       pfe_firmware_name);
276			break;
277		}
278		pfe_firmware = malloc(raw_image_size);
279		if (!pfe_firmware)
280			return -ENOMEM;
281		memcpy((void *)pfe_firmware, (void *)raw_image_addr,
282		       raw_image_size);
283
284		switch (fw_count) {
285		case 0:
286			env_set_addr("class_elf_firmware", pfe_firmware);
287			env_set_addr("class_elf_size", (void *)raw_image_size);
288			break;
289		case 1:
290			env_set_addr("tmu_elf_firmware", pfe_firmware);
291			env_set_addr("tmu_elf_size", (void *)raw_image_size);
292			break;
293		case 2:
294			env_set_addr("util_elf_firmware", pfe_firmware);
295			env_set_addr("util_elf_size", (void *)raw_image_size);
296			break;
297		}
298	}
299
300	raw_image_addr = NULL;
301	pfe_firmware = NULL;
302	raw_image_size = 0;
303	for (fw_count = 0; fw_count < 2; fw_count++) {
304		if (fw_count == 0)
305			pfe_firmware_name = "class";
306		else if (fw_count == 1)
307			pfe_firmware_name = "tmu";
308
309		pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
310		pfe_firmware = malloc(raw_image_size);
311		if (!pfe_firmware)
312			return -ENOMEM;
313		memcpy((void *)pfe_firmware, (void *)raw_image_addr,
314		       raw_image_size);
315
316		if (fw_count == 0)
317			ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
318		else if (fw_count == 1)
319			ret = pfe_load_elf(TMU_MASK, pfe_firmware);
320
321		if (ret < 0) {
322			printf("%s: %s firmware load failed\n", __func__,
323			       pfe_firmware_name);
324			goto err;
325		}
326		debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
327		free(pfe_firmware);
328	}
329
330	tmu_enable(0xb);
331	class_enable();
332	gpi_enable(HGPI_BASE_ADDR);
333
334err:
335	return ret;
336}
337
338/*
339 * PFE firmware cleanup
340 * Puts PE's in reset
341 */
342void pfe_firmware_exit(void)
343{
344	debug("%s\n", __func__);
345
346	class_disable();
347	tmu_disable(0xf);
348	hif_tx_disable();
349	hif_rx_disable();
350}
351