Loading drivers/gpu/drm/msm/sde/sde_encoder.c +74 −35 Original line number Diff line number Diff line Loading @@ -1121,6 +1121,62 @@ static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc, return ret; } static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_display_info *disp_info, bool is_dummy) { struct sde_vsync_source_cfg vsync_cfg = { 0 }; struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_hw_mdp *hw_mdptop; struct drm_encoder *drm_enc; int i; if (!sde_enc || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); return; } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d\n", sde_enc->num_phys_encs, (int) ARRAY_SIZE(sde_enc->hw_pp)); return; } drm_enc = &sde_enc->base; /* this pointers are checked in virt_enable_helper */ priv = drm_enc->dev->dev_private; sde_kms = to_sde_kms(priv->kms); if (!sde_kms) { SDE_ERROR("invalid sde_kms\n"); return; } hw_mdptop = sde_kms->hw_mdp; if (!hw_mdptop) { SDE_ERROR("invalid mdptop\n"); return; } if (hw_mdptop->ops.setup_vsync_source && disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { for (i = 0; i < sde_enc->num_phys_encs; i++) vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; vsync_cfg.pp_count = sde_enc->num_phys_encs; vsync_cfg.frame_rate = sde_enc->disp_info.frame_rate; if (is_dummy) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; else if (disp_info->is_te_using_watchdog_timer) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; else vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO; vsync_cfg.is_dummy = is_dummy; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); } } static int sde_encoder_update_rsc_client( struct drm_encoder *drm_enc, struct sde_encoder_rsc_config *config, bool enable) Loading Loading @@ -1237,6 +1293,9 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, rsc_cfg.inline_rotate_prefill = sde_crtc_get_inline_prefill(drm_enc->crtc); _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false); /* enable RSC */ sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true); Loading @@ -1245,6 +1304,14 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, /* disable RSC */ sde_encoder_update_rsc_client(drm_enc, NULL, false); /** * this call is for hardware workaround on sdm845 and should * not be removed without considering the design changes for * sde rsc + command mode concurrency. It may lead to pp * timeout due to vsync from panel for command mode panel. */ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, true); /* disable all the irq */ for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = Loading Loading @@ -1604,33 +1671,22 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) struct sde_encoder_virt *sde_enc = NULL; struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_hw_mdp *hw_mdptop; int i = 0; struct sde_watchdog_te_status te_cfg = { 0 }; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } priv = drm_enc->dev->dev_private; sde_enc = to_sde_encoder_virt(drm_enc); if (!sde_enc || !sde_enc->cur_master) { SDE_ERROR("invalid sde encoder/master\n"); return; } priv = drm_enc->dev->dev_private; sde_kms = to_sde_kms(priv->kms); hw_mdptop = sde_kms->hw_mdp; if (!hw_mdptop) { SDE_ERROR("invalid mdptop\n"); if (!sde_kms) { SDE_ERROR("invalid sde_kms\n"); return; } sde_kms = to_sde_kms(priv->kms); if (!sde_kms) { SDE_ERROR("invalid sde_kms\n"); sde_enc = to_sde_encoder_virt(drm_enc); if (!sde_enc || !sde_enc->cur_master) { SDE_ERROR("invalid sde encoder/master\n"); return; } Loading @@ -1640,24 +1696,7 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) sde_enc->cur_master->hw_mdptop, sde_kms->catalog); if (sde_enc->num_phys_encs > ARRAY_SIZE(te_cfg.ppnumber) || sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d/%d\n", sde_enc->num_phys_encs, (int) ARRAY_SIZE(te_cfg.ppnumber), (int) ARRAY_SIZE(sde_enc->hw_pp)); return; } if (hw_mdptop->ops.setup_vsync_sel) { for (i = 0; i < sde_enc->num_phys_encs; i++) te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; te_cfg.pp_count = sde_enc->num_phys_encs; te_cfg.frame_rate = sde_enc->disp_info.frame_rate; hw_mdptop->ops.setup_vsync_sel(hw_mdptop, &te_cfg, sde_enc->disp_info.is_te_using_watchdog_timer); } _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false); memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi)); memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi)); Loading drivers/gpu/drm/msm/sde/sde_hw_mdss.h +13 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,19 @@ enum sde_format_flags { #define SDE_BLEND_BG_INV_MOD_ALPHA (1 << 12) #define SDE_BLEND_BG_TRANSP_EN (1 << 13) #define SDE_VSYNC0_SOURCE_GPIO 0 #define SDE_VSYNC1_SOURCE_GPIO 1 #define SDE_VSYNC2_SOURCE_GPIO 2 #define SDE_VSYNC_SOURCE_INTF_0 3 #define SDE_VSYNC_SOURCE_INTF_1 4 #define SDE_VSYNC_SOURCE_INTF_2 5 #define SDE_VSYNC_SOURCE_INTF_3 6 #define SDE_VSYNC_SOURCE_WD_TIMER_4 11 #define SDE_VSYNC_SOURCE_WD_TIMER_3 12 #define SDE_VSYNC_SOURCE_WD_TIMER_2 13 #define SDE_VSYNC_SOURCE_WD_TIMER_1 14 #define SDE_VSYNC_SOURCE_WD_TIMER_0 15 enum sde_hw_blk_type { SDE_HW_BLK_TOP = 0, SDE_HW_BLK_SSPP, Loading drivers/gpu/drm/msm/sde/sde_hw_top.c +67 −19 Original line number Diff line number Diff line Loading @@ -38,6 +38,18 @@ #define MDP_WD_TIMER_0_CTL 0x380 #define MDP_WD_TIMER_0_CTL2 0x384 #define MDP_WD_TIMER_0_LOAD_VALUE 0x388 #define MDP_WD_TIMER_1_CTL 0x390 #define MDP_WD_TIMER_1_CTL2 0x394 #define MDP_WD_TIMER_1_LOAD_VALUE 0x398 #define MDP_WD_TIMER_2_CTL 0x420 #define MDP_WD_TIMER_2_CTL2 0x424 #define MDP_WD_TIMER_2_LOAD_VALUE 0x428 #define MDP_WD_TIMER_3_CTL 0x430 #define MDP_WD_TIMER_3_CTL2 0x434 #define MDP_WD_TIMER_3_LOAD_VALUE 0x438 #define MDP_WD_TIMER_4_CTL 0x440 #define MDP_WD_TIMER_4_CTL2 0x444 #define MDP_WD_TIMER_4_LOAD_VALUE 0x448 #define MDP_TICK_COUNT 16 #define XO_CLK_RATE 19200 Loading Loading @@ -204,38 +216,74 @@ static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp, status->wb[WB_3] = 0; } static void sde_hw_setup_vsync_sel(struct sde_hw_mdp *mdp, struct sde_watchdog_te_status *cfg, bool watchdog_te) static void sde_hw_setup_vsync_source(struct sde_hw_mdp *mdp, struct sde_vsync_source_cfg *cfg) { struct sde_hw_blk_reg_map *c = &mdp->hw; u32 reg = 0; int i = 0; u32 pp_offset[] = {0xC, 0x8, 0x4, 0x13}; struct sde_hw_blk_reg_map *c; u32 reg, wd_load_value, wd_ctl, wd_ctl2, i; static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18}; if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber))) return; c = &mdp->hw; reg = SDE_REG_READ(c, MDP_VSYNC_SEL); for (i = 0; i < cfg->pp_count; i++) { int pp_idx = cfg->ppnumber[i] - PINGPONG_0; if (pp_idx >= ARRAY_SIZE(pp_offset)) continue; if (watchdog_te) reg |= 0xF << pp_offset[pp_idx]; else reg &= ~(0xF << pp_offset[pp_idx]); reg &= ~(0xf << pp_offset[pp_idx]); reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx]; } SDE_REG_WRITE(c, MDP_VSYNC_SEL, reg); if (watchdog_te) { SDE_REG_WRITE(c, MDP_WD_TIMER_0_LOAD_VALUE, if (cfg->vsync_source >= SDE_VSYNC_SOURCE_WD_TIMER_4 && cfg->vsync_source <= SDE_VSYNC_SOURCE_WD_TIMER_0) { switch (cfg->vsync_source) { case SDE_VSYNC_SOURCE_WD_TIMER_4: wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_4_CTL; wd_ctl2 = MDP_WD_TIMER_4_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_3: wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_3_CTL; wd_ctl2 = MDP_WD_TIMER_3_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_2: wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_2_CTL; wd_ctl2 = MDP_WD_TIMER_2_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_1: wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_1_CTL; wd_ctl2 = MDP_WD_TIMER_1_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_0: default: wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_0_CTL; wd_ctl2 = MDP_WD_TIMER_0_CTL2; break; } if (cfg->is_dummy) { SDE_REG_WRITE(c, wd_ctl2, 0x0); } else { SDE_REG_WRITE(c, wd_load_value, CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL, BIT(0)); /* clear timer */ reg = SDE_REG_READ(c, MDP_WD_TIMER_0_CTL2); SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */ reg = SDE_REG_READ(c, wd_ctl2); reg |= BIT(8); /* enable heartbeat timer */ reg |= BIT(0); /* enable WD timer */ SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL2, reg); SDE_REG_WRITE(c, wd_ctl2, reg); } /* make sure that timers are enabled/disabled for vsync state */ wmb(); } } Loading Loading @@ -308,7 +356,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, ops->setup_cdm_output = sde_hw_setup_cdm_output; ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl; ops->get_danger_status = sde_hw_get_danger_status; ops->setup_vsync_sel = sde_hw_setup_vsync_sel; ops->setup_vsync_source = sde_hw_setup_vsync_source; ops->get_safe_status = sde_hw_get_safe_status; ops->setup_dce = sde_hw_setup_dce; ops->reset_ubwc = sde_hw_reset_ubwc; Loading drivers/gpu/drm/msm/sde/sde_hw_top.h +12 −7 Original line number Diff line number Diff line Loading @@ -78,15 +78,21 @@ struct sde_danger_safe_status { }; /** * struct sde_watchdog_te_status - configure watchdog timer to generate TE * struct sde_vsync_source_cfg - configure vsync source and configure the * watchdog timers if required. * @pp_count: number of ping pongs active * @frame_rate: Display frame rate * @ppnumber: ping pong index array * @vsync_source: vsync source selection * @is_dummy: a dummy source of vsync selection. It must not be selected for * any case other than sde rsc idle request. */ struct sde_watchdog_te_status { struct sde_vsync_source_cfg { u32 pp_count; u32 frame_rate; u32 ppnumber[PINGPONG_MAX]; u32 vsync_source; bool is_dummy; }; /** Loading Loading @@ -155,13 +161,12 @@ struct sde_hw_mdp_ops { struct sde_danger_safe_status *status); /** * setup_vsync_sel - get vsync configuration details * setup_vsync_source - setup vsync source configuration details * @mdp: mdp top context driver * @cfg: watchdog timer configuration * @watchdog_te: watchdog timer enable * @cfg: vsync source selection configuration */ void (*setup_vsync_sel)(struct sde_hw_mdp *mdp, struct sde_watchdog_te_status *cfg, bool watchdog_te); void (*setup_vsync_source)(struct sde_hw_mdp *mdp, struct sde_vsync_source_cfg *cfg); /** * get_safe_status - get safe status Loading Loading
drivers/gpu/drm/msm/sde/sde_encoder.c +74 −35 Original line number Diff line number Diff line Loading @@ -1121,6 +1121,62 @@ static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc, return ret; } static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_display_info *disp_info, bool is_dummy) { struct sde_vsync_source_cfg vsync_cfg = { 0 }; struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_hw_mdp *hw_mdptop; struct drm_encoder *drm_enc; int i; if (!sde_enc || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); return; } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d\n", sde_enc->num_phys_encs, (int) ARRAY_SIZE(sde_enc->hw_pp)); return; } drm_enc = &sde_enc->base; /* this pointers are checked in virt_enable_helper */ priv = drm_enc->dev->dev_private; sde_kms = to_sde_kms(priv->kms); if (!sde_kms) { SDE_ERROR("invalid sde_kms\n"); return; } hw_mdptop = sde_kms->hw_mdp; if (!hw_mdptop) { SDE_ERROR("invalid mdptop\n"); return; } if (hw_mdptop->ops.setup_vsync_source && disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { for (i = 0; i < sde_enc->num_phys_encs; i++) vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; vsync_cfg.pp_count = sde_enc->num_phys_encs; vsync_cfg.frame_rate = sde_enc->disp_info.frame_rate; if (is_dummy) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; else if (disp_info->is_te_using_watchdog_timer) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; else vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO; vsync_cfg.is_dummy = is_dummy; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); } } static int sde_encoder_update_rsc_client( struct drm_encoder *drm_enc, struct sde_encoder_rsc_config *config, bool enable) Loading Loading @@ -1237,6 +1293,9 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, rsc_cfg.inline_rotate_prefill = sde_crtc_get_inline_prefill(drm_enc->crtc); _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false); /* enable RSC */ sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true); Loading @@ -1245,6 +1304,14 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, /* disable RSC */ sde_encoder_update_rsc_client(drm_enc, NULL, false); /** * this call is for hardware workaround on sdm845 and should * not be removed without considering the design changes for * sde rsc + command mode concurrency. It may lead to pp * timeout due to vsync from panel for command mode panel. */ _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, true); /* disable all the irq */ for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = Loading Loading @@ -1604,33 +1671,22 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) struct sde_encoder_virt *sde_enc = NULL; struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_hw_mdp *hw_mdptop; int i = 0; struct sde_watchdog_te_status te_cfg = { 0 }; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } priv = drm_enc->dev->dev_private; sde_enc = to_sde_encoder_virt(drm_enc); if (!sde_enc || !sde_enc->cur_master) { SDE_ERROR("invalid sde encoder/master\n"); return; } priv = drm_enc->dev->dev_private; sde_kms = to_sde_kms(priv->kms); hw_mdptop = sde_kms->hw_mdp; if (!hw_mdptop) { SDE_ERROR("invalid mdptop\n"); if (!sde_kms) { SDE_ERROR("invalid sde_kms\n"); return; } sde_kms = to_sde_kms(priv->kms); if (!sde_kms) { SDE_ERROR("invalid sde_kms\n"); sde_enc = to_sde_encoder_virt(drm_enc); if (!sde_enc || !sde_enc->cur_master) { SDE_ERROR("invalid sde encoder/master\n"); return; } Loading @@ -1640,24 +1696,7 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) sde_enc->cur_master->hw_mdptop, sde_kms->catalog); if (sde_enc->num_phys_encs > ARRAY_SIZE(te_cfg.ppnumber) || sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d/%d\n", sde_enc->num_phys_encs, (int) ARRAY_SIZE(te_cfg.ppnumber), (int) ARRAY_SIZE(sde_enc->hw_pp)); return; } if (hw_mdptop->ops.setup_vsync_sel) { for (i = 0; i < sde_enc->num_phys_encs; i++) te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; te_cfg.pp_count = sde_enc->num_phys_encs; te_cfg.frame_rate = sde_enc->disp_info.frame_rate; hw_mdptop->ops.setup_vsync_sel(hw_mdptop, &te_cfg, sde_enc->disp_info.is_te_using_watchdog_timer); } _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false); memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi)); memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi)); Loading
drivers/gpu/drm/msm/sde/sde_hw_mdss.h +13 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,19 @@ enum sde_format_flags { #define SDE_BLEND_BG_INV_MOD_ALPHA (1 << 12) #define SDE_BLEND_BG_TRANSP_EN (1 << 13) #define SDE_VSYNC0_SOURCE_GPIO 0 #define SDE_VSYNC1_SOURCE_GPIO 1 #define SDE_VSYNC2_SOURCE_GPIO 2 #define SDE_VSYNC_SOURCE_INTF_0 3 #define SDE_VSYNC_SOURCE_INTF_1 4 #define SDE_VSYNC_SOURCE_INTF_2 5 #define SDE_VSYNC_SOURCE_INTF_3 6 #define SDE_VSYNC_SOURCE_WD_TIMER_4 11 #define SDE_VSYNC_SOURCE_WD_TIMER_3 12 #define SDE_VSYNC_SOURCE_WD_TIMER_2 13 #define SDE_VSYNC_SOURCE_WD_TIMER_1 14 #define SDE_VSYNC_SOURCE_WD_TIMER_0 15 enum sde_hw_blk_type { SDE_HW_BLK_TOP = 0, SDE_HW_BLK_SSPP, Loading
drivers/gpu/drm/msm/sde/sde_hw_top.c +67 −19 Original line number Diff line number Diff line Loading @@ -38,6 +38,18 @@ #define MDP_WD_TIMER_0_CTL 0x380 #define MDP_WD_TIMER_0_CTL2 0x384 #define MDP_WD_TIMER_0_LOAD_VALUE 0x388 #define MDP_WD_TIMER_1_CTL 0x390 #define MDP_WD_TIMER_1_CTL2 0x394 #define MDP_WD_TIMER_1_LOAD_VALUE 0x398 #define MDP_WD_TIMER_2_CTL 0x420 #define MDP_WD_TIMER_2_CTL2 0x424 #define MDP_WD_TIMER_2_LOAD_VALUE 0x428 #define MDP_WD_TIMER_3_CTL 0x430 #define MDP_WD_TIMER_3_CTL2 0x434 #define MDP_WD_TIMER_3_LOAD_VALUE 0x438 #define MDP_WD_TIMER_4_CTL 0x440 #define MDP_WD_TIMER_4_CTL2 0x444 #define MDP_WD_TIMER_4_LOAD_VALUE 0x448 #define MDP_TICK_COUNT 16 #define XO_CLK_RATE 19200 Loading Loading @@ -204,38 +216,74 @@ static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp, status->wb[WB_3] = 0; } static void sde_hw_setup_vsync_sel(struct sde_hw_mdp *mdp, struct sde_watchdog_te_status *cfg, bool watchdog_te) static void sde_hw_setup_vsync_source(struct sde_hw_mdp *mdp, struct sde_vsync_source_cfg *cfg) { struct sde_hw_blk_reg_map *c = &mdp->hw; u32 reg = 0; int i = 0; u32 pp_offset[] = {0xC, 0x8, 0x4, 0x13}; struct sde_hw_blk_reg_map *c; u32 reg, wd_load_value, wd_ctl, wd_ctl2, i; static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18}; if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber))) return; c = &mdp->hw; reg = SDE_REG_READ(c, MDP_VSYNC_SEL); for (i = 0; i < cfg->pp_count; i++) { int pp_idx = cfg->ppnumber[i] - PINGPONG_0; if (pp_idx >= ARRAY_SIZE(pp_offset)) continue; if (watchdog_te) reg |= 0xF << pp_offset[pp_idx]; else reg &= ~(0xF << pp_offset[pp_idx]); reg &= ~(0xf << pp_offset[pp_idx]); reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx]; } SDE_REG_WRITE(c, MDP_VSYNC_SEL, reg); if (watchdog_te) { SDE_REG_WRITE(c, MDP_WD_TIMER_0_LOAD_VALUE, if (cfg->vsync_source >= SDE_VSYNC_SOURCE_WD_TIMER_4 && cfg->vsync_source <= SDE_VSYNC_SOURCE_WD_TIMER_0) { switch (cfg->vsync_source) { case SDE_VSYNC_SOURCE_WD_TIMER_4: wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_4_CTL; wd_ctl2 = MDP_WD_TIMER_4_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_3: wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_3_CTL; wd_ctl2 = MDP_WD_TIMER_3_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_2: wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_2_CTL; wd_ctl2 = MDP_WD_TIMER_2_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_1: wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_1_CTL; wd_ctl2 = MDP_WD_TIMER_1_CTL2; break; case SDE_VSYNC_SOURCE_WD_TIMER_0: default: wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_0_CTL; wd_ctl2 = MDP_WD_TIMER_0_CTL2; break; } if (cfg->is_dummy) { SDE_REG_WRITE(c, wd_ctl2, 0x0); } else { SDE_REG_WRITE(c, wd_load_value, CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL, BIT(0)); /* clear timer */ reg = SDE_REG_READ(c, MDP_WD_TIMER_0_CTL2); SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */ reg = SDE_REG_READ(c, wd_ctl2); reg |= BIT(8); /* enable heartbeat timer */ reg |= BIT(0); /* enable WD timer */ SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL2, reg); SDE_REG_WRITE(c, wd_ctl2, reg); } /* make sure that timers are enabled/disabled for vsync state */ wmb(); } } Loading Loading @@ -308,7 +356,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, ops->setup_cdm_output = sde_hw_setup_cdm_output; ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl; ops->get_danger_status = sde_hw_get_danger_status; ops->setup_vsync_sel = sde_hw_setup_vsync_sel; ops->setup_vsync_source = sde_hw_setup_vsync_source; ops->get_safe_status = sde_hw_get_safe_status; ops->setup_dce = sde_hw_setup_dce; ops->reset_ubwc = sde_hw_reset_ubwc; Loading
drivers/gpu/drm/msm/sde/sde_hw_top.h +12 −7 Original line number Diff line number Diff line Loading @@ -78,15 +78,21 @@ struct sde_danger_safe_status { }; /** * struct sde_watchdog_te_status - configure watchdog timer to generate TE * struct sde_vsync_source_cfg - configure vsync source and configure the * watchdog timers if required. * @pp_count: number of ping pongs active * @frame_rate: Display frame rate * @ppnumber: ping pong index array * @vsync_source: vsync source selection * @is_dummy: a dummy source of vsync selection. It must not be selected for * any case other than sde rsc idle request. */ struct sde_watchdog_te_status { struct sde_vsync_source_cfg { u32 pp_count; u32 frame_rate; u32 ppnumber[PINGPONG_MAX]; u32 vsync_source; bool is_dummy; }; /** Loading Loading @@ -155,13 +161,12 @@ struct sde_hw_mdp_ops { struct sde_danger_safe_status *status); /** * setup_vsync_sel - get vsync configuration details * setup_vsync_source - setup vsync source configuration details * @mdp: mdp top context driver * @cfg: watchdog timer configuration * @watchdog_te: watchdog timer enable * @cfg: vsync source selection configuration */ void (*setup_vsync_sel)(struct sde_hw_mdp *mdp, struct sde_watchdog_te_status *cfg, bool watchdog_te); void (*setup_vsync_source)(struct sde_hw_mdp *mdp, struct sde_vsync_source_cfg *cfg); /** * get_safe_status - get safe status Loading