blob: f06ed3729284a9187460a319ae6ba2db39bb711c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Calvin Johnson781b8382018-03-08 15:30:25 +05302/*
3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
4 * Copyright 2017 NXP
Calvin Johnson781b8382018-03-08 15:30:25 +05305 */
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
18static 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 */
29static 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
78err:
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 */
91static 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 */
140static 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 */
169int 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
213err:
214 return ret;
215}
216
217/*
218 * PFE firmware cleanup
219 * Puts PE's in reset
220 */
221void 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}