aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2016-03-24 06:41:40 -0400
committerImre Deak <imre.deak@intel.com>2016-03-24 08:48:21 -0400
commitdb18b6a64ca3fb260858279b218b84d5c179330f (patch)
tree979018a17717d0ddb5fc2e432af789a408d09620
parent307e44988018943586f27d554a1773f685b3342e (diff)
drm/i915/bxt: Fix DSI HW state readout
Currently the machine hangs during booting while accessing the BXT_MIPI_PORT_CTRL register during pipe HW state readout. After some experimentation I found that the hang is caused by the DSI PLL being disabled, or it being enabled but with an incorrect divider configuration. Enabling the PLL got rid of the boot problem, so fix this by checking the PLL enabled state/configuration before attempting to read out the HW state. The DSI_PLL_ENABLE register is in the always-on power well, while the BXT_DSI_PLL_CTL is in power well 0. This isn't exactly matched by the transcoder power domain, but what we really need is just a runtime PM reference, which is provided by any power domain. Ville also found this dependency specified in BSpec, so I added a reference to that too. v2: - Make sure we hold a power reference while accessing the PLL registers. v3: (Jani) - Simplify check in bxt_get_dsi_transcoder_state() - Add comment explaining why we check for valid dividers in bxt_dsi_pll_is_enabled() CC: Shashank Sharma <shashank.sharma@intel.com> CC: Uma Shankar <uma.shankar@intel.com> CC: Jani Nikula <jani.nikula@intel.com> Fixes: c6c794a2fc5e ("drm/i915/bxt: Initialize MIPI DSI for BXT") Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Reviewed-by: Shashank Sharma <shashank.sharma@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1458816100-31269-1-git-send-email-imre.deak@intel.com
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c11
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c9
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.h1
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_pll.c40
5 files changed, 63 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f3ba43c2ca22..c839ce952a50 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7811,9 +7811,11 @@ enum skl_disp_power_wells {
7811#define BXT_DSIC_16X_BY2 (1 << 10) 7811#define BXT_DSIC_16X_BY2 (1 << 10)
7812#define BXT_DSIC_16X_BY3 (2 << 10) 7812#define BXT_DSIC_16X_BY3 (2 << 10)
7813#define BXT_DSIC_16X_BY4 (3 << 10) 7813#define BXT_DSIC_16X_BY4 (3 << 10)
7814#define BXT_DSIC_16X_MASK (3 << 10)
7814#define BXT_DSIA_16X_BY2 (1 << 8) 7815#define BXT_DSIA_16X_BY2 (1 << 8)
7815#define BXT_DSIA_16X_BY3 (2 << 8) 7816#define BXT_DSIA_16X_BY3 (2 << 8)
7816#define BXT_DSIA_16X_BY4 (3 << 8) 7817#define BXT_DSIA_16X_BY4 (3 << 8)
7818#define BXT_DSIA_16X_MASK (3 << 8)
7817#define BXT_DSI_FREQ_SEL_SHIFT 8 7819#define BXT_DSI_FREQ_SEL_SHIFT 8
7818#define BXT_DSI_FREQ_SEL_MASK (0xF << BXT_DSI_FREQ_SEL_SHIFT) 7820#define BXT_DSI_FREQ_SEL_MASK (0xF << BXT_DSI_FREQ_SEL_SHIFT)
7819 7821
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 7c4ffcaf13c1..29aa64be1f03 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -36,6 +36,7 @@
36#include "intel_drv.h" 36#include "intel_drv.h"
37#include <drm/i915_drm.h> 37#include <drm/i915_drm.h>
38#include "i915_drv.h" 38#include "i915_drv.h"
39#include "intel_dsi.h"
39#include "i915_trace.h" 40#include "i915_trace.h"
40#include <drm/drm_atomic.h> 41#include <drm/drm_atomic.h>
41#include <drm/drm_atomic_helper.h> 42#include <drm/drm_atomic_helper.h>
@@ -9870,6 +9871,16 @@ static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc,
9870 continue; 9871 continue;
9871 *power_domain_mask |= BIT(power_domain); 9872 *power_domain_mask |= BIT(power_domain);
9872 9873
9874 /*
9875 * The PLL needs to be enabled with a valid divider
9876 * configuration, otherwise accessing DSI registers will hang
9877 * the machine. See BSpec North Display Engine
9878 * registers/MIPI[BXT]. We can break out here early, since we
9879 * need the same DSI PLL to be enabled for both DSI ports.
9880 */
9881 if (!intel_dsi_pll_is_enabled(dev_priv))
9882 break;
9883
9873 /* XXX: this works for video mode only */ 9884 /* XXX: this works for video mode only */
9874 tmp = I915_READ(BXT_MIPI_PORT_CTRL(port)); 9885 tmp = I915_READ(BXT_MIPI_PORT_CTRL(port));
9875 if (!(tmp & DPI_ENABLE)) 9886 if (!(tmp & DPI_ENABLE))
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 96ea3f741a89..0de74e1b7ab3 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -684,6 +684,14 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
684 if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) 684 if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
685 return false; 685 return false;
686 686
687 /*
688 * On Broxton the PLL needs to be enabled with a valid divider
689 * configuration, otherwise accessing DSI registers will hang the
690 * machine. See BSpec North Display Engine registers/MIPI[BXT].
691 */
692 if (IS_BROXTON(dev_priv) && !intel_dsi_pll_is_enabled(dev_priv))
693 goto out_put_power;
694
687 /* XXX: this only works for one DSI output */ 695 /* XXX: this only works for one DSI output */
688 for_each_dsi_port(port, intel_dsi->ports) { 696 for_each_dsi_port(port, intel_dsi->ports) {
689 i915_reg_t ctrl_reg = IS_BROXTON(dev) ? 697 i915_reg_t ctrl_reg = IS_BROXTON(dev) ?
@@ -726,6 +734,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
726 break; 734 break;
727 } 735 }
728 736
737out_put_power:
729 intel_display_power_put(dev_priv, power_domain); 738 intel_display_power_put(dev_priv, power_domain);
730 739
731 return active; 740 return active;
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index e582ef8f3dac..ec58ead9ccd1 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -126,6 +126,7 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
126 return container_of(encoder, struct intel_dsi, base.base); 126 return container_of(encoder, struct intel_dsi, base.base);
127} 127}
128 128
129bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
129extern void intel_enable_dsi_pll(struct intel_encoder *encoder); 130extern void intel_enable_dsi_pll(struct intel_encoder *encoder);
130extern void intel_disable_dsi_pll(struct intel_encoder *encoder); 131extern void intel_disable_dsi_pll(struct intel_encoder *encoder);
131extern u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp); 132extern u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp);
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index e3e343c80221..4e53fcf6e087 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -192,6 +192,36 @@ static void vlv_disable_dsi_pll(struct intel_encoder *encoder)
192 mutex_unlock(&dev_priv->sb_lock); 192 mutex_unlock(&dev_priv->sb_lock);
193} 193}
194 194
195static bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
196{
197 bool enabled;
198 u32 val;
199 u32 mask;
200
201 mask = BXT_DSI_PLL_DO_ENABLE | BXT_DSI_PLL_LOCKED;
202 val = I915_READ(BXT_DSI_PLL_ENABLE);
203 enabled = (val & mask) == mask;
204
205 if (!enabled)
206 return false;
207
208 /*
209 * Both dividers must be programmed with valid values even if only one
210 * of the PLL is used, see BSpec/Broxton Clocks. Check this here for
211 * paranoia, since BIOS is known to misconfigure PLLs in this way at
212 * times, and since accessing DSI registers with invalid dividers
213 * causes a system hang.
214 */
215 val = I915_READ(BXT_DSI_PLL_CTL);
216 if (!(val & BXT_DSIA_16X_MASK) || !(val & BXT_DSIC_16X_MASK)) {
217 DRM_DEBUG_DRIVER("PLL is enabled with invalid divider settings (%08x)\n",
218 val);
219 enabled = false;
220 }
221
222 return enabled;
223}
224
195static void bxt_disable_dsi_pll(struct intel_encoder *encoder) 225static void bxt_disable_dsi_pll(struct intel_encoder *encoder)
196{ 226{
197 struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 227 struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -486,6 +516,16 @@ static void bxt_enable_dsi_pll(struct intel_encoder *encoder)
486 DRM_DEBUG_KMS("DSI PLL locked\n"); 516 DRM_DEBUG_KMS("DSI PLL locked\n");
487} 517}
488 518
519bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
520{
521 if (IS_BROXTON(dev_priv))
522 return bxt_dsi_pll_is_enabled(dev_priv);
523
524 MISSING_CASE(INTEL_DEVID(dev_priv));
525
526 return false;
527}
528
489void intel_enable_dsi_pll(struct intel_encoder *encoder) 529void intel_enable_dsi_pll(struct intel_encoder *encoder)
490{ 530{
491 struct drm_device *dev = encoder->base.dev; 531 struct drm_device *dev = encoder->base.dev;