1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Support for Medifield PNW Camera Imaging ISP subsystem.
4 *
5 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6 *
7 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 *
19 */
20
21 #include <linux/module.h>
22 #include <linux/pm_runtime.h>
23
24 #include <media/v4l2-ioctl.h>
25 #include <media/videobuf2-vmalloc.h>
26
27 #include "atomisp_cmd.h"
28 #include "atomisp_common.h"
29 #include "atomisp_fops.h"
30 #include "atomisp_internal.h"
31 #include "atomisp_ioctl.h"
32 #include "atomisp_compat.h"
33 #include "atomisp_subdev.h"
34 #include "atomisp_v4l2.h"
35 #include "atomisp-regs.h"
36 #include "hmm/hmm.h"
37
38 #include "ia_css_frame.h"
39 #include "type_support.h"
40 #include "device_access/device_access.h"
41
42 /*
43 * Videobuf2 ops
44 */
atomisp_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])45 static int atomisp_queue_setup(struct vb2_queue *vq,
46 unsigned int *nbuffers, unsigned int *nplanes,
47 unsigned int sizes[], struct device *alloc_devs[])
48 {
49 struct atomisp_video_pipe *pipe = container_of(vq, struct atomisp_video_pipe, vb_queue);
50 u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev);
51 int ret;
52
53 mutex_lock(&pipe->asd->isp->mutex); /* for get_css_frame_info() / set_fmt() */
54
55 /*
56 * When VIDIOC_S_FMT has not been called before VIDIOC_REQBUFS, then
57 * this will fail. Call atomisp_set_fmt() ourselves and try again.
58 */
59 ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info);
60 if (ret) {
61 struct v4l2_format f = {
62 .fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420,
63 .fmt.pix.width = 10000,
64 .fmt.pix.height = 10000,
65 };
66
67 ret = atomisp_set_fmt(&pipe->vdev, &f);
68 if (ret)
69 goto out;
70
71 ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info);
72 if (ret)
73 goto out;
74 }
75
76 atomisp_alloc_css_stat_bufs(pipe->asd, ATOMISP_INPUT_STREAM_GENERAL);
77
78 *nplanes = 1;
79 sizes[0] = PAGE_ALIGN(pipe->pix.sizeimage);
80
81 out:
82 mutex_unlock(&pipe->asd->isp->mutex);
83 return ret;
84 }
85
atomisp_buf_init(struct vb2_buffer * vb)86 static int atomisp_buf_init(struct vb2_buffer *vb)
87 {
88 struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
89 struct ia_css_frame *frame = vb_to_frame(vb);
90 int ret;
91
92 ret = ia_css_frame_init_from_info(frame, &pipe->frame_info);
93 if (ret)
94 return ret;
95
96 if (frame->data_bytes > vb2_plane_size(vb, 0)) {
97 dev_err(pipe->asd->isp->dev, "Internal error frame.data_bytes(%u) > vb.length(%lu)\n",
98 frame->data_bytes, vb2_plane_size(vb, 0));
99 return -EIO;
100 }
101
102 frame->data = hmm_create_from_vmalloc_buf(vb2_plane_size(vb, 0),
103 vb2_plane_vaddr(vb, 0));
104 if (frame->data == mmgr_NULL)
105 return -ENOMEM;
106
107 return 0;
108 }
109
atomisp_q_one_metadata_buffer(struct atomisp_sub_device * asd,enum atomisp_input_stream_id stream_id,enum ia_css_pipe_id css_pipe_id)110 static int atomisp_q_one_metadata_buffer(struct atomisp_sub_device *asd,
111 enum atomisp_input_stream_id stream_id,
112 enum ia_css_pipe_id css_pipe_id)
113 {
114 struct atomisp_metadata_buf *metadata_buf;
115 enum atomisp_metadata_type md_type =
116 atomisp_get_metadata_type(asd, css_pipe_id);
117 struct list_head *metadata_list;
118
119 if (asd->metadata_bufs_in_css[stream_id][css_pipe_id] >=
120 ATOMISP_CSS_Q_DEPTH)
121 return 0; /* we have reached CSS queue depth */
122
123 if (!list_empty(&asd->metadata[md_type])) {
124 metadata_list = &asd->metadata[md_type];
125 } else if (!list_empty(&asd->metadata_ready[md_type])) {
126 metadata_list = &asd->metadata_ready[md_type];
127 } else {
128 dev_warn(asd->isp->dev, "%s: No metadata buffers available for type %d!\n",
129 __func__, md_type);
130 return -EINVAL;
131 }
132
133 metadata_buf = list_entry(metadata_list->next,
134 struct atomisp_metadata_buf, list);
135 list_del_init(&metadata_buf->list);
136
137 if (atomisp_q_metadata_buffer_to_css(asd, metadata_buf,
138 stream_id, css_pipe_id)) {
139 list_add(&metadata_buf->list, metadata_list);
140 return -EINVAL;
141 } else {
142 list_add_tail(&metadata_buf->list,
143 &asd->metadata_in_css[md_type]);
144 }
145 asd->metadata_bufs_in_css[stream_id][css_pipe_id]++;
146
147 return 0;
148 }
149
atomisp_q_one_s3a_buffer(struct atomisp_sub_device * asd,enum atomisp_input_stream_id stream_id,enum ia_css_pipe_id css_pipe_id)150 static int atomisp_q_one_s3a_buffer(struct atomisp_sub_device *asd,
151 enum atomisp_input_stream_id stream_id,
152 enum ia_css_pipe_id css_pipe_id)
153 {
154 struct atomisp_s3a_buf *s3a_buf;
155 struct list_head *s3a_list;
156 unsigned int exp_id;
157
158 if (asd->s3a_bufs_in_css[css_pipe_id] >= ATOMISP_CSS_Q_DEPTH)
159 return 0; /* we have reached CSS queue depth */
160
161 if (!list_empty(&asd->s3a_stats)) {
162 s3a_list = &asd->s3a_stats;
163 } else if (!list_empty(&asd->s3a_stats_ready)) {
164 s3a_list = &asd->s3a_stats_ready;
165 } else {
166 dev_warn(asd->isp->dev, "%s: No s3a buffers available!\n",
167 __func__);
168 return -EINVAL;
169 }
170
171 s3a_buf = list_entry(s3a_list->next, struct atomisp_s3a_buf, list);
172 list_del_init(&s3a_buf->list);
173 exp_id = s3a_buf->s3a_data->exp_id;
174
175 hmm_flush_vmap(s3a_buf->s3a_data->data_ptr);
176 if (atomisp_q_s3a_buffer_to_css(asd, s3a_buf,
177 stream_id, css_pipe_id)) {
178 /* got from head, so return back to the head */
179 list_add(&s3a_buf->list, s3a_list);
180 return -EINVAL;
181 } else {
182 list_add_tail(&s3a_buf->list, &asd->s3a_stats_in_css);
183 if (s3a_list == &asd->s3a_stats_ready)
184 dev_dbg(asd->isp->dev, "drop one s3a stat with exp_id %d\n", exp_id);
185 }
186
187 asd->s3a_bufs_in_css[css_pipe_id]++;
188 return 0;
189 }
190
atomisp_q_one_dis_buffer(struct atomisp_sub_device * asd,enum atomisp_input_stream_id stream_id,enum ia_css_pipe_id css_pipe_id)191 static int atomisp_q_one_dis_buffer(struct atomisp_sub_device *asd,
192 enum atomisp_input_stream_id stream_id,
193 enum ia_css_pipe_id css_pipe_id)
194 {
195 struct atomisp_dis_buf *dis_buf;
196 unsigned long irqflags;
197
198 if (asd->dis_bufs_in_css >= ATOMISP_CSS_Q_DEPTH)
199 return 0; /* we have reached CSS queue depth */
200
201 spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
202 if (list_empty(&asd->dis_stats)) {
203 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
204 dev_warn(asd->isp->dev, "%s: No dis buffers available!\n",
205 __func__);
206 return -EINVAL;
207 }
208
209 dis_buf = list_entry(asd->dis_stats.prev,
210 struct atomisp_dis_buf, list);
211 list_del_init(&dis_buf->list);
212 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
213
214 hmm_flush_vmap(dis_buf->dis_data->data_ptr);
215 if (atomisp_q_dis_buffer_to_css(asd, dis_buf,
216 stream_id, css_pipe_id)) {
217 spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
218 /* got from tail, so return back to the tail */
219 list_add_tail(&dis_buf->list, &asd->dis_stats);
220 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
221 return -EINVAL;
222 } else {
223 spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
224 list_add_tail(&dis_buf->list, &asd->dis_stats_in_css);
225 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
226 }
227
228 asd->dis_bufs_in_css++;
229
230 return 0;
231 }
232
atomisp_q_video_buffers_to_css(struct atomisp_sub_device * asd,struct atomisp_video_pipe * pipe,enum atomisp_input_stream_id stream_id,enum ia_css_buffer_type css_buf_type,enum ia_css_pipe_id css_pipe_id)233 static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
234 struct atomisp_video_pipe *pipe,
235 enum atomisp_input_stream_id stream_id,
236 enum ia_css_buffer_type css_buf_type,
237 enum ia_css_pipe_id css_pipe_id)
238 {
239 struct atomisp_css_params_with_list *param;
240 struct ia_css_dvs_grid_info *dvs_grid =
241 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
242 unsigned long irqflags;
243 int space, err = 0;
244
245 lockdep_assert_held(&asd->isp->mutex);
246
247 if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM))
248 return -EINVAL;
249
250 if (pipe->stopping)
251 return -EINVAL;
252
253 space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe);
254 while (space--) {
255 struct ia_css_frame *frame;
256
257 spin_lock_irqsave(&pipe->irq_lock, irqflags);
258 frame = list_first_entry_or_null(&pipe->activeq, struct ia_css_frame, queue);
259 if (frame)
260 list_move_tail(&frame->queue, &pipe->buffers_in_css);
261 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
262
263 if (!frame)
264 return -EINVAL;
265
266 /*
267 * If there is a per_frame setting to apply on the buffer,
268 * do it before buffer en-queueing.
269 */
270 param = pipe->frame_params[frame->vb.vb2_buf.index];
271 if (param) {
272 atomisp_makeup_css_parameters(asd,
273 &asd->params.css_param.update_flag,
274 ¶m->params);
275 atomisp_apply_css_parameters(asd, ¶m->params);
276
277 if (param->params.update_flag.dz_config &&
278 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
279 err = atomisp_calculate_real_zoom_region(asd,
280 ¶m->params.dz_config, css_pipe_id);
281 if (!err)
282 asd->params.config.dz_config = ¶m->params.dz_config;
283 }
284 atomisp_css_set_isp_config_applied_frame(asd, frame);
285 atomisp_css_update_isp_params_on_pipe(asd,
286 asd->stream_env[stream_id].pipes[css_pipe_id]);
287 asd->params.dvs_6axis = (struct ia_css_dvs_6axis_config *)
288 param->params.dvs_6axis;
289
290 /*
291 * WORKAROUND:
292 * Because the camera halv3 can't ensure to set zoom
293 * region to per_frame setting and global setting at
294 * same time and only set zoom region to pre_frame
295 * setting now.so when the pre_frame setting include
296 * zoom region,I will set it to global setting.
297 */
298 if (param->params.update_flag.dz_config &&
299 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO
300 && !err) {
301 memcpy(&asd->params.css_param.dz_config,
302 ¶m->params.dz_config,
303 sizeof(struct ia_css_dz_config));
304 asd->params.css_param.update_flag.dz_config =
305 (struct atomisp_dz_config *)
306 &asd->params.css_param.dz_config;
307 asd->params.css_update_params_needed = true;
308 }
309 pipe->frame_params[frame->vb.vb2_buf.index] = NULL;
310 }
311 /* Enqueue buffer */
312 err = atomisp_q_video_buffer_to_css(asd, frame, stream_id,
313 css_buf_type, css_pipe_id);
314 if (err) {
315 spin_lock_irqsave(&pipe->irq_lock, irqflags);
316 list_move_tail(&frame->queue, &pipe->activeq);
317 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
318 dev_err(asd->isp->dev, "%s, css q fails: %d\n",
319 __func__, err);
320 return -EINVAL;
321 }
322
323 /* enqueue 3A/DIS/metadata buffers */
324 if (asd->params.curr_grid_info.s3a_grid.enable &&
325 css_pipe_id == asd->params.s3a_enabled_pipe &&
326 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
327 atomisp_q_one_s3a_buffer(asd, stream_id,
328 css_pipe_id);
329
330 if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
331 metadata_info.size &&
332 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
333 atomisp_q_one_metadata_buffer(asd, stream_id,
334 css_pipe_id);
335
336 if (dvs_grid && dvs_grid->enable &&
337 css_pipe_id == IA_CSS_PIPE_ID_VIDEO &&
338 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
339 atomisp_q_one_dis_buffer(asd, stream_id,
340 css_pipe_id);
341 }
342
343 return 0;
344 }
345
atomisp_get_css_buf_type(struct atomisp_sub_device * asd,enum ia_css_pipe_id pipe_id,uint16_t source_pad)346 static int atomisp_get_css_buf_type(struct atomisp_sub_device *asd,
347 enum ia_css_pipe_id pipe_id,
348 uint16_t source_pad)
349 {
350 if (ATOMISP_USE_YUVPP(asd)) {
351 /* when run ZSL case */
352 if (asd->continuous_mode->val &&
353 asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
354 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE)
355 return IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
356 else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW)
357 return IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME;
358 else
359 return IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME;
360 }
361
362 /*when run SDV case*/
363 if (asd->continuous_mode->val &&
364 asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
365 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE)
366 return IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
367 else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW)
368 return IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME;
369 else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO)
370 return IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME;
371 else
372 return IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME;
373 }
374
375 /*other case: default setting*/
376 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE ||
377 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO ||
378 (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW &&
379 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO))
380 return IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
381 else
382 return IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME;
383 }
384
385 if (pipe_id == IA_CSS_PIPE_ID_COPY ||
386 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE ||
387 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO ||
388 (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW &&
389 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO))
390 return IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
391 else
392 return IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME;
393 }
394
395 /* queue all available buffers to css */
atomisp_qbuffers_to_css(struct atomisp_sub_device * asd)396 int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd)
397 {
398 enum ia_css_buffer_type buf_type;
399 enum ia_css_pipe_id css_capture_pipe_id = IA_CSS_PIPE_ID_NUM;
400 enum ia_css_pipe_id css_preview_pipe_id = IA_CSS_PIPE_ID_NUM;
401 enum ia_css_pipe_id css_video_pipe_id = IA_CSS_PIPE_ID_NUM;
402 enum atomisp_input_stream_id input_stream_id;
403 struct atomisp_video_pipe *capture_pipe = NULL;
404 struct atomisp_video_pipe *vf_pipe = NULL;
405 struct atomisp_video_pipe *preview_pipe = NULL;
406 struct atomisp_video_pipe *video_pipe = NULL;
407 bool raw_mode = atomisp_is_mbuscode_raw(
408 asd->fmt[asd->capture_pad].fmt.code);
409
410 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
411 video_pipe = &asd->video_out_video_capture;
412 css_video_pipe_id = IA_CSS_PIPE_ID_VIDEO;
413 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
414 preview_pipe = &asd->video_out_capture;
415 css_preview_pipe_id = IA_CSS_PIPE_ID_CAPTURE;
416 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
417 if (asd->continuous_mode->val) {
418 capture_pipe = &asd->video_out_capture;
419 vf_pipe = &asd->video_out_vf;
420 css_capture_pipe_id = IA_CSS_PIPE_ID_CAPTURE;
421 }
422 video_pipe = &asd->video_out_video_capture;
423 preview_pipe = &asd->video_out_preview;
424 css_video_pipe_id = IA_CSS_PIPE_ID_VIDEO;
425 css_preview_pipe_id = IA_CSS_PIPE_ID_VIDEO;
426 } else if (asd->continuous_mode->val) {
427 capture_pipe = &asd->video_out_capture;
428 vf_pipe = &asd->video_out_vf;
429 preview_pipe = &asd->video_out_preview;
430
431 css_preview_pipe_id = IA_CSS_PIPE_ID_PREVIEW;
432 css_capture_pipe_id = IA_CSS_PIPE_ID_CAPTURE;
433 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
434 preview_pipe = &asd->video_out_preview;
435 css_preview_pipe_id = IA_CSS_PIPE_ID_PREVIEW;
436 } else {
437 /* ATOMISP_RUN_MODE_STILL_CAPTURE */
438 capture_pipe = &asd->video_out_capture;
439 if (!raw_mode)
440 vf_pipe = &asd->video_out_vf;
441 css_capture_pipe_id = IA_CSS_PIPE_ID_CAPTURE;
442 }
443
444 if (IS_ISP2401 && asd->copy_mode) {
445 css_capture_pipe_id = IA_CSS_PIPE_ID_COPY;
446 css_preview_pipe_id = IA_CSS_PIPE_ID_COPY;
447 css_video_pipe_id = IA_CSS_PIPE_ID_COPY;
448 }
449
450 if (asd->yuvpp_mode) {
451 capture_pipe = &asd->video_out_capture;
452 video_pipe = &asd->video_out_video_capture;
453 preview_pipe = &asd->video_out_preview;
454 css_capture_pipe_id = IA_CSS_PIPE_ID_COPY;
455 css_video_pipe_id = IA_CSS_PIPE_ID_YUVPP;
456 css_preview_pipe_id = IA_CSS_PIPE_ID_YUVPP;
457 }
458
459 if (capture_pipe) {
460 buf_type = atomisp_get_css_buf_type(
461 asd, css_capture_pipe_id,
462 atomisp_subdev_source_pad(&capture_pipe->vdev));
463 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL;
464
465 /*
466 * use yuvpp pipe for SOC camera.
467 */
468 if (ATOMISP_USE_YUVPP(asd))
469 css_capture_pipe_id = IA_CSS_PIPE_ID_YUVPP;
470
471 atomisp_q_video_buffers_to_css(asd, capture_pipe,
472 input_stream_id,
473 buf_type, css_capture_pipe_id);
474 }
475
476 if (vf_pipe) {
477 buf_type = atomisp_get_css_buf_type(
478 asd, css_capture_pipe_id,
479 atomisp_subdev_source_pad(&vf_pipe->vdev));
480 if (asd->stream_env[ATOMISP_INPUT_STREAM_POSTVIEW].stream)
481 input_stream_id = ATOMISP_INPUT_STREAM_POSTVIEW;
482 else
483 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL;
484
485 /*
486 * use yuvpp pipe for SOC camera.
487 */
488 if (ATOMISP_USE_YUVPP(asd))
489 css_capture_pipe_id = IA_CSS_PIPE_ID_YUVPP;
490 atomisp_q_video_buffers_to_css(asd, vf_pipe,
491 input_stream_id,
492 buf_type, css_capture_pipe_id);
493 }
494
495 if (preview_pipe) {
496 buf_type = atomisp_get_css_buf_type(
497 asd, css_preview_pipe_id,
498 atomisp_subdev_source_pad(&preview_pipe->vdev));
499 if (ATOMISP_SOC_CAMERA(asd) && css_preview_pipe_id == IA_CSS_PIPE_ID_YUVPP)
500 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL;
501 /* else for ext isp use case */
502 else if (css_preview_pipe_id == IA_CSS_PIPE_ID_YUVPP)
503 input_stream_id = ATOMISP_INPUT_STREAM_VIDEO;
504 else if (asd->stream_env[ATOMISP_INPUT_STREAM_PREVIEW].stream)
505 input_stream_id = ATOMISP_INPUT_STREAM_PREVIEW;
506 else
507 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL;
508
509 /*
510 * use yuvpp pipe for SOC camera.
511 */
512 if (ATOMISP_USE_YUVPP(asd))
513 css_preview_pipe_id = IA_CSS_PIPE_ID_YUVPP;
514
515 atomisp_q_video_buffers_to_css(asd, preview_pipe,
516 input_stream_id,
517 buf_type, css_preview_pipe_id);
518 }
519
520 if (video_pipe) {
521 buf_type = atomisp_get_css_buf_type(
522 asd, css_video_pipe_id,
523 atomisp_subdev_source_pad(&video_pipe->vdev));
524 if (asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO].stream)
525 input_stream_id = ATOMISP_INPUT_STREAM_VIDEO;
526 else
527 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL;
528
529 /*
530 * use yuvpp pipe for SOC camera.
531 */
532 if (ATOMISP_USE_YUVPP(asd))
533 css_video_pipe_id = IA_CSS_PIPE_ID_YUVPP;
534
535 atomisp_q_video_buffers_to_css(asd, video_pipe,
536 input_stream_id,
537 buf_type, css_video_pipe_id);
538 }
539
540 return 0;
541 }
542
atomisp_buf_queue(struct vb2_buffer * vb)543 static void atomisp_buf_queue(struct vb2_buffer *vb)
544 {
545 struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
546 struct ia_css_frame *frame = vb_to_frame(vb);
547 struct atomisp_sub_device *asd = pipe->asd;
548 u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev);
549 unsigned long irqflags;
550 int ret;
551
552 mutex_lock(&asd->isp->mutex);
553
554 ret = atomisp_pipe_check(pipe, false);
555 if (ret || pipe->stopping) {
556 spin_lock_irqsave(&pipe->irq_lock, irqflags);
557 atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
558 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
559 goto out_unlock;
560 }
561
562 /* FIXME this ugliness comes from the original atomisp buffer handling */
563 if (!(vb->skip_cache_sync_on_finish && vb->skip_cache_sync_on_prepare))
564 wbinvd();
565
566 pipe->frame_params[vb->index] = NULL;
567
568 spin_lock_irqsave(&pipe->irq_lock, irqflags);
569 /*
570 * when a frame buffer meets following conditions, it should be put into
571 * the waiting list:
572 * 1. It is not a main output frame, and it has a per-frame parameter
573 * to go with it.
574 * 2. It is not a main output frame, and the waiting buffer list is not
575 * empty, to keep the FIFO sequence of frame buffer processing, it
576 * is put to waiting list until previous per-frame parameter buffers
577 * get enqueued.
578 */
579 if (!atomisp_is_vf_pipe(pipe) &&
580 (pipe->frame_request_config_id[vb->index] ||
581 !list_empty(&pipe->buffers_waiting_for_param)))
582 list_add_tail(&frame->queue, &pipe->buffers_waiting_for_param);
583 else
584 list_add_tail(&frame->queue, &pipe->activeq);
585
586 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
587
588 /* TODO: do this better, not best way to queue to css */
589 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
590 if (!list_empty(&pipe->buffers_waiting_for_param))
591 atomisp_handle_parameter_and_buffer(pipe);
592 else
593 atomisp_qbuffers_to_css(asd);
594 }
595
596 /*
597 * Workaround: Due to the design of HALv3,
598 * sometimes in ZSL or SDV mode HAL needs to
599 * capture multiple images within one streaming cycle.
600 * But the capture number cannot be determined by HAL.
601 * So HAL only sets the capture number to be 1 and queue multiple
602 * buffers. Atomisp driver needs to check this case and re-trigger
603 * CSS to do capture when new buffer is queued.
604 */
605 if (asd->continuous_mode->val && source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
606 !asd->enable_raw_buffer_lock->val && asd->params.offline_parm.num_captures == 1) {
607 asd->pending_capture_request++;
608 dev_dbg(asd->isp->dev, "Add one pending capture request.\n");
609 }
610
611 out_unlock:
612 mutex_unlock(&asd->isp->mutex);
613 }
614
atomisp_buf_cleanup(struct vb2_buffer * vb)615 static void atomisp_buf_cleanup(struct vb2_buffer *vb)
616 {
617 struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
618 struct ia_css_frame *frame = vb_to_frame(vb);
619 int index = frame->vb.vb2_buf.index;
620
621 pipe->frame_request_config_id[index] = 0;
622 pipe->frame_params[index] = NULL;
623
624 hmm_free(frame->data);
625 }
626
627 const struct vb2_ops atomisp_vb2_ops = {
628 .queue_setup = atomisp_queue_setup,
629 .buf_init = atomisp_buf_init,
630 .buf_cleanup = atomisp_buf_cleanup,
631 .buf_queue = atomisp_buf_queue,
632 .start_streaming = atomisp_start_streaming,
633 .stop_streaming = atomisp_stop_streaming,
634 };
635
atomisp_dev_init_struct(struct atomisp_device * isp)636 static void atomisp_dev_init_struct(struct atomisp_device *isp)
637 {
638 unsigned int i;
639
640 isp->need_gfx_throttle = true;
641 isp->isp_fatal_error = false;
642 isp->mipi_frame_size = 0;
643
644 for (i = 0; i < isp->input_cnt; i++)
645 isp->inputs[i].asd = NULL;
646 /*
647 * For Merrifield, frequency is scalable.
648 * After boot-up, the default frequency is 200MHz.
649 */
650 isp->running_freq = ISP_FREQ_200MHZ;
651 }
652
atomisp_subdev_init_struct(struct atomisp_sub_device * asd)653 static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd)
654 {
655 v4l2_ctrl_s_ctrl(asd->run_mode, ATOMISP_RUN_MODE_STILL_CAPTURE);
656 memset(&asd->params.css_param, 0, sizeof(asd->params.css_param));
657 asd->params.color_effect = V4L2_COLORFX_NONE;
658 asd->params.bad_pixel_en = true;
659 asd->params.gdc_cac_en = false;
660 asd->params.video_dis_en = false;
661 asd->params.sc_en = false;
662 asd->params.fpn_en = false;
663 asd->params.xnr_en = false;
664 asd->params.false_color = 0;
665 asd->params.online_process = 1;
666 asd->params.yuv_ds_en = 0;
667 /* s3a grid not enabled for any pipe */
668 asd->params.s3a_enabled_pipe = IA_CSS_PIPE_ID_NUM;
669
670 asd->params.offline_parm.num_captures = 1;
671 asd->params.offline_parm.skip_frames = 0;
672 asd->params.offline_parm.offset = 0;
673 asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED;
674 /* Add for channel */
675 asd->input_curr = 0;
676
677 asd->mipi_frame_size = 0;
678 asd->copy_mode = false;
679 asd->yuvpp_mode = false;
680
681 asd->stream_prepared = false;
682 asd->high_speed_mode = false;
683 asd->sensor_array_res.height = 0;
684 asd->sensor_array_res.width = 0;
685 atomisp_css_init_struct(asd);
686 }
687
688 /*
689 * file operation functions
690 */
atomisp_subdev_users(struct atomisp_sub_device * asd)691 static unsigned int atomisp_subdev_users(struct atomisp_sub_device *asd)
692 {
693 return asd->video_out_preview.users +
694 asd->video_out_vf.users +
695 asd->video_out_capture.users +
696 asd->video_out_video_capture.users;
697 }
698
atomisp_dev_users(struct atomisp_device * isp)699 unsigned int atomisp_dev_users(struct atomisp_device *isp)
700 {
701 unsigned int i, sum;
702
703 for (i = 0, sum = 0; i < isp->num_of_streams; i++)
704 sum += atomisp_subdev_users(&isp->asd[i]);
705
706 return sum;
707 }
708
atomisp_open(struct file * file)709 static int atomisp_open(struct file *file)
710 {
711 struct video_device *vdev = video_devdata(file);
712 struct atomisp_device *isp = video_get_drvdata(vdev);
713 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
714 struct atomisp_sub_device *asd = pipe->asd;
715 int ret;
716
717 dev_dbg(isp->dev, "open device %s\n", vdev->name);
718
719 ret = v4l2_fh_open(file);
720 if (ret)
721 return ret;
722
723 mutex_lock(&isp->mutex);
724
725 asd->subdev.devnode = vdev;
726
727 if (!isp->input_cnt) {
728 dev_err(isp->dev, "no camera attached\n");
729 ret = -EINVAL;
730 goto error;
731 }
732
733 /*
734 * atomisp does not allow multiple open
735 */
736 if (pipe->users) {
737 dev_dbg(isp->dev, "video node already opened\n");
738 mutex_unlock(&isp->mutex);
739 return -EBUSY;
740 }
741
742 if (atomisp_dev_users(isp)) {
743 dev_dbg(isp->dev, "skip init isp in open\n");
744 goto init_subdev;
745 }
746
747 /* runtime power management, turn on ISP */
748 ret = pm_runtime_resume_and_get(vdev->v4l2_dev->dev);
749 if (ret < 0) {
750 dev_err(isp->dev, "Failed to power on device\n");
751 goto error;
752 }
753
754 atomisp_dev_init_struct(isp);
755
756 ret = v4l2_subdev_call(isp->flash, core, s_power, 1);
757 if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) {
758 dev_err(isp->dev, "Failed to power-on flash\n");
759 goto css_error;
760 }
761
762 init_subdev:
763 if (atomisp_subdev_users(asd))
764 goto done;
765
766 atomisp_subdev_init_struct(asd);
767 /* Ensure that a mode is set */
768 v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode);
769
770 done:
771 pipe->users++;
772 mutex_unlock(&isp->mutex);
773
774
775 return 0;
776
777 css_error:
778 pm_runtime_put(vdev->v4l2_dev->dev);
779 error:
780 mutex_unlock(&isp->mutex);
781 v4l2_fh_release(file);
782 return ret;
783 }
784
atomisp_release(struct file * file)785 static int atomisp_release(struct file *file)
786 {
787 struct video_device *vdev = video_devdata(file);
788 struct atomisp_device *isp = video_get_drvdata(vdev);
789 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
790 struct atomisp_sub_device *asd = pipe->asd;
791 struct v4l2_subdev_fh fh;
792 struct v4l2_rect clear_compose = {0};
793 unsigned long flags;
794 int ret;
795
796 v4l2_fh_init(&fh.vfh, vdev);
797
798 dev_dbg(isp->dev, "release device %s\n", vdev->name);
799
800 asd->subdev.devnode = vdev;
801
802 /* Note file must not be used after this! */
803 vb2_fop_release(file);
804
805 mutex_lock(&isp->mutex);
806
807 pipe->users--;
808 if (pipe->users)
809 goto done;
810
811 /*
812 * A little trick here:
813 * file injection input resolution is recorded in the sink pad,
814 * therefore can not be cleared when releaseing one device node.
815 * The sink pad setting can only be cleared when all device nodes
816 * get released.
817 */
818 if (asd->fmt_auto->val) {
819 struct v4l2_mbus_framefmt isp_sink_fmt = { 0 };
820
821 atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
822 V4L2_SUBDEV_FORMAT_ACTIVE,
823 ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt);
824 }
825
826 if (atomisp_subdev_users(asd))
827 goto done;
828
829 atomisp_css_free_stat_buffers(asd);
830 atomisp_free_internal_buffers(asd);
831
832 if (isp->inputs[asd->input_curr].asd == asd) {
833 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
834 core, s_power, 0);
835 if (ret && ret != -ENOIOCTLCMD)
836 dev_warn(isp->dev, "Failed to power-off sensor\n");
837
838 /* clear the asd field to show this camera is not used */
839 isp->inputs[asd->input_curr].asd = NULL;
840 }
841
842 spin_lock_irqsave(&isp->lock, flags);
843 asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
844 spin_unlock_irqrestore(&isp->lock, flags);
845
846 if (atomisp_dev_users(isp))
847 goto done;
848
849 atomisp_destroy_pipes_stream_force(asd);
850
851 ret = v4l2_subdev_call(isp->flash, core, s_power, 0);
852 if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD)
853 dev_warn(isp->dev, "Failed to power-off flash\n");
854
855 if (pm_runtime_put_sync(vdev->v4l2_dev->dev) < 0)
856 dev_err(isp->dev, "Failed to power off device\n");
857
858 done:
859 atomisp_subdev_set_selection(&asd->subdev, fh.state,
860 V4L2_SUBDEV_FORMAT_ACTIVE,
861 atomisp_subdev_source_pad(vdev),
862 V4L2_SEL_TGT_COMPOSE, 0,
863 &clear_compose);
864 mutex_unlock(&isp->mutex);
865 return 0;
866 }
867
868 const struct v4l2_file_operations atomisp_fops = {
869 .owner = THIS_MODULE,
870 .open = atomisp_open,
871 .release = atomisp_release,
872 .mmap = vb2_fop_mmap,
873 .poll = vb2_fop_poll,
874 .unlocked_ioctl = video_ioctl2,
875 #ifdef CONFIG_COMPAT
876 /*
877 * this was removed because of bugs, the interface
878 * needs to be made safe for compat tasks instead.
879 .compat_ioctl32 = atomisp_compat_ioctl32,
880 */
881 #endif
882 };
883