File Index
Files and directories
Sign in
FILE

xilinx-tpg.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/xilinx/xilinx-tpg.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Xilinx Test Pattern Generator
  4 *
  5 * Copyright (C) 2013-2015 Ideas on Board
  6 * Copyright (C) 2013-2015 Xilinx, Inc.
  7 *
  8 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  9 *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 10 */
 11
 12#include <linux/device.h>
 13#include <linux/gpio/consumer.h>
 14#include <linux/module.h>
 15#include <linux/of.h>
 16#include <linux/of_graph.h>
 17#include <linux/platform_device.h>
 18#include <linux/xilinx-v4l2-controls.h>
 19
 20#include <media/v4l2-async.h>
 21#include <media/v4l2-ctrls.h>
 22#include <media/v4l2-subdev.h>
 23
 24#include "xilinx-vip.h"
 25#include "xilinx-vtc.h"
 26
 27#define XTPG_CTRL_STATUS_SLAVE_ERROR		(1 << 16)
 28#define XTPG_CTRL_IRQ_SLAVE_ERROR		(1 << 16)
 29
 30#define XTPG_PATTERN_CONTROL			0x0100
 31#define XTPG_PATTERN_MASK			(0xf << 0)
 32#define XTPG_PATTERN_CONTROL_CROSS_HAIRS	(1 << 4)
 33#define XTPG_PATTERN_CONTROL_MOVING_BOX		(1 << 5)
 34#define XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT	6
 35#define XTPG_PATTERN_CONTROL_COLOR_MASK_MASK	(0xf << 6)
 36#define XTPG_PATTERN_CONTROL_STUCK_PIXEL	(1 << 9)
 37#define XTPG_PATTERN_CONTROL_NOISE		(1 << 10)
 38#define XTPG_PATTERN_CONTROL_MOTION		(1 << 12)
 39#define XTPG_MOTION_SPEED			0x0104
 40#define XTPG_CROSS_HAIRS			0x0108
 41#define XTPG_CROSS_HAIRS_ROW_SHIFT		0
 42#define XTPG_CROSS_HAIRS_ROW_MASK		(0xfff << 0)
 43#define XTPG_CROSS_HAIRS_COLUMN_SHIFT		16
 44#define XTPG_CROSS_HAIRS_COLUMN_MASK		(0xfff << 16)
 45#define XTPG_ZPLATE_HOR_CONTROL			0x010c
 46#define XTPG_ZPLATE_VER_CONTROL			0x0110
 47#define XTPG_ZPLATE_START_SHIFT			0
 48#define XTPG_ZPLATE_START_MASK			(0xffff << 0)
 49#define XTPG_ZPLATE_SPEED_SHIFT			16
 50#define XTPG_ZPLATE_SPEED_MASK			(0xffff << 16)
 51#define XTPG_BOX_SIZE				0x0114
 52#define XTPG_BOX_COLOR				0x0118
 53#define XTPG_STUCK_PIXEL_THRESH			0x011c
 54#define XTPG_NOISE_GAIN				0x0120
 55#define XTPG_BAYER_PHASE			0x0124
 56#define XTPG_BAYER_PHASE_RGGB			0
 57#define XTPG_BAYER_PHASE_GRBG			1
 58#define XTPG_BAYER_PHASE_GBRG			2
 59#define XTPG_BAYER_PHASE_BGGR			3
 60#define XTPG_BAYER_PHASE_OFF			4
 61
 62/*
 63 * The minimum blanking value is one clock cycle for the front porch, one clock
 64 * cycle for the sync pulse and one clock cycle for the back porch.
 65 */
 66#define XTPG_MIN_HBLANK			3
 67#define XTPG_MAX_HBLANK			(XVTC_MAX_HSIZE - XVIP_MIN_WIDTH)
 68#define XTPG_MIN_VBLANK			3
 69#define XTPG_MAX_VBLANK			(XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT)
 70
 71/**
 72 * struct xtpg_device - Xilinx Test Pattern Generator device structure
 73 * @xvip: Xilinx Video IP device
 74 * @pads: media pads
 75 * @npads: number of pads (1 or 2)
 76 * @has_input: whether an input is connected to the sink pad
 77 * @formats: active V4L2 media bus format for each pad
 78 * @default_format: default V4L2 media bus format
 79 * @vip_format: format information corresponding to the active format
 80 * @bayer: boolean flag if TPG is set to any bayer format
 81 * @ctrl_handler: control handler
 82 * @hblank: horizontal blanking control
 83 * @vblank: vertical blanking control
 84 * @pattern: test pattern control
 85 * @streaming: is the video stream active
 86 * @vtc: video timing controller
 87 * @vtmux_gpio: video timing mux GPIO
 88 */
 89struct xtpg_device {
 90	struct xvip_device xvip;
 91
 92	struct media_pad pads[2];
 93	unsigned int npads;
 94	bool has_input;
 95
 96	struct v4l2_mbus_framefmt formats[2];
 97	struct v4l2_mbus_framefmt default_format;
 98	const struct xvip_video_format *vip_format;
 99	bool bayer;
100
101	struct v4l2_ctrl_handler ctrl_handler;
102	struct v4l2_ctrl *hblank;
103	struct v4l2_ctrl *vblank;
104	struct v4l2_ctrl *pattern;
105	bool streaming;
106
107	struct xvtc_device *vtc;
108	struct gpio_desc *vtmux_gpio;
109};
110
111static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev)
112{
113	return container_of(subdev, struct xtpg_device, xvip.subdev);
114}
115
116static u32 xtpg_get_bayer_phase(unsigned int code)
117{
118	switch (code) {
119	case MEDIA_BUS_FMT_SRGGB8_1X8:
120		return XTPG_BAYER_PHASE_RGGB;
121	case MEDIA_BUS_FMT_SGRBG8_1X8:
122		return XTPG_BAYER_PHASE_GRBG;
123	case MEDIA_BUS_FMT_SGBRG8_1X8:
124		return XTPG_BAYER_PHASE_GBRG;
125	case MEDIA_BUS_FMT_SBGGR8_1X8:
126		return XTPG_BAYER_PHASE_BGGR;
127	default:
128		return XTPG_BAYER_PHASE_OFF;
129	}
130}
131
132static void __xtpg_update_pattern_control(struct xtpg_device *xtpg,
133					  bool passthrough, bool pattern)
134{
135	u32 pattern_mask = (1 << (xtpg->pattern->maximum + 1)) - 1;
136
137	/*
138	 * If the TPG has no sink pad or no input connected to its sink pad
139	 * passthrough mode can't be enabled.
140	 */
141	if (xtpg->npads == 1 || !xtpg->has_input)
142		passthrough = false;
143
144	/* If passthrough mode is allowed unmask bit 0. */
145	if (passthrough)
146		pattern_mask &= ~1;
147
148	/* If test pattern mode is allowed unmask all other bits. */
149	if (pattern)
150		pattern_mask &= 1;
151
152	__v4l2_ctrl_modify_range(xtpg->pattern, 0, xtpg->pattern->maximum,
153				 pattern_mask, pattern ? 9 : 0);
154}
155
156static void xtpg_update_pattern_control(struct xtpg_device *xtpg,
157					bool passthrough, bool pattern)
158{
159	mutex_lock(xtpg->ctrl_handler.lock);
160	__xtpg_update_pattern_control(xtpg, passthrough, pattern);
161	mutex_unlock(xtpg->ctrl_handler.lock);
162}
163
164/* -----------------------------------------------------------------------------
165 * V4L2 Subdevice Video Operations
166 */
167
168static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
169{
170	struct xtpg_device *xtpg = to_tpg(subdev);
171	unsigned int width = xtpg->formats[0].width;
172	unsigned int height = xtpg->formats[0].height;
173	bool passthrough;
174	u32 bayer_phase;
175
176	if (!enable) {
177		xvip_stop(&xtpg->xvip);
178		if (xtpg->vtc)
179			xvtc_generator_stop(xtpg->vtc);
180
181		xtpg_update_pattern_control(xtpg, true, true);
182		xtpg->streaming = false;
183		return 0;
184	}
185
186	xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]);
187
188	if (xtpg->vtc) {
189		struct xvtc_config config = {
190			.hblank_start = width,
191			.hsync_start = width + 1,
192			.vblank_start = height,
193			.vsync_start = height + 1,
194		};
195		unsigned int htotal;
196		unsigned int vtotal;
197
198		htotal = min_t(unsigned int, XVTC_MAX_HSIZE,
199			       v4l2_ctrl_g_ctrl(xtpg->hblank) + width);
200		vtotal = min_t(unsigned int, XVTC_MAX_VSIZE,
201			       v4l2_ctrl_g_ctrl(xtpg->vblank) + height);
202
203		config.hsync_end = htotal - 1;
204		config.hsize = htotal;
205		config.vsync_end = vtotal - 1;
206		config.vsize = vtotal;
207
208		xvtc_generator_start(xtpg->vtc, &config);
209	}
210
211	/*
212	 * Configure the bayer phase and video timing mux based on the
213	 * operation mode (passthrough or test pattern generation). The test
214	 * pattern can be modified by the control set handler, we thus need to
215	 * take the control lock here to avoid races.
216	 */
217	mutex_lock(xtpg->ctrl_handler.lock);
218
219	xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
220			 XTPG_PATTERN_MASK, xtpg->pattern->cur.val);
221
222	/*
223	 * Switching between passthrough and test pattern generation modes isn't
224	 * allowed during streaming, update the control range accordingly.
225	 */
226	passthrough = xtpg->pattern->cur.val == 0;
227	__xtpg_update_pattern_control(xtpg, passthrough, !passthrough);
228
229	xtpg->streaming = true;
230
231	mutex_unlock(xtpg->ctrl_handler.lock);
232
233	/*
234	 * For TPG v5.0, the bayer phase needs to be off for the pass through
235	 * mode, otherwise the external input would be subsampled.
236	 */
237	bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF
238		    : xtpg_get_bayer_phase(xtpg->formats[0].code);
239	xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase);
240
241	if (xtpg->vtmux_gpio)
242		gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough);
243
244	xvip_start(&xtpg->xvip);
245
246	return 0;
247}
248
249/* -----------------------------------------------------------------------------
250 * V4L2 Subdevice Pad Operations
251 */
252
253static struct v4l2_mbus_framefmt *
254__xtpg_get_pad_format(struct xtpg_device *xtpg,
255		      struct v4l2_subdev_state *sd_state,
256		      unsigned int pad, u32 which)
257{
258	switch (which) {
259	case V4L2_SUBDEV_FORMAT_TRY:
260		return v4l2_subdev_state_get_format(sd_state, pad);
261	case V4L2_SUBDEV_FORMAT_ACTIVE:
262		return &xtpg->formats[pad];
263	default:
264		return NULL;
265	}
266}
267
268static int xtpg_get_format(struct v4l2_subdev *subdev,
269			   struct v4l2_subdev_state *sd_state,
270			   struct v4l2_subdev_format *fmt)
271{
272	struct xtpg_device *xtpg = to_tpg(subdev);
273
274	fmt->format = *__xtpg_get_pad_format(xtpg, sd_state, fmt->pad,
275					     fmt->which);
276
277	return 0;
278}
279
280static int xtpg_set_format(struct v4l2_subdev *subdev,
281			   struct v4l2_subdev_state *sd_state,
282			   struct v4l2_subdev_format *fmt)
283{
284	struct xtpg_device *xtpg = to_tpg(subdev);
285	struct v4l2_mbus_framefmt *__format;
286	u32 bayer_phase;
287
288	__format = __xtpg_get_pad_format(xtpg, sd_state, fmt->pad, fmt->which);
289
290	/* In two pads mode the source pad format is always identical to the
291	 * sink pad format.
292	 */
293	if (xtpg->npads == 2 && fmt->pad == 1) {
294		fmt->format = *__format;
295		return 0;
296	}
297
298	/* Bayer phase is configurable at runtime */
299	if (xtpg->bayer) {
300		bayer_phase = xtpg_get_bayer_phase(fmt->format.code);
301		if (bayer_phase != XTPG_BAYER_PHASE_OFF)
302			__format->code = fmt->format.code;
303	}
304
305	xvip_set_format_size(__format, fmt);
306
307	fmt->format = *__format;
308
309	/* Propagate the format to the source pad. */
310	if (xtpg->npads == 2) {
311		__format = __xtpg_get_pad_format(xtpg, sd_state, 1,
312						 fmt->which);
313		*__format = fmt->format;
314	}
315
316	return 0;
317}
318
319/* -----------------------------------------------------------------------------
320 * V4L2 Subdevice Operations
321 */
322
323static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
324				struct v4l2_subdev_state *sd_state,
325				struct v4l2_subdev_frame_size_enum *fse)
326{
327	struct v4l2_mbus_framefmt *format;
328
329	format = v4l2_subdev_state_get_format(sd_state, fse->pad);
330
331	if (fse->index || fse->code != format->code)
332		return -EINVAL;
333
334	/* Min / max values for pad 0 is always fixed in both one and two pads
335	 * modes. In two pads mode, the source pad(= 1) size is identical to
336	 * the sink pad size */
337	if (fse->pad == 0) {
338		fse->min_width = XVIP_MIN_WIDTH;
339		fse->max_width = XVIP_MAX_WIDTH;
340		fse->min_height = XVIP_MIN_HEIGHT;
341		fse->max_height = XVIP_MAX_HEIGHT;
342	} else {
343		fse->min_width = format->width;
344		fse->max_width = format->width;
345		fse->min_height = format->height;
346		fse->max_height = format->height;
347	}
348
349	return 0;
350}
351
352static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
353{
354	struct xtpg_device *xtpg = to_tpg(subdev);
355	struct v4l2_mbus_framefmt *format;
356
357	format = v4l2_subdev_state_get_format(fh->state, 0);
358	*format = xtpg->default_format;
359
360	if (xtpg->npads == 2) {
361		format = v4l2_subdev_state_get_format(fh->state, 1);
362		*format = xtpg->default_format;
363	}
364
365	return 0;
366}
367
368static int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
369{
370	return 0;
371}
372
373static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl)
374{
375	struct xtpg_device *xtpg = container_of(ctrl->handler,
376						struct xtpg_device,
377						ctrl_handler);
378	switch (ctrl->id) {
379	case V4L2_CID_TEST_PATTERN:
380		xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
381				 XTPG_PATTERN_MASK, ctrl->val);
382		return 0;
383	case V4L2_CID_XILINX_TPG_CROSS_HAIRS:
384		xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
385				XTPG_PATTERN_CONTROL_CROSS_HAIRS, ctrl->val);
386		return 0;
387	case V4L2_CID_XILINX_TPG_MOVING_BOX:
388		xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
389				XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val);
390		return 0;
391	case V4L2_CID_XILINX_TPG_COLOR_MASK:
392		xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
393				 XTPG_PATTERN_CONTROL_COLOR_MASK_MASK,
394				 ctrl->val <<
395				 XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT);
396		return 0;
397	case V4L2_CID_XILINX_TPG_STUCK_PIXEL:
398		xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
399				XTPG_PATTERN_CONTROL_STUCK_PIXEL, ctrl->val);
400		return 0;
401	case V4L2_CID_XILINX_TPG_NOISE:
402		xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
403				XTPG_PATTERN_CONTROL_NOISE, ctrl->val);
404		return 0;
405	case V4L2_CID_XILINX_TPG_MOTION:
406		xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
407				XTPG_PATTERN_CONTROL_MOTION, ctrl->val);
408		return 0;
409	case V4L2_CID_XILINX_TPG_MOTION_SPEED:
410		xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val);
411		return 0;
412	case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW:
413		xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
414				 XTPG_CROSS_HAIRS_ROW_MASK,
415				 ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT);
416		return 0;
417	case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN:
418		xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
419				 XTPG_CROSS_HAIRS_COLUMN_MASK,
420				 ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT);
421		return 0;
422	case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START:
423		xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
424				 XTPG_ZPLATE_START_MASK,
425				 ctrl->val << XTPG_ZPLATE_START_SHIFT);
426		return 0;
427	case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED:
428		xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
429				 XTPG_ZPLATE_SPEED_MASK,
430				 ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
431		return 0;
432	case V4L2_CID_XILINX_TPG_ZPLATE_VER_START:
433		xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
434				 XTPG_ZPLATE_START_MASK,
435				 ctrl->val << XTPG_ZPLATE_START_SHIFT);
436		return 0;
437	case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED:
438		xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
439				 XTPG_ZPLATE_SPEED_MASK,
440				 ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
441		return 0;
442	case V4L2_CID_XILINX_TPG_BOX_SIZE:
443		xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val);
444		return 0;
445	case V4L2_CID_XILINX_TPG_BOX_COLOR:
446		xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val);
447		return 0;
448	case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH:
449		xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val);
450		return 0;
451	case V4L2_CID_XILINX_TPG_NOISE_GAIN:
452		xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val);
453		return 0;
454	}
455
456	return 0;
457}
458
459static const struct v4l2_ctrl_ops xtpg_ctrl_ops = {
460	.s_ctrl	= xtpg_s_ctrl,
461};
462
463static const struct v4l2_subdev_core_ops xtpg_core_ops = {
464};
465
466static const struct v4l2_subdev_video_ops xtpg_video_ops = {
467	.s_stream = xtpg_s_stream,
468};
469
470static const struct v4l2_subdev_pad_ops xtpg_pad_ops = {
471	.enum_mbus_code		= xvip_enum_mbus_code,
472	.enum_frame_size	= xtpg_enum_frame_size,
473	.get_fmt		= xtpg_get_format,
474	.set_fmt		= xtpg_set_format,
475};
476
477static const struct v4l2_subdev_ops xtpg_ops = {
478	.core   = &xtpg_core_ops,
479	.video  = &xtpg_video_ops,
480	.pad    = &xtpg_pad_ops,
481};
482
483static const struct v4l2_subdev_internal_ops xtpg_internal_ops = {
484	.open	= xtpg_open,
485	.close	= xtpg_close,
486};
487
488/*
489 * Control Config
490 */
491
492static const char *const xtpg_pattern_strings[] = {
493	"Passthrough",
494	"Horizontal Ramp",
495	"Vertical Ramp",
496	"Temporal Ramp",
497	"Solid Red",
498	"Solid Green",
499	"Solid Blue",
500	"Solid Black",
501	"Solid White",
502	"Color Bars",
503	"Zone Plate",
504	"Tartan Color Bars",
505	"Cross Hatch",
506	"None",
507	"Vertical/Horizontal Ramps",
508	"Black/White Checker Board",
509};
510
511static struct v4l2_ctrl_config xtpg_ctrls[] = {
512	{
513		.ops	= &xtpg_ctrl_ops,
514		.id	= V4L2_CID_XILINX_TPG_CROSS_HAIRS,
515		.name	= "Test Pattern: Cross Hairs",
516		.type	= V4L2_CTRL_TYPE_BOOLEAN,
517		.min	= false,
518		.max	= true,
519		.step	= 1,
520		.def	= 0,
521	}, {
522		.ops	= &xtpg_ctrl_ops,
523		.id	= V4L2_CID_XILINX_TPG_MOVING_BOX,
524		.name	= "Test Pattern: Moving Box",
525		.type	= V4L2_CTRL_TYPE_BOOLEAN,
526		.min	= false,
527		.max	= true,
528		.step	= 1,
529		.def	= 0,
530	}, {
531		.ops	= &xtpg_ctrl_ops,
532		.id	= V4L2_CID_XILINX_TPG_COLOR_MASK,
533		.name	= "Test Pattern: Color Mask",
534		.type	= V4L2_CTRL_TYPE_BITMASK,
535		.min	= 0,
536		.max	= 0xf,
537		.def	= 0,
538	}, {
539		.ops	= &xtpg_ctrl_ops,
540		.id	= V4L2_CID_XILINX_TPG_STUCK_PIXEL,
541		.name	= "Test Pattern: Stuck Pixel",
542		.type	= V4L2_CTRL_TYPE_BOOLEAN,
543		.min	= false,
544		.max	= true,
545		.step	= 1,
546		.def	= 0,
547	}, {
548		.ops	= &xtpg_ctrl_ops,
549		.id	= V4L2_CID_XILINX_TPG_NOISE,
550		.name	= "Test Pattern: Noise",
551		.type	= V4L2_CTRL_TYPE_BOOLEAN,
552		.min	= false,
553		.max	= true,
554		.step	= 1,
555		.def	= 0,
556	}, {
557		.ops	= &xtpg_ctrl_ops,
558		.id	= V4L2_CID_XILINX_TPG_MOTION,
559		.name	= "Test Pattern: Motion",
560		.type	= V4L2_CTRL_TYPE_BOOLEAN,
561		.min	= false,
562		.max	= true,
563		.step	= 1,
564		.def	= 0,
565	}, {
566		.ops	= &xtpg_ctrl_ops,
567		.id	= V4L2_CID_XILINX_TPG_MOTION_SPEED,
568		.name	= "Test Pattern: Motion Speed",
569		.type	= V4L2_CTRL_TYPE_INTEGER,
570		.min	= 0,
571		.max	= (1 << 8) - 1,
572		.step	= 1,
573		.def	= 4,
574		.flags	= V4L2_CTRL_FLAG_SLIDER,
575	}, {
576		.ops	= &xtpg_ctrl_ops,
577		.id	= V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW,
578		.name	= "Test Pattern: Cross Hairs Row",
579		.type	= V4L2_CTRL_TYPE_INTEGER,
580		.min	= 0,
581		.max	= (1 << 12) - 1,
582		.step	= 1,
583		.def	= 0x64,
584		.flags	= V4L2_CTRL_FLAG_SLIDER,
585	}, {
586		.ops	= &xtpg_ctrl_ops,
587		.id	= V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN,
588		.name	= "Test Pattern: Cross Hairs Column",
589		.type	= V4L2_CTRL_TYPE_INTEGER,
590		.min	= 0,
591		.max	= (1 << 12) - 1,
592		.step	= 1,
593		.def	= 0x64,
594		.flags	= V4L2_CTRL_FLAG_SLIDER,
595	}, {
596		.ops	= &xtpg_ctrl_ops,
597		.id	= V4L2_CID_XILINX_TPG_ZPLATE_HOR_START,
598		.name	= "Test Pattern: Zplate Horizontal Start Pos",
599		.type	= V4L2_CTRL_TYPE_INTEGER,
600		.min	= 0,
601		.max	= (1 << 16) - 1,
602		.step	= 1,
603		.def	= 0x1e,
604		.flags	= V4L2_CTRL_FLAG_SLIDER,
605	}, {
606		.ops	= &xtpg_ctrl_ops,
607		.id	= V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED,
608		.name	= "Test Pattern: Zplate Horizontal Speed",
609		.type	= V4L2_CTRL_TYPE_INTEGER,
610		.min	= 0,
611		.max	= (1 << 16) - 1,
612		.step	= 1,
613		.def	= 0,
614		.flags	= V4L2_CTRL_FLAG_SLIDER,
615	}, {
616		.ops	= &xtpg_ctrl_ops,
617		.id	= V4L2_CID_XILINX_TPG_ZPLATE_VER_START,
618		.name	= "Test Pattern: Zplate Vertical Start Pos",
619		.type	= V4L2_CTRL_TYPE_INTEGER,
620		.min	= 0,
621		.max	= (1 << 16) - 1,
622		.step	= 1,
623		.def	= 1,
624		.flags	= V4L2_CTRL_FLAG_SLIDER,
625	}, {
626		.ops	= &xtpg_ctrl_ops,
627		.id	= V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED,
628		.name	= "Test Pattern: Zplate Vertical Speed",
629		.type	= V4L2_CTRL_TYPE_INTEGER,
630		.min	= 0,
631		.max	= (1 << 16) - 1,
632		.step	= 1,
633		.def	= 0,
634		.flags	= V4L2_CTRL_FLAG_SLIDER,
635	}, {
636		.ops	= &xtpg_ctrl_ops,
637		.id	= V4L2_CID_XILINX_TPG_BOX_SIZE,
638		.name	= "Test Pattern: Box Size",
639		.type	= V4L2_CTRL_TYPE_INTEGER,
640		.min	= 0,
641		.max	= (1 << 12) - 1,
642		.step	= 1,
643		.def	= 0x32,
644		.flags	= V4L2_CTRL_FLAG_SLIDER,
645	}, {
646		.ops	= &xtpg_ctrl_ops,
647		.id	= V4L2_CID_XILINX_TPG_BOX_COLOR,
648		.name	= "Test Pattern: Box Color(RGB)",
649		.type	= V4L2_CTRL_TYPE_INTEGER,
650		.min	= 0,
651		.max	= (1 << 24) - 1,
652		.step	= 1,
653		.def	= 0,
654	}, {
655		.ops	= &xtpg_ctrl_ops,
656		.id	= V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH,
657		.name	= "Test Pattern: Stuck Pixel threshold",
658		.type	= V4L2_CTRL_TYPE_INTEGER,
659		.min	= 0,
660		.max	= (1 << 16) - 1,
661		.step	= 1,
662		.def	= 0,
663		.flags	= V4L2_CTRL_FLAG_SLIDER,
664	}, {
665		.ops	= &xtpg_ctrl_ops,
666		.id	= V4L2_CID_XILINX_TPG_NOISE_GAIN,
667		.name	= "Test Pattern: Noise Gain",
668		.type	= V4L2_CTRL_TYPE_INTEGER,
669		.min	= 0,
670		.max	= (1 << 8) - 1,
671		.step	= 1,
672		.def	= 0,
673		.flags	= V4L2_CTRL_FLAG_SLIDER,
674	},
675};
676
677/* -----------------------------------------------------------------------------
678 * Media Operations
679 */
680
681static const struct media_entity_operations xtpg_media_ops = {
682	.link_validate = v4l2_subdev_link_validate,
683};
684
685/* -----------------------------------------------------------------------------
686 * Power Management
687 */
688
689static int __maybe_unused xtpg_pm_suspend(struct device *dev)
690{
691	struct xtpg_device *xtpg = dev_get_drvdata(dev);
692
693	xvip_suspend(&xtpg->xvip);
694
695	return 0;
696}
697
698static int __maybe_unused xtpg_pm_resume(struct device *dev)
699{
700	struct xtpg_device *xtpg = dev_get_drvdata(dev);
701
702	xvip_resume(&xtpg->xvip);
703
704	return 0;
705}
706
707/* -----------------------------------------------------------------------------
708 * Platform Device Driver
709 */
710
711static int xtpg_parse_of(struct xtpg_device *xtpg)
712{
713	struct device *dev = xtpg->xvip.dev;
714	struct device_node *node = xtpg->xvip.dev->of_node;
715	unsigned int nports = 0;
716	bool has_endpoint = false;
717
718	for_each_of_graph_port(node, port) {
719		const struct xvip_video_format *format;
720		struct device_node *endpoint;
721
722		format = xvip_of_get_format(port);
723		if (IS_ERR(format)) {
724			dev_err(dev, "invalid format in DT");
725			return PTR_ERR(format);
726		}
727
728		/* Get and check the format description */
729		if (!xtpg->vip_format) {
730			xtpg->vip_format = format;
731		} else if (xtpg->vip_format != format) {
732			dev_err(dev, "in/out format mismatch in DT");
733			return -EINVAL;
734		}
735
736		if (nports == 0) {
737			endpoint = of_graph_get_next_port_endpoint(port, NULL);
738			if (endpoint)
739				has_endpoint = true;
740			of_node_put(endpoint);
741		}
742
743		/* Count the number of ports. */
744		nports++;
745	}
746
747	if (nports != 1 && nports != 2) {
748		dev_err(dev, "invalid number of ports %u\n", nports);
749		return -EINVAL;
750	}
751
752	xtpg->npads = nports;
753	if (nports == 2 && has_endpoint)
754		xtpg->has_input = true;
755
756	return 0;
757}
758
759static int xtpg_probe(struct platform_device *pdev)
760{
761	struct v4l2_subdev *subdev;
762	struct xtpg_device *xtpg;
763	u32 i, bayer_phase;
764	int ret;
765
766	xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL);
767	if (!xtpg)
768		return -ENOMEM;
769
770	xtpg->xvip.dev = &pdev->dev;
771
772	ret = xtpg_parse_of(xtpg);
773	if (ret < 0)
774		return ret;
775
776	ret = xvip_init_resources(&xtpg->xvip);
777	if (ret < 0)
778		return ret;
779
780	xtpg->vtmux_gpio = devm_gpiod_get_optional(&pdev->dev, "timing",
781						   GPIOD_OUT_HIGH);
782	if (IS_ERR(xtpg->vtmux_gpio)) {
783		ret = PTR_ERR(xtpg->vtmux_gpio);
784		goto error_resource;
785	}
786
787	xtpg->vtc = xvtc_of_get(pdev->dev.of_node);
788	if (IS_ERR(xtpg->vtc)) {
789		ret = PTR_ERR(xtpg->vtc);
790		goto error_resource;
791	}
792
793	/* Reset and initialize the core */
794	xvip_reset(&xtpg->xvip);
795
796	/* Initialize V4L2 subdevice and media entity. Pad numbers depend on the
797	 * number of pads.
798	 */
799	if (xtpg->npads == 2) {
800		xtpg->pads[0].flags = MEDIA_PAD_FL_SINK;
801		xtpg->pads[1].flags = MEDIA_PAD_FL_SOURCE;
802	} else {
803		xtpg->pads[0].flags = MEDIA_PAD_FL_SOURCE;
804	}
805
806	/* Initialize the default format */
807	xtpg->default_format.code = xtpg->vip_format->code;
808	xtpg->default_format.field = V4L2_FIELD_NONE;
809	xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB;
810	xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format);
811
812	bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code);
813	if (bayer_phase != XTPG_BAYER_PHASE_OFF)
814		xtpg->bayer = true;
815
816	xtpg->formats[0] = xtpg->default_format;
817	if (xtpg->npads == 2)
818		xtpg->formats[1] = xtpg->default_format;
819
820	/* Initialize V4L2 subdevice and media entity */
821	subdev = &xtpg->xvip.subdev;
822	v4l2_subdev_init(subdev, &xtpg_ops);
823	subdev->dev = &pdev->dev;
824	subdev->internal_ops = &xtpg_internal_ops;
825	strscpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
826	v4l2_set_subdevdata(subdev, xtpg);
827	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
828	subdev->entity.ops = &xtpg_media_ops;
829
830	ret = media_entity_pads_init(&subdev->entity, xtpg->npads, xtpg->pads);
831	if (ret < 0)
832		goto error;
833
834	v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls));
835
836	xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
837					 V4L2_CID_VBLANK, XTPG_MIN_VBLANK,
838					 XTPG_MAX_VBLANK, 1, 100);
839	xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
840					 V4L2_CID_HBLANK, XTPG_MIN_HBLANK,
841					 XTPG_MAX_HBLANK, 1, 100);
842	xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler,
843					&xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN,
844					ARRAY_SIZE(xtpg_pattern_strings) - 1,
845					1, 9, xtpg_pattern_strings);
846
847	for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++)
848		v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL);
849
850	if (xtpg->ctrl_handler.error) {
851		dev_err(&pdev->dev, "failed to add controls\n");
852		ret = xtpg->ctrl_handler.error;
853		goto error;
854	}
855	subdev->ctrl_handler = &xtpg->ctrl_handler;
856
857	xtpg_update_pattern_control(xtpg, true, true);
858
859	ret = v4l2_ctrl_handler_setup(&xtpg->ctrl_handler);
860	if (ret < 0) {
861		dev_err(&pdev->dev, "failed to set controls\n");
862		goto error;
863	}
864
865	platform_set_drvdata(pdev, xtpg);
866
867	xvip_print_version(&xtpg->xvip);
868
869	ret = v4l2_async_register_subdev(subdev);
870	if (ret < 0) {
871		dev_err(&pdev->dev, "failed to register subdev\n");
872		goto error;
873	}
874
875	return 0;
876
877error:
878	v4l2_ctrl_handler_free(&xtpg->ctrl_handler);
879	media_entity_cleanup(&subdev->entity);
880	xvtc_put(xtpg->vtc);
881error_resource:
882	xvip_cleanup_resources(&xtpg->xvip);
883	return ret;
884}
885
886static void xtpg_remove(struct platform_device *pdev)
887{
888	struct xtpg_device *xtpg = platform_get_drvdata(pdev);
889	struct v4l2_subdev *subdev = &xtpg->xvip.subdev;
890
891	v4l2_async_unregister_subdev(subdev);
892	v4l2_ctrl_handler_free(&xtpg->ctrl_handler);
893	media_entity_cleanup(&subdev->entity);
894
895	xvip_cleanup_resources(&xtpg->xvip);
896}
897
898static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume);
899
900static const struct of_device_id xtpg_of_id_table[] = {
901	{ .compatible = "xlnx,v-tpg-5.0" },
902	{ }
903};
904MODULE_DEVICE_TABLE(of, xtpg_of_id_table);
905
906static struct platform_driver xtpg_driver = {
907	.driver = {
908		.name		= "xilinx-tpg",
909		.pm		= &xtpg_pm_ops,
910		.of_match_table	= xtpg_of_id_table,
911	},
912	.probe			= xtpg_probe,
913	.remove			= xtpg_remove,
914};
915
916module_platform_driver(xtpg_driver);
917
918MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
919MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver");
920MODULE_LICENSE("GPL v2");
~/ Read-only file preview.