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