1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2015-2016 Freescale Semiconductor, Inc. 4 * Copyright 2017,2021 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 <dm.h> 14#include <dm/device-internal.h> 15#include <image.h> 16#include <log.h> 17#include <malloc.h> 18#include <linux/bitops.h> 19#include <net/pfe_eth/pfe_eth.h> 20#include <net/pfe_eth/pfe_firmware.h> 21#include <spi_flash.h> 22#ifdef CONFIG_CHAIN_OF_TRUST 23#include <fsl_validate.h> 24#endif 25 26#define PFE_FIRMWARE_FIT_CNF_NAME "config@1" 27 28static const void *pfe_fit_addr; 29#ifdef CONFIG_CHAIN_OF_TRUST 30static const void *pfe_esbc_hdr_addr; 31#endif 32 33/* 34 * PFE elf firmware loader. 35 * Loads an elf firmware image into a list of PE's (specified using a bitmask) 36 * 37 * @param pe_mask Mask of PE id's to load firmware to 38 * @param pfe_firmware Pointer to the firmware image 39 * 40 * Return: 0 on success, a negative value on error 41 */ 42static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware) 43{ 44 Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware; 45 Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum); 46 Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware + 47 be32_to_cpu(elf_hdr->e_shoff)); 48 int id, section; 49 int ret; 50 51 debug("%s: no of sections: %d\n", __func__, sections); 52 53 /* Some sanity checks */ 54 if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) { 55 printf("%s: incorrect elf magic number\n", __func__); 56 return -1; 57 } 58 59 if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) { 60 printf("%s: incorrect elf class(%x)\n", __func__, 61 elf_hdr->e_ident[EI_CLASS]); 62 return -1; 63 } 64 65 if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) { 66 printf("%s: incorrect elf data(%x)\n", __func__, 67 elf_hdr->e_ident[EI_DATA]); 68 return -1; 69 } 70 71 if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) { 72 printf("%s: incorrect elf file type(%x)\n", __func__, 73 be16_to_cpu(elf_hdr->e_type)); 74 return -1; 75 } 76 77 for (section = 0; section < sections; section++, shdr++) { 78 if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC | 79 SHF_EXECINSTR))) 80 continue; 81 for (id = 0; id < MAX_PE; id++) 82 if (pe_mask & BIT(id)) { 83 ret = pe_load_elf_section(id, 84 pfe_firmware, shdr); 85 if (ret < 0) 86 goto err; 87 } 88 } 89 return 0; 90 91err: 92 return ret; 93} 94 95/* 96 * Get PFE firmware from FIT image 97 * 98 * @param data pointer to PFE firmware 99 * @param size pointer to size of the firmware 100 * @param fw_name pfe firmware name, either class or tmu 101 * 102 * Return: 0 on success, a negative value on error 103 */ 104static int pfe_get_fw(const void **data, 105 size_t *size, char *fw_name) 106{ 107 return fit_get_data_conf_prop(pfe_fit_addr, fw_name, data, size); 108} 109 110/* 111 * Check PFE FIT image 112 * 113 * Return: 0 on success, a negative value on error 114 */ 115static int pfe_fit_check(void) 116{ 117 int ret = 0; 118 119 ret = fdt_check_header(pfe_fit_addr); 120 if (ret) { 121 printf("PFE Firmware: Bad firmware image (not a FIT image)\n"); 122 return ret; 123 } 124 125 if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) { 126 printf("PFE Firmware: Bad firmware image (bad FIT header)\n"); 127 ret = -1; 128 return ret; 129 } 130 131 return ret; 132} 133 134int pfe_spi_flash_init(void) 135{ 136 struct spi_flash *pfe_flash; 137 int ret = 0; 138 void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH); 139 140 if (!addr) 141 return -ENOMEM; 142 143 pfe_flash = spi_flash_probe(CONFIG_SYS_FSL_PFE_SPI_BUS, 144 CONFIG_SYS_FSL_PFE_SPI_CS, 145 CONFIG_SYS_FSL_PFE_SPI_MAX_HZ, 146 CONFIG_SYS_FSL_PFE_SPI_MODE); 147 148 if (!pfe_flash) { 149 printf("SF: probe for pfe failed\n"); 150 free(addr); 151 return -ENODEV; 152 } 153 154 ret = spi_flash_read(pfe_flash, 155 CONFIG_SYS_LS_PFE_FW_ADDR, 156 CONFIG_SYS_LS_PFE_FW_LENGTH, 157 addr); 158 if (ret) { 159 printf("SF: read for pfe failed\n"); 160 free(addr); 161 spi_flash_free(pfe_flash); 162 return ret; 163 } 164 165#ifdef CONFIG_CHAIN_OF_TRUST 166 void *hdr_addr = malloc(CONFIG_SYS_LS_PFE_ESBC_LENGTH); 167 168 if (!hdr_addr) { 169 free(addr); 170 spi_flash_free(pfe_flash); 171 return -ENOMEM; 172 } 173 174 ret = spi_flash_read(pfe_flash, 175 CONFIG_SYS_LS_PFE_ESBC_ADDR, 176 CONFIG_SYS_LS_PFE_ESBC_LENGTH, 177 hdr_addr); 178 if (ret) { 179 printf("SF: failed to read pfe esbc header\n"); 180 free(addr); 181 free(hdr_addr); 182 spi_flash_free(pfe_flash); 183 return ret; 184 } 185 186 pfe_esbc_hdr_addr = hdr_addr; 187#endif 188 pfe_fit_addr = addr; 189 spi_flash_free(pfe_flash); 190 191 return ret; 192} 193 194/* 195 * PFE firmware initialization. 196 * Loads different firmware files from FIT image. 197 * Initializes PE IMEM/DMEM and UTIL-PE DDR 198 * Initializes control path symbol addresses (by looking them up in the elf 199 * firmware files 200 * Takes PE's out of reset 201 * 202 * Return: 0 on success, a negative value on error 203 */ 204int pfe_firmware_init(void) 205{ 206#define PFE_KEY_HASH NULL 207 char *pfe_firmware_name; 208 const void *raw_image_addr; 209 size_t raw_image_size = 0; 210 u8 *pfe_firmware; 211#ifdef CONFIG_CHAIN_OF_TRUST 212 uintptr_t pfe_esbc_hdr = 0; 213 uintptr_t pfe_img_addr = 0; 214#endif 215 int ret = 0; 216 int fw_count, max_fw_count; 217 const char *p; 218 219 ret = pfe_spi_flash_init(); 220 if (ret) 221 goto err; 222 223 ret = pfe_fit_check(); 224 if (ret) 225 goto err; 226 227#ifdef CONFIG_CHAIN_OF_TRUST 228 pfe_esbc_hdr = (uintptr_t)pfe_esbc_hdr_addr; 229 pfe_img_addr = (uintptr_t)pfe_fit_addr; 230 if (fsl_check_boot_mode_secure() != 0) { 231 /* 232 * In case of failure in validation, fsl_secboot_validate 233 * would not return back in case of Production environment 234 * with ITS=1. In Development environment (ITS=0 and 235 * SB_EN=1), the function may return back in case of 236 * non-fatal failures. 237 */ 238 ret = fsl_secboot_validate(pfe_esbc_hdr, 239 PFE_KEY_HASH, 240 &pfe_img_addr); 241 if (ret != 0) 242 printf("PFE firmware(s) validation failed\n"); 243 else 244 printf("PFE firmware(s) validation Successful\n"); 245 } 246#endif 247 248 p = env_get("load_util"); 249 if (!p) { 250 max_fw_count = 2; 251 } else { 252 max_fw_count = dectoul(p, NULL); 253 if (max_fw_count) 254 max_fw_count = 3; 255 else 256 max_fw_count = 2; 257 } 258 259 for (fw_count = 0; fw_count < max_fw_count; fw_count++) { 260 switch (fw_count) { 261 case 0: 262 pfe_firmware_name = "class_slowpath"; 263 break; 264 case 1: 265 pfe_firmware_name = "tmu_slowpath"; 266 break; 267 case 2: 268 pfe_firmware_name = "util_slowpath"; 269 break; 270 } 271 272 if (pfe_get_fw(&raw_image_addr, &raw_image_size, 273 pfe_firmware_name)) { 274 printf("%s firmware couldn't be found in FIT image\n", 275 pfe_firmware_name); 276 break; 277 } 278 pfe_firmware = malloc(raw_image_size); 279 if (!pfe_firmware) 280 return -ENOMEM; 281 memcpy((void *)pfe_firmware, (void *)raw_image_addr, 282 raw_image_size); 283 284 switch (fw_count) { 285 case 0: 286 env_set_addr("class_elf_firmware", pfe_firmware); 287 env_set_addr("class_elf_size", (void *)raw_image_size); 288 break; 289 case 1: 290 env_set_addr("tmu_elf_firmware", pfe_firmware); 291 env_set_addr("tmu_elf_size", (void *)raw_image_size); 292 break; 293 case 2: 294 env_set_addr("util_elf_firmware", pfe_firmware); 295 env_set_addr("util_elf_size", (void *)raw_image_size); 296 break; 297 } 298 } 299 300 raw_image_addr = NULL; 301 pfe_firmware = NULL; 302 raw_image_size = 0; 303 for (fw_count = 0; fw_count < 2; fw_count++) { 304 if (fw_count == 0) 305 pfe_firmware_name = "class"; 306 else if (fw_count == 1) 307 pfe_firmware_name = "tmu"; 308 309 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name); 310 pfe_firmware = malloc(raw_image_size); 311 if (!pfe_firmware) 312 return -ENOMEM; 313 memcpy((void *)pfe_firmware, (void *)raw_image_addr, 314 raw_image_size); 315 316 if (fw_count == 0) 317 ret = pfe_load_elf(CLASS_MASK, pfe_firmware); 318 else if (fw_count == 1) 319 ret = pfe_load_elf(TMU_MASK, pfe_firmware); 320 321 if (ret < 0) { 322 printf("%s: %s firmware load failed\n", __func__, 323 pfe_firmware_name); 324 goto err; 325 } 326 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name); 327 free(pfe_firmware); 328 } 329 330 tmu_enable(0xb); 331 class_enable(); 332 gpi_enable(HGPI_BASE_ADDR); 333 334err: 335 return ret; 336} 337 338/* 339 * PFE firmware cleanup 340 * Puts PE's in reset 341 */ 342void pfe_firmware_exit(void) 343{ 344 debug("%s\n", __func__); 345 346 class_disable(); 347 tmu_disable(0xf); 348 hif_tx_disable(); 349 hif_rx_disable(); 350} 351