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