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