aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>2020-01-16 09:16:18 -0500
committerAlex Deucher <alexander.deucher@amd.com>2020-02-06 15:04:37 -0500
commitb1e9da7f7dd4a7bfeb8c0819cfd97db672229e42 (patch)
tree415c1eb2cff8f44a3455bc948fc2deb21b76daf1
parentdrm/amd/display: Add GPINT handler interface (diff)
downloadlinux-dev-b1e9da7f7dd4a7bfeb8c0819cfd97db672229e42.tar.xz
linux-dev-b1e9da7f7dd4a7bfeb8c0819cfd97db672229e42.zip
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: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_gpint_cmd.h6
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c36
2 files changed, 42 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_gpint_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_gpint_cmd.h
index 5398ed6b35d1..e13685917dab 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_gpint_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_gpint_cmd.h
@@ -65,4 +65,10 @@ enum dmub_gpint_command {
DMUB_GPINT__STOP_FW = 2,
};
+/**
+ * Command responses.
+ */
+
+#define DMUB_GPINT__STOP_FW_RESPONSE 0xDEADDEAD
+
#endif /* _DMUB_GPINT_CMD_H_ */
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c
index 7c1604c2221c..479f17bb3800 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c
@@ -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)
{
+ 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_ENABLE, 0);
REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);