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 #include "atomisp_ioctl.h"
35
36 const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
37 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_BGGR },
38 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GBRG },
39 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GRBG },
40 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_RGGB },
41 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_BGGR },
42 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GBRG },
43 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GRBG },
44 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_RGGB },
45 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_BGGR },
46 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GBRG },
47 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GRBG },
48 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_RGGB },
49 { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 },
50 { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 },
51 #if 0 // disabled due to clang warnings
52 { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
53 { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, IA_CSS_FRAME_FORMAT_NV12, 0 },
54 { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, IA_CSS_FRAME_FORMAT_NV21, 0 },
55 #endif
56 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0 },
57 #if 0
58 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
59 #endif
60 /* no valid V4L2 MBUS code for metadata format, so leave it 0. */
61 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0 },
62 {}
63 };
64
65 static const struct {
66 u32 code;
67 u32 compressed;
68 } compressed_codes[] = {
69 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
70 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
71 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
72 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
73 };
74
atomisp_subdev_uncompressed_code(u32 code)75 u32 atomisp_subdev_uncompressed_code(u32 code)
76 {
77 unsigned int i;
78
79 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++)
80 if (code == compressed_codes[i].compressed)
81 return compressed_codes[i].code;
82
83 return code;
84 }
85
atomisp_subdev_is_compressed(u32 code)86 bool atomisp_subdev_is_compressed(u32 code)
87 {
88 int i;
89
90 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
91 if (code == atomisp_in_fmt_conv[i].code)
92 return atomisp_in_fmt_conv[i].bpp !=
93 atomisp_in_fmt_conv[i].depth;
94
95 return false;
96 }
97
atomisp_find_in_fmt_conv(u32 code)98 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code)
99 {
100 int i;
101
102 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
103 if (code == atomisp_in_fmt_conv[i].code)
104 return atomisp_in_fmt_conv + i;
105
106 return NULL;
107 }
108
atomisp_find_in_fmt_conv_by_atomisp_in_fmt(enum atomisp_input_format atomisp_in_fmt)109 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
110 enum atomisp_input_format atomisp_in_fmt)
111 {
112 int i;
113
114 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
115 if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt)
116 return atomisp_in_fmt_conv + i;
117
118 return NULL;
119 }
120
atomisp_subdev_format_conversion(struct atomisp_sub_device * asd)121 bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd)
122 {
123 struct v4l2_mbus_framefmt *sink, *src;
124
125 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
126 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK);
127 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
128 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SOURCE);
129
130 return atomisp_is_mbuscode_raw(sink->code)
131 && !atomisp_is_mbuscode_raw(src->code);
132 }
133
134 /*
135 * V4L2 subdev operations
136 */
137
138 /*
139 * isp_subdev_ioctl - CCDC module private ioctl's
140 * @sd: ISP V4L2 subdevice
141 * @cmd: ioctl command
142 * @arg: ioctl argument
143 *
144 * Return 0 on success or a negative error code otherwise.
145 */
isp_subdev_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)146 static long isp_subdev_ioctl(struct v4l2_subdev *sd,
147 unsigned int cmd, void *arg)
148 {
149 return 0;
150 }
151
isp_subdev_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)152 static int isp_subdev_subscribe_event(struct v4l2_subdev *sd,
153 struct v4l2_fh *fh,
154 struct v4l2_event_subscription *sub)
155 {
156 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
157 struct atomisp_device *isp = isp_sd->isp;
158
159 if (sub->type != V4L2_EVENT_FRAME_SYNC &&
160 sub->type != V4L2_EVENT_FRAME_END &&
161 sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY &&
162 sub->type != V4L2_EVENT_ATOMISP_METADATA_READY &&
163 sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER &&
164 sub->type != V4L2_EVENT_ATOMISP_CSS_RESET &&
165 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE)
166 return -EINVAL;
167
168 if (sub->type == V4L2_EVENT_FRAME_SYNC &&
169 !atomisp_css_valid_sof(isp))
170 return -EINVAL;
171
172 return v4l2_event_subscribe(fh, sub, 16, NULL);
173 }
174
isp_subdev_unsubscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)175 static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
176 struct v4l2_fh *fh,
177 struct v4l2_event_subscription *sub)
178 {
179 return v4l2_event_unsubscribe(fh, sub);
180 }
181
182 /*
183 * isp_subdev_enum_mbus_code - Handle pixel format enumeration
184 * @sd: pointer to v4l2 subdev structure
185 * @fh : V4L2 subdev file handle
186 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure
187 * return -EINVAL or zero on success
188 */
isp_subdev_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)189 static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
190 struct v4l2_subdev_state *sd_state,
191 struct v4l2_subdev_mbus_code_enum *code)
192 {
193 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
194 return -EINVAL;
195
196 code->code = atomisp_in_fmt_conv[code->index].code;
197
198 return 0;
199 }
200
isp_subdev_validate_rect(struct v4l2_subdev * sd,uint32_t pad,uint32_t target)201 static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
202 uint32_t target)
203 {
204 switch (pad) {
205 case ATOMISP_SUBDEV_PAD_SINK:
206 switch (target) {
207 case V4L2_SEL_TGT_CROP:
208 return 0;
209 }
210 break;
211 default:
212 switch (target) {
213 case V4L2_SEL_TGT_COMPOSE:
214 return 0;
215 }
216 break;
217 }
218
219 return -EINVAL;
220 }
221
atomisp_subdev_get_rect(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,u32 which,uint32_t pad,uint32_t target)222 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
223 struct v4l2_subdev_state *sd_state,
224 u32 which, uint32_t pad,
225 uint32_t target)
226 {
227 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
228
229 if (which == V4L2_SUBDEV_FORMAT_TRY) {
230 switch (target) {
231 case V4L2_SEL_TGT_CROP:
232 return v4l2_subdev_state_get_crop(sd_state, pad);
233 case V4L2_SEL_TGT_COMPOSE:
234 return v4l2_subdev_state_get_compose(sd_state, pad);
235 }
236 }
237
238 switch (target) {
239 case V4L2_SEL_TGT_CROP:
240 return &isp_sd->fmt[pad].crop;
241 case V4L2_SEL_TGT_COMPOSE:
242 return &isp_sd->fmt[pad].compose;
243 }
244
245 return NULL;
246 }
247
248 struct v4l2_mbus_framefmt
atomisp_subdev_get_ffmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,uint32_t which,uint32_t pad)249 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
250 struct v4l2_subdev_state *sd_state, uint32_t which,
251 uint32_t pad)
252 {
253 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
254
255 if (which == V4L2_SUBDEV_FORMAT_TRY)
256 return v4l2_subdev_state_get_format(sd_state, pad);
257
258 return &isp_sd->fmt[pad].fmt;
259 }
260
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])261 static void isp_get_fmt_rect(struct v4l2_subdev *sd,
262 struct v4l2_subdev_state *sd_state,
263 uint32_t which,
264 struct v4l2_mbus_framefmt **ffmt,
265 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
266 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
267 {
268 unsigned int i;
269
270 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
271 ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i);
272 crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
273 V4L2_SEL_TGT_CROP);
274 comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
275 V4L2_SEL_TGT_COMPOSE);
276 }
277 }
278
isp_subdev_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)279 static int isp_subdev_get_selection(struct v4l2_subdev *sd,
280 struct v4l2_subdev_state *sd_state,
281 struct v4l2_subdev_selection *sel)
282 {
283 struct v4l2_rect *rec;
284 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
285
286 if (rval)
287 return rval;
288
289 rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad,
290 sel->target);
291 if (!rec)
292 return -EINVAL;
293
294 sel->r = *rec;
295 return 0;
296 }
297
atomisp_pad_str(unsigned int pad)298 static const char *atomisp_pad_str(unsigned int pad)
299 {
300 static const char *const pad_str[] = {
301 "ATOMISP_SUBDEV_PAD_SINK",
302 "ATOMISP_SUBDEV_PAD_SOURCE",
303 };
304
305 if (pad >= ARRAY_SIZE(pad_str))
306 return "ATOMISP_INVALID_PAD";
307 return pad_str[pad];
308 }
309
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)310 int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
311 struct v4l2_subdev_state *sd_state,
312 u32 which, uint32_t pad, uint32_t target,
313 u32 flags, struct v4l2_rect *r)
314 {
315 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
316 struct atomisp_device *isp = isp_sd->isp;
317 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
318 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
319 *comp[ATOMISP_SUBDEV_PADS_NUM];
320
321 if ((pad == ATOMISP_SUBDEV_PAD_SINK && target != V4L2_SEL_TGT_CROP) ||
322 (pad == ATOMISP_SUBDEV_PAD_SOURCE && target != V4L2_SEL_TGT_COMPOSE))
323 return -EINVAL;
324
325 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
326
327 dev_dbg(isp->dev,
328 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
329 atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP
330 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
331 r->left, r->top, r->width, r->height,
332 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
333 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags);
334
335 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH);
336 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT);
337
338 if (pad == ATOMISP_SUBDEV_PAD_SINK) {
339 /* Only crop target supported on sink pad. */
340 unsigned int dvs_w, dvs_h;
341
342 crop[pad]->width = ffmt[pad]->width;
343 crop[pad]->height = ffmt[pad]->height;
344
345 if (atomisp_subdev_format_conversion(isp_sd)
346 && crop[pad]->width && crop[pad]->height) {
347 crop[pad]->width -= isp_sd->sink_pad_padding_w;
348 crop[pad]->height -= isp_sd->sink_pad_padding_h;
349 }
350
351 if (isp_sd->params.video_dis_en &&
352 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
353 /*
354 * This resolution contains 20 % of DVS slack
355 * (of the desired captured image before
356 * scaling, or 1 / 6 of what we get from the
357 * sensor) in both width and height. Remove it.
358 */
359 crop[pad]->width = roundup(crop[pad]->width * 5 / 6,
360 ATOM_ISP_STEP_WIDTH);
361 crop[pad]->height = roundup(crop[pad]->height * 5 / 6,
362 ATOM_ISP_STEP_HEIGHT);
363 }
364
365 crop[pad]->width = min(crop[pad]->width, r->width);
366 crop[pad]->height = min(crop[pad]->height, r->height);
367
368 if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) {
369 struct v4l2_rect tmp = *crop[pad];
370
371 atomisp_subdev_set_selection(sd, sd_state, which,
372 ATOMISP_SUBDEV_PAD_SOURCE,
373 V4L2_SEL_TGT_COMPOSE, flags, &tmp);
374 }
375
376 if (which == V4L2_SUBDEV_FORMAT_TRY)
377 goto get_rect;
378
379 if (isp_sd->params.video_dis_en &&
380 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
381 dvs_w = rounddown(crop[pad]->width / 5,
382 ATOM_ISP_STEP_WIDTH);
383 dvs_h = rounddown(crop[pad]->height / 5,
384 ATOM_ISP_STEP_HEIGHT);
385 } else if (!isp_sd->params.video_dis_en &&
386 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
387 /*
388 * For CSS2.0, digital zoom needs to set dvs envelope to 12
389 * when dvs is disabled.
390 */
391 dvs_w = dvs_h = 12;
392 } else {
393 dvs_w = dvs_h = 0;
394 }
395 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
396 atomisp_css_input_set_effective_resolution(isp_sd,
397 ATOMISP_INPUT_STREAM_GENERAL,
398 crop[pad]->width,
399 crop[pad]->height);
400 } else if (isp_sd->run_mode->val != ATOMISP_RUN_MODE_PREVIEW) {
401 /* Only compose target is supported on source pads. */
402 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
403 /* Scaling is disabled in this mode */
404 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width;
405 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height;
406 }
407
408 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width
409 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height)
410 isp_sd->params.yuv_ds_en = false;
411 else
412 isp_sd->params.yuv_ds_en = true;
413
414 comp[pad]->width = r->width;
415 comp[pad]->height = r->height;
416
417 if (r->width == 0 || r->height == 0 ||
418 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 ||
419 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0)
420 goto get_rect;
421 /*
422 * do cropping on sensor input if ratio of required resolution
423 * is different with sensor output resolution ratio:
424 *
425 * ratio = width / height
426 *
427 * if ratio_output < ratio_sensor:
428 * effect_width = sensor_height * out_width / out_height;
429 * effect_height = sensor_height;
430 * else
431 * effect_width = sensor_width;
432 * effect_height = sensor_width * out_height / out_width;
433 *
434 */
435 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height <
436 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height)
437 atomisp_css_input_set_effective_resolution(isp_sd,
438 ATOMISP_INPUT_STREAM_GENERAL,
439 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
440 height * r->width / r->height,
441 ATOM_ISP_STEP_WIDTH),
442 crop[ATOMISP_SUBDEV_PAD_SINK]->height);
443 else
444 atomisp_css_input_set_effective_resolution(isp_sd,
445 ATOMISP_INPUT_STREAM_GENERAL,
446 crop[ATOMISP_SUBDEV_PAD_SINK]->width,
447 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
448 width * r->height / r->width,
449 ATOM_ISP_STEP_WIDTH));
450 } else {
451 comp[pad]->width = r->width;
452 comp[pad]->height = r->height;
453 }
454
455 get_rect:
456 /* Set format dimensions on non-sink pads as well. */
457 if (pad != ATOMISP_SUBDEV_PAD_SINK) {
458 ffmt[pad]->width = comp[pad]->width;
459 ffmt[pad]->height = comp[pad]->height;
460 }
461
462 if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target))
463 return -EINVAL;
464 *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target);
465
466 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
467 r->left, r->top, r->width, r->height);
468
469 return 0;
470 }
471
isp_subdev_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)472 static int isp_subdev_set_selection(struct v4l2_subdev *sd,
473 struct v4l2_subdev_state *sd_state,
474 struct v4l2_subdev_selection *sel)
475 {
476 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
477
478 if (rval)
479 return rval;
480
481 return atomisp_subdev_set_selection(sd, sd_state, sel->which,
482 sel->pad,
483 sel->target, sel->flags, &sel->r);
484 }
485
atomisp_subdev_set_ffmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,uint32_t which,u32 pad,struct v4l2_mbus_framefmt * ffmt)486 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
487 struct v4l2_subdev_state *sd_state,
488 uint32_t which,
489 u32 pad, struct v4l2_mbus_framefmt *ffmt)
490 {
491 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
492 struct atomisp_device *isp = isp_sd->isp;
493 struct v4l2_mbus_framefmt *__ffmt =
494 atomisp_subdev_get_ffmt(sd, sd_state, which, pad);
495
496 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
497 atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code,
498 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
499 : "V4L2_SUBDEV_FORMAT_ACTIVE");
500
501 switch (pad) {
502 case ATOMISP_SUBDEV_PAD_SINK: {
503 const struct atomisp_in_fmt_conv *fc =
504 atomisp_find_in_fmt_conv(ffmt->code);
505 struct v4l2_rect r = {};
506
507 if (!fc) {
508 fc = atomisp_in_fmt_conv;
509 ffmt->code = fc->code;
510 dev_dbg(isp->dev, "using 0x%8.8x instead\n",
511 ffmt->code);
512 }
513
514 *__ffmt = *ffmt;
515
516 /* Propagate new ffmt to selection */
517 r.width = ffmt->width;
518 r.height = ffmt->height;
519 /* Only crop target supported on sink pad. */
520 atomisp_subdev_set_selection(sd, sd_state, which, pad,
521 V4L2_SEL_TGT_CROP, 0, &r);
522
523 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
524 atomisp_css_input_set_resolution(isp_sd,
525 ATOMISP_INPUT_STREAM_GENERAL, ffmt);
526 atomisp_css_input_set_binning_factor(isp_sd,
527 ATOMISP_INPUT_STREAM_GENERAL,
528 0);
529 atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
530 fc->bayer_order);
531 atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
532 fc->atomisp_in_fmt);
533 atomisp_css_set_default_isys_config(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
534 ffmt);
535 }
536
537 break;
538 }
539 case ATOMISP_SUBDEV_PAD_SOURCE:
540 __ffmt->code = ffmt->code;
541 break;
542 }
543 }
544
545 /*
546 * isp_subdev_get_format - Retrieve the video format on a pad
547 * @sd : ISP V4L2 subdevice
548 * @fh : V4L2 subdev file handle
549 * @pad: Pad number
550 * @fmt: Format
551 *
552 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
553 * to the format type.
554 */
isp_subdev_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)555 static int isp_subdev_get_format(struct v4l2_subdev *sd,
556 struct v4l2_subdev_state *sd_state,
557 struct v4l2_subdev_format *fmt)
558 {
559 fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which,
560 fmt->pad);
561
562 return 0;
563 }
564
565 /*
566 * isp_subdev_set_format - Set the video format on a pad
567 * @sd : ISP subdev V4L2 subdevice
568 * @fh : V4L2 subdev file handle
569 * @pad: Pad number
570 * @fmt: Format
571 *
572 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
573 * to the format type.
574 */
isp_subdev_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)575 static int isp_subdev_set_format(struct v4l2_subdev *sd,
576 struct v4l2_subdev_state *sd_state,
577 struct v4l2_subdev_format *fmt)
578 {
579 atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
580 &fmt->format);
581
582 return 0;
583 }
584
585 /* V4L2 subdev core operations */
586 static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = {
587 .ioctl = isp_subdev_ioctl,
588 .subscribe_event = isp_subdev_subscribe_event,
589 .unsubscribe_event = isp_subdev_unsubscribe_event,
590 };
591
592 /* V4L2 subdev pad operations */
593 static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = {
594 .enum_mbus_code = isp_subdev_enum_mbus_code,
595 .get_fmt = isp_subdev_get_format,
596 .set_fmt = isp_subdev_set_format,
597 .get_selection = isp_subdev_get_selection,
598 .set_selection = isp_subdev_set_selection,
599 .link_validate = v4l2_subdev_link_validate_default,
600 };
601
602 /* V4L2 subdev operations */
603 static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = {
604 .core = &isp_subdev_v4l2_core_ops,
605 .pad = &isp_subdev_v4l2_pad_ops,
606 };
607
isp_subdev_init_params(struct atomisp_sub_device * asd)608 static void isp_subdev_init_params(struct atomisp_sub_device *asd)
609 {
610 unsigned int i;
611
612 /* parameters initialization */
613 INIT_LIST_HEAD(&asd->s3a_stats);
614 INIT_LIST_HEAD(&asd->s3a_stats_in_css);
615 INIT_LIST_HEAD(&asd->s3a_stats_ready);
616 INIT_LIST_HEAD(&asd->dis_stats);
617 INIT_LIST_HEAD(&asd->dis_stats_in_css);
618 spin_lock_init(&asd->dis_stats_lock);
619 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
620 INIT_LIST_HEAD(&asd->metadata[i]);
621 INIT_LIST_HEAD(&asd->metadata_in_css[i]);
622 INIT_LIST_HEAD(&asd->metadata_ready[i]);
623 }
624 }
625
626 /* media operations */
atomisp_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)627 static int atomisp_link_setup(struct media_entity *entity,
628 const struct media_pad *local,
629 const struct media_pad *remote, u32 flags)
630 {
631 struct v4l2_subdev *sd = container_of(entity, struct v4l2_subdev,
632 entity);
633 struct atomisp_sub_device *asd = v4l2_get_subdevdata(sd);
634 struct atomisp_device *isp = asd->isp;
635 int i;
636
637 /* ISP's source is immutable */
638 if (local != &asd->pads[ATOMISP_SUBDEV_PAD_SINK]) {
639 v4l2_err(sd, "Error pad %d does not support changing flags\n",
640 local->index);
641 return -EINVAL;
642 }
643
644 for (i = 0; i < isp->input_cnt; i++) {
645 if (&isp->inputs[i].csi_port->entity.pads[CSI2_PAD_SOURCE] == remote)
646 break;
647 }
648
649 if (i == isp->input_cnt) {
650 v4l2_err(sd, "Error no sensor for selected CSI receiver\n");
651 return -EINVAL;
652 }
653
654 /* Turn off the sensor on link disable */
655 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
656 atomisp_s_sensor_power(isp, i, 0);
657 return 0;
658 }
659
660 return atomisp_select_input(isp, i);
661 }
662
663 static const struct media_entity_operations isp_subdev_media_ops = {
664 .link_validate = v4l2_subdev_link_validate,
665 .link_setup = atomisp_link_setup,
666 /* .set_power = v4l2_subdev_set_power, */
667 };
668
669 static const char *const ctrl_run_mode_menu[] = {
670 [ATOMISP_RUN_MODE_VIDEO] = "Video",
671 [ATOMISP_RUN_MODE_STILL_CAPTURE] = "Still capture",
672 [ATOMISP_RUN_MODE_PREVIEW] = "Preview",
673 };
674
675 static const struct v4l2_ctrl_config ctrl_run_mode = {
676 .id = V4L2_CID_RUN_MODE,
677 .name = "Atomisp run mode",
678 .type = V4L2_CTRL_TYPE_MENU,
679 .min = ATOMISP_RUN_MODE_MIN,
680 .def = ATOMISP_RUN_MODE_PREVIEW,
681 .max = ATOMISP_RUN_MODE_MAX,
682 .qmenu = ctrl_run_mode_menu,
683 };
684
685 static const char *const ctrl_vfpp_mode_menu[] = {
686 "Enable", /* vfpp always enabled */
687 "Disable to scaler mode", /* CSS into video mode and disable */
688 "Disable to low latency mode", /* CSS into still mode and disable */
689 };
690
691 static const struct v4l2_ctrl_config ctrl_vfpp = {
692 .id = V4L2_CID_VFPP,
693 .name = "Atomisp vf postprocess",
694 .type = V4L2_CTRL_TYPE_MENU,
695 .min = 0,
696 .def = 0,
697 .max = 2,
698 .qmenu = ctrl_vfpp_mode_menu,
699 };
700
701 /*
702 * Control for continuous mode raw buffer size
703 *
704 * The size of the RAW ringbuffer sets limit on how much
705 * back in time application can go when requesting capture
706 * frames to be rendered, and how many frames can be rendered
707 * in a burst at full sensor rate.
708 *
709 * Note: this setting has a big impact on memory consumption of
710 * the CSS subsystem.
711 */
712 static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = {
713 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE,
714 .type = V4L2_CTRL_TYPE_INTEGER,
715 .name = "Continuous raw ringbuffer size",
716 .min = 1,
717 .max = 100, /* depends on CSS version, runtime checked */
718 .step = 1,
719 .def = 3,
720 };
721
722 /*
723 * Control for enabling continuous viewfinder
724 *
725 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ),
726 * preview pipeline continues concurrently with capture
727 * processing. When disabled, and continuous mode is used,
728 * preview is paused while captures are processed, but
729 * full pipeline restart is not needed.
730 *
731 * By setting this to disabled, capture processing is
732 * essentially given priority over preview, and the effective
733 * capture output rate may be higher than with continuous
734 * viewfinder enabled.
735 */
736 static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = {
737 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER,
738 .type = V4L2_CTRL_TYPE_BOOLEAN,
739 .name = "Continuous viewfinder",
740 .min = 0,
741 .max = 1,
742 .step = 1,
743 .def = 0,
744 };
745
746 /*
747 * Control for enabling Lock&Unlock Raw Buffer mechanism
748 *
749 * When enabled, Raw Buffer can be locked and unlocked.
750 * Application can hold the exp_id of Raw Buffer
751 * and unlock it when no longer needed.
752 * Note: Make sure set this configuration before creating stream.
753 */
754 static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = {
755 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK,
756 .type = V4L2_CTRL_TYPE_BOOLEAN,
757 .name = "Lock Unlock Raw Buffer",
758 .min = 0,
759 .max = 1,
760 .step = 1,
761 .def = 0,
762 };
763
764 /*
765 * Control to disable digital zoom of the whole stream
766 *
767 * When it is true, pipe configuration enable_dz will be set to false.
768 * This can help get a better performance by disabling pp binary.
769 *
770 * Note: Make sure set this configuration before creating stream.
771 */
772 static const struct v4l2_ctrl_config ctrl_disable_dz = {
773 .id = V4L2_CID_DISABLE_DZ,
774 .type = V4L2_CTRL_TYPE_BOOLEAN,
775 .name = "Disable digital zoom",
776 .min = 0,
777 .max = 1,
778 .step = 1,
779 .def = 0,
780 };
781
atomisp_init_subdev_pipe(struct atomisp_sub_device * asd,struct atomisp_video_pipe * pipe,enum v4l2_buf_type buf_type)782 static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
783 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
784 {
785 int ret;
786
787 pipe->type = buf_type;
788 pipe->asd = asd;
789 pipe->isp = asd->isp;
790 spin_lock_init(&pipe->irq_lock);
791 mutex_init(&pipe->vb_queue_mutex);
792
793 /* Init videobuf2 queue structure */
794 pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
795 pipe->vb_queue.io_modes = VB2_MMAP | VB2_DMABUF;
796 pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
797 pipe->vb_queue.ops = &atomisp_vb2_ops;
798 pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
799 pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
800 pipe->vb_queue.lock = &pipe->vb_queue_mutex;
801 ret = vb2_queue_init(&pipe->vb_queue);
802 if (ret)
803 return ret;
804
805 pipe->vdev.queue = &pipe->vb_queue;
806
807 INIT_LIST_HEAD(&pipe->buffers_in_css);
808 INIT_LIST_HEAD(&pipe->activeq);
809 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
810 INIT_LIST_HEAD(&pipe->per_frame_params);
811
812 return 0;
813 }
814
815 /*
816 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
817 * @asd: ISP CCDC module
818 *
819 * Return 0 on success and a negative error code on failure.
820 */
isp_subdev_init_entities(struct atomisp_sub_device * asd)821 static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
822 {
823 struct v4l2_subdev *sd = &asd->subdev;
824 struct media_pad *pads = asd->pads;
825 struct media_entity *me = &sd->entity;
826 int ret;
827
828 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
829 sprintf(sd->name, "Atom ISP");
830 v4l2_set_subdevdata(sd, asd);
831 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
832
833 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
834 pads[ATOMISP_SUBDEV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
835
836 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10;
837 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE].fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10;
838
839 me->ops = &isp_subdev_media_ops;
840 me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
841 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
842 if (ret < 0)
843 return ret;
844
845 ret = atomisp_init_subdev_pipe(asd, &asd->video_out, V4L2_BUF_TYPE_VIDEO_CAPTURE);
846 if (ret)
847 return ret;
848
849 ret = atomisp_video_init(&asd->video_out);
850 if (ret < 0)
851 return ret;
852
853 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
854 if (ret)
855 return ret;
856
857 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
858 &ctrl_run_mode, NULL);
859 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
860 &ctrl_vfpp, NULL);
861 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
862 &ctrl_continuous_viewfinder,
863 NULL);
864 asd->continuous_raw_buffer_size =
865 v4l2_ctrl_new_custom(&asd->ctrl_handler,
866 &ctrl_continuous_raw_buffer_size,
867 NULL);
868
869 asd->enable_raw_buffer_lock =
870 v4l2_ctrl_new_custom(&asd->ctrl_handler,
871 &ctrl_enable_raw_buffer_lock,
872 NULL);
873 asd->disable_dz =
874 v4l2_ctrl_new_custom(&asd->ctrl_handler,
875 &ctrl_disable_dz,
876 NULL);
877
878 /* Make controls visible on subdev as well. */
879 asd->subdev.ctrl_handler = &asd->ctrl_handler;
880 spin_lock_init(&asd->raw_buffer_bitmap_lock);
881 return asd->ctrl_handler.error;
882 }
883
atomisp_subdev_cleanup_entities(struct atomisp_sub_device * asd)884 static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd)
885 {
886 v4l2_ctrl_handler_free(&asd->ctrl_handler);
887
888 media_entity_cleanup(&asd->subdev.entity);
889 }
890
atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device * asd)891 void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd)
892 {
893 struct v4l2_fh *fh, *fh_tmp;
894 struct v4l2_event event;
895 unsigned int i, pending_event;
896
897 list_for_each_entry_safe(fh, fh_tmp,
898 &asd->subdev.devnode->fh_list, list) {
899 pending_event = v4l2_event_pending(fh);
900 for (i = 0; i < pending_event; i++)
901 v4l2_event_dequeue(fh, &event, 1);
902 }
903 }
904
atomisp_subdev_unregister_entities(struct atomisp_sub_device * asd)905 void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd)
906 {
907 atomisp_subdev_cleanup_entities(asd);
908 v4l2_device_unregister_subdev(&asd->subdev);
909 atomisp_video_unregister(&asd->video_out);
910 }
911
atomisp_subdev_register_subdev(struct atomisp_sub_device * asd,struct v4l2_device * vdev)912 int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd,
913 struct v4l2_device *vdev)
914 {
915 return v4l2_device_register_subdev(vdev, &asd->subdev);
916 }
917
918 /*
919 * atomisp_subdev_init - ISP Subdevice initialization.
920 * @dev: Device pointer specific to the ATOM ISP.
921 *
922 * TODO: Get the initialisation values from platform data.
923 *
924 * Return 0 on success or a negative error code otherwise.
925 */
atomisp_subdev_init(struct atomisp_device * isp)926 int atomisp_subdev_init(struct atomisp_device *isp)
927 {
928 int ret;
929
930 isp->asd.isp = isp;
931 isp_subdev_init_params(&isp->asd);
932 ret = isp_subdev_init_entities(&isp->asd);
933 if (ret < 0)
934 atomisp_subdev_cleanup_entities(&isp->asd);
935
936 return ret;
937 }
938