xref: /linux/drivers/media/pci/hws/hws_v4l2_ioctl.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/kernel.h>
3 #include <linux/string.h>
4 #include <linux/pci.h>
5 #include <linux/errno.h>
6 #include <linux/io.h>
7 #include <linux/math64.h>
8 
9 #include <media/v4l2-ioctl.h>
10 #include <media/v4l2-dev.h>
11 #include <media/v4l2-dv-timings.h>
12 #include <media/videobuf2-core.h>
13 #include <media/videobuf2-v4l2.h>
14 
15 #include "hws.h"
16 #include "hws_reg.h"
17 #include "hws_video.h"
18 #include "hws_v4l2_ioctl.h"
19 
20 struct hws_dv_mode {
21 	struct v4l2_dv_timings timings;
22 	u32 refresh_hz;
23 };
24 
25 static const struct hws_dv_mode *
26 hws_find_dv_by_wh(u32 w, u32 h, bool interlaced);
27 static const struct hws_dv_mode *
28 hws_find_dv_by_wh_fps(u32 w, u32 h, bool interlaced, u32 fps);
29 static u32 hws_get_live_fps(struct hws_video *vid);
30 static u32 hws_input_status(struct hws_video *vid);
31 static int hws_fill_dv_timings(u32 w, u32 h, bool interlace, u32 fps,
32 			       struct v4l2_dv_timings *timings);
33 
34 static const struct hws_dv_mode hws_dv_modes[] = {
35 	{
36 		{
37 			.type = V4L2_DV_BT_656_1120,
38 			.bt = {
39 				.width = 1920,
40 				.height = 1080,
41 				.hfrontporch = 88,
42 				.hsync = 44,
43 				.hbackporch = 148,
44 				.vfrontporch = 4,
45 				.vsync = 5,
46 				.vbackporch = 36,
47 				.pixelclock = 148500000,
48 				.polarities = V4L2_DV_VSYNC_POS_POL |
49 					      V4L2_DV_HSYNC_POS_POL,
50 				.interlaced = 0,
51 			},
52 		},
53 		60,
54 	},
55 	{
56 		{
57 			.type = V4L2_DV_BT_656_1120,
58 			.bt = {
59 				.width = 1920,
60 				.height = 1080,
61 				.hfrontporch = 88,
62 				.hsync = 44,
63 				.hbackporch = 148,
64 				.vfrontporch = 4,
65 				.vsync = 5,
66 				.vbackporch = 36,
67 				.pixelclock = 74250000,
68 				.polarities = V4L2_DV_VSYNC_POS_POL |
69 					      V4L2_DV_HSYNC_POS_POL,
70 				.interlaced = 0,
71 			},
72 		},
73 		30,
74 	},
75 	{
76 		{
77 			.type = V4L2_DV_BT_656_1120,
78 			.bt = {
79 				.width = 1280,
80 				.height = 720,
81 				.hfrontporch = 110,
82 				.hsync = 40,
83 				.hbackporch = 220,
84 				.vfrontporch = 5,
85 				.vsync = 5,
86 				.vbackporch = 20,
87 				.pixelclock = 74250000,
88 				.polarities = V4L2_DV_VSYNC_POS_POL |
89 					      V4L2_DV_HSYNC_POS_POL,
90 				.interlaced = 0,
91 			},
92 		},
93 		60,
94 	},
95 	{
96 		{
97 			.type = V4L2_DV_BT_656_1120,
98 			.bt = {
99 				.width = 720,
100 				.height = 480,
101 				.interlaced = 0,
102 			},
103 		},
104 		60,
105 	},
106 	{
107 		{
108 			.type = V4L2_DV_BT_656_1120,
109 			.bt = {
110 				.width = 720,
111 				.height = 576,
112 				.interlaced = 0,
113 			},
114 		},
115 		50,
116 	},
117 	{
118 		{
119 			.type = V4L2_DV_BT_656_1120,
120 			.bt = {
121 				.width = 800,
122 				.height = 600,
123 				.interlaced = 0,
124 			},
125 		},
126 		60,
127 	},
128 	{
129 		{
130 			.type = V4L2_DV_BT_656_1120,
131 			.bt = {
132 				.width = 640,
133 				.height = 480,
134 				.interlaced = 0,
135 			},
136 		},
137 		60,
138 	},
139 	{
140 		{
141 			.type = V4L2_DV_BT_656_1120,
142 			.bt = {
143 				.width = 1024,
144 				.height = 768,
145 				.interlaced = 0,
146 			},
147 		},
148 		60,
149 	},
150 	{
151 		{
152 			.type = V4L2_DV_BT_656_1120,
153 			.bt = {
154 				.width = 1280,
155 				.height = 768,
156 				.interlaced = 0,
157 			},
158 		},
159 		60,
160 	},
161 	{
162 		{
163 			.type = V4L2_DV_BT_656_1120,
164 			.bt = {
165 				.width = 1280,
166 				.height = 800,
167 				.interlaced = 0,
168 			},
169 		},
170 		60,
171 	},
172 	{
173 		{
174 			.type = V4L2_DV_BT_656_1120,
175 			.bt = {
176 				.width = 1280,
177 				.height = 1024,
178 				.interlaced = 0,
179 			},
180 		},
181 		60,
182 	},
183 	{
184 		{
185 			.type = V4L2_DV_BT_656_1120,
186 			.bt = {
187 				.width = 1360,
188 				.height = 768,
189 				.interlaced = 0,
190 			},
191 		},
192 		60,
193 	},
194 	{
195 		{
196 			.type = V4L2_DV_BT_656_1120,
197 			.bt = {
198 				.width = 1440,
199 				.height = 900,
200 				.interlaced = 0,
201 			},
202 		},
203 		60,
204 	},
205 	{
206 		{
207 			.type = V4L2_DV_BT_656_1120,
208 			.bt = {
209 				.width = 1680,
210 				.height = 1050,
211 				.interlaced = 0,
212 			},
213 		},
214 		60,
215 	},
216 	/* Portrait */
217 	{
218 		{
219 			.type = V4L2_DV_BT_656_1120,
220 			.bt = {
221 				.width = 1080,
222 				.height = 1920,
223 				.interlaced = 0,
224 			},
225 		},
226 		60,
227 	},
228 };
229 
230 static const size_t hws_dv_modes_cnt = ARRAY_SIZE(hws_dv_modes);
231 
232 /* YUYV: 16 bpp; align to 64 as you did elsewhere */
233 static inline u32 hws_calc_bpl_yuyv(u32 w)     { return ALIGN(w * 2, 64); }
234 static inline u32 hws_calc_size_yuyv(u32 w, u32 h) { return hws_calc_bpl_yuyv(w) * h; }
235 static inline u32 hws_calc_half_size(u32 sizeimage)
236 {
237 	return sizeimage / 2;
238 }
239 
240 static inline void hws_hw_write_bchs(struct hws_pcie_dev *hws, unsigned int ch,
241 				     u8 br, u8 co, u8 hu, u8 sa)
242 {
243 	u32 packed = (sa << 24) | (hu << 16) | (co << 8) | br;
244 
245 	if (!hws || !hws->bar0_base || ch >= hws->max_channels)
246 		return;
247 	writel_relaxed(packed, hws->bar0_base + HWS_REG_BCHS(ch));
248 	(void)readl(hws->bar0_base + HWS_REG_BCHS(ch)); /* post write */
249 }
250 
251 /* Helper: find a supported DV mode by W/H + interlace flag */
252 static const struct hws_dv_mode *
253 hws_match_supported_dv(const struct v4l2_dv_timings *req)
254 {
255 	const struct v4l2_bt_timings *bt;
256 	u32 fps;
257 
258 	if (!req || req->type != V4L2_DV_BT_656_1120)
259 		return NULL;
260 
261 	bt = &req->bt;
262 	fps = 0;
263 	if (bt->pixelclock) {
264 		u32 total_w = bt->width + bt->hfrontporch + bt->hsync +
265 			      bt->hbackporch;
266 		u32 total_h = bt->height + bt->vfrontporch + bt->vsync +
267 			      bt->vbackporch;
268 
269 		if (total_w && total_h)
270 			fps = DIV_ROUND_CLOSEST_ULL((u64)bt->pixelclock,
271 						    (u64)total_w * total_h);
272 	}
273 	if (fps) {
274 		const struct hws_dv_mode *exact =
275 			hws_find_dv_by_wh_fps(bt->width, bt->height,
276 					      !!bt->interlaced, fps);
277 		if (exact)
278 			return exact;
279 	}
280 	return hws_find_dv_by_wh(bt->width, bt->height, !!bt->interlaced);
281 }
282 
283 /* Helper: find a supported DV mode by W/H + interlace flag */
284 static const struct hws_dv_mode *
285 hws_find_dv_by_wh(u32 w, u32 h, bool interlaced)
286 {
287 	size_t i;
288 
289 	for (i = 0; i < ARRAY_SIZE(hws_dv_modes); i++) {
290 		const struct hws_dv_mode *t = &hws_dv_modes[i];
291 		const struct v4l2_bt_timings *bt = &t->timings.bt;
292 
293 		if (t->timings.type != V4L2_DV_BT_656_1120)
294 			continue;
295 
296 		if (bt->width == w && bt->height == h &&
297 		    !!bt->interlaced == interlaced)
298 			return t;
299 	}
300 	return NULL;
301 }
302 
303 static const struct hws_dv_mode *
304 hws_find_dv_by_wh_fps(u32 w, u32 h, bool interlaced, u32 fps)
305 {
306 	size_t i;
307 
308 	for (i = 0; i < ARRAY_SIZE(hws_dv_modes); i++) {
309 		const struct hws_dv_mode *t = &hws_dv_modes[i];
310 		const struct v4l2_bt_timings *bt = &t->timings.bt;
311 
312 		if (t->timings.type != V4L2_DV_BT_656_1120)
313 			continue;
314 
315 		if (bt->width == w && bt->height == h &&
316 		    !!bt->interlaced == interlaced &&
317 		    t->refresh_hz == fps)
318 			return t;
319 	}
320 	return NULL;
321 }
322 
323 static bool hws_get_live_dv_geometry(struct hws_video *vid,
324 				     u32 *w, u32 *h, bool *interlaced)
325 {
326 	struct hws_pcie_dev *pdx;
327 	u32 reg;
328 
329 	if (!vid)
330 		return false;
331 
332 	pdx = vid->parent;
333 	if (!pdx || !pdx->bar0_base)
334 		return false;
335 
336 	reg = readl(pdx->bar0_base + HWS_REG_IN_RES(vid->channel_index));
337 	if (!reg || reg == 0xFFFFFFFF)
338 		return false;
339 
340 	if (w)
341 		*w = reg & 0xFFFF;
342 	if (h)
343 		*h = (reg >> 16) & 0xFFFF;
344 	if (interlaced) {
345 		reg = readl(pdx->bar0_base + HWS_REG_ACTIVE_STATUS);
346 		*interlaced = !!(reg & BIT(8 + vid->channel_index));
347 	}
348 	return true;
349 }
350 
351 static u32 hws_get_live_fps(struct hws_video *vid)
352 {
353 	struct hws_pcie_dev *pdx;
354 	u32 fps;
355 
356 	if (!vid)
357 		return 0;
358 
359 	pdx = vid->parent;
360 	if (!pdx || !pdx->bar0_base)
361 		return 0;
362 
363 	fps = readl(pdx->bar0_base + HWS_REG_FRAME_RATE(vid->channel_index));
364 	if (!fps || fps == 0xFFFFFFFF || fps > 240)
365 		return 0;
366 
367 	return fps;
368 }
369 
370 static u32 hws_pick_fps_from_mode(u32 w, u32 h, bool interlaced)
371 {
372 	const struct hws_dv_mode *m = hws_find_dv_by_wh(w, h, interlaced);
373 
374 	if (m && m->refresh_hz)
375 		return m->refresh_hz;
376 	/* Fallback to a sane default */
377 	return 60;
378 }
379 
380 static int hws_fill_dv_timings(u32 w, u32 h, bool interlace, u32 fps,
381 			       struct v4l2_dv_timings *timings)
382 {
383 	const struct hws_dv_mode *m;
384 
385 	m = fps ? hws_find_dv_by_wh_fps(w, h, interlace, fps) : NULL;
386 	if (!m)
387 		m = hws_find_dv_by_wh(w, h, interlace);
388 	if (!m)
389 		return -ENOLINK;
390 
391 	*timings = m->timings;
392 	return 0;
393 }
394 
395 static u32 hws_input_status(struct hws_video *vid)
396 {
397 	struct hws_pcie_dev *pdx;
398 	u32 reg;
399 
400 	if (!vid)
401 		return V4L2_IN_ST_NO_SIGNAL;
402 
403 	pdx = vid->parent;
404 	if (!pdx || !pdx->bar0_base)
405 		return V4L2_IN_ST_NO_SIGNAL;
406 
407 	reg = readl(pdx->bar0_base + HWS_REG_ACTIVE_STATUS);
408 	if (reg == 0xffffffff)
409 		return V4L2_IN_ST_NO_SIGNAL;
410 
411 	return (reg & BIT(vid->channel_index)) ? 0 : V4L2_IN_ST_NO_SIGNAL;
412 }
413 
414 /* Query the *current detected* DV timings on the input.
415  * If you have a real hardware detector, call it here; otherwise we
416  * derive from the cached pix state and map to the closest supported DV mode.
417  */
418 int hws_vidioc_query_dv_timings(struct file *file, void *fh,
419 				struct v4l2_dv_timings *timings)
420 {
421 	struct hws_video *vid = video_drvdata(file);
422 	u32 w, h;
423 	u32 fps;
424 	bool interlace;
425 
426 	if (!timings)
427 		return -EINVAL;
428 
429 	w = vid->pix.width;
430 	h = vid->pix.height;
431 	interlace = vid->pix.interlaced;
432 	hws_get_live_dv_geometry(vid, &w, &h, &interlace);
433 	fps = hws_get_live_fps(vid);
434 	if (!fps)
435 		fps = vid->current_fps ? vid->current_fps :
436 		      hws_pick_fps_from_mode(w, h, interlace);
437 
438 	return hws_fill_dv_timings(w, h, interlace, fps, timings);
439 }
440 
441 /* Enumerate the Nth supported DV timings from our static table. */
442 int hws_vidioc_enum_dv_timings(struct file *file, void *fh,
443 			       struct v4l2_enum_dv_timings *edv)
444 {
445 	struct hws_video *vid = video_drvdata(file);
446 	const struct hws_dv_mode *m;
447 	u32 w, h;
448 	u32 fps;
449 	bool interlace;
450 
451 	if (!edv)
452 		return -EINVAL;
453 
454 	if (edv->pad)
455 		return -EINVAL;
456 
457 	w = 0;
458 	h = 0;
459 	interlace = false;
460 	if (hws_get_live_dv_geometry(vid, &w, &h, &interlace)) {
461 		fps = hws_get_live_fps(vid);
462 		if (!fps)
463 			fps = vid->current_fps ? vid->current_fps :
464 			      hws_pick_fps_from_mode(w, h, interlace);
465 		m = fps ? hws_find_dv_by_wh_fps(w, h, interlace, fps) : NULL;
466 		if (!m)
467 			m = hws_find_dv_by_wh(w, h, interlace);
468 		if (m) {
469 			if (edv->index)
470 				return -EINVAL;
471 			edv->timings = m->timings;
472 			return 0;
473 		}
474 	}
475 
476 	if (edv->index >= hws_dv_modes_cnt)
477 		return -EINVAL;
478 
479 	edv->timings = hws_dv_modes[edv->index].timings;
480 	return 0;
481 }
482 
483 /* Get the *currently configured* DV timings. */
484 int hws_vidioc_g_dv_timings(struct file *file, void *fh,
485 			    struct v4l2_dv_timings *timings)
486 {
487 	struct hws_video *vid = video_drvdata(file);
488 	u32 w, h;
489 	u32 fps;
490 	bool interlace;
491 
492 	if (!timings)
493 		return -EINVAL;
494 
495 	w = vid->pix.width;
496 	h = vid->pix.height;
497 	interlace = vid->pix.interlaced;
498 	if (hws_get_live_dv_geometry(vid, &w, &h, &interlace)) {
499 		fps = hws_get_live_fps(vid);
500 		if (!fps)
501 			fps = vid->current_fps ? vid->current_fps :
502 			      hws_pick_fps_from_mode(w, h, interlace);
503 		return hws_fill_dv_timings(w, h, interlace, fps, timings);
504 	}
505 
506 	*timings = vid->cur_dv_timings;
507 	return 0;
508 }
509 
510 static inline void hws_set_colorimetry_state(struct hws_pix_state *p)
511 {
512 	bool sd = p->height <= 576;
513 
514 	p->colorspace   = sd ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
515 	p->ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
516 	p->quantization = V4L2_QUANTIZATION_FULL_RANGE;
517 	p->xfer_func    = V4L2_XFER_FUNC_DEFAULT;
518 }
519 
520 /* Set DV timings: must match one of our supported modes.
521  * If buffers are queued and this implies a size change, we reject with -EBUSY.
522  * Otherwise we update pix state and (optionally) reprogram the HW.
523  */
524 int hws_vidioc_s_dv_timings(struct file *file, void *fh,
525 			    struct v4l2_dv_timings *timings)
526 {
527 	struct hws_video *vid = video_drvdata(file);
528 	const struct hws_dv_mode *m;
529 	const struct v4l2_bt_timings *bt;
530 	u32 new_w, new_h;
531 	bool interlaced;
532 	int ret = 0;
533 	unsigned long was_busy;
534 	u32 live_w, live_h;
535 	u32 live_fps;
536 	bool live_interlaced;
537 	bool live_present;
538 
539 	if (!timings)
540 		return -EINVAL;
541 
542 	m = hws_match_supported_dv(timings);
543 	if (!m)
544 		return -EINVAL;
545 
546 	bt = &m->timings.bt;
547 	if (bt->interlaced)
548 		return -EINVAL; /* only progressive modes are advertised */
549 	new_w = bt->width;
550 	new_h = bt->height;
551 	interlaced = false;
552 
553 	lockdep_assert_held(&vid->state_lock);
554 	live_present = hws_get_live_dv_geometry(vid, &live_w, &live_h,
555 						&live_interlaced);
556 
557 	/* If vb2 has active buffers and size would change, reject. */
558 	was_busy = vb2_is_busy(&vid->buffer_queue);
559 	if (was_busy &&
560 	    (new_w != vid->pix.width || new_h != vid->pix.height ||
561 	     interlaced != vid->pix.interlaced)) {
562 		ret = -EBUSY;
563 		return ret;
564 	}
565 
566 	/* When a live input signal is present, the receiver owns the timing.
567 	 * Allow setting the already-active timings so v4l2-compliance can
568 	 * round-trip them, but reject attempts to retime the live source.
569 	 */
570 	if (live_present) {
571 		live_fps = hws_get_live_fps(vid);
572 		if (!live_fps)
573 			live_fps = vid->current_fps ? vid->current_fps :
574 					hws_pick_fps_from_mode(live_w, live_h,
575 							       live_interlaced);
576 		if (live_w == new_w && live_h == new_h &&
577 		    live_interlaced == interlaced &&
578 		    m->refresh_hz == live_fps)
579 			return 0;
580 		return -EBUSY;
581 	}
582 
583 	/* Update software pixel state (and recalc sizes) */
584 	vid->pix.width      = new_w;
585 	vid->pix.height     = new_h;
586 	vid->pix.field      = interlaced ? V4L2_FIELD_INTERLACED
587 					 : V4L2_FIELD_NONE;
588 	vid->pix.interlaced = interlaced;
589 	vid->pix.fourcc     = V4L2_PIX_FMT_YUYV;
590 
591 	hws_set_colorimetry_state(&vid->pix);
592 
593 	/* Recompute stride, sizeimage, and half_size. */
594 	vid->pix.bytesperline = hws_calc_bpl_yuyv(new_w);
595 	vid->pix.sizeimage    = hws_calc_size_yuyv(new_w, new_h);
596 	vid->pix.half_size    = hws_calc_half_size(vid->pix.sizeimage);
597 	vid->cur_dv_timings   = m->timings;
598 	vid->current_fps      = m->refresh_hz;
599 	return ret;
600 }
601 
602 /* Report DV timings capability: advertise BT.656/1120 with
603  * the min/max WxH derived from our table and basic progressive support.
604  */
605 int hws_vidioc_dv_timings_cap(struct file *file, void *fh,
606 			      struct v4l2_dv_timings_cap *cap)
607 {
608 	u32 min_w = ~0U, min_h = ~0U;
609 	u32 max_w = 0,       max_h = 0;
610 	size_t i, n = 0;
611 
612 	if (!cap)
613 		return -EINVAL;
614 
615 	memset(cap, 0, sizeof(*cap));
616 	cap->type = V4L2_DV_BT_656_1120;
617 
618 	for (i = 0; i < ARRAY_SIZE(hws_dv_modes); i++) {
619 		const struct v4l2_bt_timings *bt = &hws_dv_modes[i].timings.bt;
620 
621 		if (hws_dv_modes[i].timings.type != V4L2_DV_BT_656_1120)
622 			continue;
623 		n++;
624 
625 		if (bt->width  < min_w)
626 			min_w = bt->width;
627 		if (bt->height < min_h)
628 			min_h = bt->height;
629 		if (bt->width  > max_w)
630 			max_w = bt->width;
631 		if (bt->height > max_h)
632 			max_h = bt->height;
633 	}
634 
635 	/* If the table was empty, fail gracefully. */
636 	if (!n || min_w == U32_MAX)
637 		return -ENODATA;
638 
639 	cap->bt.min_width  = min_w;
640 	cap->bt.max_width  = max_w;
641 	cap->bt.min_height = min_h;
642 	cap->bt.max_height = max_h;
643 
644 	/* We support both CEA-861- and VESA-style modes in the list. */
645 	cap->bt.standards =
646 		V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT;
647 
648 	/* Only progressive modes are advertised. */
649 	cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE;
650 
651 	/* Leave pixelclock/porch limits unconstrained (0) for now. */
652 	return 0;
653 }
654 
655 static int hws_s_ctrl(struct v4l2_ctrl *ctrl)
656 {
657 	struct hws_video *vid =
658 		container_of(ctrl->handler, struct hws_video, control_handler);
659 	struct hws_pcie_dev *pdx = vid->parent;
660 	bool program = false;
661 
662 	switch (ctrl->id) {
663 	case V4L2_CID_BRIGHTNESS:
664 		vid->current_brightness = ctrl->val;
665 		program = true;
666 		break;
667 	case V4L2_CID_CONTRAST:
668 		vid->current_contrast = ctrl->val;
669 		program = true;
670 		break;
671 	case V4L2_CID_SATURATION:
672 		vid->current_saturation = ctrl->val;
673 		program = true;
674 		break;
675 	case V4L2_CID_HUE:
676 		vid->current_hue = ctrl->val;
677 		program = true;
678 		break;
679 	default:
680 		return -EINVAL;
681 	}
682 
683 	if (program) {
684 		hws_hw_write_bchs(pdx, vid->channel_index,
685 				  (u8)vid->current_brightness,
686 				  (u8)vid->current_contrast,
687 				  (u8)vid->current_hue,
688 				  (u8)vid->current_saturation);
689 	}
690 	return 0;
691 }
692 
693 const struct v4l2_ctrl_ops hws_ctrl_ops = {
694 	.s_ctrl = hws_s_ctrl,
695 };
696 
697 int hws_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
698 {
699 	struct hws_video *vid = video_drvdata(file);
700 	int vi_index = vid->channel_index + 1; /* keep it simple */
701 
702 	strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
703 	snprintf(cap->card, sizeof(cap->card),
704 		 "AVMatrix HWS Capture %d", vi_index);
705 	return 0;
706 }
707 
708 int hws_vidioc_enum_fmt_vid_cap(struct file *file, void *priv_fh, struct v4l2_fmtdesc *f)
709 {
710 	if (f->index != 0)
711 		return -EINVAL; /* only one format */
712 
713 	f->pixelformat = V4L2_PIX_FMT_YUYV;
714 	return 0;
715 }
716 
717 int hws_vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
718 {
719 	struct hws_video *vid = video_drvdata(file);
720 
721 	fmt->fmt.pix.width        = vid->pix.width;
722 	fmt->fmt.pix.height       = vid->pix.height;
723 	fmt->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUYV;
724 	fmt->fmt.pix.field        = vid->pix.field;
725 	fmt->fmt.pix.bytesperline = vid->pix.bytesperline;
726 	fmt->fmt.pix.sizeimage    = vid->pix.sizeimage;
727 	fmt->fmt.pix.colorspace   = vid->pix.colorspace;
728 	fmt->fmt.pix.ycbcr_enc    = vid->pix.ycbcr_enc;
729 	fmt->fmt.pix.quantization = vid->pix.quantization;
730 	fmt->fmt.pix.xfer_func    = vid->pix.xfer_func;
731 	return 0;
732 }
733 
734 static inline void hws_set_colorimetry_fmt(struct v4l2_pix_format *p)
735 {
736 	bool sd = p->height <= 576;
737 
738 	p->colorspace   = sd ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
739 	p->ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
740 	p->quantization = V4L2_QUANTIZATION_FULL_RANGE;
741 	p->xfer_func    = V4L2_XFER_FUNC_DEFAULT;
742 }
743 
744 int hws_vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
745 {
746 	struct hws_video *vid = file ? video_drvdata(file) : NULL;
747 	struct hws_pcie_dev *pdev = vid ? vid->parent : NULL;
748 	struct v4l2_pix_format *pix = &f->fmt.pix;
749 	u32 req_w = pix->width, req_h = pix->height;
750 	u32 w, h, min_bpl, bpl;
751 	size_t size; /* wider than u32 for overflow check */
752 	size_t max_frame = pdev ? pdev->max_hw_video_buf_sz : MAX_MM_VIDEO_SIZE;
753 
754 	/* Only YUYV */
755 	pix->pixelformat = V4L2_PIX_FMT_YUYV;
756 
757 	/* Defaults then clamp */
758 	w = (req_w ? req_w : 640);
759 	h = (req_h ? req_h : 480);
760 	if (w > MAX_VIDEO_HW_W)
761 		w = MAX_VIDEO_HW_W;
762 	if (h > MAX_VIDEO_HW_H)
763 		h = MAX_VIDEO_HW_H;
764 	if (!w)
765 		w = 640; /* hard fallback in case macros are odd */
766 	if (!h)
767 		h = 480;
768 
769 	/* Field policy */
770 	pix->field = V4L2_FIELD_NONE;
771 
772 	/* Stride policy for packed 16bpp, 64B align */
773 	min_bpl = ALIGN(w * 2, 64);
774 
775 	/* Bound requested bpl to something sane, then align */
776 	bpl = pix->bytesperline;
777 	if (bpl < min_bpl) {
778 		bpl = min_bpl;
779 	} else {
780 		/* Cap at 16x width to avoid silly values that overflow sizeimage */
781 		u32 max_bpl = ALIGN(w * 2 * 16, 64);
782 
783 		if (bpl > max_bpl)
784 			bpl = max_bpl;
785 		bpl = ALIGN(bpl, 64);
786 	}
787 	if (h && max_frame) {
788 		size_t max_bpl_hw = max_frame / h;
789 
790 		if (max_bpl_hw < min_bpl)
791 			return -ERANGE;
792 		max_bpl_hw = rounddown(max_bpl_hw, 64);
793 		if (!max_bpl_hw)
794 			return -ERANGE;
795 		if (bpl > max_bpl_hw) {
796 			if (pdev)
797 				dev_dbg(&pdev->pdev->dev,
798 					"try_fmt: clamp bpl %u -> %zu due to hw buf cap %zu\n",
799 					bpl, max_bpl_hw, max_frame);
800 			bpl = (u32)max_bpl_hw;
801 		}
802 	}
803 	size = (size_t)bpl * (size_t)h;
804 	if (size > max_frame)
805 		return -ERANGE;
806 
807 	pix->width        = w;
808 	pix->height       = h;
809 	pix->bytesperline = bpl;
810 	pix->sizeimage    = (u32)size; /* logical size, not page-aligned */
811 
812 	hws_set_colorimetry_fmt(pix);
813 	if (pdev)
814 		dev_dbg(&pdev->pdev->dev,
815 			"try_fmt: w=%u h=%u bpl=%u size=%u field=%u\n",
816 			pix->width, pix->height, pix->bytesperline,
817 			pix->sizeimage, pix->field);
818 	return 0;
819 }
820 
821 int hws_vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
822 {
823 	struct hws_video *vid = video_drvdata(file);
824 	int ret;
825 
826 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
827 		return -EINVAL;
828 
829 	/* Normalize the request */
830 	ret = hws_vidioc_try_fmt_vid_cap(file, priv, f);
831 	if (ret)
832 		return ret;
833 
834 	/* Don't allow buffer layout changes while buffers are queued. */
835 	if (vb2_is_busy(&vid->buffer_queue)) {
836 		if (f->fmt.pix.width  != vid->pix.width  ||
837 		    f->fmt.pix.height != vid->pix.height ||
838 		    f->fmt.pix.bytesperline != vid->pix.bytesperline)
839 			return -EBUSY;
840 	}
841 
842 	/* Apply to driver state */
843 	vid->pix.width        = f->fmt.pix.width;
844 	vid->pix.height       = f->fmt.pix.height;
845 	vid->pix.fourcc       = V4L2_PIX_FMT_YUYV;
846 	vid->pix.field        = f->fmt.pix.field;
847 	vid->pix.colorspace   = f->fmt.pix.colorspace;
848 	vid->pix.ycbcr_enc    = f->fmt.pix.ycbcr_enc;
849 	vid->pix.quantization = f->fmt.pix.quantization;
850 	vid->pix.xfer_func    = f->fmt.pix.xfer_func;
851 
852 	/* Update negotiated buffer sizes. */
853 	vid->pix.bytesperline = f->fmt.pix.bytesperline; /* aligned */
854 	vid->pix.sizeimage    = f->fmt.pix.sizeimage;    /* logical */
855 	vid->pix.half_size    = hws_calc_half_size(vid->pix.sizeimage);
856 	vid->pix.interlaced   = false;
857 	/* S_FMT negotiates buffer layout only. Keep detector-owned DV timing
858 	 * state unchanged so a harmless restart cannot clobber the live FPS.
859 	 */
860 	/* Or:
861 	 * hws_calc_sizeimage(vid, vid->pix.width, vid->pix.height, false);
862 	 */
863 
864 	dev_dbg(&vid->parent->pdev->dev,
865 		"s_fmt:   w=%u h=%u bpl=%u size=%u\n",
866 		vid->pix.width, vid->pix.height, vid->pix.bytesperline,
867 		vid->pix.sizeimage);
868 
869 	return 0;
870 }
871 
872 int hws_vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *param)
873 {
874 	struct hws_video *vid = video_drvdata(file);
875 	u32 fps;
876 
877 	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
878 		return -EINVAL;
879 
880 	fps = hws_get_live_fps(vid);
881 	if (!fps)
882 		fps = vid->current_fps ? vid->current_fps : 60;
883 
884 	/* HDMI receivers report the detected frame period, they don't set it. */
885 	param->parm.capture.capability           = 0;
886 	param->parm.capture.capturemode          = 0;
887 	param->parm.capture.timeperframe.numerator   = 1;
888 	param->parm.capture.timeperframe.denominator = fps;
889 	param->parm.capture.extendedmode         = 0;
890 	param->parm.capture.readbuffers          = 0;
891 
892 	return 0;
893 }
894 
895 int hws_vidioc_enum_input(struct file *file, void *priv,
896 			  struct v4l2_input *input)
897 {
898 	struct hws_video *vid = video_drvdata(file);
899 
900 	if (input->index)
901 		return -EINVAL;
902 	input->type         = V4L2_INPUT_TYPE_CAMERA;
903 	strscpy(input->name, KBUILD_MODNAME, sizeof(input->name));
904 	input->capabilities = V4L2_IN_CAP_DV_TIMINGS;
905 	input->status       = hws_input_status(vid);
906 
907 	return 0;
908 }
909 
910 int hws_vidioc_g_input(struct file *file, void *priv, unsigned int *index)
911 {
912 	*index = 0;
913 	return 0;
914 }
915 
916 int hws_vidioc_s_input(struct file *file, void *priv, unsigned int i)
917 {
918 	return i ? -EINVAL : 0;
919 }
920