]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/msm/dpu: fix WD timer handling on DPU 8.x
authorDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tue, 30 Dec 2025 07:17:57 +0000 (09:17 +0200)
committerDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tue, 6 Jan 2026 03:23:01 +0000 (05:23 +0200)
Since DPU 8.x Watchdog timer settings were moved from the TOP to the
INTF block. Support programming the timer in the INTF block. Fixes tag
points to the commit which removed register access to those registers on
DPU 8.x+ (and which also should have added proper support for WD timer
on those devices).

Fixes: 43e3293fc614 ("drm/msm/dpu: add support for MDP_TOP blackhole")
Reviewed-by: Marijn Suijten <marijn.suijten@somainline.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/696586/
Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-2-98203d150611@oss.qualcomm.com
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h

index af5122a514bd1279ee64fafe554d382d591381b0..eba1d52211f68f3a70c6902fa4c6c9bd28705c51 100644 (file)
@@ -786,13 +786,13 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
        }
 
        vsync_cfg.vsync_source = disp_info->vsync_source;
+       vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode);
 
        if (hw_mdptop->ops.setup_vsync_source) {
                for (i = 0; i < dpu_enc->num_phys_encs; i++)
                        vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx;
 
                vsync_cfg.pp_count = dpu_enc->num_phys_encs;
-               vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode);
 
                hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg);
        }
@@ -802,7 +802,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
 
                if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel)
                        phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf,
-                                                        vsync_cfg.vsync_source);
+                                                        &vsync_cfg);
        }
 }
 
index a80ac82a96255da1d52e1f2fa7fc39388fc3782b..7e620f59098499503813f11f330e6ec5d31d14b1 100644 (file)
 #define INTF_MISR_CTRL                  0x180
 #define INTF_MISR_SIGNATURE             0x184
 
+#define INTF_WD_TIMER_0_CTL            0x230
+#define INTF_WD_TIMER_0_CTL2           0x234
+#define INTF_WD_TIMER_0_LOAD_VALUE     0x238
+
 #define INTF_MUX                        0x25C
 #define INTF_STATUS                     0x26C
 #define INTF_AVR_CONTROL                0x270
@@ -475,7 +479,20 @@ static int dpu_hw_intf_get_vsync_info(struct dpu_hw_intf *intf,
 }
 
 static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf,
-                                 enum dpu_vsync_source vsync_source)
+                                 struct dpu_vsync_source_cfg *cfg)
+{
+       struct dpu_hw_blk_reg_map *c;
+
+       if (!intf)
+               return;
+
+       c = &intf->hw;
+
+       DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (cfg->vsync_source & 0xf));
+}
+
+static void dpu_hw_intf_vsync_sel_v8(struct dpu_hw_intf *intf,
+                                 struct dpu_vsync_source_cfg *cfg)
 {
        struct dpu_hw_blk_reg_map *c;
 
@@ -484,7 +501,30 @@ static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf,
 
        c = &intf->hw;
 
-       DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (vsync_source & 0xf));
+       if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 &&
+           cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_1) {
+               pr_warn_once("DPU 8.x supports only GPIOs and timer0 as TE sources\n");
+               return;
+       }
+
+       if (cfg->vsync_source == DPU_VSYNC_SOURCE_WD_TIMER_0) {
+               u32 reg;
+
+               DPU_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE,
+                             CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
+
+               DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */
+
+               reg  = BIT(8);          /* enable heartbeat timer */
+               reg |= BIT(0);          /* enable WD timer */
+               reg |= BIT(1);          /* select default 16 clock ticks */
+               DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL2, reg);
+
+               /* make sure that timers are enabled/disabled for vsync state */
+               wmb();
+       }
+
+       dpu_hw_intf_vsync_sel(intf, cfg);
 }
 
 static void dpu_hw_intf_disable_autorefresh(struct dpu_hw_intf *intf,
@@ -598,7 +638,10 @@ struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev,
                c->ops.enable_tearcheck = dpu_hw_intf_enable_te;
                c->ops.disable_tearcheck = dpu_hw_intf_disable_te;
                c->ops.connect_external_te = dpu_hw_intf_connect_external_te;
-               c->ops.vsync_sel = dpu_hw_intf_vsync_sel;
+               if (mdss_rev->core_major_ver >= 8)
+                       c->ops.vsync_sel = dpu_hw_intf_vsync_sel_v8;
+               else
+                       c->ops.vsync_sel = dpu_hw_intf_vsync_sel;
                c->ops.disable_autorefresh = dpu_hw_intf_disable_autorefresh;
        }
 
index 5a19cd74fa9471fc001a22b92e7d9b616bea6069..f6ef2c21b66d42b364d436397264a5e9fee6bdd3 100644 (file)
@@ -12,6 +12,7 @@
 #include "dpu_hw_util.h"
 
 struct dpu_hw_intf;
+struct dpu_vsync_source_cfg;
 
 /* intf timing settings */
 struct dpu_hw_intf_timing_params {
@@ -104,7 +105,7 @@ struct dpu_hw_intf_ops {
 
        int (*connect_external_te)(struct dpu_hw_intf *intf, bool enable_external_te);
 
-       void (*vsync_sel)(struct dpu_hw_intf *intf, enum dpu_vsync_source vsync_source);
+       void (*vsync_sel)(struct dpu_hw_intf *intf, struct dpu_vsync_source_cfg *cfg);
 
        void (*disable_autorefresh)(struct dpu_hw_intf *intf, uint32_t encoder_id, u16 vdisplay);
 
index 96dc10589bee6cf144eabaecf9f8ec5777431ac3..1ebd75d4f9be8d85e1591d11b5227b87da84e307 100644 (file)
 #define TRAFFIC_SHAPER_WR_CLIENT(num)     (0x060 + (num * 4))
 #define TRAFFIC_SHAPER_FIXPOINT_FACTOR    4
 
-#define MDP_TICK_COUNT                    16
-#define XO_CLK_RATE                       19200
-#define MS_TICKS_IN_SEC                   1000
-
-#define CALCULATE_WD_LOAD_VALUE(fps) \
-       ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
-
 static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp,
                struct split_pipe_cfg *cfg)
 {
index 67b08e99335dcf64c2f036fe6f6433ad84d087c8..6fe65bc3bff4e8b9ac37888219a5c6cd63edf1c3 100644 (file)
 
 #define TO_S15D16(_x_)((_x_) << 7)
 
+#define MDP_TICK_COUNT                    16
+#define XO_CLK_RATE                       19200
+#define MS_TICKS_IN_SEC                   1000
+
+#define CALCULATE_WD_LOAD_VALUE(fps) \
+       ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
+
 extern const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L;
 extern const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L;
 extern const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l;