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 * 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.
10 *
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.
15 *
16 *
17 */
18 #include <linux/module.h>
19 #include <linux/uaccess.h>
20 #include <linux/delay.h>
21 #include <linux/device.h>
22 #include <linux/mm.h>
23 #include <linux/sched.h>
24 #include <linux/slab.h>
25
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"
34
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 },
54 #endif
55 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0 },
56 #if 0
57 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
58 #endif
59 /* no valid V4L2 MBUS code for metadata format, so leave it 0. */
60 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0 },
61 {}
62 };
63
64 static const struct {
65 u32 code;
66 u32 compressed;
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 },
72 };
73
atomisp_subdev_uncompressed_code(u32 code)74 u32 atomisp_subdev_uncompressed_code(u32 code)
75 {
76 unsigned int i;
77
78 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++)
79 if (code == compressed_codes[i].compressed)
80 return compressed_codes[i].code;
81
82 return code;
83 }
84
atomisp_subdev_is_compressed(u32 code)85 bool atomisp_subdev_is_compressed(u32 code)
86 {
87 int i;
88
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;
93
94 return false;
95 }
96
atomisp_find_in_fmt_conv(u32 code)97 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code)
98 {
99 int i;
100
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;
104
105 return NULL;
106 }
107
atomisp_find_in_fmt_conv_by_atomisp_in_fmt(enum atomisp_input_format atomisp_in_fmt)108 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
109 enum atomisp_input_format atomisp_in_fmt)
110 {
111 int i;
112
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;
116
117 return NULL;
118 }
119
atomisp_subdev_format_conversion(struct atomisp_sub_device * asd,unsigned int source_pad)120 bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd,
121 unsigned int source_pad)
122 {
123 struct v4l2_mbus_framefmt *sink, *src;
124
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);
130
131 return atomisp_is_mbuscode_raw(sink->code)
132 && !atomisp_is_mbuscode_raw(src->code);
133 }
134
atomisp_subdev_source_pad(struct video_device * vdev)135 uint16_t atomisp_subdev_source_pad(struct video_device *vdev)
136 {
137 struct media_link *link;
138 u16 ret = 0;
139
140 list_for_each_entry(link, &vdev->entity.links, list) {
141 if (link->source) {
142 ret = link->source->index;
143 break;
144 }
145 }
146 return ret;
147 }
148
149 /*
150 * V4L2 subdev operations
151 */
152
153 /*
154 * isp_subdev_ioctl - CCDC module private ioctl's
155 * @sd: ISP V4L2 subdevice
156 * @cmd: ioctl command
157 * @arg: ioctl argument
158 *
159 * Return 0 on success or a negative error code otherwise.
160 */
isp_subdev_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)161 static long isp_subdev_ioctl(struct v4l2_subdev *sd,
162 unsigned int cmd, void *arg)
163 {
164 return 0;
165 }
166
167 /*
168 * isp_subdev_set_power - Power on/off the CCDC module
169 * @sd: ISP V4L2 subdevice
170 * @on: power on/off
171 *
172 * Return 0 on success or a negative error code otherwise.
173 */
isp_subdev_set_power(struct v4l2_subdev * sd,int on)174 static int isp_subdev_set_power(struct v4l2_subdev *sd, int on)
175 {
176 return 0;
177 }
178
isp_subdev_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)179 static int isp_subdev_subscribe_event(struct v4l2_subdev *sd,
180 struct v4l2_fh *fh,
181 struct v4l2_event_subscription *sub)
182 {
183 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
184 struct atomisp_device *isp = isp_sd->isp;
185
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_RAW_BUFFERS_ALLOC_DONE &&
193 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE)
194 return -EINVAL;
195
196 if (sub->type == V4L2_EVENT_FRAME_SYNC &&
197 !atomisp_css_valid_sof(isp))
198 return -EINVAL;
199
200 return v4l2_event_subscribe(fh, sub, 16, NULL);
201 }
202
isp_subdev_unsubscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)203 static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
204 struct v4l2_fh *fh,
205 struct v4l2_event_subscription *sub)
206 {
207 return v4l2_event_unsubscribe(fh, sub);
208 }
209
210 /*
211 * isp_subdev_enum_mbus_code - Handle pixel format enumeration
212 * @sd: pointer to v4l2 subdev structure
213 * @fh : V4L2 subdev file handle
214 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure
215 * return -EINVAL or zero on success
216 */
isp_subdev_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)217 static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
218 struct v4l2_subdev_state *sd_state,
219 struct v4l2_subdev_mbus_code_enum *code)
220 {
221 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
222 return -EINVAL;
223
224 code->code = atomisp_in_fmt_conv[code->index].code;
225
226 return 0;
227 }
228
isp_subdev_validate_rect(struct v4l2_subdev * sd,uint32_t pad,uint32_t target)229 static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
230 uint32_t target)
231 {
232 switch (pad) {
233 case ATOMISP_SUBDEV_PAD_SINK:
234 switch (target) {
235 case V4L2_SEL_TGT_CROP:
236 return 0;
237 }
238 break;
239 default:
240 switch (target) {
241 case V4L2_SEL_TGT_COMPOSE:
242 return 0;
243 }
244 break;
245 }
246
247 return -EINVAL;
248 }
249
atomisp_subdev_get_rect(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,u32 which,uint32_t pad,uint32_t target)250 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
251 struct v4l2_subdev_state *sd_state,
252 u32 which, uint32_t pad,
253 uint32_t target)
254 {
255 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
256
257 if (which == V4L2_SUBDEV_FORMAT_TRY) {
258 switch (target) {
259 case V4L2_SEL_TGT_CROP:
260 return v4l2_subdev_get_try_crop(sd, sd_state, pad);
261 case V4L2_SEL_TGT_COMPOSE:
262 return v4l2_subdev_get_try_compose(sd, sd_state, pad);
263 }
264 }
265
266 switch (target) {
267 case V4L2_SEL_TGT_CROP:
268 return &isp_sd->fmt[pad].crop;
269 case V4L2_SEL_TGT_COMPOSE:
270 return &isp_sd->fmt[pad].compose;
271 }
272
273 return NULL;
274 }
275
276 struct v4l2_mbus_framefmt
atomisp_subdev_get_ffmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,uint32_t which,uint32_t pad)277 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
278 struct v4l2_subdev_state *sd_state, uint32_t which,
279 uint32_t pad)
280 {
281 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
282
283 if (which == V4L2_SUBDEV_FORMAT_TRY)
284 return v4l2_subdev_get_try_format(sd, sd_state, pad);
285
286 return &isp_sd->fmt[pad].fmt;
287 }
288
isp_get_fmt_rect(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,uint32_t which,struct v4l2_mbus_framefmt ** ffmt,struct v4l2_rect * crop[ATOMISP_SUBDEV_PADS_NUM],struct v4l2_rect * comp[ATOMISP_SUBDEV_PADS_NUM])289 static void isp_get_fmt_rect(struct v4l2_subdev *sd,
290 struct v4l2_subdev_state *sd_state,
291 uint32_t which,
292 struct v4l2_mbus_framefmt **ffmt,
293 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
294 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
295 {
296 unsigned int i;
297
298 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
299 ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i);
300 crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
301 V4L2_SEL_TGT_CROP);
302 comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
303 V4L2_SEL_TGT_COMPOSE);
304 }
305 }
306
isp_subdev_propagate(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,u32 which,uint32_t pad,uint32_t target,uint32_t flags)307 static void isp_subdev_propagate(struct v4l2_subdev *sd,
308 struct v4l2_subdev_state *sd_state,
309 u32 which, uint32_t pad, uint32_t target,
310 uint32_t flags)
311 {
312 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
313 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
314 *comp[ATOMISP_SUBDEV_PADS_NUM];
315
316 if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
317 return;
318
319 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
320
321 switch (pad) {
322 case ATOMISP_SUBDEV_PAD_SINK: {
323 struct v4l2_rect r = {0};
324
325 /* Only crop target supported on sink pad. */
326 r.width = ffmt[pad]->width;
327 r.height = ffmt[pad]->height;
328
329 atomisp_subdev_set_selection(sd, sd_state, which, pad,
330 target, flags, &r);
331 break;
332 }
333 }
334 }
335
isp_subdev_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)336 static int isp_subdev_get_selection(struct v4l2_subdev *sd,
337 struct v4l2_subdev_state *sd_state,
338 struct v4l2_subdev_selection *sel)
339 {
340 struct v4l2_rect *rec;
341 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
342
343 if (rval)
344 return rval;
345
346 rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad,
347 sel->target);
348 if (!rec)
349 return -EINVAL;
350
351 sel->r = *rec;
352 return 0;
353 }
354
atomisp_pad_str(unsigned int pad)355 static const char *atomisp_pad_str(unsigned int pad)
356 {
357 static const char *const pad_str[] = {
358 "ATOMISP_SUBDEV_PAD_SINK",
359 "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
360 "ATOMISP_SUBDEV_PAD_SOURCE_VF",
361 "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
362 "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO",
363 };
364
365 if (pad >= ARRAY_SIZE(pad_str))
366 return "ATOMISP_INVALID_PAD";
367 return pad_str[pad];
368 }
369
atomisp_subdev_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,u32 which,uint32_t pad,uint32_t target,u32 flags,struct v4l2_rect * r)370 int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
371 struct v4l2_subdev_state *sd_state,
372 u32 which, uint32_t pad, uint32_t target,
373 u32 flags, struct v4l2_rect *r)
374 {
375 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
376 struct atomisp_device *isp = isp_sd->isp;
377 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
378 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
379 *comp[ATOMISP_SUBDEV_PADS_NUM];
380 unsigned int i;
381 unsigned int padding_w = pad_w;
382 unsigned int padding_h = pad_h;
383
384 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
385
386 dev_dbg(isp->dev,
387 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
388 atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP
389 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
390 r->left, r->top, r->width, r->height,
391 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
392 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags);
393
394 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH);
395 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT);
396
397 switch (pad) {
398 case ATOMISP_SUBDEV_PAD_SINK: {
399 /* Only crop target supported on sink pad. */
400 unsigned int dvs_w, dvs_h;
401
402 crop[pad]->width = ffmt[pad]->width;
403 crop[pad]->height = ffmt[pad]->height;
404
405 /* Workaround for BYT 1080p perfectshot since the maxinum resolution of
406 * front camera ov2722 is 1932x1092 and cannot use pad_w > 12*/
407 if (!strncmp(isp->inputs[isp_sd->input_curr].camera->name,
408 "ov2722", 6) && crop[pad]->height == 1092) {
409 padding_w = 12;
410 padding_h = 12;
411 }
412
413 if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA) {
414 padding_w = 0;
415 padding_h = 0;
416 }
417
418 if (atomisp_subdev_format_conversion(isp_sd,
419 isp_sd->capture_pad)
420 && crop[pad]->width && crop[pad]->height) {
421 crop[pad]->width -= padding_w;
422 crop[pad]->height -= padding_h;
423 }
424
425 /* if subdev type is SOC camera,we do not need to set DVS */
426 if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA)
427 isp_sd->params.video_dis_en = 0;
428
429 if (isp_sd->params.video_dis_en &&
430 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
431 !isp_sd->continuous_mode->val) {
432 /* This resolution contains 20 % of DVS slack
433 * (of the desired captured image before
434 * scaling, or 1 / 6 of what we get from the
435 * sensor) in both width and height. Remove
436 * it. */
437 crop[pad]->width = roundup(crop[pad]->width * 5 / 6,
438 ATOM_ISP_STEP_WIDTH);
439 crop[pad]->height = roundup(crop[pad]->height * 5 / 6,
440 ATOM_ISP_STEP_HEIGHT);
441 }
442
443 crop[pad]->width = min(crop[pad]->width, r->width);
444 crop[pad]->height = min(crop[pad]->height, r->height);
445
446 if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) {
447 for (i = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE;
448 i < ATOMISP_SUBDEV_PADS_NUM; i++) {
449 struct v4l2_rect tmp = *crop[pad];
450
451 atomisp_subdev_set_selection(
452 sd, sd_state, which, i,
453 V4L2_SEL_TGT_COMPOSE,
454 flags, &tmp);
455 }
456 }
457
458 if (which == V4L2_SUBDEV_FORMAT_TRY)
459 break;
460
461 if (isp_sd->params.video_dis_en &&
462 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
463 !isp_sd->continuous_mode->val) {
464 dvs_w = rounddown(crop[pad]->width / 5,
465 ATOM_ISP_STEP_WIDTH);
466 dvs_h = rounddown(crop[pad]->height / 5,
467 ATOM_ISP_STEP_HEIGHT);
468 } else if (!isp_sd->params.video_dis_en &&
469 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
470 /*
471 * For CSS2.0, digital zoom needs to set dvs envelope to 12
472 * when dvs is disabled.
473 */
474 dvs_w = dvs_h = 12;
475 } else {
476 dvs_w = dvs_h = 0;
477 }
478 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
479 atomisp_css_input_set_effective_resolution(isp_sd,
480 ATOMISP_INPUT_STREAM_GENERAL,
481 crop[pad]->width,
482 crop[pad]->height);
483 break;
484 }
485 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
486 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: {
487 /* Only compose target is supported on source pads. */
488
489 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
490 /* Scaling is disabled in this mode */
491 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width;
492 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height;
493 }
494
495 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width
496 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height)
497 isp_sd->params.yuv_ds_en = false;
498 else
499 isp_sd->params.yuv_ds_en = true;
500
501 comp[pad]->width = r->width;
502 comp[pad]->height = r->height;
503
504 if (r->width == 0 || r->height == 0 ||
505 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 ||
506 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0)
507 break;
508 /*
509 * do cropping on sensor input if ratio of required resolution
510 * is different with sensor output resolution ratio:
511 *
512 * ratio = width / height
513 *
514 * if ratio_output < ratio_sensor:
515 * effect_width = sensor_height * out_width / out_height;
516 * effect_height = sensor_height;
517 * else
518 * effect_width = sensor_width;
519 * effect_height = sensor_width * out_height / out_width;
520 *
521 */
522 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height <
523 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height)
524 atomisp_css_input_set_effective_resolution(isp_sd,
525 ATOMISP_INPUT_STREAM_GENERAL,
526 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
527 height * r->width / r->height,
528 ATOM_ISP_STEP_WIDTH),
529 crop[ATOMISP_SUBDEV_PAD_SINK]->height);
530 else
531 atomisp_css_input_set_effective_resolution(isp_sd,
532 ATOMISP_INPUT_STREAM_GENERAL,
533 crop[ATOMISP_SUBDEV_PAD_SINK]->width,
534 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
535 width * r->height / r->width,
536 ATOM_ISP_STEP_WIDTH));
537
538 break;
539 }
540 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
541 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
542 comp[pad]->width = r->width;
543 comp[pad]->height = r->height;
544 break;
545 default:
546 return -EINVAL;
547 }
548
549 /* Set format dimensions on non-sink pads as well. */
550 if (pad != ATOMISP_SUBDEV_PAD_SINK) {
551 ffmt[pad]->width = comp[pad]->width;
552 ffmt[pad]->height = comp[pad]->height;
553 }
554
555 if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target))
556 return -EINVAL;
557 *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target);
558
559 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
560 r->left, r->top, r->width, r->height);
561
562 return 0;
563 }
564
isp_subdev_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)565 static int isp_subdev_set_selection(struct v4l2_subdev *sd,
566 struct v4l2_subdev_state *sd_state,
567 struct v4l2_subdev_selection *sel)
568 {
569 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
570
571 if (rval)
572 return rval;
573
574 return atomisp_subdev_set_selection(sd, sd_state, sel->which,
575 sel->pad,
576 sel->target, sel->flags, &sel->r);
577 }
578
atomisp_subdev_set_ffmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,uint32_t which,u32 pad,struct v4l2_mbus_framefmt * ffmt)579 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
580 struct v4l2_subdev_state *sd_state,
581 uint32_t which,
582 u32 pad, struct v4l2_mbus_framefmt *ffmt)
583 {
584 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
585 struct atomisp_device *isp = isp_sd->isp;
586 struct v4l2_mbus_framefmt *__ffmt =
587 atomisp_subdev_get_ffmt(sd, sd_state, which, pad);
588
589 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
590 atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code,
591 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
592 : "V4L2_SUBDEV_FORMAT_ACTIVE");
593
594 switch (pad) {
595 case ATOMISP_SUBDEV_PAD_SINK: {
596 const struct atomisp_in_fmt_conv *fc =
597 atomisp_find_in_fmt_conv(ffmt->code);
598
599 if (!fc) {
600 fc = atomisp_in_fmt_conv;
601 ffmt->code = fc->code;
602 dev_dbg(isp->dev, "using 0x%8.8x instead\n",
603 ffmt->code);
604 }
605
606 *__ffmt = *ffmt;
607
608 isp_subdev_propagate(sd, sd_state, which, pad,
609 V4L2_SEL_TGT_CROP, 0);
610
611 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
612 atomisp_css_input_set_resolution(isp_sd,
613 ATOMISP_INPUT_STREAM_GENERAL, ffmt);
614 atomisp_css_input_set_binning_factor(isp_sd,
615 ATOMISP_INPUT_STREAM_GENERAL,
616 0);
617 atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
618 fc->bayer_order);
619 atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
620 fc->atomisp_in_fmt);
621 atomisp_css_set_default_isys_config(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
622 ffmt);
623 }
624
625 break;
626 }
627 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
628 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
629 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
630 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
631 __ffmt->code = ffmt->code;
632 break;
633 }
634 }
635
636 /*
637 * isp_subdev_get_format - Retrieve the video format on a pad
638 * @sd : ISP V4L2 subdevice
639 * @fh : V4L2 subdev file handle
640 * @pad: Pad number
641 * @fmt: Format
642 *
643 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
644 * to the format type.
645 */
isp_subdev_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)646 static int isp_subdev_get_format(struct v4l2_subdev *sd,
647 struct v4l2_subdev_state *sd_state,
648 struct v4l2_subdev_format *fmt)
649 {
650 fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which,
651 fmt->pad);
652
653 return 0;
654 }
655
656 /*
657 * isp_subdev_set_format - Set the video format on a pad
658 * @sd : ISP subdev V4L2 subdevice
659 * @fh : V4L2 subdev file handle
660 * @pad: Pad number
661 * @fmt: Format
662 *
663 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
664 * to the format type.
665 */
isp_subdev_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)666 static int isp_subdev_set_format(struct v4l2_subdev *sd,
667 struct v4l2_subdev_state *sd_state,
668 struct v4l2_subdev_format *fmt)
669 {
670 atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
671 &fmt->format);
672
673 return 0;
674 }
675
676 /* V4L2 subdev core operations */
677 static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = {
678 .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power,
679 .subscribe_event = isp_subdev_subscribe_event,
680 .unsubscribe_event = isp_subdev_unsubscribe_event,
681 };
682
683 /* V4L2 subdev pad operations */
684 static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = {
685 .enum_mbus_code = isp_subdev_enum_mbus_code,
686 .get_fmt = isp_subdev_get_format,
687 .set_fmt = isp_subdev_set_format,
688 .get_selection = isp_subdev_get_selection,
689 .set_selection = isp_subdev_set_selection,
690 .link_validate = v4l2_subdev_link_validate_default,
691 };
692
693 /* V4L2 subdev operations */
694 static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = {
695 .core = &isp_subdev_v4l2_core_ops,
696 .pad = &isp_subdev_v4l2_pad_ops,
697 };
698
isp_subdev_init_params(struct atomisp_sub_device * asd)699 static void isp_subdev_init_params(struct atomisp_sub_device *asd)
700 {
701 unsigned int i;
702
703 /* parameters initialization */
704 INIT_LIST_HEAD(&asd->s3a_stats);
705 INIT_LIST_HEAD(&asd->s3a_stats_in_css);
706 INIT_LIST_HEAD(&asd->s3a_stats_ready);
707 INIT_LIST_HEAD(&asd->dis_stats);
708 INIT_LIST_HEAD(&asd->dis_stats_in_css);
709 spin_lock_init(&asd->dis_stats_lock);
710 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
711 INIT_LIST_HEAD(&asd->metadata[i]);
712 INIT_LIST_HEAD(&asd->metadata_in_css[i]);
713 INIT_LIST_HEAD(&asd->metadata_ready[i]);
714 }
715 }
716
717 /* media operations */
718 static const struct media_entity_operations isp_subdev_media_ops = {
719 .link_validate = v4l2_subdev_link_validate,
720 /* .set_power = v4l2_subdev_set_power, */
721 };
722
__atomisp_update_run_mode(struct atomisp_sub_device * asd)723 static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
724 {
725 struct atomisp_device *isp = asd->isp;
726 struct v4l2_ctrl *ctrl = asd->run_mode;
727 struct v4l2_ctrl *c;
728 s32 mode;
729
730 if (ctrl->val != ATOMISP_RUN_MODE_VIDEO &&
731 asd->continuous_mode->val)
732 mode = ATOMISP_RUN_MODE_PREVIEW;
733 else
734 mode = ctrl->val;
735
736 c = v4l2_ctrl_find(
737 isp->inputs[asd->input_curr].camera->ctrl_handler,
738 V4L2_CID_RUN_MODE);
739
740 if (c)
741 return v4l2_ctrl_s_ctrl(c, mode);
742
743 return 0;
744 }
745
atomisp_update_run_mode(struct atomisp_sub_device * asd)746 int atomisp_update_run_mode(struct atomisp_sub_device *asd)
747 {
748 int rval;
749
750 mutex_lock(asd->ctrl_handler.lock);
751 rval = __atomisp_update_run_mode(asd);
752 mutex_unlock(asd->ctrl_handler.lock);
753
754 return rval;
755 }
756
s_ctrl(struct v4l2_ctrl * ctrl)757 static int s_ctrl(struct v4l2_ctrl *ctrl)
758 {
759 struct atomisp_sub_device *asd = container_of(
760 ctrl->handler, struct atomisp_sub_device, ctrl_handler);
761 unsigned int streaming;
762 unsigned long flags;
763
764 switch (ctrl->id) {
765 case V4L2_CID_RUN_MODE:
766 return __atomisp_update_run_mode(asd);
767 case V4L2_CID_DEPTH_MODE:
768 /* Use spinlock instead of mutex to avoid possible locking issues */
769 spin_lock_irqsave(&asd->isp->lock, flags);
770 streaming = asd->streaming;
771 spin_unlock_irqrestore(&asd->isp->lock, flags);
772 if (streaming != ATOMISP_DEVICE_STREAMING_DISABLED) {
773 dev_err(asd->isp->dev,
774 "ISP is streaming, it is not supported to change the depth mode\n");
775 return -EINVAL;
776 }
777 break;
778 }
779
780 return 0;
781 }
782
783 static const struct v4l2_ctrl_ops ctrl_ops = {
784 .s_ctrl = &s_ctrl,
785 };
786
787 static const struct v4l2_ctrl_config ctrl_fmt_auto = {
788 .ops = &ctrl_ops,
789 .id = V4L2_CID_FMT_AUTO,
790 .name = "Automatic format guessing",
791 .type = V4L2_CTRL_TYPE_BOOLEAN,
792 .min = 0,
793 .max = 1,
794 .step = 1,
795 .def = 1,
796 };
797
798 static const char *const ctrl_run_mode_menu[] = {
799 NULL,
800 "Video",
801 "Still capture",
802 "Continuous capture",
803 "Preview",
804 };
805
806 static const struct v4l2_ctrl_config ctrl_run_mode = {
807 .ops = &ctrl_ops,
808 .id = V4L2_CID_RUN_MODE,
809 .name = "Atomisp run mode",
810 .type = V4L2_CTRL_TYPE_MENU,
811 .min = 1,
812 .def = 1,
813 .max = 4,
814 .qmenu = ctrl_run_mode_menu,
815 };
816
817 static const char *const ctrl_vfpp_mode_menu[] = {
818 "Enable", /* vfpp always enabled */
819 "Disable to scaler mode", /* CSS into video mode and disable */
820 "Disable to low latency mode", /* CSS into still mode and disable */
821 };
822
823 static const struct v4l2_ctrl_config ctrl_vfpp = {
824 .id = V4L2_CID_VFPP,
825 .name = "Atomisp vf postprocess",
826 .type = V4L2_CTRL_TYPE_MENU,
827 .min = 0,
828 .def = 0,
829 .max = 2,
830 .qmenu = ctrl_vfpp_mode_menu,
831 };
832
833 /*
834 * Control for ISP continuous mode
835 *
836 * When enabled, capture processing is possible without
837 * stopping the preview pipeline. When disabled, ISP needs
838 * to be restarted between preview and capture.
839 */
840 static const struct v4l2_ctrl_config ctrl_continuous_mode = {
841 .ops = &ctrl_ops,
842 .id = V4L2_CID_ATOMISP_CONTINUOUS_MODE,
843 .type = V4L2_CTRL_TYPE_BOOLEAN,
844 .name = "Continuous mode",
845 .min = 0,
846 .max = 1,
847 .step = 1,
848 .def = 0,
849 };
850
851 /*
852 * Control for continuous mode raw buffer size
853 *
854 * The size of the RAW ringbuffer sets limit on how much
855 * back in time application can go when requesting capture
856 * frames to be rendered, and how many frames can be rendered
857 * in a burst at full sensor rate.
858 *
859 * Note: this setting has a big impact on memory consumption of
860 * the CSS subsystem.
861 */
862 static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = {
863 .ops = &ctrl_ops,
864 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE,
865 .type = V4L2_CTRL_TYPE_INTEGER,
866 .name = "Continuous raw ringbuffer size",
867 .min = 1,
868 .max = 100, /* depends on CSS version, runtime checked */
869 .step = 1,
870 .def = 3,
871 };
872
873 /*
874 * Control for enabling continuous viewfinder
875 *
876 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ),
877 * preview pipeline continues concurrently with capture
878 * processing. When disabled, and continuous mode is used,
879 * preview is paused while captures are processed, but
880 * full pipeline restart is not needed.
881 *
882 * By setting this to disabled, capture processing is
883 * essentially given priority over preview, and the effective
884 * capture output rate may be higher than with continuous
885 * viewfinder enabled.
886 */
887 static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = {
888 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER,
889 .type = V4L2_CTRL_TYPE_BOOLEAN,
890 .name = "Continuous viewfinder",
891 .min = 0,
892 .max = 1,
893 .step = 1,
894 .def = 0,
895 };
896
897 /*
898 * Control for enabling Lock&Unlock Raw Buffer mechanism
899 *
900 * When enabled, Raw Buffer can be locked and unlocked.
901 * Application can hold the exp_id of Raw Buffer
902 * and unlock it when no longer needed.
903 * Note: Make sure set this configuration before creating stream.
904 */
905 static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = {
906 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK,
907 .type = V4L2_CTRL_TYPE_BOOLEAN,
908 .name = "Lock Unlock Raw Buffer",
909 .min = 0,
910 .max = 1,
911 .step = 1,
912 .def = 0,
913 };
914
915 /*
916 * Control to disable digital zoom of the whole stream
917 *
918 * When it is true, pipe configuration enable_dz will be set to false.
919 * This can help get a better performance by disabling pp binary.
920 *
921 * Note: Make sure set this configuration before creating stream.
922 */
923 static const struct v4l2_ctrl_config ctrl_disable_dz = {
924 .id = V4L2_CID_DISABLE_DZ,
925 .type = V4L2_CTRL_TYPE_BOOLEAN,
926 .name = "Disable digital zoom",
927 .min = 0,
928 .max = 1,
929 .step = 1,
930 .def = 0,
931 };
932
933 /*
934 * Control for ISP depth mode
935 *
936 * When enabled, that means ISP will deal with dual streams and sensors will be
937 * in slave/master mode.
938 * slave sensor will have no output until master sensor is streamed on.
939 */
940 static const struct v4l2_ctrl_config ctrl_depth_mode = {
941 .ops = &ctrl_ops,
942 .id = V4L2_CID_DEPTH_MODE,
943 .type = V4L2_CTRL_TYPE_BOOLEAN,
944 .name = "Depth mode",
945 .min = 0,
946 .max = 1,
947 .step = 1,
948 .def = 0,
949 };
950
atomisp_init_subdev_pipe(struct atomisp_sub_device * asd,struct atomisp_video_pipe * pipe,enum v4l2_buf_type buf_type)951 static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
952 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
953 {
954 int ret;
955
956 pipe->type = buf_type;
957 pipe->asd = asd;
958 pipe->isp = asd->isp;
959 spin_lock_init(&pipe->irq_lock);
960 mutex_init(&pipe->vb_queue_mutex);
961
962 /* Init videobuf2 queue structure */
963 pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
964 pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
965 pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
966 pipe->vb_queue.ops = &atomisp_vb2_ops;
967 pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
968 pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
969 ret = vb2_queue_init(&pipe->vb_queue);
970 if (ret)
971 return ret;
972
973 pipe->vdev.queue = &pipe->vb_queue;
974 pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
975
976 INIT_LIST_HEAD(&pipe->buffers_in_css);
977 INIT_LIST_HEAD(&pipe->activeq);
978 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
979 INIT_LIST_HEAD(&pipe->per_frame_params);
980
981 return 0;
982 }
983
984 /*
985 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
986 * @asd: ISP CCDC module
987 *
988 * Return 0 on success and a negative error code on failure.
989 */
isp_subdev_init_entities(struct atomisp_sub_device * asd)990 static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
991 {
992 struct v4l2_subdev *sd = &asd->subdev;
993 struct media_pad *pads = asd->pads;
994 struct media_entity *me = &sd->entity;
995 int ret;
996
997 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
998 sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index);
999 v4l2_set_subdevdata(sd, asd);
1000 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1001
1002 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1003 pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE;
1004 pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
1005 pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE;
1006 pads[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
1007
1008 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code =
1009 MEDIA_BUS_FMT_SBGGR10_1X10;
1010 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code =
1011 MEDIA_BUS_FMT_SBGGR10_1X10;
1012 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code =
1013 MEDIA_BUS_FMT_SBGGR10_1X10;
1014 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code =
1015 MEDIA_BUS_FMT_SBGGR10_1X10;
1016 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].fmt.code =
1017 MEDIA_BUS_FMT_SBGGR10_1X10;
1018
1019 me->ops = &isp_subdev_media_ops;
1020 me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
1021 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
1022 if (ret < 0)
1023 return ret;
1024
1025 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
1026 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1027 if (ret)
1028 return ret;
1029
1030 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
1031 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1032 if (ret)
1033 return ret;
1034
1035 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
1036 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1037 if (ret)
1038 return ret;
1039
1040 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
1041 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1042 if (ret)
1043 return ret;
1044
1045 ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE",
1046 ATOMISP_RUN_MODE_STILL_CAPTURE);
1047 if (ret < 0)
1048 return ret;
1049
1050 ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER",
1051 ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE);
1052 if (ret < 0)
1053 return ret;
1054
1055 ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW",
1056 ATOMISP_RUN_MODE_PREVIEW);
1057 if (ret < 0)
1058 return ret;
1059
1060 ret = atomisp_video_init(&asd->video_out_video_capture, "VIDEO",
1061 ATOMISP_RUN_MODE_VIDEO);
1062 if (ret < 0)
1063 return ret;
1064
1065 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
1066 if (ret)
1067 return ret;
1068
1069 asd->fmt_auto = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1070 &ctrl_fmt_auto, NULL);
1071 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1072 &ctrl_run_mode, NULL);
1073 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1074 &ctrl_vfpp, NULL);
1075 asd->continuous_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1076 &ctrl_continuous_mode, NULL);
1077 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1078 &ctrl_continuous_viewfinder,
1079 NULL);
1080 asd->continuous_raw_buffer_size =
1081 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1082 &ctrl_continuous_raw_buffer_size,
1083 NULL);
1084
1085 asd->enable_raw_buffer_lock =
1086 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1087 &ctrl_enable_raw_buffer_lock,
1088 NULL);
1089 asd->depth_mode =
1090 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1091 &ctrl_depth_mode,
1092 NULL);
1093 asd->disable_dz =
1094 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1095 &ctrl_disable_dz,
1096 NULL);
1097
1098 /* Make controls visible on subdev as well. */
1099 asd->subdev.ctrl_handler = &asd->ctrl_handler;
1100 spin_lock_init(&asd->raw_buffer_bitmap_lock);
1101 return asd->ctrl_handler.error;
1102 }
1103
atomisp_create_pads_links(struct atomisp_device * isp)1104 int atomisp_create_pads_links(struct atomisp_device *isp)
1105 {
1106 struct atomisp_sub_device *asd;
1107 int i, j, ret = 0;
1108
1109 isp->num_of_streams = 2;
1110 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
1111 for (j = 0; j < isp->num_of_streams; j++) {
1112 ret =
1113 media_create_pad_link(&isp->csi2_port[i].subdev.
1114 entity, CSI2_PAD_SOURCE,
1115 &isp->asd[j].subdev.entity,
1116 ATOMISP_SUBDEV_PAD_SINK, 0);
1117 if (ret < 0)
1118 return ret;
1119 }
1120 }
1121 for (i = 0; i < isp->input_cnt; i++) {
1122 /* Don't create links for the test-pattern-generator */
1123 if (isp->inputs[i].type == TEST_PATTERN)
1124 continue;
1125
1126 ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0,
1127 &isp->csi2_port[isp->inputs[i].
1128 port].subdev.entity,
1129 CSI2_PAD_SINK,
1130 MEDIA_LNK_FL_ENABLED |
1131 MEDIA_LNK_FL_IMMUTABLE);
1132 if (ret < 0)
1133 return ret;
1134 }
1135 for (i = 0; i < isp->num_of_streams; i++) {
1136 asd = &isp->asd[i];
1137 ret = media_create_pad_link(&asd->subdev.entity,
1138 ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW,
1139 &asd->video_out_preview.vdev.entity,
1140 0, 0);
1141 if (ret < 0)
1142 return ret;
1143 ret = media_create_pad_link(&asd->subdev.entity,
1144 ATOMISP_SUBDEV_PAD_SOURCE_VF,
1145 &asd->video_out_vf.vdev.entity, 0,
1146 0);
1147 if (ret < 0)
1148 return ret;
1149 ret = media_create_pad_link(&asd->subdev.entity,
1150 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
1151 &asd->video_out_capture.vdev.entity,
1152 0, 0);
1153 if (ret < 0)
1154 return ret;
1155 ret = media_create_pad_link(&asd->subdev.entity,
1156 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
1157 &asd->video_out_video_capture.vdev.
1158 entity, 0, 0);
1159 if (ret < 0)
1160 return ret;
1161 }
1162 return 0;
1163 }
1164
atomisp_subdev_cleanup_entities(struct atomisp_sub_device * asd)1165 static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd)
1166 {
1167 v4l2_ctrl_handler_free(&asd->ctrl_handler);
1168
1169 media_entity_cleanup(&asd->subdev.entity);
1170 }
1171
atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device * asd)1172 void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd)
1173 {
1174 struct v4l2_fh *fh, *fh_tmp;
1175 struct v4l2_event event;
1176 unsigned int i, pending_event;
1177
1178 list_for_each_entry_safe(fh, fh_tmp,
1179 &asd->subdev.devnode->fh_list, list) {
1180 pending_event = v4l2_event_pending(fh);
1181 for (i = 0; i < pending_event; i++)
1182 v4l2_event_dequeue(fh, &event, 1);
1183 }
1184 }
1185
atomisp_subdev_unregister_entities(struct atomisp_sub_device * asd)1186 void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd)
1187 {
1188 atomisp_subdev_cleanup_entities(asd);
1189 v4l2_device_unregister_subdev(&asd->subdev);
1190 atomisp_video_unregister(&asd->video_out_preview);
1191 atomisp_video_unregister(&asd->video_out_vf);
1192 atomisp_video_unregister(&asd->video_out_capture);
1193 atomisp_video_unregister(&asd->video_out_video_capture);
1194 }
1195
atomisp_subdev_register_subdev(struct atomisp_sub_device * asd,struct v4l2_device * vdev)1196 int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd,
1197 struct v4l2_device *vdev)
1198 {
1199 return v4l2_device_register_subdev(vdev, &asd->subdev);
1200 }
1201
atomisp_subdev_register_video_nodes(struct atomisp_sub_device * asd,struct v4l2_device * vdev)1202 int atomisp_subdev_register_video_nodes(struct atomisp_sub_device *asd,
1203 struct v4l2_device *vdev)
1204 {
1205 int ret;
1206
1207 /*
1208 * FIXME: check if all device caps are properly initialized.
1209 * Should any of those use V4L2_CAP_META_CAPTURE? Probably yes.
1210 */
1211
1212 asd->video_out_preview.vdev.v4l2_dev = vdev;
1213 asd->video_out_preview.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1214 ret = video_register_device(&asd->video_out_preview.vdev,
1215 VFL_TYPE_VIDEO, -1);
1216 if (ret < 0)
1217 goto error;
1218
1219 asd->video_out_capture.vdev.v4l2_dev = vdev;
1220 asd->video_out_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1221 ret = video_register_device(&asd->video_out_capture.vdev,
1222 VFL_TYPE_VIDEO, -1);
1223 if (ret < 0)
1224 goto error;
1225
1226 asd->video_out_vf.vdev.v4l2_dev = vdev;
1227 asd->video_out_vf.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1228 ret = video_register_device(&asd->video_out_vf.vdev,
1229 VFL_TYPE_VIDEO, -1);
1230 if (ret < 0)
1231 goto error;
1232
1233 asd->video_out_video_capture.vdev.v4l2_dev = vdev;
1234 asd->video_out_video_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1235 ret = video_register_device(&asd->video_out_video_capture.vdev,
1236 VFL_TYPE_VIDEO, -1);
1237 if (ret < 0)
1238 goto error;
1239
1240 return 0;
1241
1242 error:
1243 atomisp_subdev_unregister_entities(asd);
1244 return ret;
1245 }
1246
1247 /*
1248 * atomisp_subdev_init - ISP Subdevice initialization.
1249 * @dev: Device pointer specific to the ATOM ISP.
1250 *
1251 * TODO: Get the initialisation values from platform data.
1252 *
1253 * Return 0 on success or a negative error code otherwise.
1254 */
atomisp_subdev_init(struct atomisp_device * isp)1255 int atomisp_subdev_init(struct atomisp_device *isp)
1256 {
1257 struct atomisp_sub_device *asd;
1258 int i, ret = 0;
1259
1260 /*
1261 * CSS2.0 running ISP2400 support
1262 * multiple streams
1263 */
1264 isp->num_of_streams = 2;
1265 isp->asd = devm_kzalloc(isp->dev, sizeof(struct atomisp_sub_device) *
1266 isp->num_of_streams, GFP_KERNEL);
1267 if (!isp->asd)
1268 return -ENOMEM;
1269 for (i = 0; i < isp->num_of_streams; i++) {
1270 asd = &isp->asd[i];
1271 asd->isp = isp;
1272 isp_subdev_init_params(asd);
1273 asd->index = i;
1274 ret = isp_subdev_init_entities(asd);
1275 if (ret < 0) {
1276 atomisp_subdev_cleanup_entities(asd);
1277 break;
1278 }
1279 }
1280
1281 return ret;
1282 }
1283