mirror of https://gitee.com/openkylin/linux.git
drm/i915: Only look for matching clocks for LVDS downclock
This patch enforces that the downclock clock source is the same as the preferred clock source for LVDS. This fixes a bug where the driver chooses a downclock clock source with a different P than the preferred mode clock source. This happened even if the preferred clock source implemented an acceptable rate for the downclock. The result of this bug is that downclock is disabled. Signed-off-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
0b8ecdda19
commit
cec2f356d5
|
@ -75,7 +75,7 @@ struct intel_limit {
|
||||||
intel_range_t dot, vco, n, m, m1, m2, p, p1;
|
intel_range_t dot, vco, n, m, m1, m2, p, p1;
|
||||||
intel_p2_t p2;
|
intel_p2_t p2;
|
||||||
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
|
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
|
||||||
int, int, intel_clock_t *);
|
int, int, intel_clock_t *, intel_clock_t *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FDI */
|
/* FDI */
|
||||||
|
@ -83,17 +83,21 @@ struct intel_limit {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock);
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock);
|
||||||
static bool
|
static bool
|
||||||
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock);
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
|
intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock);
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock);
|
||||||
static bool
|
static bool
|
||||||
intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
|
intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock);
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock);
|
||||||
|
|
||||||
static inline u32 /* units of 100MHz */
|
static inline u32 /* units of 100MHz */
|
||||||
intel_fdi_link_freq(struct drm_device *dev)
|
intel_fdi_link_freq(struct drm_device *dev)
|
||||||
|
@ -515,7 +519,8 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock)
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock)
|
||||||
|
|
||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
|
@ -562,6 +567,9 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
if (!intel_PLL_is_valid(dev, limit,
|
if (!intel_PLL_is_valid(dev, limit,
|
||||||
&clock))
|
&clock))
|
||||||
continue;
|
continue;
|
||||||
|
if (match_clock &&
|
||||||
|
clock.p != match_clock->p)
|
||||||
|
continue;
|
||||||
|
|
||||||
this_err = abs(clock.dot - target);
|
this_err = abs(clock.dot - target);
|
||||||
if (this_err < err) {
|
if (this_err < err) {
|
||||||
|
@ -578,7 +586,8 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock)
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
@ -625,6 +634,9 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
if (!intel_PLL_is_valid(dev, limit,
|
if (!intel_PLL_is_valid(dev, limit,
|
||||||
&clock))
|
&clock))
|
||||||
continue;
|
continue;
|
||||||
|
if (match_clock &&
|
||||||
|
clock.p != match_clock->p)
|
||||||
|
continue;
|
||||||
|
|
||||||
this_err = abs(clock.dot - target);
|
this_err = abs(clock.dot - target);
|
||||||
if (this_err < err_most) {
|
if (this_err < err_most) {
|
||||||
|
@ -642,7 +654,8 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock)
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
intel_clock_t clock;
|
intel_clock_t clock;
|
||||||
|
@ -668,7 +681,8 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
/* DisplayPort has only two frequencies, 162MHz and 270MHz */
|
/* DisplayPort has only two frequencies, 162MHz and 270MHz */
|
||||||
static bool
|
static bool
|
||||||
intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||||
int target, int refclk, intel_clock_t *best_clock)
|
int target, int refclk, intel_clock_t *match_clock,
|
||||||
|
intel_clock_t *best_clock)
|
||||||
{
|
{
|
||||||
intel_clock_t clock;
|
intel_clock_t clock;
|
||||||
if (target < 200000) {
|
if (target < 200000) {
|
||||||
|
@ -5038,7 +5052,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
||||||
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
||||||
*/
|
*/
|
||||||
limit = intel_limit(crtc, refclk);
|
limit = intel_limit(crtc, refclk);
|
||||||
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
|
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
|
||||||
|
&clock);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -5048,21 +5063,17 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
||||||
intel_crtc_update_cursor(crtc, true);
|
intel_crtc_update_cursor(crtc, true);
|
||||||
|
|
||||||
if (is_lvds && dev_priv->lvds_downclock_avail) {
|
if (is_lvds && dev_priv->lvds_downclock_avail) {
|
||||||
|
/*
|
||||||
|
* Ensure we match the reduced clock's P to the target clock.
|
||||||
|
* If the clocks don't match, we can't switch the display clock
|
||||||
|
* by using the FP0/FP1. In such case we will disable the LVDS
|
||||||
|
* downclock feature.
|
||||||
|
*/
|
||||||
has_reduced_clock = limit->find_pll(limit, crtc,
|
has_reduced_clock = limit->find_pll(limit, crtc,
|
||||||
dev_priv->lvds_downclock,
|
dev_priv->lvds_downclock,
|
||||||
refclk,
|
refclk,
|
||||||
|
&clock,
|
||||||
&reduced_clock);
|
&reduced_clock);
|
||||||
if (has_reduced_clock && (clock.p != reduced_clock.p)) {
|
|
||||||
/*
|
|
||||||
* If the different P is found, it means that we can't
|
|
||||||
* switch the display clock by using the FP0/FP1.
|
|
||||||
* In such case we will disable the LVDS downclock
|
|
||||||
* feature.
|
|
||||||
*/
|
|
||||||
DRM_DEBUG_KMS("Different P is found for "
|
|
||||||
"LVDS clock/downclock\n");
|
|
||||||
has_reduced_clock = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* SDVO TV has fixed PLL values depend on its clock range,
|
/* SDVO TV has fixed PLL values depend on its clock range,
|
||||||
this mirrors vbios setting. */
|
this mirrors vbios setting. */
|
||||||
|
@ -5583,7 +5594,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
||||||
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
||||||
*/
|
*/
|
||||||
limit = intel_limit(crtc, refclk);
|
limit = intel_limit(crtc, refclk);
|
||||||
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
|
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
|
||||||
|
&clock);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -5593,21 +5605,17 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
||||||
intel_crtc_update_cursor(crtc, true);
|
intel_crtc_update_cursor(crtc, true);
|
||||||
|
|
||||||
if (is_lvds && dev_priv->lvds_downclock_avail) {
|
if (is_lvds && dev_priv->lvds_downclock_avail) {
|
||||||
|
/*
|
||||||
|
* Ensure we match the reduced clock's P to the target clock.
|
||||||
|
* If the clocks don't match, we can't switch the display clock
|
||||||
|
* by using the FP0/FP1. In such case we will disable the LVDS
|
||||||
|
* downclock feature.
|
||||||
|
*/
|
||||||
has_reduced_clock = limit->find_pll(limit, crtc,
|
has_reduced_clock = limit->find_pll(limit, crtc,
|
||||||
dev_priv->lvds_downclock,
|
dev_priv->lvds_downclock,
|
||||||
refclk,
|
refclk,
|
||||||
|
&clock,
|
||||||
&reduced_clock);
|
&reduced_clock);
|
||||||
if (has_reduced_clock && (clock.p != reduced_clock.p)) {
|
|
||||||
/*
|
|
||||||
* If the different P is found, it means that we can't
|
|
||||||
* switch the display clock by using the FP0/FP1.
|
|
||||||
* In such case we will disable the LVDS downclock
|
|
||||||
* feature.
|
|
||||||
*/
|
|
||||||
DRM_DEBUG_KMS("Different P is found for "
|
|
||||||
"LVDS clock/downclock\n");
|
|
||||||
has_reduced_clock = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* SDVO TV has fixed PLL values depend on its clock range,
|
/* SDVO TV has fixed PLL values depend on its clock range,
|
||||||
this mirrors vbios setting. */
|
this mirrors vbios setting. */
|
||||||
|
|
Loading…
Reference in New Issue