1 // SPDX-License-Identifier: GPL-2.0
3 * Support for Medifield PNW Camera Imaging ISP subsystem.
5 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/module.h>
19 #include <linux/uaccess.h>
20 #include <linux/delay.h>
21 #include <linux/device.h>
23 #include <linux/sched.h>
24 #include <linux/slab.h>
26 #include <media/v4l2-event.h>
27 #include <media/v4l2-mediabus.h>
28 #include <media/videobuf2-vmalloc.h>
29 #include "atomisp_cmd.h"
30 #include "atomisp_common.h"
31 #include "atomisp_compat.h"
32 #include "atomisp_fops.h"
33 #include "atomisp_internal.h"
35 const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
36 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_BGGR },
37 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GBRG },
38 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GRBG },
39 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_RGGB },
40 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_BGGR },
41 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GBRG },
42 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GRBG },
43 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_RGGB },
44 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_BGGR },
45 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GBRG },
46 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GRBG },
47 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_RGGB },
48 { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 },
49 { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 },
50 #if 0 // disabled due to clang warnings
51 { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
52 { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, IA_CSS_FRAME_FORMAT_NV12, 0 },
53 { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, IA_CSS_FRAME_FORMAT_NV21, 0 },
55 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0 },
57 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
59 /* no valid V4L2 MBUS code for metadata format, so leave it 0. */
60 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0 },
67 } compressed_codes[] = {
68 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
69 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
70 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
71 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
74 u32 atomisp_subdev_uncompressed_code(u32 code)
78 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++)
79 if (code == compressed_codes[i].compressed)
80 return compressed_codes[i].code;
85 bool atomisp_subdev_is_compressed(u32 code)
89 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
90 if (code == atomisp_in_fmt_conv[i].code)
91 return atomisp_in_fmt_conv[i].bpp !=
92 atomisp_in_fmt_conv[i].depth;
97 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code)
101 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
102 if (code == atomisp_in_fmt_conv[i].code)
103 return atomisp_in_fmt_conv + i;
108 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
109 enum atomisp_input_format atomisp_in_fmt)
113 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
114 if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt)
115 return atomisp_in_fmt_conv + i;
120 bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd,
121 unsigned int source_pad)
123 struct v4l2_mbus_framefmt *sink, *src;
125 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
126 V4L2_SUBDEV_FORMAT_ACTIVE,
127 ATOMISP_SUBDEV_PAD_SINK);
128 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
129 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad);
131 return atomisp_is_mbuscode_raw(sink->code)
132 && !atomisp_is_mbuscode_raw(src->code);
135 uint16_t atomisp_subdev_source_pad(struct video_device *vdev)
137 struct media_link *link;
140 list_for_each_entry(link, &vdev->entity.links, list) {
142 ret = link->source->index;
150 * V4L2 subdev operations
154 * isp_subdev_ioctl - CCDC module private ioctl's
155 * @sd: ISP V4L2 subdevice
156 * @cmd: ioctl command
157 * @arg: ioctl argument
159 * Return 0 on success or a negative error code otherwise.
161 static long isp_subdev_ioctl(struct v4l2_subdev *sd,
162 unsigned int cmd, void *arg)
168 * isp_subdev_set_power - Power on/off the CCDC module
169 * @sd: ISP V4L2 subdevice
172 * Return 0 on success or a negative error code otherwise.
174 static int isp_subdev_set_power(struct v4l2_subdev *sd, int on)
179 static int isp_subdev_subscribe_event(struct v4l2_subdev *sd,
181 struct v4l2_event_subscription *sub)
183 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
184 struct atomisp_device *isp = isp_sd->isp;
186 if (sub->type != V4L2_EVENT_FRAME_SYNC &&
187 sub->type != V4L2_EVENT_FRAME_END &&
188 sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY &&
189 sub->type != V4L2_EVENT_ATOMISP_METADATA_READY &&
190 sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER &&
191 sub->type != V4L2_EVENT_ATOMISP_CSS_RESET &&
192 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE)
195 if (sub->type == V4L2_EVENT_FRAME_SYNC &&
196 !atomisp_css_valid_sof(isp))
199 return v4l2_event_subscribe(fh, sub, 16, NULL);
202 static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
204 struct v4l2_event_subscription *sub)
206 return v4l2_event_unsubscribe(fh, sub);
210 * isp_subdev_enum_mbus_code - Handle pixel format enumeration
211 * @sd: pointer to v4l2 subdev structure
212 * @fh : V4L2 subdev file handle
213 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure
214 * return -EINVAL or zero on success
216 static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
217 struct v4l2_subdev_state *sd_state,
218 struct v4l2_subdev_mbus_code_enum *code)
220 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
223 code->code = atomisp_in_fmt_conv[code->index].code;
228 static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
232 case ATOMISP_SUBDEV_PAD_SINK:
234 case V4L2_SEL_TGT_CROP:
240 case V4L2_SEL_TGT_COMPOSE:
249 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
250 struct v4l2_subdev_state *sd_state,
251 u32 which, uint32_t pad,
254 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
256 if (which == V4L2_SUBDEV_FORMAT_TRY) {
258 case V4L2_SEL_TGT_CROP:
259 return v4l2_subdev_get_try_crop(sd, sd_state, pad);
260 case V4L2_SEL_TGT_COMPOSE:
261 return v4l2_subdev_get_try_compose(sd, sd_state, pad);
266 case V4L2_SEL_TGT_CROP:
267 return &isp_sd->fmt[pad].crop;
268 case V4L2_SEL_TGT_COMPOSE:
269 return &isp_sd->fmt[pad].compose;
275 struct v4l2_mbus_framefmt
276 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
277 struct v4l2_subdev_state *sd_state, uint32_t which,
280 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
282 if (which == V4L2_SUBDEV_FORMAT_TRY)
283 return v4l2_subdev_get_try_format(sd, sd_state, pad);
285 return &isp_sd->fmt[pad].fmt;
288 static void isp_get_fmt_rect(struct v4l2_subdev *sd,
289 struct v4l2_subdev_state *sd_state,
291 struct v4l2_mbus_framefmt **ffmt,
292 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
293 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
297 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
298 ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i);
299 crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
301 comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
302 V4L2_SEL_TGT_COMPOSE);
306 static void isp_subdev_propagate(struct v4l2_subdev *sd,
307 struct v4l2_subdev_state *sd_state,
308 u32 which, uint32_t pad, uint32_t target,
311 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
312 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
313 *comp[ATOMISP_SUBDEV_PADS_NUM];
315 if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
318 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
321 case ATOMISP_SUBDEV_PAD_SINK: {
322 struct v4l2_rect r = {0};
324 /* Only crop target supported on sink pad. */
325 r.width = ffmt[pad]->width;
326 r.height = ffmt[pad]->height;
328 atomisp_subdev_set_selection(sd, sd_state, which, pad,
335 static int isp_subdev_get_selection(struct v4l2_subdev *sd,
336 struct v4l2_subdev_state *sd_state,
337 struct v4l2_subdev_selection *sel)
339 struct v4l2_rect *rec;
340 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
345 rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad,
354 static const char *atomisp_pad_str(unsigned int pad)
356 static const char *const pad_str[] = {
357 "ATOMISP_SUBDEV_PAD_SINK",
358 "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
359 "ATOMISP_SUBDEV_PAD_SOURCE_VF",
360 "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
361 "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO",
364 if (pad >= ARRAY_SIZE(pad_str))
365 return "ATOMISP_INVALID_PAD";
369 int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
370 struct v4l2_subdev_state *sd_state,
371 u32 which, uint32_t pad, uint32_t target,
372 u32 flags, struct v4l2_rect *r)
374 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
375 struct atomisp_device *isp = isp_sd->isp;
376 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
377 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
378 *comp[ATOMISP_SUBDEV_PADS_NUM];
380 unsigned int padding_w = pad_w;
381 unsigned int padding_h = pad_h;
383 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
386 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
387 atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP
388 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
389 r->left, r->top, r->width, r->height,
390 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
391 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags);
393 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH);
394 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT);
397 case ATOMISP_SUBDEV_PAD_SINK: {
398 /* Only crop target supported on sink pad. */
399 unsigned int dvs_w, dvs_h;
401 crop[pad]->width = ffmt[pad]->width;
402 crop[pad]->height = ffmt[pad]->height;
404 /* Workaround for BYT 1080p perfectshot since the maxinum resolution of
405 * front camera ov2722 is 1932x1092 and cannot use pad_w > 12*/
406 if (!strncmp(isp->inputs[isp_sd->input_curr].camera->name,
407 "ov2722", 6) && crop[pad]->height == 1092) {
412 if (atomisp_subdev_format_conversion(isp_sd,
414 && crop[pad]->width && crop[pad]->height) {
415 crop[pad]->width -= padding_w;
416 crop[pad]->height -= padding_h;
419 if (isp_sd->params.video_dis_en &&
420 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
421 /* This resolution contains 20 % of DVS slack
422 * (of the desired captured image before
423 * scaling, or 1 / 6 of what we get from the
424 * sensor) in both width and height. Remove
426 crop[pad]->width = roundup(crop[pad]->width * 5 / 6,
427 ATOM_ISP_STEP_WIDTH);
428 crop[pad]->height = roundup(crop[pad]->height * 5 / 6,
429 ATOM_ISP_STEP_HEIGHT);
432 crop[pad]->width = min(crop[pad]->width, r->width);
433 crop[pad]->height = min(crop[pad]->height, r->height);
435 if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) {
436 for (i = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE;
437 i < ATOMISP_SUBDEV_PADS_NUM; i++) {
438 struct v4l2_rect tmp = *crop[pad];
440 atomisp_subdev_set_selection(
441 sd, sd_state, which, i,
442 V4L2_SEL_TGT_COMPOSE,
447 if (which == V4L2_SUBDEV_FORMAT_TRY)
450 if (isp_sd->params.video_dis_en &&
451 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
452 dvs_w = rounddown(crop[pad]->width / 5,
453 ATOM_ISP_STEP_WIDTH);
454 dvs_h = rounddown(crop[pad]->height / 5,
455 ATOM_ISP_STEP_HEIGHT);
456 } else if (!isp_sd->params.video_dis_en &&
457 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
459 * For CSS2.0, digital zoom needs to set dvs envelope to 12
460 * when dvs is disabled.
466 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
467 atomisp_css_input_set_effective_resolution(isp_sd,
468 ATOMISP_INPUT_STREAM_GENERAL,
473 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
474 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: {
475 /* Only compose target is supported on source pads. */
477 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
478 /* Scaling is disabled in this mode */
479 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width;
480 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height;
483 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width
484 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height)
485 isp_sd->params.yuv_ds_en = false;
487 isp_sd->params.yuv_ds_en = true;
489 comp[pad]->width = r->width;
490 comp[pad]->height = r->height;
492 if (r->width == 0 || r->height == 0 ||
493 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 ||
494 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0)
497 * do cropping on sensor input if ratio of required resolution
498 * is different with sensor output resolution ratio:
500 * ratio = width / height
502 * if ratio_output < ratio_sensor:
503 * effect_width = sensor_height * out_width / out_height;
504 * effect_height = sensor_height;
506 * effect_width = sensor_width;
507 * effect_height = sensor_width * out_height / out_width;
510 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height <
511 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height)
512 atomisp_css_input_set_effective_resolution(isp_sd,
513 ATOMISP_INPUT_STREAM_GENERAL,
514 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
515 height * r->width / r->height,
516 ATOM_ISP_STEP_WIDTH),
517 crop[ATOMISP_SUBDEV_PAD_SINK]->height);
519 atomisp_css_input_set_effective_resolution(isp_sd,
520 ATOMISP_INPUT_STREAM_GENERAL,
521 crop[ATOMISP_SUBDEV_PAD_SINK]->width,
522 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
523 width * r->height / r->width,
524 ATOM_ISP_STEP_WIDTH));
528 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
529 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
530 comp[pad]->width = r->width;
531 comp[pad]->height = r->height;
537 /* Set format dimensions on non-sink pads as well. */
538 if (pad != ATOMISP_SUBDEV_PAD_SINK) {
539 ffmt[pad]->width = comp[pad]->width;
540 ffmt[pad]->height = comp[pad]->height;
543 if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target))
545 *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target);
547 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
548 r->left, r->top, r->width, r->height);
553 static int isp_subdev_set_selection(struct v4l2_subdev *sd,
554 struct v4l2_subdev_state *sd_state,
555 struct v4l2_subdev_selection *sel)
557 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
562 return atomisp_subdev_set_selection(sd, sd_state, sel->which,
564 sel->target, sel->flags, &sel->r);
567 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
568 struct v4l2_subdev_state *sd_state,
570 u32 pad, struct v4l2_mbus_framefmt *ffmt)
572 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
573 struct atomisp_device *isp = isp_sd->isp;
574 struct v4l2_mbus_framefmt *__ffmt =
575 atomisp_subdev_get_ffmt(sd, sd_state, which, pad);
577 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
578 atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code,
579 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
580 : "V4L2_SUBDEV_FORMAT_ACTIVE");
583 case ATOMISP_SUBDEV_PAD_SINK: {
584 const struct atomisp_in_fmt_conv *fc =
585 atomisp_find_in_fmt_conv(ffmt->code);
588 fc = atomisp_in_fmt_conv;
589 ffmt->code = fc->code;
590 dev_dbg(isp->dev, "using 0x%8.8x instead\n",
596 isp_subdev_propagate(sd, sd_state, which, pad,
597 V4L2_SEL_TGT_CROP, 0);
599 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
600 atomisp_css_input_set_resolution(isp_sd,
601 ATOMISP_INPUT_STREAM_GENERAL, ffmt);
602 atomisp_css_input_set_binning_factor(isp_sd,
603 ATOMISP_INPUT_STREAM_GENERAL,
605 atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
607 atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
609 atomisp_css_set_default_isys_config(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
615 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
616 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
617 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
618 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
619 __ffmt->code = ffmt->code;
625 * isp_subdev_get_format - Retrieve the video format on a pad
626 * @sd : ISP V4L2 subdevice
627 * @fh : V4L2 subdev file handle
631 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
632 * to the format type.
634 static int isp_subdev_get_format(struct v4l2_subdev *sd,
635 struct v4l2_subdev_state *sd_state,
636 struct v4l2_subdev_format *fmt)
638 fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which,
645 * isp_subdev_set_format - Set the video format on a pad
646 * @sd : ISP subdev V4L2 subdevice
647 * @fh : V4L2 subdev file handle
651 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
652 * to the format type.
654 static int isp_subdev_set_format(struct v4l2_subdev *sd,
655 struct v4l2_subdev_state *sd_state,
656 struct v4l2_subdev_format *fmt)
658 atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
664 /* V4L2 subdev core operations */
665 static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = {
666 .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power,
667 .subscribe_event = isp_subdev_subscribe_event,
668 .unsubscribe_event = isp_subdev_unsubscribe_event,
671 /* V4L2 subdev pad operations */
672 static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = {
673 .enum_mbus_code = isp_subdev_enum_mbus_code,
674 .get_fmt = isp_subdev_get_format,
675 .set_fmt = isp_subdev_set_format,
676 .get_selection = isp_subdev_get_selection,
677 .set_selection = isp_subdev_set_selection,
678 .link_validate = v4l2_subdev_link_validate_default,
681 /* V4L2 subdev operations */
682 static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = {
683 .core = &isp_subdev_v4l2_core_ops,
684 .pad = &isp_subdev_v4l2_pad_ops,
687 static void isp_subdev_init_params(struct atomisp_sub_device *asd)
691 /* parameters initialization */
692 INIT_LIST_HEAD(&asd->s3a_stats);
693 INIT_LIST_HEAD(&asd->s3a_stats_in_css);
694 INIT_LIST_HEAD(&asd->s3a_stats_ready);
695 INIT_LIST_HEAD(&asd->dis_stats);
696 INIT_LIST_HEAD(&asd->dis_stats_in_css);
697 spin_lock_init(&asd->dis_stats_lock);
698 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
699 INIT_LIST_HEAD(&asd->metadata[i]);
700 INIT_LIST_HEAD(&asd->metadata_in_css[i]);
701 INIT_LIST_HEAD(&asd->metadata_ready[i]);
705 /* media operations */
706 static const struct media_entity_operations isp_subdev_media_ops = {
707 .link_validate = v4l2_subdev_link_validate,
708 /* .set_power = v4l2_subdev_set_power, */
711 static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
713 struct atomisp_device *isp = asd->isp;
714 struct v4l2_ctrl *ctrl = asd->run_mode;
721 isp->inputs[asd->input_curr].camera->ctrl_handler,
725 return v4l2_ctrl_s_ctrl(c, mode);
730 int atomisp_update_run_mode(struct atomisp_sub_device *asd)
734 mutex_lock(asd->ctrl_handler.lock);
735 rval = __atomisp_update_run_mode(asd);
736 mutex_unlock(asd->ctrl_handler.lock);
741 static int s_ctrl(struct v4l2_ctrl *ctrl)
743 struct atomisp_sub_device *asd = container_of(
744 ctrl->handler, struct atomisp_sub_device, ctrl_handler);
746 case V4L2_CID_RUN_MODE:
747 return __atomisp_update_run_mode(asd);
753 static const struct v4l2_ctrl_ops ctrl_ops = {
757 static const char *const ctrl_run_mode_menu[] = {
761 "Continuous capture",
765 static const struct v4l2_ctrl_config ctrl_run_mode = {
767 .id = V4L2_CID_RUN_MODE,
768 .name = "Atomisp run mode",
769 .type = V4L2_CTRL_TYPE_MENU,
773 .qmenu = ctrl_run_mode_menu,
776 static const char *const ctrl_vfpp_mode_menu[] = {
777 "Enable", /* vfpp always enabled */
778 "Disable to scaler mode", /* CSS into video mode and disable */
779 "Disable to low latency mode", /* CSS into still mode and disable */
782 static const struct v4l2_ctrl_config ctrl_vfpp = {
784 .name = "Atomisp vf postprocess",
785 .type = V4L2_CTRL_TYPE_MENU,
789 .qmenu = ctrl_vfpp_mode_menu,
793 * Control for continuous mode raw buffer size
795 * The size of the RAW ringbuffer sets limit on how much
796 * back in time application can go when requesting capture
797 * frames to be rendered, and how many frames can be rendered
798 * in a burst at full sensor rate.
800 * Note: this setting has a big impact on memory consumption of
803 static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = {
805 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE,
806 .type = V4L2_CTRL_TYPE_INTEGER,
807 .name = "Continuous raw ringbuffer size",
809 .max = 100, /* depends on CSS version, runtime checked */
815 * Control for enabling continuous viewfinder
817 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ),
818 * preview pipeline continues concurrently with capture
819 * processing. When disabled, and continuous mode is used,
820 * preview is paused while captures are processed, but
821 * full pipeline restart is not needed.
823 * By setting this to disabled, capture processing is
824 * essentially given priority over preview, and the effective
825 * capture output rate may be higher than with continuous
826 * viewfinder enabled.
828 static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = {
829 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER,
830 .type = V4L2_CTRL_TYPE_BOOLEAN,
831 .name = "Continuous viewfinder",
839 * Control for enabling Lock&Unlock Raw Buffer mechanism
841 * When enabled, Raw Buffer can be locked and unlocked.
842 * Application can hold the exp_id of Raw Buffer
843 * and unlock it when no longer needed.
844 * Note: Make sure set this configuration before creating stream.
846 static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = {
847 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK,
848 .type = V4L2_CTRL_TYPE_BOOLEAN,
849 .name = "Lock Unlock Raw Buffer",
857 * Control to disable digital zoom of the whole stream
859 * When it is true, pipe configuration enable_dz will be set to false.
860 * This can help get a better performance by disabling pp binary.
862 * Note: Make sure set this configuration before creating stream.
864 static const struct v4l2_ctrl_config ctrl_disable_dz = {
865 .id = V4L2_CID_DISABLE_DZ,
866 .type = V4L2_CTRL_TYPE_BOOLEAN,
867 .name = "Disable digital zoom",
874 static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
875 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
879 pipe->type = buf_type;
881 pipe->isp = asd->isp;
882 spin_lock_init(&pipe->irq_lock);
883 mutex_init(&pipe->vb_queue_mutex);
885 /* Init videobuf2 queue structure */
886 pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
887 pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
888 pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
889 pipe->vb_queue.ops = &atomisp_vb2_ops;
890 pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
891 pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
892 ret = vb2_queue_init(&pipe->vb_queue);
896 pipe->vdev.queue = &pipe->vb_queue;
897 pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
899 INIT_LIST_HEAD(&pipe->buffers_in_css);
900 INIT_LIST_HEAD(&pipe->activeq);
901 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
902 INIT_LIST_HEAD(&pipe->per_frame_params);
908 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
909 * @asd: ISP CCDC module
911 * Return 0 on success and a negative error code on failure.
913 static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
915 struct v4l2_subdev *sd = &asd->subdev;
916 struct media_pad *pads = asd->pads;
917 struct media_entity *me = &sd->entity;
920 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
921 sprintf(sd->name, "ATOMISP_SUBDEV");
922 v4l2_set_subdevdata(sd, asd);
923 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
925 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
926 pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE;
927 pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
928 pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE;
929 pads[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
931 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code =
932 MEDIA_BUS_FMT_SBGGR10_1X10;
933 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code =
934 MEDIA_BUS_FMT_SBGGR10_1X10;
935 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code =
936 MEDIA_BUS_FMT_SBGGR10_1X10;
937 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code =
938 MEDIA_BUS_FMT_SBGGR10_1X10;
939 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].fmt.code =
940 MEDIA_BUS_FMT_SBGGR10_1X10;
942 me->ops = &isp_subdev_media_ops;
943 me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
944 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
948 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
949 V4L2_BUF_TYPE_VIDEO_CAPTURE);
953 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
954 V4L2_BUF_TYPE_VIDEO_CAPTURE);
958 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
959 V4L2_BUF_TYPE_VIDEO_CAPTURE);
963 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
964 V4L2_BUF_TYPE_VIDEO_CAPTURE);
968 ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE",
969 ATOMISP_RUN_MODE_STILL_CAPTURE);
973 ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER",
974 ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE);
978 ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW",
979 ATOMISP_RUN_MODE_PREVIEW);
983 ret = atomisp_video_init(&asd->video_out_video_capture, "VIDEO",
984 ATOMISP_RUN_MODE_VIDEO);
988 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
992 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
993 &ctrl_run_mode, NULL);
994 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
996 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
997 &ctrl_continuous_viewfinder,
999 asd->continuous_raw_buffer_size =
1000 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1001 &ctrl_continuous_raw_buffer_size,
1004 asd->enable_raw_buffer_lock =
1005 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1006 &ctrl_enable_raw_buffer_lock,
1009 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1013 /* Make controls visible on subdev as well. */
1014 asd->subdev.ctrl_handler = &asd->ctrl_handler;
1015 spin_lock_init(&asd->raw_buffer_bitmap_lock);
1016 return asd->ctrl_handler.error;
1019 int atomisp_create_pads_links(struct atomisp_device *isp)
1023 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
1024 ret = media_create_pad_link(&isp->csi2_port[i].subdev.entity,
1025 CSI2_PAD_SOURCE, &isp->asd.subdev.entity,
1026 ATOMISP_SUBDEV_PAD_SINK, 0);
1031 for (i = 0; i < isp->input_cnt; i++) {
1032 /* Don't create links for the test-pattern-generator */
1033 if (isp->inputs[i].type == TEST_PATTERN)
1036 ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0,
1037 &isp->csi2_port[isp->inputs[i].
1038 port].subdev.entity,
1040 MEDIA_LNK_FL_ENABLED |
1041 MEDIA_LNK_FL_IMMUTABLE);
1046 ret = media_create_pad_link(&isp->asd.subdev.entity,
1047 ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW,
1048 &isp->asd.video_out_preview.vdev.entity, 0, 0);
1051 ret = media_create_pad_link(&isp->asd.subdev.entity,
1052 ATOMISP_SUBDEV_PAD_SOURCE_VF,
1053 &isp->asd.video_out_vf.vdev.entity, 0, 0);
1056 ret = media_create_pad_link(&isp->asd.subdev.entity,
1057 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
1058 &isp->asd.video_out_capture.vdev.entity, 0, 0);
1061 ret = media_create_pad_link(&isp->asd.subdev.entity,
1062 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
1063 &isp->asd.video_out_video_capture.vdev.entity, 0, 0);
1070 static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd)
1072 v4l2_ctrl_handler_free(&asd->ctrl_handler);
1074 media_entity_cleanup(&asd->subdev.entity);
1077 void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd)
1079 struct v4l2_fh *fh, *fh_tmp;
1080 struct v4l2_event event;
1081 unsigned int i, pending_event;
1083 list_for_each_entry_safe(fh, fh_tmp,
1084 &asd->subdev.devnode->fh_list, list) {
1085 pending_event = v4l2_event_pending(fh);
1086 for (i = 0; i < pending_event; i++)
1087 v4l2_event_dequeue(fh, &event, 1);
1091 void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd)
1093 atomisp_subdev_cleanup_entities(asd);
1094 v4l2_device_unregister_subdev(&asd->subdev);
1095 atomisp_video_unregister(&asd->video_out_preview);
1096 atomisp_video_unregister(&asd->video_out_vf);
1097 atomisp_video_unregister(&asd->video_out_capture);
1098 atomisp_video_unregister(&asd->video_out_video_capture);
1101 int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd,
1102 struct v4l2_device *vdev)
1104 return v4l2_device_register_subdev(vdev, &asd->subdev);
1107 int atomisp_subdev_register_video_nodes(struct atomisp_sub_device *asd,
1108 struct v4l2_device *vdev)
1113 * FIXME: check if all device caps are properly initialized.
1114 * Should any of those use V4L2_CAP_META_CAPTURE? Probably yes.
1117 asd->video_out_preview.vdev.v4l2_dev = vdev;
1118 asd->video_out_preview.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1119 ret = video_register_device(&asd->video_out_preview.vdev,
1120 VFL_TYPE_VIDEO, -1);
1124 asd->video_out_capture.vdev.v4l2_dev = vdev;
1125 asd->video_out_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1126 ret = video_register_device(&asd->video_out_capture.vdev,
1127 VFL_TYPE_VIDEO, -1);
1131 asd->video_out_vf.vdev.v4l2_dev = vdev;
1132 asd->video_out_vf.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1133 ret = video_register_device(&asd->video_out_vf.vdev,
1134 VFL_TYPE_VIDEO, -1);
1138 asd->video_out_video_capture.vdev.v4l2_dev = vdev;
1139 asd->video_out_video_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1140 ret = video_register_device(&asd->video_out_video_capture.vdev,
1141 VFL_TYPE_VIDEO, -1);
1148 atomisp_subdev_unregister_entities(asd);
1153 * atomisp_subdev_init - ISP Subdevice initialization.
1154 * @dev: Device pointer specific to the ATOM ISP.
1156 * TODO: Get the initialisation values from platform data.
1158 * Return 0 on success or a negative error code otherwise.
1160 int atomisp_subdev_init(struct atomisp_device *isp)
1165 isp_subdev_init_params(&isp->asd);
1166 ret = isp_subdev_init_entities(&isp->asd);
1168 atomisp_subdev_cleanup_entities(&isp->asd);