From: Leo Chen <[email protected]> [Why & How] There is an updated workaround for PG Repeater issue in DCN42. This PR is addressing the dynamic power gating use cases (Driver PG) to align with the new sequence.
Reviewed-by: Ovidiu (Ovi) Bunea <[email protected]> Signed-off-by: Leo Chen <[email protected]> Signed-off-by: George Zhang <[email protected]> --- .../amd/display/dc/dccg/dcn42/dcn42_dccg.c | 18 +++- .../amd/display/dc/dccg/dcn42/dcn42_dccg.h | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 1 + .../amd/display/dc/pg/dcn42/dcn42_pg_cntl.c | 97 +++++++++++++------ .../amd/display/dc/pg/dcn42/dcn42_pg_cntl.h | 22 ++++- 5 files changed, 99 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c index 6cbc1f4ef411..616a896f0782 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c @@ -77,7 +77,7 @@ void dccg42_otg_drop_pixel(struct dccg *dccg, } } -void dccg42_enable_global_fgcg(struct dccg *dccg, bool value) +void dccg42_enable_global_fgcg(struct dccg *dccg, bool enable) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -85,9 +85,18 @@ void dccg42_enable_global_fgcg(struct dccg *dccg, bool value) * Fine grain control via bit2 of debug flag. */ if (dccg->ctx->dc->debug.disable_clock_gate || (dccg->ctx->dc->debug.iommu_mismatch_temp_wka & 0x4)) - value = false; + enable = false; - REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !value); + REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !enable); +} + +bool dccg42_get_global_fgcg_status(struct dccg *dccg) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + uint32_t disabled = 0; + + REG_GET(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, &disabled); + return disabled & 0x1; } void dccg42_set_physymclk( @@ -339,7 +348,8 @@ static const struct dccg_funcs dccg42_funcs = { .dccg_root_gate_disable_control = dccg35_root_gate_disable_control, .dccg_read_reg_state = dccg31_read_reg_state, .dccg_enable_global_fgcg = dccg42_enable_global_fgcg, - .allow_clock_gating = dccg2_allow_clock_gating + .allow_clock_gating = dccg2_allow_clock_gating, + .dccg_get_global_fgcg_status = dccg42_get_global_fgcg_status, }; struct dccg *dccg42_create( diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h index a2b17ed11bdb..ebd3cec1a977 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h @@ -247,6 +247,7 @@ void dccg42_otg_add_pixel(struct dccg *dccg, void dccg42_otg_drop_pixel(struct dccg *dccg, uint32_t otg_inst); void dccg42_enable_global_fgcg(struct dccg *dccg, bool value); +bool dccg42_get_global_fgcg_status(struct dccg *dccg); void dccg42_set_physymclk( struct dccg *dccg, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 6db7c8753081..e756719308ab 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -348,6 +348,7 @@ struct dccg_funcs { void (*dccg_root_gate_disable_control)(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating); void (*dccg_read_reg_state)(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_reg_state); void (*dccg_enable_global_fgcg)(struct dccg *dccg, bool enable); + bool (*dccg_get_global_fgcg_status)(struct dccg *dccg); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c index 729c2b653161..94361e326c56 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c @@ -22,6 +22,45 @@ #define DC_LOGGER \ pg_cntl->ctx->logger +/* + * ONO PG Workoaround: Saved FGCG repeaters states captured before powering up an ONO + * domain so it can be restored once the domain is powered up. + */ +struct dcn42_global_fgcg_rep_state { + uint32_t dmu_rep_fgcg; + uint32_t dccg_global_ono_rep_fgcg; + uint32_t az_rep_fgcg; +}; + +/* Save and disable FGCG repeaters before powering up the ONO domain. */ +static void pg_cntl42_save_and_disable_global_fgcg_rep(struct pg_cntl *pg_cntl, + struct dcn42_global_fgcg_rep_state *state) +{ + struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); + + REG_GET(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, &state->dmu_rep_fgcg); + if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_get_global_fgcg_status) + state->dccg_global_ono_rep_fgcg = pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_get_global_fgcg_status(pg_cntl->ctx->dc->res_pool->dccg); + REG_GET(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, &state->az_rep_fgcg); + + REG_UPDATE(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, 1); + if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) + pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); + REG_UPDATE(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, 1); +} + +/* Restore FGCG repeaters after the ONO domains are powered up. */ +static void pg_cntl42_restore_global_fgcg_rep(struct pg_cntl *pg_cntl, + struct dcn42_global_fgcg_rep_state *state) +{ + struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); + + REG_UPDATE(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, state->dmu_rep_fgcg); + if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) + pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, state->dccg_global_ono_rep_fgcg); + REG_UPDATE(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, state->az_rep_fgcg); +} + static bool pg_cntl42_dsc_pg_status(struct pg_cntl *pg_cntl, unsigned int dsc_inst) { struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); @@ -54,6 +93,7 @@ void pg_cntl42_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl = 0; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; bool block_enabled; /*need to enable dscclk regardless DSC_PG*/ @@ -81,10 +121,9 @@ void pg_cntl42_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + switch (dsc_inst) { case 0: /* DSC0 */ REG_UPDATE(DOMAIN16_PG_CONFIG, @@ -123,10 +162,8 @@ void pg_cntl42_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo break; } - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); if (dsc_inst < MAX_PIPES) pg_cntl->pg_pipe_res_enable[PG_DSC][dsc_inst] = power_on; @@ -174,6 +211,7 @@ void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; bool block_enabled; bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || pg_cntl->ctx->dc->debug.disable_hubp_power_gate || @@ -196,10 +234,8 @@ void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); switch (hubp_dpp_inst) { case 0: @@ -227,10 +263,9 @@ void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp break; } - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + DC_LOG_DEBUG("HUBP DPP instance %d, power %s", hubp_dpp_inst, power_on ? "ON" : "OFF"); @@ -258,6 +293,7 @@ void pg_cntl42_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; uint32_t power_forceon; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; bool block_enabled; bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || @@ -282,17 +318,15 @@ void pg_cntl42_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + REG_UPDATE(DOMAIN25_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); REG_WAIT(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + pg_cntl->pg_res_enable[PG_HPO] = power_on; } @@ -466,6 +500,7 @@ void pg_cntl42_dio_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; bool block_enabled; bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || @@ -486,18 +521,16 @@ void pg_cntl42_dio_pg_control(struct pg_cntl *pg_cntl, bool power_on) REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + /* DIO */ REG_UPDATE(DOMAIN26_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); REG_WAIT(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + pg_cntl->pg_res_enable[PG_DIO] = power_on; } diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h index 7e8f4f03ae0e..813fa5c81172 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h @@ -34,7 +34,9 @@ SR(DOMAIN24_PG_STATUS), \ SR(DOMAIN25_PG_STATUS), \ SR(DOMAIN26_PG_STATUS), \ - SR(DC_IP_REQUEST_CNTL) + SR(DC_IP_REQUEST_CNTL), \ + SR(DMU_CLK_CNTL), \ + SR(AZ_CLOCK_CNTL) #define PG_CNTL_REG_LIST_DCN42B()\ SR(DOMAIN0_PG_CONFIG), \ @@ -63,7 +65,9 @@ SR(DOMAIN24_PG_STATUS), \ SR(DOMAIN25_PG_STATUS), \ SR(DOMAIN26_PG_STATUS), \ - SR(DC_IP_REQUEST_CNTL) + SR(DC_IP_REQUEST_CNTL), \ + SR(DMU_CLK_CNTL), \ + SR(AZ_CLOCK_CNTL) #define PG_CNTL_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -121,7 +125,9 @@ PG_CNTL_SF(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_DESIRED_PWR_STATE, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) + PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + PG_CNTL_SF(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh), \ + PG_CNTL_SF(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, mask_sh) /* Not in DCN42B: * PG_CNTL_SF(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), @@ -178,7 +184,9 @@ PG_CNTL_SF(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_DESIRED_PWR_STATE, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) + PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + PG_CNTL_SF(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh), \ + PG_CNTL_SF(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, mask_sh) struct pg_cntl_shift { uint8_t IP_REQUEST_EN; @@ -186,6 +194,8 @@ struct pg_cntl_shift { uint8_t DOMAIN_POWER_GATE; uint8_t DOMAIN_DESIRED_PWR_STATE; uint8_t DOMAIN_PGFSM_PWR_STATUS; + uint8_t LONO_FGCG_REP_DIS; + uint8_t AZ_GLOBAL_FGCG_REP_DIS; }; struct pg_cntl_mask { uint32_t IP_REQUEST_EN; @@ -193,6 +203,8 @@ struct pg_cntl_mask { uint32_t DOMAIN_POWER_GATE; uint32_t DOMAIN_DESIRED_PWR_STATE; uint32_t DOMAIN_PGFSM_PWR_STATUS; + uint32_t LONO_FGCG_REP_DIS; + uint32_t AZ_GLOBAL_FGCG_REP_DIS; }; struct pg_cntl_registers { @@ -224,6 +236,8 @@ struct pg_cntl_registers { uint32_t DOMAIN24_PG_STATUS; uint32_t DOMAIN25_PG_STATUS; uint32_t DOMAIN26_PG_STATUS; + uint32_t DMU_CLK_CNTL; + uint32_t AZ_CLOCK_CNTL; }; struct dcn_pg_cntl { -- 2.54.0
