1 // SPDX-License-Identifier: GPL-2.0
3 * Support for Clovertrail PNW Camera Imaging ISP subsystem.
5 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
20 * This file implements loadable acceleration firmware API,
21 * including ioctls to map and unmap acceleration parameters and buffers.
24 #include <linux/init.h>
25 #include <media/v4l2-event.h>
29 #include "atomisp_acc.h"
30 #include "atomisp_internal.h"
31 #include "atomisp_compat.h"
32 #include "atomisp_cmd.h"
38 enum ia_css_pipe_id pipe_id;
39 } acc_flag_to_pipe[] = {
40 { ATOMISP_ACC_FW_LOAD_FL_PREVIEW, IA_CSS_PIPE_ID_PREVIEW },
41 { ATOMISP_ACC_FW_LOAD_FL_COPY, IA_CSS_PIPE_ID_COPY },
42 { ATOMISP_ACC_FW_LOAD_FL_VIDEO, IA_CSS_PIPE_ID_VIDEO },
43 { ATOMISP_ACC_FW_LOAD_FL_CAPTURE, IA_CSS_PIPE_ID_CAPTURE },
44 { ATOMISP_ACC_FW_LOAD_FL_ACC, IA_CSS_PIPE_ID_ACC }
48 * Allocate struct atomisp_acc_fw along with space for firmware.
49 * The returned struct atomisp_acc_fw is cleared (firmware region is not).
51 static struct atomisp_acc_fw *acc_alloc_fw(unsigned int fw_size)
53 struct atomisp_acc_fw *acc_fw;
55 acc_fw = kzalloc(sizeof(*acc_fw), GFP_KERNEL);
59 acc_fw->fw = vmalloc(fw_size);
68 static void acc_free_fw(struct atomisp_acc_fw *acc_fw)
74 static struct atomisp_acc_fw *
75 acc_get_fw(struct atomisp_sub_device *asd, unsigned int handle)
77 struct atomisp_acc_fw *acc_fw;
79 list_for_each_entry(acc_fw, &asd->acc.fw, list)
80 if (acc_fw->handle == handle)
86 static struct atomisp_map *acc_get_map(struct atomisp_sub_device *asd,
87 unsigned long css_ptr, size_t length)
89 struct atomisp_map *atomisp_map;
91 list_for_each_entry(atomisp_map, &asd->acc.memory_maps, list) {
92 if (atomisp_map->ptr == css_ptr &&
93 atomisp_map->length == length)
99 static int acc_stop_acceleration(struct atomisp_sub_device *asd)
103 ret = atomisp_css_stop_acc_pipe(asd);
104 atomisp_css_destroy_acc_pipe(asd);
109 void atomisp_acc_cleanup(struct atomisp_device *isp)
113 for (i = 0; i < isp->num_of_streams; i++)
114 ida_destroy(&isp->asd[i].acc.ida);
117 void atomisp_acc_release(struct atomisp_sub_device *asd)
119 struct atomisp_acc_fw *acc_fw, *ta;
120 struct atomisp_map *atomisp_map, *tm;
122 /* Stop acceleration if already running */
123 if (asd->acc.pipeline)
124 acc_stop_acceleration(asd);
126 /* Unload all loaded acceleration binaries */
127 list_for_each_entry_safe(acc_fw, ta, &asd->acc.fw, list) {
128 list_del(&acc_fw->list);
129 ida_free(&asd->acc.ida, acc_fw->handle);
133 /* Free all mapped memory blocks */
134 list_for_each_entry_safe(atomisp_map, tm, &asd->acc.memory_maps, list) {
135 list_del(&atomisp_map->list);
136 hmm_free(atomisp_map->ptr);
141 int atomisp_acc_load_to_pipe(struct atomisp_sub_device *asd,
142 struct atomisp_acc_fw_load_to_pipe *user_fw)
144 static const unsigned int pipeline_flags =
145 ATOMISP_ACC_FW_LOAD_FL_PREVIEW | ATOMISP_ACC_FW_LOAD_FL_COPY |
146 ATOMISP_ACC_FW_LOAD_FL_VIDEO |
147 ATOMISP_ACC_FW_LOAD_FL_CAPTURE | ATOMISP_ACC_FW_LOAD_FL_ACC;
149 struct atomisp_acc_fw *acc_fw;
152 if (!user_fw->data || user_fw->size < sizeof(*acc_fw->fw))
155 /* Binary has to be enabled at least for one pipeline */
156 if (!(user_fw->flags & pipeline_flags))
159 /* We do not support other flags yet */
160 if (user_fw->flags & ~pipeline_flags)
163 if (user_fw->type < ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT ||
164 user_fw->type > ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE)
167 if (asd->acc.pipeline || asd->acc.extension_mode)
170 acc_fw = acc_alloc_fw(user_fw->size);
174 if (copy_from_user(acc_fw->fw, user_fw->data, user_fw->size)) {
179 handle = ida_alloc(&asd->acc.ida, GFP_KERNEL);
185 user_fw->fw_handle = handle;
186 acc_fw->handle = handle;
187 acc_fw->flags = user_fw->flags;
188 acc_fw->type = user_fw->type;
189 acc_fw->fw->handle = handle;
192 * correct isp firmware type in order ISP firmware can be appended
193 * to correct pipe properly
195 if (acc_fw->fw->type == ia_css_isp_firmware) {
196 static const int type_to_css[] = {
197 [ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT] =
199 [ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER] =
200 IA_CSS_ACC_VIEWFINDER,
201 [ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE] =
202 IA_CSS_ACC_STANDALONE,
204 acc_fw->fw->info.isp.type = type_to_css[acc_fw->type];
207 list_add_tail(&acc_fw->list, &asd->acc.fw);
211 int atomisp_acc_load(struct atomisp_sub_device *asd,
212 struct atomisp_acc_fw_load *user_fw)
214 struct atomisp_acc_fw_load_to_pipe ltp = {0};
217 ltp.flags = ATOMISP_ACC_FW_LOAD_FL_ACC;
218 ltp.type = ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE;
219 ltp.size = user_fw->size;
220 ltp.data = user_fw->data;
221 r = atomisp_acc_load_to_pipe(asd, <p);
222 user_fw->fw_handle = ltp.fw_handle;
226 int atomisp_acc_unload(struct atomisp_sub_device *asd, unsigned int *handle)
228 struct atomisp_acc_fw *acc_fw;
230 if (asd->acc.pipeline || asd->acc.extension_mode)
233 acc_fw = acc_get_fw(asd, *handle);
237 list_del(&acc_fw->list);
238 ida_free(&asd->acc.ida, acc_fw->handle);
244 int atomisp_acc_start(struct atomisp_sub_device *asd, unsigned int *handle)
246 struct atomisp_device *isp = asd->isp;
247 struct atomisp_acc_fw *acc_fw;
251 if (asd->acc.pipeline || asd->acc.extension_mode)
254 /* Invalidate caches. FIXME: should flush only necessary buffers */
257 ret = atomisp_css_create_acc_pipe(asd);
262 list_for_each_entry(acc_fw, &asd->acc.fw, list) {
263 if (*handle != 0 && *handle != acc_fw->handle)
266 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE)
269 /* Add the binary into the pipeline */
270 ret = atomisp_css_load_acc_binary(asd, acc_fw->fw, nbin);
272 dev_err(isp->dev, "acc_load_binary failed\n");
276 ret = atomisp_css_set_acc_parameters(acc_fw);
278 dev_err(isp->dev, "acc_set_parameters failed\n");
284 /* Refuse creating pipelines with no binaries */
285 dev_err(isp->dev, "%s: no acc binary available\n", __func__);
290 ret = atomisp_css_start_acc_pipe(asd);
292 dev_err(isp->dev, "%s: atomisp_acc_start_acc_pipe failed\n",
300 atomisp_css_destroy_acc_pipe(asd);
304 int atomisp_acc_wait(struct atomisp_sub_device *asd, unsigned int *handle)
306 struct atomisp_device *isp = asd->isp;
309 if (!asd->acc.pipeline)
312 if (*handle && !acc_get_fw(asd, *handle))
315 ret = atomisp_css_wait_acc_finish(asd);
316 if (acc_stop_acceleration(asd) == -EIO) {
324 void atomisp_acc_done(struct atomisp_sub_device *asd, unsigned int handle)
326 struct v4l2_event event = { 0 };
328 event.type = V4L2_EVENT_ATOMISP_ACC_COMPLETE;
329 event.u.frame_sync.frame_sequence = atomic_read(&asd->sequence);
332 v4l2_event_queue(asd->subdev.devnode, &event);
335 int atomisp_acc_map(struct atomisp_sub_device *asd, struct atomisp_acc_map *map)
337 struct atomisp_map *atomisp_map;
344 if (asd->acc.pipeline)
348 /* Buffer to map must be page-aligned */
349 if ((unsigned long)map->user_ptr & ~PAGE_MASK) {
350 dev_err(asd->isp->dev,
351 "%s: mapped buffer address %p is not page aligned\n",
352 __func__, map->user_ptr);
356 pgnr = DIV_ROUND_UP(map->length, PAGE_SIZE);
357 if (pgnr < ((PAGE_ALIGN(map->length)) >> PAGE_SHIFT)) {
358 dev_err(asd->isp->dev,
359 "user space memory size is less than the expected size..\n");
361 } else if (pgnr > ((PAGE_ALIGN(map->length)) >> PAGE_SHIFT)) {
362 dev_err(asd->isp->dev,
363 "user space memory size is large than the expected size..\n");
367 cssptr = hmm_alloc(map->length, HMM_BO_USER, 0, map->user_ptr,
368 map->flags & ATOMISP_MAP_FLAG_CACHED);
371 /* Allocate private buffer. */
372 cssptr = hmm_alloc(map->length, HMM_BO_PRIVATE, 0, NULL,
373 map->flags & ATOMISP_MAP_FLAG_CACHED);
379 atomisp_map = kmalloc(sizeof(*atomisp_map), GFP_KERNEL);
384 atomisp_map->ptr = cssptr;
385 atomisp_map->length = map->length;
386 list_add(&atomisp_map->list, &asd->acc.memory_maps);
388 dev_dbg(asd->isp->dev, "%s: userptr %p, css_address 0x%x, size %d\n",
389 __func__, map->user_ptr, cssptr, map->length);
390 map->css_ptr = cssptr;
394 int atomisp_acc_unmap(struct atomisp_sub_device *asd,
395 struct atomisp_acc_map *map)
397 struct atomisp_map *atomisp_map;
399 if (asd->acc.pipeline)
402 atomisp_map = acc_get_map(asd, map->css_ptr, map->length);
406 list_del(&atomisp_map->list);
407 hmm_free(atomisp_map->ptr);
412 int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd,
413 struct atomisp_acc_s_mapped_arg *arg)
415 struct atomisp_acc_fw *acc_fw;
417 if (arg->memory >= ATOMISP_ACC_NR_MEMORY)
420 if (asd->acc.pipeline)
423 acc_fw = acc_get_fw(asd, arg->fw_handle);
427 if (arg->css_ptr != 0 || arg->length != 0) {
428 /* Unless the parameter is cleared, check that it exists */
429 if (!acc_get_map(asd, arg->css_ptr, arg->length))
433 acc_fw->args[arg->memory].length = arg->length;
434 acc_fw->args[arg->memory].css_ptr = arg->css_ptr;
436 dev_dbg(asd->isp->dev, "%s: mem %d, address %p, size %ld\n",
437 __func__, arg->memory, (void *)arg->css_ptr,
438 (unsigned long)arg->length);
442 static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *asd,
444 struct atomisp_acc_fw *acc_fw)
447 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
448 atomisp_css_unload_acc_extension(asd, acc_fw->fw,
449 acc_flag_to_pipe[i].pipe_id);
455 * Appends the loaded acceleration binary extensions to the
456 * current ISP mode. Must be called just before sh_css_start().
458 int atomisp_acc_load_extensions(struct atomisp_sub_device *asd)
460 struct atomisp_acc_fw *acc_fw;
461 bool ext_loaded = false;
462 bool continuous = asd->continuous_mode->val &&
463 asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW;
465 struct atomisp_device *isp = asd->isp;
467 if (asd->acc.pipeline || asd->acc.extension_mode)
470 /* Invalidate caches. FIXME: should flush only necessary buffers */
473 list_for_each_entry(acc_fw, &asd->acc.fw, list) {
474 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
475 acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
478 for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
480 * QoS (ACC pipe) acceleration stages are
481 * currently allowed only in continuous mode.
482 * Skip them for all other modes.
485 acc_flag_to_pipe[i].flag ==
486 ATOMISP_ACC_FW_LOAD_FL_ACC)
489 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
490 ret = atomisp_css_load_acc_extension(asd,
492 acc_flag_to_pipe[i].pipe_id,
495 atomisp_acc_unload_some_extensions(asd, i, acc_fw);
503 ret = atomisp_css_set_acc_parameters(acc_fw);
505 atomisp_acc_unload_some_extensions(asd, i, acc_fw);
513 ret = atomisp_css_update_stream(asd);
515 dev_err(isp->dev, "%s: update stream failed.\n", __func__);
516 atomisp_acc_unload_extensions(asd);
520 asd->acc.extension_mode = true;
524 list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) {
525 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
526 acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
529 for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) {
531 acc_flag_to_pipe[i].flag ==
532 ATOMISP_ACC_FW_LOAD_FL_ACC)
534 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
535 atomisp_css_unload_acc_extension(asd,
537 acc_flag_to_pipe[i].pipe_id);
544 void atomisp_acc_unload_extensions(struct atomisp_sub_device *asd)
546 struct atomisp_acc_fw *acc_fw;
549 if (!asd->acc.extension_mode)
552 list_for_each_entry_reverse(acc_fw, &asd->acc.fw, list) {
553 if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
554 acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
557 for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) {
558 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
559 atomisp_css_unload_acc_extension(asd,
561 acc_flag_to_pipe[i].pipe_id);
566 asd->acc.extension_mode = false;
569 int atomisp_acc_set_state(struct atomisp_sub_device *asd,
570 struct atomisp_acc_state *arg)
572 struct atomisp_acc_fw *acc_fw;
573 bool enable = (arg->flags & ATOMISP_STATE_FLAG_ENABLE) != 0;
574 struct ia_css_pipe *pipe;
578 if (!asd->acc.extension_mode)
581 if (arg->flags & ~ATOMISP_STATE_FLAG_ENABLE)
584 acc_fw = acc_get_fw(asd, arg->fw_handle);
591 for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
592 if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
593 pipe = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
594 pipes[acc_flag_to_pipe[i].pipe_id];
595 r = ia_css_pipe_set_qos_ext_state(pipe, acc_fw->handle,
603 acc_fw->flags |= ATOMISP_ACC_FW_LOAD_FL_ENABLE;
605 acc_fw->flags &= ~ATOMISP_ACC_FW_LOAD_FL_ENABLE;
610 int atomisp_acc_get_state(struct atomisp_sub_device *asd,
611 struct atomisp_acc_state *arg)
613 struct atomisp_acc_fw *acc_fw;
615 if (!asd->acc.extension_mode)
618 acc_fw = acc_get_fw(asd, arg->fw_handle);
622 arg->flags = acc_fw->flags;