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