2 * Support for Intel Camera Imaging ISP subsystem.
3 * Copyright (c) 2015, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include <linux/slab.h>
16 #include <linux/vmalloc.h>
20 #include <math_support.h>
21 #include "platform_support.h"
22 #include "sh_css_firmware.h"
24 #include "sh_css_defs.h"
25 #include "ia_css_debug.h"
26 #include "sh_css_internal.h"
27 #include "ia_css_isp_param.h"
29 #include "assert_support.h"
30 #include "string_support.h"
32 #include "isp.h" /* PMEM_WIDTH_LOG2 */
34 #include "ia_css_isp_params.h"
35 #include "ia_css_isp_configs.h"
36 #include "ia_css_isp_states.h"
39 #define STR(x) _STR(x)
41 struct firmware_header {
42 struct sh_css_fw_bi_file_h file_header;
43 struct ia_css_fw_info binary_header;
51 static struct firmware_header *firmware_header;
53 /* The string STR is a place holder
54 * which will be replaced with the actual RELEASE_VERSION
55 * during package generation. Please do not modify */
56 static const char *isp2400_release_version = STR(irci_stable_candrpv_0415_20150521_0458);
57 static const char *isp2401_release_version = STR(irci_ecr - master_20150911_0724);
59 #define MAX_FW_REL_VER_NAME 300
60 static char FW_rel_ver_name[MAX_FW_REL_VER_NAME] = "---";
62 struct ia_css_fw_info sh_css_sp_fw;
63 struct ia_css_blob_descr *sh_css_blob_info; /* Only ISP blob info (no SP) */
64 unsigned int sh_css_num_binaries; /* This includes 1 SP binary */
66 static struct fw_param *fw_minibuffer;
68 char *sh_css_get_fw_version(void)
70 return FW_rel_ver_name;
74 * Split the loaded firmware into blobs
77 /* Setup sp/sp1 binary */
79 setup_binary(struct ia_css_fw_info *fw, const char *fw_data,
80 struct ia_css_fw_info *sh_css_fw, unsigned int binary_id) {
81 const char *blob_data;
83 if ((!fw) || (!fw_data))
86 blob_data = fw_data + fw->blob.offset;
90 sh_css_fw->blob.code = vmalloc(fw->blob.size);
91 if (!sh_css_fw->blob.code)
94 memcpy((void *)sh_css_fw->blob.code, blob_data, fw->blob.size);
95 sh_css_fw->blob.data = (char *)sh_css_fw->blob.code + fw->blob.data_source;
96 fw_minibuffer[binary_id].buffer = sh_css_fw->blob.code;
102 sh_css_load_blob_info(const char *fw, const struct ia_css_fw_info *bi,
103 struct ia_css_blob_descr *bd,
104 unsigned int index) {
106 const unsigned char *blob;
111 /* Special case: only one binary in fw */
112 if (!bi) bi = (const struct ia_css_fw_info *)fw;
114 name = fw + bi->blob.prog_name_offset;
115 blob = (const unsigned char *)fw + bi->blob.offset;
118 if (bi->blob.size != bi->blob.text_size + bi->blob.icache_size + bi->blob.data_size + bi->blob.padding_size)
120 /* sanity check, note the padding bytes added for section to DDR alignment */
124 if ((bi->blob.offset % (1UL << (ISP_PMEM_WIDTH_LOG2 - 3))) != 0)
130 if (bi->type == ia_css_isp_firmware || bi->type == ia_css_sp_firmware)
134 namebuffer = kstrdup(name, GFP_KERNEL);
137 bd->name = fw_minibuffer[index].name = namebuffer;
143 if (bi->type == ia_css_isp_firmware)
145 size_t paramstruct_size = sizeof(struct ia_css_memory_offsets);
146 size_t configstruct_size = sizeof(struct ia_css_config_memory_offsets);
147 size_t statestruct_size = sizeof(struct ia_css_state_memory_offsets);
149 char *parambuf = kmalloc(paramstruct_size + configstruct_size +
155 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = NULL;
156 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_CONFIG].ptr = NULL;
157 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_STATE].ptr = NULL;
159 fw_minibuffer[index].buffer = parambuf;
161 /* copy ia_css_memory_offsets */
162 memcpy(parambuf, (void *)(fw +
163 bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_PARAM]),
165 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = parambuf;
167 /* copy ia_css_config_memory_offsets */
168 memcpy(parambuf + paramstruct_size,
169 (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_CONFIG]),
171 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_CONFIG].ptr = parambuf +
174 /* copy ia_css_state_memory_offsets */
175 memcpy(parambuf + paramstruct_size + configstruct_size,
176 (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_STATE]),
178 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_STATE].ptr = parambuf +
179 paramstruct_size + configstruct_size;
185 sh_css_check_firmware_version(struct device *dev, const char *fw_data)
187 struct sh_css_fw_bi_file_h *file_header;
189 const char *release_version;
191 if (!atomisp_hw_is_isp2401)
192 release_version = isp2400_release_version;
194 release_version = isp2401_release_version;
196 firmware_header = (struct firmware_header *)fw_data;
197 file_header = &firmware_header->file_header;
199 if (strcmp(file_header->version, release_version) != 0) {
200 dev_err(dev, "Firmware version may not be compatible with this driver\n");
201 dev_err(dev, "Expecting version '%s', but firmware is '%s'.\n",
202 release_version, file_header->version);
205 /* For now, let's just accept a wrong version, even if wrong */
210 sh_css_load_firmware(struct device *dev, const char *fw_data,
211 unsigned int fw_size) {
213 struct ia_css_fw_info *binaries;
214 struct sh_css_fw_bi_file_h *file_header;
216 const char *release_version;
218 if (!atomisp_hw_is_isp2401)
219 release_version = isp2400_release_version;
221 release_version = isp2401_release_version;
223 firmware_header = (struct firmware_header *)fw_data;
224 file_header = &firmware_header->file_header;
225 binaries = &firmware_header->binary_header;
226 strscpy(FW_rel_ver_name, file_header->version, min(sizeof(FW_rel_ver_name), sizeof(file_header->version)));
227 ret = sh_css_check_firmware_version(dev, fw_data);
229 IA_CSS_ERROR("CSS code version (%s) and firmware version (%s) mismatch!",
230 file_header->version, release_version);
233 IA_CSS_LOG("successfully load firmware version %s", release_version);
236 /* some sanity checks */
237 if (!fw_data || fw_size < sizeof(struct sh_css_fw_bi_file_h))
240 if (file_header->h_size != sizeof(struct sh_css_fw_bi_file_h))
243 sh_css_num_binaries = file_header->binary_nr;
244 /* Only allocate memory for ISP blob info */
245 if (sh_css_num_binaries > NUM_OF_SPS)
247 sh_css_blob_info = kmalloc(
248 (sh_css_num_binaries - NUM_OF_SPS) *
249 sizeof(*sh_css_blob_info), GFP_KERNEL);
250 if (!sh_css_blob_info)
253 sh_css_blob_info = NULL;
256 fw_minibuffer = kcalloc(sh_css_num_binaries, sizeof(struct fw_param),
261 for (i = 0; i < sh_css_num_binaries; i++)
263 struct ia_css_fw_info *bi = &binaries[i];
264 /* note: the var below is made static as it is quite large;
265 if it is not static it ends up on the stack which could
266 cause issues for drivers
268 static struct ia_css_blob_descr bd;
271 err = sh_css_load_blob_info(fw_data, bi, &bd, i);
276 if (bi->blob.offset + bi->blob.size > fw_size)
279 if (bi->type == ia_css_sp_firmware) {
280 if (i != SP_FIRMWARE)
282 err = setup_binary(bi, fw_data, &sh_css_sp_fw, i);
285 dev_dbg(dev, "firmware #%d (SP), name %s\n", i, bd.name);
288 /* All subsequent binaries (including bootloaders) (i>NUM_OF_SPS) are ISP firmware */
292 if (bi->type != ia_css_isp_firmware)
294 if (!sh_css_blob_info) /* cannot happen but KW does not see this */
296 sh_css_blob_info[i - NUM_OF_SPS] = bd;
303 void sh_css_unload_firmware(void)
305 /* release firmware minibuffer */
309 for (i = 0; i < sh_css_num_binaries; i++) {
310 if (fw_minibuffer[i].name)
311 kfree((void *)fw_minibuffer[i].name);
312 if (fw_minibuffer[i].buffer)
313 vfree((void *)fw_minibuffer[i].buffer);
315 kfree(fw_minibuffer);
316 fw_minibuffer = NULL;
319 memset(&sh_css_sp_fw, 0, sizeof(sh_css_sp_fw));
320 kfree(sh_css_blob_info);
321 sh_css_blob_info = NULL;
322 sh_css_num_binaries = 0;
326 sh_css_load_blob(const unsigned char *blob, unsigned int size)
328 ia_css_ptr target_addr = hmm_alloc(size, HMM_BO_PRIVATE, 0, NULL, 0);
329 /* this will allocate memory aligned to a DDR word boundary which
330 is required for the CSS DMA to read the instructions. */
334 hmm_store(target_addr, blob, size);