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