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