From 028a998c62f72cb879d44809cb96acdcc47d6137 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Thu, 9 Sep 2021 16:33:52 -0400 Subject: drm/amd/display: Defer LUT memory powerdown until LUT bypass latches [WHY] Blnd, 3dlut, and shaper LUT select registers are double buffered, however their accompanying LUT memory shutdown registers are not. As a result, shutting down LUT memory immediately after setting a block to bypass causes corruption as bypass only happens at next Vupdate. [HOW] Re-enable mem low power for CM block Force optimization on next flip and disable LUT memory during optimization sequence if LUT select field is then set to bypass v2: squash in CONFIG_DRM_AMD_DC_DCN fix (Alex) Reviewed-by: Eric Yang Acked-by: Anson Jacob Signed-off-by: Michael Strauss Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 21 ++++++++ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c | 59 +++++++++++++++++++--- .../gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 +- drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 12 +++++ 4 files changed, 87 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 644005846433..b113e7e74ded 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1793,6 +1793,25 @@ static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context) return false; } +/* Perform updates here which need to be deferred until next vupdate + * + * i.e. blnd lut, 3dlut, and shaper lut bypass regs are double buffered + * but forcing lut memory to shutdown state is immediate. This causes + * single frame corruption as lut gets disabled mid-frame unless shutdown + * is deferred until after entering bypass. + */ +static void process_deferred_updates(struct dc *dc) +{ +#ifdef CONFIG_DRM_AMD_DC_DCN + int i; + + if (dc->debug.enable_mem_low_power.bits.cm) + for (i = 0; i < dc->dcn_ip->max_num_dpp; i++) + if (dc->res_pool->dpps[i]->funcs->dpp_deferred_update) + dc->res_pool->dpps[i]->funcs->dpp_deferred_update(dc->res_pool->dpps[i]); +#endif +} + void dc_post_update_surfaces_to_stream(struct dc *dc) { int i; @@ -1818,6 +1837,8 @@ void dc_post_update_surfaces_to_stream(struct dc *dc) dc->hwss.disable_plane(dc, &context->res_ctx.pipe_ctx[i]); } + process_deferred_updates(dc); + dc->hwss.optimize_bandwidth(dc, context); dc->optimized_required = false; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c index 23a52d47e61c..ef5f6da5248a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c @@ -488,6 +488,40 @@ void dpp3_cnv_set_bias_scale( REG_UPDATE(FCNV_FP_SCALE_B, FCNV_FP_SCALE_B, bias_and_scale->scale_blue); } +void dpp3_deferred_update( + struct dpp *dpp_base) +{ + int bypass_state; + struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); + + if (dpp_base->deferred_reg_writes.bits.disable_blnd_lut) { + REG_GET(CM_BLNDGAM_CONTROL, CM_BLNDGAM_MODE_CURRENT, &bypass_state); + if (bypass_state == 0) { // only program if bypass was latched + REG_UPDATE(CM_MEM_PWR_CTRL, BLNDGAM_MEM_PWR_FORCE, 3); + } else + ASSERT(0); // LUT select was updated again before vupdate + dpp_base->deferred_reg_writes.bits.disable_blnd_lut = false; + } + + if (dpp_base->deferred_reg_writes.bits.disable_3dlut) { + REG_GET(CM_3DLUT_MODE, CM_3DLUT_MODE_CURRENT, &bypass_state); + if (bypass_state == 0) { // only program if bypass was latched + REG_UPDATE(CM_MEM_PWR_CTRL2, HDR3DLUT_MEM_PWR_FORCE, 3); + } else + ASSERT(0); // LUT select was updated again before vupdate + dpp_base->deferred_reg_writes.bits.disable_3dlut = false; + } + + if (dpp_base->deferred_reg_writes.bits.disable_shaper) { + REG_GET(CM_SHAPER_CONTROL, CM_SHAPER_MODE_CURRENT, &bypass_state); + if (bypass_state == 0) { // only program if bypass was latched + REG_UPDATE(CM_MEM_PWR_CTRL2, SHAPER_MEM_PWR_FORCE, 3); + } else + ASSERT(0); // LUT select was updated again before vupdate + dpp_base->deferred_reg_writes.bits.disable_shaper = false; + } +} + static void dpp3_power_on_blnd_lut( struct dpp *dpp_base, bool power_on) @@ -495,9 +529,13 @@ static void dpp3_power_on_blnd_lut( struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.cm) { - REG_UPDATE(CM_MEM_PWR_CTRL, BLNDGAM_MEM_PWR_FORCE, power_on ? 0 : 3); - if (power_on) + if (power_on) { + REG_UPDATE(CM_MEM_PWR_CTRL, BLNDGAM_MEM_PWR_FORCE, 0); REG_WAIT(CM_MEM_PWR_STATUS, BLNDGAM_MEM_PWR_STATE, 0, 1, 5); + } else { + dpp_base->ctx->dc->optimized_required = true; + dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; + } } else { REG_SET(CM_MEM_PWR_CTRL, 0, BLNDGAM_MEM_PWR_FORCE, power_on == true ? 0 : 1); @@ -511,9 +549,13 @@ static void dpp3_power_on_hdr3dlut( struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.cm) { - REG_UPDATE(CM_MEM_PWR_CTRL2, HDR3DLUT_MEM_PWR_FORCE, power_on ? 0 : 3); - if (power_on) + if (power_on) { + REG_UPDATE(CM_MEM_PWR_CTRL2, HDR3DLUT_MEM_PWR_FORCE, 0); REG_WAIT(CM_MEM_PWR_STATUS2, HDR3DLUT_MEM_PWR_STATE, 0, 1, 5); + } else { + dpp_base->ctx->dc->optimized_required = true; + dpp_base->deferred_reg_writes.bits.disable_3dlut = true; + } } } @@ -524,9 +566,13 @@ static void dpp3_power_on_shaper( struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.cm) { - REG_UPDATE(CM_MEM_PWR_CTRL2, SHAPER_MEM_PWR_FORCE, power_on ? 0 : 3); - if (power_on) + if (power_on) { + REG_UPDATE(CM_MEM_PWR_CTRL2, SHAPER_MEM_PWR_FORCE, 0); REG_WAIT(CM_MEM_PWR_STATUS2, SHAPER_MEM_PWR_STATE, 0, 1, 5); + } else { + dpp_base->ctx->dc->optimized_required = true; + dpp_base->deferred_reg_writes.bits.disable_shaper = true; + } } } @@ -1400,6 +1446,7 @@ static struct dpp_funcs dcn30_dpp_funcs = { .dpp_program_blnd_lut = dpp3_program_blnd_lut, .dpp_program_shaper_lut = dpp3_program_shaper, .dpp_program_3dlut = dpp3_program_3dlut, + .dpp_deferred_update = dpp3_deferred_update, .dpp_program_bias_and_scale = NULL, .dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer, .set_cursor_attributes = dpp3_set_cursor_attributes, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 6f0c788d1904..613d34bde7dd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1013,7 +1013,7 @@ static const struct dc_debug_options debug_defaults_drv = { .i2c = true, .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled .dscl = true, - .cm = false, // visible flicker on OLED eDPs + .cm = true, .mpc = true, .optc = true, .vpg = true, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 00fc81431b43..9f12792b7e59 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -29,6 +29,15 @@ #include "transform.h" +union defer_reg_writes { + struct { + bool disable_blnd_lut:1; + bool disable_3dlut:1; + bool disable_shaper:1; + } bits; + uint32_t raw; +}; + struct dpp { const struct dpp_funcs *funcs; struct dc_context *ctx; @@ -43,6 +52,7 @@ struct dpp { struct pwl_params regamma_params; struct pwl_params degamma_params; struct dpp_cursor_attributes cur_attr; + union defer_reg_writes deferred_reg_writes; struct pwl_params shaper_params; bool cm_bypass_mode; @@ -245,6 +255,8 @@ struct dpp_funcs { bool dppclk_div, bool enable); + void (*dpp_deferred_update)( + struct dpp *dpp); bool (*dpp_program_blnd_lut)( struct dpp *dpp, const struct pwl_params *params); -- cgit v1.2.3