1
2
3
4
5
6
7
8
9
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 0x0100
30#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 6
34#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 0x0104
39#define XTPG_CROSS_HAIRS 0x0108
40#define XTPG_CROSS_HAIRS_ROW_SHIFT 0
41#define XTPG_CROSS_HAIRS_ROW_MASK (0xfff << 0)
42#define XTPG_CROSS_HAIRS_COLUMN_SHIFT 16
43#define XTPG_CROSS_HAIRS_COLUMN_MASK (0xfff << 16)
44#define XTPG_ZPLATE_HOR_CONTROL 0x010c
45#define XTPG_ZPLATE_VER_CONTROL 0x0110
46#define XTPG_ZPLATE_START_SHIFT 0
47#define XTPG_ZPLATE_START_MASK (0xffff << 0)
48#define XTPG_ZPLATE_SPEED_SHIFT 16
49#define XTPG_ZPLATE_SPEED_MASK (0xffff << 16)
50#define XTPG_BOX_SIZE 0x0114
51#define XTPG_BOX_COLOR 0x0118
52#define XTPG_STUCK_PIXEL_THRESH 0x011c
53#define XTPG_NOISE_GAIN 0x0120
54#define XTPG_BAYER_PHASE 0x0124
55#define XTPG_BAYER_PHASE_RGGB 0
56#define XTPG_BAYER_PHASE_GRBG 1
57#define XTPG_BAYER_PHASE_GBRG 2
58#define XTPG_BAYER_PHASE_BGGR 3
59#define XTPG_BAYER_PHASE_OFF 4
60
61
62
63
64
65#define XTPG_MIN_HBLANK 3
66#define XTPG_MAX_HBLANK (XVTC_MAX_HSIZE - XVIP_MIN_WIDTH)
67#define XTPG_MIN_VBLANK 3
68#define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT)
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
138
139
140 if (xtpg->npads == 1 || !xtpg->has_input)
141 passthrough = false;
142
143
144 if (passthrough)
145 pattern_mask &= ~1;
146
147
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
165
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
212
213
214
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
223
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
234
235
236 bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF
237 : 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
250
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_get_try_format(&xtpg->xvip.subdev,
260 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
291
292
293 if (xtpg->npads == 2 && fmt->pad == 1) {
294 fmt->format = *__format;
295 return 0;
296 }
297
298
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
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
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_get_try_format(subdev, sd_state, fse->pad);
330
331 if (fse->index || fse->code != format->code)
332 return -EINVAL;
333
334
335
336
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_get_try_format(subdev, fh->state, 0);
358 *format = xtpg->default_format;
359
360 if (xtpg->npads == 2) {
361 format = v4l2_subdev_get_try_format(subdev, 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
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
679
680
681static const struct media_entity_operations xtpg_media_ops = {
682 .link_validate = v4l2_subdev_link_validate,
683};
684
685
686
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
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 struct device_node *ports;
716 struct device_node *port;
717 unsigned int nports = 0;
718 bool has_endpoint = false;
719
720 ports = of_get_child_by_name(node, "ports");
721 if (ports == NULL)
722 ports = node;
723
724 for_each_child_of_node(ports, port) {
725 const struct xvip_video_format *format;
726 struct device_node *endpoint;
727
728 if (!of_node_name_eq(port, "port"))
729 continue;
730
731 format = xvip_of_get_format(port);
732 if (IS_ERR(format)) {
733 dev_err(dev, "invalid format in DT");
734 of_node_put(port);
735 return PTR_ERR(format);
736 }
737
738
739 if (!xtpg->vip_format) {
740 xtpg->vip_format = format;
741 } else if (xtpg->vip_format != format) {
742 dev_err(dev, "in/out format mismatch in DT");
743 of_node_put(port);
744 return -EINVAL;
745 }
746
747 if (nports == 0) {
748 endpoint = of_get_next_child(port, NULL);
749 if (endpoint)
750 has_endpoint = true;
751 of_node_put(endpoint);
752 }
753
754
755 nports++;
756 }
757
758 if (nports != 1 && nports != 2) {
759 dev_err(dev, "invalid number of ports %u\n", nports);
760 return -EINVAL;
761 }
762
763 xtpg->npads = nports;
764 if (nports == 2 && has_endpoint)
765 xtpg->has_input = true;
766
767 return 0;
768}
769
770static int xtpg_probe(struct platform_device *pdev)
771{
772 struct v4l2_subdev *subdev;
773 struct xtpg_device *xtpg;
774 u32 i, bayer_phase;
775 int ret;
776
777 xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL);
778 if (!xtpg)
779 return -ENOMEM;
780
781 xtpg->xvip.dev = &pdev->dev;
782
783 ret = xtpg_parse_of(xtpg);
784 if (ret < 0)
785 return ret;
786
787 ret = xvip_init_resources(&xtpg->xvip);
788 if (ret < 0)
789 return ret;
790
791 xtpg->vtmux_gpio = devm_gpiod_get_optional(&pdev->dev, "timing",
792 GPIOD_OUT_HIGH);
793 if (IS_ERR(xtpg->vtmux_gpio)) {
794 ret = PTR_ERR(xtpg->vtmux_gpio);
795 goto error_resource;
796 }
797
798 xtpg->vtc = xvtc_of_get(pdev->dev.of_node);
799 if (IS_ERR(xtpg->vtc)) {
800 ret = PTR_ERR(xtpg->vtc);
801 goto error_resource;
802 }
803
804
805 xvip_reset(&xtpg->xvip);
806
807
808
809
810 if (xtpg->npads == 2) {
811 xtpg->pads[0].flags = MEDIA_PAD_FL_SINK;
812 xtpg->pads[1].flags = MEDIA_PAD_FL_SOURCE;
813 } else {
814 xtpg->pads[0].flags = MEDIA_PAD_FL_SOURCE;
815 }
816
817
818 xtpg->default_format.code = xtpg->vip_format->code;
819 xtpg->default_format.field = V4L2_FIELD_NONE;
820 xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB;
821 xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format);
822
823 bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code);
824 if (bayer_phase != XTPG_BAYER_PHASE_OFF)
825 xtpg->bayer = true;
826
827 xtpg->formats[0] = xtpg->default_format;
828 if (xtpg->npads == 2)
829 xtpg->formats[1] = xtpg->default_format;
830
831
832 subdev = &xtpg->xvip.subdev;
833 v4l2_subdev_init(subdev, &xtpg_ops);
834 subdev->dev = &pdev->dev;
835 subdev->internal_ops = &xtpg_internal_ops;
836 strscpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
837 v4l2_set_subdevdata(subdev, xtpg);
838 subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
839 subdev->entity.ops = &xtpg_media_ops;
840
841 ret = media_entity_pads_init(&subdev->entity, xtpg->npads, xtpg->pads);
842 if (ret < 0)
843 goto error;
844
845 v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls));
846
847 xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
848 V4L2_CID_VBLANK, XTPG_MIN_VBLANK,
849 XTPG_MAX_VBLANK, 1, 100);
850 xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
851 V4L2_CID_HBLANK, XTPG_MIN_HBLANK,
852 XTPG_MAX_HBLANK, 1, 100);
853 xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler,
854 &xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN,
855 ARRAY_SIZE(xtpg_pattern_strings) - 1,
856 1, 9, xtpg_pattern_strings);
857
858 for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++)
859 v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL);
860
861 if (xtpg->ctrl_handler.error) {
862 dev_err(&pdev->dev, "failed to add controls\n");
863 ret = xtpg->ctrl_handler.error;
864 goto error;
865 }
866 subdev->ctrl_handler = &xtpg->ctrl_handler;
867
868 xtpg_update_pattern_control(xtpg, true, true);
869
870 ret = v4l2_ctrl_handler_setup(&xtpg->ctrl_handler);
871 if (ret < 0) {
872 dev_err(&pdev->dev, "failed to set controls\n");
873 goto error;
874 }
875
876 platform_set_drvdata(pdev, xtpg);
877
878 xvip_print_version(&xtpg->xvip);
879
880 ret = v4l2_async_register_subdev(subdev);
881 if (ret < 0) {
882 dev_err(&pdev->dev, "failed to register subdev\n");
883 goto error;
884 }
885
886 return 0;
887
888error:
889 v4l2_ctrl_handler_free(&xtpg->ctrl_handler);
890 media_entity_cleanup(&subdev->entity);
891 xvtc_put(xtpg->vtc);
892error_resource:
893 xvip_cleanup_resources(&xtpg->xvip);
894 return ret;
895}
896
897static int xtpg_remove(struct platform_device *pdev)
898{
899 struct xtpg_device *xtpg = platform_get_drvdata(pdev);
900 struct v4l2_subdev *subdev = &xtpg->xvip.subdev;
901
902 v4l2_async_unregister_subdev(subdev);
903 v4l2_ctrl_handler_free(&xtpg->ctrl_handler);
904 media_entity_cleanup(&subdev->entity);
905
906 xvip_cleanup_resources(&xtpg->xvip);
907
908 return 0;
909}
910
911static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume);
912
913static const struct of_device_id xtpg_of_id_table[] = {
914 { .compatible = "xlnx,v-tpg-5.0" },
915 { }
916};
917MODULE_DEVICE_TABLE(of, xtpg_of_id_table);
918
919static struct platform_driver xtpg_driver = {
920 .driver = {
921 .name = "xilinx-tpg",
922 .pm = &xtpg_pm_ops,
923 .of_match_table = xtpg_of_id_table,
924 },
925 .probe = xtpg_probe,
926 .remove = xtpg_remove,
927};
928
929module_platform_driver(xtpg_driver);
930
931MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
932MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver");
933MODULE_LICENSE("GPL v2");
934