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