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 #ifdef CONFIG_CHAIN_OF_TRUST 16 #include <fsl_validate.h> 17 #endif 18 19 #define PFE_FIRMEWARE_FIT_CNF_NAME "config@1" 20 21 static const void *pfe_fit_addr = (void *)CONFIG_SYS_LS_PFE_FW_ADDR; 22 23 /* 24 * PFE elf firmware loader. 25 * Loads an elf firmware image into a list of PE's (specified using a bitmask) 26 * 27 * @param pe_mask Mask of PE id's to load firmware to 28 * @param pfe_firmware Pointer to the firmware image 29 * 30 * @return 0 on success, a negative value on error 31 */ 32 static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware) 33 { 34 Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware; 35 Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum); 36 Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware + 37 be32_to_cpu(elf_hdr->e_shoff)); 38 int id, section; 39 int ret; 40 41 debug("%s: no of sections: %d\n", __func__, sections); 42 43 /* Some sanity checks */ 44 if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) { 45 printf("%s: incorrect elf magic number\n", __func__); 46 return -1; 47 } 48 49 if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) { 50 printf("%s: incorrect elf class(%x)\n", __func__, 51 elf_hdr->e_ident[EI_CLASS]); 52 return -1; 53 } 54 55 if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) { 56 printf("%s: incorrect elf data(%x)\n", __func__, 57 elf_hdr->e_ident[EI_DATA]); 58 return -1; 59 } 60 61 if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) { 62 printf("%s: incorrect elf file type(%x)\n", __func__, 63 be16_to_cpu(elf_hdr->e_type)); 64 return -1; 65 } 66 67 for (section = 0; section < sections; section++, shdr++) { 68 if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC | 69 SHF_EXECINSTR))) 70 continue; 71 for (id = 0; id < MAX_PE; id++) 72 if (pe_mask & BIT(id)) { 73 ret = pe_load_elf_section(id, 74 pfe_firmware, shdr); 75 if (ret < 0) 76 goto err; 77 } 78 } 79 return 0; 80 81 err: 82 return ret; 83 } 84 85 /* 86 * Get PFE firmware from FIT image 87 * 88 * @param data pointer to PFE firmware 89 * @param size pointer to size of the firmware 90 * @param fw_name pfe firmware name, either class or tmu 91 * 92 * @return 0 on success, a negative value on error 93 */ 94 static int pfe_get_fw(const void **data, 95 size_t *size, char *fw_name) 96 { 97 int conf_node_off, fw_node_off; 98 char *conf_node_name = NULL; 99 char *desc; 100 int ret = 0; 101 102 conf_node_name = PFE_FIRMEWARE_FIT_CNF_NAME; 103 104 conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name); 105 if (conf_node_off < 0) { 106 printf("PFE Firmware: %s: no such config\n", conf_node_name); 107 return -ENOENT; 108 } 109 110 fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off, 111 fw_name); 112 if (fw_node_off < 0) { 113 printf("PFE Firmware: No '%s' in config\n", 114 fw_name); 115 return -ENOLINK; 116 } 117 118 if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) { 119 printf("PFE Firmware: Bad firmware image (bad CRC)\n"); 120 return -EINVAL; 121 } 122 123 if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) { 124 printf("PFE Firmware: Can't get %s subimage data/size", 125 fw_name); 126 return -ENOENT; 127 } 128 129 ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc); 130 if (ret) 131 printf("PFE Firmware: Can't get description\n"); 132 else 133 printf("%s\n", desc); 134 135 return ret; 136 } 137 138 /* 139 * Check PFE FIT image 140 * 141 * @return 0 on success, a negative value on error 142 */ 143 static int pfe_fit_check(void) 144 { 145 int ret = 0; 146 147 ret = fdt_check_header(pfe_fit_addr); 148 if (ret) { 149 printf("PFE Firmware: Bad firmware image (not a FIT image)\n"); 150 return ret; 151 } 152 153 if (!fit_check_format(pfe_fit_addr)) { 154 printf("PFE Firmware: Bad firmware image (bad FIT header)\n"); 155 ret = -1; 156 return ret; 157 } 158 159 return ret; 160 } 161 162 /* 163 * PFE firmware initialization. 164 * Loads different firmware files from FIT image. 165 * Initializes PE IMEM/DMEM and UTIL-PE DDR 166 * Initializes control path symbol addresses (by looking them up in the elf 167 * firmware files 168 * Takes PE's out of reset 169 * 170 * @return 0 on success, a negative value on error 171 */ 172 int pfe_firmware_init(void) 173 { 174 #define PFE_KEY_HASH NULL 175 char *pfe_firmware_name; 176 const void *raw_image_addr; 177 size_t raw_image_size = 0; 178 u8 *pfe_firmware; 179 #ifdef CONFIG_CHAIN_OF_TRUST 180 uintptr_t pfe_esbc_hdr = 0; 181 uintptr_t pfe_img_addr = 0; 182 #endif 183 int ret = 0; 184 int fw_count; 185 186 ret = pfe_fit_check(); 187 if (ret) 188 goto err; 189 190 #ifdef CONFIG_CHAIN_OF_TRUST 191 pfe_esbc_hdr = CONFIG_SYS_LS_PFE_ESBC_ADDR; 192 pfe_img_addr = (uintptr_t)pfe_fit_addr; 193 if (fsl_check_boot_mode_secure() != 0) { 194 /* 195 * In case of failure in validation, fsl_secboot_validate 196 * would not return back in case of Production environment 197 * with ITS=1. In Development environment (ITS=0 and 198 * SB_EN=1), the function may return back in case of 199 * non-fatal failures. 200 */ 201 ret = fsl_secboot_validate(pfe_esbc_hdr, 202 PFE_KEY_HASH, 203 &pfe_img_addr); 204 if (ret != 0) 205 printf("PFE firmware(s) validation failed\n"); 206 else 207 printf("PFE firmware(s) validation Successful\n"); 208 } 209 #endif 210 211 for (fw_count = 0; fw_count < 2; fw_count++) { 212 if (fw_count == 0) 213 pfe_firmware_name = "class"; 214 else if (fw_count == 1) 215 pfe_firmware_name = "tmu"; 216 217 pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name); 218 pfe_firmware = malloc(raw_image_size); 219 if (!pfe_firmware) 220 return -ENOMEM; 221 memcpy((void *)pfe_firmware, (void *)raw_image_addr, 222 raw_image_size); 223 224 if (fw_count == 0) 225 ret = pfe_load_elf(CLASS_MASK, pfe_firmware); 226 else if (fw_count == 1) 227 ret = pfe_load_elf(TMU_MASK, pfe_firmware); 228 229 if (ret < 0) { 230 printf("%s: %s firmware load failed\n", __func__, 231 pfe_firmware_name); 232 goto err; 233 } 234 debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name); 235 free(pfe_firmware); 236 } 237 238 tmu_enable(0xb); 239 class_enable(); 240 gpi_enable(HGPI_BASE_ADDR); 241 242 err: 243 return ret; 244 } 245 246 /* 247 * PFE firmware cleanup 248 * Puts PE's in reset 249 */ 250 void pfe_firmware_exit(void) 251 { 252 debug("%s\n", __func__); 253 254 class_disable(); 255 tmu_disable(0xf); 256 hif_tx_disable(); 257 hif_rx_disable(); 258 } 259