brintos

brintos / linux-shallow public Read only

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