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