File Index
Files and directories
Sign in
FILE

atomisp_subdev.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/atomisp/pci/atomisp_subdev.c C
  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
 25const 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
 54static 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
 64u32 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
 75bool 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
 87const 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
 98const 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
110bool 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 */
135static long isp_subdev_ioctl(struct v4l2_subdev *sd,
136			     unsigned int cmd, void *arg)
137{
138	return 0;
139}
140
141static 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 */
171static 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
183static 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
204struct 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
230struct v4l2_mbus_framefmt
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
243static 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
261static 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
280static 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
292int 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
437get_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
454static 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
468void 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 */
537static 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 */
557static 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 */
568static 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 */
575static 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 */
585static 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
590static 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 */
609static 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
645static 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
651static 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
657static 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
667static 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
673static 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 */
694static 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 */
718static 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 */
736static 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 */
754static 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
764static 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 */
803static 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
866static 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
873void 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
887void 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
894int 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 */
908int 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}
~/ Read-only file preview.