aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_dpll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dpll.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll.c242
1 files changed, 158 insertions, 84 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index 1ce0c171f4fb..6eef0b8a91eb 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -4,6 +4,7 @@
*/
#include <linux/kernel.h>
+#include <linux/string_helpers.h>
#include "intel_crtc.h"
#include "intel_de.h"
@@ -16,6 +17,13 @@
#include "intel_snps_phy.h"
#include "vlv_sideband.h"
+struct intel_dpll_funcs {
+ int (*crtc_compute_clock)(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
+ int (*crtc_get_shared_dpll)(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
+};
+
struct intel_limit {
struct {
int min, max;
@@ -249,12 +257,12 @@ static const struct intel_limit ilk_limits_dual_lvds_100m = {
static const struct intel_limit intel_limits_vlv = {
/*
- * These are the data rate limits (measured in fast clocks)
+ * These are based on the data rate limits (measured in fast clocks)
* since those are the strictest limits we have. The fast
* clock and actual rate limits are more relaxed, so checking
* them would make no difference.
*/
- .dot = { .min = 25000 * 5, .max = 270000 * 5 },
+ .dot = { .min = 25000, .max = 270000 },
.vco = { .min = 4000000, .max = 6000000 },
.n = { .min = 1, .max = 7 },
.m1 = { .min = 2, .max = 3 },
@@ -265,12 +273,12 @@ static const struct intel_limit intel_limits_vlv = {
static const struct intel_limit intel_limits_chv = {
/*
- * These are the data rate limits (measured in fast clocks)
+ * These are based on the data rate limits (measured in fast clocks)
* since those are the strictest limits we have. The fast
* clock and actual rate limits are more relaxed, so checking
* them would make no difference.
*/
- .dot = { .min = 25000 * 5, .max = 540000 * 5},
+ .dot = { .min = 25000, .max = 540000 },
.vco = { .min = 4800000, .max = 6480000 },
.n = { .min = 1, .max = 1 },
.m1 = { .min = 2, .max = 2 },
@@ -280,8 +288,7 @@ static const struct intel_limit intel_limits_chv = {
};
static const struct intel_limit intel_limits_bxt = {
- /* FIXME: find real dot limits */
- .dot = { .min = 0, .max = INT_MAX },
+ .dot = { .min = 25000, .max = 594000 },
.vco = { .min = 4800000, .max = 6700000 },
.n = { .min = 1, .max = 1 },
.m1 = { .min = 2, .max = 2 },
@@ -332,26 +339,26 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
int vlv_calc_dpll_params(int refclk, struct dpll *clock)
{
clock->m = clock->m1 * clock->m2;
- clock->p = clock->p1 * clock->p2;
+ clock->p = clock->p1 * clock->p2 * 5;
if (WARN_ON(clock->n == 0 || clock->p == 0))
return 0;
clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
- return clock->dot / 5;
+ return clock->dot;
}
int chv_calc_dpll_params(int refclk, struct dpll *clock)
{
clock->m = clock->m1 * clock->m2;
- clock->p = clock->p1 * clock->p2;
+ clock->p = clock->p1 * clock->p2 * 5;
if (WARN_ON(clock->n == 0 || clock->p == 0))
return 0;
clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
clock->n << 22);
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
- return clock->dot / 5;
+ return clock->dot;
}
/*
@@ -420,8 +427,7 @@ i9xx_select_p2_div(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE. The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ * refclk, or FALSE.
*
* Target and reference clocks are specified in kHz.
*
@@ -479,8 +485,7 @@ i9xx_find_best_dpll(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE. The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ * refclk, or FALSE.
*
* Target and reference clocks are specified in kHz.
*
@@ -536,8 +541,7 @@ pnv_find_best_dpll(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE. The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ * refclk, or FALSE.
*
* Target and reference clocks are specified in kHz.
*
@@ -636,8 +640,7 @@ static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
/*
* Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE. The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ * refclk, or FALSE.
*/
static bool
vlv_find_best_dpll(const struct intel_limit *limit,
@@ -654,8 +657,6 @@ vlv_find_best_dpll(const struct intel_limit *limit,
int max_n = min(limit->n.max, refclk / 19200);
bool found = false;
- target *= 5; /* fast clock */
-
memset(best_clock, 0, sizeof(*best_clock));
/* based on hardware requirement, prefer smaller n to precision */
@@ -663,7 +664,7 @@ vlv_find_best_dpll(const struct intel_limit *limit,
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
clock.p2 -= clock.p2 > 10 ? 2 : 1) {
- clock.p = clock.p1 * clock.p2;
+ clock.p = clock.p1 * clock.p2 * 5;
/* based on hardware requirement, prefer bigger m1,m2 values */
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
unsigned int ppm;
@@ -697,8 +698,7 @@ vlv_find_best_dpll(const struct intel_limit *limit,
/*
* Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE. The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ * refclk, or FALSE.
*/
static bool
chv_find_best_dpll(const struct intel_limit *limit,
@@ -724,7 +724,6 @@ chv_find_best_dpll(const struct intel_limit *limit,
*/
clock.n = 1;
clock.m1 = 2;
- target *= 5; /* fast clock */
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
for (clock.p2 = limit->p2.p2_fast;
@@ -732,7 +731,7 @@ chv_find_best_dpll(const struct intel_limit *limit,
clock.p2 -= clock.p2 > 10 ? 2 : 1) {
unsigned int error_ppm;
- clock.p = clock.p1 * clock.p2;
+ clock.p = clock.p1 * clock.p2 * 5;
m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
refclk * clock.m1);
@@ -763,8 +762,8 @@ chv_find_best_dpll(const struct intel_limit *limit,
bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
struct dpll *best_clock)
{
- int refclk = 100000;
const struct intel_limit *limit = &intel_limits_bxt;
+ int refclk = 100000;
return chv_find_best_dpll(limit, crtc_state,
crtc_state->port_clock, refclk,
@@ -931,32 +930,48 @@ static void i8xx_compute_dpll(struct intel_crtc_state *crtc_state,
crtc_state->dpll_hw_state.dpll = dpll;
}
-static int hsw_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int hsw_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct intel_atomic_state *state =
- to_intel_atomic_state(crtc_state->uapi.state);
+ return 0;
+}
+
+static int hsw_crtc_get_shared_dpll(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
struct intel_encoder *encoder =
intel_get_crtc_new_encoder(state, crtc_state);
-
- if (IS_DG2(dev_priv))
- return intel_mpllb_calc_state(crtc_state, encoder);
+ int ret;
if (DISPLAY_VER(dev_priv) < 11 &&
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
return 0;
- if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
+ ret = intel_reserve_shared_dplls(state, crtc, encoder);
+ if (ret) {
drm_dbg_kms(&dev_priv->drm,
"failed to find PLL for pipe %c\n",
pipe_name(crtc->pipe));
- return -EINVAL;
+ return ret;
}
return 0;
}
+static int dg2_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ struct intel_encoder *encoder =
+ intel_get_crtc_new_encoder(state, crtc_state);
+
+ return intel_mpllb_calc_state(crtc_state, encoder);
+}
+
static bool ilk_needs_fb_cb_tune(const struct dpll *dpll, int factor)
{
return dpll->m < factor * dpll->n;
@@ -1072,18 +1087,15 @@ static void ilk_compute_dpll(struct intel_crtc_state *crtc_state,
crtc_state->dpll_hw_state.dpll = dpll;
}
-static int ilk_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int ilk_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct intel_atomic_state *state =
- to_intel_atomic_state(crtc_state->uapi.state);
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit;
int refclk = 120000;
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
if (!crtc_state->has_pch_encoder)
return 0;
@@ -1122,11 +1134,27 @@ static int ilk_crtc_compute_clock(struct intel_crtc_state *crtc_state)
ilk_compute_dpll(crtc_state, &crtc_state->dpll,
&crtc_state->dpll);
- if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
+ return 0;
+}
+
+static int ilk_crtc_get_shared_dpll(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ int ret;
+
+ /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
+ if (!crtc_state->has_pch_encoder)
+ return 0;
+
+ ret = intel_reserve_shared_dplls(state, crtc, NULL);
+ if (ret) {
drm_dbg_kms(&dev_priv->drm,
"failed to find PLL for pipe %c\n",
pipe_name(crtc->pipe));
- return -EINVAL;
+ return ret;
}
return 0;
@@ -1167,14 +1195,14 @@ void chv_compute_dpll(struct intel_crtc_state *crtc_state)
(crtc_state->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
}
-static int chv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int chv_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- int refclk = 100000;
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit = &intel_limits_chv;
- struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
-
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
+ int refclk = 100000;
if (!crtc_state->clock_set &&
!chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
@@ -1188,14 +1216,14 @@ static int chv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
return 0;
}
-static int vlv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int vlv_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- int refclk = 100000;
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit = &intel_limits_vlv;
- struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
-
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
+ int refclk = 100000;
if (!crtc_state->clock_set &&
!vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
@@ -1209,16 +1237,15 @@ static int vlv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
return 0;
}
-static int g4x_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int g4x_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit;
int refclk = 96000;
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
if (intel_panel_use_ssc(dev_priv)) {
refclk = dev_priv->vbt.lvds_ssc_freq;
@@ -1255,16 +1282,15 @@ static int g4x_crtc_compute_clock(struct intel_crtc_state *crtc_state)
return 0;
}
-static int pnv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int pnv_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit;
int refclk = 96000;
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
if (intel_panel_use_ssc(dev_priv)) {
refclk = dev_priv->vbt.lvds_ssc_freq;
@@ -1292,16 +1318,15 @@ static int pnv_crtc_compute_clock(struct intel_crtc_state *crtc_state)
return 0;
}
-static int i9xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int i9xx_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit;
int refclk = 96000;
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
if (intel_panel_use_ssc(dev_priv)) {
refclk = dev_priv->vbt.lvds_ssc_freq;
@@ -1329,16 +1354,15 @@ static int i9xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
return 0;
}
-static int i8xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
+static int i8xx_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_limit *limit;
int refclk = 48000;
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
if (intel_panel_use_ssc(dev_priv)) {
refclk = dev_priv->vbt.lvds_ssc_freq;
@@ -1368,12 +1392,18 @@ static int i8xx_crtc_compute_clock(struct intel_crtc_state *crtc_state)
return 0;
}
+static const struct intel_dpll_funcs dg2_dpll_funcs = {
+ .crtc_compute_clock = dg2_crtc_compute_clock,
+};
+
static const struct intel_dpll_funcs hsw_dpll_funcs = {
.crtc_compute_clock = hsw_crtc_compute_clock,
+ .crtc_get_shared_dpll = hsw_crtc_get_shared_dpll,
};
static const struct intel_dpll_funcs ilk_dpll_funcs = {
.crtc_compute_clock = ilk_crtc_compute_clock,
+ .crtc_get_shared_dpll = ilk_crtc_get_shared_dpll,
};
static const struct intel_dpll_funcs chv_dpll_funcs = {
@@ -1400,10 +1430,54 @@ static const struct intel_dpll_funcs i8xx_dpll_funcs = {
.crtc_compute_clock = i8xx_crtc_compute_clock,
};
+int intel_dpll_crtc_compute_clock(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+
+ drm_WARN_ON(&i915->drm, !intel_crtc_needs_modeset(crtc_state));
+
+ if (drm_WARN_ON(&i915->drm, crtc_state->shared_dpll))
+ return 0;
+
+ memset(&crtc_state->dpll_hw_state, 0,
+ sizeof(crtc_state->dpll_hw_state));
+
+ if (!crtc_state->hw.enable)
+ return 0;
+
+ return i915->dpll_funcs->crtc_compute_clock(state, crtc);
+}
+
+int intel_dpll_crtc_get_shared_dpll(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+
+ drm_WARN_ON(&i915->drm, !intel_crtc_needs_modeset(crtc_state));
+
+ if (drm_WARN_ON(&i915->drm, crtc_state->shared_dpll))
+ return 0;
+
+ if (!crtc_state->hw.enable)
+ return 0;
+
+ if (!i915->dpll_funcs->crtc_get_shared_dpll)
+ return 0;
+
+ return i915->dpll_funcs->crtc_get_shared_dpll(state, crtc);
+}
+
void
intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv)
{
- if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv))
+ if (IS_DG2(dev_priv))
+ dev_priv->dpll_funcs = &dg2_dpll_funcs;
+ else if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv))
dev_priv->dpll_funcs = &hsw_dpll_funcs;
else if (HAS_PCH_SPLIT(dev_priv))
dev_priv->dpll_funcs = &ilk_dpll_funcs;
@@ -1933,7 +2007,7 @@ static void assert_pll(struct drm_i915_private *dev_priv,
cur_state = intel_de_read(dev_priv, DPLL(pipe)) & DPLL_VCO_ENABLE;
I915_STATE_WARN(cur_state != state,
"PLL state assertion failure (expected %s, current %s)\n",
- onoff(state), onoff(cur_state));
+ str_on_off(state), str_on_off(cur_state));
}
void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe)