1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for Intel Camera Imaging ISP subsystem. 4 * Copyright (c) 2015, Intel Corporation. 5 */ 6 7 #include <linux/string.h> /* for memcpy() */ 8 #include <linux/slab.h> 9 #include <linux/vmalloc.h> 10 11 #include "hmm.h" 12 13 #include <math_support.h> 14 #include "platform_support.h" 15 #include "sh_css_firmware.h" 16 17 #include "sh_css_defs.h" 18 #include "ia_css_debug.h" 19 #include "sh_css_internal.h" 20 #include "ia_css_isp_param.h" 21 22 #include "assert_support.h" 23 24 #include "isp.h" /* PMEM_WIDTH_LOG2 */ 25 26 #include "ia_css_isp_params.h" 27 #include "ia_css_isp_configs.h" 28 #include "ia_css_isp_states.h" 29 30 #define _STR(x) #x 31 #define STR(x) _STR(x) 32 33 struct firmware_header { 34 struct sh_css_fw_bi_file_h file_header; 35 struct ia_css_fw_info binary_header; 36 }; 37 38 struct fw_param { 39 const char *name; 40 const void *buffer; 41 }; 42 43 static struct firmware_header *firmware_header; 44 45 /* 46 * The string STR is a place holder 47 * which will be replaced with the actual RELEASE_VERSION 48 * during package generation. Please do not modify 49 */ 50 static const char *release_version_2401 = STR(irci_stable_candrpv_0415_20150521_0458); 51 static const char *release_version_2400 = STR(irci_stable_candrpv_0415_20150423_1753); 52 53 #define MAX_FW_REL_VER_NAME 300 54 static char FW_rel_ver_name[MAX_FW_REL_VER_NAME] = "---"; 55 56 struct ia_css_fw_info sh_css_sp_fw; 57 struct ia_css_blob_descr *sh_css_blob_info; /* Only ISP blob info (no SP) */ 58 unsigned int sh_css_num_binaries; /* This includes 1 SP binary */ 59 60 static struct fw_param *fw_minibuffer; 61 62 char *sh_css_get_fw_version(void) 63 { 64 return FW_rel_ver_name; 65 } 66 67 /* 68 * Split the loaded firmware into blobs 69 */ 70 71 /* Setup sp/sp1 binary */ 72 static int 73 setup_binary(struct ia_css_fw_info *fw, const char *fw_data, 74 struct ia_css_fw_info *sh_css_fw, unsigned int binary_id) 75 { 76 const char *blob_data; 77 78 if ((!fw) || (!fw_data)) 79 return -EINVAL; 80 81 blob_data = fw_data + fw->blob.offset; 82 83 *sh_css_fw = *fw; 84 85 sh_css_fw->blob.code = vmalloc(fw->blob.size); 86 if (!sh_css_fw->blob.code) 87 return -ENOMEM; 88 89 memcpy((void *)sh_css_fw->blob.code, blob_data, fw->blob.size); 90 sh_css_fw->blob.data = (char *)sh_css_fw->blob.code + fw->blob.data_source; 91 fw_minibuffer[binary_id].buffer = sh_css_fw->blob.code; 92 93 return 0; 94 } 95 96 int 97 sh_css_load_blob_info(const char *fw, const struct ia_css_fw_info *bi, 98 struct ia_css_blob_descr *bd, 99 unsigned int index) 100 { 101 const char *name; 102 const unsigned char *blob; 103 104 if ((!fw) || (!bd)) 105 return -EINVAL; 106 107 /* Special case: only one binary in fw */ 108 if (!bi) 109 bi = (const struct ia_css_fw_info *)fw; 110 111 name = fw + bi->blob.prog_name_offset; 112 blob = (const unsigned char *)fw + bi->blob.offset; 113 114 /* sanity check */ 115 if (bi->blob.size != 116 bi->blob.text_size + bi->blob.icache_size + 117 bi->blob.data_size + bi->blob.padding_size) { 118 /* sanity check, note the padding bytes added for section to DDR alignment */ 119 return -EINVAL; 120 } 121 122 if ((bi->blob.offset % (1UL << (ISP_PMEM_WIDTH_LOG2 - 3))) != 0) 123 return -EINVAL; 124 125 bd->blob = blob; 126 bd->header = *bi; 127 128 if (bi->type == ia_css_isp_firmware || bi->type == ia_css_sp_firmware) { 129 char *namebuffer; 130 131 namebuffer = kstrdup(name, GFP_KERNEL); 132 if (!namebuffer) 133 return -ENOMEM; 134 bd->name = fw_minibuffer[index].name = namebuffer; 135 } else { 136 bd->name = name; 137 } 138 139 if (bi->type == ia_css_isp_firmware) { 140 size_t paramstruct_size = sizeof(struct ia_css_memory_offsets); 141 size_t configstruct_size = sizeof(struct ia_css_config_memory_offsets); 142 size_t statestruct_size = sizeof(struct ia_css_state_memory_offsets); 143 144 char *parambuf = kmalloc(paramstruct_size + configstruct_size + 145 statestruct_size, 146 GFP_KERNEL); 147 if (!parambuf) 148 return -ENOMEM; 149 150 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = NULL; 151 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_CONFIG].ptr = NULL; 152 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_STATE].ptr = NULL; 153 154 fw_minibuffer[index].buffer = parambuf; 155 156 /* copy ia_css_memory_offsets */ 157 memcpy(parambuf, (void *)(fw + 158 bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_PARAM]), 159 paramstruct_size); 160 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = parambuf; 161 162 /* copy ia_css_config_memory_offsets */ 163 memcpy(parambuf + paramstruct_size, 164 (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_CONFIG]), 165 configstruct_size); 166 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_CONFIG].ptr = parambuf + 167 paramstruct_size; 168 169 /* copy ia_css_state_memory_offsets */ 170 memcpy(parambuf + paramstruct_size + configstruct_size, 171 (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_STATE]), 172 statestruct_size); 173 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_STATE].ptr = parambuf + 174 paramstruct_size + configstruct_size; 175 } 176 return 0; 177 } 178 179 bool 180 sh_css_check_firmware_version(struct device *dev, const char *fw_data) 181 { 182 const char *release_version; 183 struct sh_css_fw_bi_file_h *file_header; 184 185 if (IS_ISP2401) 186 release_version = release_version_2401; 187 else 188 release_version = release_version_2400; 189 190 firmware_header = (struct firmware_header *)fw_data; 191 file_header = &firmware_header->file_header; 192 193 if (strcmp(file_header->version, release_version) != 0) { 194 dev_err(dev, "Firmware version may not be compatible with this driver\n"); 195 dev_err(dev, "Expecting version '%s', but firmware is '%s'.\n", 196 release_version, file_header->version); 197 } 198 199 /* For now, let's just accept a wrong version, even if wrong */ 200 return false; 201 } 202 203 static const char * const fw_type_name[] = { 204 [ia_css_sp_firmware] = "SP", 205 [ia_css_isp_firmware] = "ISP", 206 [ia_css_bootloader_firmware] = "BootLoader", 207 [ia_css_acc_firmware] = "accel", 208 }; 209 210 static const char * const fw_acc_type_name[] = { 211 [IA_CSS_ACC_NONE] = "Normal", 212 [IA_CSS_ACC_OUTPUT] = "Accel for output", 213 [IA_CSS_ACC_VIEWFINDER] = "Accel for viewfinder", 214 [IA_CSS_ACC_STANDALONE] = "Stand-alone accel", 215 }; 216 217 int 218 sh_css_load_firmware(struct device *dev, const char *fw_data, 219 unsigned int fw_size) 220 { 221 unsigned int i; 222 const char *release_version; 223 struct ia_css_fw_info *binaries; 224 struct sh_css_fw_bi_file_h *file_header; 225 int ret; 226 227 /* some sanity checks */ 228 if (!fw_data || fw_size < sizeof(struct sh_css_fw_bi_file_h)) 229 return -EINVAL; 230 231 firmware_header = (struct firmware_header *)fw_data; 232 file_header = &firmware_header->file_header; 233 234 if (file_header->h_size != sizeof(struct sh_css_fw_bi_file_h)) 235 return -EINVAL; 236 237 binaries = &firmware_header->binary_header; 238 strscpy(FW_rel_ver_name, file_header->version, 239 min(sizeof(FW_rel_ver_name), sizeof(file_header->version))); 240 if (IS_ISP2401) 241 release_version = release_version_2401; 242 else 243 release_version = release_version_2400; 244 ret = sh_css_check_firmware_version(dev, fw_data); 245 if (ret) { 246 IA_CSS_ERROR("CSS code version (%s) and firmware version (%s) mismatch!", 247 file_header->version, release_version); 248 return -EINVAL; 249 } else { 250 IA_CSS_LOG("successfully load firmware version %s", release_version); 251 } 252 253 sh_css_num_binaries = file_header->binary_nr; 254 /* Only allocate memory for ISP blob info */ 255 if (sh_css_num_binaries > NUM_OF_SPS) { 256 sh_css_blob_info = 257 kmalloc_array(sh_css_num_binaries - NUM_OF_SPS, 258 sizeof(*sh_css_blob_info), GFP_KERNEL); 259 if (!sh_css_blob_info) 260 return -ENOMEM; 261 } else { 262 sh_css_blob_info = NULL; 263 } 264 265 fw_minibuffer = kzalloc_objs(struct fw_param, sh_css_num_binaries); 266 if (!fw_minibuffer) 267 return -ENOMEM; 268 269 for (i = 0; i < sh_css_num_binaries; i++) { 270 struct ia_css_fw_info *bi = &binaries[i]; 271 /* 272 * note: the var below is made static as it is quite large; 273 * if it is not static it ends up on the stack which could 274 * cause issues for drivers 275 */ 276 static struct ia_css_blob_descr bd; 277 int err; 278 279 err = sh_css_load_blob_info(fw_data, bi, &bd, i); 280 281 if (err) 282 return -EINVAL; 283 284 if (bi->blob.offset + bi->blob.size > fw_size) 285 return -EINVAL; 286 287 switch (bd.header.type) { 288 case ia_css_isp_firmware: 289 if (bd.header.info.isp.type > IA_CSS_ACC_STANDALONE) { 290 dev_err(dev, "binary #%2d: invalid SP type\n", 291 i); 292 return -EINVAL; 293 } 294 295 dev_dbg(dev, 296 "binary #%-2d type %s (%s), binary id is %2d: %s\n", 297 i, 298 fw_type_name[bd.header.type], 299 fw_acc_type_name[bd.header.info.isp.type], 300 bd.header.info.isp.sp.id, 301 bd.name); 302 break; 303 case ia_css_sp_firmware: 304 case ia_css_bootloader_firmware: 305 case ia_css_acc_firmware: 306 dev_dbg(dev, 307 "binary #%-2d type %s: %s\n", 308 i, fw_type_name[bd.header.type], 309 bd.name); 310 break; 311 default: 312 if (bd.header.info.isp.type > IA_CSS_ACC_STANDALONE) { 313 dev_err(dev, 314 "binary #%2d: invalid firmware type\n", 315 i); 316 return -EINVAL; 317 } 318 break; 319 } 320 321 if (bi->type == ia_css_sp_firmware) { 322 if (i != SP_FIRMWARE) 323 return -EINVAL; 324 err = setup_binary(bi, fw_data, &sh_css_sp_fw, i); 325 if (err) 326 return err; 327 328 } else { 329 /* 330 * All subsequent binaries 331 * (including bootloaders) (i>NUM_OF_SPS) 332 * are ISP firmware 333 */ 334 if (i < NUM_OF_SPS) 335 return -EINVAL; 336 337 if (bi->type != ia_css_isp_firmware) 338 return -EINVAL; 339 if (!sh_css_blob_info) /* cannot happen but KW does not see this */ 340 return -EINVAL; 341 sh_css_blob_info[i - NUM_OF_SPS] = bd; 342 } 343 } 344 345 return 0; 346 } 347 348 void sh_css_unload_firmware(void) 349 { 350 /* release firmware minibuffer */ 351 if (fw_minibuffer) { 352 unsigned int i = 0; 353 354 for (i = 0; i < sh_css_num_binaries; i++) { 355 kfree(fw_minibuffer[i].name); 356 kvfree(fw_minibuffer[i].buffer); 357 } 358 kfree(fw_minibuffer); 359 fw_minibuffer = NULL; 360 } 361 362 memset(&sh_css_sp_fw, 0, sizeof(sh_css_sp_fw)); 363 kfree(sh_css_blob_info); 364 sh_css_blob_info = NULL; 365 sh_css_num_binaries = 0; 366 } 367 368 ia_css_ptr 369 sh_css_load_blob(const unsigned char *blob, unsigned int size) 370 { 371 ia_css_ptr target_addr = hmm_alloc(size); 372 /* 373 * this will allocate memory aligned to a DDR word boundary which 374 * is required for the CSS DMA to read the instructions. 375 */ 376 377 assert(blob); 378 if (target_addr) 379 hmm_store(target_addr, blob, size); 380 return target_addr; 381 } 382