xref: /linux/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c (revision 4b660dbd9ee2059850fd30e0df420ca7a38a1856)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for STM32 Digital Camera Memory Interface Pixel Processor
4  *
5  * Copyright (C) STMicroelectronics SA 2023
6  * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
7  *          Alain Volmat <alain.volmat@foss.st.com>
8  *          for STMicroelectronics.
9  */
10 
11 #include <linux/v4l2-mediabus.h>
12 #include <media/v4l2-event.h>
13 #include <media/v4l2-subdev.h>
14 
15 #include "dcmipp-common.h"
16 
17 #define DCMIPP_PRCR	0x104
18 #define DCMIPP_PRCR_FORMAT_SHIFT	16
19 #define DCMIPP_PRCR_FORMAT_YUV422	0x1e
20 #define DCMIPP_PRCR_FORMAT_RGB565	0x22
21 #define DCMIPP_PRCR_FORMAT_RAW8		0x2a
22 #define DCMIPP_PRCR_FORMAT_G8		0x4a
23 #define DCMIPP_PRCR_FORMAT_BYTE_STREAM	0x5a
24 #define DCMIPP_PRCR_ESS			BIT(4)
25 #define DCMIPP_PRCR_PCKPOL		BIT(5)
26 #define DCMIPP_PRCR_HSPOL		BIT(6)
27 #define DCMIPP_PRCR_VSPOL		BIT(7)
28 #define DCMIPP_PRCR_ENABLE		BIT(14)
29 #define DCMIPP_PRCR_SWAPCYCLES		BIT(25)
30 
31 #define DCMIPP_PRESCR	0x108
32 #define DCMIPP_PRESUR	0x10c
33 
34 #define IS_SINK(pad) (!(pad))
35 #define IS_SRC(pad)  ((pad))
36 
37 struct dcmipp_par_pix_map {
38 	unsigned int code_sink;
39 	unsigned int code_src;
40 	u8 prcr_format;
41 	u8 prcr_swapcycles;
42 };
43 
44 #define PIXMAP_SINK_SRC_PRCR_SWAP(sink, src, prcr, swap)	\
45 	{							\
46 		.code_sink = MEDIA_BUS_FMT_##sink,		\
47 		.code_src = MEDIA_BUS_FMT_##src,		\
48 		.prcr_format = DCMIPP_PRCR_FORMAT_##prcr,	\
49 		.prcr_swapcycles = swap,			\
50 	}
51 static const struct dcmipp_par_pix_map dcmipp_par_pix_map_list[] = {
52 	/* RGB565 */
53 	PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1),
54 	PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0),
55 	/* YUV422 */
56 	PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1),
57 	PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, UYVY8_2X8, YUV422, 0),
58 	PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, UYVY8_2X8, YUV422, 1),
59 	PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, YUYV8_2X8, YUV422, 0),
60 	PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_2X8, YVYU8_2X8, YUV422, 1),
61 	PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_2X8, VYUY8_2X8, YUV422, 1),
62 	/* GREY */
63 	PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0),
64 	/* Raw Bayer */
65 	PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0),
66 	PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0),
67 	PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG8_1X8, SGRBG8_1X8, RAW8, 0),
68 	PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB8_1X8, SRGGB8_1X8, RAW8, 0),
69 	/* JPEG */
70 	PIXMAP_SINK_SRC_PRCR_SWAP(JPEG_1X8, JPEG_1X8, BYTE_STREAM, 0),
71 };
72 
73 /*
74  * Search through the pix_map table, skipping two consecutive entry with the
75  * same code
76  */
77 static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_index
78 						(unsigned int index,
79 						 unsigned int pad)
80 {
81 	unsigned int i = 0;
82 	u32 prev_code = 0, cur_code;
83 
84 	while (i < ARRAY_SIZE(dcmipp_par_pix_map_list)) {
85 		if (IS_SRC(pad))
86 			cur_code = dcmipp_par_pix_map_list[i].code_src;
87 		else
88 			cur_code = dcmipp_par_pix_map_list[i].code_sink;
89 
90 		if (cur_code == prev_code) {
91 			i++;
92 			continue;
93 		}
94 		prev_code = cur_code;
95 
96 		if (index == 0)
97 			break;
98 		i++;
99 		index--;
100 	}
101 
102 	if (i >= ARRAY_SIZE(dcmipp_par_pix_map_list))
103 		return NULL;
104 
105 	return &dcmipp_par_pix_map_list[i];
106 }
107 
108 static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_code
109 					(u32 code_sink, u32 code_src)
110 {
111 	unsigned int i;
112 
113 	for (i = 0; i < ARRAY_SIZE(dcmipp_par_pix_map_list); i++) {
114 		if ((dcmipp_par_pix_map_list[i].code_sink == code_sink &&
115 		     dcmipp_par_pix_map_list[i].code_src == code_src) ||
116 		    (dcmipp_par_pix_map_list[i].code_sink == code_src &&
117 		     dcmipp_par_pix_map_list[i].code_src == code_sink) ||
118 		    (dcmipp_par_pix_map_list[i].code_sink == code_sink &&
119 		     code_src == 0) ||
120 		    (code_sink == 0 &&
121 		     dcmipp_par_pix_map_list[i].code_src == code_src))
122 			return &dcmipp_par_pix_map_list[i];
123 	}
124 	return NULL;
125 }
126 
127 struct dcmipp_par_device {
128 	struct dcmipp_ent_device ved;
129 	struct v4l2_subdev sd;
130 	struct device *dev;
131 	void __iomem *regs;
132 	bool streaming;
133 };
134 
135 static const struct v4l2_mbus_framefmt fmt_default = {
136 	.width = DCMIPP_FMT_WIDTH_DEFAULT,
137 	.height = DCMIPP_FMT_HEIGHT_DEFAULT,
138 	.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
139 	.field = V4L2_FIELD_NONE,
140 	.colorspace = DCMIPP_COLORSPACE_DEFAULT,
141 	.ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
142 	.quantization = DCMIPP_QUANTIZATION_DEFAULT,
143 	.xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
144 };
145 
146 static int dcmipp_par_init_state(struct v4l2_subdev *sd,
147 				 struct v4l2_subdev_state *sd_state)
148 {
149 	unsigned int i;
150 
151 	for (i = 0; i < sd->entity.num_pads; i++) {
152 		struct v4l2_mbus_framefmt *mf;
153 
154 		mf = v4l2_subdev_state_get_format(sd_state, i);
155 		*mf = fmt_default;
156 	}
157 
158 	return 0;
159 }
160 
161 static int dcmipp_par_enum_mbus_code(struct v4l2_subdev *sd,
162 				     struct v4l2_subdev_state *sd_state,
163 				     struct v4l2_subdev_mbus_code_enum *code)
164 {
165 	const struct dcmipp_par_pix_map *vpix =
166 		dcmipp_par_pix_map_by_index(code->index, code->pad);
167 
168 	if (!vpix)
169 		return -EINVAL;
170 
171 	code->code = IS_SRC(code->pad) ? vpix->code_src : vpix->code_sink;
172 
173 	return 0;
174 }
175 
176 static int dcmipp_par_enum_frame_size(struct v4l2_subdev *sd,
177 				      struct v4l2_subdev_state *sd_state,
178 				      struct v4l2_subdev_frame_size_enum *fse)
179 {
180 	const struct dcmipp_par_pix_map *vpix;
181 
182 	if (fse->index)
183 		return -EINVAL;
184 
185 	/* Only accept code in the pix map table */
186 	vpix = dcmipp_par_pix_map_by_code(IS_SINK(fse->pad) ? fse->code : 0,
187 					  IS_SRC(fse->pad) ? fse->code : 0);
188 	if (!vpix)
189 		return -EINVAL;
190 
191 	fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
192 	fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
193 	fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
194 	fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
195 
196 	return 0;
197 }
198 
199 static void dcmipp_par_adjust_fmt(struct dcmipp_par_device *par,
200 				  struct v4l2_mbus_framefmt *fmt, __u32 pad)
201 {
202 	const struct dcmipp_par_pix_map *vpix;
203 
204 	/* Only accept code in the pix map table */
205 	vpix = dcmipp_par_pix_map_by_code(IS_SINK(pad) ? fmt->code : 0,
206 					  IS_SRC(pad) ? fmt->code : 0);
207 	if (!vpix)
208 		fmt->code = fmt_default.code;
209 
210 	/* Exclude JPEG if BT656 bus is selected */
211 	if (vpix && vpix->code_sink == MEDIA_BUS_FMT_JPEG_1X8 &&
212 	    par->ved.bus_type == V4L2_MBUS_BT656)
213 		fmt->code = fmt_default.code;
214 
215 	fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
216 			     DCMIPP_FRAME_MAX_WIDTH) & ~1;
217 	fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
218 			      DCMIPP_FRAME_MAX_HEIGHT) & ~1;
219 
220 	if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
221 		fmt->field = fmt_default.field;
222 
223 	dcmipp_colorimetry_clamp(fmt);
224 }
225 
226 static int dcmipp_par_set_fmt(struct v4l2_subdev *sd,
227 			      struct v4l2_subdev_state *sd_state,
228 			      struct v4l2_subdev_format *fmt)
229 {
230 	struct dcmipp_par_device *par = v4l2_get_subdevdata(sd);
231 	struct v4l2_mbus_framefmt *mf;
232 
233 	if (par->streaming)
234 		return -EBUSY;
235 
236 	mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
237 
238 	/* Set the new format */
239 	dcmipp_par_adjust_fmt(par, &fmt->format, fmt->pad);
240 
241 	dev_dbg(par->dev, "%s: format update: old:%dx%d (0x%x, %d, %d, %d, %d) new:%dx%d (0x%x, %d, %d, %d, %d)\n",
242 		par->sd.name,
243 		/* old */
244 		mf->width, mf->height, mf->code,
245 		mf->colorspace,	mf->quantization,
246 		mf->xfer_func, mf->ycbcr_enc,
247 		/* new */
248 		fmt->format.width, fmt->format.height, fmt->format.code,
249 		fmt->format.colorspace, fmt->format.quantization,
250 		fmt->format.xfer_func, fmt->format.ycbcr_enc);
251 
252 	*mf = fmt->format;
253 
254 	/* When setting the sink format, report that format on the src pad */
255 	if (IS_SINK(fmt->pad)) {
256 		mf = v4l2_subdev_state_get_format(sd_state, 1);
257 		*mf = fmt->format;
258 		dcmipp_par_adjust_fmt(par, mf, 1);
259 	}
260 
261 	return 0;
262 }
263 
264 static const struct v4l2_subdev_pad_ops dcmipp_par_pad_ops = {
265 	.enum_mbus_code		= dcmipp_par_enum_mbus_code,
266 	.enum_frame_size	= dcmipp_par_enum_frame_size,
267 	.get_fmt		= v4l2_subdev_get_fmt,
268 	.set_fmt		= dcmipp_par_set_fmt,
269 };
270 
271 static int dcmipp_par_configure(struct dcmipp_par_device *par)
272 {
273 	u32 val = 0;
274 	const struct dcmipp_par_pix_map *vpix;
275 	struct v4l2_subdev_state *state;
276 	struct v4l2_mbus_framefmt *sink_fmt;
277 	struct v4l2_mbus_framefmt *src_fmt;
278 
279 	/* Set vertical synchronization polarity */
280 	if (par->ved.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
281 		val |= DCMIPP_PRCR_VSPOL;
282 
283 	/* Set horizontal synchronization polarity */
284 	if (par->ved.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
285 		val |= DCMIPP_PRCR_HSPOL;
286 
287 	/* Set pixel clock polarity */
288 	if (par->ved.bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
289 		val |= DCMIPP_PRCR_PCKPOL;
290 
291 	/*
292 	 * BT656 embedded synchronisation bus mode.
293 	 *
294 	 * Default SAV/EAV mode is supported here with default codes
295 	 * SAV=0xff000080 & EAV=0xff00009d.
296 	 * With DCMIPP this means LSC=SAV=0x80 & LEC=EAV=0x9d.
297 	 */
298 	if (par->ved.bus_type == V4L2_MBUS_BT656) {
299 		val |= DCMIPP_PRCR_ESS;
300 
301 		/* Unmask all codes */
302 		reg_write(par, DCMIPP_PRESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */
303 
304 		/* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */
305 		reg_write(par, DCMIPP_PRESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */
306 	}
307 
308 	/* Set format */
309 	state = v4l2_subdev_lock_and_get_active_state(&par->sd);
310 	sink_fmt = v4l2_subdev_state_get_format(state, 0);
311 	src_fmt = v4l2_subdev_state_get_format(state, 1);
312 	v4l2_subdev_unlock_state(state);
313 
314 	vpix = dcmipp_par_pix_map_by_code(sink_fmt->code, src_fmt->code);
315 	if (!vpix) {
316 		dev_err(par->dev, "Invalid sink/src format configuration\n");
317 		return -EINVAL;
318 	}
319 
320 	val |= vpix->prcr_format << DCMIPP_PRCR_FORMAT_SHIFT;
321 
322 	/* swap cycles */
323 	if (vpix->prcr_swapcycles)
324 		val |= DCMIPP_PRCR_SWAPCYCLES;
325 
326 	reg_write(par, DCMIPP_PRCR, val);
327 
328 	return 0;
329 }
330 
331 static int dcmipp_par_s_stream(struct v4l2_subdev *sd, int enable)
332 {
333 	struct dcmipp_par_device *par =
334 				container_of(sd, struct dcmipp_par_device, sd);
335 	struct v4l2_subdev *s_subdev;
336 	struct media_pad *pad;
337 	int ret = 0;
338 
339 	/* Get source subdev */
340 	pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
341 	if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
342 		return -EINVAL;
343 	s_subdev = media_entity_to_v4l2_subdev(pad->entity);
344 
345 	if (enable) {
346 		ret = dcmipp_par_configure(par);
347 		if (ret)
348 			return ret;
349 
350 		/* Enable parallel interface */
351 		reg_set(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
352 
353 		ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
354 		if (ret < 0) {
355 			dev_err(par->dev,
356 				"failed to start source subdev streaming (%d)\n",
357 				ret);
358 			return ret;
359 		}
360 	} else {
361 		ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
362 		if (ret < 0) {
363 			dev_err(par->dev,
364 				"failed to stop source subdev streaming (%d)\n",
365 				ret);
366 			return ret;
367 		}
368 
369 		/* Disable parallel interface */
370 		reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
371 	}
372 
373 	par->streaming = enable;
374 
375 	return ret;
376 }
377 
378 static const struct v4l2_subdev_video_ops dcmipp_par_video_ops = {
379 	.s_stream = dcmipp_par_s_stream,
380 };
381 
382 static const struct v4l2_subdev_ops dcmipp_par_ops = {
383 	.pad = &dcmipp_par_pad_ops,
384 	.video = &dcmipp_par_video_ops,
385 };
386 
387 static void dcmipp_par_release(struct v4l2_subdev *sd)
388 {
389 	struct dcmipp_par_device *par =
390 				container_of(sd, struct dcmipp_par_device, sd);
391 
392 	kfree(par);
393 }
394 
395 static const struct v4l2_subdev_internal_ops dcmipp_par_int_ops = {
396 	.init_state = dcmipp_par_init_state,
397 	.release = dcmipp_par_release,
398 };
399 
400 void dcmipp_par_ent_release(struct dcmipp_ent_device *ved)
401 {
402 	struct dcmipp_par_device *par =
403 			container_of(ved, struct dcmipp_par_device, ved);
404 
405 	dcmipp_ent_sd_unregister(ved, &par->sd);
406 }
407 
408 struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev,
409 					      const char *entity_name,
410 					      struct v4l2_device *v4l2_dev,
411 					      void __iomem *regs)
412 {
413 	struct dcmipp_par_device *par;
414 	const unsigned long pads_flag[] = {
415 		MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
416 	};
417 	int ret;
418 
419 	/* Allocate the par struct */
420 	par = kzalloc(sizeof(*par), GFP_KERNEL);
421 	if (!par)
422 		return ERR_PTR(-ENOMEM);
423 
424 	par->regs = regs;
425 
426 	/* Initialize ved and sd */
427 	ret = dcmipp_ent_sd_register(&par->ved, &par->sd, v4l2_dev,
428 				     entity_name, MEDIA_ENT_F_VID_IF_BRIDGE,
429 				     ARRAY_SIZE(pads_flag), pads_flag,
430 				     &dcmipp_par_int_ops, &dcmipp_par_ops,
431 				     NULL, NULL);
432 	if (ret) {
433 		kfree(par);
434 		return ERR_PTR(ret);
435 	}
436 
437 	par->dev = dev;
438 
439 	return &par->ved;
440 }
441