Merge https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq
[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 <image.h>
14 #include <log.h>
15 #include <malloc.h>
16 #include <linux/bitops.h>
17 #include <net/pfe_eth/pfe_eth.h>
18 #include <net/pfe_eth/pfe_firmware.h>
19 #include <spi_flash.h>
20 #ifdef CONFIG_CHAIN_OF_TRUST
21 #include <fsl_validate.h>
22 #endif
23
24 #define PFE_FIRMWARE_FIT_CNF_NAME       "config@1"
25
26 static const void *pfe_fit_addr;
27
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  */
37 static 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
86 err:
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  */
99 static 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
107         conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
108
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  */
148 static 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
167 int pfe_spi_flash_init(void)
168 {
169         struct spi_flash *pfe_flash;
170         int ret = 0;
171         void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
172
173 #ifdef CONFIG_DM_SPI_FLASH
174         struct udevice *new;
175
176         /* speed and mode will be read from DT */
177         ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
178                                      CONFIG_ENV_SPI_CS, 0, 0, &new);
179
180         pfe_flash = dev_get_uclass_priv(new);
181 #else
182         pfe_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
183                                     CONFIG_ENV_SPI_CS,
184                                     CONFIG_ENV_SPI_MAX_HZ,
185                                     CONFIG_ENV_SPI_MODE);
186 #endif
187         if (!pfe_flash) {
188                 printf("SF: probe for pfe failed\n");
189                 return -ENODEV;
190         }
191
192         ret = spi_flash_read(pfe_flash,
193                              CONFIG_SYS_LS_PFE_FW_ADDR,
194                              CONFIG_SYS_QE_FMAN_FW_LENGTH,
195                              addr);
196         if (ret)
197                 printf("SF: read for pfe failed\n");
198
199         pfe_fit_addr = addr;
200         spi_flash_free(pfe_flash);
201
202         return ret;
203 }
204
205 /*
206  * PFE firmware initialization.
207  * Loads different firmware files from FIT image.
208  * Initializes PE IMEM/DMEM and UTIL-PE DDR
209  * Initializes control path symbol addresses (by looking them up in the elf
210  * firmware files
211  * Takes PE's out of reset
212  *
213  * @return 0 on success, a negative value on error
214  */
215 int pfe_firmware_init(void)
216 {
217 #define PFE_KEY_HASH    NULL
218         char *pfe_firmware_name;
219         const void *raw_image_addr;
220         size_t raw_image_size = 0;
221         u8 *pfe_firmware;
222 #ifdef CONFIG_CHAIN_OF_TRUST
223         uintptr_t pfe_esbc_hdr = 0;
224         uintptr_t pfe_img_addr = 0;
225 #endif
226         int ret = 0;
227         int fw_count;
228
229         ret = pfe_spi_flash_init();
230         if (ret)
231                 goto err;
232
233         ret = pfe_fit_check();
234         if (ret)
235                 goto err;
236
237 #ifdef CONFIG_CHAIN_OF_TRUST
238         pfe_esbc_hdr = CONFIG_SYS_LS_PFE_ESBC_ADDR;
239         pfe_img_addr = (uintptr_t)pfe_fit_addr;
240         if (fsl_check_boot_mode_secure() != 0) {
241                 /*
242                  * In case of failure in validation, fsl_secboot_validate
243                  * would not return back in case of Production environment
244                  * with ITS=1. In Development environment (ITS=0 and
245                  * SB_EN=1), the function may return back in case of
246                  * non-fatal failures.
247                  */
248                 ret = fsl_secboot_validate(pfe_esbc_hdr,
249                                            PFE_KEY_HASH,
250                                            &pfe_img_addr);
251                 if (ret != 0)
252                         printf("PFE firmware(s) validation failed\n");
253                 else
254                         printf("PFE firmware(s) validation Successful\n");
255         }
256 #endif
257
258         for (fw_count = 0; fw_count < 2; fw_count++) {
259                 if (fw_count == 0)
260                         pfe_firmware_name = "class";
261                 else if (fw_count == 1)
262                         pfe_firmware_name = "tmu";
263
264                 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
265                 pfe_firmware = malloc(raw_image_size);
266                 if (!pfe_firmware)
267                         return -ENOMEM;
268                 memcpy((void *)pfe_firmware, (void *)raw_image_addr,
269                        raw_image_size);
270
271                 if (fw_count == 0)
272                         ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
273                 else if (fw_count == 1)
274                         ret = pfe_load_elf(TMU_MASK, pfe_firmware);
275
276                 if (ret < 0) {
277                         printf("%s: %s firmware load failed\n", __func__,
278                                pfe_firmware_name);
279                         goto err;
280                 }
281                 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
282                 free(pfe_firmware);
283         }
284
285         tmu_enable(0xb);
286         class_enable();
287         gpi_enable(HGPI_BASE_ADDR);
288
289 err:
290         return ret;
291 }
292
293 /*
294  * PFE firmware cleanup
295  * Puts PE's in reset
296  */
297 void pfe_firmware_exit(void)
298 {
299         debug("%s\n", __func__);
300
301         class_disable();
302         tmu_disable(0xf);
303         hif_tx_disable();
304         hif_rx_disable();
305 }