Message ID | f98b323ed69f16e31d73dcde46c642fa15b8cb8d.1458070700.git.jani.nikula@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Mar 15, 2016 at 09:51:16PM +0200, Jani Nikula wrote: > The BXT display connections have DSI transcoders A and C that can be > muxed to any pipe, not unlike the eDP transcoder. Add the notion of DSI > transcoders. > > The "normal" transcoders A, B and C are not used with BXT DSI, so care > must be taken to avoid accessing those registers with DSI transcoders in > the hardware state readout, modeset, and generally everywhere. > > Signed-off-by: Jani Nikula <jani.nikula@intel.com> > --- > drivers/gpu/drm/i915/i915_drv.h | 10 ++++ > drivers/gpu/drm/i915/intel_ddi.c | 6 +++ > drivers/gpu/drm/i915/intel_display.c | 90 +++++++++++++++++++++++++++++---- > drivers/gpu/drm/i915/intel_drv.h | 3 +- > drivers/gpu/drm/i915/intel_dsi.c | 9 ++++ > drivers/gpu/drm/i915/intel_runtime_pm.c | 6 +++ > 6 files changed, 112 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 5e4a42d996d8..0ddd0f492ca9 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -123,6 +123,8 @@ enum transcoder { > TRANSCODER_B, > TRANSCODER_C, > TRANSCODER_EDP, > + TRANSCODER_DSI_A, > + TRANSCODER_DSI_C, > I915_MAX_TRANSCODERS > }; > > @@ -137,11 +139,17 @@ static inline const char *transcoder_name(enum transcoder transcoder) > return "C"; > case TRANSCODER_EDP: > return "eDP"; > + case TRANSCODER_DSI_A: > + return "DSI A"; > + case TRANSCODER_DSI_C: > + return "DSI C"; > default: > return "<invalid>"; > } > } > > +#define IS_DSI_TRANSCODER(t) ((t) == TRANSCODER_DSI_A || (t) == TRANSCODER_DSI_C) > + > /* > * I915_MAX_PLANES in the enum below is the maximum (across all platforms) > * number of planes per CRTC. Not all platforms really have this many planes, > @@ -192,6 +200,8 @@ enum intel_display_power_domain { > POWER_DOMAIN_TRANSCODER_B, > POWER_DOMAIN_TRANSCODER_C, > POWER_DOMAIN_TRANSCODER_EDP, > + POWER_DOMAIN_TRANSCODER_DSI_A, > + POWER_DOMAIN_TRANSCODER_DSI_C, > POWER_DOMAIN_PORT_DDI_A_LANES, > POWER_DOMAIN_PORT_DDI_B_LANES, > POWER_DOMAIN_PORT_DDI_C_LANES, > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c > index 91654ffc3a42..8726711864eb 100644 > --- a/drivers/gpu/drm/i915/intel_ddi.c > +++ b/drivers/gpu/drm/i915/intel_ddi.c > @@ -1061,6 +1061,8 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) > uint32_t temp; > > if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) { > + WARN_ON(IS_DSI_TRANSCODER(cpu_transcoder)); That all caps IS_DSI_TRANSCODER doesn't really agree with me for some reason. static inline with lower caps name maybe? > + > temp = TRANS_MSA_SYNC_CLK; > switch (intel_crtc->config->pipe_bpp) { > case 18: > @@ -1942,6 +1944,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder, > struct intel_hdmi *intel_hdmi; > u32 temp, flags = 0; > > + /* XXX: DSI transcoder paranoia */ > + if (WARN_ON(IS_DSI_TRANSCODER(cpu_transcoder))) > + return; > + > temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); > if (temp & TRANS_DDI_PHSYNC) > flags |= DRM_MODE_FLAG_PHSYNC; > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 842467528892..f1d0a868e80c 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -4906,7 +4906,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) > > intel_set_pipe_timings(intel_crtc); > > - if (intel_crtc->config->cpu_transcoder != TRANSCODER_EDP) { > + if (intel_crtc->config->cpu_transcoder < TRANSCODER_EDP) { > I915_WRITE(PIPE_MULT(intel_crtc->config->cpu_transcoder), > intel_crtc->config->pixel_multiplier - 1); > } > @@ -4957,7 +4957,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) > dev_priv->display.initial_watermarks(pipe_config); > else > intel_update_watermarks(crtc); > - intel_enable_pipe(intel_crtc); > + > + /* XXX: Do the pipe assertions at the right place for BXT DSI. */ > + if (!intel_crtc->config->has_dsi_encoder) > + intel_enable_pipe(intel_crtc); > > if (intel_crtc->config->has_pch_encoder) > lpt_pch_enable(crtc); > @@ -5090,7 +5093,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) > drm_crtc_vblank_off(crtc); > assert_vblank_disabled(crtc); > > - intel_disable_pipe(intel_crtc); > + /* XXX: Do the pipe assertions at the right place for BXT DSI. */ > + if (!intel_crtc->config->has_dsi_encoder) > + intel_disable_pipe(intel_crtc); > > if (intel_crtc->config->dp_encoder_is_mst) > intel_ddi_set_vc_payload_alloc(crtc, false); > @@ -7707,7 +7712,8 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) > enum pipe pipe = intel_crtc->pipe; > enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; > > - intel_set_trans_timings(intel_crtc); > + if (!IS_DSI_TRANSCODER(cpu_transcoder)) > + intel_set_trans_timings(intel_crtc); I think we should put all the DSI checks to the top level .crtc_enable/disable hooks. Will need to do the function splitting a bit differently perhaps, but I've already commented on those. The main benefit would be a more immediate view on the modeset sequence without having to go through all the functions that get called. Also I would expect it would then be easier to start shifting stuff into the encoder hooks if we choose to go that route. > > /* Workaround: when the EDP input selection is B, the VTOTAL_B must be > * programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is > @@ -7765,9 +7771,11 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc, > { > struct drm_device *dev = crtc->base.dev; > struct drm_i915_private *dev_priv = dev->dev_private; > + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; > uint32_t tmp; > > - intel_get_trans_timings(crtc, pipe_config); > + if (!IS_DSI_TRANSCODER(cpu_transcoder)) > + intel_get_trans_timings(crtc, pipe_config); > > tmp = I915_READ(PIPESRC(crtc->pipe)); > pipe_config->pipe_src_h = (tmp & 0xffff) + 1; > @@ -8776,9 +8784,11 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc) > struct drm_i915_private *dev_priv = dev->dev_private; > struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > enum pipe pipe = intel_crtc->pipe; > + enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; > u32 val; > > - haswell_set_transconf(crtc); > + if (!IS_DSI_TRANSCODER(cpu_transcoder)) > + haswell_set_transconf(crtc); > > I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT); > POSTING_READ(GAMMA_MODE(intel_crtc->pipe)); > @@ -9936,6 +9946,47 @@ static bool hsw_get_trans_config(struct intel_crtc *crtc, > return tmp & PIPECONF_ENABLE; > } > > +static bool bxt_get_dsi_trans_config(struct intel_crtc *crtc, > + struct intel_crtc_state *pipe_config, > + unsigned long *power_domain_mask) > +{ > + struct drm_device *dev = crtc->base.dev; > + struct drm_i915_private *dev_priv = dev->dev_private; > + enum intel_display_power_domain power_domain; > + enum port port; > + enum transcoder cpu_transcoder; > + u32 tmp; > + > + pipe_config->has_dsi_encoder = false; > + > + for_each_port_masked(port, BIT(PORT_A) | BIT(PORT_C)) { > + if (port == PORT_A) > + cpu_transcoder = TRANSCODER_DSI_A; > + else > + cpu_transcoder = TRANSCODER_DSI_C; > + > + power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder); > + if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) > + continue; > + *power_domain_mask |= BIT(power_domain); > + > + /* XXX: this works for video mode only */ > + tmp = I915_READ(BXT_MIPI_PORT_CTRL(port)); > + if (!(tmp & DPI_ENABLE)) > + continue; > + > + tmp = I915_READ(MIPI_CTRL(port)); > + if ((tmp & BXT_PIPE_SELECT_MASK) != BXT_PIPE_SELECT(crtc->pipe)) > + continue; > + > + pipe_config->cpu_transcoder = cpu_transcoder; > + pipe_config->has_dsi_encoder = true; > + break; > + } > + > + return pipe_config->has_dsi_encoder; > +} > + > static void haswell_get_ddi_port_state(struct intel_crtc *crtc, > struct intel_crtc_state *pipe_config) > { > @@ -9997,10 +10048,18 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, > > active = hsw_get_trans_config(crtc, pipe_config, &power_domain_mask); > > + if (IS_BROXTON(dev_priv)) { > + bxt_get_dsi_trans_config(crtc, pipe_config, &power_domain_mask); > + WARN_ON(active && pipe_config->has_dsi_encoder); > + if (pipe_config->has_dsi_encoder) > + active = true; > + } > + > if (!active) > goto out; > > - haswell_get_ddi_port_state(crtc, pipe_config); > + if (!pipe_config->has_dsi_encoder) > + haswell_get_ddi_port_state(crtc, pipe_config); > > intel_get_pipe_timings(crtc, pipe_config); > > @@ -10026,7 +10085,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, > pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && > (I915_READ(IPS_CTL) & IPS_ENABLE); > > - if (pipe_config->cpu_transcoder != TRANSCODER_EDP) { > + if (pipe_config->cpu_transcoder < TRANSCODER_EDP) { > pipe_config->pixel_multiplier = > I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1; > } else { > @@ -15516,10 +15575,18 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) > { > struct drm_device *dev = crtc->base.dev; > struct drm_i915_private *dev_priv = dev->dev_private; > - i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder); > + enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; > > - /* Clear any frame start delays used for debugging left by the BIOS */ > - I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); > + if (!IS_DSI_TRANSCODER(cpu_transcoder)) { > + i915_reg_t reg = PIPECONF(cpu_transcoder); > + > + /* > + * Clear any frame start delays used for debugging left by the > + * BIOS. > + */ > + I915_WRITE(reg, > + I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); > + } > > /* restore vblank interrupts to correct state */ > drm_crtc_vblank_reset(&crtc->base); > @@ -16195,6 +16262,7 @@ intel_display_capture_error_state(struct drm_device *dev) > error->pipe[i].stat = I915_READ(PIPESTAT(i)); > } > > + /* Note: this does not include DSI transcoders. */ > error->num_transcoders = INTEL_INFO(dev)->num_pipes; > if (HAS_DDI(dev_priv->dev)) > error->num_transcoders++; /* Account for eDP. */ > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 02b3d22862a1..6e8c1386129e 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -436,7 +436,8 @@ struct intel_crtc_state { > bool has_infoframe; > > /* CPU Transcoder for the pipe. Currently this can only differ from the > - * pipe on Haswell (where we have a special eDP transcoder). */ > + * pipe on Haswell and later (where we have a special eDP transcoder) > + * and Broxton (where we have special DSI transcoders). */ > enum transcoder cpu_transcoder; > > /* > diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c > index 73c15210fdb1..47fd0296a05a 100644 > --- a/drivers/gpu/drm/i915/intel_dsi.c > +++ b/drivers/gpu/drm/i915/intel_dsi.c > @@ -268,6 +268,7 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) > static bool intel_dsi_compute_config(struct intel_encoder *encoder, > struct intel_crtc_state *pipe_config) > { > + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; > struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, > base); > struct intel_connector *intel_connector = intel_dsi->attached_connector; > @@ -284,6 +285,14 @@ 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; > > + if (IS_BROXTON(dev_priv)) { > + /* Dual link goes to DSI transcoder A. */ > + if (intel_dsi->ports == BIT(PORT_C)) > + pipe_config->cpu_transcoder = TRANSCODER_DSI_C; > + else > + pipe_config->cpu_transcoder = TRANSCODER_DSI_A; > + } > + > return true; > } > > diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c > index 2e88a5e06884..d189a0012277 100644 > --- a/drivers/gpu/drm/i915/intel_runtime_pm.c > +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c > @@ -89,6 +89,10 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) > return "TRANSCODER_C"; > case POWER_DOMAIN_TRANSCODER_EDP: > return "TRANSCODER_EDP"; > + case POWER_DOMAIN_TRANSCODER_DSI_A: > + return "TRANSCODER_DSI_A"; > + case POWER_DOMAIN_TRANSCODER_DSI_C: > + return "TRANSCODER_DSI_C"; > case POWER_DOMAIN_PORT_DDI_A_LANES: > return "PORT_DDI_A_LANES"; > case POWER_DOMAIN_PORT_DDI_B_LANES: > @@ -419,6 +423,8 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, > BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ > BIT(POWER_DOMAIN_PIPE_A) | \ > BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ > + BIT(POWER_DOMAIN_TRANSCODER_DSI_A) | \ > + BIT(POWER_DOMAIN_TRANSCODER_DSI_C) | \ > BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ > BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ > BIT(POWER_DOMAIN_PORT_DSI) | \ > -- > 2.1.4
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5e4a42d996d8..0ddd0f492ca9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -123,6 +123,8 @@ enum transcoder { TRANSCODER_B, TRANSCODER_C, TRANSCODER_EDP, + TRANSCODER_DSI_A, + TRANSCODER_DSI_C, I915_MAX_TRANSCODERS }; @@ -137,11 +139,17 @@ static inline const char *transcoder_name(enum transcoder transcoder) return "C"; case TRANSCODER_EDP: return "eDP"; + case TRANSCODER_DSI_A: + return "DSI A"; + case TRANSCODER_DSI_C: + return "DSI C"; default: return "<invalid>"; } } +#define IS_DSI_TRANSCODER(t) ((t) == TRANSCODER_DSI_A || (t) == TRANSCODER_DSI_C) + /* * I915_MAX_PLANES in the enum below is the maximum (across all platforms) * number of planes per CRTC. Not all platforms really have this many planes, @@ -192,6 +200,8 @@ enum intel_display_power_domain { POWER_DOMAIN_TRANSCODER_B, POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_EDP, + POWER_DOMAIN_TRANSCODER_DSI_A, + POWER_DOMAIN_TRANSCODER_DSI_C, POWER_DOMAIN_PORT_DDI_A_LANES, POWER_DOMAIN_PORT_DDI_B_LANES, POWER_DOMAIN_PORT_DDI_C_LANES, diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 91654ffc3a42..8726711864eb 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1061,6 +1061,8 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) uint32_t temp; if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) { + WARN_ON(IS_DSI_TRANSCODER(cpu_transcoder)); + temp = TRANS_MSA_SYNC_CLK; switch (intel_crtc->config->pipe_bpp) { case 18: @@ -1942,6 +1944,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi; u32 temp, flags = 0; + /* XXX: DSI transcoder paranoia */ + if (WARN_ON(IS_DSI_TRANSCODER(cpu_transcoder))) + return; + temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); if (temp & TRANS_DDI_PHSYNC) flags |= DRM_MODE_FLAG_PHSYNC; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 842467528892..f1d0a868e80c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4906,7 +4906,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_set_pipe_timings(intel_crtc); - if (intel_crtc->config->cpu_transcoder != TRANSCODER_EDP) { + if (intel_crtc->config->cpu_transcoder < TRANSCODER_EDP) { I915_WRITE(PIPE_MULT(intel_crtc->config->cpu_transcoder), intel_crtc->config->pixel_multiplier - 1); } @@ -4957,7 +4957,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) dev_priv->display.initial_watermarks(pipe_config); else intel_update_watermarks(crtc); - intel_enable_pipe(intel_crtc); + + /* XXX: Do the pipe assertions at the right place for BXT DSI. */ + if (!intel_crtc->config->has_dsi_encoder) + intel_enable_pipe(intel_crtc); if (intel_crtc->config->has_pch_encoder) lpt_pch_enable(crtc); @@ -5090,7 +5093,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); assert_vblank_disabled(crtc); - intel_disable_pipe(intel_crtc); + /* XXX: Do the pipe assertions at the right place for BXT DSI. */ + if (!intel_crtc->config->has_dsi_encoder) + intel_disable_pipe(intel_crtc); if (intel_crtc->config->dp_encoder_is_mst) intel_ddi_set_vc_payload_alloc(crtc, false); @@ -7707,7 +7712,8 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) enum pipe pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - intel_set_trans_timings(intel_crtc); + if (!IS_DSI_TRANSCODER(cpu_transcoder)) + intel_set_trans_timings(intel_crtc); /* Workaround: when the EDP input selection is B, the VTOTAL_B must be * programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is @@ -7765,9 +7771,11 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; uint32_t tmp; - intel_get_trans_timings(crtc, pipe_config); + if (!IS_DSI_TRANSCODER(cpu_transcoder)) + intel_get_trans_timings(crtc, pipe_config); tmp = I915_READ(PIPESRC(crtc->pipe)); pipe_config->pipe_src_h = (tmp & 0xffff) + 1; @@ -8776,9 +8784,11 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; u32 val; - haswell_set_transconf(crtc); + if (!IS_DSI_TRANSCODER(cpu_transcoder)) + haswell_set_transconf(crtc); I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT); POSTING_READ(GAMMA_MODE(intel_crtc->pipe)); @@ -9936,6 +9946,47 @@ static bool hsw_get_trans_config(struct intel_crtc *crtc, return tmp & PIPECONF_ENABLE; } +static bool bxt_get_dsi_trans_config(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config, + unsigned long *power_domain_mask) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum intel_display_power_domain power_domain; + enum port port; + enum transcoder cpu_transcoder; + u32 tmp; + + pipe_config->has_dsi_encoder = false; + + for_each_port_masked(port, BIT(PORT_A) | BIT(PORT_C)) { + if (port == PORT_A) + cpu_transcoder = TRANSCODER_DSI_A; + else + cpu_transcoder = TRANSCODER_DSI_C; + + power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder); + if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) + continue; + *power_domain_mask |= BIT(power_domain); + + /* XXX: this works for video mode only */ + tmp = I915_READ(BXT_MIPI_PORT_CTRL(port)); + if (!(tmp & DPI_ENABLE)) + continue; + + tmp = I915_READ(MIPI_CTRL(port)); + if ((tmp & BXT_PIPE_SELECT_MASK) != BXT_PIPE_SELECT(crtc->pipe)) + continue; + + pipe_config->cpu_transcoder = cpu_transcoder; + pipe_config->has_dsi_encoder = true; + break; + } + + return pipe_config->has_dsi_encoder; +} + static void haswell_get_ddi_port_state(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { @@ -9997,10 +10048,18 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, active = hsw_get_trans_config(crtc, pipe_config, &power_domain_mask); + if (IS_BROXTON(dev_priv)) { + bxt_get_dsi_trans_config(crtc, pipe_config, &power_domain_mask); + WARN_ON(active && pipe_config->has_dsi_encoder); + if (pipe_config->has_dsi_encoder) + active = true; + } + if (!active) goto out; - haswell_get_ddi_port_state(crtc, pipe_config); + if (!pipe_config->has_dsi_encoder) + haswell_get_ddi_port_state(crtc, pipe_config); intel_get_pipe_timings(crtc, pipe_config); @@ -10026,7 +10085,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && (I915_READ(IPS_CTL) & IPS_ENABLE); - if (pipe_config->cpu_transcoder != TRANSCODER_EDP) { + if (pipe_config->cpu_transcoder < TRANSCODER_EDP) { pipe_config->pixel_multiplier = I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1; } else { @@ -15516,10 +15575,18 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder); + enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; - /* Clear any frame start delays used for debugging left by the BIOS */ - I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); + if (!IS_DSI_TRANSCODER(cpu_transcoder)) { + i915_reg_t reg = PIPECONF(cpu_transcoder); + + /* + * Clear any frame start delays used for debugging left by the + * BIOS. + */ + I915_WRITE(reg, + I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); + } /* restore vblank interrupts to correct state */ drm_crtc_vblank_reset(&crtc->base); @@ -16195,6 +16262,7 @@ intel_display_capture_error_state(struct drm_device *dev) error->pipe[i].stat = I915_READ(PIPESTAT(i)); } + /* Note: this does not include DSI transcoders. */ error->num_transcoders = INTEL_INFO(dev)->num_pipes; if (HAS_DDI(dev_priv->dev)) error->num_transcoders++; /* Account for eDP. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02b3d22862a1..6e8c1386129e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -436,7 +436,8 @@ struct intel_crtc_state { bool has_infoframe; /* CPU Transcoder for the pipe. Currently this can only differ from the - * pipe on Haswell (where we have a special eDP transcoder). */ + * pipe on Haswell and later (where we have a special eDP transcoder) + * and Broxton (where we have special DSI transcoders). */ enum transcoder cpu_transcoder; /* diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 73c15210fdb1..47fd0296a05a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -268,6 +268,7 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) static bool intel_dsi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, base); struct intel_connector *intel_connector = intel_dsi->attached_connector; @@ -284,6 +285,14 @@ 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; + if (IS_BROXTON(dev_priv)) { + /* Dual link goes to DSI transcoder A. */ + if (intel_dsi->ports == BIT(PORT_C)) + pipe_config->cpu_transcoder = TRANSCODER_DSI_C; + else + pipe_config->cpu_transcoder = TRANSCODER_DSI_A; + } + return true; } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 2e88a5e06884..d189a0012277 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -89,6 +89,10 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "TRANSCODER_C"; case POWER_DOMAIN_TRANSCODER_EDP: return "TRANSCODER_EDP"; + case POWER_DOMAIN_TRANSCODER_DSI_A: + return "TRANSCODER_DSI_A"; + case POWER_DOMAIN_TRANSCODER_DSI_C: + return "TRANSCODER_DSI_C"; case POWER_DOMAIN_PORT_DDI_A_LANES: return "PORT_DDI_A_LANES"; case POWER_DOMAIN_PORT_DDI_B_LANES: @@ -419,6 +423,8 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ BIT(POWER_DOMAIN_PIPE_A) | \ BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ + BIT(POWER_DOMAIN_TRANSCODER_DSI_A) | \ + BIT(POWER_DOMAIN_TRANSCODER_DSI_C) | \ BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ BIT(POWER_DOMAIN_PORT_DSI) | \
The BXT display connections have DSI transcoders A and C that can be muxed to any pipe, not unlike the eDP transcoder. Add the notion of DSI transcoders. The "normal" transcoders A, B and C are not used with BXT DSI, so care must be taken to avoid accessing those registers with DSI transcoders in the hardware state readout, modeset, and generally everywhere. Signed-off-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 10 ++++ drivers/gpu/drm/i915/intel_ddi.c | 6 +++ drivers/gpu/drm/i915/intel_display.c | 90 +++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_dsi.c | 9 ++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 6 +++ 6 files changed, 112 insertions(+), 12 deletions(-)