[Intel-gfx] [PATCH v3] drm/i915/bxt: Fix DSI HW state readout
Jani Nikula
jani.nikula at intel.com
Thu Mar 24 10:49:16 UTC 2016
On Thu, 24 Mar 2016, Imre Deak <imre.deak at intel.com> wrote:
> 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 at intel.com>
> CC: Uma Shankar <uma.shankar at intel.com>
> CC: Jani Nikula <jani.nikula at intel.com>
> Fixes: c6c794a2fc5e ("drm/i915/bxt: Initialize MIPI DSI for BXT")
> Signed-off-by: Imre Deak <imre.deak at intel.com>
Thanks for fixing this.
Reviewed-by: Jani Nikula <jani.nikula at intel.com>
> ---
> drivers/gpu/drm/i915/i915_reg.h | 2 ++
> drivers/gpu/drm/i915/intel_display.c | 11 ++++++++++
> drivers/gpu/drm/i915/intel_dsi.c | 9 ++++++++
> drivers/gpu/drm/i915/intel_dsi.h | 1 +
> drivers/gpu/drm/i915/intel_dsi_pll.c | 40 ++++++++++++++++++++++++++++++++++++
> 5 files changed, 63 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index f3ba43c..c839ce9 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 {
> #define BXT_DSIC_16X_BY2 (1 << 10)
> #define BXT_DSIC_16X_BY3 (2 << 10)
> #define BXT_DSIC_16X_BY4 (3 << 10)
> +#define BXT_DSIC_16X_MASK (3 << 10)
> #define BXT_DSIA_16X_BY2 (1 << 8)
> #define BXT_DSIA_16X_BY3 (2 << 8)
> #define BXT_DSIA_16X_BY4 (3 << 8)
> +#define BXT_DSIA_16X_MASK (3 << 8)
> #define BXT_DSI_FREQ_SEL_SHIFT 8
> #define BXT_DSI_FREQ_SEL_MASK (0xF << BXT_DSI_FREQ_SEL_SHIFT)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 009b03b..e05393e 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -36,6 +36,7 @@
> #include "intel_drv.h"
> #include <drm/i915_drm.h>
> #include "i915_drv.h"
> +#include "intel_dsi.h"
> #include "i915_trace.h"
> #include <drm/drm_atomic.h>
> #include <drm/drm_atomic_helper.h>
> @@ -9867,6 +9868,16 @@ static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc,
> continue;
> *power_domain_mask |= BIT(power_domain);
>
> + /*
> + * The PLL needs to be enabled with a valid divider
> + * configuration, otherwise accessing DSI registers will hang
> + * the machine. See BSpec North Display Engine
> + * registers/MIPI[BXT]. We can break out here early, since we
> + * need the same DSI PLL to be enabled for both DSI ports.
> + */
> + if (!intel_dsi_pll_is_enabled(dev_priv))
> + break;
> +
> /* XXX: this works for video mode only */
> tmp = I915_READ(BXT_MIPI_PORT_CTRL(port));
> if (!(tmp & DPI_ENABLE))
> diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
> index 96ea3f7..0de74e1 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,
> if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> return false;
>
> + /*
> + * On Broxton the PLL needs to be enabled with a valid divider
> + * configuration, otherwise accessing DSI registers will hang the
> + * machine. See BSpec North Display Engine registers/MIPI[BXT].
> + */
> + if (IS_BROXTON(dev_priv) && !intel_dsi_pll_is_enabled(dev_priv))
> + goto out_put_power;
> +
> /* XXX: this only works for one DSI output */
> for_each_dsi_port(port, intel_dsi->ports) {
> i915_reg_t ctrl_reg = IS_BROXTON(dev) ?
> @@ -726,6 +734,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
> break;
> }
>
> +out_put_power:
> intel_display_power_put(dev_priv, power_domain);
>
> return active;
> diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
> index e582ef8..ec58ead 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)
> return container_of(encoder, struct intel_dsi, base.base);
> }
>
> +bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
> extern void intel_enable_dsi_pll(struct intel_encoder *encoder);
> extern void intel_disable_dsi_pll(struct intel_encoder *encoder);
> extern 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 e3e343c..ce688f9 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)
> mutex_unlock(&dev_priv->sb_lock);
> }
>
> +static bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
> +{
> + bool enabled;
> + u32 val;
> + u32 mask;
> +
> + mask = BXT_DSI_PLL_DO_ENABLE | BXT_DSI_PLL_LOCKED;
> + val = I915_READ(BXT_DSI_PLL_ENABLE);
> + enabled = (val & mask) == mask;
> +
> + if (!enabled)
> + return false;
> +
> + /*
> + * Both dividers must be programmed with valid values even if only one
> + * of the PLL is used, see BSpec/Broxton Clocks. Check this here for
> + * paranoia, since BIOS is known to misconfigure PLLs in this way at
> + * times, and since accessing DSI registers with invalid dividers
> + * causes a system hang.
> + */
> + val = I915_READ(BXT_DSI_PLL_CTL);
> + if (!(val & BXT_DSIA_16X_MASK) || !(val & BXT_DSIC_16X_MASK)) {
> + DRM_DEBUG_DRIVER("PLL is enabled with invalid divider settings "
> + "(%08x)\n", val);
> + enabled = false;
> + }
> +
> + return enabled;
> +}
> +
> static void bxt_disable_dsi_pll(struct intel_encoder *encoder)
> {
> 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)
> DRM_DEBUG_KMS("DSI PLL locked\n");
> }
>
> +bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
> +{
> + if (IS_BROXTON(dev_priv))
> + return bxt_dsi_pll_is_enabled(dev_priv);
> +
> + MISSING_CASE(INTEL_DEVID(dev_priv));
> +
> + return false;
> +}
> +
> void intel_enable_dsi_pll(struct intel_encoder *encoder)
> {
> struct drm_device *dev = encoder->base.dev;
--
Jani Nikula, Intel Open Source Technology Center
More information about the Intel-gfx
mailing list