1123475Swpaul// SPDX-License-Identifier: GPL-2.0 2123475Swpaul/* 3123475Swpaul * Xilinx Test Pattern Generator 4123475Swpaul * 5123475Swpaul * Copyright (C) 2013-2015 Ideas on Board 6123475Swpaul * Copyright (C) 2013-2015 Xilinx, Inc. 7123475Swpaul * 8123475Swpaul * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> 9123475Swpaul * Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10123475Swpaul */ 11123475Swpaul 12123475Swpaul#include <linux/device.h> 13123475Swpaul#include <linux/gpio/consumer.h> 14123475Swpaul#include <linux/module.h> 15123475Swpaul#include <linux/of.h> 16123475Swpaul#include <linux/platform_device.h> 17123475Swpaul#include <linux/xilinx-v4l2-controls.h> 18123475Swpaul 19123475Swpaul#include <media/v4l2-async.h> 20123475Swpaul#include <media/v4l2-ctrls.h> 21123475Swpaul#include <media/v4l2-subdev.h> 22123475Swpaul 23123475Swpaul#include "xilinx-vip.h" 24123475Swpaul#include "xilinx-vtc.h" 25123475Swpaul 26123475Swpaul#define XTPG_CTRL_STATUS_SLAVE_ERROR (1 << 16) 27123475Swpaul#define XTPG_CTRL_IRQ_SLAVE_ERROR (1 << 16) 28123475Swpaul 29123475Swpaul#define XTPG_PATTERN_CONTROL 0x0100 30123475Swpaul#define XTPG_PATTERN_MASK (0xf << 0) 31123475Swpaul#define XTPG_PATTERN_CONTROL_CROSS_HAIRS (1 << 4) 32123475Swpaul#define XTPG_PATTERN_CONTROL_MOVING_BOX (1 << 5) 33123475Swpaul#define XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT 6 34123475Swpaul#define XTPG_PATTERN_CONTROL_COLOR_MASK_MASK (0xf << 6) 35123475Swpaul#define XTPG_PATTERN_CONTROL_STUCK_PIXEL (1 << 9) 36123475Swpaul#define XTPG_PATTERN_CONTROL_NOISE (1 << 10) 37123475Swpaul#define XTPG_PATTERN_CONTROL_MOTION (1 << 12) 38123475Swpaul#define XTPG_MOTION_SPEED 0x0104 39123475Swpaul#define XTPG_CROSS_HAIRS 0x0108 40123475Swpaul#define XTPG_CROSS_HAIRS_ROW_SHIFT 0 41123475Swpaul#define XTPG_CROSS_HAIRS_ROW_MASK (0xfff << 0) 42123475Swpaul#define XTPG_CROSS_HAIRS_COLUMN_SHIFT 16 43123475Swpaul#define XTPG_CROSS_HAIRS_COLUMN_MASK (0xfff << 16) 44123475Swpaul#define XTPG_ZPLATE_HOR_CONTROL 0x010c 45123475Swpaul#define XTPG_ZPLATE_VER_CONTROL 0x0110 46123475Swpaul#define XTPG_ZPLATE_START_SHIFT 0 47123475Swpaul#define XTPG_ZPLATE_START_MASK (0xffff << 0) 48123475Swpaul#define XTPG_ZPLATE_SPEED_SHIFT 16 49123475Swpaul#define XTPG_ZPLATE_SPEED_MASK (0xffff << 16) 50123475Swpaul#define XTPG_BOX_SIZE 0x0114 51123475Swpaul#define XTPG_BOX_COLOR 0x0118 52123475Swpaul#define XTPG_STUCK_PIXEL_THRESH 0x011c 53123475Swpaul#define XTPG_NOISE_GAIN 0x0120 54123475Swpaul#define XTPG_BAYER_PHASE 0x0124 55123475Swpaul#define XTPG_BAYER_PHASE_RGGB 0 56123475Swpaul#define XTPG_BAYER_PHASE_GRBG 1 57123475Swpaul#define XTPG_BAYER_PHASE_GBRG 2 58123475Swpaul#define XTPG_BAYER_PHASE_BGGR 3 59123475Swpaul#define XTPG_BAYER_PHASE_OFF 4 60123475Swpaul 61123475Swpaul/* 62123475Swpaul * The minimum blanking value is one clock cycle for the front porch, one clock 63123475Swpaul * cycle for the sync pulse and one clock cycle for the back porch. 64123475Swpaul */ 65123475Swpaul#define XTPG_MIN_HBLANK 3 66123475Swpaul#define XTPG_MAX_HBLANK (XVTC_MAX_HSIZE - XVIP_MIN_WIDTH) 67123475Swpaul#define XTPG_MIN_VBLANK 3 68123475Swpaul#define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT) 69123475Swpaul 70123475Swpaul/** 71123475Swpaul * struct xtpg_device - Xilinx Test Pattern Generator device structure 72123475Swpaul * @xvip: Xilinx Video IP device 73123475Swpaul * @pads: media pads 74123475Swpaul * @npads: number of pads (1 or 2) 75123475Swpaul * @has_input: whether an input is connected to the sink pad 76123475Swpaul * @formats: active V4L2 media bus format for each pad 77123475Swpaul * @default_format: default V4L2 media bus format 78123475Swpaul * @vip_format: format information corresponding to the active format 79123475Swpaul * @bayer: boolean flag if TPG is set to any bayer format 80123475Swpaul * @ctrl_handler: control handler 81123475Swpaul * @hblank: horizontal blanking control 82123475Swpaul * @vblank: vertical blanking control 83123475Swpaul * @pattern: test pattern control 84123475Swpaul * @streaming: is the video stream active 85123475Swpaul * @vtc: video timing controller 86123475Swpaul * @vtmux_gpio: video timing mux GPIO 87123475Swpaul */ 88123475Swpaulstruct xtpg_device { 89123475Swpaul struct xvip_device xvip; 90123475Swpaul 91123475Swpaul struct media_pad pads[2]; 92123475Swpaul unsigned int npads; 93123475Swpaul bool has_input; 94123475Swpaul 95123475Swpaul struct v4l2_mbus_framefmt formats[2]; 96123475Swpaul struct v4l2_mbus_framefmt default_format; 97123475Swpaul const struct xvip_video_format *vip_format; 98123475Swpaul bool bayer; 99123475Swpaul 100123475Swpaul struct v4l2_ctrl_handler ctrl_handler; 101123475Swpaul struct v4l2_ctrl *hblank; 102123475Swpaul struct v4l2_ctrl *vblank; 103123475Swpaul struct v4l2_ctrl *pattern; 104123475Swpaul bool streaming; 105123475Swpaul 106123475Swpaul struct xvtc_device *vtc; 107123475Swpaul struct gpio_desc *vtmux_gpio; 108123475Swpaul}; 109123475Swpaul 110123475Swpaulstatic inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev) 111123475Swpaul{ 112123475Swpaul return container_of(subdev, struct xtpg_device, xvip.subdev); 113123475Swpaul} 114123475Swpaul 115123475Swpaulstatic u32 xtpg_get_bayer_phase(unsigned int code) 116123475Swpaul{ 117123475Swpaul switch (code) { 118123475Swpaul case MEDIA_BUS_FMT_SRGGB8_1X8: 119123475Swpaul return XTPG_BAYER_PHASE_RGGB; 120123475Swpaul case MEDIA_BUS_FMT_SGRBG8_1X8: 121123475Swpaul return XTPG_BAYER_PHASE_GRBG; 122123475Swpaul case MEDIA_BUS_FMT_SGBRG8_1X8: 123123475Swpaul return XTPG_BAYER_PHASE_GBRG; 124123475Swpaul case MEDIA_BUS_FMT_SBGGR8_1X8: 125123475Swpaul return XTPG_BAYER_PHASE_BGGR; 126123475Swpaul default: 127123475Swpaul return XTPG_BAYER_PHASE_OFF; 128123475Swpaul } 129123475Swpaul} 130123475Swpaul 131123475Swpaulstatic void __xtpg_update_pattern_control(struct xtpg_device *xtpg, 132123475Swpaul bool passthrough, bool pattern) 133123475Swpaul{ 134123475Swpaul u32 pattern_mask = (1 << (xtpg->pattern->maximum + 1)) - 1; 135123475Swpaul 136123475Swpaul /* 137123475Swpaul * If the TPG has no sink pad or no input connected to its sink pad 138123475Swpaul * passthrough mode can't be enabled. 139123475Swpaul */ 140123475Swpaul if (xtpg->npads == 1 || !xtpg->has_input) 141123475Swpaul passthrough = false; 142123475Swpaul 143123475Swpaul /* If passthrough mode is allowed unmask bit 0. */ 144123475Swpaul if (passthrough) 145123475Swpaul pattern_mask &= ~1; 146123475Swpaul 147123475Swpaul /* If test pattern mode is allowed unmask all other bits. */ 148123475Swpaul if (pattern) 149123483Swpaul pattern_mask &= 1; 150123475Swpaul 151123475Swpaul __v4l2_ctrl_modify_range(xtpg->pattern, 0, xtpg->pattern->maximum, 152123475Swpaul pattern_mask, pattern ? 9 : 0); 153123475Swpaul} 154123475Swpaul 155123483Swpaulstatic void xtpg_update_pattern_control(struct xtpg_device *xtpg, 156123483Swpaul bool passthrough, bool pattern) 157123483Swpaul{ 158123483Swpaul mutex_lock(xtpg->ctrl_handler.lock); 159123483Swpaul __xtpg_update_pattern_control(xtpg, passthrough, pattern); 160123483Swpaul mutex_unlock(xtpg->ctrl_handler.lock); 161123483Swpaul} 162123483Swpaul 163123475Swpaul/* ----------------------------------------------------------------------------- 164123475Swpaul * V4L2 Subdevice Video Operations 165123475Swpaul */ 166123475Swpaul 167123475Swpaulstatic int xtpg_s_stream(struct v4l2_subdev *subdev, int enable) 168123475Swpaul{ 169123475Swpaul struct xtpg_device *xtpg = to_tpg(subdev); 170123475Swpaul unsigned int width = xtpg->formats[0].width; 171123475Swpaul unsigned int height = xtpg->formats[0].height; 172123475Swpaul bool passthrough; 173123475Swpaul u32 bayer_phase; 174123475Swpaul 175123475Swpaul if (!enable) { 176123475Swpaul xvip_stop(&xtpg->xvip); 177123475Swpaul if (xtpg->vtc) 178123475Swpaul xvtc_generator_stop(xtpg->vtc); 179123475Swpaul 180123475Swpaul xtpg_update_pattern_control(xtpg, true, true); 181123475Swpaul xtpg->streaming = false; 182123475Swpaul return 0; 183123475Swpaul } 184123480Swpaul 185123475Swpaul xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]); 186123475Swpaul 187123475Swpaul if (xtpg->vtc) { 188123475Swpaul struct xvtc_config config = { 189123475Swpaul .hblank_start = width, 190123480Swpaul .hsync_start = width + 1, 191123480Swpaul .vblank_start = height, 192123475Swpaul .vsync_start = height + 1, 193123475Swpaul }; 194123475Swpaul unsigned int htotal; 195123475Swpaul unsigned int vtotal; 196123475Swpaul 197123475Swpaul htotal = min_t(unsigned int, XVTC_MAX_HSIZE, 198123475Swpaul v4l2_ctrl_g_ctrl(xtpg->hblank) + width); 199123475Swpaul vtotal = min_t(unsigned int, XVTC_MAX_VSIZE, 200123475Swpaul v4l2_ctrl_g_ctrl(xtpg->vblank) + height); 201123475Swpaul 202123475Swpaul config.hsync_end = htotal - 1; 203123475Swpaul config.hsize = htotal; 204123475Swpaul config.vsync_end = vtotal - 1; 205123475Swpaul config.vsize = vtotal; 206123475Swpaul 207123475Swpaul xvtc_generator_start(xtpg->vtc, &config); 208123475Swpaul } 209123475Swpaul 210123475Swpaul /* 211123475Swpaul * Configure the bayer phase and video timing mux based on the 212123475Swpaul * operation mode (passthrough or test pattern generation). The test 213123475Swpaul * pattern can be modified by the control set handler, we thus need to 214123475Swpaul * take the control lock here to avoid races. 215123475Swpaul */ 216123475Swpaul mutex_lock(xtpg->ctrl_handler.lock); 217123483Swpaul 218123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 219123475Swpaul XTPG_PATTERN_MASK, xtpg->pattern->cur.val); 220123475Swpaul 221123475Swpaul /* 222123475Swpaul * Switching between passthrough and test pattern generation modes isn't 223123475Swpaul * allowed during streaming, update the control range accordingly. 224123475Swpaul */ 225123475Swpaul passthrough = xtpg->pattern->cur.val == 0; 226123475Swpaul __xtpg_update_pattern_control(xtpg, passthrough, !passthrough); 227123475Swpaul 228123475Swpaul xtpg->streaming = true; 229123475Swpaul 230123475Swpaul mutex_unlock(xtpg->ctrl_handler.lock); 231123475Swpaul 232123475Swpaul /* 233123475Swpaul * For TPG v5.0, the bayer phase needs to be off for the pass through 234123475Swpaul * mode, otherwise the external input would be subsampled. 235123475Swpaul */ 236123475Swpaul bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF 237123475Swpaul : xtpg_get_bayer_phase(xtpg->formats[0].code); 238123475Swpaul xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase); 239123475Swpaul 240123483Swpaul if (xtpg->vtmux_gpio) 241123483Swpaul gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough); 242123475Swpaul 243123475Swpaul xvip_start(&xtpg->xvip); 244123475Swpaul 245123475Swpaul return 0; 246123475Swpaul} 247123475Swpaul 248123475Swpaul/* ----------------------------------------------------------------------------- 249123475Swpaul * V4L2 Subdevice Pad Operations 250123475Swpaul */ 251123475Swpaul 252123475Swpaulstatic struct v4l2_mbus_framefmt * 253123475Swpaul__xtpg_get_pad_format(struct xtpg_device *xtpg, 254123475Swpaul struct v4l2_subdev_state *sd_state, 255123475Swpaul unsigned int pad, u32 which) 256123475Swpaul{ 257123475Swpaul switch (which) { 258123475Swpaul case V4L2_SUBDEV_FORMAT_TRY: 259123475Swpaul return v4l2_subdev_state_get_format(sd_state, pad); 260123475Swpaul case V4L2_SUBDEV_FORMAT_ACTIVE: 261123475Swpaul return &xtpg->formats[pad]; 262123475Swpaul default: 263123475Swpaul return NULL; 264123475Swpaul } 265123475Swpaul} 266123475Swpaul 267123475Swpaulstatic int xtpg_get_format(struct v4l2_subdev *subdev, 268123475Swpaul struct v4l2_subdev_state *sd_state, 269123475Swpaul struct v4l2_subdev_format *fmt) 270123475Swpaul{ 271123475Swpaul struct xtpg_device *xtpg = to_tpg(subdev); 272123475Swpaul 273123475Swpaul fmt->format = *__xtpg_get_pad_format(xtpg, sd_state, fmt->pad, 274123475Swpaul fmt->which); 275123475Swpaul 276123475Swpaul return 0; 277123475Swpaul} 278123475Swpaul 279123475Swpaulstatic int xtpg_set_format(struct v4l2_subdev *subdev, 280123475Swpaul struct v4l2_subdev_state *sd_state, 281123475Swpaul struct v4l2_subdev_format *fmt) 282123475Swpaul{ 283123475Swpaul struct xtpg_device *xtpg = to_tpg(subdev); 284123475Swpaul struct v4l2_mbus_framefmt *__format; 285123475Swpaul u32 bayer_phase; 286123475Swpaul 287123475Swpaul __format = __xtpg_get_pad_format(xtpg, sd_state, fmt->pad, fmt->which); 288123475Swpaul 289123475Swpaul /* In two pads mode the source pad format is always identical to the 290123475Swpaul * sink pad format. 291123475Swpaul */ 292123475Swpaul if (xtpg->npads == 2 && fmt->pad == 1) { 293123475Swpaul fmt->format = *__format; 294123475Swpaul return 0; 295123475Swpaul } 296123475Swpaul 297123475Swpaul /* Bayer phase is configurable at runtime */ 298123475Swpaul if (xtpg->bayer) { 299123475Swpaul bayer_phase = xtpg_get_bayer_phase(fmt->format.code); 300123475Swpaul if (bayer_phase != XTPG_BAYER_PHASE_OFF) 301123475Swpaul __format->code = fmt->format.code; 302123475Swpaul } 303123475Swpaul 304123475Swpaul xvip_set_format_size(__format, fmt); 305123475Swpaul 306123475Swpaul fmt->format = *__format; 307123475Swpaul 308123475Swpaul /* Propagate the format to the source pad. */ 309123475Swpaul if (xtpg->npads == 2) { 310123475Swpaul __format = __xtpg_get_pad_format(xtpg, sd_state, 1, 311123475Swpaul fmt->which); 312123475Swpaul *__format = fmt->format; 313123475Swpaul } 314123475Swpaul 315123475Swpaul return 0; 316123475Swpaul} 317123475Swpaul 318123475Swpaul/* ----------------------------------------------------------------------------- 319123475Swpaul * V4L2 Subdevice Operations 320123475Swpaul */ 321123475Swpaul 322123475Swpaulstatic int xtpg_enum_frame_size(struct v4l2_subdev *subdev, 323123475Swpaul struct v4l2_subdev_state *sd_state, 324123475Swpaul struct v4l2_subdev_frame_size_enum *fse) 325123475Swpaul{ 326123475Swpaul struct v4l2_mbus_framefmt *format; 327123475Swpaul 328123475Swpaul format = v4l2_subdev_state_get_format(sd_state, fse->pad); 329123475Swpaul 330123475Swpaul if (fse->index || fse->code != format->code) 331123475Swpaul return -EINVAL; 332123475Swpaul 333123475Swpaul /* Min / max values for pad 0 is always fixed in both one and two pads 334123475Swpaul * modes. In two pads mode, the source pad(= 1) size is identical to 335123475Swpaul * the sink pad size */ 336123475Swpaul if (fse->pad == 0) { 337123475Swpaul fse->min_width = XVIP_MIN_WIDTH; 338123475Swpaul fse->max_width = XVIP_MAX_WIDTH; 339123475Swpaul fse->min_height = XVIP_MIN_HEIGHT; 340123475Swpaul fse->max_height = XVIP_MAX_HEIGHT; 341123475Swpaul } else { 342123475Swpaul fse->min_width = format->width; 343123475Swpaul fse->max_width = format->width; 344123475Swpaul fse->min_height = format->height; 345123475Swpaul fse->max_height = format->height; 346123475Swpaul } 347123475Swpaul 348123475Swpaul return 0; 349123475Swpaul} 350123475Swpaul 351123475Swpaulstatic int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) 352123475Swpaul{ 353123475Swpaul struct xtpg_device *xtpg = to_tpg(subdev); 354123475Swpaul struct v4l2_mbus_framefmt *format; 355123475Swpaul 356123475Swpaul format = v4l2_subdev_state_get_format(fh->state, 0); 357123475Swpaul *format = xtpg->default_format; 358123475Swpaul 359123475Swpaul if (xtpg->npads == 2) { 360123475Swpaul format = v4l2_subdev_state_get_format(fh->state, 1); 361123475Swpaul *format = xtpg->default_format; 362123475Swpaul } 363123475Swpaul 364123483Swpaul return 0; 365123475Swpaul} 366123475Swpaul 367123475Swpaulstatic int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) 368123475Swpaul{ 369123475Swpaul return 0; 370123475Swpaul} 371123475Swpaul 372123483Swpaulstatic int xtpg_s_ctrl(struct v4l2_ctrl *ctrl) 373123483Swpaul{ 374123483Swpaul struct xtpg_device *xtpg = container_of(ctrl->handler, 375123483Swpaul struct xtpg_device, 376123483Swpaul ctrl_handler); 377123483Swpaul switch (ctrl->id) { 378123483Swpaul case V4L2_CID_TEST_PATTERN: 379123483Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 380123483Swpaul XTPG_PATTERN_MASK, ctrl->val); 381123475Swpaul return 0; 382123475Swpaul case V4L2_CID_XILINX_TPG_CROSS_HAIRS: 383123475Swpaul xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 384123475Swpaul XTPG_PATTERN_CONTROL_CROSS_HAIRS, ctrl->val); 385123475Swpaul return 0; 386123475Swpaul case V4L2_CID_XILINX_TPG_MOVING_BOX: 387123475Swpaul xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 388123475Swpaul XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val); 389123475Swpaul return 0; 390123475Swpaul case V4L2_CID_XILINX_TPG_COLOR_MASK: 391123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 392123475Swpaul XTPG_PATTERN_CONTROL_COLOR_MASK_MASK, 393123475Swpaul ctrl->val << 394123475Swpaul XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT); 395123475Swpaul return 0; 396123475Swpaul case V4L2_CID_XILINX_TPG_STUCK_PIXEL: 397123475Swpaul xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 398123475Swpaul XTPG_PATTERN_CONTROL_STUCK_PIXEL, ctrl->val); 399123475Swpaul return 0; 400123483Swpaul case V4L2_CID_XILINX_TPG_NOISE: 401123483Swpaul xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 402123483Swpaul XTPG_PATTERN_CONTROL_NOISE, ctrl->val); 403123483Swpaul return 0; 404123483Swpaul case V4L2_CID_XILINX_TPG_MOTION: 405123483Swpaul xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, 406123483Swpaul XTPG_PATTERN_CONTROL_MOTION, ctrl->val); 407123483Swpaul return 0; 408123483Swpaul case V4L2_CID_XILINX_TPG_MOTION_SPEED: 409123483Swpaul xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val); 410123483Swpaul return 0; 411123483Swpaul case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW: 412123483Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, 413123483Swpaul XTPG_CROSS_HAIRS_ROW_MASK, 414123475Swpaul ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT); 415123475Swpaul return 0; 416123475Swpaul case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN: 417123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, 418123475Swpaul XTPG_CROSS_HAIRS_COLUMN_MASK, 419123475Swpaul ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT); 420123475Swpaul return 0; 421123475Swpaul case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START: 422123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, 423123475Swpaul XTPG_ZPLATE_START_MASK, 424123475Swpaul ctrl->val << XTPG_ZPLATE_START_SHIFT); 425123475Swpaul return 0; 426123475Swpaul case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED: 427123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, 428123475Swpaul XTPG_ZPLATE_SPEED_MASK, 429123475Swpaul ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); 430123475Swpaul return 0; 431123475Swpaul case V4L2_CID_XILINX_TPG_ZPLATE_VER_START: 432123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, 433123475Swpaul XTPG_ZPLATE_START_MASK, 434123475Swpaul ctrl->val << XTPG_ZPLATE_START_SHIFT); 435123475Swpaul return 0; 436123475Swpaul case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED: 437123475Swpaul xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, 438123475Swpaul XTPG_ZPLATE_SPEED_MASK, 439123475Swpaul ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); 440123475Swpaul return 0; 441123475Swpaul case V4L2_CID_XILINX_TPG_BOX_SIZE: 442123475Swpaul xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val); 443123475Swpaul return 0; 444123475Swpaul case V4L2_CID_XILINX_TPG_BOX_COLOR: 445123475Swpaul xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val); 446123475Swpaul return 0; 447123475Swpaul case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH: 448123475Swpaul xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val); 449123475Swpaul return 0; 450123475Swpaul case V4L2_CID_XILINX_TPG_NOISE_GAIN: 451123475Swpaul xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val); 452123475Swpaul return 0; 453123475Swpaul } 454123475Swpaul 455123475Swpaul return 0; 456123475Swpaul} 457123475Swpaul 458123475Swpaulstatic const struct v4l2_ctrl_ops xtpg_ctrl_ops = { 459123475Swpaul .s_ctrl = xtpg_s_ctrl, 460123475Swpaul}; 461123475Swpaul 462123475Swpaulstatic const struct v4l2_subdev_core_ops xtpg_core_ops = { 463123475Swpaul}; 464123475Swpaul 465123475Swpaulstatic const struct v4l2_subdev_video_ops xtpg_video_ops = { 466123475Swpaul .s_stream = xtpg_s_stream, 467123475Swpaul}; 468123475Swpaul 469123475Swpaulstatic const struct v4l2_subdev_pad_ops xtpg_pad_ops = { 470123475Swpaul .enum_mbus_code = xvip_enum_mbus_code, 471123475Swpaul .enum_frame_size = xtpg_enum_frame_size, 472123475Swpaul .get_fmt = xtpg_get_format, 473123475Swpaul .set_fmt = xtpg_set_format, 474123475Swpaul}; 475123475Swpaul 476123475Swpaulstatic const struct v4l2_subdev_ops xtpg_ops = { 477123475Swpaul .core = &xtpg_core_ops, 478123475Swpaul .video = &xtpg_video_ops, 479123475Swpaul .pad = &xtpg_pad_ops, 480123475Swpaul}; 481123475Swpaul 482123475Swpaulstatic const struct v4l2_subdev_internal_ops xtpg_internal_ops = { 483123475Swpaul .open = xtpg_open, 484123475Swpaul .close = xtpg_close, 485123475Swpaul}; 486123475Swpaul 487123475Swpaul/* 488123475Swpaul * Control Config 489123475Swpaul */ 490123475Swpaul 491123475Swpaulstatic const char *const xtpg_pattern_strings[] = { 492123475Swpaul "Passthrough", 493123475Swpaul "Horizontal Ramp", 494123475Swpaul "Vertical Ramp", 495123475Swpaul "Temporal Ramp", 496123475Swpaul "Solid Red", 497123475Swpaul "Solid Green", 498123475Swpaul "Solid Blue", 499123475Swpaul "Solid Black", 500123475Swpaul "Solid White", 501123475Swpaul "Color Bars", 502123475Swpaul "Zone Plate", 503123475Swpaul "Tartan Color Bars", 504123475Swpaul "Cross Hatch", 505123475Swpaul "None", 506123475Swpaul "Vertical/Horizontal Ramps", 507123475Swpaul "Black/White Checker Board", 508123475Swpaul}; 509123475Swpaul 510123475Swpaulstatic struct v4l2_ctrl_config xtpg_ctrls[] = { 511123475Swpaul { 512123475Swpaul .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 Operations 678 */ 679 680static const struct media_entity_operations xtpg_media_ops = { 681 .link_validate = v4l2_subdev_link_validate, 682}; 683 684/* ----------------------------------------------------------------------------- 685 * Power Management 686 */ 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 Driver 708 */ 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 the 807 * 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