Home | History | Annotate | Download | only in pfe_eth
      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