xref: /linux/drivers/media/test-drivers/vimc/vimc-debayer.c (revision dacca5f0fa69f04c2e70aad9847e8250b459971c)
1*dacca5f0SHans Verkuil // SPDX-License-Identifier: GPL-2.0-or-later
2*dacca5f0SHans Verkuil /*
3*dacca5f0SHans Verkuil  * vimc-debayer.c Virtual Media Controller Driver
4*dacca5f0SHans Verkuil  *
5*dacca5f0SHans Verkuil  * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
6*dacca5f0SHans Verkuil  */
7*dacca5f0SHans Verkuil 
8*dacca5f0SHans Verkuil #include <linux/moduleparam.h>
9*dacca5f0SHans Verkuil #include <linux/platform_device.h>
10*dacca5f0SHans Verkuil #include <linux/vmalloc.h>
11*dacca5f0SHans Verkuil #include <linux/v4l2-mediabus.h>
12*dacca5f0SHans Verkuil #include <media/v4l2-ctrls.h>
13*dacca5f0SHans Verkuil #include <media/v4l2-event.h>
14*dacca5f0SHans Verkuil #include <media/v4l2-subdev.h>
15*dacca5f0SHans Verkuil 
16*dacca5f0SHans Verkuil #include "vimc-common.h"
17*dacca5f0SHans Verkuil 
18*dacca5f0SHans Verkuil enum vimc_deb_rgb_colors {
19*dacca5f0SHans Verkuil 	VIMC_DEB_RED = 0,
20*dacca5f0SHans Verkuil 	VIMC_DEB_GREEN = 1,
21*dacca5f0SHans Verkuil 	VIMC_DEB_BLUE = 2,
22*dacca5f0SHans Verkuil };
23*dacca5f0SHans Verkuil 
24*dacca5f0SHans Verkuil struct vimc_deb_pix_map {
25*dacca5f0SHans Verkuil 	u32 code;
26*dacca5f0SHans Verkuil 	enum vimc_deb_rgb_colors order[2][2];
27*dacca5f0SHans Verkuil };
28*dacca5f0SHans Verkuil 
29*dacca5f0SHans Verkuil struct vimc_deb_device {
30*dacca5f0SHans Verkuil 	struct vimc_ent_device ved;
31*dacca5f0SHans Verkuil 	struct v4l2_subdev sd;
32*dacca5f0SHans Verkuil 	/* The active format */
33*dacca5f0SHans Verkuil 	struct v4l2_mbus_framefmt sink_fmt;
34*dacca5f0SHans Verkuil 	u32 src_code;
35*dacca5f0SHans Verkuil 	void (*set_rgb_src)(struct vimc_deb_device *vdeb, unsigned int lin,
36*dacca5f0SHans Verkuil 			    unsigned int col, unsigned int rgb[3]);
37*dacca5f0SHans Verkuil 	/* Values calculated when the stream starts */
38*dacca5f0SHans Verkuil 	u8 *src_frame;
39*dacca5f0SHans Verkuil 	const struct vimc_deb_pix_map *sink_pix_map;
40*dacca5f0SHans Verkuil 	unsigned int sink_bpp;
41*dacca5f0SHans Verkuil 	unsigned int mean_win_size;
42*dacca5f0SHans Verkuil 	struct v4l2_ctrl_handler hdl;
43*dacca5f0SHans Verkuil 	struct media_pad pads[2];
44*dacca5f0SHans Verkuil };
45*dacca5f0SHans Verkuil 
46*dacca5f0SHans Verkuil static const struct v4l2_mbus_framefmt sink_fmt_default = {
47*dacca5f0SHans Verkuil 	.width = 640,
48*dacca5f0SHans Verkuil 	.height = 480,
49*dacca5f0SHans Verkuil 	.code = MEDIA_BUS_FMT_SRGGB8_1X8,
50*dacca5f0SHans Verkuil 	.field = V4L2_FIELD_NONE,
51*dacca5f0SHans Verkuil 	.colorspace = V4L2_COLORSPACE_DEFAULT,
52*dacca5f0SHans Verkuil };
53*dacca5f0SHans Verkuil 
54*dacca5f0SHans Verkuil static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = {
55*dacca5f0SHans Verkuil 	{
56*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
57*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
58*dacca5f0SHans Verkuil 			   { VIMC_DEB_GREEN, VIMC_DEB_RED } }
59*dacca5f0SHans Verkuil 	},
60*dacca5f0SHans Verkuil 	{
61*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
62*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
63*dacca5f0SHans Verkuil 			   { VIMC_DEB_RED, VIMC_DEB_GREEN } }
64*dacca5f0SHans Verkuil 	},
65*dacca5f0SHans Verkuil 	{
66*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
67*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
68*dacca5f0SHans Verkuil 			   { VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
69*dacca5f0SHans Verkuil 	},
70*dacca5f0SHans Verkuil 	{
71*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
72*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
73*dacca5f0SHans Verkuil 			   { VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
74*dacca5f0SHans Verkuil 	},
75*dacca5f0SHans Verkuil 	{
76*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
77*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
78*dacca5f0SHans Verkuil 			   { VIMC_DEB_GREEN, VIMC_DEB_RED } }
79*dacca5f0SHans Verkuil 	},
80*dacca5f0SHans Verkuil 	{
81*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SGBRG10_1X10,
82*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
83*dacca5f0SHans Verkuil 			   { VIMC_DEB_RED, VIMC_DEB_GREEN } }
84*dacca5f0SHans Verkuil 	},
85*dacca5f0SHans Verkuil 	{
86*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
87*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
88*dacca5f0SHans Verkuil 			   { VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
89*dacca5f0SHans Verkuil 	},
90*dacca5f0SHans Verkuil 	{
91*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
92*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
93*dacca5f0SHans Verkuil 			   { VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
94*dacca5f0SHans Verkuil 	},
95*dacca5f0SHans Verkuil 	{
96*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
97*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
98*dacca5f0SHans Verkuil 			   { VIMC_DEB_GREEN, VIMC_DEB_RED } }
99*dacca5f0SHans Verkuil 	},
100*dacca5f0SHans Verkuil 	{
101*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
102*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
103*dacca5f0SHans Verkuil 			   { VIMC_DEB_RED, VIMC_DEB_GREEN } }
104*dacca5f0SHans Verkuil 	},
105*dacca5f0SHans Verkuil 	{
106*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
107*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
108*dacca5f0SHans Verkuil 			   { VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
109*dacca5f0SHans Verkuil 	},
110*dacca5f0SHans Verkuil 	{
111*dacca5f0SHans Verkuil 		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
112*dacca5f0SHans Verkuil 		.order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
113*dacca5f0SHans Verkuil 			   { VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
114*dacca5f0SHans Verkuil 	},
115*dacca5f0SHans Verkuil };
116*dacca5f0SHans Verkuil 
117*dacca5f0SHans Verkuil static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code(u32 code)
118*dacca5f0SHans Verkuil {
119*dacca5f0SHans Verkuil 	unsigned int i;
120*dacca5f0SHans Verkuil 
121*dacca5f0SHans Verkuil 	for (i = 0; i < ARRAY_SIZE(vimc_deb_pix_map_list); i++)
122*dacca5f0SHans Verkuil 		if (vimc_deb_pix_map_list[i].code == code)
123*dacca5f0SHans Verkuil 			return &vimc_deb_pix_map_list[i];
124*dacca5f0SHans Verkuil 
125*dacca5f0SHans Verkuil 	return NULL;
126*dacca5f0SHans Verkuil }
127*dacca5f0SHans Verkuil 
128*dacca5f0SHans Verkuil static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
129*dacca5f0SHans Verkuil 			     struct v4l2_subdev_pad_config *cfg)
130*dacca5f0SHans Verkuil {
131*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
132*dacca5f0SHans Verkuil 	struct v4l2_mbus_framefmt *mf;
133*dacca5f0SHans Verkuil 	unsigned int i;
134*dacca5f0SHans Verkuil 
135*dacca5f0SHans Verkuil 	mf = v4l2_subdev_get_try_format(sd, cfg, 0);
136*dacca5f0SHans Verkuil 	*mf = sink_fmt_default;
137*dacca5f0SHans Verkuil 
138*dacca5f0SHans Verkuil 	for (i = 1; i < sd->entity.num_pads; i++) {
139*dacca5f0SHans Verkuil 		mf = v4l2_subdev_get_try_format(sd, cfg, i);
140*dacca5f0SHans Verkuil 		*mf = sink_fmt_default;
141*dacca5f0SHans Verkuil 		mf->code = vdeb->src_code;
142*dacca5f0SHans Verkuil 	}
143*dacca5f0SHans Verkuil 
144*dacca5f0SHans Verkuil 	return 0;
145*dacca5f0SHans Verkuil }
146*dacca5f0SHans Verkuil 
147*dacca5f0SHans Verkuil static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
148*dacca5f0SHans Verkuil 				   struct v4l2_subdev_pad_config *cfg,
149*dacca5f0SHans Verkuil 				   struct v4l2_subdev_mbus_code_enum *code)
150*dacca5f0SHans Verkuil {
151*dacca5f0SHans Verkuil 	/* We only support one format for source pads */
152*dacca5f0SHans Verkuil 	if (VIMC_IS_SRC(code->pad)) {
153*dacca5f0SHans Verkuil 		struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
154*dacca5f0SHans Verkuil 
155*dacca5f0SHans Verkuil 		if (code->index)
156*dacca5f0SHans Verkuil 			return -EINVAL;
157*dacca5f0SHans Verkuil 
158*dacca5f0SHans Verkuil 		code->code = vdeb->src_code;
159*dacca5f0SHans Verkuil 	} else {
160*dacca5f0SHans Verkuil 		if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list))
161*dacca5f0SHans Verkuil 			return -EINVAL;
162*dacca5f0SHans Verkuil 
163*dacca5f0SHans Verkuil 		code->code = vimc_deb_pix_map_list[code->index].code;
164*dacca5f0SHans Verkuil 	}
165*dacca5f0SHans Verkuil 
166*dacca5f0SHans Verkuil 	return 0;
167*dacca5f0SHans Verkuil }
168*dacca5f0SHans Verkuil 
169*dacca5f0SHans Verkuil static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
170*dacca5f0SHans Verkuil 				    struct v4l2_subdev_pad_config *cfg,
171*dacca5f0SHans Verkuil 				    struct v4l2_subdev_frame_size_enum *fse)
172*dacca5f0SHans Verkuil {
173*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
174*dacca5f0SHans Verkuil 
175*dacca5f0SHans Verkuil 	if (fse->index)
176*dacca5f0SHans Verkuil 		return -EINVAL;
177*dacca5f0SHans Verkuil 
178*dacca5f0SHans Verkuil 	if (VIMC_IS_SINK(fse->pad)) {
179*dacca5f0SHans Verkuil 		const struct vimc_deb_pix_map *vpix =
180*dacca5f0SHans Verkuil 			vimc_deb_pix_map_by_code(fse->code);
181*dacca5f0SHans Verkuil 
182*dacca5f0SHans Verkuil 		if (!vpix)
183*dacca5f0SHans Verkuil 			return -EINVAL;
184*dacca5f0SHans Verkuil 	} else if (fse->code != vdeb->src_code) {
185*dacca5f0SHans Verkuil 		return -EINVAL;
186*dacca5f0SHans Verkuil 	}
187*dacca5f0SHans Verkuil 
188*dacca5f0SHans Verkuil 	fse->min_width = VIMC_FRAME_MIN_WIDTH;
189*dacca5f0SHans Verkuil 	fse->max_width = VIMC_FRAME_MAX_WIDTH;
190*dacca5f0SHans Verkuil 	fse->min_height = VIMC_FRAME_MIN_HEIGHT;
191*dacca5f0SHans Verkuil 	fse->max_height = VIMC_FRAME_MAX_HEIGHT;
192*dacca5f0SHans Verkuil 
193*dacca5f0SHans Verkuil 	return 0;
194*dacca5f0SHans Verkuil }
195*dacca5f0SHans Verkuil 
196*dacca5f0SHans Verkuil static int vimc_deb_get_fmt(struct v4l2_subdev *sd,
197*dacca5f0SHans Verkuil 			    struct v4l2_subdev_pad_config *cfg,
198*dacca5f0SHans Verkuil 			    struct v4l2_subdev_format *fmt)
199*dacca5f0SHans Verkuil {
200*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
201*dacca5f0SHans Verkuil 
202*dacca5f0SHans Verkuil 	/* Get the current sink format */
203*dacca5f0SHans Verkuil 	fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
204*dacca5f0SHans Verkuil 		      *v4l2_subdev_get_try_format(sd, cfg, 0) :
205*dacca5f0SHans Verkuil 		      vdeb->sink_fmt;
206*dacca5f0SHans Verkuil 
207*dacca5f0SHans Verkuil 	/* Set the right code for the source pad */
208*dacca5f0SHans Verkuil 	if (VIMC_IS_SRC(fmt->pad))
209*dacca5f0SHans Verkuil 		fmt->format.code = vdeb->src_code;
210*dacca5f0SHans Verkuil 
211*dacca5f0SHans Verkuil 	return 0;
212*dacca5f0SHans Verkuil }
213*dacca5f0SHans Verkuil 
214*dacca5f0SHans Verkuil static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
215*dacca5f0SHans Verkuil {
216*dacca5f0SHans Verkuil 	const struct vimc_deb_pix_map *vpix;
217*dacca5f0SHans Verkuil 
218*dacca5f0SHans Verkuil 	/* Don't accept a code that is not on the debayer table */
219*dacca5f0SHans Verkuil 	vpix = vimc_deb_pix_map_by_code(fmt->code);
220*dacca5f0SHans Verkuil 	if (!vpix)
221*dacca5f0SHans Verkuil 		fmt->code = sink_fmt_default.code;
222*dacca5f0SHans Verkuil 
223*dacca5f0SHans Verkuil 	fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH,
224*dacca5f0SHans Verkuil 			     VIMC_FRAME_MAX_WIDTH) & ~1;
225*dacca5f0SHans Verkuil 	fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT,
226*dacca5f0SHans Verkuil 			      VIMC_FRAME_MAX_HEIGHT) & ~1;
227*dacca5f0SHans Verkuil 
228*dacca5f0SHans Verkuil 	if (fmt->field == V4L2_FIELD_ANY)
229*dacca5f0SHans Verkuil 		fmt->field = sink_fmt_default.field;
230*dacca5f0SHans Verkuil 
231*dacca5f0SHans Verkuil 	vimc_colorimetry_clamp(fmt);
232*dacca5f0SHans Verkuil }
233*dacca5f0SHans Verkuil 
234*dacca5f0SHans Verkuil static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
235*dacca5f0SHans Verkuil 			    struct v4l2_subdev_pad_config *cfg,
236*dacca5f0SHans Verkuil 			    struct v4l2_subdev_format *fmt)
237*dacca5f0SHans Verkuil {
238*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
239*dacca5f0SHans Verkuil 	struct v4l2_mbus_framefmt *sink_fmt;
240*dacca5f0SHans Verkuil 
241*dacca5f0SHans Verkuil 	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
242*dacca5f0SHans Verkuil 		/* Do not change the format while stream is on */
243*dacca5f0SHans Verkuil 		if (vdeb->src_frame)
244*dacca5f0SHans Verkuil 			return -EBUSY;
245*dacca5f0SHans Verkuil 
246*dacca5f0SHans Verkuil 		sink_fmt = &vdeb->sink_fmt;
247*dacca5f0SHans Verkuil 	} else {
248*dacca5f0SHans Verkuil 		sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
249*dacca5f0SHans Verkuil 	}
250*dacca5f0SHans Verkuil 
251*dacca5f0SHans Verkuil 	/*
252*dacca5f0SHans Verkuil 	 * Do not change the format of the source pad,
253*dacca5f0SHans Verkuil 	 * it is propagated from the sink
254*dacca5f0SHans Verkuil 	 */
255*dacca5f0SHans Verkuil 	if (VIMC_IS_SRC(fmt->pad)) {
256*dacca5f0SHans Verkuil 		fmt->format = *sink_fmt;
257*dacca5f0SHans Verkuil 		/* TODO: Add support for other formats */
258*dacca5f0SHans Verkuil 		fmt->format.code = vdeb->src_code;
259*dacca5f0SHans Verkuil 	} else {
260*dacca5f0SHans Verkuil 		/* Set the new format in the sink pad */
261*dacca5f0SHans Verkuil 		vimc_deb_adjust_sink_fmt(&fmt->format);
262*dacca5f0SHans Verkuil 
263*dacca5f0SHans Verkuil 		dev_dbg(vdeb->ved.dev, "%s: sink format update: "
264*dacca5f0SHans Verkuil 			"old:%dx%d (0x%x, %d, %d, %d, %d) "
265*dacca5f0SHans Verkuil 			"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name,
266*dacca5f0SHans Verkuil 			/* old */
267*dacca5f0SHans Verkuil 			sink_fmt->width, sink_fmt->height, sink_fmt->code,
268*dacca5f0SHans Verkuil 			sink_fmt->colorspace, sink_fmt->quantization,
269*dacca5f0SHans Verkuil 			sink_fmt->xfer_func, sink_fmt->ycbcr_enc,
270*dacca5f0SHans Verkuil 			/* new */
271*dacca5f0SHans Verkuil 			fmt->format.width, fmt->format.height, fmt->format.code,
272*dacca5f0SHans Verkuil 			fmt->format.colorspace,	fmt->format.quantization,
273*dacca5f0SHans Verkuil 			fmt->format.xfer_func, fmt->format.ycbcr_enc);
274*dacca5f0SHans Verkuil 
275*dacca5f0SHans Verkuil 		*sink_fmt = fmt->format;
276*dacca5f0SHans Verkuil 	}
277*dacca5f0SHans Verkuil 
278*dacca5f0SHans Verkuil 	return 0;
279*dacca5f0SHans Verkuil }
280*dacca5f0SHans Verkuil 
281*dacca5f0SHans Verkuil static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = {
282*dacca5f0SHans Verkuil 	.init_cfg		= vimc_deb_init_cfg,
283*dacca5f0SHans Verkuil 	.enum_mbus_code		= vimc_deb_enum_mbus_code,
284*dacca5f0SHans Verkuil 	.enum_frame_size	= vimc_deb_enum_frame_size,
285*dacca5f0SHans Verkuil 	.get_fmt		= vimc_deb_get_fmt,
286*dacca5f0SHans Verkuil 	.set_fmt		= vimc_deb_set_fmt,
287*dacca5f0SHans Verkuil };
288*dacca5f0SHans Verkuil 
289*dacca5f0SHans Verkuil static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb,
290*dacca5f0SHans Verkuil 						  unsigned int lin,
291*dacca5f0SHans Verkuil 						  unsigned int col,
292*dacca5f0SHans Verkuil 						  unsigned int rgb[3])
293*dacca5f0SHans Verkuil {
294*dacca5f0SHans Verkuil 	unsigned int i, index;
295*dacca5f0SHans Verkuil 
296*dacca5f0SHans Verkuil 	index = VIMC_FRAME_INDEX(lin, col, vdeb->sink_fmt.width, 3);
297*dacca5f0SHans Verkuil 	for (i = 0; i < 3; i++)
298*dacca5f0SHans Verkuil 		vdeb->src_frame[index + i] = rgb[i];
299*dacca5f0SHans Verkuil }
300*dacca5f0SHans Verkuil 
301*dacca5f0SHans Verkuil static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
302*dacca5f0SHans Verkuil {
303*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
304*dacca5f0SHans Verkuil 
305*dacca5f0SHans Verkuil 	if (enable) {
306*dacca5f0SHans Verkuil 		const struct vimc_pix_map *vpix;
307*dacca5f0SHans Verkuil 		unsigned int frame_size;
308*dacca5f0SHans Verkuil 
309*dacca5f0SHans Verkuil 		if (vdeb->src_frame)
310*dacca5f0SHans Verkuil 			return 0;
311*dacca5f0SHans Verkuil 
312*dacca5f0SHans Verkuil 		/* Calculate the frame size of the source pad */
313*dacca5f0SHans Verkuil 		vpix = vimc_pix_map_by_code(vdeb->src_code);
314*dacca5f0SHans Verkuil 		frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height *
315*dacca5f0SHans Verkuil 				vpix->bpp;
316*dacca5f0SHans Verkuil 
317*dacca5f0SHans Verkuil 		/* Save the bytes per pixel of the sink */
318*dacca5f0SHans Verkuil 		vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code);
319*dacca5f0SHans Verkuil 		vdeb->sink_bpp = vpix->bpp;
320*dacca5f0SHans Verkuil 
321*dacca5f0SHans Verkuil 		/* Get the corresponding pixel map from the table */
322*dacca5f0SHans Verkuil 		vdeb->sink_pix_map =
323*dacca5f0SHans Verkuil 			vimc_deb_pix_map_by_code(vdeb->sink_fmt.code);
324*dacca5f0SHans Verkuil 
325*dacca5f0SHans Verkuil 		/*
326*dacca5f0SHans Verkuil 		 * Allocate the frame buffer. Use vmalloc to be able to
327*dacca5f0SHans Verkuil 		 * allocate a large amount of memory
328*dacca5f0SHans Verkuil 		 */
329*dacca5f0SHans Verkuil 		vdeb->src_frame = vmalloc(frame_size);
330*dacca5f0SHans Verkuil 		if (!vdeb->src_frame)
331*dacca5f0SHans Verkuil 			return -ENOMEM;
332*dacca5f0SHans Verkuil 
333*dacca5f0SHans Verkuil 	} else {
334*dacca5f0SHans Verkuil 		if (!vdeb->src_frame)
335*dacca5f0SHans Verkuil 			return 0;
336*dacca5f0SHans Verkuil 
337*dacca5f0SHans Verkuil 		vfree(vdeb->src_frame);
338*dacca5f0SHans Verkuil 		vdeb->src_frame = NULL;
339*dacca5f0SHans Verkuil 	}
340*dacca5f0SHans Verkuil 
341*dacca5f0SHans Verkuil 	return 0;
342*dacca5f0SHans Verkuil }
343*dacca5f0SHans Verkuil 
344*dacca5f0SHans Verkuil static const struct v4l2_subdev_core_ops vimc_deb_core_ops = {
345*dacca5f0SHans Verkuil 	.log_status = v4l2_ctrl_subdev_log_status,
346*dacca5f0SHans Verkuil 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
347*dacca5f0SHans Verkuil 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
348*dacca5f0SHans Verkuil };
349*dacca5f0SHans Verkuil 
350*dacca5f0SHans Verkuil static const struct v4l2_subdev_video_ops vimc_deb_video_ops = {
351*dacca5f0SHans Verkuil 	.s_stream = vimc_deb_s_stream,
352*dacca5f0SHans Verkuil };
353*dacca5f0SHans Verkuil 
354*dacca5f0SHans Verkuil static const struct v4l2_subdev_ops vimc_deb_ops = {
355*dacca5f0SHans Verkuil 	.core = &vimc_deb_core_ops,
356*dacca5f0SHans Verkuil 	.pad = &vimc_deb_pad_ops,
357*dacca5f0SHans Verkuil 	.video = &vimc_deb_video_ops,
358*dacca5f0SHans Verkuil };
359*dacca5f0SHans Verkuil 
360*dacca5f0SHans Verkuil static unsigned int vimc_deb_get_val(const u8 *bytes,
361*dacca5f0SHans Verkuil 				     const unsigned int n_bytes)
362*dacca5f0SHans Verkuil {
363*dacca5f0SHans Verkuil 	unsigned int i;
364*dacca5f0SHans Verkuil 	unsigned int acc = 0;
365*dacca5f0SHans Verkuil 
366*dacca5f0SHans Verkuil 	for (i = 0; i < n_bytes; i++)
367*dacca5f0SHans Verkuil 		acc = acc + (bytes[i] << (8 * i));
368*dacca5f0SHans Verkuil 
369*dacca5f0SHans Verkuil 	return acc;
370*dacca5f0SHans Verkuil }
371*dacca5f0SHans Verkuil 
372*dacca5f0SHans Verkuil static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
373*dacca5f0SHans Verkuil 				   const u8 *frame,
374*dacca5f0SHans Verkuil 				   const unsigned int lin,
375*dacca5f0SHans Verkuil 				   const unsigned int col,
376*dacca5f0SHans Verkuil 				   unsigned int rgb[3])
377*dacca5f0SHans Verkuil {
378*dacca5f0SHans Verkuil 	unsigned int i, seek, wlin, wcol;
379*dacca5f0SHans Verkuil 	unsigned int n_rgb[3] = {0, 0, 0};
380*dacca5f0SHans Verkuil 
381*dacca5f0SHans Verkuil 	for (i = 0; i < 3; i++)
382*dacca5f0SHans Verkuil 		rgb[i] = 0;
383*dacca5f0SHans Verkuil 
384*dacca5f0SHans Verkuil 	/*
385*dacca5f0SHans Verkuil 	 * Calculate how many we need to subtract to get to the pixel in
386*dacca5f0SHans Verkuil 	 * the top left corner of the mean window (considering the current
387*dacca5f0SHans Verkuil 	 * pixel as the center)
388*dacca5f0SHans Verkuil 	 */
389*dacca5f0SHans Verkuil 	seek = vdeb->mean_win_size / 2;
390*dacca5f0SHans Verkuil 
391*dacca5f0SHans Verkuil 	/* Sum the values of the colors in the mean window */
392*dacca5f0SHans Verkuil 
393*dacca5f0SHans Verkuil 	dev_dbg(vdeb->ved.dev,
394*dacca5f0SHans Verkuil 		"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n",
395*dacca5f0SHans Verkuil 		vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek);
396*dacca5f0SHans Verkuil 
397*dacca5f0SHans Verkuil 	/*
398*dacca5f0SHans Verkuil 	 * Iterate through all the lines in the mean window, start
399*dacca5f0SHans Verkuil 	 * with zero if the pixel is outside the frame and don't pass
400*dacca5f0SHans Verkuil 	 * the height when the pixel is in the bottom border of the
401*dacca5f0SHans Verkuil 	 * frame
402*dacca5f0SHans Verkuil 	 */
403*dacca5f0SHans Verkuil 	for (wlin = seek > lin ? 0 : lin - seek;
404*dacca5f0SHans Verkuil 	     wlin < lin + seek + 1 && wlin < vdeb->sink_fmt.height;
405*dacca5f0SHans Verkuil 	     wlin++) {
406*dacca5f0SHans Verkuil 
407*dacca5f0SHans Verkuil 		/*
408*dacca5f0SHans Verkuil 		 * Iterate through all the columns in the mean window, start
409*dacca5f0SHans Verkuil 		 * with zero if the pixel is outside the frame and don't pass
410*dacca5f0SHans Verkuil 		 * the width when the pixel is in the right border of the
411*dacca5f0SHans Verkuil 		 * frame
412*dacca5f0SHans Verkuil 		 */
413*dacca5f0SHans Verkuil 		for (wcol = seek > col ? 0 : col - seek;
414*dacca5f0SHans Verkuil 		     wcol < col + seek + 1 && wcol < vdeb->sink_fmt.width;
415*dacca5f0SHans Verkuil 		     wcol++) {
416*dacca5f0SHans Verkuil 			enum vimc_deb_rgb_colors color;
417*dacca5f0SHans Verkuil 			unsigned int index;
418*dacca5f0SHans Verkuil 
419*dacca5f0SHans Verkuil 			/* Check which color this pixel is */
420*dacca5f0SHans Verkuil 			color = vdeb->sink_pix_map->order[wlin % 2][wcol % 2];
421*dacca5f0SHans Verkuil 
422*dacca5f0SHans Verkuil 			index = VIMC_FRAME_INDEX(wlin, wcol,
423*dacca5f0SHans Verkuil 						 vdeb->sink_fmt.width,
424*dacca5f0SHans Verkuil 						 vdeb->sink_bpp);
425*dacca5f0SHans Verkuil 
426*dacca5f0SHans Verkuil 			dev_dbg(vdeb->ved.dev,
427*dacca5f0SHans Verkuil 				"deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n",
428*dacca5f0SHans Verkuil 				vdeb->sd.name, index, wlin, wcol, color);
429*dacca5f0SHans Verkuil 
430*dacca5f0SHans Verkuil 			/* Get its value */
431*dacca5f0SHans Verkuil 			rgb[color] = rgb[color] +
432*dacca5f0SHans Verkuil 				vimc_deb_get_val(&frame[index], vdeb->sink_bpp);
433*dacca5f0SHans Verkuil 
434*dacca5f0SHans Verkuil 			/* Save how many values we already added */
435*dacca5f0SHans Verkuil 			n_rgb[color]++;
436*dacca5f0SHans Verkuil 
437*dacca5f0SHans Verkuil 			dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n",
438*dacca5f0SHans Verkuil 				vdeb->sd.name, rgb[color], n_rgb[color]);
439*dacca5f0SHans Verkuil 		}
440*dacca5f0SHans Verkuil 	}
441*dacca5f0SHans Verkuil 
442*dacca5f0SHans Verkuil 	/* Calculate the mean */
443*dacca5f0SHans Verkuil 	for (i = 0; i < 3; i++) {
444*dacca5f0SHans Verkuil 		dev_dbg(vdeb->ved.dev,
445*dacca5f0SHans Verkuil 			"deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n",
446*dacca5f0SHans Verkuil 			vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]);
447*dacca5f0SHans Verkuil 
448*dacca5f0SHans Verkuil 		if (n_rgb[i])
449*dacca5f0SHans Verkuil 			rgb[i] = rgb[i] / n_rgb[i];
450*dacca5f0SHans Verkuil 
451*dacca5f0SHans Verkuil 		dev_dbg(vdeb->ved.dev,
452*dacca5f0SHans Verkuil 			"deb: %s: FINAL CALC: %dx%d Color %d, val %d\n",
453*dacca5f0SHans Verkuil 			vdeb->sd.name, lin, col, i, rgb[i]);
454*dacca5f0SHans Verkuil 	}
455*dacca5f0SHans Verkuil }
456*dacca5f0SHans Verkuil 
457*dacca5f0SHans Verkuil static void *vimc_deb_process_frame(struct vimc_ent_device *ved,
458*dacca5f0SHans Verkuil 				    const void *sink_frame)
459*dacca5f0SHans Verkuil {
460*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device,
461*dacca5f0SHans Verkuil 						    ved);
462*dacca5f0SHans Verkuil 	unsigned int rgb[3];
463*dacca5f0SHans Verkuil 	unsigned int i, j;
464*dacca5f0SHans Verkuil 
465*dacca5f0SHans Verkuil 	/* If the stream in this node is not active, just return */
466*dacca5f0SHans Verkuil 	if (!vdeb->src_frame)
467*dacca5f0SHans Verkuil 		return ERR_PTR(-EINVAL);
468*dacca5f0SHans Verkuil 
469*dacca5f0SHans Verkuil 	for (i = 0; i < vdeb->sink_fmt.height; i++)
470*dacca5f0SHans Verkuil 		for (j = 0; j < vdeb->sink_fmt.width; j++) {
471*dacca5f0SHans Verkuil 			vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb);
472*dacca5f0SHans Verkuil 			vdeb->set_rgb_src(vdeb, i, j, rgb);
473*dacca5f0SHans Verkuil 		}
474*dacca5f0SHans Verkuil 
475*dacca5f0SHans Verkuil 	return vdeb->src_frame;
476*dacca5f0SHans Verkuil }
477*dacca5f0SHans Verkuil 
478*dacca5f0SHans Verkuil static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl)
479*dacca5f0SHans Verkuil {
480*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb =
481*dacca5f0SHans Verkuil 		container_of(ctrl->handler, struct vimc_deb_device, hdl);
482*dacca5f0SHans Verkuil 
483*dacca5f0SHans Verkuil 	switch (ctrl->id) {
484*dacca5f0SHans Verkuil 	case VIMC_CID_MEAN_WIN_SIZE:
485*dacca5f0SHans Verkuil 		vdeb->mean_win_size = ctrl->val;
486*dacca5f0SHans Verkuil 		break;
487*dacca5f0SHans Verkuil 	default:
488*dacca5f0SHans Verkuil 		return -EINVAL;
489*dacca5f0SHans Verkuil 	}
490*dacca5f0SHans Verkuil 	return 0;
491*dacca5f0SHans Verkuil }
492*dacca5f0SHans Verkuil 
493*dacca5f0SHans Verkuil static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = {
494*dacca5f0SHans Verkuil 	.s_ctrl = vimc_deb_s_ctrl,
495*dacca5f0SHans Verkuil };
496*dacca5f0SHans Verkuil 
497*dacca5f0SHans Verkuil static void vimc_deb_release(struct vimc_ent_device *ved)
498*dacca5f0SHans Verkuil {
499*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb =
500*dacca5f0SHans Verkuil 		container_of(ved, struct vimc_deb_device, ved);
501*dacca5f0SHans Verkuil 
502*dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&vdeb->hdl);
503*dacca5f0SHans Verkuil 	media_entity_cleanup(vdeb->ved.ent);
504*dacca5f0SHans Verkuil 	kfree(vdeb);
505*dacca5f0SHans Verkuil }
506*dacca5f0SHans Verkuil 
507*dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vimc_deb_ctrl_class = {
508*dacca5f0SHans Verkuil 	.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
509*dacca5f0SHans Verkuil 	.id = VIMC_CID_VIMC_CLASS,
510*dacca5f0SHans Verkuil 	.name = "VIMC Controls",
511*dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_CTRL_CLASS,
512*dacca5f0SHans Verkuil };
513*dacca5f0SHans Verkuil 
514*dacca5f0SHans Verkuil static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = {
515*dacca5f0SHans Verkuil 	.ops = &vimc_deb_ctrl_ops,
516*dacca5f0SHans Verkuil 	.id = VIMC_CID_MEAN_WIN_SIZE,
517*dacca5f0SHans Verkuil 	.name = "Debayer Mean Window Size",
518*dacca5f0SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
519*dacca5f0SHans Verkuil 	.min = 1,
520*dacca5f0SHans Verkuil 	.max = 25,
521*dacca5f0SHans Verkuil 	.step = 2,
522*dacca5f0SHans Verkuil 	.def = 3,
523*dacca5f0SHans Verkuil };
524*dacca5f0SHans Verkuil 
525*dacca5f0SHans Verkuil static struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
526*dacca5f0SHans Verkuil 					    const char *vcfg_name)
527*dacca5f0SHans Verkuil {
528*dacca5f0SHans Verkuil 	struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
529*dacca5f0SHans Verkuil 	struct vimc_deb_device *vdeb;
530*dacca5f0SHans Verkuil 	int ret;
531*dacca5f0SHans Verkuil 
532*dacca5f0SHans Verkuil 	/* Allocate the vdeb struct */
533*dacca5f0SHans Verkuil 	vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL);
534*dacca5f0SHans Verkuil 	if (!vdeb)
535*dacca5f0SHans Verkuil 		return ERR_PTR(-ENOMEM);
536*dacca5f0SHans Verkuil 
537*dacca5f0SHans Verkuil 	/* Create controls: */
538*dacca5f0SHans Verkuil 	v4l2_ctrl_handler_init(&vdeb->hdl, 2);
539*dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL);
540*dacca5f0SHans Verkuil 	v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL);
541*dacca5f0SHans Verkuil 	vdeb->sd.ctrl_handler = &vdeb->hdl;
542*dacca5f0SHans Verkuil 	if (vdeb->hdl.error) {
543*dacca5f0SHans Verkuil 		ret = vdeb->hdl.error;
544*dacca5f0SHans Verkuil 		goto err_free_vdeb;
545*dacca5f0SHans Verkuil 	}
546*dacca5f0SHans Verkuil 
547*dacca5f0SHans Verkuil 	/* Initialize ved and sd */
548*dacca5f0SHans Verkuil 	vdeb->pads[0].flags = MEDIA_PAD_FL_SINK;
549*dacca5f0SHans Verkuil 	vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE;
550*dacca5f0SHans Verkuil 
551*dacca5f0SHans Verkuil 	ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev,
552*dacca5f0SHans Verkuil 				   vcfg_name,
553*dacca5f0SHans Verkuil 				   MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
554*dacca5f0SHans Verkuil 				   vdeb->pads, &vimc_deb_ops);
555*dacca5f0SHans Verkuil 	if (ret)
556*dacca5f0SHans Verkuil 		goto err_free_hdl;
557*dacca5f0SHans Verkuil 
558*dacca5f0SHans Verkuil 	vdeb->ved.process_frame = vimc_deb_process_frame;
559*dacca5f0SHans Verkuil 	vdeb->ved.dev = vimc->mdev.dev;
560*dacca5f0SHans Verkuil 	vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def;
561*dacca5f0SHans Verkuil 
562*dacca5f0SHans Verkuil 	/* Initialize the frame format */
563*dacca5f0SHans Verkuil 	vdeb->sink_fmt = sink_fmt_default;
564*dacca5f0SHans Verkuil 	/*
565*dacca5f0SHans Verkuil 	 * TODO: Add support for more output formats, we only support
566*dacca5f0SHans Verkuil 	 * RGB888 for now
567*dacca5f0SHans Verkuil 	 * NOTE: the src format is always the same as the sink, except
568*dacca5f0SHans Verkuil 	 * for the code
569*dacca5f0SHans Verkuil 	 */
570*dacca5f0SHans Verkuil 	vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24;
571*dacca5f0SHans Verkuil 	vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24;
572*dacca5f0SHans Verkuil 
573*dacca5f0SHans Verkuil 	return &vdeb->ved;
574*dacca5f0SHans Verkuil 
575*dacca5f0SHans Verkuil err_free_hdl:
576*dacca5f0SHans Verkuil 	v4l2_ctrl_handler_free(&vdeb->hdl);
577*dacca5f0SHans Verkuil err_free_vdeb:
578*dacca5f0SHans Verkuil 	kfree(vdeb);
579*dacca5f0SHans Verkuil 
580*dacca5f0SHans Verkuil 	return ERR_PTR(ret);
581*dacca5f0SHans Verkuil }
582*dacca5f0SHans Verkuil 
583*dacca5f0SHans Verkuil struct vimc_ent_type vimc_deb_type = {
584*dacca5f0SHans Verkuil 	.add = vimc_deb_add,
585*dacca5f0SHans Verkuil 	.release = vimc_deb_release
586*dacca5f0SHans Verkuil };
587