Commit b1e9da7f authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher

drm/amd/display: Wait for clean shutdown in DMCUB reset

[Why]
The DMCUB may be currently executing commands when the reset is
triggered.

Before issuing a reset we should first wait for the DMCUB to finish
its work.

[How]
Send the GPINT command for halting the firmware before reset.

Get the ack for the command then wait for the scratch register to
become the correct value.

We want this to take under ~40us or so at most before we force reset
to cover PHY delay sequence max time.

Each register read will be at least ~1-3us so don't bother using udelay.
Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent fbbd3f8f
...@@ -65,4 +65,10 @@ enum dmub_gpint_command { ...@@ -65,4 +65,10 @@ enum dmub_gpint_command {
DMUB_GPINT__STOP_FW = 2, DMUB_GPINT__STOP_FW = 2,
}; };
/**
* Command responses.
*/
#define DMUB_GPINT__STOP_FW_RESPONSE 0xDEADDEAD
#endif /* _DMUB_GPINT_CMD_H_ */ #endif /* _DMUB_GPINT_CMD_H_ */
...@@ -77,6 +77,42 @@ static inline void dmub_dcn20_translate_addr(const union dmub_addr *addr_in, ...@@ -77,6 +77,42 @@ static inline void dmub_dcn20_translate_addr(const union dmub_addr *addr_in,
void dmub_dcn20_reset(struct dmub_srv *dmub) void dmub_dcn20_reset(struct dmub_srv *dmub)
{ {
union dmub_gpint_data_register cmd;
const uint32_t timeout = 30;
uint32_t in_reset, scratch, i;
REG_GET(DMCUB_CNTL, DMCUB_SOFT_RESET, &in_reset);
if (in_reset == 0) {
cmd.bits.status = 1;
cmd.bits.command_code = DMUB_GPINT__STOP_FW;
cmd.bits.param = 0;
dmub->hw_funcs.set_gpint(dmub, cmd);
/**
* Timeout covers both the ACK and the wait
* for remaining work to finish.
*
* This is mostly bound by the PHY disable sequence.
* Each register check will be greater than 1us, so
* don't bother using udelay.
*/
for (i = 0; i < timeout; ++i) {
if (dmub->hw_funcs.is_gpint_acked(dmub, cmd))
break;
}
for (i = 0; i < timeout; ++i) {
scratch = dmub->hw_funcs.get_gpint_response(dmub);
if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
break;
}
/* Force reset in case we timed out, DMCUB is likely hung. */
}
REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 1); REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 1);
REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1); REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
......
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