drm/amd/display: Update ONO PG Workaround for DCN42

[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 <ovidiu.bunea@amd.com>
Signed-off-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: George Zhang <george.zhang@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Leo Chen
2026-06-09 18:38:23 -04:00
committed by Alex Deucher
parent 1f8722455e
commit 3754bdca43
5 changed files with 99 additions and 40 deletions

View File

@@ -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(

View File

@@ -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,

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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 {