Commit 4547668a authored by Zhao Yakui's avatar Zhao Yakui Committed by Eric Anholt

drm/i915: Add DP dpll limit on ironlake and use existing DPLL search function

For some clocks, the old Ironlake DPLL calculator wold give m/n/p
combinations that didn't match the spreadsheet of what HW validation
tests.  Instead, use the G4X DPLL calculator, which does a better job
at it.

So we use the intel_g4x_find_best_pll to calculate the DPLL for CRT/HDMI/LVDS
on ironlake. At the same time to consider the dpll setting for display port, we
add the display port DPLL limit on ironlake, which will directly use the
function of intel_find_pll_ironlake_dp to get the corresponding dpll setting.
Signed-off-by: default avatarZhao Yakui <yakui.zhao@intel.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent e5a95eb7
...@@ -262,6 +262,14 @@ struct intel_limit { ...@@ -262,6 +262,14 @@ struct intel_limit {
#define IRONLAKE_P2_LVDS_FAST 7 /* double channel */ #define IRONLAKE_P2_LVDS_FAST 7 /* double channel */
#define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ #define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */
#define IRONLAKE_P_DISPLAY_PORT_MIN 10
#define IRONLAKE_P_DISPLAY_PORT_MAX 20
#define IRONLAKE_P2_DISPLAY_PORT_FAST 10
#define IRONLAKE_P2_DISPLAY_PORT_SLOW 10
#define IRONLAKE_P2_DISPLAY_PORT_LIMIT 0
#define IRONLAKE_P1_DISPLAY_PORT_MIN 1
#define IRONLAKE_P1_DISPLAY_PORT_MAX 2
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 *best_clock);
...@@ -271,9 +279,6 @@ intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, ...@@ -271,9 +279,6 @@ intel_find_best_reduced_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 *best_clock);
static bool
intel_ironlake_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, 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,
...@@ -496,7 +501,7 @@ static const intel_limit_t intel_limits_ironlake_sdvo = { ...@@ -496,7 +501,7 @@ static const intel_limit_t intel_limits_ironlake_sdvo = {
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
.p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW, .p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW,
.p2_fast = IRONLAKE_P2_SDVO_DAC_FAST }, .p2_fast = IRONLAKE_P2_SDVO_DAC_FAST },
.find_pll = intel_ironlake_find_best_PLL, .find_pll = intel_g4x_find_best_PLL,
}; };
static const intel_limit_t intel_limits_ironlake_lvds = { static const intel_limit_t intel_limits_ironlake_lvds = {
...@@ -511,7 +516,30 @@ static const intel_limit_t intel_limits_ironlake_lvds = { ...@@ -511,7 +516,30 @@ static const intel_limit_t intel_limits_ironlake_lvds = {
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
.p2_slow = IRONLAKE_P2_LVDS_SLOW, .p2_slow = IRONLAKE_P2_LVDS_SLOW,
.p2_fast = IRONLAKE_P2_LVDS_FAST }, .p2_fast = IRONLAKE_P2_LVDS_FAST },
.find_pll = intel_ironlake_find_best_PLL, .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_display_port = {
.dot = { .min = IRONLAKE_DOT_MIN,
.max = IRONLAKE_DOT_MAX },
.vco = { .min = IRONLAKE_VCO_MIN,
.max = IRONLAKE_VCO_MAX},
.n = { .min = IRONLAKE_N_MIN,
.max = IRONLAKE_N_MAX },
.m = { .min = IRONLAKE_M_MIN,
.max = IRONLAKE_M_MAX },
.m1 = { .min = IRONLAKE_M1_MIN,
.max = IRONLAKE_M1_MAX },
.m2 = { .min = IRONLAKE_M2_MIN,
.max = IRONLAKE_M2_MAX },
.p = { .min = IRONLAKE_P_DISPLAY_PORT_MIN,
.max = IRONLAKE_P_DISPLAY_PORT_MAX },
.p1 = { .min = IRONLAKE_P1_DISPLAY_PORT_MIN,
.max = IRONLAKE_P1_DISPLAY_PORT_MAX},
.p2 = { .dot_limit = IRONLAKE_P2_DISPLAY_PORT_LIMIT,
.p2_slow = IRONLAKE_P2_DISPLAY_PORT_SLOW,
.p2_fast = IRONLAKE_P2_DISPLAY_PORT_FAST },
.find_pll = intel_find_pll_ironlake_dp,
}; };
static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
...@@ -519,6 +547,9 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) ...@@ -519,6 +547,9 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
const intel_limit_t *limit; const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits_ironlake_lvds; limit = &intel_limits_ironlake_lvds;
else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
HAS_eDP)
limit = &intel_limits_ironlake_display_port;
else else
limit = &intel_limits_ironlake_sdvo; limit = &intel_limits_ironlake_sdvo;
...@@ -791,7 +822,13 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, ...@@ -791,7 +822,13 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
found = false; found = false;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == int lvds_reg;
if (IS_IRONLAKE(dev))
lvds_reg = PCH_LVDS;
else
lvds_reg = LVDS;
if ((I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP) LVDS_CLKB_POWER_UP)
clock.p2 = limit->p2.p2_fast; clock.p2 = limit->p2.p2_fast;
else else
...@@ -839,6 +876,11 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc, ...@@ -839,6 +876,11 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
intel_clock_t clock; intel_clock_t clock;
/* return directly when it is eDP */
if (HAS_eDP)
return true;
if (target < 200000) { if (target < 200000) {
clock.n = 1; clock.n = 1;
clock.p1 = 2; clock.p1 = 2;
...@@ -857,68 +899,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc, ...@@ -857,68 +899,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
return true; return true;
} }
static bool
intel_ironlake_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
intel_clock_t clock;
int err_most = 47;
int err_min = 10000;
/* eDP has only 2 clock choice, no n/m/p setting */
if (HAS_eDP)
return true;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
return intel_find_pll_ironlake_dp(limit, crtc, target,
refclk, best_clock);
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
clock.p2 = limit->p2.p2_fast;
else
clock.p2 = limit->p2.p2_slow;
} else {
if (target < limit->p2.dot_limit)
clock.p2 = limit->p2.p2_slow;
else
clock.p2 = limit->p2.p2_fast;
}
memset(best_clock, 0, sizeof(*best_clock));
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
/* based on hardware requriment prefer smaller n to precision */
for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) {
/* based on hardware requirment prefere larger m1,m2 */
for (clock.m1 = limit->m1.max;
clock.m1 >= limit->m1.min; clock.m1--) {
for (clock.m2 = limit->m2.max;
clock.m2 >= limit->m2.min; clock.m2--) {
int this_err;
intel_clock(dev, refclk, &clock);
if (!intel_PLL_is_valid(crtc, &clock))
continue;
this_err = abs((10000 - (target*10000/clock.dot)));
if (this_err < err_most) {
*best_clock = clock;
/* found on first matching */
goto out;
} else if (this_err < err_min) {
*best_clock = clock;
err_min = this_err;
}
}
}
}
}
out:
return true;
}
/* 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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment