dm: core: Create a new header file for 'compat' features
[oweals/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 <malloc.h>
14 #include <net/pfe_eth/pfe_eth.h>
15 #include <net/pfe_eth/pfe_firmware.h>
16 #ifdef CONFIG_CHAIN_OF_TRUST
17 #include <fsl_validate.h>
18 #endif
19
20 #define PFE_FIRMWARE_FIT_CNF_NAME       "config@1"
21
22 static 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  */
33 static 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
82 err:
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  */
95 static 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
103         conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
104
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  */
144 static 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  */
173 int pfe_firmware_init(void)
174 {
175 #define PFE_KEY_HASH    NULL
176         char *pfe_firmware_name;
177         const void *raw_image_addr;
178         size_t raw_image_size = 0;
179         u8 *pfe_firmware;
180 #ifdef CONFIG_CHAIN_OF_TRUST
181         uintptr_t pfe_esbc_hdr = 0;
182         uintptr_t pfe_img_addr = 0;
183 #endif
184         int ret = 0;
185         int fw_count;
186
187         ret = pfe_fit_check();
188         if (ret)
189                 goto err;
190
191 #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
212         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
243 err:
244         return ret;
245 }
246
247 /*
248  * PFE firmware cleanup
249  * Puts PE's in reset
250  */
251 void 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 }