xref: /linux/drivers/staging/media/atomisp/pci/atomisp_subdev.c (revision 2ace52718376fdb56aca863da2eebe70d7e2ddb1)
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