2 * Support for Clovertrail PNW Camera Imaging ISP subsystem.
4 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * This file implements loadable acceleration firmware API,
24 * including ioctls to map and unmap acceleration parameters and buffers.
27 #include <linux/init.h>
28 #include <media/v4l2-event.h>
30 #include "atomisp_acc.h"
31 #include "atomisp_internal.h"
32 #include "atomisp_compat.h"
33 #include "atomisp_cmd.h"
35 #include "hrt/hive_isp_css_mm_hrt.h"
36 #include "memory_access/memory_access.h"
41 enum atomisp_css_pipe_id pipe_id;
42 } acc_flag_to_pipe[] = {
43 { ATOMISP_ACC_FW_LOAD_FL_PREVIEW, CSS_PIPE_ID_PREVIEW },
44 { ATOMISP_ACC_FW_LOAD_FL_COPY, CSS_PIPE_ID_COPY },
45 { ATOMISP_ACC_FW_LOAD_FL_VIDEO, CSS_PIPE_ID_VIDEO },
46 { ATOMISP_ACC_FW_LOAD_FL_CAPTURE, CSS_PIPE_ID_CAPTURE },
47 { ATOMISP_ACC_FW_LOAD_FL_ACC, CSS_PIPE_ID_ACC }
51 * Allocate struct atomisp_acc_fw along with space for firmware.
52 * The returned struct atomisp_acc_fw is cleared (firmware region is not).
54 static struct atomisp_acc_fw *acc_alloc_fw(unsigned int fw_size)
56 struct atomisp_acc_fw *acc_fw;
58 acc_fw = kzalloc(sizeof(*acc_fw), GFP_KERNEL);
62 acc_fw->fw = vmalloc(fw_size);
71 static void acc_free_fw(struct atomisp_acc_fw *acc_fw)
77 static struct atomisp_acc_fw *
78 acc_get_fw(struct atomisp_sub_device *asd, unsigned int handle)
80 struct atomisp_acc_fw *acc_fw;
82 list_for_each_entry(acc_fw, &asd->acc.fw, list)
83 if (acc_fw->handle == handle)
89 static struct atomisp_map *acc_get_map(struct atomisp_sub_device *asd,
90 unsigned long css_ptr, size_t length)
92 struct atomisp_map *atomisp_map;
94 list_for_each_entry(atomisp_map, &asd->acc.memory_maps, list) {
95 if (atomisp_map->ptr == css_ptr &&
96 atomisp_map->length == length)
102 static int acc_stop_acceleration(struct atomisp_sub_device *asd)
106 ret = atomisp_css_stop_acc_pipe(asd);
107 atomisp_css_destroy_acc_pipe(asd);
112 void atomisp_acc_cleanup(struct atomisp_device *isp)
116 for (i = 0; i < isp->num_of_streams; i++)
117 ida_destroy(&isp->asd[i].acc.ida);
120 void atomisp_acc_release(struct atomisp_sub_device *asd)
122 struct atomisp_acc_fw *acc_fw, *ta;
123 struct atomisp_map *atomisp_map, *tm;
125 /* Stop acceleration if already running */
126 if (asd->acc.pipeline)
127 acc_stop_acceleration(asd);
129 /* Unload all loaded acceleration binaries */
130 list_for_each_entry_safe(acc_fw, ta, &asd->acc.fw, list) {
131 list_del(&acc_fw->list);
132 ida_remove(&asd->acc.ida, acc_fw->handle);
136 /* Free all mapped memory blocks */
137 list_for_each_entry_safe(atomisp_map, tm, &asd->acc.memory_maps, list) {
138 list_del(&atomisp_map->list);
139 hmm_free(atomisp_map->ptr);
144 int atomisp_acc_load_to_pipe(struct atomisp_sub_device *asd,
145 struct atomisp_acc_fw_load_to_pipe *user_fw)
147 static const unsigned int pipeline_flags =
148 ATOMISP_ACC_FW_LOAD_FL_PREVIEW | ATOMISP_ACC_FW_LOAD_FL_COPY |
149 ATOMISP_ACC_FW_LOAD_FL_VIDEO |
150 ATOMISP_ACC_FW_LOAD_FL_CAPTURE | ATOMISP_ACC_FW_LOAD_FL_ACC;
152 struct atomisp_acc_fw *acc_fw;
155 if (!user_fw->data || user_fw->size < sizeof(*acc_fw->fw))
158 /* Binary has to be enabled at least for one pipeline */
159 if (!(user_fw->flags & pipeline_flags))
162 /* We do not support other flags yet */
163 if (user_fw->flags & ~pipeline_flags)
166 if (user_fw->type < ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT ||
167 user_fw->type > ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE)
170 if (asd->acc.pipeline || asd->acc.extension_mode)
173 acc_fw = acc_alloc_fw(user_fw->size);
177 if (copy_from_user(acc_fw->fw, user_fw->data, user_fw->size)) {
182 if (!ida_pre_get(&asd->acc.ida, GFP_KERNEL) ||
183 ida_get_new_above(&asd->acc.ida, 1, &handle)) {
188 user_fw->fw_handle = handle;
189 acc_fw->handle = handle;
190 acc_fw->flags = user_fw->flags;
191 acc_fw->type = user_fw->type;
192 acc_fw->fw->handle = handle;
195 * correct isp firmware type in order ISP firmware can be appended
196 * to correct pipe properly
198 if (acc_fw->fw->type == ia_css_isp_firmware) {
199 static const int type_to_css[] = {
200 [ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT] =
202 [ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER] =
203 IA_CSS_ACC_VIEWFINDER,
204 [ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE] =
205 IA_CSS_ACC_STANDALONE,
207 acc_fw->fw->info.isp.type = type_to_css[acc_fw->type];
210 list_add_tail(&acc_fw->list, &asd->acc.fw);
214 int atomisp_acc_load(struct atomisp_sub_device *asd,
215 struct atomisp_acc_fw_load *user_fw)
217 struct atomisp_acc_fw_load_to_pipe ltp = {0};
220 ltp.flags = ATOMISP_ACC_FW_LOAD_FL_ACC;
221 ltp.type = ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE;
222 ltp.size = user_fw->size;
223 ltp.data = user_fw->data;
224 r = atomisp_acc_load_to_pipe(asd, <p);
225 user_fw->fw_handle = ltp.fw_handle;
229 int atomisp_acc_unload(struct atomisp_sub_device *asd, unsigned int *handle)
231 struct atomisp_acc_fw *acc_fw;
233 if (asd->acc.pipeline || asd->acc.extension_mode)
236 acc_fw = acc_get_fw(asd, *handle);
240 list_del(&acc_fw->list);
241 ida_remove(&asd->acc.ida, acc_fw->handle);
247 int atomisp_acc_start(struct atomisp_sub_device *asd, unsigned int *handle)
249 struct atomisp_device *isp = asd->isp;
250 struct atomisp_acc_fw *acc_fw;
254 if (asd->acc.pipeline || asd->acc.extension_mode)
257 /* Invalidate caches. FIXME: should flush only necessary buffers */
260 ret = atomisp_css_create_acc_pipe(asd);
265 list_for_each_entry(acc_fw, &asd->acc.fw, list) {
266 if (*handle != 0 && *handle != acc_fw->handle)
269 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE)
272 /* Add the binary into the pipeline */
273 ret = atomisp_css_load_acc_binary(asd, acc_fw->fw, nbin);
275 dev_err(isp->dev, "acc_load_binary failed\n");
279 ret = atomisp_css_set_acc_parameters(acc_fw);
281 dev_err(isp->dev, "acc_set_parameters failed\n");
287 /* Refuse creating pipelines with no binaries */
288 dev_err(isp->dev, "%s: no acc binary available\n", __func__);
293 ret = atomisp_css_start_acc_pipe(asd);
295 dev_err(isp->dev, "%s: atomisp_acc_start_acc_pipe failed\n",
303 atomisp_css_destroy_acc_pipe(asd);
307 int atomisp_acc_wait(struct atomisp_sub_device *asd, unsigned int *handle)
309 struct atomisp_device *isp = asd->isp;
312 if (!asd->acc.pipeline)
315 if (*handle && !acc_get_fw(asd, *handle))
318 ret = atomisp_css_wait_acc_finish(asd);
319 if (acc_stop_acceleration(asd) == -EIO) {
327 void atomisp_acc_done(struct atomisp_sub_device *asd, unsigned int handle)
329 struct v4l2_event event = { 0 };
331 event.type = V4L2_EVENT_ATOMISP_ACC_COMPLETE;
332 event.u.frame_sync.frame_sequence = atomic_read(&asd->sequence);
335 v4l2_event_queue(asd->subdev.devnode, &event);
338 int atomisp_acc_map(struct atomisp_sub_device *asd, struct atomisp_acc_map *map)
340 struct atomisp_map *atomisp_map;
347 if (asd->acc.pipeline)
351 /* Buffer to map must be page-aligned */
352 if ((unsigned long)map->user_ptr & ~PAGE_MASK) {
353 dev_err(asd->isp->dev,
354 "%s: mapped buffer address %p is not page aligned\n",
355 __func__, map->user_ptr);
359 pgnr = DIV_ROUND_UP(map->length, PAGE_SIZE);
360 cssptr = hrt_isp_css_mm_alloc_user_ptr(
361 map->length, map->user_ptr,
363 (map->flags & ATOMISP_MAP_FLAG_CACHED));
365 /* Allocate private buffer. */
366 if (map->flags & ATOMISP_MAP_FLAG_CACHED)
367 cssptr = hrt_isp_css_mm_calloc_cached(map->length);
369 cssptr = hrt_isp_css_mm_calloc(map->length);
375 atomisp_map = kmalloc(sizeof(*atomisp_map), GFP_KERNEL);
380 atomisp_map->ptr = cssptr;
381 atomisp_map->length = map->length;
382 list_add(&atomisp_map->list, &asd->acc.memory_maps);
384 dev_dbg(asd->isp->dev, "%s: userptr %p, css_address 0x%x, size %d\n",
385 __func__, map->user_ptr, cssptr, map->length);
386 map->css_ptr = cssptr;
390 int atomisp_acc_unmap(struct atomisp_sub_device *asd, struct atomisp_acc_map *map)
392 struct atomisp_map *atomisp_map;
394 if (asd->acc.pipeline)
397 atomisp_map = acc_get_map(asd, map->css_ptr, map->length);
401 list_del(&atomisp_map->list);
402 hmm_free(atomisp_map->ptr);
407 int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd,
408 struct atomisp_acc_s_mapped_arg *arg)
410 struct atomisp_acc_fw *acc_fw;
412 if (arg->memory >= ATOMISP_ACC_NR_MEMORY)
415 if (asd->acc.pipeline)
418 acc_fw = acc_get_fw(asd, arg->fw_handle);
422 if (arg->css_ptr != 0 || arg->length != 0) {
423 /* Unless the parameter is cleared, check that it exists */
424 if (!acc_get_map(asd, arg->css_ptr, arg->length))
428 acc_fw->args[arg->memory].length = arg->length;
429 acc_fw->args[arg->memory].css_ptr = arg->css_ptr;
431 dev_dbg(asd->isp->dev, "%s: mem %d, address %p, size %ld\n",
432 __func__, arg->memory, (void *)arg->css_ptr,
433 (unsigned long)arg->length);
438 * Appends the loaded acceleration binary extensions to the
439 * current ISP mode. Must be called just before sh_css_start().
441 int atomisp_acc_load_extensions(struct atomisp_sub_device *asd)
443 struct atomisp_acc_fw *acc_fw;
444 bool ext_loaded = false;
445 bool continuous = asd->continuous_mode->val &&
446 asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW;
448 struct atomisp_device *isp = asd->isp;
450 if (asd->acc.pipeline || asd->acc.extension_mode)
453 /* Invalidate caches. FIXME: should flush only necessary buffers */
456 list_for_each_entry(acc_fw, &asd->acc.fw, list) {
457 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
458 acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
461 for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
462 /* QoS (ACC pipe) acceleration stages are currently
463 * allowed only in continuous mode. Skip them for
464 * all other modes. */
466 acc_flag_to_pipe[i].flag ==
467 ATOMISP_ACC_FW_LOAD_FL_ACC)
470 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
471 ret = atomisp_css_load_acc_extension(asd,
473 acc_flag_to_pipe[i].pipe_id,
482 ret = atomisp_css_set_acc_parameters(acc_fw);
490 ret = atomisp_css_update_stream(asd);
492 dev_err(isp->dev, "%s: update stream failed.\n", __func__);
496 asd->acc.extension_mode = true;
501 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
502 atomisp_css_unload_acc_extension(asd, acc_fw->fw,
503 acc_flag_to_pipe[i].pipe_id);
507 list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) {
508 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
509 acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
512 for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) {
514 acc_flag_to_pipe[i].flag ==
515 ATOMISP_ACC_FW_LOAD_FL_ACC)
517 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
518 atomisp_css_unload_acc_extension(asd,
520 acc_flag_to_pipe[i].pipe_id);
527 void atomisp_acc_unload_extensions(struct atomisp_sub_device *asd)
529 struct atomisp_acc_fw *acc_fw;
532 if (!asd->acc.extension_mode)
535 list_for_each_entry_reverse(acc_fw, &asd->acc.fw, list) {
536 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
537 acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
540 for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) {
541 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
542 atomisp_css_unload_acc_extension(asd,
544 acc_flag_to_pipe[i].pipe_id);
549 asd->acc.extension_mode = false;
552 int atomisp_acc_set_state(struct atomisp_sub_device *asd,
553 struct atomisp_acc_state *arg)
555 struct atomisp_acc_fw *acc_fw;
556 bool enable = (arg->flags & ATOMISP_STATE_FLAG_ENABLE) != 0;
557 struct ia_css_pipe *pipe;
561 if (!asd->acc.extension_mode)
564 if (arg->flags & ~ATOMISP_STATE_FLAG_ENABLE)
567 acc_fw = acc_get_fw(asd, arg->fw_handle);
574 for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
575 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
576 pipe = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
577 pipes[acc_flag_to_pipe[i].pipe_id];
578 r = ia_css_pipe_set_qos_ext_state(pipe, acc_fw->handle,
580 if (r != IA_CSS_SUCCESS)
586 acc_fw->flags |= ATOMISP_ACC_FW_LOAD_FL_ENABLE;
588 acc_fw->flags &= ~ATOMISP_ACC_FW_LOAD_FL_ENABLE;
593 int atomisp_acc_get_state(struct atomisp_sub_device *asd,
594 struct atomisp_acc_state *arg)
596 struct atomisp_acc_fw *acc_fw;
598 if (!asd->acc.extension_mode)
601 acc_fw = acc_get_fw(asd, arg->fw_handle);
605 arg->flags = acc_fw->flags;