Loading msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_IDLE_PC_STATE, CRTC_PROP_CACHE_STATE, /* total # of properties */ CRTC_PROP_COUNT Loading msm/msm_gem.c +6 −1 Original line number Diff line number Diff line Loading @@ -1223,9 +1223,14 @@ int msm_gem_delayed_import(struct drm_gem_object *obj) if (msm_obj->flags & MSM_BO_SKIPSYNC) attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; /* * All SMMU mapping are generated with cache hint. * SSPP cache hint will control the LLCC access. */ if (msm_obj->flags & MSM_BO_KEEPATTRS) attach->dma_map_attrs |= DMA_ATTR_IOMMU_USE_UPSTREAM_HINT; (DMA_ATTR_IOMMU_USE_UPSTREAM_HINT | DMA_ATTR_IOMMU_USE_LLC_NWA); /* * dma_buf_map_attachment will call dma_map_sg for ion buffer Loading msm/msm_smmu.c +3 −0 Original line number Diff line number Diff line Loading @@ -229,6 +229,9 @@ static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, return -ENOMEM; } if (flags & MSM_BO_KEEPATTRS) attrs |= DMA_ATTR_IOMMU_USE_LLC_NWA; /* * For import buffer type, dma_map_sg_attrs is called during * dma_buf_map_attachment and is not required to call again Loading msm/sde/sde_core_perf.c +179 −127 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "sde_trace.h" #include "sde_crtc.h" #include "sde_encoder.h" #include "sde_hw_catalog.h" #include "sde_core_perf.h" #define SDE_PERF_MODE_STRING_SIZE 128 Loading Loading @@ -293,19 +294,20 @@ static inline enum sde_crtc_client_type _get_sde_client_type( /** * @_sde_core_perf_activate_llcc() - Activates/deactivates the system llcc * @kms - pointer to the kms * @uid - ID for which the llcc would be activated * @type - llcc type to be activated * @activate - boolean to indicate if activate/deactivate the LLCC * * Function assumes that caller has already acquired the "sde_core_perf_lock", * which would protect from any race condition between CRTC's */ static int _sde_core_perf_activate_llcc(struct sde_kms *kms, u32 uid, bool activate) enum sde_sys_cache_type type, bool activate) { struct llcc_slice_desc *slice; struct drm_device *drm_dev; struct device *dev; struct platform_device *pdev; u32 llcc_id[SDE_SYS_CACHE_MAX] = {LLCC_ROTATOR, LLCC_DISP}; int rc = 0; if (!kms || !kms->dev || !kms->dev->dev) { Loading @@ -319,51 +321,57 @@ static int _sde_core_perf_activate_llcc(struct sde_kms *kms, pdev = to_platform_device(dev); /* If LLCC is already in the requested state, skip */ SDE_EVT32(activate, kms->perf.llcc_active); if ((activate && kms->perf.llcc_active) || (!activate && !kms->perf.llcc_active)) { SDE_DEBUG("skip llcc request:%d state:%d\n", activate, kms->perf.llcc_active); SDE_EVT32(activate, type, kms->perf.llcc_active[type]); if ((activate && kms->perf.llcc_active[type]) || (!activate && !kms->perf.llcc_active[type])) { SDE_DEBUG("skip llcc type:%d request:%d state:%d\n", type, activate, kms->perf.llcc_active[type]); goto exit; } SDE_DEBUG("activate/deactivate the llcc request:%d state:%d\n", activate, kms->perf.llcc_active); SDE_DEBUG("%sactivate the llcc type:%d state:%d\n", activate ? "" : "de", type, kms->perf.llcc_active[type]); slice = llcc_slice_getd(uid); slice = llcc_slice_getd(llcc_id[type]); if (IS_ERR_OR_NULL(slice)) { SDE_ERROR("failed to get llcc slice for uid:%d\n", uid); SDE_ERROR("failed to get llcc slice for uid:%d\n", llcc_id[type]); rc = -EINVAL; goto exit; } if (activate) { llcc_slice_activate(slice); kms->perf.llcc_active = true; kms->perf.llcc_active[type] = true; } else { llcc_slice_deactivate(slice); kms->perf.llcc_active = false; kms->perf.llcc_active[type] = false; } exit: if (rc) SDE_ERROR("error activating llcc:%d rc:%d\n", activate, rc); SDE_ERROR("error %sactivating llcc type:%d rc:%d\n", activate ? "" : "de", type, rc); return rc; } static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, struct drm_crtc *crtc) static void _sde_core_perf_crtc_set_llcc_cache_type(struct sde_kms *kms, struct drm_crtc *crtc, enum sde_sys_cache_type type) { struct drm_crtc *tmp_crtc; struct sde_crtc *sde_crtc; struct sde_sc_cfg *sc_cfg = kms->perf.catalog->sc_cfg; struct sde_core_perf_params *cur_perf; enum sde_crtc_client_type curr_client_type = sde_crtc_get_client_type(crtc); u32 total_llcc_active = 0; u32 llcc_active = 0; if (!kms->perf.catalog->sc_cfg.has_sys_cache) { SDE_DEBUG("System Cache is not enabled!. Won't use\n"); if (!sc_cfg[type].has_sys_cache) { SDE_DEBUG("System Cache %d is not enabled!. Won't use\n", type); return; } Loading @@ -374,23 +382,72 @@ static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, /* use current perf, which are the values voted */ sde_crtc = to_sde_crtc(tmp_crtc); total_llcc_active |= sde_crtc->cur_perf.llcc_active; cur_perf = &sde_crtc->cur_perf; llcc_active |= cur_perf->llcc_active[type]; SDE_DEBUG("crtc=%d llcc:%u active:0x%x\n", tmp_crtc->base.id, sde_crtc->cur_perf.llcc_active, total_llcc_active); SDE_DEBUG("crtc=%d type:%d llcc:%u active:0x%x\n", tmp_crtc->base.id, type, cur_perf->llcc_active[type], llcc_active); } } if (total_llcc_active) break; _sde_core_perf_activate_llcc(kms, type, llcc_active ? true : false); } void sde_core_perf_crtc_update_llcc(struct drm_crtc *crtc) { struct sde_kms *kms; struct sde_crtc *sde_crtc; struct sde_core_perf_params *old, *new; int update_llcc[SDE_SYS_CACHE_MAX] = {0, 0}; int i; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } _sde_core_perf_activate_llcc(kms, LLCC_ROTATOR, total_llcc_active ? true : false); kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } sde_crtc = to_sde_crtc(crtc); old = &sde_crtc->cur_perf; new = &sde_crtc->new_perf; mutex_lock(&sde_core_perf_lock); if (_sde_core_perf_crtc_is_power_on(crtc)) { for (i = 0; i < SDE_SYS_CACHE_MAX; i++) { if (new->llcc_active[i] != old->llcc_active[i]) { SDE_DEBUG("crtc=%d llcc=%d new=%d old=%d", crtc->base.id, i, new->llcc_active[i], old->llcc_active[i]); old->llcc_active[i] = new->llcc_active[i]; update_llcc[i] = 1; } } } else { for (i = 0; i < SDE_SYS_CACHE_MAX; i++) update_llcc[i] = 1; } for (i = 0; i < SDE_SYS_CACHE_MAX; i++) { if (update_llcc[i]) _sde_core_perf_crtc_set_llcc_cache_type(kms, crtc, i); } mutex_unlock(&sde_core_perf_lock); }; static void _sde_core_uidle_setup_wd(struct sde_kms *kms, bool enable) { Loading Loading @@ -749,71 +806,15 @@ static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms) return clk_rate; } void sde_core_perf_crtc_update(struct drm_crtc *crtc, int params_changed, bool stop_req) static void _sde_core_perf_crtc_update_check(struct drm_crtc *crtc, int params_changed, int *update_bus, int *update_clk) { struct sde_core_perf_params *new, *old; int update_bus = 0, update_clk = 0, update_llcc = 0; u64 clk_rate = 0; struct sde_crtc *sde_crtc; struct sde_crtc_state *sde_cstate; int ret, i; struct msm_drm_private *priv; struct sde_kms *kms; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } priv = kms->dev->dev_private; sde_crtc = to_sde_crtc(crtc); sde_cstate = to_sde_crtc_state(crtc->state); SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n", crtc->base.id, stop_req, kms->perf.core_clk_rate); mutex_lock(&sde_core_perf_lock); /* * cache the performance numbers in the crtc prior to the * crtc kickoff, so the same numbers are used during the * perf update that happens post kickoff. */ if (params_changed) memcpy(&sde_crtc->new_perf, &sde_cstate->new_perf, sizeof(struct sde_core_perf_params)); old = &sde_crtc->cur_perf; new = &sde_crtc->new_perf; if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) { /* * cases for the llcc update. * 1. llcc is transitioning: 'inactive->active' during kickoff, * for current request. * 2. llcc is transitioning: 'active->inactive'at the end of the * commit or during stop */ if ((params_changed && new->llcc_active && !old->llcc_active) || (!params_changed && !new->llcc_active && old->llcc_active)) { SDE_DEBUG("crtc=%d p=%d new_llcc=%d, old_llcc=%d\n", crtc->base.id, params_changed, new->llcc_active, old->llcc_active); old->llcc_active = new->llcc_active; update_llcc = 1; } struct sde_kms *kms = _sde_crtc_get_kms(crtc); struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct sde_core_perf_params *old = &sde_crtc->cur_perf; struct sde_core_perf_params *new = &sde_crtc->new_perf; int i; for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { /* Loading @@ -834,7 +835,7 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, crtc->base.id, params_changed, new->bw_ctl[i], old->bw_ctl[i]); old->bw_ctl[i] = new->bw_ctl[i]; update_bus |= BIT(i); *update_bus |= BIT(i); } if ((params_changed && Loading @@ -851,7 +852,7 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, old->max_per_pipe_ib[i]); old->max_per_pipe_ib[i] = new->max_per_pipe_ib[i]; update_bus |= BIT(i); *update_bus |= BIT(i); } /* display rsc override during solver mode */ Loading @@ -866,31 +867,84 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, old->bw_ctl[i] = new->bw_ctl[i]; old->max_per_pipe_ib[i] = new->max_per_pipe_ib[i]; update_bus |= BIT(i); *update_bus |= BIT(i); /* * reduce bw vote is not required in solver * mode */ } else if (!params_changed) { update_bus &= ~BIT(i); *update_bus &= ~BIT(i); } } } if (kms->perf.perf_tune.mode_changed && kms->perf.perf_tune.min_core_clk) new->core_clk_rate = kms->perf.perf_tune.min_core_clk; if ((params_changed && (new->core_clk_rate > old->core_clk_rate)) || (!params_changed && new->core_clk_rate && (new->core_clk_rate < old->core_clk_rate))) { (new->core_clk_rate < old->core_clk_rate)) || kms->perf.perf_tune.mode_changed) { old->core_clk_rate = new->core_clk_rate; update_clk = 1; *update_clk = 1; kms->perf.perf_tune.mode_changed = false; } } void sde_core_perf_crtc_update(struct drm_crtc *crtc, int params_changed, bool stop_req) { struct sde_core_perf_params *new, *old; int update_bus = 0, update_clk = 0; u64 clk_rate = 0; struct sde_crtc *sde_crtc; struct sde_crtc_state *sde_cstate; int ret, i; struct msm_drm_private *priv; struct sde_kms *kms; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } priv = kms->dev->dev_private; sde_crtc = to_sde_crtc(crtc); sde_cstate = to_sde_crtc_state(crtc->state); SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n", crtc->base.id, stop_req, kms->perf.core_clk_rate); mutex_lock(&sde_core_perf_lock); /* * cache the performance numbers in the crtc prior to the * crtc kickoff, so the same numbers are used during the * perf update that happens post kickoff. */ if (params_changed) memcpy(&sde_crtc->new_perf, &sde_cstate->new_perf, sizeof(struct sde_core_perf_params)); old = &sde_crtc->cur_perf; new = &sde_crtc->new_perf; if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) { _sde_core_perf_crtc_update_check(crtc, params_changed, &update_bus, &update_clk); } else { SDE_DEBUG("crtc=%d disable\n", crtc->base.id); memset(old, 0, sizeof(*old)); memset(new, 0, sizeof(*new)); update_bus = ~0; update_clk = 1; update_llcc = 1; } trace_sde_perf_crtc_update(crtc->base.id, new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC], Loading @@ -902,9 +956,6 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, new->core_clk_rate, stop_req, update_bus, update_clk, params_changed); if (update_llcc) _sde_core_perf_crtc_update_llcc(kms, crtc); for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { if (update_bus & BIT(i)) _sde_core_perf_crtc_update_bus(kms, crtc, i); Loading Loading @@ -1056,6 +1107,7 @@ static ssize_t _sde_core_perf_mode_write(struct file *file, DRM_INFO("normal performance mode\n"); } perf->perf_tune.mode = perf_mode; perf->perf_tune.mode_changed = true; return count; } Loading msm/sde/sde_core_perf.h +10 −2 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ struct sde_core_perf_params { u64 max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MAX]; u64 bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MAX]; u64 core_clk_rate; bool llcc_active; bool llcc_active[SDE_SYS_CACHE_MAX]; }; /** Loading @@ -47,11 +47,13 @@ struct sde_core_perf_params { * @mode: performance mode * @min_core_clk: minimum core clock * @min_bus_vote: minimum bus vote * @mode_changed: indicate if clock tuning strategy changed */ struct sde_core_perf_tune { u32 mode; u64 min_core_clk; u64 min_bus_vote; bool mode_changed; }; /** Loading Loading @@ -92,10 +94,16 @@ struct sde_core_perf { u32 bw_vote_mode; bool sde_rsc_available; bool bw_vote_mode_updated; bool llcc_active; bool llcc_active[SDE_SYS_CACHE_MAX]; bool uidle_enabled; }; /** * sde_core_perf_crtc_update_llcc - update llcc performance for crtc * @crtc: Pointer to crtc */ void sde_core_perf_crtc_update_llcc(struct drm_crtc *crtc); /** * sde_core_perf_crtc_check - validate performance of the given crtc state * @crtc: Pointer to crtc Loading Loading
msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_IDLE_PC_STATE, CRTC_PROP_CACHE_STATE, /* total # of properties */ CRTC_PROP_COUNT Loading
msm/msm_gem.c +6 −1 Original line number Diff line number Diff line Loading @@ -1223,9 +1223,14 @@ int msm_gem_delayed_import(struct drm_gem_object *obj) if (msm_obj->flags & MSM_BO_SKIPSYNC) attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; /* * All SMMU mapping are generated with cache hint. * SSPP cache hint will control the LLCC access. */ if (msm_obj->flags & MSM_BO_KEEPATTRS) attach->dma_map_attrs |= DMA_ATTR_IOMMU_USE_UPSTREAM_HINT; (DMA_ATTR_IOMMU_USE_UPSTREAM_HINT | DMA_ATTR_IOMMU_USE_LLC_NWA); /* * dma_buf_map_attachment will call dma_map_sg for ion buffer Loading
msm/msm_smmu.c +3 −0 Original line number Diff line number Diff line Loading @@ -229,6 +229,9 @@ static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, return -ENOMEM; } if (flags & MSM_BO_KEEPATTRS) attrs |= DMA_ATTR_IOMMU_USE_LLC_NWA; /* * For import buffer type, dma_map_sg_attrs is called during * dma_buf_map_attachment and is not required to call again Loading
msm/sde/sde_core_perf.c +179 −127 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "sde_trace.h" #include "sde_crtc.h" #include "sde_encoder.h" #include "sde_hw_catalog.h" #include "sde_core_perf.h" #define SDE_PERF_MODE_STRING_SIZE 128 Loading Loading @@ -293,19 +294,20 @@ static inline enum sde_crtc_client_type _get_sde_client_type( /** * @_sde_core_perf_activate_llcc() - Activates/deactivates the system llcc * @kms - pointer to the kms * @uid - ID for which the llcc would be activated * @type - llcc type to be activated * @activate - boolean to indicate if activate/deactivate the LLCC * * Function assumes that caller has already acquired the "sde_core_perf_lock", * which would protect from any race condition between CRTC's */ static int _sde_core_perf_activate_llcc(struct sde_kms *kms, u32 uid, bool activate) enum sde_sys_cache_type type, bool activate) { struct llcc_slice_desc *slice; struct drm_device *drm_dev; struct device *dev; struct platform_device *pdev; u32 llcc_id[SDE_SYS_CACHE_MAX] = {LLCC_ROTATOR, LLCC_DISP}; int rc = 0; if (!kms || !kms->dev || !kms->dev->dev) { Loading @@ -319,51 +321,57 @@ static int _sde_core_perf_activate_llcc(struct sde_kms *kms, pdev = to_platform_device(dev); /* If LLCC is already in the requested state, skip */ SDE_EVT32(activate, kms->perf.llcc_active); if ((activate && kms->perf.llcc_active) || (!activate && !kms->perf.llcc_active)) { SDE_DEBUG("skip llcc request:%d state:%d\n", activate, kms->perf.llcc_active); SDE_EVT32(activate, type, kms->perf.llcc_active[type]); if ((activate && kms->perf.llcc_active[type]) || (!activate && !kms->perf.llcc_active[type])) { SDE_DEBUG("skip llcc type:%d request:%d state:%d\n", type, activate, kms->perf.llcc_active[type]); goto exit; } SDE_DEBUG("activate/deactivate the llcc request:%d state:%d\n", activate, kms->perf.llcc_active); SDE_DEBUG("%sactivate the llcc type:%d state:%d\n", activate ? "" : "de", type, kms->perf.llcc_active[type]); slice = llcc_slice_getd(uid); slice = llcc_slice_getd(llcc_id[type]); if (IS_ERR_OR_NULL(slice)) { SDE_ERROR("failed to get llcc slice for uid:%d\n", uid); SDE_ERROR("failed to get llcc slice for uid:%d\n", llcc_id[type]); rc = -EINVAL; goto exit; } if (activate) { llcc_slice_activate(slice); kms->perf.llcc_active = true; kms->perf.llcc_active[type] = true; } else { llcc_slice_deactivate(slice); kms->perf.llcc_active = false; kms->perf.llcc_active[type] = false; } exit: if (rc) SDE_ERROR("error activating llcc:%d rc:%d\n", activate, rc); SDE_ERROR("error %sactivating llcc type:%d rc:%d\n", activate ? "" : "de", type, rc); return rc; } static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, struct drm_crtc *crtc) static void _sde_core_perf_crtc_set_llcc_cache_type(struct sde_kms *kms, struct drm_crtc *crtc, enum sde_sys_cache_type type) { struct drm_crtc *tmp_crtc; struct sde_crtc *sde_crtc; struct sde_sc_cfg *sc_cfg = kms->perf.catalog->sc_cfg; struct sde_core_perf_params *cur_perf; enum sde_crtc_client_type curr_client_type = sde_crtc_get_client_type(crtc); u32 total_llcc_active = 0; u32 llcc_active = 0; if (!kms->perf.catalog->sc_cfg.has_sys_cache) { SDE_DEBUG("System Cache is not enabled!. Won't use\n"); if (!sc_cfg[type].has_sys_cache) { SDE_DEBUG("System Cache %d is not enabled!. Won't use\n", type); return; } Loading @@ -374,23 +382,72 @@ static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, /* use current perf, which are the values voted */ sde_crtc = to_sde_crtc(tmp_crtc); total_llcc_active |= sde_crtc->cur_perf.llcc_active; cur_perf = &sde_crtc->cur_perf; llcc_active |= cur_perf->llcc_active[type]; SDE_DEBUG("crtc=%d llcc:%u active:0x%x\n", tmp_crtc->base.id, sde_crtc->cur_perf.llcc_active, total_llcc_active); SDE_DEBUG("crtc=%d type:%d llcc:%u active:0x%x\n", tmp_crtc->base.id, type, cur_perf->llcc_active[type], llcc_active); } } if (total_llcc_active) break; _sde_core_perf_activate_llcc(kms, type, llcc_active ? true : false); } void sde_core_perf_crtc_update_llcc(struct drm_crtc *crtc) { struct sde_kms *kms; struct sde_crtc *sde_crtc; struct sde_core_perf_params *old, *new; int update_llcc[SDE_SYS_CACHE_MAX] = {0, 0}; int i; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } _sde_core_perf_activate_llcc(kms, LLCC_ROTATOR, total_llcc_active ? true : false); kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } sde_crtc = to_sde_crtc(crtc); old = &sde_crtc->cur_perf; new = &sde_crtc->new_perf; mutex_lock(&sde_core_perf_lock); if (_sde_core_perf_crtc_is_power_on(crtc)) { for (i = 0; i < SDE_SYS_CACHE_MAX; i++) { if (new->llcc_active[i] != old->llcc_active[i]) { SDE_DEBUG("crtc=%d llcc=%d new=%d old=%d", crtc->base.id, i, new->llcc_active[i], old->llcc_active[i]); old->llcc_active[i] = new->llcc_active[i]; update_llcc[i] = 1; } } } else { for (i = 0; i < SDE_SYS_CACHE_MAX; i++) update_llcc[i] = 1; } for (i = 0; i < SDE_SYS_CACHE_MAX; i++) { if (update_llcc[i]) _sde_core_perf_crtc_set_llcc_cache_type(kms, crtc, i); } mutex_unlock(&sde_core_perf_lock); }; static void _sde_core_uidle_setup_wd(struct sde_kms *kms, bool enable) { Loading Loading @@ -749,71 +806,15 @@ static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms) return clk_rate; } void sde_core_perf_crtc_update(struct drm_crtc *crtc, int params_changed, bool stop_req) static void _sde_core_perf_crtc_update_check(struct drm_crtc *crtc, int params_changed, int *update_bus, int *update_clk) { struct sde_core_perf_params *new, *old; int update_bus = 0, update_clk = 0, update_llcc = 0; u64 clk_rate = 0; struct sde_crtc *sde_crtc; struct sde_crtc_state *sde_cstate; int ret, i; struct msm_drm_private *priv; struct sde_kms *kms; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } priv = kms->dev->dev_private; sde_crtc = to_sde_crtc(crtc); sde_cstate = to_sde_crtc_state(crtc->state); SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n", crtc->base.id, stop_req, kms->perf.core_clk_rate); mutex_lock(&sde_core_perf_lock); /* * cache the performance numbers in the crtc prior to the * crtc kickoff, so the same numbers are used during the * perf update that happens post kickoff. */ if (params_changed) memcpy(&sde_crtc->new_perf, &sde_cstate->new_perf, sizeof(struct sde_core_perf_params)); old = &sde_crtc->cur_perf; new = &sde_crtc->new_perf; if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) { /* * cases for the llcc update. * 1. llcc is transitioning: 'inactive->active' during kickoff, * for current request. * 2. llcc is transitioning: 'active->inactive'at the end of the * commit or during stop */ if ((params_changed && new->llcc_active && !old->llcc_active) || (!params_changed && !new->llcc_active && old->llcc_active)) { SDE_DEBUG("crtc=%d p=%d new_llcc=%d, old_llcc=%d\n", crtc->base.id, params_changed, new->llcc_active, old->llcc_active); old->llcc_active = new->llcc_active; update_llcc = 1; } struct sde_kms *kms = _sde_crtc_get_kms(crtc); struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct sde_core_perf_params *old = &sde_crtc->cur_perf; struct sde_core_perf_params *new = &sde_crtc->new_perf; int i; for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { /* Loading @@ -834,7 +835,7 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, crtc->base.id, params_changed, new->bw_ctl[i], old->bw_ctl[i]); old->bw_ctl[i] = new->bw_ctl[i]; update_bus |= BIT(i); *update_bus |= BIT(i); } if ((params_changed && Loading @@ -851,7 +852,7 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, old->max_per_pipe_ib[i]); old->max_per_pipe_ib[i] = new->max_per_pipe_ib[i]; update_bus |= BIT(i); *update_bus |= BIT(i); } /* display rsc override during solver mode */ Loading @@ -866,31 +867,84 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, old->bw_ctl[i] = new->bw_ctl[i]; old->max_per_pipe_ib[i] = new->max_per_pipe_ib[i]; update_bus |= BIT(i); *update_bus |= BIT(i); /* * reduce bw vote is not required in solver * mode */ } else if (!params_changed) { update_bus &= ~BIT(i); *update_bus &= ~BIT(i); } } } if (kms->perf.perf_tune.mode_changed && kms->perf.perf_tune.min_core_clk) new->core_clk_rate = kms->perf.perf_tune.min_core_clk; if ((params_changed && (new->core_clk_rate > old->core_clk_rate)) || (!params_changed && new->core_clk_rate && (new->core_clk_rate < old->core_clk_rate))) { (new->core_clk_rate < old->core_clk_rate)) || kms->perf.perf_tune.mode_changed) { old->core_clk_rate = new->core_clk_rate; update_clk = 1; *update_clk = 1; kms->perf.perf_tune.mode_changed = false; } } void sde_core_perf_crtc_update(struct drm_crtc *crtc, int params_changed, bool stop_req) { struct sde_core_perf_params *new, *old; int update_bus = 0, update_clk = 0; u64 clk_rate = 0; struct sde_crtc *sde_crtc; struct sde_crtc_state *sde_cstate; int ret, i; struct msm_drm_private *priv; struct sde_kms *kms; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } kms = _sde_crtc_get_kms(crtc); if (!kms || !kms->catalog) { SDE_ERROR("invalid kms\n"); return; } priv = kms->dev->dev_private; sde_crtc = to_sde_crtc(crtc); sde_cstate = to_sde_crtc_state(crtc->state); SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n", crtc->base.id, stop_req, kms->perf.core_clk_rate); mutex_lock(&sde_core_perf_lock); /* * cache the performance numbers in the crtc prior to the * crtc kickoff, so the same numbers are used during the * perf update that happens post kickoff. */ if (params_changed) memcpy(&sde_crtc->new_perf, &sde_cstate->new_perf, sizeof(struct sde_core_perf_params)); old = &sde_crtc->cur_perf; new = &sde_crtc->new_perf; if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) { _sde_core_perf_crtc_update_check(crtc, params_changed, &update_bus, &update_clk); } else { SDE_DEBUG("crtc=%d disable\n", crtc->base.id); memset(old, 0, sizeof(*old)); memset(new, 0, sizeof(*new)); update_bus = ~0; update_clk = 1; update_llcc = 1; } trace_sde_perf_crtc_update(crtc->base.id, new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC], Loading @@ -902,9 +956,6 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, new->core_clk_rate, stop_req, update_bus, update_clk, params_changed); if (update_llcc) _sde_core_perf_crtc_update_llcc(kms, crtc); for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { if (update_bus & BIT(i)) _sde_core_perf_crtc_update_bus(kms, crtc, i); Loading Loading @@ -1056,6 +1107,7 @@ static ssize_t _sde_core_perf_mode_write(struct file *file, DRM_INFO("normal performance mode\n"); } perf->perf_tune.mode = perf_mode; perf->perf_tune.mode_changed = true; return count; } Loading
msm/sde/sde_core_perf.h +10 −2 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ struct sde_core_perf_params { u64 max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MAX]; u64 bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MAX]; u64 core_clk_rate; bool llcc_active; bool llcc_active[SDE_SYS_CACHE_MAX]; }; /** Loading @@ -47,11 +47,13 @@ struct sde_core_perf_params { * @mode: performance mode * @min_core_clk: minimum core clock * @min_bus_vote: minimum bus vote * @mode_changed: indicate if clock tuning strategy changed */ struct sde_core_perf_tune { u32 mode; u64 min_core_clk; u64 min_bus_vote; bool mode_changed; }; /** Loading Loading @@ -92,10 +94,16 @@ struct sde_core_perf { u32 bw_vote_mode; bool sde_rsc_available; bool bw_vote_mode_updated; bool llcc_active; bool llcc_active[SDE_SYS_CACHE_MAX]; bool uidle_enabled; }; /** * sde_core_perf_crtc_update_llcc - update llcc performance for crtc * @crtc: Pointer to crtc */ void sde_core_perf_crtc_update_llcc(struct drm_crtc *crtc); /** * sde_core_perf_crtc_check - validate performance of the given crtc state * @crtc: Pointer to crtc Loading