Merge tag 'u-boot-atmel-fixes-2021.01-b' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / drivers / net / pfe_eth / pfe_firmware.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2015-2016 Freescale Semiconductor, Inc.
4  * Copyright 2017 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
28 static const void *pfe_fit_addr;
29 #ifdef CONFIG_CHAIN_OF_TRUST
30 static 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  */
42 static 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
91 err:
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  */
104 static 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
112         conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
113
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  */
153 static 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
163         if (!fit_check_format(pfe_fit_addr)) {
164                 printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
165                 ret = -1;
166                 return ret;
167         }
168
169         return ret;
170 }
171
172 int pfe_spi_flash_init(void)
173 {
174         struct spi_flash *pfe_flash;
175         struct udevice *new;
176         int ret = 0;
177         void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH);
178
179         if (!addr)
180                 return -ENOMEM;
181
182         ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
183                                      CONFIG_ENV_SPI_CS,
184                                      CONFIG_ENV_SPI_MAX_HZ,
185                                      CONFIG_ENV_SPI_MODE,
186                                      &new);
187         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
194
195         pfe_flash = dev_get_uclass_priv(new);
196         if (!pfe_flash) {
197                 printf("SF: probe for pfe failed\n");
198                 free(addr);
199                 device_remove(new, DM_REMOVE_NORMAL);
200                 return -ENODEV;
201         }
202
203         ret = spi_flash_read(pfe_flash,
204                              CONFIG_SYS_LS_PFE_FW_ADDR,
205                              CONFIG_SYS_LS_PFE_FW_LENGTH,
206                              addr);
207         if (ret) {
208                 printf("SF: read for pfe failed\n");
209                 free(addr);
210                 spi_flash_free(pfe_flash);
211                 return ret;
212         }
213
214 #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
237         pfe_fit_addr = addr;
238         spi_flash_free(pfe_flash);
239
240         return ret;
241 }
242
243 /*
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  */
253 int pfe_firmware_init(void)
254 {
255 #define PFE_KEY_HASH    NULL
256         char *pfe_firmware_name;
257         const void *raw_image_addr;
258         size_t raw_image_size = 0;
259         u8 *pfe_firmware;
260 #ifdef CONFIG_CHAIN_OF_TRUST
261         uintptr_t pfe_esbc_hdr = 0;
262         uintptr_t pfe_img_addr = 0;
263 #endif
264         int ret = 0;
265         int fw_count;
266
267         ret = pfe_spi_flash_init();
268         if (ret)
269                 goto err;
270
271         ret = pfe_fit_check();
272         if (ret)
273                 goto err;
274
275 #ifdef CONFIG_CHAIN_OF_TRUST
276         pfe_esbc_hdr = (uintptr_t)pfe_esbc_hdr_addr;
277         pfe_img_addr = (uintptr_t)pfe_fit_addr;
278         if (fsl_check_boot_mode_secure() != 0) {
279                 /*
280                  * In case of failure in validation, fsl_secboot_validate
281                  * would not return back in case of Production environment
282                  * with ITS=1. In Development environment (ITS=0 and
283                  * SB_EN=1), the function may return back in case of
284                  * non-fatal failures.
285                  */
286                 ret = fsl_secboot_validate(pfe_esbc_hdr,
287                                            PFE_KEY_HASH,
288                                            &pfe_img_addr);
289                 if (ret != 0)
290                         printf("PFE firmware(s) validation failed\n");
291                 else
292                         printf("PFE firmware(s) validation Successful\n");
293         }
294 #endif
295
296         for (fw_count = 0; fw_count < 2; fw_count++) {
297                 if (fw_count == 0)
298                         pfe_firmware_name = "class";
299                 else if (fw_count == 1)
300                         pfe_firmware_name = "tmu";
301
302                 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
303                 pfe_firmware = malloc(raw_image_size);
304                 if (!pfe_firmware)
305                         return -ENOMEM;
306                 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
307                        raw_image_size);
308
309                 if (fw_count == 0)
310                         ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
311                 else if (fw_count == 1)
312                         ret = pfe_load_elf(TMU_MASK, pfe_firmware);
313
314                 if (ret < 0) {
315                         printf("%s: %s firmware load failed\n", __func__,
316                                pfe_firmware_name);
317                         goto err;
318                 }
319                 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
320                 free(pfe_firmware);
321         }
322
323         tmu_enable(0xb);
324         class_enable();
325         gpi_enable(HGPI_BASE_ADDR);
326
327 err:
328         return ret;
329 }
330
331 /*
332  * PFE firmware cleanup
333  * Puts PE's in reset
334  */
335 void pfe_firmware_exit(void)
336 {
337         debug("%s\n", __func__);
338
339         class_disable();
340         tmu_disable(0xf);
341         hif_tx_disable();
342         hif_rx_disable();
343 }