When the clock is higher than the dotclock, try with 2 pipes enabled. If we can enable 2, then we will go into big joiner mode, and steal the adjacent crtc. This only links the crtc's in software, no hardware or plane programming is done yet. Blobs are also copied from the master's crtc_state, so it doesn't depend at commit time on the other crtc_state. Changes since v1: - Rename pipe timings to transcoder timings, as they are now different. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/display/intel_atomic.c | 15 +- drivers/gpu/drm/i915/display/intel_atomic.h | 3 +- drivers/gpu/drm/i915/display/intel_display.c | 218 ++++++++++++++++-- .../drm/i915/display/intel_display_types.h | 11 +- drivers/gpu/drm/i915/display/intel_dp.c | 25 +- 5 files changed, 234 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 4783d7ff4fcf..a5b11bd9da68 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -228,25 +228,26 @@ void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state) intel_crtc_put_color_blobs(crtc_state); } -void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state) +void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state, + const struct intel_crtc_state *from_crtc_state) { intel_crtc_put_color_blobs(crtc_state); - if (crtc_state->uapi.degamma_lut) + if (from_crtc_state->uapi.degamma_lut) crtc_state->hw.degamma_lut = - drm_property_blob_get(crtc_state->uapi.degamma_lut); + drm_property_blob_get(from_crtc_state->uapi.degamma_lut); else crtc_state->hw.degamma_lut = NULL; - if (crtc_state->uapi.gamma_lut) + if (from_crtc_state->uapi.gamma_lut) crtc_state->hw.gamma_lut = - drm_property_blob_get(crtc_state->uapi.gamma_lut); + drm_property_blob_get(from_crtc_state->uapi.gamma_lut); else crtc_state->hw.gamma_lut = NULL; - if (crtc_state->uapi.ctm) + if (from_crtc_state->uapi.ctm) crtc_state->hw.ctm = - drm_property_blob_get(crtc_state->uapi.ctm); + drm_property_blob_get(from_crtc_state->uapi.ctm); else crtc_state->hw.ctm = NULL; } diff --git a/drivers/gpu/drm/i915/display/intel_atomic.h b/drivers/gpu/drm/i915/display/intel_atomic.h index 42be91e0772a..8da84d64aa04 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.h +++ b/drivers/gpu/drm/i915/display/intel_atomic.h @@ -36,7 +36,8 @@ struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc); void intel_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state); -void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state); +void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state, + const struct intel_crtc_state *from_crtc_state); struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); void intel_atomic_state_clear(struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index caab8cfddcbd..c2b3c7b6f39b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -123,7 +123,7 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc, static int intel_framebuffer_init(struct intel_framebuffer *ifb, struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd); -static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state); +static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state); static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state); static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state, const struct intel_link_m_n *m_n, @@ -6308,7 +6308,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config, if (intel_crtc_has_dp_encoder(pipe_config)) intel_dp_set_m_n(pipe_config, M1_N1); - intel_set_pipe_timings(pipe_config); + intel_set_transcoder_timings(pipe_config); intel_set_pipe_src_size(pipe_config); if (pipe_config->has_pch_encoder) { @@ -6435,7 +6435,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, intel_dp_set_m_n(pipe_config, M1_N1); if (!transcoder_is_dsi(cpu_transcoder)) - intel_set_pipe_timings(pipe_config); + intel_set_transcoder_timings(pipe_config); intel_set_pipe_src_size(pipe_config); @@ -6838,7 +6838,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config, if (intel_crtc_has_dp_encoder(pipe_config)) intel_dp_set_m_n(pipe_config, M1_N1); - intel_set_pipe_timings(pipe_config); + intel_set_transcoder_timings(pipe_config); intel_set_pipe_src_size(pipe_config); if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) { @@ -6906,7 +6906,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config, if (intel_crtc_has_dp_encoder(pipe_config)) intel_dp_set_m_n(pipe_config, M1_N1); - intel_set_pipe_timings(pipe_config); + intel_set_transcoder_timings(pipe_config); intel_set_pipe_src_size(pipe_config); i9xx_set_pipeconf(pipe_config); @@ -7396,7 +7396,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; + struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; int clock_limit = dev_priv->max_dotclk_freq; if (INTEL_GEN(dev_priv) < 4) { @@ -7413,6 +7413,25 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, } } + /* + * copy hw mode to transcoder mode. + * This matters mostly for big joiner, which splits the mode in half. + */ + pipe_config->hw.transcoder_mode = pipe_config->hw.adjusted_mode; + if (pipe_config->bigjoiner) { + /* Make sure the crtc config is halved horizontally */ + adjusted_mode->crtc_clock /= 2; + adjusted_mode->crtc_hdisplay /= 2; + adjusted_mode->crtc_hblank_start /= 2; + adjusted_mode->crtc_hblank_end /= 2; + adjusted_mode->crtc_hsync_start /= 2; + adjusted_mode->crtc_hsync_end /= 2; + adjusted_mode->crtc_htotal /= 2; + adjusted_mode->crtc_hskew /= 2; + + pipe_config->pipe_src_w /= 2; + } + if (adjusted_mode->crtc_clock > clock_limit) { DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n", adjusted_mode->crtc_clock, clock_limit, @@ -8114,13 +8133,13 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc, crtc_state->dpll_hw_state.dpll = dpll; } -static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state) +static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.transcoder_mode; u32 crtc_vtotal, crtc_vblank_end; int vsyncshift = 0; @@ -8205,8 +8224,8 @@ static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state) return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK; } -static void intel_get_pipe_timings(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) +static void intel_get_transcoder_timings(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); @@ -8809,7 +8828,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, if (INTEL_GEN(dev_priv) < 4) pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE; - intel_get_pipe_timings(crtc, pipe_config); + intel_get_transcoder_timings(crtc, pipe_config); intel_get_pipe_src_size(crtc, pipe_config); i9xx_get_pfit_config(crtc, pipe_config); @@ -10045,7 +10064,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, pipe_config->pixel_multiplier = 1; } - intel_get_pipe_timings(crtc, pipe_config); + intel_get_transcoder_timings(crtc, pipe_config); intel_get_pipe_src_size(crtc, pipe_config); ironlake_get_pfit_config(crtc, pipe_config); @@ -10445,7 +10464,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, if (!transcoder_is_dsi(pipe_config->cpu_transcoder) || INTEL_GEN(dev_priv) >= 11) { haswell_get_ddi_port_state(crtc, pipe_config); - intel_get_pipe_timings(crtc, pipe_config); + intel_get_transcoder_timings(crtc, pipe_config); } intel_get_pipe_src_size(crtc, pipe_config); @@ -11814,6 +11833,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, if (mode_changed && crtc_state->hw.enable && dev_priv->display.crtc_compute_clock && + !crtc_state->bigjoiner_slave && !WARN_ON(crtc_state->shared_dpll)) { ret = dev_priv->display.crtc_compute_clock(crtc, crtc_state); if (ret) @@ -12278,7 +12298,7 @@ static void copy_uapi_to_hw_state(struct intel_crtc_state *crtc_state) crtc_state->hw.active = crtc_state->uapi.active; crtc_state->hw.mode = crtc_state->uapi.mode; crtc_state->hw.adjusted_mode = crtc_state->uapi.adjusted_mode; - intel_crtc_copy_color_blobs(crtc_state); + intel_crtc_copy_color_blobs(crtc_state, crtc_state); } static void copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state) @@ -12286,7 +12306,48 @@ static void copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state) crtc_state->uapi.enable = crtc_state->hw.enable; crtc_state->uapi.active = crtc_state->hw.active; crtc_state->uapi.mode = crtc_state->hw.mode; - crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode; + crtc_state->uapi.adjusted_mode = crtc_state->hw.transcoder_mode; +} + +static int +copy_bigjoiner_crtc_state(struct intel_crtc_state *crtc_state, + const struct intel_crtc_state *from_crtc_state) +{ + struct intel_crtc_state *saved_state; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + saved_state = kmemdup(from_crtc_state, sizeof(*saved_state), GFP_KERNEL); + if (!saved_state) + return -ENOMEM; + + saved_state->uapi = crtc_state->uapi; + saved_state->scaler_state = crtc_state->scaler_state; + saved_state->shared_dpll = crtc_state->shared_dpll; + saved_state->dpll_hw_state = crtc_state->dpll_hw_state; + saved_state->crc_enabled = crtc_state->crc_enabled; + + intel_crtc_free_hw_state(crtc_state); + memcpy(crtc_state, saved_state, sizeof(*crtc_state)); + kfree(saved_state); + + /* Re-init hw state */ + memset(&crtc_state->hw, 0, sizeof(saved_state->hw)); + crtc_state->hw.enable = from_crtc_state->hw.enable; + crtc_state->hw.active = from_crtc_state->hw.active; + crtc_state->hw.mode = from_crtc_state->hw.mode; + crtc_state->hw.adjusted_mode = from_crtc_state->hw.adjusted_mode; + + /* Some fixups */ + crtc_state->uapi.mode_changed = from_crtc_state->uapi.mode_changed; + crtc_state->uapi.connectors_changed = from_crtc_state->uapi.connectors_changed; + crtc_state->uapi.active_changed = from_crtc_state->uapi.active_changed; + crtc_state->nv12_planes = crtc_state->c8_planes = crtc_state->update_planes = 0; + crtc_state->bigjoiner_linked_crtc = to_intel_crtc(from_crtc_state->uapi.crtc); + crtc_state->bigjoiner_slave = true; + crtc_state->cpu_transcoder = (enum transcoder)crtc->pipe; + crtc_state->has_audio = false; + + return 0; } static int @@ -12459,7 +12520,7 @@ intel_modeset_pipe_config(struct intel_crtc_state *pipe_config) base_bpp, pipe_config->pipe_bpp, pipe_config->dither); /* uapi wants a copy of the adjusted_mode for vblank bookkeeping */ - pipe_config->uapi.adjusted_mode = pipe_config->hw.adjusted_mode; + pipe_config->uapi.adjusted_mode = pipe_config->hw.transcoder_mode; return 0; } @@ -13612,6 +13673,109 @@ static int intel_atomic_check_crtcs(struct intel_atomic_state *state) return 0; } +static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_crtc_state *old_crtc_state, *new_crtc_state, *slave_crtc_state, *master_crtc_state; + struct intel_crtc *crtc, *slave, *master; + int i, ret = 0; + + if (INTEL_GEN(dev_priv) < 11) + return 0; + + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, + new_crtc_state, i) { + if (!old_crtc_state->bigjoiner_slave) + continue; + + if (crtc->pipe == PIPE_A) { + DRM_ERROR("Bigjoiner slave on pipe A?\n"); + return -EINVAL; + } + + /* crtc staying in slave mode? */ + if (!new_crtc_state->uapi.enable) + continue; + + if (needs_modeset(new_crtc_state) || new_crtc_state->update_pipe) { + master = old_crtc_state->bigjoiner_linked_crtc; + master_crtc_state = intel_atomic_get_crtc_state(&state->base, master); + if (IS_ERR(master_crtc_state)) + return PTR_ERR(master_crtc_state); + + /* + * Force modeset on master, to recalculate bigjoiner + * state. + * + * If master_crtc_state was not part of the atomic commit, + * we will fail because the master was not deconfigured, + * but at least fail below to unify the checks. + */ + master_crtc_state->uapi.mode_changed = true; + + ret = drm_atomic_add_affected_planes(&state->base, &crtc->base); + if (ret) + return ret; + + ret = drm_atomic_add_affected_connectors(&state->base, &crtc->base); + if (ret) + return ret; + } + } + + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, + new_crtc_state, i) { + if (!new_crtc_state->uapi.enable || !new_crtc_state->bigjoiner) { + if (!old_crtc_state->bigjoiner) + continue; + } + + if (!needs_modeset(new_crtc_state) && !new_crtc_state->update_pipe) + continue; + + if (new_crtc_state->bigjoiner && !new_crtc_state->bigjoiner_slave) { + if (1 + crtc->pipe >= INTEL_NUM_PIPES(dev_priv)) { + DRM_DEBUG_KMS("Big joiner configuration requires CRTC + 1 to be used, doesn't exist\n"); + return -EINVAL; + } + + slave = new_crtc_state->bigjoiner_linked_crtc = + intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1); + slave_crtc_state = intel_atomic_get_crtc_state(&state->base, slave); + if (IS_ERR(slave_crtc_state)) + return PTR_ERR(slave_crtc_state); + + if (slave_crtc_state->uapi.enable) { + DRM_DEBUG_KMS("[CRTC:%d:%s] Big joiner configuration requires this CRTC to be unconfigured\n", + slave->base.base.id, slave->base.name); + return -EINVAL; + } else { + DRM_DEBUG_KMS("[CRTC:%d:%s] Used as slave for big joiner\n", + slave->base.base.id, slave->base.name); + ret = copy_bigjoiner_crtc_state(slave_crtc_state, new_crtc_state); + } + } else { + master = new_crtc_state->bigjoiner_linked_crtc; + if (!master) + continue; + + master_crtc_state = intel_atomic_get_crtc_state(&state->base, master); + if (IS_ERR(master_crtc_state)) + return PTR_ERR(master_crtc_state); + + if (!master_crtc_state->uapi.enable && !new_crtc_state->uapi.enable) { + DRM_DEBUG_KMS("[CRTC:%d:%s] Disabling slave from big joiner\n", + crtc->base.base.id, crtc->base.name); + ret = clear_intel_crtc_state(new_crtc_state); + } + } + if (ret) + return ret; + } + + return 0; +} + /** * intel_atomic_check - validate state object * @dev: drm device @@ -13642,16 +13806,19 @@ static int intel_atomic_check(struct drm_device *dev, for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (!needs_modeset(new_crtc_state)) { - if (new_crtc_state->uapi.color_mgmt_changed) - intel_crtc_copy_color_blobs(new_crtc_state); + if (new_crtc_state->uapi.color_mgmt_changed && + !new_crtc_state->bigjoiner_slave) + intel_crtc_copy_color_blobs(new_crtc_state, new_crtc_state); continue; } if (!new_crtc_state->uapi.enable) { any_ms = true; - intel_crtc_free_hw_state(new_crtc_state); - memset(&new_crtc_state->hw, 0, - sizeof(new_crtc_state->hw)); + if (!new_crtc_state->bigjoiner_slave) { + intel_crtc_free_hw_state(new_crtc_state); + memset(&new_crtc_state->hw, 0, + sizeof(new_crtc_state->hw)); + } continue; } @@ -13665,6 +13832,10 @@ static int intel_atomic_check(struct drm_device *dev, any_ms = true; } + ret = intel_atomic_check_bigjoiner(state); + if (ret) + return ret; + ret = drm_dp_mst_atomic_check(&state->base); if (ret) goto fail; @@ -13860,7 +14031,9 @@ static void intel_update_crtc(struct intel_crtc *crtc, commit_pipe_config(state, old_crtc_state, new_crtc_state); - if (INTEL_GEN(dev_priv) >= 9) + if (new_crtc_state->bigjoiner) + {/* Not supported yet */} + else if (INTEL_GEN(dev_priv) >= 9) skl_update_planes_on_crtc(state, crtc); else i9xx_update_planes_on_crtc(state, crtc); @@ -16915,7 +17088,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) } intel_bw_crtc_update(bw_state, crtc_state); - copy_hw_to_uapi_state(crtc_state); intel_pipe_config_sanity_check(dev_priv, crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 67644818efd2..6ce823943a69 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -791,7 +791,7 @@ struct intel_crtc_state { struct { bool active, enable; struct drm_property_blob *degamma_lut, *gamma_lut, *ctm; - struct drm_display_mode mode, adjusted_mode; + struct drm_display_mode mode, adjusted_mode, transcoder_mode; } hw; /** @@ -1022,6 +1022,15 @@ struct intel_crtc_state { /* enable pipe csc? */ bool csc_enable; + /* enable pipe big joiner? */ + bool bigjoiner; + + /* big joiner slave crtc? */ + bool bigjoiner_slave; + + /* linked crtc for bigjoiner, either slave or master */ + struct intel_crtc *bigjoiner_linked_crtc; + /* Display Stream compression state */ struct { bool compression_enable; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 5c7323af08b3..637ee7d0656a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2106,6 +2106,19 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->port_clock = intel_dp->common_rates[limits->max_clock]; pipe_config->lane_count = limits->max_lane_count; + if (adjusted_mode->crtc_clock > intel_dp_downstream_max_dotclock(intel_dp, false)) { + if (adjusted_mode->crtc_clock > intel_dp_downstream_max_dotclock(intel_dp, true)) { + DRM_DEBUG_KMS("Clock rate too high for big joiner\n"); + return -EINVAL; + } + if (intel_dp_is_edp(intel_dp)) { + DRM_DEBUG_KMS("Cannot split eDP stream in bigjoiner configuration.\n"); + return -EINVAL; + } + pipe_config->bigjoiner = true; + DRM_DEBUG_KMS("Using bigjoiner configuration\n"); + } + if (intel_dp_is_edp(intel_dp)) { pipe_config->dsc_params.compressed_bpp = min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4, @@ -2123,12 +2136,12 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->lane_count, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, - false); + pipe_config->bigjoiner); dsc_dp_slice_count = intel_dp_dsc_get_slice_count(intel_dp, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, - false); + pipe_config->bigjoiner); if (!dsc_max_output_bpp || !dsc_dp_slice_count) { DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n"); return -EINVAL; @@ -2143,13 +2156,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, * is greater than the maximum Cdclock and if slice count is even * then we need to use 2 VDSC instances. */ - if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) { - if (pipe_config->dsc_params.slice_count > 1) { - pipe_config->dsc_params.dsc_split = true; - } else { + if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq || pipe_config->bigjoiner) { + if (pipe_config->dsc_params.slice_count < 2) { DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n"); return -EINVAL; } + + pipe_config->dsc_params.dsc_split = true; } ret = intel_dp_compute_dsc_params(intel_dp, pipe_config); -- 2.23.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx