Commit 3ba43a59 authored by Charlene Liu's avatar Charlene Liu Committed by Alex Deucher

drm/amd/display: underflow/blankscreen recovery

[Description]
for any reason, if driver detects HUBP underflow,
if a debug option enabled to enable recovery.
it will kick in a sequence of recovery.
Signed-off-by: default avatarCharlene Liu <charlene.liu@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Acked-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0002d3ac
...@@ -239,6 +239,8 @@ struct dc_debug { ...@@ -239,6 +239,8 @@ struct dc_debug {
bool az_endpoint_mute_only; bool az_endpoint_mute_only;
bool always_use_regamma; bool always_use_regamma;
bool p010_mpo_support; bool p010_mpo_support;
bool recovery_enabled;
}; };
struct dc_state; struct dc_state;
struct resource_pool; struct resource_pool;
......
...@@ -476,6 +476,14 @@ void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub) ...@@ -476,6 +476,14 @@ void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req); DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req);
} }
void hubbub1_soft_reset(struct hubbub *hubbub, bool reset)
{
uint32_t reset_en = reset ? 1 : 0;
REG_UPDATE(DCHUBBUB_SOFT_RESET,
DCHUBBUB_GLOBAL_SOFT_RESET, reset_en);
}
static bool hubbub1_dcc_support_swizzle( static bool hubbub1_dcc_support_swizzle(
enum swizzle_mode_values swizzle, enum swizzle_mode_values swizzle,
unsigned int bytes_per_element, unsigned int bytes_per_element,
......
...@@ -48,7 +48,8 @@ ...@@ -48,7 +48,8 @@
SR(DCHUBBUB_ARB_DF_REQ_OUTSTAND),\ SR(DCHUBBUB_ARB_DF_REQ_OUTSTAND),\
SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \
SR(DCHUBBUB_TEST_DEBUG_INDEX), \ SR(DCHUBBUB_TEST_DEBUG_INDEX), \
SR(DCHUBBUB_TEST_DEBUG_DATA) SR(DCHUBBUB_TEST_DEBUG_DATA),\
SR(DCHUBBUB_SOFT_RESET)
#define HUBBUB_SR_WATERMARK_REG_LIST()\ #define HUBBUB_SR_WATERMARK_REG_LIST()\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A),\ SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A),\
...@@ -105,6 +106,7 @@ struct dcn_hubbub_registers { ...@@ -105,6 +106,7 @@ struct dcn_hubbub_registers {
uint32_t DCHUBBUB_SDPIF_AGP_BOT; uint32_t DCHUBBUB_SDPIF_AGP_BOT;
uint32_t DCHUBBUB_SDPIF_AGP_TOP; uint32_t DCHUBBUB_SDPIF_AGP_TOP;
uint32_t DCHUBBUB_CRC_CTRL; uint32_t DCHUBBUB_CRC_CTRL;
uint32_t DCHUBBUB_SOFT_RESET;
}; };
/* set field name */ /* set field name */
...@@ -114,6 +116,7 @@ struct dcn_hubbub_registers { ...@@ -114,6 +116,7 @@ struct dcn_hubbub_registers {
#define HUBBUB_MASK_SH_LIST_DCN(mask_sh)\ #define HUBBUB_MASK_SH_LIST_DCN(mask_sh)\
HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_SOFT_RESET, DCHUBBUB_GLOBAL_SOFT_RESET, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, mask_sh), \
...@@ -143,6 +146,7 @@ struct dcn_hubbub_registers { ...@@ -143,6 +146,7 @@ struct dcn_hubbub_registers {
type DCHUBBUB_ARB_SAT_LEVEL;\ type DCHUBBUB_ARB_SAT_LEVEL;\
type DCHUBBUB_ARB_MIN_REQ_OUTSTAND;\ type DCHUBBUB_ARB_MIN_REQ_OUTSTAND;\
type DCHUBBUB_GLOBAL_TIMER_REFDIV;\ type DCHUBBUB_GLOBAL_TIMER_REFDIV;\
type DCHUBBUB_GLOBAL_SOFT_RESET; \
type SDPIF_FB_TOP;\ type SDPIF_FB_TOP;\
type SDPIF_FB_BASE;\ type SDPIF_FB_BASE;\
type SDPIF_FB_OFFSET;\ type SDPIF_FB_OFFSET;\
...@@ -201,6 +205,7 @@ void hubbub1_toggle_watermark_change_req( ...@@ -201,6 +205,7 @@ void hubbub1_toggle_watermark_change_req(
void hubbub1_wm_read_state(struct hubbub *hubbub, void hubbub1_wm_read_state(struct hubbub *hubbub,
struct dcn_hubbub_wm *wm); struct dcn_hubbub_wm *wm);
void hubbub1_soft_reset(struct hubbub *hubbub, bool reset);
void hubbub1_construct(struct hubbub *hubbub, void hubbub1_construct(struct hubbub *hubbub,
struct dc_context *ctx, struct dc_context *ctx,
const struct dcn_hubbub_registers *hubbub_regs, const struct dcn_hubbub_registers *hubbub_regs,
......
...@@ -78,6 +78,27 @@ static void hubp1_disconnect(struct hubp *hubp) ...@@ -78,6 +78,27 @@ static void hubp1_disconnect(struct hubp *hubp)
CURSOR_ENABLE, 0); CURSOR_ENABLE, 0);
} }
static void hubp1_disable_control(struct hubp *hubp, bool disable_hubp)
{
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
uint32_t disable = disable_hubp ? 1 : 0;
REG_UPDATE(DCHUBP_CNTL,
HUBP_DISABLE, disable);
}
static unsigned int hubp1_get_underflow_status(struct hubp *hubp)
{
uint32_t hubp_underflow = 0;
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
REG_GET(DCHUBP_CNTL,
HUBP_UNDERFLOW_STATUS,
&hubp_underflow);
return hubp_underflow;
}
static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank) static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank)
{ {
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
...@@ -1117,6 +1138,9 @@ static struct hubp_funcs dcn10_hubp_funcs = { ...@@ -1117,6 +1138,9 @@ static struct hubp_funcs dcn10_hubp_funcs = {
.hubp_clk_cntl = hubp1_clk_cntl, .hubp_clk_cntl = hubp1_clk_cntl,
.hubp_vtg_sel = hubp1_vtg_sel, .hubp_vtg_sel = hubp1_vtg_sel,
.hubp_read_state = hubp1_read_state, .hubp_read_state = hubp1_read_state,
.hubp_disable_control = hubp1_disable_control,
.hubp_get_underflow_status = hubp1_get_underflow_status,
}; };
/*****************************************/ /*****************************************/
......
...@@ -253,6 +253,7 @@ ...@@ -253,6 +253,7 @@
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PIPES, mask_sh),\ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PIPES, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_BANKS, mask_sh),\ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_BANKS, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, PIPE_INTERLEAVE, mask_sh),\ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, PIPE_INTERLEAVE, mask_sh),\
...@@ -421,6 +422,7 @@ ...@@ -421,6 +422,7 @@
#define DCN_HUBP_REG_FIELD_LIST(type) \ #define DCN_HUBP_REG_FIELD_LIST(type) \
type HUBP_BLANK_EN;\ type HUBP_BLANK_EN;\
type HUBP_DISABLE;\
type HUBP_TTU_DISABLE;\ type HUBP_TTU_DISABLE;\
type HUBP_NO_OUTSTANDING_REQ;\ type HUBP_NO_OUTSTANDING_REQ;\
type HUBP_VTG_SEL;\ type HUBP_VTG_SEL;\
...@@ -723,4 +725,5 @@ void hubp1_read_state(struct hubp *hubp); ...@@ -723,4 +725,5 @@ void hubp1_read_state(struct hubp *hubp);
enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch); enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch);
#endif #endif
...@@ -747,6 +747,90 @@ static void reset_back_end_for_pipe( ...@@ -747,6 +747,90 @@ static void reset_back_end_for_pipe(
pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
} }
static bool dcn10_hw_wa_force_recovery(struct dc *dc)
{
struct hubp *hubp ;
unsigned int i;
bool need_recover = true;
if (!dc->debug.recovery_enabled)
return false;
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx =
&dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
if (hubp != NULL) {
if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) {
/* one pipe underflow, we will reset all the pipes*/
need_recover = true;
}
}
}
}
if (!need_recover)
return false;
/*
DCHUBP_CNTL:HUBP_BLANK_EN=1
DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1
DCHUBP_CNTL:HUBP_DISABLE=1
DCHUBP_CNTL:HUBP_DISABLE=0
DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0
DCSURF_PRIMARY_SURFACE_ADDRESS
DCHUBP_CNTL:HUBP_BLANK_EN=0
*/
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx =
&dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_BLANK_EN=1*/
if (hubp != NULL)
hubp->funcs->set_hubp_blank_en(hubp, true);
}
}
/*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/
hubbub1_soft_reset(dc->res_pool->hubbub, true);
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx =
&dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_DISABLE=1*/
if (hubp != NULL)
hubp->funcs->hubp_disable_control(hubp, true);
}
}
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx =
&dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_DISABLE=0*/
if (hubp != NULL)
hubp->funcs->hubp_disable_control(hubp, true);
}
}
/*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/
hubbub1_soft_reset(dc->res_pool->hubbub, false);
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx =
&dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_BLANK_EN=0*/
if (hubp != NULL)
hubp->funcs->set_hubp_blank_en(hubp, true);
}
}
return true;
}
static void dcn10_verify_allow_pstate_change_high(struct dc *dc) static void dcn10_verify_allow_pstate_change_high(struct dc *dc)
{ {
static bool should_log_hw_state; /* prevent hw state log by default */ static bool should_log_hw_state; /* prevent hw state log by default */
...@@ -755,8 +839,12 @@ static void dcn10_verify_allow_pstate_change_high(struct dc *dc) ...@@ -755,8 +839,12 @@ static void dcn10_verify_allow_pstate_change_high(struct dc *dc)
if (should_log_hw_state) { if (should_log_hw_state) {
dcn10_log_hw_state(dc); dcn10_log_hw_state(dc);
} }
BREAK_TO_DEBUGGER(); BREAK_TO_DEBUGGER();
if (dcn10_hw_wa_force_recovery(dc)) {
/*check again*/
if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub))
BREAK_TO_DEBUGGER();
}
} }
} }
......
...@@ -446,6 +446,7 @@ static const struct dc_debug debug_defaults_drv = { ...@@ -446,6 +446,7 @@ static const struct dc_debug debug_defaults_drv = {
.vsr_support = true, .vsr_support = true,
.performance_trace = false, .performance_trace = false,
.az_endpoint_mute_only = true, .az_endpoint_mute_only = true,
.recovery_enabled = false, /*enable this by default after testing.*/
}; };
static const struct dc_debug debug_defaults_diags = { static const struct dc_debug debug_defaults_diags = {
......
...@@ -121,6 +121,8 @@ struct hubp_funcs { ...@@ -121,6 +121,8 @@ struct hubp_funcs {
void (*hubp_clk_cntl)(struct hubp *hubp, bool enable); void (*hubp_clk_cntl)(struct hubp *hubp, bool enable);
void (*hubp_vtg_sel)(struct hubp *hubp, uint32_t otg_inst); void (*hubp_vtg_sel)(struct hubp *hubp, uint32_t otg_inst);
void (*hubp_read_state)(struct hubp *hubp); void (*hubp_read_state)(struct hubp *hubp);
void (*hubp_disable_control)(struct hubp *hubp, bool disable_hubp);
unsigned int (*hubp_get_underflow_status)(struct hubp *hubp);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment