Loading Documentation/devicetree/bindings/display/msm/sde.txt +6 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,9 @@ Optional properties: vbif blocks. These offsets will be calculated from register "vbif_phys" defined in reg property. - qcom,sde-vbif-size: A u32 value indicates the vbif block address range. - qcom,sde-uidle-off: A u32 value with the offset for the uidle block, from the "mdp_phys". - qcom,sde-uidle-size: A u32 value indicates the uidle block address range. - qcom,sde-te-off: A u32 offset indicates the te block offset on pingpong. This offset is 0x0 by default. - qcom,sde-te2-off: A u32 offset indicates the te2 block offset on pingpong. Loading Loading @@ -683,6 +686,9 @@ Example: qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; qcom,sde-uidle-off = <0x80000>; qcom,sde-uidle-size = <0x70>; qcom,sde-dram-channels = <2>; qcom,sde-num-nrt-paths = <1>; Loading arch/arm64/boot/dts/qcom/kona-sde.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,9 @@ /* offsets are based off dspp 0 and dspp 1 */ qcom,sde-dspp-ltm-off = <0x2a000 0x28100>; qcom,sde-uidle-off = <0x80000>; qcom,sde-uidle-size = <0x70>; qcom,sde-vbif-off = <0>; qcom,sde-vbif-size = <0x1040>; qcom,sde-vbif-id = <0>; Loading drivers/gpu/drm/msm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_reg_dma_v1_color_proc.o \ sde/sde_hw_color_proc_v4.o \ sde/sde_hw_ad4.o \ sde/sde_hw_uidle.o \ sde_edid_parser.o \ sde_hdcp_1x.o \ sde_hdcp_2x.o Loading drivers/gpu/drm/msm/sde/sde_core_perf.c +168 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "sde_kms.h" #include "sde_trace.h" #include "sde_crtc.h" #include "sde_encoder.h" #include "sde_core_perf.h" #define SDE_PERF_MODE_STRING_SIZE 128 Loading Loading @@ -400,6 +401,173 @@ static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, total_llcc_active ? true : false); } static void _sde_core_uidle_setup_wd(struct sde_kms *kms, bool enable) { struct sde_uidle_wd_cfg wd; struct sde_hw_uidle *uidle; uidle = kms->hw_uidle; wd.enable = enable; wd.clear = false; wd.granularity = SDE_UIDLE_WD_GRANULARITY; wd.heart_beat = SDE_UIDLE_WD_HEART_BEAT; wd.load_value = SDE_UIDLE_WD_LOAD_VAL; if (uidle->ops.setup_wd_timer) uidle->ops.setup_wd_timer(uidle, &wd); } static void _sde_core_uidle_setup_cfg(struct sde_kms *kms, bool enable) { struct sde_uidle_ctl_cfg cfg; struct sde_hw_uidle *uidle; uidle = kms->hw_uidle; cfg.uidle_enable = enable; cfg.fal10_danger = kms->catalog->uidle_cfg.fal10_danger; cfg.fal10_exit_cnt = kms->catalog->uidle_cfg.fal10_exit_cnt; cfg.fal10_exit_danger = kms->catalog->uidle_cfg.fal10_exit_danger; SDE_DEBUG("fal10_danger:%d fal10_exit_cnt:%d fal10_exit_danger:%d\n", cfg.fal10_danger, cfg.fal10_exit_cnt, cfg.fal10_exit_danger); SDE_EVT32(enable, cfg.fal10_danger, cfg.fal10_exit_cnt, cfg.fal10_exit_danger); if (uidle->ops.set_uidle_ctl) uidle->ops.set_uidle_ctl(uidle, &cfg); } static void _sde_core_uidle_setup_ctl(struct drm_crtc *crtc, bool enable) { struct drm_encoder *drm_enc; /* Disable uidle in the CTL */ drm_for_each_encoder(drm_enc, crtc->dev) { if (drm_enc->crtc != crtc) continue; sde_encoder_uidle_enable(drm_enc, enable); } } static int _sde_core_perf_enable_uidle(struct sde_kms *kms, struct drm_crtc *crtc, bool enable) { int rc = 0; if (!kms->dev || !kms->dev->dev || !kms->hw_uidle) { SDE_ERROR("wrong params won't enable uidlen"); rc = -EINVAL; goto exit; } /* if no status change, just return */ if ((enable && kms->perf.uidle_enabled) || (!enable && !kms->perf.uidle_enabled)) { SDE_DEBUG("no status change enable:%d uidle:%d\n", enable, kms->perf.uidle_enabled); goto exit; } SDE_EVT32(enable); _sde_core_uidle_setup_wd(kms, enable); _sde_core_uidle_setup_cfg(kms, enable); _sde_core_uidle_setup_ctl(crtc, enable); kms->perf.uidle_enabled = enable; exit: return rc; } static inline bool _sde_core_perf_is_wb(struct drm_crtc *crtc) { enum sde_intf_mode if_mode = INTF_MODE_NONE; if_mode = sde_crtc_get_intf_mode(crtc); if (if_mode == INTF_MODE_WB_BLOCK || if_mode == INTF_MODE_WB_LINE) return true; return false; } static bool _sde_core_perf_is_cwb(struct drm_crtc *crtc) { struct drm_encoder *encoder; /* if any other encoder is connected to same crtc in clone mode */ drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc == crtc && sde_encoder_in_clone_mode(encoder)) { return true; } } return false; } void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable) { struct drm_crtc *tmp_crtc; struct sde_kms *kms; bool disable_uidle = false; u32 fps; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } mutex_lock(&sde_core_perf_lock); if (!kms->perf.catalog->uidle_cfg.uidle_rev || !kms->perf.catalog->uidle_cfg.debugfs_ctrl) { SDE_DEBUG("uidle is not enabled %d %d\n", kms->perf.catalog->uidle_cfg.uidle_rev, kms->perf.catalog->uidle_cfg.debugfs_ctrl); goto exit; } drm_for_each_crtc(tmp_crtc, crtc->dev) { if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) { fps = sde_crtc_get_fps_mode(tmp_crtc); SDE_DEBUG("crtc=%d fps:%d wb:%d cwb:%d dis:%d en:%d\n", tmp_crtc->base.id, fps, _sde_core_perf_is_wb(tmp_crtc), _sde_core_perf_is_cwb(tmp_crtc), disable_uidle, enable); if (_sde_core_perf_is_wb(tmp_crtc) || _sde_core_perf_is_cwb(tmp_crtc) || (!fps || fps > kms->perf.catalog->uidle_cfg.max_fps)) { disable_uidle = true; break; } } } _sde_core_perf_enable_uidle(kms, crtc, (enable && !disable_uidle) ? true : false); exit: mutex_unlock(&sde_core_perf_lock); } static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms, struct drm_crtc *crtc, u32 bus_id) { Loading drivers/gpu/drm/msm/sde/sde_core_perf.h +9 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ struct sde_core_perf_tune { * @sde_rsc_available: is display rsc available * @bw_vote_mode_updated: bandwidth vote mode update * @llcc_active: status of the llcc, true if active. * @uidle_enabled: indicates if uidle is already enabled */ struct sde_core_perf { struct drm_device *dev; Loading @@ -82,6 +83,7 @@ struct sde_core_perf { bool sde_rsc_available; bool bw_vote_mode_updated; bool llcc_active; bool uidle_enabled; }; /** Loading @@ -108,6 +110,13 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, */ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc); /** * sde_core_perf_crtc_update_uidle - attempts to enable uidle of the given crtc * @crtc: Pointer to crtc * @enable: enable/disable uidle */ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable); /** * sde_core_perf_destroy - destroy the given core performance context * @perf: Pointer to core performance context Loading Loading
Documentation/devicetree/bindings/display/msm/sde.txt +6 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,9 @@ Optional properties: vbif blocks. These offsets will be calculated from register "vbif_phys" defined in reg property. - qcom,sde-vbif-size: A u32 value indicates the vbif block address range. - qcom,sde-uidle-off: A u32 value with the offset for the uidle block, from the "mdp_phys". - qcom,sde-uidle-size: A u32 value indicates the uidle block address range. - qcom,sde-te-off: A u32 offset indicates the te block offset on pingpong. This offset is 0x0 by default. - qcom,sde-te2-off: A u32 offset indicates the te2 block offset on pingpong. Loading Loading @@ -683,6 +686,9 @@ Example: qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; qcom,sde-uidle-off = <0x80000>; qcom,sde-uidle-size = <0x70>; qcom,sde-dram-channels = <2>; qcom,sde-num-nrt-paths = <1>; Loading
arch/arm64/boot/dts/qcom/kona-sde.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,9 @@ /* offsets are based off dspp 0 and dspp 1 */ qcom,sde-dspp-ltm-off = <0x2a000 0x28100>; qcom,sde-uidle-off = <0x80000>; qcom,sde-uidle-size = <0x70>; qcom,sde-vbif-off = <0>; qcom,sde-vbif-size = <0x1040>; qcom,sde-vbif-id = <0>; Loading
drivers/gpu/drm/msm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_reg_dma_v1_color_proc.o \ sde/sde_hw_color_proc_v4.o \ sde/sde_hw_ad4.o \ sde/sde_hw_uidle.o \ sde_edid_parser.o \ sde_hdcp_1x.o \ sde_hdcp_2x.o Loading
drivers/gpu/drm/msm/sde/sde_core_perf.c +168 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "sde_kms.h" #include "sde_trace.h" #include "sde_crtc.h" #include "sde_encoder.h" #include "sde_core_perf.h" #define SDE_PERF_MODE_STRING_SIZE 128 Loading Loading @@ -400,6 +401,173 @@ static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, total_llcc_active ? true : false); } static void _sde_core_uidle_setup_wd(struct sde_kms *kms, bool enable) { struct sde_uidle_wd_cfg wd; struct sde_hw_uidle *uidle; uidle = kms->hw_uidle; wd.enable = enable; wd.clear = false; wd.granularity = SDE_UIDLE_WD_GRANULARITY; wd.heart_beat = SDE_UIDLE_WD_HEART_BEAT; wd.load_value = SDE_UIDLE_WD_LOAD_VAL; if (uidle->ops.setup_wd_timer) uidle->ops.setup_wd_timer(uidle, &wd); } static void _sde_core_uidle_setup_cfg(struct sde_kms *kms, bool enable) { struct sde_uidle_ctl_cfg cfg; struct sde_hw_uidle *uidle; uidle = kms->hw_uidle; cfg.uidle_enable = enable; cfg.fal10_danger = kms->catalog->uidle_cfg.fal10_danger; cfg.fal10_exit_cnt = kms->catalog->uidle_cfg.fal10_exit_cnt; cfg.fal10_exit_danger = kms->catalog->uidle_cfg.fal10_exit_danger; SDE_DEBUG("fal10_danger:%d fal10_exit_cnt:%d fal10_exit_danger:%d\n", cfg.fal10_danger, cfg.fal10_exit_cnt, cfg.fal10_exit_danger); SDE_EVT32(enable, cfg.fal10_danger, cfg.fal10_exit_cnt, cfg.fal10_exit_danger); if (uidle->ops.set_uidle_ctl) uidle->ops.set_uidle_ctl(uidle, &cfg); } static void _sde_core_uidle_setup_ctl(struct drm_crtc *crtc, bool enable) { struct drm_encoder *drm_enc; /* Disable uidle in the CTL */ drm_for_each_encoder(drm_enc, crtc->dev) { if (drm_enc->crtc != crtc) continue; sde_encoder_uidle_enable(drm_enc, enable); } } static int _sde_core_perf_enable_uidle(struct sde_kms *kms, struct drm_crtc *crtc, bool enable) { int rc = 0; if (!kms->dev || !kms->dev->dev || !kms->hw_uidle) { SDE_ERROR("wrong params won't enable uidlen"); rc = -EINVAL; goto exit; } /* if no status change, just return */ if ((enable && kms->perf.uidle_enabled) || (!enable && !kms->perf.uidle_enabled)) { SDE_DEBUG("no status change enable:%d uidle:%d\n", enable, kms->perf.uidle_enabled); goto exit; } SDE_EVT32(enable); _sde_core_uidle_setup_wd(kms, enable); _sde_core_uidle_setup_cfg(kms, enable); _sde_core_uidle_setup_ctl(crtc, enable); kms->perf.uidle_enabled = enable; exit: return rc; } static inline bool _sde_core_perf_is_wb(struct drm_crtc *crtc) { enum sde_intf_mode if_mode = INTF_MODE_NONE; if_mode = sde_crtc_get_intf_mode(crtc); if (if_mode == INTF_MODE_WB_BLOCK || if_mode == INTF_MODE_WB_LINE) return true; return false; } static bool _sde_core_perf_is_cwb(struct drm_crtc *crtc) { struct drm_encoder *encoder; /* if any other encoder is connected to same crtc in clone mode */ drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc == crtc && sde_encoder_in_clone_mode(encoder)) { return true; } } return false; } void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable) { struct drm_crtc *tmp_crtc; struct sde_kms *kms; bool disable_uidle = false; u32 fps; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } mutex_lock(&sde_core_perf_lock); if (!kms->perf.catalog->uidle_cfg.uidle_rev || !kms->perf.catalog->uidle_cfg.debugfs_ctrl) { SDE_DEBUG("uidle is not enabled %d %d\n", kms->perf.catalog->uidle_cfg.uidle_rev, kms->perf.catalog->uidle_cfg.debugfs_ctrl); goto exit; } drm_for_each_crtc(tmp_crtc, crtc->dev) { if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) { fps = sde_crtc_get_fps_mode(tmp_crtc); SDE_DEBUG("crtc=%d fps:%d wb:%d cwb:%d dis:%d en:%d\n", tmp_crtc->base.id, fps, _sde_core_perf_is_wb(tmp_crtc), _sde_core_perf_is_cwb(tmp_crtc), disable_uidle, enable); if (_sde_core_perf_is_wb(tmp_crtc) || _sde_core_perf_is_cwb(tmp_crtc) || (!fps || fps > kms->perf.catalog->uidle_cfg.max_fps)) { disable_uidle = true; break; } } } _sde_core_perf_enable_uidle(kms, crtc, (enable && !disable_uidle) ? true : false); exit: mutex_unlock(&sde_core_perf_lock); } static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms, struct drm_crtc *crtc, u32 bus_id) { Loading
drivers/gpu/drm/msm/sde/sde_core_perf.h +9 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ struct sde_core_perf_tune { * @sde_rsc_available: is display rsc available * @bw_vote_mode_updated: bandwidth vote mode update * @llcc_active: status of the llcc, true if active. * @uidle_enabled: indicates if uidle is already enabled */ struct sde_core_perf { struct drm_device *dev; Loading @@ -82,6 +83,7 @@ struct sde_core_perf { bool sde_rsc_available; bool bw_vote_mode_updated; bool llcc_active; bool uidle_enabled; }; /** Loading @@ -108,6 +110,13 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, */ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc); /** * sde_core_perf_crtc_update_uidle - attempts to enable uidle of the given crtc * @crtc: Pointer to crtc * @enable: enable/disable uidle */ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable); /** * sde_core_perf_destroy - destroy the given core performance context * @perf: Pointer to core performance context Loading