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