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 <[email protected]>
> ---
>  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

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to