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