diff options
| -rw-r--r-- | drivers/gpu/drm/stm/ltdc.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 014cef8cef37..616191fe98ae 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c | |||
| @@ -445,6 +445,43 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, | |||
| 445 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | 445 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | #define CLK_TOLERANCE_HZ 50 | ||
| 449 | |||
| 450 | static enum drm_mode_status | ||
| 451 | ltdc_crtc_mode_valid(struct drm_crtc *crtc, | ||
| 452 | const struct drm_display_mode *mode) | ||
| 453 | { | ||
| 454 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
| 455 | int target = mode->clock * 1000; | ||
| 456 | int target_min = target - CLK_TOLERANCE_HZ; | ||
| 457 | int target_max = target + CLK_TOLERANCE_HZ; | ||
| 458 | int result; | ||
| 459 | |||
| 460 | /* | ||
| 461 | * Accept all "preferred" modes: | ||
| 462 | * - this is important for panels because panel clock tolerances are | ||
| 463 | * bigger than hdmi ones and there is no reason to not accept them | ||
| 464 | * (the fps may vary a little but it is not a problem). | ||
| 465 | * - the hdmi preferred mode will be accepted too, but userland will | ||
| 466 | * be able to use others hdmi "valid" modes if necessary. | ||
| 467 | */ | ||
| 468 | if (mode->type & DRM_MODE_TYPE_PREFERRED) | ||
| 469 | return MODE_OK; | ||
| 470 | |||
| 471 | result = clk_round_rate(ldev->pixel_clk, target); | ||
| 472 | |||
| 473 | DRM_DEBUG_DRIVER("clk rate target %d, available %d\n", target, result); | ||
| 474 | |||
| 475 | /* | ||
| 476 | * Filter modes according to the clock value, particularly useful for | ||
| 477 | * hdmi modes that require precise pixel clocks. | ||
| 478 | */ | ||
| 479 | if (result < target_min || result > target_max) | ||
| 480 | return MODE_CLOCK_RANGE; | ||
| 481 | |||
| 482 | return MODE_OK; | ||
| 483 | } | ||
| 484 | |||
| 448 | static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, | 485 | static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, |
| 449 | const struct drm_display_mode *mode, | 486 | const struct drm_display_mode *mode, |
| 450 | struct drm_display_mode *adjusted_mode) | 487 | struct drm_display_mode *adjusted_mode) |
| @@ -559,6 +596,7 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, | |||
| 559 | } | 596 | } |
| 560 | 597 | ||
| 561 | static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { | 598 | static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { |
| 599 | .mode_valid = ltdc_crtc_mode_valid, | ||
| 562 | .mode_fixup = ltdc_crtc_mode_fixup, | 600 | .mode_fixup = ltdc_crtc_mode_fixup, |
| 563 | .mode_set_nofb = ltdc_crtc_mode_set_nofb, | 601 | .mode_set_nofb = ltdc_crtc_mode_set_nofb, |
| 564 | .atomic_flush = ltdc_crtc_atomic_flush, | 602 | .atomic_flush = ltdc_crtc_atomic_flush, |
