From cfe01a5eba1ff5723f3a47895fb7e9d890edf157 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 1 Sep 2015 19:41:38 +0530 Subject: [PATCH] drm/i915/bxt: Enable BXT DSI PLL This patch adds new functions for BXT clock and PLL programming. They are: 1. configure_dsi_pll for BXT. This function does the basic math and generates the divider ratio based on requested pixclock, and program clock registers. 2. enable_dsi_pll function. This function programs the calculated clock values on the PLL. 3. intel_enable_dsi_pll Wrapper function to use same code for multiple platforms. It checks the platform and calls appropriate core pll enable function. v2: Fixed Jani's review comments. Macros are adjusted as per convention. v3: Removed a redundant change wrt code comment. Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 22 +++++++ drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_dsi.h | 2 +- drivers/gpu/drm/i915/intel_dsi_pll.c | 95 +++++++++++++++++++++++++++- 4 files changed, 118 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dd3d235b27ac..4ef16aabc30a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7507,6 +7507,28 @@ enum skl_disp_power_wells { #define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */ +#define BXT_DSI_PLL_CTL 0x161000 +#define BXT_DSI_PLL_PVD_RATIO_SHIFT 16 +#define BXT_DSI_PLL_PVD_RATIO_MASK (3 << BXT_DSI_PLL_PVD_RATIO_SHIFT) +#define BXT_DSI_PLL_PVD_RATIO_1 (1 << BXT_DSI_PLL_PVD_RATIO_SHIFT) +#define BXT_DSIC_16X_BY2 (1 << 10) +#define BXT_DSIC_16X_BY3 (2 << 10) +#define BXT_DSIC_16X_BY4 (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_DSI_FREQ_SEL_SHIFT 8 +#define BXT_DSI_FREQ_SEL_MASK (0xF << BXT_DSI_FREQ_SEL_SHIFT) + +#define BXT_DSI_PLL_RATIO_MAX 0x7D +#define BXT_DSI_PLL_RATIO_MIN 0x22 +#define BXT_DSI_PLL_RATIO_MASK 0xFF +#define BXT_REF_CLOCK_KHZ 19500 + +#define BXT_DSI_PLL_ENABLE 0x46080 +#define BXT_DSI_PLL_DO_ENABLE (1 << 31) +#define BXT_DSI_PLL_LOCKED (1 << 30) + #define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) #define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) #define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 781c267ea97c..f2f819605e5c 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -914,8 +914,8 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); intel_dsi_prepare(encoder); + intel_enable_dsi_pll(encoder); - vlv_enable_dsi_pll(encoder); } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 42a68593e32a..7f16c686771b 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -124,7 +124,7 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) return container_of(encoder, struct intel_dsi, base.base); } -extern void vlv_enable_dsi_pll(struct intel_encoder *encoder); +extern void intel_enable_dsi_pll(struct intel_encoder *encoder); extern void vlv_disable_dsi_pll(struct intel_encoder *encoder); extern u32 vlv_get_dsi_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 c6a8975b128f..b07483beded0 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -246,7 +246,7 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp.dsi_pll_ctrl); } -void vlv_enable_dsi_pll(struct intel_encoder *encoder) +static void vlv_enable_dsi_pll(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; u32 tmp; @@ -363,3 +363,96 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) return pclk; } + +static bool bxt_configure_dsi_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u8 dsi_ratio; + u32 dsi_clk; + u32 val; + + dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, + intel_dsi->lane_count); + + /* + * From clock diagram, to get PLL ratio divider, divide double of DSI + * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to + * round 'up' the result + */ + dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ); + if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN || + dsi_ratio > BXT_DSI_PLL_RATIO_MAX) { + DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n"); + return false; + } + + /* + * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x + * Spec says both have to be programmed, even if one is not getting + * used. Configure MIPI_CLOCK_CTL dividers in modeset + */ + val = I915_READ(BXT_DSI_PLL_CTL); + val &= ~BXT_DSI_PLL_PVD_RATIO_MASK; + val &= ~BXT_DSI_FREQ_SEL_MASK; + val &= ~BXT_DSI_PLL_RATIO_MASK; + val |= (dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2); + + /* As per recommendation from hardware team, + * Prog PVD ratio =1 if dsi ratio <= 50 + */ + if (dsi_ratio <= 50) { + val &= ~BXT_DSI_PLL_PVD_RATIO_MASK; + val |= BXT_DSI_PLL_PVD_RATIO_1; + } + + I915_WRITE(BXT_DSI_PLL_CTL, val); + POSTING_READ(BXT_DSI_PLL_CTL); + + return true; +} + +static void bxt_enable_dsi_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + u32 val; + + DRM_DEBUG_KMS("\n"); + + val = I915_READ(BXT_DSI_PLL_ENABLE); + + if (val & BXT_DSI_PLL_DO_ENABLE) { + WARN(1, "DSI PLL already enabled. Disabling it.\n"); + val &= ~BXT_DSI_PLL_DO_ENABLE; + I915_WRITE(BXT_DSI_PLL_ENABLE, val); + } + + /* Configure PLL vales */ + if (!bxt_configure_dsi_pll(encoder)) { + DRM_ERROR("Configure DSI PLL failed, abort PLL enable\n"); + return; + } + + /* Enable DSI PLL */ + val = I915_READ(BXT_DSI_PLL_ENABLE); + val |= BXT_DSI_PLL_DO_ENABLE; + I915_WRITE(BXT_DSI_PLL_ENABLE, val); + + /* Timeout and fail if PLL not locked */ + if (wait_for(I915_READ(BXT_DSI_PLL_ENABLE) & BXT_DSI_PLL_LOCKED, 1)) { + DRM_ERROR("Timed out waiting for DSI PLL to lock\n"); + return; + } + + DRM_DEBUG_KMS("DSI PLL locked\n"); +} + +void intel_enable_dsi_pll(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + + if (IS_VALLEYVIEW(dev)) + vlv_enable_dsi_pll(encoder); + else if (IS_BROXTON(dev)) + bxt_enable_dsi_pll(encoder); +}