travis: Install pyelftools via pip
[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 #ifdef CONFIG_CHAIN_OF_TRUST
20 #include <fsl_validate.h>
21 #endif
22
23 #define PFE_FIRMWARE_FIT_CNF_NAME       "config@1"
24
25 static 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  */
36 static 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
85 err:
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  */
98 static 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
106         conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
107
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  */
147 static 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  */
176 int pfe_firmware_init(void)
177 {
178 #define PFE_KEY_HASH    NULL
179         char *pfe_firmware_name;
180         const void *raw_image_addr;
181         size_t raw_image_size = 0;
182         u8 *pfe_firmware;
183 #ifdef CONFIG_CHAIN_OF_TRUST
184         uintptr_t pfe_esbc_hdr = 0;
185         uintptr_t pfe_img_addr = 0;
186 #endif
187         int ret = 0;
188         int fw_count;
189
190         ret = pfe_fit_check();
191         if (ret)
192                 goto err;
193
194 #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
215         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
246 err:
247         return ret;
248 }
249
250 /*
251  * PFE firmware cleanup
252  * Puts PE's in reset
253  */
254 void 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 }