drm/amd/display: cap dpp dto phase not more than modulo.
authorYongqiang Sun <yongqiang.sun@amd.com>
Sun, 1 Nov 2020 18:05:11 +0000 (13:05 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 10 Nov 2020 19:26:18 +0000 (14:26 -0500)
[Why]
4K monitor shows corruption if dpp dto phase is larger than modulo.

[How]
cap phase value never larger than modulo.

Signed-off-by: Yongqiang Sun <yongqiang.sun@amd.com>
Acked-by: Bindu Ramamurthy <bindu.r@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_dccg.c

index f9e3a23..60cf3ff 100644 (file)
@@ -50,43 +50,47 @@ void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk)
        if (dccg->ref_dppclk) {
                int ref_dppclk = dccg->ref_dppclk;
                int modulo = ref_dppclk / 10000;
+               int phase;
 
                if (req_dppclk) {
-                       int phase;
-
                        /*
                         * program DPP DTO phase and modulo as below
-                        * phase = dpp_pipe_clk_mhz / 10
-                        * module = dpp_global_clk_mhz / 10
-                        * dmub FW will read phase value to
-                        * determine minimum dpp clk and notify smu
-                        * to set clks for more power saving in PSR state
+                        * phase = ceiling(dpp_pipe_clk_mhz / 10)
+                        * module = trunc(dpp_global_clk_mhz / 10)
+                        *
+                        * storing frequencies in registers allow dmcub fw
+                        * to run time lower clocks when possible for power saving
+                        *
+                        * ceiling phase and truncate modulo guarentees the divided
+                        * down per pipe dpp clock has high enough frequency
                         */
                        phase = (req_dppclk + 9999) / 10000;
 
-                       if (phase > 0xff) {
-                               ASSERT(false);
-                               phase = 0xff;
+                       if (phase > modulo) {
+                               /* phase > modulo result in screen corruption
+                                * ie phase = 30, mod = 29 for 4k@60 HDMI
+                                * in these case we don't want pipe clock to be divided
+                                */
+                               phase = modulo;
                        }
-
-                       REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
-                                       DPPCLK0_DTO_PHASE, phase,
-                                       DPPCLK0_DTO_MODULO, modulo);
-                       REG_UPDATE(DPPCLK_DTO_CTRL,
-                                       DPPCLK_DTO_ENABLE[dpp_inst], 1);
                } else {
                        /*
                         *  set phase to 10 if dpp isn't used to
                         *  prevent hard hang if access dpp register
                         *  on unused pipe
+                        *
+                        *  DTO should be on to divide down un-used
+                        *  pipe clock for power saving
                         */
-                       REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
-                               DPPCLK0_DTO_PHASE, 10,
+                       phase = 10;
+               }
+
+               REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
+                               DPPCLK0_DTO_PHASE, phase,
                                DPPCLK0_DTO_MODULO, modulo);
 
-                       REG_UPDATE(DPPCLK_DTO_CTRL,
-                               DPPCLK_DTO_ENABLE[dpp_inst], 0);
-               }
+               REG_UPDATE(DPPCLK_DTO_CTRL,
+                               DPPCLK_DTO_ENABLE[dpp_inst], 1);
        }
 
        dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk;