drm/amd/display: Negate IPS allow and commit bits
authorDuncan Ma <duncan.ma@amd.com>
Wed, 25 Oct 2023 23:07:21 +0000 (19:07 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 17 Nov 2023 05:53:10 +0000 (00:53 -0500)
[WHY]
On s0i3, IPS mask isn't saved and restored.
It is reset to zero on exit.

If it is cleared unexpectedly, driver will
proceed operations while DCN is in IPS2 and
cause a hang.

[HOW]
Negate the bit logic. Default value of
zero indicates it is still in IPS2. Driver
must poll for the bit to assert.

Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Reviewed-by: Charlene Liu <charlene.liu@amd.com>
Acked-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Duncan Ma <duncan.ma@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c

index 0fa4fcd..507a7cf 100644 (file)
@@ -820,22 +820,22 @@ static void dcn35_set_idle_state(struct clk_mgr *clk_mgr_base, bool allow_idle)
 
        if (dc->config.disable_ips == DMUB_IPS_ENABLE ||
                dc->config.disable_ips == DMUB_IPS_DISABLE_DYNAMIC) {
-               val |= DMUB_IPS1_ALLOW_MASK;
-               val |= DMUB_IPS2_ALLOW_MASK;
-       } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS1) {
                val = val & ~DMUB_IPS1_ALLOW_MASK;
                val = val & ~DMUB_IPS2_ALLOW_MASK;
-       } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2) {
-               val |= DMUB_IPS1_ALLOW_MASK;
-               val = val & ~DMUB_IPS2_ALLOW_MASK;
-       } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2_Z10) {
+       } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS1) {
                val |= DMUB_IPS1_ALLOW_MASK;
                val |= DMUB_IPS2_ALLOW_MASK;
+       } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2) {
+               val = val & ~DMUB_IPS1_ALLOW_MASK;
+               val |= DMUB_IPS2_ALLOW_MASK;
+       } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2_Z10) {
+               val = val & ~DMUB_IPS1_ALLOW_MASK;
+               val = val & ~DMUB_IPS2_ALLOW_MASK;
        }
 
        if (!allow_idle) {
-               val = val & ~DMUB_IPS1_ALLOW_MASK;
-               val = val & ~DMUB_IPS2_ALLOW_MASK;
+               val |= DMUB_IPS1_ALLOW_MASK;
+               val |= DMUB_IPS2_ALLOW_MASK;
        }
 
        dcn35_smu_write_ips_scratch(clk_mgr, val);
index d8f4347..76b47f1 100644 (file)
@@ -4934,8 +4934,8 @@ bool dc_dmub_is_ips_idle_state(struct dc *dc)
        if (dc->hwss.get_idle_state)
                idle_state = dc->hwss.get_idle_state(dc);
 
-       if ((idle_state & DMUB_IPS1_ALLOW_MASK) ||
-               (idle_state & DMUB_IPS2_ALLOW_MASK))
+       if (!(idle_state & DMUB_IPS1_ALLOW_MASK) ||
+               !(idle_state & DMUB_IPS2_ALLOW_MASK))
                return true;
 
        return false;
index e4c0072..0e07699 100644 (file)
@@ -1202,11 +1202,11 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
                allow_state = dc->hwss.get_idle_state(dc);
                dc->hwss.set_idle_state(dc, false);
 
-               if (allow_state & DMUB_IPS2_ALLOW_MASK) {
+               if (!(allow_state & DMUB_IPS2_ALLOW_MASK)) {
                        // Wait for evaluation time
                        udelay(dc->debug.ips2_eval_delay_us);
                        commit_state = dc->hwss.get_idle_state(dc);
-                       if (commit_state & DMUB_IPS2_COMMIT_MASK) {
+                       if (!(commit_state & DMUB_IPS2_COMMIT_MASK)) {
                                // Tell PMFW to exit low power state
                                dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
 
@@ -1216,7 +1216,7 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
 
                                for (i = 0; i < max_num_polls; ++i) {
                                        commit_state = dc->hwss.get_idle_state(dc);
-                                       if (!(commit_state & DMUB_IPS2_COMMIT_MASK))
+                                       if (commit_state & DMUB_IPS2_COMMIT_MASK)
                                                break;
 
                                        udelay(1);
@@ -1235,10 +1235,10 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
                }
 
                dc_dmub_srv_notify_idle(dc, false);
-               if (allow_state & DMUB_IPS1_ALLOW_MASK) {
+               if (!(allow_state & DMUB_IPS1_ALLOW_MASK)) {
                        for (i = 0; i < max_num_polls; ++i) {
                                commit_state = dc->hwss.get_idle_state(dc);
-                               if (!(commit_state & DMUB_IPS1_COMMIT_MASK))
+                               if (commit_state & DMUB_IPS1_COMMIT_MASK)
                                        break;
 
                                udelay(1);