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