Loading drivers/gpu/drm/msm/sde/sde_core_perf.c +131 −2 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #include <linux/clk.h> #include <linux/bitmap.h> #include <linux/sde_rsc.h> #include <linux/platform_device.h> #include <linux/soc/qcom/llcc-qcom.h> #include "msm_prop.h" Loading Loading @@ -297,6 +299,107 @@ static inline enum sde_crtc_client_type _get_sde_client_type( return RT_CLIENT; } /** * @_sde_core_perf_activate_llcc() - Activates/deactivates the system llcc * @kms - pointer to the kms * @uid - ID for which the llcc would 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) { struct llcc_slice_desc *slice; struct drm_device *drm_dev; struct device *dev; struct platform_device *pdev; int rc = 0; if (!kms || !kms->dev || !kms->dev->dev) { SDE_ERROR("wrong params won't activate llcc\n"); rc = -EINVAL; goto exit; } drm_dev = kms->dev; dev = drm_dev->dev; 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); goto exit; } SDE_DEBUG("activate/deactivate the llcc request:%d state:%d\n", activate, kms->perf.llcc_active); slice = llcc_slice_getd(uid); if (IS_ERR_OR_NULL(slice)) { SDE_ERROR("failed to get llcc slice for uid:%d\n", uid); rc = -EINVAL; goto exit; } if (activate) { llcc_slice_activate(slice); kms->perf.llcc_active = true; } else { llcc_slice_deactivate(slice); kms->perf.llcc_active = false; } exit: if (rc) SDE_ERROR("error activating llcc:%d rc:%d\n", activate, rc); return rc; } static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, struct drm_crtc *crtc) { struct drm_crtc *tmp_crtc; struct sde_crtc *sde_crtc; enum sde_crtc_client_type curr_client_type = sde_crtc_get_client_type(crtc); u32 total_llcc_active = 0; if (!kms->perf.catalog->sc_cfg.has_sys_cache) { SDE_DEBUG("System Cache is not enabled!. Won't use\n"); return; } drm_for_each_crtc(tmp_crtc, crtc->dev) { if (_sde_core_perf_crtc_is_power_on(tmp_crtc) && _is_crtc_client_type_matches(tmp_crtc, curr_client_type, &kms->perf)) { /* use current perf, which are the values voted */ sde_crtc = to_sde_crtc(tmp_crtc); total_llcc_active |= sde_crtc->cur_perf.llcc_active; SDE_DEBUG("crtc=%d llcc:%llu active:0x%x\n", tmp_crtc->base.id, sde_crtc->cur_perf.llcc_active, total_llcc_active); if (total_llcc_active) break; } } _sde_core_perf_activate_llcc(kms, LLCC_ROTATOR, total_llcc_active ? true : false); } static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms, struct drm_crtc *crtc, u32 bus_id) { Loading Loading @@ -494,7 +597,7 @@ 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; 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; Loading Loading @@ -534,6 +637,28 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, 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; } for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { /* * cases for bus bandwidth update. Loading Loading @@ -604,11 +729,12 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, update_clk = 1; } } else { SDE_DEBUG("crtc=%d disable\n", crtc->base.id); SDE_ERROR("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 @@ -620,6 +746,9 @@ 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 drivers/gpu/drm/msm/sde/sde_core_perf.h +4 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ * @max_per_pipe_ib: maximum instantaneous bandwidth request * @bw_ctl: arbitrated bandwidth request * @core_clk_rate: core clock rate request * @llcc_active: request to activate/deactivate the llcc */ 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; }; /** Loading Loading @@ -59,6 +61,7 @@ struct sde_core_perf_tune { * @bw_vote_mode: apps rsc vs display rsc bandwidth vote mode * @sde_rsc_available: is display rsc available * @bw_vote_mode_updated: bandwidth vote mode update * @llcc_active: status of the llcc, true if active. */ struct sde_core_perf { struct drm_device *dev; Loading @@ -78,6 +81,7 @@ struct sde_core_perf { u32 bw_vote_mode; bool sde_rsc_available; bool bw_vote_mode_updated; bool llcc_active; }; /** Loading drivers/gpu/drm/msm/sde/sde_crtc.c +19 −2 Original line number Diff line number Diff line Loading @@ -1234,7 +1234,8 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, state->src_x >> 16, state->src_y >> 16, state->src_w >> 16, state->src_h >> 16, state->crtc_x, state->crtc_y, state->crtc_w, state->crtc_h); state->crtc_w, state->crtc_h, pstate->rotation); stage_idx = zpos_cnt[pstate->stage]++; stage_cfg->stage[pstate->stage][stage_idx] = Loading Loading @@ -2965,10 +2966,18 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, * required. However, if those planes were power collapsed since * last commit cycle, driver has to restore the hardware state * of those planes explicitly here prior to plane flush. * Also use this iteration to see if any plane requires cache, * so during the perf update driver can activate/deactivate * the cache accordingly. */ drm_atomic_crtc_for_each_plane(plane, crtc) sde_crtc->new_perf.llcc_active = false; drm_atomic_crtc_for_each_plane(plane, crtc) { sde_plane_restore(plane); if (sde_plane_is_cache_required(plane)) sde_crtc->new_perf.llcc_active = true; } /* wait for acquire fences before anything else is done */ _sde_crtc_wait_for_fences(crtc); Loading Loading @@ -5737,9 +5746,17 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_cp_crtc_init(crtc); sde_cp_crtc_install_properties(crtc); sde_crtc->cur_perf.llcc_active = false; sde_crtc->new_perf.llcc_active = false; kthread_init_delayed_work(&sde_crtc->idle_notify_work, __sde_crtc_idle_notify_work); SDE_DEBUG("crtc=%d new_llcc=%d, old_llcc=%d\n", crtc->base.id, sde_crtc->new_perf.llcc_active, sde_crtc->cur_perf.llcc_active); SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name); return crtc; } Loading drivers/gpu/drm/msm/sde/sde_formats.c +45 −0 Original line number Diff line number Diff line Loading @@ -642,6 +642,16 @@ static const struct sde_format sde_format_map_tp10_ubwc[] = { SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12), }; inline bool sde_format_is_tp10_ubwc(const struct sde_format *fmt) { if (SDE_FORMAT_IS_YUV(fmt) && SDE_FORMAT_IS_DX(fmt) && SDE_FORMAT_IS_UBWC(fmt) && (fmt->num_planes == 4) && fmt->unpack_tight) return true; else return false; } /* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support * Note: Not using the drm_format_*_subsampling since we have formats */ Loading Loading @@ -1334,3 +1344,38 @@ uint32_t sde_populate_formats( return i; } int sde_format_validate_fmt(struct msm_kms *kms, const struct msm_format *msm_fmt, const struct sde_format_extended *fmt_list) { const struct msm_format *fmt_tmp; bool valid_format = false; int ret = 0; if (!msm_fmt || !fmt_list) { SDE_ERROR("invalid fmt:%d list:%d\n", !msm_fmt, !fmt_list); ret = -EINVAL; goto exit; } while (fmt_list->fourcc_format) { fmt_tmp = sde_get_msm_format(kms, fmt_list->fourcc_format, fmt_list->modifier); if (fmt_tmp && (fmt_tmp->pixel_format == msm_fmt->pixel_format)) { valid_format = true; break; } ++fmt_list; } if (!valid_format) { SDE_ERROR("fmt:%d not found within the list!\n", *msm_fmt); ret = -EINVAL; } exit: return ret; } drivers/gpu/drm/msm/sde/sde_formats.h +21 −0 Original line number Diff line number Diff line Loading @@ -142,4 +142,25 @@ uint32_t sde_format_get_framebuffer_size( const uint32_t *pitches, const uint64_t modifier); /** * sde_format_is_tp10_ubwc - check if the format is tp10 ubwc * @format: DRM pixel format * * Return: returns true if the format is tp10 ubwc, otherwise false. */ inline bool sde_format_is_tp10_ubwc(const struct sde_format *fmt); /** * sde_format_validate_fmt - validates if the format "msm_fmt" is within * the list "fmt_list" * @kms: pointer to the kms object * @msm_fmt: pointer to the format to look within the list * @fmt_list: list where driver will loop to look for the 'msm_fmt' format. * @result: returns 0 if the format is found, otherwise will return an * error code. */ int sde_format_validate_fmt(struct msm_kms *kms, const struct msm_format *msm_fmt, const struct sde_format_extended *fmt_list); #endif /*_SDE_FORMATS_H */ Loading
drivers/gpu/drm/msm/sde/sde_core_perf.c +131 −2 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #include <linux/clk.h> #include <linux/bitmap.h> #include <linux/sde_rsc.h> #include <linux/platform_device.h> #include <linux/soc/qcom/llcc-qcom.h> #include "msm_prop.h" Loading Loading @@ -297,6 +299,107 @@ static inline enum sde_crtc_client_type _get_sde_client_type( return RT_CLIENT; } /** * @_sde_core_perf_activate_llcc() - Activates/deactivates the system llcc * @kms - pointer to the kms * @uid - ID for which the llcc would 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) { struct llcc_slice_desc *slice; struct drm_device *drm_dev; struct device *dev; struct platform_device *pdev; int rc = 0; if (!kms || !kms->dev || !kms->dev->dev) { SDE_ERROR("wrong params won't activate llcc\n"); rc = -EINVAL; goto exit; } drm_dev = kms->dev; dev = drm_dev->dev; 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); goto exit; } SDE_DEBUG("activate/deactivate the llcc request:%d state:%d\n", activate, kms->perf.llcc_active); slice = llcc_slice_getd(uid); if (IS_ERR_OR_NULL(slice)) { SDE_ERROR("failed to get llcc slice for uid:%d\n", uid); rc = -EINVAL; goto exit; } if (activate) { llcc_slice_activate(slice); kms->perf.llcc_active = true; } else { llcc_slice_deactivate(slice); kms->perf.llcc_active = false; } exit: if (rc) SDE_ERROR("error activating llcc:%d rc:%d\n", activate, rc); return rc; } static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, struct drm_crtc *crtc) { struct drm_crtc *tmp_crtc; struct sde_crtc *sde_crtc; enum sde_crtc_client_type curr_client_type = sde_crtc_get_client_type(crtc); u32 total_llcc_active = 0; if (!kms->perf.catalog->sc_cfg.has_sys_cache) { SDE_DEBUG("System Cache is not enabled!. Won't use\n"); return; } drm_for_each_crtc(tmp_crtc, crtc->dev) { if (_sde_core_perf_crtc_is_power_on(tmp_crtc) && _is_crtc_client_type_matches(tmp_crtc, curr_client_type, &kms->perf)) { /* use current perf, which are the values voted */ sde_crtc = to_sde_crtc(tmp_crtc); total_llcc_active |= sde_crtc->cur_perf.llcc_active; SDE_DEBUG("crtc=%d llcc:%llu active:0x%x\n", tmp_crtc->base.id, sde_crtc->cur_perf.llcc_active, total_llcc_active); if (total_llcc_active) break; } } _sde_core_perf_activate_llcc(kms, LLCC_ROTATOR, total_llcc_active ? true : false); } static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms, struct drm_crtc *crtc, u32 bus_id) { Loading Loading @@ -494,7 +597,7 @@ 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; 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; Loading Loading @@ -534,6 +637,28 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, 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; } for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { /* * cases for bus bandwidth update. Loading Loading @@ -604,11 +729,12 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc, update_clk = 1; } } else { SDE_DEBUG("crtc=%d disable\n", crtc->base.id); SDE_ERROR("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 @@ -620,6 +746,9 @@ 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
drivers/gpu/drm/msm/sde/sde_core_perf.h +4 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ * @max_per_pipe_ib: maximum instantaneous bandwidth request * @bw_ctl: arbitrated bandwidth request * @core_clk_rate: core clock rate request * @llcc_active: request to activate/deactivate the llcc */ 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; }; /** Loading Loading @@ -59,6 +61,7 @@ struct sde_core_perf_tune { * @bw_vote_mode: apps rsc vs display rsc bandwidth vote mode * @sde_rsc_available: is display rsc available * @bw_vote_mode_updated: bandwidth vote mode update * @llcc_active: status of the llcc, true if active. */ struct sde_core_perf { struct drm_device *dev; Loading @@ -78,6 +81,7 @@ struct sde_core_perf { u32 bw_vote_mode; bool sde_rsc_available; bool bw_vote_mode_updated; bool llcc_active; }; /** Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +19 −2 Original line number Diff line number Diff line Loading @@ -1234,7 +1234,8 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, state->src_x >> 16, state->src_y >> 16, state->src_w >> 16, state->src_h >> 16, state->crtc_x, state->crtc_y, state->crtc_w, state->crtc_h); state->crtc_w, state->crtc_h, pstate->rotation); stage_idx = zpos_cnt[pstate->stage]++; stage_cfg->stage[pstate->stage][stage_idx] = Loading Loading @@ -2965,10 +2966,18 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, * required. However, if those planes were power collapsed since * last commit cycle, driver has to restore the hardware state * of those planes explicitly here prior to plane flush. * Also use this iteration to see if any plane requires cache, * so during the perf update driver can activate/deactivate * the cache accordingly. */ drm_atomic_crtc_for_each_plane(plane, crtc) sde_crtc->new_perf.llcc_active = false; drm_atomic_crtc_for_each_plane(plane, crtc) { sde_plane_restore(plane); if (sde_plane_is_cache_required(plane)) sde_crtc->new_perf.llcc_active = true; } /* wait for acquire fences before anything else is done */ _sde_crtc_wait_for_fences(crtc); Loading Loading @@ -5737,9 +5746,17 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_cp_crtc_init(crtc); sde_cp_crtc_install_properties(crtc); sde_crtc->cur_perf.llcc_active = false; sde_crtc->new_perf.llcc_active = false; kthread_init_delayed_work(&sde_crtc->idle_notify_work, __sde_crtc_idle_notify_work); SDE_DEBUG("crtc=%d new_llcc=%d, old_llcc=%d\n", crtc->base.id, sde_crtc->new_perf.llcc_active, sde_crtc->cur_perf.llcc_active); SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name); return crtc; } Loading
drivers/gpu/drm/msm/sde/sde_formats.c +45 −0 Original line number Diff line number Diff line Loading @@ -642,6 +642,16 @@ static const struct sde_format sde_format_map_tp10_ubwc[] = { SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12), }; inline bool sde_format_is_tp10_ubwc(const struct sde_format *fmt) { if (SDE_FORMAT_IS_YUV(fmt) && SDE_FORMAT_IS_DX(fmt) && SDE_FORMAT_IS_UBWC(fmt) && (fmt->num_planes == 4) && fmt->unpack_tight) return true; else return false; } /* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support * Note: Not using the drm_format_*_subsampling since we have formats */ Loading Loading @@ -1334,3 +1344,38 @@ uint32_t sde_populate_formats( return i; } int sde_format_validate_fmt(struct msm_kms *kms, const struct msm_format *msm_fmt, const struct sde_format_extended *fmt_list) { const struct msm_format *fmt_tmp; bool valid_format = false; int ret = 0; if (!msm_fmt || !fmt_list) { SDE_ERROR("invalid fmt:%d list:%d\n", !msm_fmt, !fmt_list); ret = -EINVAL; goto exit; } while (fmt_list->fourcc_format) { fmt_tmp = sde_get_msm_format(kms, fmt_list->fourcc_format, fmt_list->modifier); if (fmt_tmp && (fmt_tmp->pixel_format == msm_fmt->pixel_format)) { valid_format = true; break; } ++fmt_list; } if (!valid_format) { SDE_ERROR("fmt:%d not found within the list!\n", *msm_fmt); ret = -EINVAL; } exit: return ret; }
drivers/gpu/drm/msm/sde/sde_formats.h +21 −0 Original line number Diff line number Diff line Loading @@ -142,4 +142,25 @@ uint32_t sde_format_get_framebuffer_size( const uint32_t *pitches, const uint64_t modifier); /** * sde_format_is_tp10_ubwc - check if the format is tp10 ubwc * @format: DRM pixel format * * Return: returns true if the format is tp10 ubwc, otherwise false. */ inline bool sde_format_is_tp10_ubwc(const struct sde_format *fmt); /** * sde_format_validate_fmt - validates if the format "msm_fmt" is within * the list "fmt_list" * @kms: pointer to the kms object * @msm_fmt: pointer to the format to look within the list * @fmt_list: list where driver will loop to look for the 'msm_fmt' format. * @result: returns 0 if the format is found, otherwise will return an * error code. */ int sde_format_validate_fmt(struct msm_kms *kms, const struct msm_format *msm_fmt, const struct sde_format_extended *fmt_list); #endif /*_SDE_FORMATS_H */