blob: 9dc063dc7504677ed2959df60f69154ff1935511 [file] [log] [blame]
Calvin Johnson781b8382018-03-08 15:30:25 +05301/*
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
19static 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 */
30static 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
79err:
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 */
92static 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 */
141static 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 */
170int 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
214err:
215 return ret;
216}
217
218/*
219 * PFE firmware cleanup
220 * Puts PE's in reset
221 */
222void 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}