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/vmalloc.h>
12#include <linux/v4l2-mediabus.h>
13#include <media/v4l2-rect.h>
14#include <media/v4l2-subdev.h>
15
16#include "dcmipp-common.h"
17
18#define DCMIPP_P0FCTCR	0x500
19#define DCMIPP_P0FCTCR_FRATE_MASK	GENMASK(1, 0)
20#define DCMIPP_P0SCSTR	0x504
21#define DCMIPP_P0SCSTR_HSTART_SHIFT	0
22#define DCMIPP_P0SCSTR_VSTART_SHIFT	16
23#define DCMIPP_P0SCSZR	0x508
24#define DCMIPP_P0SCSZR_ENABLE		BIT(31)
25#define DCMIPP_P0SCSZR_HSIZE_SHIFT	0
26#define DCMIPP_P0SCSZR_VSIZE_SHIFT	16
27#define DCMIPP_P0PPCR	0x5c0
28#define DCMIPP_P0PPCR_BSM_1_2		0x1
29#define DCMIPP_P0PPCR_BSM_1_4		0x2
30#define DCMIPP_P0PPCR_BSM_2_4		0x3
31#define DCMIPP_P0PPCR_BSM_MASK		GENMASK(8, 7)
32#define DCMIPP_P0PPCR_BSM_SHIFT		0x7
33#define DCMIPP_P0PPCR_LSM		BIT(10)
34#define DCMIPP_P0PPCR_OELS		BIT(11)
35
36#define IS_SINK(pad) (!(pad))
37#define IS_SRC(pad)  ((pad))
38
39struct dcmipp_byteproc_pix_map {
40	unsigned int code;
41	unsigned int bpp;
42};
43
44#define PIXMAP_MBUS_BPP(mbus, byteperpixel)		\
45	{						\
46		.code = MEDIA_BUS_FMT_##mbus,		\
47		.bpp = byteperpixel,			\
48	}
49static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
50	PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2),
51	PIXMAP_MBUS_BPP(YUYV8_2X8, 2),
52	PIXMAP_MBUS_BPP(YVYU8_2X8, 2),
53	PIXMAP_MBUS_BPP(UYVY8_2X8, 2),
54	PIXMAP_MBUS_BPP(VYUY8_2X8, 2),
55	PIXMAP_MBUS_BPP(Y8_1X8, 1),
56	PIXMAP_MBUS_BPP(SBGGR8_1X8, 1),
57	PIXMAP_MBUS_BPP(SGBRG8_1X8, 1),
58	PIXMAP_MBUS_BPP(SGRBG8_1X8, 1),
59	PIXMAP_MBUS_BPP(SRGGB8_1X8, 1),
60	PIXMAP_MBUS_BPP(JPEG_1X8, 1),
61};
62
63static const struct dcmipp_byteproc_pix_map *
64dcmipp_byteproc_pix_map_by_code(u32 code)
65{
66	unsigned int i;
67
68	for (i = 0; i < ARRAY_SIZE(dcmipp_byteproc_pix_map_list); i++) {
69		if (dcmipp_byteproc_pix_map_list[i].code == code)
70			return &dcmipp_byteproc_pix_map_list[i];
71	}
72
73	return NULL;
74}
75
76struct dcmipp_byteproc_device {
77	struct dcmipp_ent_device ved;
78	struct v4l2_subdev sd;
79	struct device *dev;
80	void __iomem *regs;
81	bool streaming;
82};
83
84static const struct v4l2_mbus_framefmt fmt_default = {
85	.width = DCMIPP_FMT_WIDTH_DEFAULT,
86	.height = DCMIPP_FMT_HEIGHT_DEFAULT,
87	.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
88	.field = V4L2_FIELD_NONE,
89	.colorspace = DCMIPP_COLORSPACE_DEFAULT,
90	.ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
91	.quantization = DCMIPP_QUANTIZATION_DEFAULT,
92	.xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
93};
94
95static const struct v4l2_rect crop_min = {
96	.width = DCMIPP_FRAME_MIN_WIDTH,
97	.height = DCMIPP_FRAME_MIN_HEIGHT,
98	.top = 0,
99	.left = 0,
100};
101
102static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r,
103					struct v4l2_rect *compose)
104{
105	/* Disallow rectangles smaller than the minimal one. */
106	v4l2_rect_set_min_size(r, &crop_min);
107	v4l2_rect_map_inside(r, compose);
108}
109
110static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
111					   const struct v4l2_mbus_framefmt *fmt)
112{
113	r->top = 0;
114	r->left = 0;
115
116	/* Compose is not possible for JPEG or Bayer formats */
117	if (fmt->code == MEDIA_BUS_FMT_JPEG_1X8 ||
118	    fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
119	    fmt->code == MEDIA_BUS_FMT_SGBRG8_1X8 ||
120	    fmt->code == MEDIA_BUS_FMT_SGRBG8_1X8 ||
121	    fmt->code == MEDIA_BUS_FMT_SRGGB8_1X8) {
122		r->width = fmt->width;
123		r->height = fmt->height;
124		return;
125	}
126
127	/* Adjust height - we can only perform 1/2 decimation */
128	if (r->height <= (fmt->height / 2))
129		r->height = fmt->height / 2;
130	else
131		r->height = fmt->height;
132
133	/* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
134	if (fmt->code == MEDIA_BUS_FMT_Y8_1X8 && r->width <= (fmt->width / 4))
135		r->width = fmt->width / 4;
136	else if (r->width <= (fmt->width / 2))
137		r->width = fmt->width / 2;
138	else
139		r->width = fmt->width;
140}
141
142static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
143{
144	const struct dcmipp_byteproc_pix_map *vpix;
145
146	/* Only accept code in the pix map table */
147	vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
148	if (!vpix)
149		fmt->code = fmt_default.code;
150
151	fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
152			     DCMIPP_FRAME_MAX_WIDTH) & ~1;
153	fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
154			      DCMIPP_FRAME_MAX_HEIGHT) & ~1;
155
156	if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
157		fmt->field = fmt_default.field;
158
159	dcmipp_colorimetry_clamp(fmt);
160}
161
162static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd,
163				      struct v4l2_subdev_state *sd_state)
164{
165	unsigned int i;
166
167	for (i = 0; i < sd->entity.num_pads; i++) {
168		struct v4l2_mbus_framefmt *mf;
169		struct v4l2_rect *r;
170
171		mf = v4l2_subdev_state_get_format(sd_state, i);
172		*mf = fmt_default;
173
174		if (IS_SINK(i))
175			r = v4l2_subdev_state_get_compose(sd_state, i);
176		else
177			r = v4l2_subdev_state_get_crop(sd_state, i);
178
179		r->top = 0;
180		r->left = 0;
181		r->width = DCMIPP_FMT_WIDTH_DEFAULT;
182		r->height = DCMIPP_FMT_HEIGHT_DEFAULT;
183	}
184
185	return 0;
186}
187
188static int
189dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd,
190			       struct v4l2_subdev_state *sd_state,
191			       struct v4l2_subdev_mbus_code_enum *code)
192{
193	const struct dcmipp_byteproc_pix_map *vpix;
194	struct v4l2_mbus_framefmt *sink_fmt;
195
196	if (IS_SINK(code->pad)) {
197		if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list))
198			return -EINVAL;
199		vpix = &dcmipp_byteproc_pix_map_list[code->index];
200		code->code = vpix->code;
201	} else {
202		/* byteproc doesn't support transformation on format */
203		if (code->index > 0)
204			return -EINVAL;
205
206		sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
207		code->code = sink_fmt->code;
208	}
209
210	return 0;
211}
212
213static int
214dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd,
215				struct v4l2_subdev_state *sd_state,
216				struct v4l2_subdev_frame_size_enum *fse)
217{
218	struct v4l2_rect *compose;
219
220	if (fse->index)
221		return -EINVAL;
222
223	fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
224	fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
225
226	if (IS_SINK(fse->pad)) {
227		fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
228		fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
229	} else {
230		compose = v4l2_subdev_state_get_compose(sd_state, 0);
231		fse->max_width = compose->width;
232		fse->max_height = compose->height;
233	}
234
235	return 0;
236}
237
238static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
239				   struct v4l2_subdev_state *sd_state,
240				   struct v4l2_subdev_format *fmt)
241{
242	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
243	struct v4l2_mbus_framefmt *mf;
244	struct v4l2_rect *crop, *compose;
245
246	if (byteproc->streaming)
247		return -EBUSY;
248
249	mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
250
251	crop = v4l2_subdev_state_get_crop(sd_state, 1);
252	compose = v4l2_subdev_state_get_compose(sd_state, 0);
253
254	if (IS_SRC(fmt->pad)) {
255		fmt->format = *v4l2_subdev_state_get_format(sd_state, 0);
256		fmt->format.width = crop->width;
257		fmt->format.height = crop->height;
258	} else {
259		dcmipp_byteproc_adjust_fmt(&fmt->format);
260		crop->top = 0;
261		crop->left = 0;
262		crop->width = fmt->format.width;
263		crop->height = fmt->format.height;
264		*compose = *crop;
265		/* Set the same format on SOURCE pad as well */
266		*v4l2_subdev_state_get_format(sd_state, 1) = fmt->format;
267	}
268	*mf = fmt->format;
269
270	return 0;
271}
272
273static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd,
274					 struct v4l2_subdev_state *sd_state,
275					 struct v4l2_subdev_selection *s)
276{
277	struct v4l2_mbus_framefmt *sink_fmt;
278	struct v4l2_rect *crop, *compose;
279
280	/*
281	 * In the HW, the decimation block is located prior to the crop hence:
282	 * Compose is done on the sink pad
283	 * Crop is done on the src pad
284	 */
285	if (IS_SINK(s->pad) &&
286	    (s->target == V4L2_SEL_TGT_CROP ||
287	     s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
288	     s->target == V4L2_SEL_TGT_CROP_DEFAULT))
289		return -EINVAL;
290
291	if (IS_SRC(s->pad) &&
292	    (s->target == V4L2_SEL_TGT_COMPOSE ||
293	     s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
294	     s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT))
295		return -EINVAL;
296
297	sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
298	crop = v4l2_subdev_state_get_crop(sd_state, 1);
299	compose = v4l2_subdev_state_get_compose(sd_state, 0);
300
301	switch (s->target) {
302	case V4L2_SEL_TGT_CROP:
303		s->r = *crop;
304		break;
305	case V4L2_SEL_TGT_CROP_BOUNDS:
306	case V4L2_SEL_TGT_CROP_DEFAULT:
307		s->r = *compose;
308		break;
309	case V4L2_SEL_TGT_COMPOSE:
310		s->r = *compose;
311		break;
312	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
313	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
314		s->r.top = 0;
315		s->r.left = 0;
316		s->r.width = sink_fmt->width;
317		s->r.height = sink_fmt->height;
318		break;
319	default:
320		return -EINVAL;
321	}
322
323	return 0;
324}
325
326static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
327					 struct v4l2_subdev_state *sd_state,
328					 struct v4l2_subdev_selection *s)
329{
330	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
331	struct v4l2_mbus_framefmt *mf;
332	struct v4l2_rect *crop, *compose;
333
334	/*
335	 * In the HW, the decimation block is located prior to the crop hence:
336	 * Compose is done on the sink pad
337	 * Crop is done on the src pad
338	 */
339	if ((s->target == V4L2_SEL_TGT_CROP ||
340	     s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
341	     s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad))
342		return -EINVAL;
343
344	if ((s->target == V4L2_SEL_TGT_COMPOSE ||
345	     s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
346	     s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad))
347		return -EINVAL;
348
349	crop = v4l2_subdev_state_get_crop(sd_state, 1);
350	compose = v4l2_subdev_state_get_compose(sd_state, 0);
351
352	switch (s->target) {
353	case V4L2_SEL_TGT_CROP:
354		dcmipp_byteproc_adjust_crop(&s->r, compose);
355
356		*crop = s->r;
357		mf = v4l2_subdev_state_get_format(sd_state, 1);
358		mf->width = s->r.width;
359		mf->height = s->r.height;
360
361		dev_dbg(byteproc->dev, "s_selection: crop %ux%u@(%u,%u)\n",
362			crop->width, crop->height, crop->left, crop->top);
363		break;
364	case V4L2_SEL_TGT_COMPOSE:
365		mf = v4l2_subdev_state_get_format(sd_state, 0);
366		dcmipp_byteproc_adjust_compose(&s->r, mf);
367		*compose = s->r;
368		*crop = s->r;
369
370		mf = v4l2_subdev_state_get_format(sd_state, 1);
371		mf->width = s->r.width;
372		mf->height = s->r.height;
373
374		dev_dbg(byteproc->dev, "s_selection: compose %ux%u@(%u,%u)\n",
375			compose->width, compose->height,
376			compose->left, compose->top);
377		break;
378	default:
379		return -EINVAL;
380	}
381
382	return 0;
383}
384
385static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
386	.enum_mbus_code		= dcmipp_byteproc_enum_mbus_code,
387	.enum_frame_size	= dcmipp_byteproc_enum_frame_size,
388	.get_fmt		= v4l2_subdev_get_fmt,
389	.set_fmt		= dcmipp_byteproc_set_fmt,
390	.get_selection		= dcmipp_byteproc_get_selection,
391	.set_selection		= dcmipp_byteproc_set_selection,
392};
393
394static int dcmipp_byteproc_configure_scale_crop
395			(struct dcmipp_byteproc_device *byteproc)
396{
397	const struct dcmipp_byteproc_pix_map *vpix;
398	struct v4l2_subdev_state *state;
399	struct v4l2_mbus_framefmt *sink_fmt;
400	u32 hprediv, vprediv;
401	struct v4l2_rect *compose, *crop;
402	u32 val = 0;
403
404	state = v4l2_subdev_lock_and_get_active_state(&byteproc->sd);
405	sink_fmt = v4l2_subdev_state_get_format(state, 0);
406	compose = v4l2_subdev_state_get_compose(state, 0);
407	crop = v4l2_subdev_state_get_crop(state, 1);
408	v4l2_subdev_unlock_state(state);
409
410	/* find output format bpp */
411	vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
412	if (!vpix)
413		return -EINVAL;
414
415	/* clear decimation/crop */
416	reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK);
417	reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM);
418	reg_write(byteproc, DCMIPP_P0SCSTR, 0);
419	reg_write(byteproc, DCMIPP_P0SCSZR, 0);
420
421	/* Ignore decimation/crop with JPEG */
422	if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8)
423		return 0;
424
425	/* decimation */
426	hprediv = sink_fmt->width / compose->width;
427	if (hprediv == 4)
428		val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT;
429	else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2))
430		val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT;
431	else if (hprediv == 2)
432		val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT;
433
434	vprediv = sink_fmt->height / compose->height;
435	if (vprediv == 2)
436		val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS;
437
438	/* decimate using bytes and lines skipping */
439	if (val) {
440		reg_set(byteproc, DCMIPP_P0PPCR, val);
441
442		dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n",
443			compose->width, compose->height,
444			hprediv, vprediv);
445	}
446
447	dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height);
448
449	/* expressed in 32-bits words on X axis, lines on Y axis */
450	reg_write(byteproc, DCMIPP_P0SCSTR,
451		  (((crop->left * vpix->bpp) / 4) <<
452		   DCMIPP_P0SCSTR_HSTART_SHIFT) |
453		  (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT));
454	reg_write(byteproc, DCMIPP_P0SCSZR,
455		  DCMIPP_P0SCSZR_ENABLE |
456		  (((crop->width * vpix->bpp) / 4) <<
457		   DCMIPP_P0SCSZR_HSIZE_SHIFT) |
458		  (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT));
459
460	return 0;
461}
462
463static int dcmipp_byteproc_s_stream(struct v4l2_subdev *sd, int enable)
464{
465	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
466	struct v4l2_subdev *s_subdev;
467	struct media_pad *pad;
468	int ret = 0;
469
470	/* Get source subdev */
471	pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
472	if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
473		return -EINVAL;
474	s_subdev = media_entity_to_v4l2_subdev(pad->entity);
475
476	if (enable) {
477		ret = dcmipp_byteproc_configure_scale_crop(byteproc);
478		if (ret)
479			return ret;
480
481		ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
482		if (ret < 0) {
483			dev_err(byteproc->dev,
484				"failed to start source subdev streaming (%d)\n",
485				ret);
486			return ret;
487		}
488	} else {
489		ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
490		if (ret < 0) {
491			dev_err(byteproc->dev,
492				"failed to stop source subdev streaming (%d)\n",
493				ret);
494			return ret;
495		}
496	}
497
498	byteproc->streaming = enable;
499
500	return 0;
501}
502
503static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
504	.s_stream = dcmipp_byteproc_s_stream,
505};
506
507static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
508	.pad = &dcmipp_byteproc_pad_ops,
509	.video = &dcmipp_byteproc_video_ops,
510};
511
512static void dcmipp_byteproc_release(struct v4l2_subdev *sd)
513{
514	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
515
516	kfree(byteproc);
517}
518
519static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = {
520	.init_state = dcmipp_byteproc_init_state,
521	.release = dcmipp_byteproc_release,
522};
523
524void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved)
525{
526	struct dcmipp_byteproc_device *byteproc =
527			container_of(ved, struct dcmipp_byteproc_device, ved);
528
529	dcmipp_ent_sd_unregister(ved, &byteproc->sd);
530}
531
532struct dcmipp_ent_device *
533dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
534			 struct v4l2_device *v4l2_dev, void __iomem *regs)
535{
536	struct dcmipp_byteproc_device *byteproc;
537	const unsigned long pads_flag[] = {
538		MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
539	};
540	int ret;
541
542	/* Allocate the byteproc struct */
543	byteproc = kzalloc(sizeof(*byteproc), GFP_KERNEL);
544	if (!byteproc)
545		return ERR_PTR(-ENOMEM);
546
547	byteproc->regs = regs;
548
549	/* Initialize ved and sd */
550	ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd,
551				     v4l2_dev, entity_name,
552				     MEDIA_ENT_F_PROC_VIDEO_SCALER,
553				     ARRAY_SIZE(pads_flag), pads_flag,
554				     &dcmipp_byteproc_int_ops,
555				     &dcmipp_byteproc_ops,
556				     NULL, NULL);
557	if (ret) {
558		kfree(byteproc);
559		return ERR_PTR(ret);
560	}
561
562	byteproc->dev = dev;
563
564	return &byteproc->ved;
565}
566