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 }
230