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 int ret;
51
52 mutex_lock(&pipe->asd->isp->mutex); /* for get_css_frame_info() / set_fmt() */
53
54 /*
55 * When VIDIOC_S_FMT has not been called before VIDIOC_REQBUFS, then
56 * this will fail. Call atomisp_set_fmt() ourselves and try again.
57 */
58 ret = atomisp_get_css_frame_info(pipe->asd, &pipe->frame_info);
59 if (ret) {
60 struct v4l2_format f = {
61 .fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420,
62 .fmt.pix.width = 10000,
63 .fmt.pix.height = 10000,
64 };
65
66 ret = atomisp_set_fmt(&pipe->vdev, &f);
67 if (ret)
68 goto out;
69
70 ret = atomisp_get_css_frame_info(pipe->asd, &pipe->frame_info);
71 if (ret)
72 goto out;
73 }
74
75 atomisp_alloc_css_stat_bufs(pipe->asd, ATOMISP_INPUT_STREAM_GENERAL);
76
77 *nplanes = 1;
78 sizes[0] = PAGE_ALIGN(pipe->pix.sizeimage);
79
80 out:
81 mutex_unlock(&pipe->asd->isp->mutex);
82 return ret;
83 }
84
atomisp_buf_init(struct vb2_buffer * vb)85 static int atomisp_buf_init(struct vb2_buffer *vb)
86 {
87 struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
88 struct ia_css_frame *frame = vb_to_frame(vb);
89 int ret;
90
91 ret = ia_css_frame_init_from_info(frame, &pipe->frame_info);
92 if (ret)
93 return ret;
94
95 if (frame->data_bytes > vb2_plane_size(vb, 0)) {
96 dev_err(pipe->asd->isp->dev, "Internal error frame.data_bytes(%u) > vb.length(%lu)\n",
97 frame->data_bytes, vb2_plane_size(vb, 0));
98 return -EIO;
99 }
100
101 frame->data = hmm_create_from_vmalloc_buf(vb2_plane_size(vb, 0),
102 vb2_plane_vaddr(vb, 0));
103 if (frame->data == mmgr_NULL)
104 return -ENOMEM;
105
106 return 0;
107 }
108
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)109 static int atomisp_q_one_metadata_buffer(struct atomisp_sub_device *asd,
110 enum atomisp_input_stream_id stream_id,
111 enum ia_css_pipe_id css_pipe_id)
112 {
113 struct atomisp_metadata_buf *metadata_buf;
114 enum atomisp_metadata_type md_type = ATOMISP_MAIN_METADATA;
115 struct list_head *metadata_list;
116
117 if (asd->metadata_bufs_in_css[stream_id][css_pipe_id] >=
118 ATOMISP_CSS_Q_DEPTH)
119 return 0; /* we have reached CSS queue depth */
120
121 if (!list_empty(&asd->metadata[md_type])) {
122 metadata_list = &asd->metadata[md_type];
123 } else if (!list_empty(&asd->metadata_ready[md_type])) {
124 metadata_list = &asd->metadata_ready[md_type];
125 } else {
126 dev_warn(asd->isp->dev, "%s: No metadata buffers available for type %d!\n",
127 __func__, md_type);
128 return -EINVAL;
129 }
130
131 metadata_buf = list_entry(metadata_list->next,
132 struct atomisp_metadata_buf, list);
133 list_del_init(&metadata_buf->list);
134
135 if (atomisp_q_metadata_buffer_to_css(asd, metadata_buf,
136 stream_id, css_pipe_id)) {
137 list_add(&metadata_buf->list, metadata_list);
138 return -EINVAL;
139 } else {
140 list_add_tail(&metadata_buf->list,
141 &asd->metadata_in_css[md_type]);
142 }
143 asd->metadata_bufs_in_css[stream_id][css_pipe_id]++;
144
145 return 0;
146 }
147
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)148 static int atomisp_q_one_s3a_buffer(struct atomisp_sub_device *asd,
149 enum atomisp_input_stream_id stream_id,
150 enum ia_css_pipe_id css_pipe_id)
151 {
152 struct atomisp_s3a_buf *s3a_buf;
153 struct list_head *s3a_list;
154 unsigned int exp_id;
155
156 if (asd->s3a_bufs_in_css[css_pipe_id] >= ATOMISP_CSS_Q_DEPTH)
157 return 0; /* we have reached CSS queue depth */
158
159 if (!list_empty(&asd->s3a_stats)) {
160 s3a_list = &asd->s3a_stats;
161 } else if (!list_empty(&asd->s3a_stats_ready)) {
162 s3a_list = &asd->s3a_stats_ready;
163 } else {
164 dev_warn(asd->isp->dev, "%s: No s3a buffers available!\n",
165 __func__);
166 return -EINVAL;
167 }
168
169 s3a_buf = list_entry(s3a_list->next, struct atomisp_s3a_buf, list);
170 list_del_init(&s3a_buf->list);
171 exp_id = s3a_buf->s3a_data->exp_id;
172
173 hmm_flush_vmap(s3a_buf->s3a_data->data_ptr);
174 if (atomisp_q_s3a_buffer_to_css(asd, s3a_buf,
175 stream_id, css_pipe_id)) {
176 /* got from head, so return back to the head */
177 list_add(&s3a_buf->list, s3a_list);
178 return -EINVAL;
179 } else {
180 list_add_tail(&s3a_buf->list, &asd->s3a_stats_in_css);
181 if (s3a_list == &asd->s3a_stats_ready)
182 dev_dbg(asd->isp->dev, "drop one s3a stat with exp_id %d\n", exp_id);
183 }
184
185 asd->s3a_bufs_in_css[css_pipe_id]++;
186 return 0;
187 }
188
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)189 static int atomisp_q_one_dis_buffer(struct atomisp_sub_device *asd,
190 enum atomisp_input_stream_id stream_id,
191 enum ia_css_pipe_id css_pipe_id)
192 {
193 struct atomisp_dis_buf *dis_buf;
194 unsigned long irqflags;
195
196 if (asd->dis_bufs_in_css >= ATOMISP_CSS_Q_DEPTH)
197 return 0; /* we have reached CSS queue depth */
198
199 spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
200 if (list_empty(&asd->dis_stats)) {
201 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
202 dev_warn(asd->isp->dev, "%s: No dis buffers available!\n",
203 __func__);
204 return -EINVAL;
205 }
206
207 dis_buf = list_entry(asd->dis_stats.prev,
208 struct atomisp_dis_buf, list);
209 list_del_init(&dis_buf->list);
210 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
211
212 hmm_flush_vmap(dis_buf->dis_data->data_ptr);
213 if (atomisp_q_dis_buffer_to_css(asd, dis_buf,
214 stream_id, css_pipe_id)) {
215 spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
216 /* got from tail, so return back to the tail */
217 list_add_tail(&dis_buf->list, &asd->dis_stats);
218 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
219 return -EINVAL;
220 } else {
221 spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
222 list_add_tail(&dis_buf->list, &asd->dis_stats_in_css);
223 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
224 }
225
226 asd->dis_bufs_in_css++;
227
228 return 0;
229 }
230
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)231 static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
232 struct atomisp_video_pipe *pipe,
233 enum atomisp_input_stream_id stream_id,
234 enum ia_css_buffer_type css_buf_type,
235 enum ia_css_pipe_id css_pipe_id)
236 {
237 struct atomisp_css_params_with_list *param;
238 struct ia_css_dvs_grid_info *dvs_grid =
239 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
240 unsigned long irqflags;
241 int space, err = 0;
242
243 lockdep_assert_held(&asd->isp->mutex);
244
245 if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM))
246 return -EINVAL;
247
248 if (pipe->stopping)
249 return -EINVAL;
250
251 space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe);
252 while (space--) {
253 struct ia_css_frame *frame;
254
255 spin_lock_irqsave(&pipe->irq_lock, irqflags);
256 frame = list_first_entry_or_null(&pipe->activeq, struct ia_css_frame, queue);
257 if (frame)
258 list_move_tail(&frame->queue, &pipe->buffers_in_css);
259 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
260
261 if (!frame)
262 return -EINVAL;
263
264 /*
265 * If there is a per_frame setting to apply on the buffer,
266 * do it before buffer en-queueing.
267 */
268 param = pipe->frame_params[frame->vb.vb2_buf.index];
269 if (param) {
270 atomisp_makeup_css_parameters(asd,
271 &asd->params.css_param.update_flag,
272 ¶m->params);
273 atomisp_apply_css_parameters(asd, ¶m->params);
274
275 if (param->params.update_flag.dz_config &&
276 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
277 err = atomisp_calculate_real_zoom_region(asd,
278 ¶m->params.dz_config, css_pipe_id);
279 if (!err)
280 asd->params.config.dz_config = ¶m->params.dz_config;
281 }
282 atomisp_css_set_isp_config_applied_frame(asd, frame);
283 atomisp_css_update_isp_params_on_pipe(asd,
284 asd->stream_env[stream_id].pipes[css_pipe_id]);
285 asd->params.dvs_6axis = (struct ia_css_dvs_6axis_config *)
286 param->params.dvs_6axis;
287
288 /*
289 * WORKAROUND:
290 * Because the camera halv3 can't ensure to set zoom
291 * region to per_frame setting and global setting at
292 * same time and only set zoom region to pre_frame
293 * setting now.so when the pre_frame setting include
294 * zoom region,I will set it to global setting.
295 */
296 if (param->params.update_flag.dz_config &&
297 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO
298 && !err) {
299 memcpy(&asd->params.css_param.dz_config,
300 ¶m->params.dz_config,
301 sizeof(struct ia_css_dz_config));
302 asd->params.css_param.update_flag.dz_config =
303 (struct atomisp_dz_config *)
304 &asd->params.css_param.dz_config;
305 asd->params.css_update_params_needed = true;
306 }
307 pipe->frame_params[frame->vb.vb2_buf.index] = NULL;
308 }
309 /* Enqueue buffer */
310 err = atomisp_q_video_buffer_to_css(asd, frame, stream_id,
311 css_buf_type, css_pipe_id);
312 if (err) {
313 spin_lock_irqsave(&pipe->irq_lock, irqflags);
314 list_move_tail(&frame->queue, &pipe->activeq);
315 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
316 dev_err(asd->isp->dev, "%s, css q fails: %d\n",
317 __func__, err);
318 return -EINVAL;
319 }
320
321 /* enqueue 3A/DIS/metadata buffers */
322 if (asd->params.curr_grid_info.s3a_grid.enable &&
323 css_pipe_id == asd->params.s3a_enabled_pipe &&
324 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
325 atomisp_q_one_s3a_buffer(asd, stream_id,
326 css_pipe_id);
327
328 if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
329 metadata_info.size &&
330 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
331 atomisp_q_one_metadata_buffer(asd, stream_id,
332 css_pipe_id);
333
334 if (dvs_grid && dvs_grid->enable &&
335 css_pipe_id == IA_CSS_PIPE_ID_VIDEO &&
336 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
337 atomisp_q_one_dis_buffer(asd, stream_id,
338 css_pipe_id);
339 }
340
341 return 0;
342 }
343
344 /* queue all available buffers to css */
atomisp_qbuffers_to_css(struct atomisp_sub_device * asd)345 int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd)
346 {
347 enum ia_css_pipe_id pipe_id;
348
349 if (asd->copy_mode) {
350 pipe_id = IA_CSS_PIPE_ID_COPY;
351 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
352 pipe_id = IA_CSS_PIPE_ID_VIDEO;
353 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
354 pipe_id = IA_CSS_PIPE_ID_CAPTURE;
355 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
356 pipe_id = IA_CSS_PIPE_ID_VIDEO;
357 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
358 pipe_id = IA_CSS_PIPE_ID_PREVIEW;
359 } else {
360 /* ATOMISP_RUN_MODE_STILL_CAPTURE */
361 pipe_id = IA_CSS_PIPE_ID_CAPTURE;
362 }
363
364 atomisp_q_video_buffers_to_css(asd, &asd->video_out,
365 ATOMISP_INPUT_STREAM_GENERAL,
366 IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, pipe_id);
367 return 0;
368 }
369
atomisp_buf_queue(struct vb2_buffer * vb)370 static void atomisp_buf_queue(struct vb2_buffer *vb)
371 {
372 struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
373 struct ia_css_frame *frame = vb_to_frame(vb);
374 struct atomisp_sub_device *asd = pipe->asd;
375 unsigned long irqflags;
376 int ret;
377
378 mutex_lock(&asd->isp->mutex);
379
380 ret = atomisp_pipe_check(pipe, false);
381 if (ret || pipe->stopping) {
382 spin_lock_irqsave(&pipe->irq_lock, irqflags);
383 atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
384 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
385 goto out_unlock;
386 }
387
388 /* FIXME this ugliness comes from the original atomisp buffer handling */
389 if (!(vb->skip_cache_sync_on_finish && vb->skip_cache_sync_on_prepare))
390 wbinvd();
391
392 pipe->frame_params[vb->index] = NULL;
393
394 spin_lock_irqsave(&pipe->irq_lock, irqflags);
395 /*
396 * when a frame buffer meets following conditions, it should be put into
397 * the waiting list:
398 * 1. It is not a main output frame, and it has a per-frame parameter
399 * to go with it.
400 * 2. It is not a main output frame, and the waiting buffer list is not
401 * empty, to keep the FIFO sequence of frame buffer processing, it
402 * is put to waiting list until previous per-frame parameter buffers
403 * get enqueued.
404 */
405 if (pipe->frame_request_config_id[vb->index] ||
406 !list_empty(&pipe->buffers_waiting_for_param))
407 list_add_tail(&frame->queue, &pipe->buffers_waiting_for_param);
408 else
409 list_add_tail(&frame->queue, &pipe->activeq);
410
411 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
412
413 /* TODO: do this better, not best way to queue to css */
414 if (asd->streaming) {
415 if (!list_empty(&pipe->buffers_waiting_for_param))
416 atomisp_handle_parameter_and_buffer(pipe);
417 else
418 atomisp_qbuffers_to_css(asd);
419 }
420
421 out_unlock:
422 mutex_unlock(&asd->isp->mutex);
423 }
424
atomisp_buf_cleanup(struct vb2_buffer * vb)425 static void atomisp_buf_cleanup(struct vb2_buffer *vb)
426 {
427 struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
428 struct ia_css_frame *frame = vb_to_frame(vb);
429 int index = frame->vb.vb2_buf.index;
430
431 pipe->frame_request_config_id[index] = 0;
432 pipe->frame_params[index] = NULL;
433
434 hmm_free(frame->data);
435 }
436
437 const struct vb2_ops atomisp_vb2_ops = {
438 .queue_setup = atomisp_queue_setup,
439 .buf_init = atomisp_buf_init,
440 .buf_cleanup = atomisp_buf_cleanup,
441 .buf_queue = atomisp_buf_queue,
442 .start_streaming = atomisp_start_streaming,
443 .stop_streaming = atomisp_stop_streaming,
444 .wait_prepare = vb2_ops_wait_prepare,
445 .wait_finish = vb2_ops_wait_finish,
446 };
447
atomisp_dev_init_struct(struct atomisp_device * isp)448 static void atomisp_dev_init_struct(struct atomisp_device *isp)
449 {
450 isp->isp_fatal_error = false;
451
452 /*
453 * For Merrifield, frequency is scalable.
454 * After boot-up, the default frequency is 200MHz.
455 */
456 isp->running_freq = ISP_FREQ_200MHZ;
457 }
458
atomisp_subdev_init_struct(struct atomisp_sub_device * asd)459 static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd)
460 {
461 memset(&asd->params.css_param, 0, sizeof(asd->params.css_param));
462 asd->params.color_effect = V4L2_COLORFX_NONE;
463 asd->params.bad_pixel_en = true;
464 asd->params.gdc_cac_en = false;
465 asd->params.video_dis_en = false;
466 asd->params.sc_en = false;
467 asd->params.fpn_en = false;
468 asd->params.xnr_en = false;
469 asd->params.false_color = 0;
470 asd->params.yuv_ds_en = 0;
471 /* s3a grid not enabled for any pipe */
472 asd->params.s3a_enabled_pipe = IA_CSS_PIPE_ID_NUM;
473
474 asd->copy_mode = false;
475
476 asd->stream_prepared = false;
477 asd->high_speed_mode = false;
478 asd->sensor_array_res.height = 0;
479 asd->sensor_array_res.width = 0;
480 atomisp_css_init_struct(asd);
481 }
482
483 /*
484 * file operation functions
485 */
atomisp_open(struct file * file)486 static int atomisp_open(struct file *file)
487 {
488 struct video_device *vdev = video_devdata(file);
489 struct atomisp_device *isp = video_get_drvdata(vdev);
490 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
491 struct atomisp_sub_device *asd = pipe->asd;
492 int ret;
493
494 dev_dbg(isp->dev, "open device %s\n", vdev->name);
495
496 ret = v4l2_fh_open(file);
497 if (ret)
498 return ret;
499
500 mutex_lock(&isp->mutex);
501
502 if (!isp->input_cnt) {
503 dev_err(isp->dev, "no camera attached\n");
504 ret = -EINVAL;
505 goto error;
506 }
507
508 /*
509 * atomisp does not allow multiple open
510 */
511 if (pipe->users) {
512 dev_dbg(isp->dev, "video node already opened\n");
513 ret = -EBUSY;
514 goto error;
515 }
516
517 /* runtime power management, turn on ISP */
518 ret = pm_runtime_resume_and_get(vdev->v4l2_dev->dev);
519 if (ret < 0) {
520 dev_err(isp->dev, "Failed to power on device\n");
521 goto error;
522 }
523
524 atomisp_dev_init_struct(isp);
525 atomisp_subdev_init_struct(asd);
526
527 pipe->users++;
528 mutex_unlock(&isp->mutex);
529 return 0;
530
531 error:
532 mutex_unlock(&isp->mutex);
533 v4l2_fh_release(file);
534 return ret;
535 }
536
atomisp_release(struct file * file)537 static int atomisp_release(struct file *file)
538 {
539 struct video_device *vdev = video_devdata(file);
540 struct atomisp_device *isp = video_get_drvdata(vdev);
541 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
542 struct atomisp_sub_device *asd = pipe->asd;
543 struct v4l2_subdev_fh fh;
544
545 v4l2_fh_init(&fh.vfh, vdev);
546
547 dev_dbg(isp->dev, "release device %s\n", vdev->name);
548
549 /* Note file must not be used after this! */
550 vb2_fop_release(file);
551
552 mutex_lock(&isp->mutex);
553
554 pipe->users--;
555
556 atomisp_css_free_stat_buffers(asd);
557 atomisp_free_internal_buffers(asd);
558
559 atomisp_s_sensor_power(isp, asd->input_curr, 0);
560
561 atomisp_destroy_pipes_stream(asd);
562
563 if (pm_runtime_put_sync(vdev->v4l2_dev->dev) < 0)
564 dev_err(isp->dev, "Failed to power off device\n");
565
566 mutex_unlock(&isp->mutex);
567 return 0;
568 }
569
570 const struct v4l2_file_operations atomisp_fops = {
571 .owner = THIS_MODULE,
572 .open = atomisp_open,
573 .release = atomisp_release,
574 .mmap = vb2_fop_mmap,
575 .poll = vb2_fop_poll,
576 .unlocked_ioctl = video_ioctl2,
577 #ifdef CONFIG_COMPAT
578 /*
579 * this was removed because of bugs, the interface
580 * needs to be made safe for compat tasks instead.
581 .compat_ioctl32 = atomisp_compat_ioctl32,
582 */
583 #endif
584 };
585