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