From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> Compute the DSI PLL parameters during .compute_config() rather than .pre_pll_enable() so that we can fail gracefully if we can't find suitable parameters. In order to do that we need to store the DSI PLL parameters in pipe_config. Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/intel_display.c | 3 ++ drivers/gpu/drm/i915/intel_drv.h | 5 ++++ drivers/gpu/drm/i915/intel_dsi.c | 16 +++++++---- drivers/gpu/drm/i915/intel_dsi.h | 8 ++++-- drivers/gpu/drm/i915/intel_dsi_pll.c | 56 +++++++++++++++++++++--------------- 5 files changed, 57 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ec39b0..9a77ca5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12488,6 +12488,9 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1); PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2); + PIPE_CONF_CHECK_X(dsi_pll.ctrl); + PIPE_CONF_CHECK_X(dsi_pll.div); + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) PIPE_CONF_CHECK_I(pipe_bpp); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cf971ef..8bb74eb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -407,6 +407,11 @@ struct intel_crtc_state { /* Actual register state of the dpll, for shared dpll cross-checking. */ struct intel_dpll_hw_state dpll_hw_state; + /* DSI PLL registers */ + struct { + u32 ctrl, div; + } dsi_pll; + int pipe_bpp; struct intel_link_m_n dp_m_n; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index e0ccaf1..4cf6c0d 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -270,6 +270,7 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, struct intel_connector *intel_connector = intel_dsi->attached_connector; struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; struct drm_display_mode *adjusted_mode = &config->base.adjusted_mode; + int ret; DRM_DEBUG_KMS("\n"); @@ -279,10 +280,10 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, /* DSI uses short packets for sync events, so clear mode flags for DSI */ adjusted_mode->flags = 0; - /* - * FIXME move the DSI PLL calc from vlv_enable_dsi_pll() - * to .compute_config(). - */ + ret = vlv_compute_dsi_pll(encoder, config); + if (ret) + return false; + config->clock_set = true; return true; @@ -629,7 +630,8 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, u32 pclk; DRM_DEBUG_KMS("\n"); - pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp); + pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp, + pipe_config); if (!pclk) return; @@ -900,6 +902,8 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) { + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + DRM_DEBUG_KMS("\n"); intel_dsi_prepare(encoder); @@ -909,7 +913,7 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) * lock. It needs to be fully powered down to fix it. */ vlv_disable_dsi_pll(encoder); - vlv_enable_dsi_pll(encoder); + vlv_enable_dsi_pll(encoder, intel_crtc->config); } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 42a6859..58c39b4 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -124,9 +124,13 @@ 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 int vlv_compute_dsi_pll(struct intel_encoder *encoder, + struct intel_crtc_state *config); +extern void vlv_enable_dsi_pll(struct intel_encoder *encoder, + const struct intel_crtc_state *config); extern void vlv_disable_dsi_pll(struct intel_encoder *encoder); -extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp); +extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp, + struct intel_crtc_state *config); struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id); diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index c6a8975..79c18a0 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -59,10 +59,6 @@ static int dsi_pixel_format_bpp(int pixel_format) return bpp; } -struct dsi_mnp { - u32 dsi_pll_ctrl; - u32 dsi_pll_div; -}; static const u32 lfsr_converts[] = { 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 62 - 70 */ @@ -158,7 +154,8 @@ static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count) #endif static int dsi_calc_mnp(struct drm_i915_private *dev_priv, - struct dsi_mnp *dsi_mnp, int target_dsi_clk) + struct intel_crtc_state *config, + int target_dsi_clk) { unsigned int calc_m = 0, calc_p = 0; unsigned int m_min, m_max, p_min = 2, p_max = 6; @@ -204,8 +201,8 @@ static int dsi_calc_mnp(struct drm_i915_private *dev_priv, /* register has log2(N1), this works fine for powers of two */ n = ffs(n) - 1; m_seed = lfsr_converts[calc_m - 62]; - dsi_mnp->dsi_pll_ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2); - dsi_mnp->dsi_pll_div = n << DSI_PLL_N1_DIV_SHIFT | + config->dsi_pll.ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2); + config->dsi_pll.div = n << DSI_PLL_N1_DIV_SHIFT | m_seed << DSI_PLL_M1_DIV_SHIFT; return 0; @@ -215,54 +212,63 @@ static int dsi_calc_mnp(struct drm_i915_private *dev_priv, * XXX: The muxing and gating is hard coded for now. Need to add support for * sharing PLLs with two DSI outputs. */ -static void vlv_configure_dsi_pll(struct intel_encoder *encoder) +int vlv_compute_dsi_pll(struct intel_encoder *encoder, + struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int ret; - struct dsi_mnp dsi_mnp; u32 dsi_clk; dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, intel_dsi->lane_count); - ret = dsi_calc_mnp(dev_priv, &dsi_mnp, dsi_clk); + ret = dsi_calc_mnp(dev_priv, config, dsi_clk); if (ret) { DRM_DEBUG_KMS("dsi_calc_mnp failed\n"); - return; + return ret; } if (intel_dsi->ports & (1 << PORT_A)) - dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; + config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; if (intel_dsi->ports & (1 << PORT_C)) - dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL; + config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL; + + config->dsi_pll.ctrl |= DSI_PLL_VCO_EN; DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n", - dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl); + config->dsi_pll.div, config->dsi_pll.ctrl); + + return 0; +} + +static void vlv_configure_dsi_pll(struct intel_encoder *encoder, + const struct intel_crtc_state *config) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0); - vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, dsi_mnp.dsi_pll_div); - vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp.dsi_pll_ctrl); + vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div); + vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, + config->dsi_pll.ctrl & ~DSI_PLL_VCO_EN); } -void vlv_enable_dsi_pll(struct intel_encoder *encoder) +void vlv_enable_dsi_pll(struct intel_encoder *encoder, + const struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - u32 tmp; DRM_DEBUG_KMS("\n"); mutex_lock(&dev_priv->sb_lock); - vlv_configure_dsi_pll(encoder); + vlv_configure_dsi_pll(encoder, config); /* wait at least 0.5 us after ungating before enabling VCO */ usleep_range(1, 10); - tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); - tmp |= DSI_PLL_VCO_EN; - vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp); + vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl); if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) & DSI_PLL_LOCK, 20)) { @@ -302,7 +308,8 @@ static void assert_bpp_mismatch(int pixel_format, int pipe_bpp) bpp, pipe_bpp); } -u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) +u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp, + struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); @@ -319,6 +326,9 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER); mutex_unlock(&dev_priv->sb_lock); + config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK; + config->dsi_pll.div = pll_div; + /* mask out other bits and extract the P1 divisor */ pll_ctl &= DSI_PLL_P1_POST_DIV_MASK; pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2); -- 2.4.6 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx