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
35const 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
64static 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
74u32 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
85bool 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
97const 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
108const 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
120bool 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 */
145static 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 */
158static int isp_subdev_set_power(struct v4l2_subdev *sd, int on)
159{
160	return 0;
161}
162
163static 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
186static 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 */
200static 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
212static 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
233struct 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
259struct v4l2_mbus_framefmt
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
272static 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
290static 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
319static 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
338static 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
350int 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
494get_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
511static 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
525void 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 */
589static 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 */
609static 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 */
620static 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 */
627static 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 */
637static 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
642static 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 */
661static 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
666static 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
672static 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
682static 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
688static 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 */
709static 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 */
733static 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 */
751static 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 */
769static 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
779static 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 */
818static 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
882static 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
889void 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
903void 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
910int 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 */
924int 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