diff options
Diffstat (limited to 'drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c')
-rw-r--r-- | drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c | 1304 |
1 files changed, 0 insertions, 1304 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c deleted file mode 100644 index 709137f25700..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#include <linux/module.h> -#include <linux/pm_runtime.h> - -#include <media/v4l2-ioctl.h> -#include <media/videobuf-vmalloc.h> - -#include "atomisp_cmd.h" -#include "atomisp_common.h" -#include "atomisp_fops.h" -#include "atomisp_internal.h" -#include "atomisp_ioctl.h" -#include "atomisp_compat.h" -#include "atomisp_subdev.h" -#include "atomisp_v4l2.h" -#include "atomisp-regs.h" -#include "hmm/hmm.h" - -#include "hrt/hive_isp_css_mm_hrt.h" - -#include "type_support.h" -#include "device_access/device_access.h" -#include "memory_access/memory_access.h" - -#include "atomisp_acc.h" - -#define ISP_LEFT_PAD 128 /* equal to 2*NWAY */ - -/* - * input image data, and current frame resolution for test - */ -#define ISP_PARAM_MMAP_OFFSET 0xfffff000 - -#define MAGIC_CHECK(is, should) \ - do { \ - if (unlikely((is) != (should))) { \ - pr_err("magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } \ - } while (0) - -/* - * Videobuf ops - */ -static int atomisp_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - *size = pipe->pix.sizeimage; - - return 0; -} - -static int atomisp_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - vb->size = pipe->pix.sizeimage; - vb->width = pipe->pix.width; - vb->height = pipe->pix.height; - vb->field = field; - vb->state = VIDEOBUF_PREPARED; - - return 0; -} - -static int atomisp_q_one_metadata_buffer(struct atomisp_sub_device *asd, - enum atomisp_input_stream_id stream_id, - enum atomisp_css_pipe_id css_pipe_id) -{ - struct atomisp_metadata_buf *metadata_buf; - enum atomisp_metadata_type md_type = - atomisp_get_metadata_type(asd, css_pipe_id); - struct list_head *metadata_list; - - if (asd->metadata_bufs_in_css[stream_id][css_pipe_id] >= - ATOMISP_CSS_Q_DEPTH) - return 0; /* we have reached CSS queue depth */ - - if (!list_empty(&asd->metadata[md_type])) { - metadata_list = &asd->metadata[md_type]; - } else if (!list_empty(&asd->metadata_ready[md_type])) { - metadata_list = &asd->metadata_ready[md_type]; - } else { - dev_warn(asd->isp->dev, "%s: No metadata buffers available for type %d!\n", - __func__, md_type); - return -EINVAL; - } - - metadata_buf = list_entry(metadata_list->next, - struct atomisp_metadata_buf, list); - list_del_init(&metadata_buf->list); - - if (atomisp_q_metadata_buffer_to_css(asd, metadata_buf, - stream_id, css_pipe_id)) { - list_add(&metadata_buf->list, metadata_list); - return -EINVAL; - } else { - list_add_tail(&metadata_buf->list, - &asd->metadata_in_css[md_type]); - } - asd->metadata_bufs_in_css[stream_id][css_pipe_id]++; - - return 0; -} - -static int atomisp_q_one_s3a_buffer(struct atomisp_sub_device *asd, - enum atomisp_input_stream_id stream_id, - enum atomisp_css_pipe_id css_pipe_id) -{ - struct atomisp_s3a_buf *s3a_buf; - struct list_head *s3a_list; - unsigned int exp_id; - - if (asd->s3a_bufs_in_css[css_pipe_id] >= ATOMISP_CSS_Q_DEPTH) - return 0; /* we have reached CSS queue depth */ - - if (!list_empty(&asd->s3a_stats)) { - s3a_list = &asd->s3a_stats; - } else if (!list_empty(&asd->s3a_stats_ready)) { - s3a_list = &asd->s3a_stats_ready; - } else { - dev_warn(asd->isp->dev, "%s: No s3a buffers available!\n", - __func__); - return -EINVAL; - } - - s3a_buf = list_entry(s3a_list->next, struct atomisp_s3a_buf, list); - list_del_init(&s3a_buf->list); - exp_id = s3a_buf->s3a_data->exp_id; - - hmm_flush_vmap(s3a_buf->s3a_data->data_ptr); - if (atomisp_q_s3a_buffer_to_css(asd, s3a_buf, - stream_id, css_pipe_id)) { - /* got from head, so return back to the head */ - list_add(&s3a_buf->list, s3a_list); - return -EINVAL; - } else { - list_add_tail(&s3a_buf->list, &asd->s3a_stats_in_css); - if (s3a_list == &asd->s3a_stats_ready) - dev_warn(asd->isp->dev, "%s: drop one s3a stat which has exp_id %d!\n", - __func__, exp_id); - } - - asd->s3a_bufs_in_css[css_pipe_id]++; - return 0; -} - -static int atomisp_q_one_dis_buffer(struct atomisp_sub_device *asd, - enum atomisp_input_stream_id stream_id, - enum atomisp_css_pipe_id css_pipe_id) -{ - struct atomisp_dis_buf *dis_buf; - unsigned long irqflags; - - if (asd->dis_bufs_in_css >= ATOMISP_CSS_Q_DEPTH) - return 0; /* we have reached CSS queue depth */ - - spin_lock_irqsave(&asd->dis_stats_lock, irqflags); - if (list_empty(&asd->dis_stats)) { - spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); - dev_warn(asd->isp->dev, "%s: No dis buffers available!\n", - __func__); - return -EINVAL; - } - - dis_buf = list_entry(asd->dis_stats.prev, - struct atomisp_dis_buf, list); - list_del_init(&dis_buf->list); - spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); - - hmm_flush_vmap(dis_buf->dis_data->data_ptr); - if (atomisp_q_dis_buffer_to_css(asd, dis_buf, - stream_id, css_pipe_id)) { - spin_lock_irqsave(&asd->dis_stats_lock, irqflags); - /* got from tail, so return back to the tail */ - list_add_tail(&dis_buf->list, &asd->dis_stats); - spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); - return -EINVAL; - } else { - spin_lock_irqsave(&asd->dis_stats_lock, irqflags); - list_add_tail(&dis_buf->list, &asd->dis_stats_in_css); - spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); - } - - asd->dis_bufs_in_css++; - - return 0; -} - -int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd, - struct atomisp_video_pipe *pipe, - enum atomisp_input_stream_id stream_id, - enum atomisp_css_buffer_type css_buf_type, - enum atomisp_css_pipe_id css_pipe_id) -{ - struct videobuf_vmalloc_memory *vm_mem; - struct atomisp_css_params_with_list *param; - struct atomisp_css_dvs_grid_info *dvs_grid = - atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); - unsigned long irqflags; - int err = 0; - - while (pipe->buffers_in_css < ATOMISP_CSS_Q_DEPTH) { - struct videobuf_buffer *vb; - - spin_lock_irqsave(&pipe->irq_lock, irqflags); - if (list_empty(&pipe->activeq)) { - spin_unlock_irqrestore(&pipe->irq_lock, irqflags); - return -EINVAL; - } - vb = list_entry(pipe->activeq.next, - struct videobuf_buffer, queue); - list_del_init(&vb->queue); - vb->state = VIDEOBUF_ACTIVE; - spin_unlock_irqrestore(&pipe->irq_lock, irqflags); - - /* - * If there is a per_frame setting to apply on the buffer, - * do it before buffer en-queueing. - */ - vm_mem = vb->priv; - - param = pipe->frame_params[vb->i]; - if (param) { - atomisp_makeup_css_parameters(asd, - &asd->params.css_param.update_flag, - ¶m->params); - atomisp_apply_css_parameters(asd, ¶m->params); - - if (param->params.update_flag.dz_config && - asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) { - err = atomisp_calculate_real_zoom_region(asd, - ¶m->params.dz_config, css_pipe_id); - if (!err) - atomisp_css_set_dz_config(asd, - ¶m->params.dz_config); - } - atomisp_css_set_isp_config_applied_frame(asd, - vm_mem->vaddr); - atomisp_css_update_isp_params_on_pipe(asd, - asd->stream_env[stream_id].pipes[css_pipe_id]); - asd->params.dvs_6axis = (struct atomisp_css_dvs_6axis *) - param->params.dvs_6axis; - - /* - * WORKAROUND: - * Because the camera halv3 can't ensure to set zoom - * region to per_frame setting and global setting at - * same time and only set zoom region to pre_frame - * setting now.so when the pre_frame setting inculde - * zoom region,I will set it to global setting. - */ - if (param->params.update_flag.dz_config && - asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO - && !err) { - memcpy(&asd->params.css_param.dz_config, - ¶m->params.dz_config, - sizeof(struct ia_css_dz_config)); - asd->params.css_param.update_flag.dz_config = - (struct atomisp_dz_config *) - &asd->params.css_param.dz_config; - asd->params.css_update_params_needed = true; - } - } - /* Enqueue buffer */ - err = atomisp_q_video_buffer_to_css(asd, vm_mem, stream_id, - css_buf_type, css_pipe_id); - if (err) { - spin_lock_irqsave(&pipe->irq_lock, irqflags); - list_add_tail(&vb->queue, &pipe->activeq); - vb->state = VIDEOBUF_QUEUED; - spin_unlock_irqrestore(&pipe->irq_lock, irqflags); - dev_err(asd->isp->dev, "%s, css q fails: %d\n", - __func__, err); - return -EINVAL; - } - pipe->buffers_in_css++; - - /* enqueue 3A/DIS/metadata buffers */ - if (asd->params.curr_grid_info.s3a_grid.enable && - css_pipe_id == asd->params.s3a_enabled_pipe && - css_buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME) - atomisp_q_one_s3a_buffer(asd, stream_id, - css_pipe_id); - - if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info. - metadata_info.size && - css_buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME) - atomisp_q_one_metadata_buffer(asd, stream_id, - css_pipe_id); - - if (dvs_grid && dvs_grid->enable && - css_pipe_id == CSS_PIPE_ID_VIDEO && - css_buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME) - atomisp_q_one_dis_buffer(asd, stream_id, - css_pipe_id); - } - - return 0; -} - -static int atomisp_get_css_buf_type(struct atomisp_sub_device *asd, - enum atomisp_css_pipe_id pipe_id, - uint16_t source_pad) -{ - if (ATOMISP_USE_YUVPP(asd)) { - /* when run ZSL case */ - if (asd->continuous_mode->val && - asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { - if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) - return CSS_BUFFER_TYPE_OUTPUT_FRAME; - else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) - return CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME; - else - return CSS_BUFFER_TYPE_VF_OUTPUT_FRAME; - } - - /*when run SDV case*/ - if (asd->continuous_mode->val && - asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { - if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) - return CSS_BUFFER_TYPE_OUTPUT_FRAME; - else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) - return CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME; - else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) - return CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME; - else - return CSS_BUFFER_TYPE_VF_OUTPUT_FRAME; - } - - /*other case: default setting*/ - if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE || - source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO || - (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && - asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO)) - return CSS_BUFFER_TYPE_OUTPUT_FRAME; - else - return CSS_BUFFER_TYPE_VF_OUTPUT_FRAME; - } - - if (pipe_id == CSS_PIPE_ID_COPY || - source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE || - source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO || - (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && - asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO)) - return CSS_BUFFER_TYPE_OUTPUT_FRAME; - else - return CSS_BUFFER_TYPE_VF_OUTPUT_FRAME; -} - -static int atomisp_qbuffers_to_css_for_all_pipes(struct atomisp_sub_device *asd) -{ - enum atomisp_css_buffer_type buf_type; - enum atomisp_css_pipe_id css_capture_pipe_id = CSS_PIPE_ID_COPY; - enum atomisp_css_pipe_id css_preview_pipe_id = CSS_PIPE_ID_COPY; - enum atomisp_css_pipe_id css_video_pipe_id = CSS_PIPE_ID_COPY; - enum atomisp_input_stream_id input_stream_id; - struct atomisp_video_pipe *capture_pipe; - struct atomisp_video_pipe *preview_pipe; - struct atomisp_video_pipe *video_pipe; - - capture_pipe = &asd->video_out_capture; - preview_pipe = &asd->video_out_preview; - video_pipe = &asd->video_out_video_capture; - - buf_type = atomisp_get_css_buf_type( - asd, css_preview_pipe_id, - atomisp_subdev_source_pad(&preview_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_PREVIEW; - atomisp_q_video_buffers_to_css(asd, preview_pipe, - input_stream_id, - buf_type, css_preview_pipe_id); - - buf_type = atomisp_get_css_buf_type(asd, css_capture_pipe_id, - atomisp_subdev_source_pad(&capture_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - atomisp_q_video_buffers_to_css(asd, capture_pipe, - input_stream_id, - buf_type, css_capture_pipe_id); - - buf_type = atomisp_get_css_buf_type(asd, css_video_pipe_id, - atomisp_subdev_source_pad(&video_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_VIDEO; - atomisp_q_video_buffers_to_css(asd, video_pipe, - input_stream_id, - buf_type, css_video_pipe_id); - return 0; -} - - -/* queue all available buffers to css */ -int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd) -{ - enum atomisp_css_buffer_type buf_type; - enum atomisp_css_pipe_id css_capture_pipe_id = CSS_PIPE_ID_NUM; - enum atomisp_css_pipe_id css_preview_pipe_id = CSS_PIPE_ID_NUM; - enum atomisp_css_pipe_id css_video_pipe_id = CSS_PIPE_ID_NUM; - enum atomisp_input_stream_id input_stream_id; - struct atomisp_video_pipe *capture_pipe = NULL; - struct atomisp_video_pipe *vf_pipe = NULL; - struct atomisp_video_pipe *preview_pipe = NULL; - struct atomisp_video_pipe *video_pipe = NULL; - bool raw_mode = atomisp_is_mbuscode_raw( - asd->fmt[asd->capture_pad].fmt.code); - - if (asd->isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num == 2 && - !asd->yuvpp_mode) - return atomisp_qbuffers_to_css_for_all_pipes(asd); - - if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { - video_pipe = &asd->video_out_video_capture; - css_video_pipe_id = CSS_PIPE_ID_VIDEO; - } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { - preview_pipe = &asd->video_out_capture; - css_preview_pipe_id = CSS_PIPE_ID_CAPTURE; - } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { - if (asd->continuous_mode->val) { - capture_pipe = &asd->video_out_capture; - vf_pipe = &asd->video_out_vf; - css_capture_pipe_id = CSS_PIPE_ID_CAPTURE; - } - video_pipe = &asd->video_out_video_capture; - preview_pipe = &asd->video_out_preview; - css_video_pipe_id = CSS_PIPE_ID_VIDEO; - css_preview_pipe_id = CSS_PIPE_ID_VIDEO; - } else if (asd->continuous_mode->val) { - capture_pipe = &asd->video_out_capture; - vf_pipe = &asd->video_out_vf; - preview_pipe = &asd->video_out_preview; - - css_preview_pipe_id = CSS_PIPE_ID_PREVIEW; - css_capture_pipe_id = CSS_PIPE_ID_CAPTURE; - } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { - preview_pipe = &asd->video_out_preview; - css_preview_pipe_id = CSS_PIPE_ID_PREVIEW; - } else { - /* ATOMISP_RUN_MODE_STILL_CAPTURE */ - capture_pipe = &asd->video_out_capture; - if (!raw_mode) - vf_pipe = &asd->video_out_vf; - css_capture_pipe_id = CSS_PIPE_ID_CAPTURE; - } - -#ifdef ISP2401_NEW_INPUT_SYSTEM - if (asd->copy_mode) { - css_capture_pipe_id = CSS_PIPE_ID_COPY; - css_preview_pipe_id = CSS_PIPE_ID_COPY; - css_video_pipe_id = CSS_PIPE_ID_COPY; - } -#endif - - if (asd->yuvpp_mode) { - capture_pipe = &asd->video_out_capture; - video_pipe = &asd->video_out_video_capture; - preview_pipe = &asd->video_out_preview; - css_capture_pipe_id = CSS_PIPE_ID_COPY; - css_video_pipe_id = CSS_PIPE_ID_YUVPP; - css_preview_pipe_id = CSS_PIPE_ID_YUVPP; - } - - if (capture_pipe) { - buf_type = atomisp_get_css_buf_type( - asd, css_capture_pipe_id, - atomisp_subdev_source_pad(&capture_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - - /* - * use yuvpp pipe for SOC camera. - */ - if (ATOMISP_USE_YUVPP(asd)) - css_capture_pipe_id = CSS_PIPE_ID_YUVPP; - - atomisp_q_video_buffers_to_css(asd, capture_pipe, - input_stream_id, - buf_type, css_capture_pipe_id); - } - - if (vf_pipe) { - buf_type = atomisp_get_css_buf_type( - asd, css_capture_pipe_id, - atomisp_subdev_source_pad(&vf_pipe->vdev)); - if (asd->stream_env[ATOMISP_INPUT_STREAM_POSTVIEW].stream) - input_stream_id = ATOMISP_INPUT_STREAM_POSTVIEW; - else - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - - /* - * use yuvpp pipe for SOC camera. - */ - if (ATOMISP_USE_YUVPP(asd)) - css_capture_pipe_id = CSS_PIPE_ID_YUVPP; - atomisp_q_video_buffers_to_css(asd, vf_pipe, - input_stream_id, - buf_type, css_capture_pipe_id); - } - - if (preview_pipe) { - buf_type = atomisp_get_css_buf_type( - asd, css_preview_pipe_id, - atomisp_subdev_source_pad(&preview_pipe->vdev)); - if (ATOMISP_SOC_CAMERA(asd) && css_preview_pipe_id == CSS_PIPE_ID_YUVPP) - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - /* else for ext isp use case */ - else if (css_preview_pipe_id == CSS_PIPE_ID_YUVPP) - input_stream_id = ATOMISP_INPUT_STREAM_VIDEO; - else if (asd->stream_env[ATOMISP_INPUT_STREAM_PREVIEW].stream) - input_stream_id = ATOMISP_INPUT_STREAM_PREVIEW; - else - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - - /* - * use yuvpp pipe for SOC camera. - */ - if (ATOMISP_USE_YUVPP(asd)) - css_preview_pipe_id = CSS_PIPE_ID_YUVPP; - - atomisp_q_video_buffers_to_css(asd, preview_pipe, - input_stream_id, - buf_type, css_preview_pipe_id); - } - - if (video_pipe) { - buf_type = atomisp_get_css_buf_type( - asd, css_video_pipe_id, - atomisp_subdev_source_pad(&video_pipe->vdev)); - if (asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO].stream) - input_stream_id = ATOMISP_INPUT_STREAM_VIDEO; - else - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - - /* - * use yuvpp pipe for SOC camera. - */ - if (ATOMISP_USE_YUVPP(asd)) - css_video_pipe_id = CSS_PIPE_ID_YUVPP; - - atomisp_q_video_buffers_to_css(asd, video_pipe, - input_stream_id, - buf_type, css_video_pipe_id); - } - - return 0; -} - -static void atomisp_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - /* - * when a frame buffer meets following conditions, it should be put into - * the waiting list: - * 1. It is not a main output frame, and it has a per-frame parameter - * to go with it. - * 2. It is not a main output frame, and the waiting buffer list is not - * empty, to keep the FIFO sequence of frame buffer processing, it - * is put to waiting list until previous per-frame parameter buffers - * get enqueued. - */ - if (!atomisp_is_vf_pipe(pipe) && - (pipe->frame_request_config_id[vb->i] || - !list_empty(&pipe->buffers_waiting_for_param))) - list_add_tail(&vb->queue, &pipe->buffers_waiting_for_param); - else - list_add_tail(&vb->queue, &pipe->activeq); - - vb->state = VIDEOBUF_QUEUED; -} - -static void atomisp_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - vb->state = VIDEOBUF_NEEDS_INIT; - atomisp_videobuf_free_buf(vb); -} - -static int atomisp_buf_setup_output(struct videobuf_queue *vq, - unsigned int *count, unsigned int *size) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - *size = pipe->pix.sizeimage; - - return 0; -} - -static int atomisp_buf_prepare_output(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - vb->size = pipe->pix.sizeimage; - vb->width = pipe->pix.width; - vb->height = pipe->pix.height; - vb->field = field; - vb->state = VIDEOBUF_PREPARED; - - return 0; -} - -static void atomisp_buf_queue_output(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - list_add_tail(&vb->queue, &pipe->activeq_out); - vb->state = VIDEOBUF_QUEUED; -} - -static void atomisp_buf_release_output(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - videobuf_vmalloc_free(vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static const struct videobuf_queue_ops videobuf_qops = { - .buf_setup = atomisp_buf_setup, - .buf_prepare = atomisp_buf_prepare, - .buf_queue = atomisp_buf_queue, - .buf_release = atomisp_buf_release, -}; - -static const struct videobuf_queue_ops videobuf_qops_output = { - .buf_setup = atomisp_buf_setup_output, - .buf_prepare = atomisp_buf_prepare_output, - .buf_queue = atomisp_buf_queue_output, - .buf_release = atomisp_buf_release_output, -}; - -static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) -{ - /* init locks */ - spin_lock_init(&pipe->irq_lock); - - videobuf_queue_vmalloc_init(&pipe->capq, &videobuf_qops, NULL, - &pipe->irq_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_NONE, - sizeof(struct atomisp_buffer), pipe, - NULL); /* ext_lock: NULL */ - - videobuf_queue_vmalloc_init(&pipe->outq, &videobuf_qops_output, NULL, - &pipe->irq_lock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_FIELD_NONE, - sizeof(struct atomisp_buffer), pipe, - NULL); /* ext_lock: NULL */ - - INIT_LIST_HEAD(&pipe->activeq); - INIT_LIST_HEAD(&pipe->activeq_out); - INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); - INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, 0, - VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, 0, - VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); - - return 0; -} - -static void atomisp_dev_init_struct(struct atomisp_device *isp) -{ - unsigned int i; - - isp->sw_contex.file_input = false; - isp->need_gfx_throttle = true; - isp->isp_fatal_error = false; - isp->mipi_frame_size = 0; - - for (i = 0; i < isp->input_cnt; i++) - isp->inputs[i].asd = NULL; - /* - * For Merrifield, frequency is scalable. - * After boot-up, the default frequency is 200MHz. - */ - isp->sw_contex.running_freq = ISP_FREQ_200MHZ; -} - -static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd) -{ - v4l2_ctrl_s_ctrl(asd->run_mode, ATOMISP_RUN_MODE_STILL_CAPTURE); - memset(&asd->params.css_param, 0, sizeof(asd->params.css_param)); - asd->params.color_effect = V4L2_COLORFX_NONE; - asd->params.bad_pixel_en = true; - asd->params.gdc_cac_en = false; - asd->params.video_dis_en = false; - asd->params.sc_en = false; - asd->params.fpn_en = false; - asd->params.xnr_en = false; - asd->params.false_color = 0; - asd->params.online_process = 1; - asd->params.yuv_ds_en = 0; - /* s3a grid not enabled for any pipe */ - asd->params.s3a_enabled_pipe = CSS_PIPE_ID_NUM; - - asd->params.offline_parm.num_captures = 1; - asd->params.offline_parm.skip_frames = 0; - asd->params.offline_parm.offset = 0; - asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED; - /* Add for channel */ - asd->input_curr = 0; - - asd->mipi_frame_size = 0; - asd->copy_mode = false; - asd->yuvpp_mode = false; - - asd->stream_prepared = false; - asd->high_speed_mode = false; - asd->sensor_array_res.height = 0; - asd->sensor_array_res.width = 0; - atomisp_css_init_struct(asd); -} -/* - * file operation functions - */ -static unsigned int atomisp_subdev_users(struct atomisp_sub_device *asd) -{ - return asd->video_out_preview.users + - asd->video_out_vf.users + - asd->video_out_capture.users + - asd->video_out_video_capture.users + - asd->video_acc.users + - asd->video_in.users; -} - -unsigned int atomisp_dev_users(struct atomisp_device *isp) -{ - unsigned int i, sum; - for (i = 0, sum = 0; i < isp->num_of_streams; i++) - sum += atomisp_subdev_users(&isp->asd[i]); - - return sum; -} - -static int atomisp_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = NULL; - struct atomisp_acc_pipe *acc_pipe = NULL; - struct atomisp_sub_device *asd; - bool acc_node = false; - int ret; - - dev_dbg(isp->dev, "open device %s\n", vdev->name); - - rt_mutex_lock(&isp->mutex); - - acc_node = !strncmp(vdev->name, "ATOMISP ISP ACC", - sizeof(vdev->name)); - if (acc_node) { - acc_pipe = atomisp_to_acc_pipe(vdev); - asd = acc_pipe->asd; - } else { - pipe = atomisp_to_video_pipe(vdev); - asd = pipe->asd; - } - asd->subdev.devnode = vdev; - /* Deferred firmware loading case. */ - if (isp->css_env.isp_css_fw.bytes == 0) { - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - dev_err(isp->dev, "Failed to load ISP firmware.\n"); - ret = -ENOENT; - goto error; - } - ret = atomisp_css_load_firmware(isp); - if (ret) { - dev_err(isp->dev, "Failed to init css.\n"); - goto error; - } - /* No need to keep FW in memory anymore. */ - release_firmware(isp->firmware); - isp->firmware = NULL; - isp->css_env.isp_css_fw.data = NULL; - } - - if (acc_node && acc_pipe->users) { - dev_dbg(isp->dev, "acc node already opened\n"); - rt_mutex_unlock(&isp->mutex); - return -EBUSY; - } else if (acc_node) { - goto dev_init; - } - - if (!isp->input_cnt) { - dev_err(isp->dev, "no camera attached\n"); - ret = -EINVAL; - goto error; - } - - /* - * atomisp does not allow multiple open - */ - if (pipe->users) { - dev_dbg(isp->dev, "video node already opened\n"); - rt_mutex_unlock(&isp->mutex); - return -EBUSY; - } - - ret = atomisp_init_pipe(pipe); - if (ret) - goto error; - -dev_init: - if (atomisp_dev_users(isp)) { - dev_dbg(isp->dev, "skip init isp in open\n"); - goto init_subdev; - } - - /* runtime power management, turn on ISP */ - ret = pm_runtime_get_sync(vdev->v4l2_dev->dev); - if (ret < 0) { - dev_err(isp->dev, "Failed to power on device\n"); - goto error; - } - - if (dypool_enable) { - ret = hmm_pool_register(dypool_pgnr, HMM_POOL_TYPE_DYNAMIC); - if (ret) - dev_err(isp->dev, "Failed to register dynamic memory pool.\n"); - } - - /* Init ISP */ - if (atomisp_css_init(isp)) { - ret = -EINVAL; - /* Need to clean up CSS init if it fails. */ - goto css_error; - } - - atomisp_dev_init_struct(isp); - - ret = v4l2_subdev_call(isp->flash, core, s_power, 1); - if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) { - dev_err(isp->dev, "Failed to power-on flash\n"); - goto css_error; - } - -init_subdev: - if (atomisp_subdev_users(asd)) - goto done; - - atomisp_subdev_init_struct(asd); - -done: - - if (acc_node) - acc_pipe->users++; - else - pipe->users++; - rt_mutex_unlock(&isp->mutex); - return 0; - -css_error: - atomisp_css_uninit(isp); -error: - hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC); - pm_runtime_put(vdev->v4l2_dev->dev); - rt_mutex_unlock(&isp->mutex); - return ret; -} - -static int atomisp_release(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe; - struct atomisp_acc_pipe *acc_pipe; - struct atomisp_sub_device *asd; - bool acc_node; - struct v4l2_requestbuffers req; - struct v4l2_subdev_fh fh; - struct v4l2_rect clear_compose = {0}; - int ret = 0; - - v4l2_fh_init(&fh.vfh, vdev); - - req.count = 0; - if (isp == NULL) - return -EBADF; - - mutex_lock(&isp->streamoff_mutex); - rt_mutex_lock(&isp->mutex); - - dev_dbg(isp->dev, "release device %s\n", vdev->name); - acc_node = !strncmp(vdev->name, "ATOMISP ISP ACC", - sizeof(vdev->name)); - if (acc_node) { - acc_pipe = atomisp_to_acc_pipe(vdev); - asd = acc_pipe->asd; - } else { - pipe = atomisp_to_video_pipe(vdev); - asd = pipe->asd; - } - asd->subdev.devnode = vdev; - if (acc_node) { - acc_pipe->users--; - goto subdev_uninit; - } - pipe->users--; - - if (pipe->capq.streaming) - dev_warn(isp->dev, - "%s: ISP still streaming while closing!", - __func__); - - if (pipe->capq.streaming && - __atomisp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE)) { - dev_err(isp->dev, - "atomisp_streamoff failed on release, driver bug"); - goto done; - } - - if (pipe->users) - goto done; - - if (__atomisp_reqbufs(file, NULL, &req)) { - dev_err(isp->dev, - "atomisp_reqbufs failed on release, driver bug"); - goto done; - } - - if (pipe->outq.bufs[0]) { - mutex_lock(&pipe->outq.vb_lock); - videobuf_queue_cancel(&pipe->outq); - mutex_unlock(&pipe->outq.vb_lock); - } - - /* - * A little trick here: - * file injection input resolution is recorded in the sink pad, - * therefore can not be cleared when releaseing one device node. - * The sink pad setting can only be cleared when all device nodes - * get released. - */ - if (!isp->sw_contex.file_input && asd->fmt_auto->val) { - struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); - } -subdev_uninit: - if (atomisp_subdev_users(asd)) - goto done; - - /* clear the sink pad for file input */ - if (isp->sw_contex.file_input && asd->fmt_auto->val) { - struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); - } - - atomisp_css_free_stat_buffers(asd); - atomisp_free_internal_buffers(asd); - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - core, s_power, 0); - if (ret) - dev_warn(isp->dev, "Failed to power-off sensor\n"); - - /* clear the asd field to show this camera is not used */ - isp->inputs[asd->input_curr].asd = NULL; - asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; - - if (atomisp_dev_users(isp)) - goto done; - - atomisp_acc_release(asd); - - atomisp_destroy_pipes_stream_force(asd); - atomisp_css_uninit(isp); - - if (defer_fw_load) { - atomisp_css_unload_firmware(isp); - isp->css_env.isp_css_fw.data = NULL; - isp->css_env.isp_css_fw.bytes = 0; - } - - hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC); - - ret = v4l2_subdev_call(isp->flash, core, s_power, 0); - if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) - dev_warn(isp->dev, "Failed to power-off flash\n"); - - if (pm_runtime_put_sync(vdev->v4l2_dev->dev) < 0) - dev_err(isp->dev, "Failed to power off device\n"); - -done: - if (!acc_node) { - atomisp_subdev_set_selection(&asd->subdev, fh.pad, - V4L2_SUBDEV_FORMAT_ACTIVE, - atomisp_subdev_source_pad(vdev), - V4L2_SEL_TGT_COMPOSE, 0, - &clear_compose); - } - rt_mutex_unlock(&isp->mutex); - mutex_unlock(&isp->streamoff_mutex); - - return 0; -} - -/* - * Memory help functions for image frame and private parameters - */ -static int do_isp_mm_remap(struct atomisp_device *isp, - struct vm_area_struct *vma, - ia_css_ptr isp_virt, u32 host_virt, u32 pgnr) -{ - u32 pfn; - - while (pgnr) { - pfn = hmm_virt_to_phys(isp_virt) >> PAGE_SHIFT; - if (remap_pfn_range(vma, host_virt, pfn, - PAGE_SIZE, PAGE_SHARED)) { - dev_err(isp->dev, "remap_pfn_range err.\n"); - return -EAGAIN; - } - - isp_virt += PAGE_SIZE; - host_virt += PAGE_SIZE; - pgnr--; - } - - return 0; -} - -static int frame_mmap(struct atomisp_device *isp, - const struct atomisp_css_frame *frame, struct vm_area_struct *vma) -{ - ia_css_ptr isp_virt; - u32 host_virt; - u32 pgnr; - - if (!frame) { - dev_err(isp->dev, "%s: NULL frame pointer.\n", __func__); - return -EINVAL; - } - - host_virt = vma->vm_start; - isp_virt = frame->data; - atomisp_get_frame_pgnr(isp, frame, &pgnr); - - if (do_isp_mm_remap(isp, vma, isp_virt, host_virt, pgnr)) - return -EAGAIN; - - return 0; -} - -int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma) -{ - u32 offset = vma->vm_pgoff << PAGE_SHIFT; - int ret = -EINVAL, i; - struct atomisp_device *isp = - ((struct atomisp_video_pipe *)(q->priv_data))->isp; - struct videobuf_vmalloc_memory *vm_mem; - struct videobuf_mapping *map; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) { - dev_err(isp->dev, "map appl bug: PROT_WRITE and MAP_SHARED are required\n"); - return -EINVAL; - } - - mutex_lock(&q->vb_lock); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - struct videobuf_buffer *buf = q->bufs[i]; - if (buf == NULL) - continue; - - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (!map) { - mutex_unlock(&q->vb_lock); - return -ENOMEM; - } - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - if (buf && buf->memory == V4L2_MEMORY_MMAP && - buf->boff == offset) { - vm_mem = buf->priv; - ret = frame_mmap(isp, vm_mem->vaddr, vma); - vma->vm_flags |= VM_IO|VM_DONTEXPAND|VM_DONTDUMP; - break; - } - } - mutex_unlock(&q->vb_lock); - - return ret; -} - -/* The input frame contains left and right padding that need to be removed. - * There is always ISP_LEFT_PAD padding on the left side. - * There is also padding on the right (padded_width - width). - */ -static int remove_pad_from_frame(struct atomisp_device *isp, - struct atomisp_css_frame *in_frame, __u32 width, __u32 height) -{ - unsigned int i; - unsigned short *buffer; - int ret = 0; - ia_css_ptr load = in_frame->data; - ia_css_ptr store = load; - - buffer = kmalloc(width*sizeof(load), GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - load += ISP_LEFT_PAD; - for (i = 0; i < height; i++) { - ret = hmm_load(load, buffer, width*sizeof(load)); - if (ret < 0) - goto remove_pad_error; - - ret = hmm_store(store, buffer, width*sizeof(store)); - if (ret < 0) - goto remove_pad_error; - - load += in_frame->info.padded_width; - store += width; - } - -remove_pad_error: - kfree(buffer); - return ret; -} - -static int atomisp_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - struct atomisp_sub_device *asd = pipe->asd; - struct atomisp_css_frame *raw_virt_addr; - u32 start = vma->vm_start; - u32 end = vma->vm_end; - u32 size = end - start; - u32 origin_size, new_size; - int ret; - - if (!(vma->vm_flags & (VM_WRITE | VM_READ))) - return -EACCES; - - rt_mutex_lock(&isp->mutex); - - if (!(vma->vm_flags & VM_SHARED)) { - /* Map private buffer. - * Set VM_SHARED to the flags since we need - * to map the buffer page by page. - * Without VM_SHARED, remap_pfn_range() treats - * this kind of mapping as invalid. - */ - vma->vm_flags |= VM_SHARED; - ret = hmm_mmap(vma, vma->vm_pgoff << PAGE_SHIFT); - rt_mutex_unlock(&isp->mutex); - return ret; - } - - /* mmap for ISP offline raw data */ - if (atomisp_subdev_source_pad(vdev) - == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE && - vma->vm_pgoff == (ISP_PARAM_MMAP_OFFSET >> PAGE_SHIFT)) { - new_size = pipe->pix.width * pipe->pix.height * 2; - if (asd->params.online_process != 0) { - ret = -EINVAL; - goto error; - } - raw_virt_addr = asd->raw_output_frame; - if (raw_virt_addr == NULL) { - dev_err(isp->dev, "Failed to request RAW frame\n"); - ret = -EINVAL; - goto error; - } - - ret = remove_pad_from_frame(isp, raw_virt_addr, - pipe->pix.width, pipe->pix.height); - if (ret < 0) { - dev_err(isp->dev, "remove pad failed.\n"); - goto error; - } - origin_size = raw_virt_addr->data_bytes; - raw_virt_addr->data_bytes = new_size; - - if (size != PAGE_ALIGN(new_size)) { - dev_err(isp->dev, "incorrect size for mmap ISP Raw Frame\n"); - ret = -EINVAL; - goto error; - } - - if (frame_mmap(isp, raw_virt_addr, vma)) { - dev_err(isp->dev, "frame_mmap failed.\n"); - raw_virt_addr->data_bytes = origin_size; - ret = -EAGAIN; - goto error; - } - raw_virt_addr->data_bytes = origin_size; - vma->vm_flags |= VM_IO|VM_DONTEXPAND|VM_DONTDUMP; - rt_mutex_unlock(&isp->mutex); - return 0; - } - - /* - * mmap for normal frames - */ - if (size != pipe->pix.sizeimage) { - dev_err(isp->dev, "incorrect size for mmap ISP frames\n"); - ret = -EINVAL; - goto error; - } - rt_mutex_unlock(&isp->mutex); - - return atomisp_videobuf_mmap_mapper(&pipe->capq, vma); - -error: - rt_mutex_unlock(&isp->mutex); - - return ret; -} - -static int atomisp_file_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - - return videobuf_mmap_mapper(&pipe->outq, vma); -} - -static __poll_t atomisp_poll(struct file *file, - struct poll_table_struct *pt) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - - rt_mutex_lock(&isp->mutex); - if (pipe->capq.streaming != 1) { - rt_mutex_unlock(&isp->mutex); - return EPOLLERR; - } - rt_mutex_unlock(&isp->mutex); - - return videobuf_poll_stream(file, &pipe->capq, pt); -} - -const struct v4l2_file_operations atomisp_fops = { - .owner = THIS_MODULE, - .open = atomisp_open, - .release = atomisp_release, - .mmap = atomisp_mmap, - .unlocked_ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - /* - * There are problems with this code. Disable this for now. - .compat_ioctl32 = atomisp_compat_ioctl32, - */ -#endif - .poll = atomisp_poll, -}; - -const struct v4l2_file_operations atomisp_file_fops = { - .owner = THIS_MODULE, - .open = atomisp_open, - .release = atomisp_release, - .mmap = atomisp_file_mmap, - .unlocked_ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - /* - * There are problems with this code. Disable this for now. - .compat_ioctl32 = atomisp_compat_ioctl32, - */ -#endif - .poll = atomisp_poll, -}; - |