1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/slab.h>
16#include <linux/vmalloc.h>
17
18#include <math_support.h>
19#include "platform_support.h"
20#include "sh_css_firmware.h"
21
22#include "sh_css_defs.h"
23#include "ia_css_debug.h"
24#include "sh_css_internal.h"
25#include "ia_css_isp_param.h"
26
27#include "memory_access.h"
28#include "assert_support.h"
29#include "string_support.h"
30
31#include "isp.h"
32
33#include "ia_css_isp_params.h"
34#include "ia_css_isp_configs.h"
35#include "ia_css_isp_states.h"
36
37#define _STR(x) #x
38#define STR(x) _STR(x)
39
40struct firmware_header {
41 struct sh_css_fw_bi_file_h file_header;
42 struct ia_css_fw_info binary_header;
43};
44
45struct fw_param {
46 const char *name;
47 const void *buffer;
48};
49
50
51static struct firmware_header *firmware_header;
52
53
54
55
56#ifndef ISP2401
57static const char *release_version = STR(irci_stable_candrpv_0415_20150521_0458);
58#else
59static const char *release_version = STR(irci_ecr-master_20150911_0724);
60#endif
61
62#define MAX_FW_REL_VER_NAME 300
63static char FW_rel_ver_name[MAX_FW_REL_VER_NAME] = "---";
64
65struct ia_css_fw_info sh_css_sp_fw;
66struct ia_css_blob_descr *sh_css_blob_info;
67unsigned sh_css_num_binaries;
68
69static struct fw_param *fw_minibuffer;
70
71
72char *sh_css_get_fw_version(void)
73{
74 return FW_rel_ver_name;
75}
76
77
78
79
80
81
82
83static enum ia_css_err
84setup_binary(struct ia_css_fw_info *fw, const char *fw_data, struct ia_css_fw_info *sh_css_fw, unsigned binary_id)
85{
86 const char *blob_data;
87
88 if ((fw == NULL) || (fw_data == NULL))
89 return IA_CSS_ERR_INVALID_ARGUMENTS;
90
91 blob_data = fw_data + fw->blob.offset;
92
93 *sh_css_fw = *fw;
94
95 sh_css_fw->blob.code = vmalloc(fw->blob.size);
96 if (sh_css_fw->blob.code == NULL)
97 return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
98
99 memcpy((void *)sh_css_fw->blob.code, blob_data, fw->blob.size);
100 sh_css_fw->blob.data = (char *)sh_css_fw->blob.code + fw->blob.data_source;
101 fw_minibuffer[binary_id].buffer = sh_css_fw->blob.code;
102
103 return IA_CSS_SUCCESS;
104}
105enum ia_css_err
106sh_css_load_blob_info(const char *fw, const struct ia_css_fw_info *bi, struct ia_css_blob_descr *bd, unsigned index)
107{
108 const char *name;
109 const unsigned char *blob;
110
111 if ((fw == NULL) || (bd == NULL))
112 return IA_CSS_ERR_INVALID_ARGUMENTS;
113
114
115 if (bi == NULL) bi = (const struct ia_css_fw_info *)fw;
116
117 name = fw + bi->blob.prog_name_offset;
118 blob = (const unsigned char *)fw + bi->blob.offset;
119
120
121 if (bi->blob.size != bi->blob.text_size + bi->blob.icache_size + bi->blob.data_size + bi->blob.padding_size) {
122
123 return IA_CSS_ERR_INVALID_ARGUMENTS;
124 }
125
126 if ((bi->blob.offset % (1UL<<(ISP_PMEM_WIDTH_LOG2-3))) != 0)
127 return IA_CSS_ERR_INVALID_ARGUMENTS;
128
129 bd->blob = blob;
130 bd->header = *bi;
131
132 if (bi->type == ia_css_isp_firmware || bi->type == ia_css_sp_firmware) {
133 char *namebuffer;
134
135 namebuffer = kstrdup(name, GFP_KERNEL);
136 if (!namebuffer)
137 return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
138 bd->name = fw_minibuffer[index].name = namebuffer;
139 } else {
140 bd->name = name;
141 }
142
143 if (bi->type == ia_css_isp_firmware) {
144 size_t paramstruct_size = sizeof(struct ia_css_memory_offsets);
145 size_t configstruct_size = sizeof(struct ia_css_config_memory_offsets);
146 size_t statestruct_size = sizeof(struct ia_css_state_memory_offsets);
147
148 char *parambuf = (char *)kmalloc(paramstruct_size + configstruct_size + statestruct_size,
149 GFP_KERNEL);
150 if (parambuf == NULL)
151 return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
152
153 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = NULL;
154 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_CONFIG].ptr = NULL;
155 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_STATE].ptr = NULL;
156
157 fw_minibuffer[index].buffer = parambuf;
158
159
160 memcpy(parambuf, (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_PARAM]),
161 paramstruct_size);
162 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = parambuf;
163
164
165 memcpy(parambuf + paramstruct_size,
166 (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_CONFIG]),
167 configstruct_size);
168 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_CONFIG].ptr = parambuf + paramstruct_size;
169
170
171 memcpy(parambuf + paramstruct_size + configstruct_size,
172 (void *)(fw + bi->blob.memory_offsets.offsets[IA_CSS_PARAM_CLASS_STATE]),
173 statestruct_size);
174 bd->mem_offsets.array[IA_CSS_PARAM_CLASS_STATE].ptr = parambuf + paramstruct_size + configstruct_size;
175 }
176 return IA_CSS_SUCCESS;
177}
178
179bool
180sh_css_check_firmware_version(const char *fw_data)
181{
182 struct sh_css_fw_bi_file_h *file_header;
183
184 firmware_header = (struct firmware_header *)fw_data;
185 file_header = &firmware_header->file_header;
186
187 if (strcmp(file_header->version, release_version) != 0) {
188 return false;
189 } else {
190
191 return true;
192 }
193}
194
195enum ia_css_err
196sh_css_load_firmware(const char *fw_data,
197 unsigned int fw_size)
198{
199 unsigned i;
200 struct ia_css_fw_info *binaries;
201 struct sh_css_fw_bi_file_h *file_header;
202 bool valid_firmware = false;
203
204 firmware_header = (struct firmware_header *)fw_data;
205 file_header = &firmware_header->file_header;
206 binaries = &firmware_header->binary_header;
207 strncpy(FW_rel_ver_name, file_header->version, min(sizeof(FW_rel_ver_name), sizeof(file_header->version)) - 1);
208 valid_firmware = sh_css_check_firmware_version(fw_data);
209 if (!valid_firmware) {
210#if !defined(HRT_RTL)
211 IA_CSS_ERROR("CSS code version (%s) and firmware version (%s) mismatch!",
212 file_header->version, release_version);
213 return IA_CSS_ERR_VERSION_MISMATCH;
214#endif
215 } else {
216 IA_CSS_LOG("successfully load firmware version %s", release_version);
217 }
218
219
220 if (!fw_data || fw_size < sizeof(struct sh_css_fw_bi_file_h))
221 return IA_CSS_ERR_INTERNAL_ERROR;
222
223 if (file_header->h_size != sizeof(struct sh_css_fw_bi_file_h))
224 return IA_CSS_ERR_INTERNAL_ERROR;
225
226 sh_css_num_binaries = file_header->binary_nr;
227
228 if (sh_css_num_binaries > NUM_OF_SPS) {
229 sh_css_blob_info = kmalloc(
230 (sh_css_num_binaries - NUM_OF_SPS) *
231 sizeof(*sh_css_blob_info), GFP_KERNEL);
232 if (sh_css_blob_info == NULL)
233 return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
234 } else {
235 sh_css_blob_info = NULL;
236 }
237
238 fw_minibuffer = kzalloc(sh_css_num_binaries * sizeof(struct fw_param), GFP_KERNEL);
239 if (fw_minibuffer == NULL)
240 return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
241
242 for (i = 0; i < sh_css_num_binaries; i++) {
243 struct ia_css_fw_info *bi = &binaries[i];
244
245
246
247
248 static struct ia_css_blob_descr bd;
249 enum ia_css_err err;
250
251 err = sh_css_load_blob_info(fw_data, bi, &bd, i);
252
253 if (err != IA_CSS_SUCCESS)
254 return IA_CSS_ERR_INTERNAL_ERROR;
255
256 if (bi->blob.offset + bi->blob.size > fw_size)
257 return IA_CSS_ERR_INTERNAL_ERROR;
258
259 if (bi->type == ia_css_sp_firmware) {
260 if (i != SP_FIRMWARE)
261 return IA_CSS_ERR_INTERNAL_ERROR;
262 err = setup_binary(bi, fw_data, &sh_css_sp_fw, i);
263 if (err != IA_CSS_SUCCESS)
264 return err;
265 } else {
266
267 if (i < NUM_OF_SPS)
268 return IA_CSS_ERR_INTERNAL_ERROR;
269
270 if (bi->type != ia_css_isp_firmware)
271 return IA_CSS_ERR_INTERNAL_ERROR;
272 if (sh_css_blob_info == NULL)
273 return IA_CSS_ERR_INTERNAL_ERROR;
274 sh_css_blob_info[i - NUM_OF_SPS] = bd;
275 }
276 }
277
278 return IA_CSS_SUCCESS;
279}
280
281void sh_css_unload_firmware(void)
282{
283
284
285 if (fw_minibuffer) {
286 unsigned int i = 0;
287 for (i = 0; i < sh_css_num_binaries; i++) {
288 if (fw_minibuffer[i].name)
289 kfree((void *)fw_minibuffer[i].name);
290 if (fw_minibuffer[i].buffer)
291 vfree((void *)fw_minibuffer[i].buffer);
292 }
293 kfree(fw_minibuffer);
294 fw_minibuffer = NULL;
295 }
296
297 memset(&sh_css_sp_fw, 0, sizeof(sh_css_sp_fw));
298 if (sh_css_blob_info) {
299 kfree(sh_css_blob_info);
300 sh_css_blob_info = NULL;
301 }
302 sh_css_num_binaries = 0;
303}
304
305hrt_vaddress
306sh_css_load_blob(const unsigned char *blob, unsigned size)
307{
308 hrt_vaddress target_addr = mmgr_malloc(size);
309
310
311
312 assert(blob != NULL);
313 if (target_addr)
314 mmgr_store(target_addr, blob, size);
315 return target_addr;
316}
317