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