blob: 0493cfe8724450bd007dc5f25cd246a3fbea827b [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>
Vinitha V Pillaiad698c32018-05-23 11:03:31 +053019#ifdef CONFIG_CHAIN_OF_TRUST
20#include <fsl_validate.h>
21#endif
Calvin Johnson781b8382018-03-08 15:30:25 +053022
Thomas Hebb1dbd3d12019-11-10 08:23:15 -080023#define PFE_FIRMWARE_FIT_CNF_NAME "config@1"
Calvin Johnson781b8382018-03-08 15:30:25 +053024
25static const void *pfe_fit_addr = (void *)CONFIG_SYS_LS_PFE_FW_ADDR;
26
27/*
28 * PFE elf firmware loader.
29 * Loads an elf firmware image into a list of PE's (specified using a bitmask)
30 *
31 * @param pe_mask Mask of PE id's to load firmware to
32 * @param pfe_firmware Pointer to the firmware image
33 *
34 * @return 0 on success, a negative value on error
35 */
36static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
37{
38 Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
39 Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
40 Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
41 be32_to_cpu(elf_hdr->e_shoff));
42 int id, section;
43 int ret;
44
45 debug("%s: no of sections: %d\n", __func__, sections);
46
47 /* Some sanity checks */
48 if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
49 printf("%s: incorrect elf magic number\n", __func__);
50 return -1;
51 }
52
53 if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
54 printf("%s: incorrect elf class(%x)\n", __func__,
55 elf_hdr->e_ident[EI_CLASS]);
56 return -1;
57 }
58
59 if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
60 printf("%s: incorrect elf data(%x)\n", __func__,
61 elf_hdr->e_ident[EI_DATA]);
62 return -1;
63 }
64
65 if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
66 printf("%s: incorrect elf file type(%x)\n", __func__,
67 be16_to_cpu(elf_hdr->e_type));
68 return -1;
69 }
70
71 for (section = 0; section < sections; section++, shdr++) {
72 if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
73 SHF_EXECINSTR)))
74 continue;
75 for (id = 0; id < MAX_PE; id++)
76 if (pe_mask & BIT(id)) {
77 ret = pe_load_elf_section(id,
78 pfe_firmware, shdr);
79 if (ret < 0)
80 goto err;
81 }
82 }
83 return 0;
84
85err:
86 return ret;
87}
88
89/*
90 * Get PFE firmware from FIT image
91 *
92 * @param data pointer to PFE firmware
93 * @param size pointer to size of the firmware
94 * @param fw_name pfe firmware name, either class or tmu
95 *
96 * @return 0 on success, a negative value on error
97 */
98static int pfe_get_fw(const void **data,
99 size_t *size, char *fw_name)
100{
101 int conf_node_off, fw_node_off;
102 char *conf_node_name = NULL;
103 char *desc;
104 int ret = 0;
105
Thomas Hebb1dbd3d12019-11-10 08:23:15 -0800106 conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
Calvin Johnson781b8382018-03-08 15:30:25 +0530107
108 conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name);
109 if (conf_node_off < 0) {
110 printf("PFE Firmware: %s: no such config\n", conf_node_name);
111 return -ENOENT;
112 }
113
114 fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off,
115 fw_name);
116 if (fw_node_off < 0) {
117 printf("PFE Firmware: No '%s' in config\n",
118 fw_name);
119 return -ENOLINK;
120 }
121
122 if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) {
123 printf("PFE Firmware: Bad firmware image (bad CRC)\n");
124 return -EINVAL;
125 }
126
127 if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) {
128 printf("PFE Firmware: Can't get %s subimage data/size",
129 fw_name);
130 return -ENOENT;
131 }
132
133 ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc);
134 if (ret)
135 printf("PFE Firmware: Can't get description\n");
136 else
137 printf("%s\n", desc);
138
139 return ret;
140}
141
142/*
143 * Check PFE FIT image
144 *
145 * @return 0 on success, a negative value on error
146 */
147static int pfe_fit_check(void)
148{
149 int ret = 0;
150
151 ret = fdt_check_header(pfe_fit_addr);
152 if (ret) {
153 printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
154 return ret;
155 }
156
157 if (!fit_check_format(pfe_fit_addr)) {
158 printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
159 ret = -1;
160 return ret;
161 }
162
163 return ret;
164}
165
166/*
167 * PFE firmware initialization.
168 * Loads different firmware files from FIT image.
169 * Initializes PE IMEM/DMEM and UTIL-PE DDR
170 * Initializes control path symbol addresses (by looking them up in the elf
171 * firmware files
172 * Takes PE's out of reset
173 *
174 * @return 0 on success, a negative value on error
175 */
176int pfe_firmware_init(void)
177{
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530178#define PFE_KEY_HASH NULL
Calvin Johnson781b8382018-03-08 15:30:25 +0530179 char *pfe_firmware_name;
180 const void *raw_image_addr;
181 size_t raw_image_size = 0;
182 u8 *pfe_firmware;
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530183#ifdef CONFIG_CHAIN_OF_TRUST
184 uintptr_t pfe_esbc_hdr = 0;
185 uintptr_t pfe_img_addr = 0;
186#endif
Calvin Johnson781b8382018-03-08 15:30:25 +0530187 int ret = 0;
188 int fw_count;
189
190 ret = pfe_fit_check();
191 if (ret)
192 goto err;
193
Vinitha V Pillaiad698c32018-05-23 11:03:31 +0530194#ifdef CONFIG_CHAIN_OF_TRUST
195 pfe_esbc_hdr = CONFIG_SYS_LS_PFE_ESBC_ADDR;
196 pfe_img_addr = (uintptr_t)pfe_fit_addr;
197 if (fsl_check_boot_mode_secure() != 0) {
198 /*
199 * In case of failure in validation, fsl_secboot_validate
200 * would not return back in case of Production environment
201 * with ITS=1. In Development environment (ITS=0 and
202 * SB_EN=1), the function may return back in case of
203 * non-fatal failures.
204 */
205 ret = fsl_secboot_validate(pfe_esbc_hdr,
206 PFE_KEY_HASH,
207 &pfe_img_addr);
208 if (ret != 0)
209 printf("PFE firmware(s) validation failed\n");
210 else
211 printf("PFE firmware(s) validation Successful\n");
212 }
213#endif
214
Calvin Johnson781b8382018-03-08 15:30:25 +0530215 for (fw_count = 0; fw_count < 2; fw_count++) {
216 if (fw_count == 0)
217 pfe_firmware_name = "class";
218 else if (fw_count == 1)
219 pfe_firmware_name = "tmu";
220
221 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
222 pfe_firmware = malloc(raw_image_size);
223 if (!pfe_firmware)
224 return -ENOMEM;
225 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
226 raw_image_size);
227
228 if (fw_count == 0)
229 ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
230 else if (fw_count == 1)
231 ret = pfe_load_elf(TMU_MASK, pfe_firmware);
232
233 if (ret < 0) {
234 printf("%s: %s firmware load failed\n", __func__,
235 pfe_firmware_name);
236 goto err;
237 }
238 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
239 free(pfe_firmware);
240 }
241
242 tmu_enable(0xb);
243 class_enable();
244 gpi_enable(HGPI_BASE_ADDR);
245
246err:
247 return ret;
248}
249
250/*
251 * PFE firmware cleanup
252 * Puts PE's in reset
253 */
254void pfe_firmware_exit(void)
255{
256 debug("%s\n", __func__);
257
258 class_disable();
259 tmu_disable(0xf);
260 hif_tx_disable();
261 hif_rx_disable();
262}