blob: c07f728fb5ddb01b70c18825462a0a0458896161 [file] [log] [blame]
From 47fff9f06340231bec1845484552322a52b70561 Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Wed, 5 Jun 2013 13:34:16 +0200
Subject: drm/i915: display pll hw state readout and checking
Currently still with an empty register state, this will follow in a
next step. This one here just creates the new vfunc and uses it for
cross-checking, initial state takeover and the dpll assert function.
And add a FIXME for the ddi pll readout code, which still needs to be
converted over.
v2:
- Add some hw state readout debug output.
- Also cross check the enabled crtc counting.
Note that I've botched up the patch ordering, and before this patch
we've read out the pll selection correctly, but did not reconstruct
the refcounts properly. See the bug link.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65673
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
(cherry picked from commit 5358901f99153085db59c3644db00b8753b50ac1)
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 7 +++
drivers/gpu/drm/i915/intel_display.c | 77 ++++++++++++++++++++++++++++++++---
2 files changed, 79 insertions(+), 5 deletions(-)
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -142,6 +142,9 @@ enum intel_dpll_id {
};
#define I915_NUM_PLLS 2
+struct intel_dpll_hw_state {
+};
+
struct intel_shared_dpll {
int refcount; /* count of number of CRTCs sharing this PLL */
int active; /* count of number of active CRTCs (i.e. DPMS on) */
@@ -149,10 +152,14 @@ struct intel_shared_dpll {
const char *name;
/* should match the index in the dev_priv->shared_dplls array */
enum intel_dpll_id id;
+ struct intel_dpll_hw_state hw_state;
void (*enable)(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll);
void (*disable)(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll);
+ bool (*get_hw_state)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
};
/* Used by dp and fdi links */
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -925,8 +925,8 @@ static void assert_shared_dpll(struct dr
struct intel_shared_dpll *pll,
bool state)
{
- u32 val;
bool cur_state;
+ struct intel_dpll_hw_state hw_state;
if (HAS_PCH_LPT(dev_priv->dev)) {
DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n");
@@ -937,11 +937,10 @@ static void assert_shared_dpll(struct dr
"asserting DPLL %s with no DPLL\n", state_string(state)))
return;
- val = I915_READ(PCH_DPLL(pll->id));
- cur_state = !!(val & DPLL_VCO_ENABLE);
+ cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
WARN(cur_state != state,
- "%s assertion failure (expected %s, current %s), val=%08x\n",
- pll->name, state_string(state), state_string(cur_state), val);
+ "%s assertion failure (expected %s, current %s)\n",
+ pll->name, state_string(state), state_string(cur_state));
}
#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
@@ -8151,6 +8150,8 @@ intel_modeset_check_state(struct drm_dev
struct intel_encoder *encoder;
struct intel_connector *connector;
struct intel_crtc_config pipe_config;
+ struct intel_dpll_hw_state dpll_hw_state;
+ int i;
list_for_each_entry(connector, &dev->mode_config.connector_list,
base.head) {
@@ -8270,6 +8271,41 @@ intel_modeset_check_state(struct drm_dev
"[sw state]");
}
}
+
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+ int enabled_crtcs = 0, active_crtcs = 0;
+ bool active;
+
+ memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
+
+ DRM_DEBUG_KMS("%s\n", pll->name);
+
+ active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
+
+ WARN(pll->active > pll->refcount,
+ "more active pll users than references: %i vs %i\n",
+ pll->active, pll->refcount);
+ WARN(pll->active && !pll->on,
+ "pll in active use but not on in sw tracking\n");
+ WARN(pll->on != active,
+ "pll on state mismatch (expected %i, found %i)\n",
+ pll->on, active);
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+ base.head) {
+ if (crtc->base.enabled && intel_crtc_to_shared_dpll(crtc) == pll)
+ enabled_crtcs++;
+ if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
+ active_crtcs++;
+ }
+ WARN(pll->active != active_crtcs,
+ "pll active crtcs mismatch (expected %i, found %i)\n",
+ pll->active, active_crtcs);
+ WARN(pll->refcount != enabled_crtcs,
+ "pll enabled crtcs mismatch (expected %i, found %i)\n",
+ pll->refcount, enabled_crtcs);
+ }
}
static int __intel_set_mode(struct drm_crtc *crtc,
@@ -8711,6 +8747,17 @@ static void intel_cpu_pll_init(struct dr
intel_ddi_pll_init(dev);
}
+static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+
+ val = I915_READ(PCH_DPLL(pll->id));
+
+ return val & DPLL_VCO_ENABLE;
+}
+
static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
@@ -8765,6 +8812,8 @@ static void ibx_pch_dpll_init(struct drm
dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
+ dev_priv->shared_dplls[i].get_hw_state =
+ ibx_pch_dpll_get_hw_state;
}
}
@@ -9704,6 +9753,7 @@ void intel_modeset_setup_hw_state(struct
struct intel_crtc *crtc;
struct intel_encoder *encoder;
struct intel_connector *connector;
+ int i;
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
base.head) {
@@ -9719,9 +9769,26 @@ void intel_modeset_setup_hw_state(struct
crtc->active ? "enabled" : "disabled");
}
+ /* FIXME: Smash this into the new shared dpll infrastructure. */
if (HAS_DDI(dev))
intel_ddi_setup_hw_pll_state(dev);
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+
+ pll->on = pll->get_hw_state(dev_priv, pll, &pll->hw_state);
+ pll->active = 0;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+ base.head) {
+ if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
+ pll->active++;
+ }
+ pll->refcount = pll->active;
+
+ DRM_DEBUG_KMS("%s hw state readout: refcount %i\n",
+ pll->name, pll->refcount);
+ }
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
base.head) {
pipe = 0;