Message ID | 1526050178-31893-12-git-send-email-ryadav@codeaurora.org (mailing list archive) |
---|---|
State | Not Applicable, archived |
Delegated to: | Andy Gross |
Headers | show |
On Fri, May 11, 2018 at 08:19:37PM +0530, Rajesh Yadav wrote: > Now, since dpu_power_handle manages only bus scaling > and power enable/disable notifications which are restricted > to dpu driver, move dpu_power_handle to dpu folder. > > Changes in v2: > - resolved conflict in dpu_unbind > - dropped (Reviewed-by: Sean Paul) due to above change > Reviewed-by: Sean Paul <seanpaul@chromium.org> > Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> > --- > drivers/gpu/drm/msm/Makefile | 2 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c | 1 - > drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 5 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 7 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 + > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 1 - > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 39 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 + > drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c | 693 +++++++++++++++++++++++ > drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 288 ++++++++++ > drivers/gpu/drm/msm/dpu_power_handle.c | 693 ----------------------- > drivers/gpu/drm/msm/dpu_power_handle.h | 288 ---------- > drivers/gpu/drm/msm/msm_drv.c | 9 - > drivers/gpu/drm/msm/msm_drv.h | 4 - > 14 files changed, 1013 insertions(+), 1020 deletions(-) > create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c > create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h > delete mode 100644 drivers/gpu/drm/msm/dpu_power_handle.c > delete mode 100644 drivers/gpu/drm/msm/dpu_power_handle.h > > diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile > index d9826c1..f578d5a 100644 > --- a/drivers/gpu/drm/msm/Makefile > +++ b/drivers/gpu/drm/msm/Makefile > @@ -82,10 +82,10 @@ msm-y := \ > disp/dpu1/dpu_rm.o \ > disp/dpu1/dpu_vbif.o \ > disp/dpu1/dpu_mdss.o \ > + disp/dpu1/dpu_power_handle.o \ > dpu_dbg.o \ > dpu_io_util.o \ > dpu_dbg_evtlog.o \ > - dpu_power_handle.o \ > msm_prop.o \ > msm_atomic.o \ > msm_debugfs.o \ > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c > index 5c5cc56..33ab2ac 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c > @@ -18,7 +18,6 @@ > #include <linux/kthread.h> > > #include "dpu_core_irq.h" > -#include "dpu_power_handle.h" > > /** > * dpu_core_irq_callback_handler - dispatch core interrupts > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > index 2cf3fca..d3a1ed9 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > @@ -257,7 +257,6 @@ static void _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, > = dpu_crtc_get_client_type(crtc); > struct drm_crtc *tmp_crtc; > struct dpu_crtc_state *dpu_cstate; > - struct msm_drm_private *priv = kms->dev->dev_private; > > drm_for_each_crtc(tmp_crtc, crtc->dev) { > if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) && > @@ -287,7 +286,7 @@ static void _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, > > switch (curr_client_type) { > case NRT_CLIENT: > - dpu_power_data_bus_set_quota(&priv->phandle, kms->core_client, > + dpu_power_data_bus_set_quota(&kms->phandle, kms->core_client, > DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, > bus_id, bus_ab_quota, bus_ib_quota); > DPU_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "nrt", > @@ -295,7 +294,7 @@ static void _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, > break; > > case RT_CLIENT: > - dpu_power_data_bus_set_quota(&priv->phandle, kms->core_client, > + dpu_power_data_bus_set_quota(&kms->phandle, kms->core_client, > DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, > bus_id, bus_ab_quota, bus_ib_quota); > DPU_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "rt", > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > index e2d2e32..99c5e75 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > @@ -598,6 +598,7 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc) > _dpu_crtc_destroy_dest_scaler(dpu_crtc); > > _dpu_crtc_deinit_events(dpu_crtc); > + dpu_crtc->phandle = NULL; > > drm_crtc_cleanup(crtc); > mutex_destroy(&dpu_crtc->crtc_lock); > @@ -2572,7 +2573,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) > } > > if (dpu_crtc->power_event) > - dpu_power_handle_unregister_event(&priv->phandle, > + dpu_power_handle_unregister_event(dpu_crtc->phandle, > dpu_crtc->power_event); > > > @@ -2643,7 +2644,7 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, > mutex_unlock(&dpu_crtc->crtc_lock); > > dpu_crtc->power_event = dpu_power_handle_register_event( > - &priv->phandle, > + dpu_crtc->phandle, > DPU_POWER_EVENT_POST_ENABLE | DPU_POWER_EVENT_POST_DISABLE | > DPU_POWER_EVENT_PRE_DISABLE, > dpu_crtc_handle_power_event, crtc, dpu_crtc->name); > @@ -3938,6 +3939,8 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) > dpu_cp_crtc_init(crtc); > dpu_cp_crtc_install_properties(crtc); > > + dpu_crtc->phandle = &kms->phandle; > + > DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); > return crtc; > } > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > index 9304058..671d909 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > @@ -184,6 +184,7 @@ struct dpu_crtc_event { > * @misr_enable : boolean entry indicates misr enable/disable status. > * @misr_frame_count : misr frame count provided by client > * @misr_data : store misr data before turning off the clocks. > + * @phandle: Pointer to power handler > * @power_event : registered power event handle > * @cur_perf : current performance committed to clock/bandwidth driver > * @rp_lock : serialization lock for resource pool > @@ -240,6 +241,7 @@ struct dpu_crtc { > u32 misr_frame_count; > u32 misr_data[CRTC_DUAL_MIXERS]; > > + struct dpu_power_handle *phandle; > struct dpu_power_event *power_event; > > struct dpu_core_perf_params cur_perf; > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > index 298a6ef..11ae6cc 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c > @@ -31,7 +31,6 @@ > #include "dpu_hw_ctl.h" > #include "dpu_formats.h" > #include "dpu_encoder_phys.h" > -#include "dpu_power_handle.h" > #include "dpu_crtc.h" > #include "dpu_trace.h" > #include "dpu_core_irq.h" > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c > index 9c3b220..0598cfb 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c > @@ -1017,24 +1017,19 @@ static long dpu_kms_round_pixclk(struct msm_kms *kms, unsigned long rate, > static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) > { > struct drm_device *dev; > - struct msm_drm_private *priv; > int i; > > dev = dpu_kms->dev; > if (!dev) > return; > > - priv = dev->dev_private; > - if (!priv) > - return; > - > if (dpu_kms->hw_intr) > dpu_hw_intr_destroy(dpu_kms->hw_intr); > dpu_kms->hw_intr = NULL; > > if (dpu_kms->power_event) > dpu_power_handle_unregister_event( > - &priv->phandle, dpu_kms->power_event); > + &dpu_kms->phandle, dpu_kms->power_event); > > /* safe to call these more than once during shutdown */ > _dpu_debugfs_destroy(dpu_kms); > @@ -1067,7 +1062,8 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) > dpu_kms->catalog = NULL; > > if (dpu_kms->core_client) > - dpu_power_client_destroy(&priv->phandle, dpu_kms->core_client); > + dpu_power_client_destroy(&dpu_kms->phandle, > + dpu_kms->core_client); > dpu_kms->core_client = NULL; > > if (dpu_kms->vbif[VBIF_NRT]) > @@ -1624,7 +1620,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) > } > #endif > > - dpu_kms->core_client = dpu_power_client_create(&priv->phandle, "core"); > + dpu_kms->core_client = dpu_power_client_create(&dpu_kms->phandle, > + "core"); > if (IS_ERR_OR_NULL(dpu_kms->core_client)) { > rc = PTR_ERR(dpu_kms->core_client); > if (!dpu_kms->core_client) > @@ -1721,7 +1718,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) > #endif > > rc = dpu_core_perf_init(&dpu_kms->perf, dev, dpu_kms->catalog, > - &priv->phandle, _dpu_kms_get_clk(dpu_kms, "core_clk")); > + &dpu_kms->phandle, > + _dpu_kms_get_clk(dpu_kms, "core_clk")); > if (rc) { > DPU_ERROR("failed to init perf %d\n", rc); > goto perf_err; > @@ -1765,7 +1763,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) > * Handle (re)initializations during power enable > */ > dpu_kms_handle_power_event(DPU_POWER_EVENT_POST_ENABLE, dpu_kms); > - dpu_kms->power_event = dpu_power_handle_register_event(&priv->phandle, > + dpu_kms->power_event = dpu_power_handle_register_event( > + &dpu_kms->phandle, > DPU_POWER_EVENT_POST_ENABLE, > dpu_kms_handle_power_event, dpu_kms, "kms"); > > @@ -1841,6 +1840,12 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) > goto clk_rate_error; > } > > + ret = dpu_power_resource_init(pdev, &dpu_kms->phandle); > + if (ret) { > + pr_err("dpu power resource init failed\n"); > + goto power_init_fail; > + } > + > platform_set_drvdata(pdev, dpu_kms); > > msm_kms_init(&dpu_kms->base, &kms_funcs); > @@ -1853,6 +1858,7 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) > priv->kms = &dpu_kms->base; > return ret; > > +power_init_fail: > clk_rate_error: > msm_dss_put_clk(mp->clk_config, mp->num_clk); > clk_get_error: > @@ -1867,6 +1873,7 @@ static void dpu_unbind(struct device *dev, struct device *master, void *data) > struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); > struct dss_module_power *mp = &dpu_kms->mp; > > + dpu_power_resource_deinit(pdev, &dpu_kms->phandle); > msm_dss_put_clk(mp->clk_config, mp->num_clk); > devm_kfree(&pdev->dev, mp->clk_config); > mp->num_clk = 0; > @@ -1897,7 +1904,6 @@ static int dpu_runtime_suspend(struct device *dev) > struct platform_device *pdev = to_platform_device(dev); > struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); > struct drm_device *ddev; > - struct msm_drm_private *priv; > struct dss_module_power *mp = &dpu_kms->mp; > > ddev = dpu_kms->dev; > @@ -1905,10 +1911,9 @@ static int dpu_runtime_suspend(struct device *dev) > DPU_ERROR("invalid drm_device\n"); > goto exit; > } > - priv = ddev->dev_private; > > - rc = dpu_power_resource_enable(&priv->phandle, > - dpu_kms->core_client, false); > + rc = dpu_power_resource_enable(&dpu_kms->phandle, > + dpu_kms->core_client, false); > if (rc) > DPU_ERROR("resource disable failed: %d\n", rc); > > @@ -1926,7 +1931,6 @@ static int dpu_runtime_resume(struct device *dev) > struct platform_device *pdev = to_platform_device(dev); > struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); > struct drm_device *ddev; > - struct msm_drm_private *priv; > struct dss_module_power *mp = &dpu_kms->mp; > > ddev = dpu_kms->dev; > @@ -1934,7 +1938,6 @@ static int dpu_runtime_resume(struct device *dev) > DPU_ERROR("invalid drm_device\n"); > goto exit; > } > - priv = ddev->dev_private; > > rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); > if (rc) { > @@ -1942,8 +1945,8 @@ static int dpu_runtime_resume(struct device *dev) > goto exit; > } > > - rc = dpu_power_resource_enable(&priv->phandle, dpu_kms->core_client, > - true); > + rc = dpu_power_resource_enable(&dpu_kms->phandle, > + dpu_kms->core_client, true); > if (rc) > DPU_ERROR("resource enable failed: %d\n", rc); > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h > index a8255fe..c48ed4e 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h > @@ -164,6 +164,7 @@ struct dpu_kms { > struct dpu_mdss_cfg *catalog; > > struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX]; > + struct dpu_power_handle phandle; > struct dpu_power_client *core_client; > #ifdef CONFIG_ION > struct ion_client *iclient; > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c > new file mode 100644 > index 0000000..77be106 > --- /dev/null > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c > @@ -0,0 +1,693 @@ > +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__ > + > +#include <linux/kernel.h> > +#include <linux/of.h> > +#include <linux/string.h> > +#include <linux/of_address.h> > +#include <linux/slab.h> > +#include <linux/mutex.h> > +#include <linux/of_platform.h> > +#ifdef CONFIG_QCOM_BUS_SCALING > +#include <linux/msm-bus.h> > +#include <linux/msm-bus-board.h> > +#endif > +#include <linux/dpu_io_util.h> > + > +#include "dpu_power_handle.h" > +#include "dpu_trace.h" > + > +static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = { > + [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus", > + [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus", > + [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus", > +}; > + > +const char *dpu_power_handle_get_dbus_name(u32 bus_id) > +{ > + if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX) > + return data_bus_name[bus_id]; > + > + return NULL; > +} > + > +static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, > + u32 event_type) > +{ > + struct dpu_power_event *event; > + > + list_for_each_entry(event, &phandle->event_list, list) { > + if (event->event_type & event_type) > + event->cb_fnc(event_type, event->usr); > + } > +} > + > +struct dpu_power_client *dpu_power_client_create( > + struct dpu_power_handle *phandle, char *client_name) > +{ > + struct dpu_power_client *client; > + static u32 id; > + > + if (!client_name || !phandle) { > + pr_err("client name is null or invalid power data\n"); > + return ERR_PTR(-EINVAL); > + } > + > + client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL); > + if (!client) > + return ERR_PTR(-ENOMEM); > + > + mutex_lock(&phandle->phandle_lock); > + strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); > + client->usecase_ndx = VOTE_INDEX_DISABLE; > + client->id = id; > + client->active = true; > + pr_debug("client %s created:%pK id :%d\n", client_name, > + client, id); > + id++; > + list_add(&client->list, &phandle->power_client_clist); > + mutex_unlock(&phandle->phandle_lock); > + > + return client; > +} > + > +void dpu_power_client_destroy(struct dpu_power_handle *phandle, > + struct dpu_power_client *client) > +{ > + if (!client || !phandle) { > + pr_err("reg bus vote: invalid client handle\n"); > + } else if (!client->active) { > + pr_err("dpu power deinit already done\n"); > + kfree(client); > + } else { > + pr_debug("bus vote client %s destroyed:%pK id:%u\n", > + client->name, client, client->id); > + mutex_lock(&phandle->phandle_lock); > + list_del_init(&client->list); > + mutex_unlock(&phandle->phandle_lock); > + kfree(client); > + } > +} > + > +#ifdef CONFIG_QCOM_BUS_SCALING > + > +#define MAX_AXI_PORT_COUNT 3 > + > +static int _dpu_power_data_bus_set_quota( > + struct dpu_power_data_bus_handle *pdbus, > + u64 ab_quota_rt, u64 ab_quota_nrt, > + u64 ib_quota_rt, u64 ib_quota_nrt) > +{ > + int new_uc_idx; > + u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0}; > + u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0}; > + int rc; > + > + if (pdbus->data_bus_hdl < 1) { > + pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl); > + return -EINVAL; > + } > + > + pdbus->ab_rt = ab_quota_rt; > + pdbus->ib_rt = ib_quota_rt; > + pdbus->ab_nrt = ab_quota_nrt; > + pdbus->ib_nrt = ib_quota_nrt; > + > + if (pdbus->enable) { > + ab_quota_rt = max_t(u64, ab_quota_rt, > + DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); > + ib_quota_rt = max_t(u64, ib_quota_rt, > + DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); > + ab_quota_nrt = max_t(u64, ab_quota_nrt, > + DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); > + ib_quota_nrt = max_t(u64, ib_quota_nrt, > + DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); > + } else { > + ab_quota_rt = min_t(u64, ab_quota_rt, > + DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); > + ib_quota_rt = min_t(u64, ib_quota_rt, > + DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); > + ab_quota_nrt = min_t(u64, ab_quota_nrt, > + DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); > + ib_quota_nrt = min_t(u64, ib_quota_nrt, > + DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); > + } > + > + if (!ab_quota_rt && !ab_quota_nrt && !ib_quota_rt && !ib_quota_nrt) { > + new_uc_idx = 0; > + } else { > + int i; > + struct msm_bus_vectors *vect = NULL; > + struct msm_bus_scale_pdata *bw_table = > + pdbus->data_bus_scale_table; > + u32 nrt_axi_port_cnt = pdbus->nrt_axi_port_cnt; > + u32 total_axi_port_cnt = pdbus->axi_port_cnt; > + u32 rt_axi_port_cnt = total_axi_port_cnt - nrt_axi_port_cnt; > + > + if (!bw_table || !total_axi_port_cnt || > + total_axi_port_cnt > MAX_AXI_PORT_COUNT) { > + pr_err("invalid input\n"); > + return -EINVAL; > + } > + > + if (pdbus->bus_channels) { > + ib_quota_rt = div_u64(ib_quota_rt, > + pdbus->bus_channels); > + ib_quota_nrt = div_u64(ib_quota_nrt, > + pdbus->bus_channels); > + } > + > + if (nrt_axi_port_cnt) { > + > + ab_quota_rt = div_u64(ab_quota_rt, rt_axi_port_cnt); > + ab_quota_nrt = div_u64(ab_quota_nrt, nrt_axi_port_cnt); > + > + for (i = 0; i < total_axi_port_cnt; i++) { > + if (i < rt_axi_port_cnt) { > + ab_quota[i] = ab_quota_rt; > + ib_quota[i] = ib_quota_rt; > + } else { > + ab_quota[i] = ab_quota_nrt; > + ib_quota[i] = ib_quota_nrt; > + } > + } > + } else { > + ab_quota[0] = div_u64(ab_quota_rt + ab_quota_nrt, > + total_axi_port_cnt); > + ib_quota[0] = ib_quota_rt + ib_quota_nrt; > + > + for (i = 1; i < total_axi_port_cnt; i++) { > + ab_quota[i] = ab_quota[0]; > + ib_quota[i] = ib_quota[0]; > + } > + } > + > + new_uc_idx = (pdbus->curr_bw_uc_idx % > + (bw_table->num_usecases - 1)) + 1; > + > + for (i = 0; i < total_axi_port_cnt; i++) { > + vect = &bw_table->usecase[new_uc_idx].vectors[i]; > + vect->ab = ab_quota[i]; > + vect->ib = ib_quota[i]; > + > + pr_debug( > + "%s uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n", > + bw_table->name, > + new_uc_idx, (i < rt_axi_port_cnt) ? "rt" : "nrt" > + , i, vect->ab, vect->ib); > + } > + } > + pdbus->curr_bw_uc_idx = new_uc_idx; > + pdbus->ao_bw_uc_idx = new_uc_idx; > + > + DPU_ATRACE_BEGIN("msm_bus_scale_req"); > + rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl, > + new_uc_idx); > + DPU_ATRACE_END("msm_bus_scale_req"); > + > + return rc; > +} > + > +int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, > + struct dpu_power_client *pclient, > + int bus_client, u32 bus_id, > + u64 ab_quota, u64 ib_quota) > +{ > + int rc = 0; > + int i; > + u64 total_ab_rt = 0, total_ib_rt = 0; > + u64 total_ab_nrt = 0, total_ib_nrt = 0; > + struct dpu_power_client *client; > + > + if (!phandle || !pclient || > + bus_client >= DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX || > + bus_id >= DPU_POWER_HANDLE_DBUS_ID_MAX) { > + pr_err("invalid parameters\n"); > + return -EINVAL; > + } > + > + mutex_lock(&phandle->phandle_lock); > + > + pclient->ab[bus_client] = ab_quota; > + pclient->ib[bus_client] = ib_quota; > + trace_dpu_perf_update_bus(bus_client, ab_quota, ib_quota); > + > + list_for_each_entry(client, &phandle->power_client_clist, list) { > + for (i = 0; i < DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) { > + if (i == DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT) { > + total_ab_nrt += client->ab[i]; > + total_ib_nrt += client->ib[i]; > + } else { > + total_ab_rt += client->ab[i]; > + total_ib_rt = max(total_ib_rt, client->ib[i]); > + } > + } > + } > + > + if (phandle->data_bus_handle[bus_id].data_bus_hdl) > + rc = _dpu_power_data_bus_set_quota( > + &phandle->data_bus_handle[bus_id], > + total_ab_rt, total_ab_nrt, > + total_ib_rt, total_ib_nrt); > + > + mutex_unlock(&phandle->phandle_lock); > + > + return rc; > +} > + > +static void dpu_power_data_bus_unregister( > + struct dpu_power_data_bus_handle *pdbus) > +{ > + if (pdbus->data_bus_hdl) { > + msm_bus_scale_unregister_client(pdbus->data_bus_hdl); > + pdbus->data_bus_hdl = 0; > + } > +} > + > +static int dpu_power_data_bus_parse(struct platform_device *pdev, > + struct dpu_power_data_bus_handle *pdbus, const char *name) > +{ > + struct device_node *node; > + int rc = 0; > + int paths; > + > + pdbus->bus_channels = 1; > + rc = of_property_read_u32(pdev->dev.of_node, > + "qcom,dpu-dram-channels", &pdbus->bus_channels); > + if (rc) { > + pr_debug("number of channels property not specified\n"); > + rc = 0; > + } > + > + pdbus->nrt_axi_port_cnt = 0; > + rc = of_property_read_u32(pdev->dev.of_node, > + "qcom,dpu-num-nrt-paths", > + &pdbus->nrt_axi_port_cnt); > + if (rc) { > + pr_debug("number of axi port property not specified\n"); > + rc = 0; > + } > + > + node = of_get_child_by_name(pdev->dev.of_node, name); > + if (node) { > + rc = of_property_read_u32(node, > + "qcom,msm-bus,num-paths", &paths); > + if (rc) { > + pr_err("Error. qcom,msm-bus,num-paths not found\n"); > + return rc; > + } > + pdbus->axi_port_cnt = paths; > + > + pdbus->data_bus_scale_table = > + msm_bus_pdata_from_node(pdev, node); > + if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) { > + pr_err("reg bus handle parsing failed\n"); > + rc = PTR_ERR(pdbus->data_bus_scale_table); > + if (!pdbus->data_bus_scale_table) > + rc = -EINVAL; > + goto end; > + } > + pdbus->data_bus_hdl = msm_bus_scale_register_client( > + pdbus->data_bus_scale_table); > + if (!pdbus->data_bus_hdl) { > + pr_err("data_bus_client register failed\n"); > + rc = -EINVAL; > + goto end; > + } > + pr_debug("register %s data_bus_hdl=%x\n", name, > + pdbus->data_bus_hdl); > + } > + > +end: > + return rc; > +} > + > +static int dpu_power_reg_bus_parse(struct platform_device *pdev, > + struct dpu_power_handle *phandle) > +{ > + struct device_node *node; > + struct msm_bus_scale_pdata *bus_scale_table; > + int rc = 0; > + > + node = of_get_child_by_name(pdev->dev.of_node, "qcom,dpu-reg-bus"); > + if (node) { > + bus_scale_table = msm_bus_pdata_from_node(pdev, node); > + if (IS_ERR_OR_NULL(bus_scale_table)) { > + pr_err("reg bus handle parsing failed\n"); > + rc = PTR_ERR(bus_scale_table); > + if (!bus_scale_table) > + rc = -EINVAL; > + goto end; > + } > + phandle->reg_bus_hdl = msm_bus_scale_register_client( > + bus_scale_table); > + if (!phandle->reg_bus_hdl) { > + pr_err("reg_bus_client register failed\n"); > + rc = -EINVAL; > + goto end; > + } > + pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl); > + } > + > +end: > + return rc; > +} > + > +static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) > +{ > + if (reg_bus_hdl) > + msm_bus_scale_unregister_client(reg_bus_hdl); > +} > + > +int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, > + bool enable) > +{ > + int i; > + > + if (!phandle) { > + pr_err("invalid param\n"); > + return -EINVAL; > + } > + > + for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; > + i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > + phandle->data_bus_handle[i].enable = enable; > + > + return 0; > +} > + > +static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, > + bool enable) > +{ > + int rc = 0; > + > + pdbus->enable = enable; > + > + if (pdbus->data_bus_hdl) > + rc = _dpu_power_data_bus_set_quota(pdbus, pdbus->ab_rt, > + pdbus->ab_nrt, pdbus->ib_rt, pdbus->ib_nrt); > + > + if (rc) > + pr_err("failed to set data bus vote rc=%d enable:%d\n", > + rc, enable); > + > + return rc; > +} > + > +static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) > +{ > + int rc = 0; > + > + if (reg_bus_hdl) > + rc = msm_bus_scale_client_update_request(reg_bus_hdl, > + usecase_ndx); > + if (rc) > + pr_err("failed to set reg bus vote rc=%d\n", rc); > + > + return rc; > +} > +#else > +static int dpu_power_data_bus_parse(struct platform_device *pdev, > + struct dpu_power_data_bus_handle *pdbus, const char *name) > +{ > + return 0; > +} > + > +static void dpu_power_data_bus_unregister( > + struct dpu_power_data_bus_handle *pdbus) > +{ > +} > + > +int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, > + struct dpu_power_client *pclient, > + int bus_client, u32 bus_id, > + u64 ab_quota, u64 ib_quota) > +{ > + return 0; > +} > + > +static int dpu_power_reg_bus_parse(struct platform_device *pdev, > + struct dpu_power_handle *phandle) > +{ > + return 0; > +} > + > +static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) > +{ > +} > + > +static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) > +{ > + return 0; > +} > + > +static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, > + bool enable) > +{ > + return 0; > +} > + > +int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, > + bool enable) > +{ > + return 0; > +} > +#endif > + > +int dpu_power_resource_init(struct platform_device *pdev, > + struct dpu_power_handle *phandle) > +{ > + int rc = 0, i; > + > + if (!phandle || !pdev) { > + pr_err("invalid input param\n"); > + return -EINVAL; > + } > + > + phandle->dev = &pdev->dev; > + > + rc = dpu_power_reg_bus_parse(pdev, phandle); > + if (rc) { > + pr_err("register bus parse failed rc=%d\n", rc); > + return rc; > + } > + > + for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; > + i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { > + rc = dpu_power_data_bus_parse(pdev, > + &phandle->data_bus_handle[i], > + data_bus_name[i]); > + if (rc) { > + pr_err("register data bus parse failed id=%d rc=%d\n", > + i, rc); > + goto data_bus_err; > + } > + } > + > + INIT_LIST_HEAD(&phandle->power_client_clist); > + INIT_LIST_HEAD(&phandle->event_list); > + > + mutex_init(&phandle->phandle_lock); > + > + return rc; > + > +data_bus_err: > + for (i--; i >= 0; i--) > + dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); > + dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); > + return rc; > +} > + > +void dpu_power_resource_deinit(struct platform_device *pdev, > + struct dpu_power_handle *phandle) > +{ > + struct dpu_power_client *curr_client, *next_client; > + struct dpu_power_event *curr_event, *next_event; > + int i; > + > + if (!phandle || !pdev) { > + pr_err("invalid input param\n"); > + return; > + } > + > + mutex_lock(&phandle->phandle_lock); > + list_for_each_entry_safe(curr_client, next_client, > + &phandle->power_client_clist, list) { > + pr_err("cliend:%s-%d still registered with refcount:%d\n", > + curr_client->name, curr_client->id, > + curr_client->refcount); > + curr_client->active = false; > + list_del(&curr_client->list); > + } > + > + list_for_each_entry_safe(curr_event, next_event, > + &phandle->event_list, list) { > + pr_err("event:%d, client:%s still registered\n", > + curr_event->event_type, > + curr_event->client_name); > + curr_event->active = false; > + list_del(&curr_event->list); > + } > + mutex_unlock(&phandle->phandle_lock); > + > + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > + dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); > + > + dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); > +} > + > +int dpu_power_resource_enable(struct dpu_power_handle *phandle, > + struct dpu_power_client *pclient, bool enable) > +{ > + int rc = 0, i; > + bool changed = false; > + u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx; > + struct dpu_power_client *client; > + > + if (!phandle || !pclient) { > + pr_err("invalid input argument\n"); > + return -EINVAL; > + } > + > + mutex_lock(&phandle->phandle_lock); > + if (enable) > + pclient->refcount++; > + else if (pclient->refcount) > + pclient->refcount--; > + > + if (pclient->refcount) > + pclient->usecase_ndx = VOTE_INDEX_LOW; > + else > + pclient->usecase_ndx = VOTE_INDEX_DISABLE; > + > + list_for_each_entry(client, &phandle->power_client_clist, list) { > + if (client->usecase_ndx < VOTE_INDEX_MAX && > + client->usecase_ndx > max_usecase_ndx) > + max_usecase_ndx = client->usecase_ndx; > + } > + > + if (phandle->current_usecase_ndx != max_usecase_ndx) { > + changed = true; > + prev_usecase_ndx = phandle->current_usecase_ndx; > + phandle->current_usecase_ndx = max_usecase_ndx; > + } > + > + pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n", > + __builtin_return_address(0), changed, max_usecase_ndx, > + pclient->name, pclient->id, enable, pclient->refcount); > + > + if (!changed) > + goto end; > + > + if (enable) { > + dpu_power_event_trigger_locked(phandle, > + DPU_POWER_EVENT_PRE_ENABLE); > + > + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { > + rc = dpu_power_data_bus_update( > + &phandle->data_bus_handle[i], enable); > + if (rc) { > + pr_err("failed to set data bus vote id=%d rc=%d\n", > + i, rc); > + goto data_bus_hdl_err; > + } > + } > + > + rc = dpu_power_reg_bus_update(phandle->reg_bus_hdl, > + max_usecase_ndx); > + if (rc) { > + pr_err("failed to set reg bus vote rc=%d\n", rc); > + goto reg_bus_hdl_err; > + } > + > + dpu_power_event_trigger_locked(phandle, > + DPU_POWER_EVENT_POST_ENABLE); > + > + } else { > + dpu_power_event_trigger_locked(phandle, > + DPU_POWER_EVENT_PRE_DISABLE); > + > + dpu_power_reg_bus_update(phandle->reg_bus_hdl, > + max_usecase_ndx); > + > + for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > + dpu_power_data_bus_update(&phandle->data_bus_handle[i], > + enable); > + > + dpu_power_event_trigger_locked(phandle, > + DPU_POWER_EVENT_POST_DISABLE); > + } > + > +end: > + mutex_unlock(&phandle->phandle_lock); > + return rc; > + > +reg_bus_hdl_err: > + for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > + dpu_power_data_bus_update(&phandle->data_bus_handle[i], 0); > +data_bus_hdl_err: > + phandle->current_usecase_ndx = prev_usecase_ndx; > + mutex_unlock(&phandle->phandle_lock); > + return rc; > +} > + > +struct dpu_power_event *dpu_power_handle_register_event( > + struct dpu_power_handle *phandle, > + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), > + void *usr, char *client_name) > +{ > + struct dpu_power_event *event; > + > + if (!phandle) { > + pr_err("invalid power handle\n"); > + return ERR_PTR(-EINVAL); > + } else if (!cb_fnc || !event_type) { > + pr_err("no callback fnc or event type\n"); > + return ERR_PTR(-EINVAL); > + } > + > + event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL); > + if (!event) > + return ERR_PTR(-ENOMEM); > + > + event->event_type = event_type; > + event->cb_fnc = cb_fnc; > + event->usr = usr; > + strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); > + event->active = true; > + > + mutex_lock(&phandle->phandle_lock); > + list_add(&event->list, &phandle->event_list); > + mutex_unlock(&phandle->phandle_lock); > + > + return event; > +} > + > +void dpu_power_handle_unregister_event( > + struct dpu_power_handle *phandle, > + struct dpu_power_event *event) > +{ > + if (!phandle || !event) { > + pr_err("invalid phandle or event\n"); > + } else if (!event->active) { > + pr_err("power handle deinit already done\n"); > + kfree(event); > + } else { > + mutex_lock(&phandle->phandle_lock); > + list_del_init(&event->list); > + mutex_unlock(&phandle->phandle_lock); > + kfree(event); > + } > +} > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h > new file mode 100644 > index 0000000..9a6d4b9 > --- /dev/null > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h > @@ -0,0 +1,288 @@ > +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#ifndef _DPU_POWER_HANDLE_H_ > +#define _DPU_POWER_HANDLE_H_ > + > +#define MAX_CLIENT_NAME_LEN 128 > + > +#define DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0 > +#define DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0 > +#define DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 1600000000 > +#define DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0 > + > +#include <linux/dpu_io_util.h> > + > +/* event will be triggered before power handler disable */ > +#define DPU_POWER_EVENT_PRE_DISABLE 0x1 > + > +/* event will be triggered after power handler disable */ > +#define DPU_POWER_EVENT_POST_DISABLE 0x2 > + > +/* event will be triggered before power handler enable */ > +#define DPU_POWER_EVENT_PRE_ENABLE 0x4 > + > +/* event will be triggered after power handler enable */ > +#define DPU_POWER_EVENT_POST_ENABLE 0x8 > + > +/** > + * mdss_bus_vote_type: register bus vote type > + * VOTE_INDEX_DISABLE: removes the client vote > + * VOTE_INDEX_LOW: keeps the lowest vote for register bus > + * VOTE_INDEX_MAX: invalid > + */ > +enum mdss_bus_vote_type { > + VOTE_INDEX_DISABLE, > + VOTE_INDEX_LOW, > + VOTE_INDEX_MAX, > +}; > + > +/** > + * enum dpu_power_handle_data_bus_client - type of axi bus clients > + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client > + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client > + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type > + */ > +enum dpu_power_handle_data_bus_client { > + DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, > + DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, > + DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX > +}; > + > +/** > + * enum DPU_POWER_HANDLE_DBUS_ID - data bus identifier > + * @DPU_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus > + * @DPU_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus > + * @DPU_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus > + */ > +enum DPU_POWER_HANDLE_DBUS_ID { > + DPU_POWER_HANDLE_DBUS_ID_MNOC, > + DPU_POWER_HANDLE_DBUS_ID_LLCC, > + DPU_POWER_HANDLE_DBUS_ID_EBI, > + DPU_POWER_HANDLE_DBUS_ID_MAX, > +}; > + > +/** > + * struct dpu_power_client: stores the power client for dpu driver > + * @name: name of the client > + * @usecase_ndx: current regs bus vote type > + * @refcount: current refcount if multiple modules are using same > + * same client for enable/disable. Power module will > + * aggregate the refcount and vote accordingly for this > + * client. > + * @id: assigned during create. helps for debugging. > + * @list: list to attach power handle master list > + * @ab: arbitrated bandwidth for each bus client > + * @ib: instantaneous bandwidth for each bus client > + * @active: inidcates the state of dpu power handle > + */ > +struct dpu_power_client { > + char name[MAX_CLIENT_NAME_LEN]; > + short usecase_ndx; > + short refcount; > + u32 id; > + struct list_head list; > + u64 ab[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; > + u64 ib[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; > + bool active; > +}; > + > +/** > + * struct dpu_power_data_handle: power handle struct for data bus > + * @data_bus_scale_table: pointer to bus scaling table > + * @data_bus_hdl: current data bus handle > + * @axi_port_cnt: number of rt axi ports > + * @nrt_axi_port_cnt: number of nrt axi ports > + * @bus_channels: number of memory bus channels > + * @curr_bw_uc_idx: current use case index of data bus > + * @ao_bw_uc_idx: active only use case index of data bus > + * @ab_rt: realtime ab quota > + * @ib_rt: realtime ib quota > + * @ab_nrt: non-realtime ab quota > + * @ib_nrt: non-realtime ib quota > + * @enable: true if bus is enabled > + */ > +struct dpu_power_data_bus_handle { > + struct msm_bus_scale_pdata *data_bus_scale_table; > + u32 data_bus_hdl; > + u32 axi_port_cnt; > + u32 nrt_axi_port_cnt; > + u32 bus_channels; > + u32 curr_bw_uc_idx; > + u32 ao_bw_uc_idx; > + u64 ab_rt; > + u64 ib_rt; > + u64 ab_nrt; > + u64 ib_nrt; > + bool enable; > +}; > + > +/* > + * struct dpu_power_event - local event registration structure > + * @client_name: name of the client registering > + * @cb_fnc: pointer to desired callback function > + * @usr: user pointer to pass to callback event trigger > + * @event: refer to DPU_POWER_HANDLE_EVENT_* > + * @list: list to attach event master list > + * @active: indicates the state of dpu power handle > + */ > +struct dpu_power_event { > + char client_name[MAX_CLIENT_NAME_LEN]; > + void (*cb_fnc)(u32 event_type, void *usr); > + void *usr; > + u32 event_type; > + struct list_head list; > + bool active; > +}; > + > +/** > + * struct dpu_power_handle: power handle main struct > + * @client_clist: master list to store all clients > + * @phandle_lock: lock to synchronize the enable/disable > + * @dev: pointer to device structure > + * @usecase_ndx: current usecase index > + * @reg_bus_hdl: current register bus handle > + * @data_bus_handle: context structure for data bus control > + * @event_list: current power handle event list > + */ > +struct dpu_power_handle { > + struct list_head power_client_clist; > + struct mutex phandle_lock; > + struct device *dev; > + u32 current_usecase_ndx; > + u32 reg_bus_hdl; > + struct dpu_power_data_bus_handle data_bus_handle > + [DPU_POWER_HANDLE_DBUS_ID_MAX]; > + struct list_head event_list; > +}; > + > +/** > + * dpu_power_resource_init() - initializes the dpu power handle > + * @pdev: platform device to search the power resources > + * @pdata: power handle to store the power resources > + * > + * Return: error code. > + */ > +int dpu_power_resource_init(struct platform_device *pdev, > + struct dpu_power_handle *pdata); > + > +/** > + * dpu_power_resource_deinit() - release the dpu power handle > + * @pdev: platform device for power resources > + * @pdata: power handle containing the resources > + * > + * Return: error code. > + */ > +void dpu_power_resource_deinit(struct platform_device *pdev, > + struct dpu_power_handle *pdata); > + > +/** > + * dpu_power_client_create() - create the client on power handle > + * @pdata: power handle containing the resources > + * @client_name: new client name for registration > + * > + * Return: error code. > + */ > +struct dpu_power_client *dpu_power_client_create(struct dpu_power_handle *pdata, > + char *client_name); > + > +/** > + * dpu_power_client_destroy() - destroy the client on power handle > + * @pdata: power handle containing the resources > + * @client_name: new client name for registration > + * > + * Return: none > + */ > +void dpu_power_client_destroy(struct dpu_power_handle *phandle, > + struct dpu_power_client *client); > + > +/** > + * dpu_power_resource_enable() - enable/disable the power resources > + * @pdata: power handle containing the resources > + * @client: client information to enable/disable its vote > + * @enable: boolean request for enable/disable > + * > + * Return: error code. > + */ > +int dpu_power_resource_enable(struct dpu_power_handle *pdata, > + struct dpu_power_client *pclient, bool enable); > + > +/** > + * dpu_power_data_bus_state_update() - update data bus state > + * @pdata: power handle containing the resources > + * @enable: take enable vs disable path > + * > + * Return: error code. > + */ > +int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, > + bool enable); > + > +/** > + * dpu_power_data_bus_set_quota() - set data bus quota for power client > + * @phandle: power handle containing the resources > + * @client: client information to set quota > + * @bus_client: real-time or non-real-time bus client > + * @bus_id: identifier of data bus, see DPU_POWER_HANDLE_DBUS_ID > + * @ab_quota: arbitrated bus bandwidth > + * @ib_quota: instantaneous bus bandwidth > + * > + * Return: zero if success, or error code otherwise > + */ > +int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, > + struct dpu_power_client *pclient, > + int bus_client, u32 bus_id, > + u64 ab_quota, u64 ib_quota); > + > +/** > + * dpu_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable > + * @phandle: power handle containing the resources > + * @client: client information to bandwidth control > + * @enable: true to enable bandwidth for data base > + * > + * Return: none > + */ > +void dpu_power_data_bus_bandwidth_ctrl(struct dpu_power_handle *phandle, > + struct dpu_power_client *pclient, int enable); > + > +/** > + * dpu_power_handle_register_event - register a callback function for an event. > + * Clients can register for multiple events with a single register. > + * Any block with access to phandle can register for the event > + * notification. > + * @phandle: power handle containing the resources > + * @event_type: event type to register; refer DPU_POWER_HANDLE_EVENT_* > + * @cb_fnc: pointer to desired callback function > + * @usr: user pointer to pass to callback on event trigger > + * > + * Return: event pointer if success, or error code otherwise > + */ > +struct dpu_power_event *dpu_power_handle_register_event( > + struct dpu_power_handle *phandle, > + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), > + void *usr, char *client_name); > +/** > + * dpu_power_handle_unregister_event - unregister callback for event(s) > + * @phandle: power handle containing the resources > + * @event: event pointer returned after power handle register > + */ > +void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle, > + struct dpu_power_event *event); > + > +/** > + * dpu_power_handle_get_dbus_name - get name of given data bus identifier > + * @bus_id: data bus identifier > + * Return: Pointer to name string if success; NULL otherwise > + */ > +const char *dpu_power_handle_get_dbus_name(u32 bus_id); > + > +#endif /* _DPU_POWER_HANDLE_H_ */ > diff --git a/drivers/gpu/drm/msm/dpu_power_handle.c b/drivers/gpu/drm/msm/dpu_power_handle.c > deleted file mode 100644 > index 77be106..0000000 > --- a/drivers/gpu/drm/msm/dpu_power_handle.c > +++ /dev/null > @@ -1,693 +0,0 @@ > -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License version 2 and > - * only version 2 as published by the Free Software Foundation. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - */ > - > -#define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__ > - > -#include <linux/kernel.h> > -#include <linux/of.h> > -#include <linux/string.h> > -#include <linux/of_address.h> > -#include <linux/slab.h> > -#include <linux/mutex.h> > -#include <linux/of_platform.h> > -#ifdef CONFIG_QCOM_BUS_SCALING > -#include <linux/msm-bus.h> > -#include <linux/msm-bus-board.h> > -#endif > -#include <linux/dpu_io_util.h> > - > -#include "dpu_power_handle.h" > -#include "dpu_trace.h" > - > -static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = { > - [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus", > - [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus", > - [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus", > -}; > - > -const char *dpu_power_handle_get_dbus_name(u32 bus_id) > -{ > - if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX) > - return data_bus_name[bus_id]; > - > - return NULL; > -} > - > -static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, > - u32 event_type) > -{ > - struct dpu_power_event *event; > - > - list_for_each_entry(event, &phandle->event_list, list) { > - if (event->event_type & event_type) > - event->cb_fnc(event_type, event->usr); > - } > -} > - > -struct dpu_power_client *dpu_power_client_create( > - struct dpu_power_handle *phandle, char *client_name) > -{ > - struct dpu_power_client *client; > - static u32 id; > - > - if (!client_name || !phandle) { > - pr_err("client name is null or invalid power data\n"); > - return ERR_PTR(-EINVAL); > - } > - > - client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL); > - if (!client) > - return ERR_PTR(-ENOMEM); > - > - mutex_lock(&phandle->phandle_lock); > - strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); > - client->usecase_ndx = VOTE_INDEX_DISABLE; > - client->id = id; > - client->active = true; > - pr_debug("client %s created:%pK id :%d\n", client_name, > - client, id); > - id++; > - list_add(&client->list, &phandle->power_client_clist); > - mutex_unlock(&phandle->phandle_lock); > - > - return client; > -} > - > -void dpu_power_client_destroy(struct dpu_power_handle *phandle, > - struct dpu_power_client *client) > -{ > - if (!client || !phandle) { > - pr_err("reg bus vote: invalid client handle\n"); > - } else if (!client->active) { > - pr_err("dpu power deinit already done\n"); > - kfree(client); > - } else { > - pr_debug("bus vote client %s destroyed:%pK id:%u\n", > - client->name, client, client->id); > - mutex_lock(&phandle->phandle_lock); > - list_del_init(&client->list); > - mutex_unlock(&phandle->phandle_lock); > - kfree(client); > - } > -} > - > -#ifdef CONFIG_QCOM_BUS_SCALING > - > -#define MAX_AXI_PORT_COUNT 3 > - > -static int _dpu_power_data_bus_set_quota( > - struct dpu_power_data_bus_handle *pdbus, > - u64 ab_quota_rt, u64 ab_quota_nrt, > - u64 ib_quota_rt, u64 ib_quota_nrt) > -{ > - int new_uc_idx; > - u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0}; > - u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0}; > - int rc; > - > - if (pdbus->data_bus_hdl < 1) { > - pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl); > - return -EINVAL; > - } > - > - pdbus->ab_rt = ab_quota_rt; > - pdbus->ib_rt = ib_quota_rt; > - pdbus->ab_nrt = ab_quota_nrt; > - pdbus->ib_nrt = ib_quota_nrt; > - > - if (pdbus->enable) { > - ab_quota_rt = max_t(u64, ab_quota_rt, > - DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); > - ib_quota_rt = max_t(u64, ib_quota_rt, > - DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); > - ab_quota_nrt = max_t(u64, ab_quota_nrt, > - DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); > - ib_quota_nrt = max_t(u64, ib_quota_nrt, > - DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); > - } else { > - ab_quota_rt = min_t(u64, ab_quota_rt, > - DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); > - ib_quota_rt = min_t(u64, ib_quota_rt, > - DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); > - ab_quota_nrt = min_t(u64, ab_quota_nrt, > - DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); > - ib_quota_nrt = min_t(u64, ib_quota_nrt, > - DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); > - } > - > - if (!ab_quota_rt && !ab_quota_nrt && !ib_quota_rt && !ib_quota_nrt) { > - new_uc_idx = 0; > - } else { > - int i; > - struct msm_bus_vectors *vect = NULL; > - struct msm_bus_scale_pdata *bw_table = > - pdbus->data_bus_scale_table; > - u32 nrt_axi_port_cnt = pdbus->nrt_axi_port_cnt; > - u32 total_axi_port_cnt = pdbus->axi_port_cnt; > - u32 rt_axi_port_cnt = total_axi_port_cnt - nrt_axi_port_cnt; > - > - if (!bw_table || !total_axi_port_cnt || > - total_axi_port_cnt > MAX_AXI_PORT_COUNT) { > - pr_err("invalid input\n"); > - return -EINVAL; > - } > - > - if (pdbus->bus_channels) { > - ib_quota_rt = div_u64(ib_quota_rt, > - pdbus->bus_channels); > - ib_quota_nrt = div_u64(ib_quota_nrt, > - pdbus->bus_channels); > - } > - > - if (nrt_axi_port_cnt) { > - > - ab_quota_rt = div_u64(ab_quota_rt, rt_axi_port_cnt); > - ab_quota_nrt = div_u64(ab_quota_nrt, nrt_axi_port_cnt); > - > - for (i = 0; i < total_axi_port_cnt; i++) { > - if (i < rt_axi_port_cnt) { > - ab_quota[i] = ab_quota_rt; > - ib_quota[i] = ib_quota_rt; > - } else { > - ab_quota[i] = ab_quota_nrt; > - ib_quota[i] = ib_quota_nrt; > - } > - } > - } else { > - ab_quota[0] = div_u64(ab_quota_rt + ab_quota_nrt, > - total_axi_port_cnt); > - ib_quota[0] = ib_quota_rt + ib_quota_nrt; > - > - for (i = 1; i < total_axi_port_cnt; i++) { > - ab_quota[i] = ab_quota[0]; > - ib_quota[i] = ib_quota[0]; > - } > - } > - > - new_uc_idx = (pdbus->curr_bw_uc_idx % > - (bw_table->num_usecases - 1)) + 1; > - > - for (i = 0; i < total_axi_port_cnt; i++) { > - vect = &bw_table->usecase[new_uc_idx].vectors[i]; > - vect->ab = ab_quota[i]; > - vect->ib = ib_quota[i]; > - > - pr_debug( > - "%s uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n", > - bw_table->name, > - new_uc_idx, (i < rt_axi_port_cnt) ? "rt" : "nrt" > - , i, vect->ab, vect->ib); > - } > - } > - pdbus->curr_bw_uc_idx = new_uc_idx; > - pdbus->ao_bw_uc_idx = new_uc_idx; > - > - DPU_ATRACE_BEGIN("msm_bus_scale_req"); > - rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl, > - new_uc_idx); > - DPU_ATRACE_END("msm_bus_scale_req"); > - > - return rc; > -} > - > -int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, > - struct dpu_power_client *pclient, > - int bus_client, u32 bus_id, > - u64 ab_quota, u64 ib_quota) > -{ > - int rc = 0; > - int i; > - u64 total_ab_rt = 0, total_ib_rt = 0; > - u64 total_ab_nrt = 0, total_ib_nrt = 0; > - struct dpu_power_client *client; > - > - if (!phandle || !pclient || > - bus_client >= DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX || > - bus_id >= DPU_POWER_HANDLE_DBUS_ID_MAX) { > - pr_err("invalid parameters\n"); > - return -EINVAL; > - } > - > - mutex_lock(&phandle->phandle_lock); > - > - pclient->ab[bus_client] = ab_quota; > - pclient->ib[bus_client] = ib_quota; > - trace_dpu_perf_update_bus(bus_client, ab_quota, ib_quota); > - > - list_for_each_entry(client, &phandle->power_client_clist, list) { > - for (i = 0; i < DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) { > - if (i == DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT) { > - total_ab_nrt += client->ab[i]; > - total_ib_nrt += client->ib[i]; > - } else { > - total_ab_rt += client->ab[i]; > - total_ib_rt = max(total_ib_rt, client->ib[i]); > - } > - } > - } > - > - if (phandle->data_bus_handle[bus_id].data_bus_hdl) > - rc = _dpu_power_data_bus_set_quota( > - &phandle->data_bus_handle[bus_id], > - total_ab_rt, total_ab_nrt, > - total_ib_rt, total_ib_nrt); > - > - mutex_unlock(&phandle->phandle_lock); > - > - return rc; > -} > - > -static void dpu_power_data_bus_unregister( > - struct dpu_power_data_bus_handle *pdbus) > -{ > - if (pdbus->data_bus_hdl) { > - msm_bus_scale_unregister_client(pdbus->data_bus_hdl); > - pdbus->data_bus_hdl = 0; > - } > -} > - > -static int dpu_power_data_bus_parse(struct platform_device *pdev, > - struct dpu_power_data_bus_handle *pdbus, const char *name) > -{ > - struct device_node *node; > - int rc = 0; > - int paths; > - > - pdbus->bus_channels = 1; > - rc = of_property_read_u32(pdev->dev.of_node, > - "qcom,dpu-dram-channels", &pdbus->bus_channels); > - if (rc) { > - pr_debug("number of channels property not specified\n"); > - rc = 0; > - } > - > - pdbus->nrt_axi_port_cnt = 0; > - rc = of_property_read_u32(pdev->dev.of_node, > - "qcom,dpu-num-nrt-paths", > - &pdbus->nrt_axi_port_cnt); > - if (rc) { > - pr_debug("number of axi port property not specified\n"); > - rc = 0; > - } > - > - node = of_get_child_by_name(pdev->dev.of_node, name); > - if (node) { > - rc = of_property_read_u32(node, > - "qcom,msm-bus,num-paths", &paths); > - if (rc) { > - pr_err("Error. qcom,msm-bus,num-paths not found\n"); > - return rc; > - } > - pdbus->axi_port_cnt = paths; > - > - pdbus->data_bus_scale_table = > - msm_bus_pdata_from_node(pdev, node); > - if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) { > - pr_err("reg bus handle parsing failed\n"); > - rc = PTR_ERR(pdbus->data_bus_scale_table); > - if (!pdbus->data_bus_scale_table) > - rc = -EINVAL; > - goto end; > - } > - pdbus->data_bus_hdl = msm_bus_scale_register_client( > - pdbus->data_bus_scale_table); > - if (!pdbus->data_bus_hdl) { > - pr_err("data_bus_client register failed\n"); > - rc = -EINVAL; > - goto end; > - } > - pr_debug("register %s data_bus_hdl=%x\n", name, > - pdbus->data_bus_hdl); > - } > - > -end: > - return rc; > -} > - > -static int dpu_power_reg_bus_parse(struct platform_device *pdev, > - struct dpu_power_handle *phandle) > -{ > - struct device_node *node; > - struct msm_bus_scale_pdata *bus_scale_table; > - int rc = 0; > - > - node = of_get_child_by_name(pdev->dev.of_node, "qcom,dpu-reg-bus"); > - if (node) { > - bus_scale_table = msm_bus_pdata_from_node(pdev, node); > - if (IS_ERR_OR_NULL(bus_scale_table)) { > - pr_err("reg bus handle parsing failed\n"); > - rc = PTR_ERR(bus_scale_table); > - if (!bus_scale_table) > - rc = -EINVAL; > - goto end; > - } > - phandle->reg_bus_hdl = msm_bus_scale_register_client( > - bus_scale_table); > - if (!phandle->reg_bus_hdl) { > - pr_err("reg_bus_client register failed\n"); > - rc = -EINVAL; > - goto end; > - } > - pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl); > - } > - > -end: > - return rc; > -} > - > -static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) > -{ > - if (reg_bus_hdl) > - msm_bus_scale_unregister_client(reg_bus_hdl); > -} > - > -int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, > - bool enable) > -{ > - int i; > - > - if (!phandle) { > - pr_err("invalid param\n"); > - return -EINVAL; > - } > - > - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; > - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > - phandle->data_bus_handle[i].enable = enable; > - > - return 0; > -} > - > -static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, > - bool enable) > -{ > - int rc = 0; > - > - pdbus->enable = enable; > - > - if (pdbus->data_bus_hdl) > - rc = _dpu_power_data_bus_set_quota(pdbus, pdbus->ab_rt, > - pdbus->ab_nrt, pdbus->ib_rt, pdbus->ib_nrt); > - > - if (rc) > - pr_err("failed to set data bus vote rc=%d enable:%d\n", > - rc, enable); > - > - return rc; > -} > - > -static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) > -{ > - int rc = 0; > - > - if (reg_bus_hdl) > - rc = msm_bus_scale_client_update_request(reg_bus_hdl, > - usecase_ndx); > - if (rc) > - pr_err("failed to set reg bus vote rc=%d\n", rc); > - > - return rc; > -} > -#else > -static int dpu_power_data_bus_parse(struct platform_device *pdev, > - struct dpu_power_data_bus_handle *pdbus, const char *name) > -{ > - return 0; > -} > - > -static void dpu_power_data_bus_unregister( > - struct dpu_power_data_bus_handle *pdbus) > -{ > -} > - > -int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, > - struct dpu_power_client *pclient, > - int bus_client, u32 bus_id, > - u64 ab_quota, u64 ib_quota) > -{ > - return 0; > -} > - > -static int dpu_power_reg_bus_parse(struct platform_device *pdev, > - struct dpu_power_handle *phandle) > -{ > - return 0; > -} > - > -static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) > -{ > -} > - > -static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) > -{ > - return 0; > -} > - > -static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, > - bool enable) > -{ > - return 0; > -} > - > -int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, > - bool enable) > -{ > - return 0; > -} > -#endif > - > -int dpu_power_resource_init(struct platform_device *pdev, > - struct dpu_power_handle *phandle) > -{ > - int rc = 0, i; > - > - if (!phandle || !pdev) { > - pr_err("invalid input param\n"); > - return -EINVAL; > - } > - > - phandle->dev = &pdev->dev; > - > - rc = dpu_power_reg_bus_parse(pdev, phandle); > - if (rc) { > - pr_err("register bus parse failed rc=%d\n", rc); > - return rc; > - } > - > - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; > - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { > - rc = dpu_power_data_bus_parse(pdev, > - &phandle->data_bus_handle[i], > - data_bus_name[i]); > - if (rc) { > - pr_err("register data bus parse failed id=%d rc=%d\n", > - i, rc); > - goto data_bus_err; > - } > - } > - > - INIT_LIST_HEAD(&phandle->power_client_clist); > - INIT_LIST_HEAD(&phandle->event_list); > - > - mutex_init(&phandle->phandle_lock); > - > - return rc; > - > -data_bus_err: > - for (i--; i >= 0; i--) > - dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); > - dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); > - return rc; > -} > - > -void dpu_power_resource_deinit(struct platform_device *pdev, > - struct dpu_power_handle *phandle) > -{ > - struct dpu_power_client *curr_client, *next_client; > - struct dpu_power_event *curr_event, *next_event; > - int i; > - > - if (!phandle || !pdev) { > - pr_err("invalid input param\n"); > - return; > - } > - > - mutex_lock(&phandle->phandle_lock); > - list_for_each_entry_safe(curr_client, next_client, > - &phandle->power_client_clist, list) { > - pr_err("cliend:%s-%d still registered with refcount:%d\n", > - curr_client->name, curr_client->id, > - curr_client->refcount); > - curr_client->active = false; > - list_del(&curr_client->list); > - } > - > - list_for_each_entry_safe(curr_event, next_event, > - &phandle->event_list, list) { > - pr_err("event:%d, client:%s still registered\n", > - curr_event->event_type, > - curr_event->client_name); > - curr_event->active = false; > - list_del(&curr_event->list); > - } > - mutex_unlock(&phandle->phandle_lock); > - > - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > - dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); > - > - dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); > -} > - > -int dpu_power_resource_enable(struct dpu_power_handle *phandle, > - struct dpu_power_client *pclient, bool enable) > -{ > - int rc = 0, i; > - bool changed = false; > - u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx; > - struct dpu_power_client *client; > - > - if (!phandle || !pclient) { > - pr_err("invalid input argument\n"); > - return -EINVAL; > - } > - > - mutex_lock(&phandle->phandle_lock); > - if (enable) > - pclient->refcount++; > - else if (pclient->refcount) > - pclient->refcount--; > - > - if (pclient->refcount) > - pclient->usecase_ndx = VOTE_INDEX_LOW; > - else > - pclient->usecase_ndx = VOTE_INDEX_DISABLE; > - > - list_for_each_entry(client, &phandle->power_client_clist, list) { > - if (client->usecase_ndx < VOTE_INDEX_MAX && > - client->usecase_ndx > max_usecase_ndx) > - max_usecase_ndx = client->usecase_ndx; > - } > - > - if (phandle->current_usecase_ndx != max_usecase_ndx) { > - changed = true; > - prev_usecase_ndx = phandle->current_usecase_ndx; > - phandle->current_usecase_ndx = max_usecase_ndx; > - } > - > - pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n", > - __builtin_return_address(0), changed, max_usecase_ndx, > - pclient->name, pclient->id, enable, pclient->refcount); > - > - if (!changed) > - goto end; > - > - if (enable) { > - dpu_power_event_trigger_locked(phandle, > - DPU_POWER_EVENT_PRE_ENABLE); > - > - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { > - rc = dpu_power_data_bus_update( > - &phandle->data_bus_handle[i], enable); > - if (rc) { > - pr_err("failed to set data bus vote id=%d rc=%d\n", > - i, rc); > - goto data_bus_hdl_err; > - } > - } > - > - rc = dpu_power_reg_bus_update(phandle->reg_bus_hdl, > - max_usecase_ndx); > - if (rc) { > - pr_err("failed to set reg bus vote rc=%d\n", rc); > - goto reg_bus_hdl_err; > - } > - > - dpu_power_event_trigger_locked(phandle, > - DPU_POWER_EVENT_POST_ENABLE); > - > - } else { > - dpu_power_event_trigger_locked(phandle, > - DPU_POWER_EVENT_PRE_DISABLE); > - > - dpu_power_reg_bus_update(phandle->reg_bus_hdl, > - max_usecase_ndx); > - > - for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > - dpu_power_data_bus_update(&phandle->data_bus_handle[i], > - enable); > - > - dpu_power_event_trigger_locked(phandle, > - DPU_POWER_EVENT_POST_DISABLE); > - } > - > -end: > - mutex_unlock(&phandle->phandle_lock); > - return rc; > - > -reg_bus_hdl_err: > - for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) > - dpu_power_data_bus_update(&phandle->data_bus_handle[i], 0); > -data_bus_hdl_err: > - phandle->current_usecase_ndx = prev_usecase_ndx; > - mutex_unlock(&phandle->phandle_lock); > - return rc; > -} > - > -struct dpu_power_event *dpu_power_handle_register_event( > - struct dpu_power_handle *phandle, > - u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), > - void *usr, char *client_name) > -{ > - struct dpu_power_event *event; > - > - if (!phandle) { > - pr_err("invalid power handle\n"); > - return ERR_PTR(-EINVAL); > - } else if (!cb_fnc || !event_type) { > - pr_err("no callback fnc or event type\n"); > - return ERR_PTR(-EINVAL); > - } > - > - event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL); > - if (!event) > - return ERR_PTR(-ENOMEM); > - > - event->event_type = event_type; > - event->cb_fnc = cb_fnc; > - event->usr = usr; > - strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); > - event->active = true; > - > - mutex_lock(&phandle->phandle_lock); > - list_add(&event->list, &phandle->event_list); > - mutex_unlock(&phandle->phandle_lock); > - > - return event; > -} > - > -void dpu_power_handle_unregister_event( > - struct dpu_power_handle *phandle, > - struct dpu_power_event *event) > -{ > - if (!phandle || !event) { > - pr_err("invalid phandle or event\n"); > - } else if (!event->active) { > - pr_err("power handle deinit already done\n"); > - kfree(event); > - } else { > - mutex_lock(&phandle->phandle_lock); > - list_del_init(&event->list); > - mutex_unlock(&phandle->phandle_lock); > - kfree(event); > - } > -} > diff --git a/drivers/gpu/drm/msm/dpu_power_handle.h b/drivers/gpu/drm/msm/dpu_power_handle.h > deleted file mode 100644 > index 9a6d4b9..0000000 > --- a/drivers/gpu/drm/msm/dpu_power_handle.h > +++ /dev/null > @@ -1,288 +0,0 @@ > -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License version 2 and > - * only version 2 as published by the Free Software Foundation. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - */ > - > -#ifndef _DPU_POWER_HANDLE_H_ > -#define _DPU_POWER_HANDLE_H_ > - > -#define MAX_CLIENT_NAME_LEN 128 > - > -#define DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0 > -#define DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0 > -#define DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 1600000000 > -#define DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0 > - > -#include <linux/dpu_io_util.h> > - > -/* event will be triggered before power handler disable */ > -#define DPU_POWER_EVENT_PRE_DISABLE 0x1 > - > -/* event will be triggered after power handler disable */ > -#define DPU_POWER_EVENT_POST_DISABLE 0x2 > - > -/* event will be triggered before power handler enable */ > -#define DPU_POWER_EVENT_PRE_ENABLE 0x4 > - > -/* event will be triggered after power handler enable */ > -#define DPU_POWER_EVENT_POST_ENABLE 0x8 > - > -/** > - * mdss_bus_vote_type: register bus vote type > - * VOTE_INDEX_DISABLE: removes the client vote > - * VOTE_INDEX_LOW: keeps the lowest vote for register bus > - * VOTE_INDEX_MAX: invalid > - */ > -enum mdss_bus_vote_type { > - VOTE_INDEX_DISABLE, > - VOTE_INDEX_LOW, > - VOTE_INDEX_MAX, > -}; > - > -/** > - * enum dpu_power_handle_data_bus_client - type of axi bus clients > - * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client > - * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client > - * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type > - */ > -enum dpu_power_handle_data_bus_client { > - DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, > - DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, > - DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX > -}; > - > -/** > - * enum DPU_POWER_HANDLE_DBUS_ID - data bus identifier > - * @DPU_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus > - * @DPU_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus > - * @DPU_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus > - */ > -enum DPU_POWER_HANDLE_DBUS_ID { > - DPU_POWER_HANDLE_DBUS_ID_MNOC, > - DPU_POWER_HANDLE_DBUS_ID_LLCC, > - DPU_POWER_HANDLE_DBUS_ID_EBI, > - DPU_POWER_HANDLE_DBUS_ID_MAX, > -}; > - > -/** > - * struct dpu_power_client: stores the power client for dpu driver > - * @name: name of the client > - * @usecase_ndx: current regs bus vote type > - * @refcount: current refcount if multiple modules are using same > - * same client for enable/disable. Power module will > - * aggregate the refcount and vote accordingly for this > - * client. > - * @id: assigned during create. helps for debugging. > - * @list: list to attach power handle master list > - * @ab: arbitrated bandwidth for each bus client > - * @ib: instantaneous bandwidth for each bus client > - * @active: inidcates the state of dpu power handle > - */ > -struct dpu_power_client { > - char name[MAX_CLIENT_NAME_LEN]; > - short usecase_ndx; > - short refcount; > - u32 id; > - struct list_head list; > - u64 ab[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; > - u64 ib[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; > - bool active; > -}; > - > -/** > - * struct dpu_power_data_handle: power handle struct for data bus > - * @data_bus_scale_table: pointer to bus scaling table > - * @data_bus_hdl: current data bus handle > - * @axi_port_cnt: number of rt axi ports > - * @nrt_axi_port_cnt: number of nrt axi ports > - * @bus_channels: number of memory bus channels > - * @curr_bw_uc_idx: current use case index of data bus > - * @ao_bw_uc_idx: active only use case index of data bus > - * @ab_rt: realtime ab quota > - * @ib_rt: realtime ib quota > - * @ab_nrt: non-realtime ab quota > - * @ib_nrt: non-realtime ib quota > - * @enable: true if bus is enabled > - */ > -struct dpu_power_data_bus_handle { > - struct msm_bus_scale_pdata *data_bus_scale_table; > - u32 data_bus_hdl; > - u32 axi_port_cnt; > - u32 nrt_axi_port_cnt; > - u32 bus_channels; > - u32 curr_bw_uc_idx; > - u32 ao_bw_uc_idx; > - u64 ab_rt; > - u64 ib_rt; > - u64 ab_nrt; > - u64 ib_nrt; > - bool enable; > -}; > - > -/* > - * struct dpu_power_event - local event registration structure > - * @client_name: name of the client registering > - * @cb_fnc: pointer to desired callback function > - * @usr: user pointer to pass to callback event trigger > - * @event: refer to DPU_POWER_HANDLE_EVENT_* > - * @list: list to attach event master list > - * @active: indicates the state of dpu power handle > - */ > -struct dpu_power_event { > - char client_name[MAX_CLIENT_NAME_LEN]; > - void (*cb_fnc)(u32 event_type, void *usr); > - void *usr; > - u32 event_type; > - struct list_head list; > - bool active; > -}; > - > -/** > - * struct dpu_power_handle: power handle main struct > - * @client_clist: master list to store all clients > - * @phandle_lock: lock to synchronize the enable/disable > - * @dev: pointer to device structure > - * @usecase_ndx: current usecase index > - * @reg_bus_hdl: current register bus handle > - * @data_bus_handle: context structure for data bus control > - * @event_list: current power handle event list > - */ > -struct dpu_power_handle { > - struct list_head power_client_clist; > - struct mutex phandle_lock; > - struct device *dev; > - u32 current_usecase_ndx; > - u32 reg_bus_hdl; > - struct dpu_power_data_bus_handle data_bus_handle > - [DPU_POWER_HANDLE_DBUS_ID_MAX]; > - struct list_head event_list; > -}; > - > -/** > - * dpu_power_resource_init() - initializes the dpu power handle > - * @pdev: platform device to search the power resources > - * @pdata: power handle to store the power resources > - * > - * Return: error code. > - */ > -int dpu_power_resource_init(struct platform_device *pdev, > - struct dpu_power_handle *pdata); > - > -/** > - * dpu_power_resource_deinit() - release the dpu power handle > - * @pdev: platform device for power resources > - * @pdata: power handle containing the resources > - * > - * Return: error code. > - */ > -void dpu_power_resource_deinit(struct platform_device *pdev, > - struct dpu_power_handle *pdata); > - > -/** > - * dpu_power_client_create() - create the client on power handle > - * @pdata: power handle containing the resources > - * @client_name: new client name for registration > - * > - * Return: error code. > - */ > -struct dpu_power_client *dpu_power_client_create(struct dpu_power_handle *pdata, > - char *client_name); > - > -/** > - * dpu_power_client_destroy() - destroy the client on power handle > - * @pdata: power handle containing the resources > - * @client_name: new client name for registration > - * > - * Return: none > - */ > -void dpu_power_client_destroy(struct dpu_power_handle *phandle, > - struct dpu_power_client *client); > - > -/** > - * dpu_power_resource_enable() - enable/disable the power resources > - * @pdata: power handle containing the resources > - * @client: client information to enable/disable its vote > - * @enable: boolean request for enable/disable > - * > - * Return: error code. > - */ > -int dpu_power_resource_enable(struct dpu_power_handle *pdata, > - struct dpu_power_client *pclient, bool enable); > - > -/** > - * dpu_power_data_bus_state_update() - update data bus state > - * @pdata: power handle containing the resources > - * @enable: take enable vs disable path > - * > - * Return: error code. > - */ > -int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, > - bool enable); > - > -/** > - * dpu_power_data_bus_set_quota() - set data bus quota for power client > - * @phandle: power handle containing the resources > - * @client: client information to set quota > - * @bus_client: real-time or non-real-time bus client > - * @bus_id: identifier of data bus, see DPU_POWER_HANDLE_DBUS_ID > - * @ab_quota: arbitrated bus bandwidth > - * @ib_quota: instantaneous bus bandwidth > - * > - * Return: zero if success, or error code otherwise > - */ > -int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, > - struct dpu_power_client *pclient, > - int bus_client, u32 bus_id, > - u64 ab_quota, u64 ib_quota); > - > -/** > - * dpu_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable > - * @phandle: power handle containing the resources > - * @client: client information to bandwidth control > - * @enable: true to enable bandwidth for data base > - * > - * Return: none > - */ > -void dpu_power_data_bus_bandwidth_ctrl(struct dpu_power_handle *phandle, > - struct dpu_power_client *pclient, int enable); > - > -/** > - * dpu_power_handle_register_event - register a callback function for an event. > - * Clients can register for multiple events with a single register. > - * Any block with access to phandle can register for the event > - * notification. > - * @phandle: power handle containing the resources > - * @event_type: event type to register; refer DPU_POWER_HANDLE_EVENT_* > - * @cb_fnc: pointer to desired callback function > - * @usr: user pointer to pass to callback on event trigger > - * > - * Return: event pointer if success, or error code otherwise > - */ > -struct dpu_power_event *dpu_power_handle_register_event( > - struct dpu_power_handle *phandle, > - u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), > - void *usr, char *client_name); > -/** > - * dpu_power_handle_unregister_event - unregister callback for event(s) > - * @phandle: power handle containing the resources > - * @event: event pointer returned after power handle register > - */ > -void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle, > - struct dpu_power_event *event); > - > -/** > - * dpu_power_handle_get_dbus_name - get name of given data bus identifier > - * @bus_id: data bus identifier > - * Return: Pointer to name string if success; NULL otherwise > - */ > -const char *dpu_power_handle_get_dbus_name(u32 bus_id); > - > -#endif /* _DPU_POWER_HANDLE_H_ */ > diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c > index 5c267cd..60b6919 100644 > --- a/drivers/gpu/drm/msm/msm_drv.c > +++ b/drivers/gpu/drm/msm/msm_drv.c > @@ -340,7 +340,6 @@ static int msm_drm_uninit(struct device *dev) > component_unbind_all(dev, ddev); > > #ifdef CONFIG_DRM_MSM_DPU > - dpu_power_resource_deinit(pdev, &priv->phandle); > dpu_dbg_destroy(); > #endif > > @@ -519,12 +518,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) > drm_mode_config_init(ddev); > > #ifdef CONFIG_DRM_MSM_DPU > - ret = dpu_power_resource_init(pdev, &priv->phandle); > - if (ret) { > - pr_err("dpu power resource init failed\n"); > - goto power_init_fail; > - } > - > ret = dpu_dbg_init(&pdev->dev); > if (ret) { > dev_err(dev, "failed to init dpu dbg: %d\n", ret); > @@ -733,8 +726,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) > #ifdef CONFIG_DRM_MSM_DPU > dpu_dbg_destroy(); > dbg_init_fail: > - dpu_power_resource_deinit(pdev, &priv->phandle); > -power_init_fail: > #endif > if (mdss && mdss->funcs) > mdss->funcs->destroy(ddev); > diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h > index f9ae96f..27a73a8 100644 > --- a/drivers/gpu/drm/msm/msm_drv.h > +++ b/drivers/gpu/drm/msm/msm_drv.h > @@ -46,8 +46,6 @@ > #include <drm/msm_drm.h> > #include <drm/drm_gem.h> > > -#include "dpu_power_handle.h" > - > #define GET_MAJOR_REV(rev) ((rev) >> 28) > #define GET_MINOR_REV(rev) (((rev) >> 16) & 0xFFF) > #define GET_STEP_REV(rev) ((rev) & 0xFFFF) > @@ -375,8 +373,6 @@ struct msm_drm_private { > > struct msm_kms *kms; > > - struct dpu_power_handle phandle; > - > /* subordinate devices, if present: */ > struct platform_device *gpu_pdev; > > -- > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, > a Linux Foundation Collaborative Project >
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index d9826c1..f578d5a 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -82,10 +82,10 @@ msm-y := \ disp/dpu1/dpu_rm.o \ disp/dpu1/dpu_vbif.o \ disp/dpu1/dpu_mdss.o \ + disp/dpu1/dpu_power_handle.o \ dpu_dbg.o \ dpu_io_util.o \ dpu_dbg_evtlog.o \ - dpu_power_handle.o \ msm_prop.o \ msm_atomic.o \ msm_debugfs.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c index 5c5cc56..33ab2ac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c @@ -18,7 +18,6 @@ #include <linux/kthread.h> #include "dpu_core_irq.h" -#include "dpu_power_handle.h" /** * dpu_core_irq_callback_handler - dispatch core interrupts diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 2cf3fca..d3a1ed9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -257,7 +257,6 @@ static void _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, = dpu_crtc_get_client_type(crtc); struct drm_crtc *tmp_crtc; struct dpu_crtc_state *dpu_cstate; - struct msm_drm_private *priv = kms->dev->dev_private; drm_for_each_crtc(tmp_crtc, crtc->dev) { if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) && @@ -287,7 +286,7 @@ static void _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, switch (curr_client_type) { case NRT_CLIENT: - dpu_power_data_bus_set_quota(&priv->phandle, kms->core_client, + dpu_power_data_bus_set_quota(&kms->phandle, kms->core_client, DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, bus_id, bus_ab_quota, bus_ib_quota); DPU_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "nrt", @@ -295,7 +294,7 @@ static void _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, break; case RT_CLIENT: - dpu_power_data_bus_set_quota(&priv->phandle, kms->core_client, + dpu_power_data_bus_set_quota(&kms->phandle, kms->core_client, DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, bus_id, bus_ab_quota, bus_ib_quota); DPU_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "rt", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index e2d2e32..99c5e75 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -598,6 +598,7 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc) _dpu_crtc_destroy_dest_scaler(dpu_crtc); _dpu_crtc_deinit_events(dpu_crtc); + dpu_crtc->phandle = NULL; drm_crtc_cleanup(crtc); mutex_destroy(&dpu_crtc->crtc_lock); @@ -2572,7 +2573,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) } if (dpu_crtc->power_event) - dpu_power_handle_unregister_event(&priv->phandle, + dpu_power_handle_unregister_event(dpu_crtc->phandle, dpu_crtc->power_event); @@ -2643,7 +2644,7 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, mutex_unlock(&dpu_crtc->crtc_lock); dpu_crtc->power_event = dpu_power_handle_register_event( - &priv->phandle, + dpu_crtc->phandle, DPU_POWER_EVENT_POST_ENABLE | DPU_POWER_EVENT_POST_DISABLE | DPU_POWER_EVENT_PRE_DISABLE, dpu_crtc_handle_power_event, crtc, dpu_crtc->name); @@ -3938,6 +3939,8 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) dpu_cp_crtc_init(crtc); dpu_cp_crtc_install_properties(crtc); + dpu_crtc->phandle = &kms->phandle; + DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); return crtc; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 9304058..671d909 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -184,6 +184,7 @@ struct dpu_crtc_event { * @misr_enable : boolean entry indicates misr enable/disable status. * @misr_frame_count : misr frame count provided by client * @misr_data : store misr data before turning off the clocks. + * @phandle: Pointer to power handler * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @rp_lock : serialization lock for resource pool @@ -240,6 +241,7 @@ struct dpu_crtc { u32 misr_frame_count; u32 misr_data[CRTC_DUAL_MIXERS]; + struct dpu_power_handle *phandle; struct dpu_power_event *power_event; struct dpu_core_perf_params cur_perf; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 298a6ef..11ae6cc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -31,7 +31,6 @@ #include "dpu_hw_ctl.h" #include "dpu_formats.h" #include "dpu_encoder_phys.h" -#include "dpu_power_handle.h" #include "dpu_crtc.h" #include "dpu_trace.h" #include "dpu_core_irq.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 9c3b220..0598cfb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1017,24 +1017,19 @@ static long dpu_kms_round_pixclk(struct msm_kms *kms, unsigned long rate, static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) { struct drm_device *dev; - struct msm_drm_private *priv; int i; dev = dpu_kms->dev; if (!dev) return; - priv = dev->dev_private; - if (!priv) - return; - if (dpu_kms->hw_intr) dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; if (dpu_kms->power_event) dpu_power_handle_unregister_event( - &priv->phandle, dpu_kms->power_event); + &dpu_kms->phandle, dpu_kms->power_event); /* safe to call these more than once during shutdown */ _dpu_debugfs_destroy(dpu_kms); @@ -1067,7 +1062,8 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) dpu_kms->catalog = NULL; if (dpu_kms->core_client) - dpu_power_client_destroy(&priv->phandle, dpu_kms->core_client); + dpu_power_client_destroy(&dpu_kms->phandle, + dpu_kms->core_client); dpu_kms->core_client = NULL; if (dpu_kms->vbif[VBIF_NRT]) @@ -1624,7 +1620,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) } #endif - dpu_kms->core_client = dpu_power_client_create(&priv->phandle, "core"); + dpu_kms->core_client = dpu_power_client_create(&dpu_kms->phandle, + "core"); if (IS_ERR_OR_NULL(dpu_kms->core_client)) { rc = PTR_ERR(dpu_kms->core_client); if (!dpu_kms->core_client) @@ -1721,7 +1718,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) #endif rc = dpu_core_perf_init(&dpu_kms->perf, dev, dpu_kms->catalog, - &priv->phandle, _dpu_kms_get_clk(dpu_kms, "core_clk")); + &dpu_kms->phandle, + _dpu_kms_get_clk(dpu_kms, "core_clk")); if (rc) { DPU_ERROR("failed to init perf %d\n", rc); goto perf_err; @@ -1765,7 +1763,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) * Handle (re)initializations during power enable */ dpu_kms_handle_power_event(DPU_POWER_EVENT_POST_ENABLE, dpu_kms); - dpu_kms->power_event = dpu_power_handle_register_event(&priv->phandle, + dpu_kms->power_event = dpu_power_handle_register_event( + &dpu_kms->phandle, DPU_POWER_EVENT_POST_ENABLE, dpu_kms_handle_power_event, dpu_kms, "kms"); @@ -1841,6 +1840,12 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) goto clk_rate_error; } + ret = dpu_power_resource_init(pdev, &dpu_kms->phandle); + if (ret) { + pr_err("dpu power resource init failed\n"); + goto power_init_fail; + } + platform_set_drvdata(pdev, dpu_kms); msm_kms_init(&dpu_kms->base, &kms_funcs); @@ -1853,6 +1858,7 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) priv->kms = &dpu_kms->base; return ret; +power_init_fail: clk_rate_error: msm_dss_put_clk(mp->clk_config, mp->num_clk); clk_get_error: @@ -1867,6 +1873,7 @@ static void dpu_unbind(struct device *dev, struct device *master, void *data) struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); struct dss_module_power *mp = &dpu_kms->mp; + dpu_power_resource_deinit(pdev, &dpu_kms->phandle); msm_dss_put_clk(mp->clk_config, mp->num_clk); devm_kfree(&pdev->dev, mp->clk_config); mp->num_clk = 0; @@ -1897,7 +1904,6 @@ static int dpu_runtime_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); struct drm_device *ddev; - struct msm_drm_private *priv; struct dss_module_power *mp = &dpu_kms->mp; ddev = dpu_kms->dev; @@ -1905,10 +1911,9 @@ static int dpu_runtime_suspend(struct device *dev) DPU_ERROR("invalid drm_device\n"); goto exit; } - priv = ddev->dev_private; - rc = dpu_power_resource_enable(&priv->phandle, - dpu_kms->core_client, false); + rc = dpu_power_resource_enable(&dpu_kms->phandle, + dpu_kms->core_client, false); if (rc) DPU_ERROR("resource disable failed: %d\n", rc); @@ -1926,7 +1931,6 @@ static int dpu_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); struct drm_device *ddev; - struct msm_drm_private *priv; struct dss_module_power *mp = &dpu_kms->mp; ddev = dpu_kms->dev; @@ -1934,7 +1938,6 @@ static int dpu_runtime_resume(struct device *dev) DPU_ERROR("invalid drm_device\n"); goto exit; } - priv = ddev->dev_private; rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); if (rc) { @@ -1942,8 +1945,8 @@ static int dpu_runtime_resume(struct device *dev) goto exit; } - rc = dpu_power_resource_enable(&priv->phandle, dpu_kms->core_client, - true); + rc = dpu_power_resource_enable(&dpu_kms->phandle, + dpu_kms->core_client, true); if (rc) DPU_ERROR("resource enable failed: %d\n", rc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index a8255fe..c48ed4e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -164,6 +164,7 @@ struct dpu_kms { struct dpu_mdss_cfg *catalog; struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX]; + struct dpu_power_handle phandle; struct dpu_power_client *core_client; #ifdef CONFIG_ION struct ion_client *iclient; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c new file mode 100644 index 0000000..77be106 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c @@ -0,0 +1,693 @@ +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__ + +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/string.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/of_platform.h> +#ifdef CONFIG_QCOM_BUS_SCALING +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#endif +#include <linux/dpu_io_util.h> + +#include "dpu_power_handle.h" +#include "dpu_trace.h" + +static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = { + [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus", + [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus", + [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus", +}; + +const char *dpu_power_handle_get_dbus_name(u32 bus_id) +{ + if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX) + return data_bus_name[bus_id]; + + return NULL; +} + +static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, + u32 event_type) +{ + struct dpu_power_event *event; + + list_for_each_entry(event, &phandle->event_list, list) { + if (event->event_type & event_type) + event->cb_fnc(event_type, event->usr); + } +} + +struct dpu_power_client *dpu_power_client_create( + struct dpu_power_handle *phandle, char *client_name) +{ + struct dpu_power_client *client; + static u32 id; + + if (!client_name || !phandle) { + pr_err("client name is null or invalid power data\n"); + return ERR_PTR(-EINVAL); + } + + client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + mutex_lock(&phandle->phandle_lock); + strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); + client->usecase_ndx = VOTE_INDEX_DISABLE; + client->id = id; + client->active = true; + pr_debug("client %s created:%pK id :%d\n", client_name, + client, id); + id++; + list_add(&client->list, &phandle->power_client_clist); + mutex_unlock(&phandle->phandle_lock); + + return client; +} + +void dpu_power_client_destroy(struct dpu_power_handle *phandle, + struct dpu_power_client *client) +{ + if (!client || !phandle) { + pr_err("reg bus vote: invalid client handle\n"); + } else if (!client->active) { + pr_err("dpu power deinit already done\n"); + kfree(client); + } else { + pr_debug("bus vote client %s destroyed:%pK id:%u\n", + client->name, client, client->id); + mutex_lock(&phandle->phandle_lock); + list_del_init(&client->list); + mutex_unlock(&phandle->phandle_lock); + kfree(client); + } +} + +#ifdef CONFIG_QCOM_BUS_SCALING + +#define MAX_AXI_PORT_COUNT 3 + +static int _dpu_power_data_bus_set_quota( + struct dpu_power_data_bus_handle *pdbus, + u64 ab_quota_rt, u64 ab_quota_nrt, + u64 ib_quota_rt, u64 ib_quota_nrt) +{ + int new_uc_idx; + u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0}; + u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0}; + int rc; + + if (pdbus->data_bus_hdl < 1) { + pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl); + return -EINVAL; + } + + pdbus->ab_rt = ab_quota_rt; + pdbus->ib_rt = ib_quota_rt; + pdbus->ab_nrt = ab_quota_nrt; + pdbus->ib_nrt = ib_quota_nrt; + + if (pdbus->enable) { + ab_quota_rt = max_t(u64, ab_quota_rt, + DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); + ib_quota_rt = max_t(u64, ib_quota_rt, + DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + ab_quota_nrt = max_t(u64, ab_quota_nrt, + DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); + ib_quota_nrt = max_t(u64, ib_quota_nrt, + DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + } else { + ab_quota_rt = min_t(u64, ab_quota_rt, + DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); + ib_quota_rt = min_t(u64, ib_quota_rt, + DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); + ab_quota_nrt = min_t(u64, ab_quota_nrt, + DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); + ib_quota_nrt = min_t(u64, ib_quota_nrt, + DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); + } + + if (!ab_quota_rt && !ab_quota_nrt && !ib_quota_rt && !ib_quota_nrt) { + new_uc_idx = 0; + } else { + int i; + struct msm_bus_vectors *vect = NULL; + struct msm_bus_scale_pdata *bw_table = + pdbus->data_bus_scale_table; + u32 nrt_axi_port_cnt = pdbus->nrt_axi_port_cnt; + u32 total_axi_port_cnt = pdbus->axi_port_cnt; + u32 rt_axi_port_cnt = total_axi_port_cnt - nrt_axi_port_cnt; + + if (!bw_table || !total_axi_port_cnt || + total_axi_port_cnt > MAX_AXI_PORT_COUNT) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (pdbus->bus_channels) { + ib_quota_rt = div_u64(ib_quota_rt, + pdbus->bus_channels); + ib_quota_nrt = div_u64(ib_quota_nrt, + pdbus->bus_channels); + } + + if (nrt_axi_port_cnt) { + + ab_quota_rt = div_u64(ab_quota_rt, rt_axi_port_cnt); + ab_quota_nrt = div_u64(ab_quota_nrt, nrt_axi_port_cnt); + + for (i = 0; i < total_axi_port_cnt; i++) { + if (i < rt_axi_port_cnt) { + ab_quota[i] = ab_quota_rt; + ib_quota[i] = ib_quota_rt; + } else { + ab_quota[i] = ab_quota_nrt; + ib_quota[i] = ib_quota_nrt; + } + } + } else { + ab_quota[0] = div_u64(ab_quota_rt + ab_quota_nrt, + total_axi_port_cnt); + ib_quota[0] = ib_quota_rt + ib_quota_nrt; + + for (i = 1; i < total_axi_port_cnt; i++) { + ab_quota[i] = ab_quota[0]; + ib_quota[i] = ib_quota[0]; + } + } + + new_uc_idx = (pdbus->curr_bw_uc_idx % + (bw_table->num_usecases - 1)) + 1; + + for (i = 0; i < total_axi_port_cnt; i++) { + vect = &bw_table->usecase[new_uc_idx].vectors[i]; + vect->ab = ab_quota[i]; + vect->ib = ib_quota[i]; + + pr_debug( + "%s uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n", + bw_table->name, + new_uc_idx, (i < rt_axi_port_cnt) ? "rt" : "nrt" + , i, vect->ab, vect->ib); + } + } + pdbus->curr_bw_uc_idx = new_uc_idx; + pdbus->ao_bw_uc_idx = new_uc_idx; + + DPU_ATRACE_BEGIN("msm_bus_scale_req"); + rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl, + new_uc_idx); + DPU_ATRACE_END("msm_bus_scale_req"); + + return rc; +} + +int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, + int bus_client, u32 bus_id, + u64 ab_quota, u64 ib_quota) +{ + int rc = 0; + int i; + u64 total_ab_rt = 0, total_ib_rt = 0; + u64 total_ab_nrt = 0, total_ib_nrt = 0; + struct dpu_power_client *client; + + if (!phandle || !pclient || + bus_client >= DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX || + bus_id >= DPU_POWER_HANDLE_DBUS_ID_MAX) { + pr_err("invalid parameters\n"); + return -EINVAL; + } + + mutex_lock(&phandle->phandle_lock); + + pclient->ab[bus_client] = ab_quota; + pclient->ib[bus_client] = ib_quota; + trace_dpu_perf_update_bus(bus_client, ab_quota, ib_quota); + + list_for_each_entry(client, &phandle->power_client_clist, list) { + for (i = 0; i < DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) { + if (i == DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT) { + total_ab_nrt += client->ab[i]; + total_ib_nrt += client->ib[i]; + } else { + total_ab_rt += client->ab[i]; + total_ib_rt = max(total_ib_rt, client->ib[i]); + } + } + } + + if (phandle->data_bus_handle[bus_id].data_bus_hdl) + rc = _dpu_power_data_bus_set_quota( + &phandle->data_bus_handle[bus_id], + total_ab_rt, total_ab_nrt, + total_ib_rt, total_ib_nrt); + + mutex_unlock(&phandle->phandle_lock); + + return rc; +} + +static void dpu_power_data_bus_unregister( + struct dpu_power_data_bus_handle *pdbus) +{ + if (pdbus->data_bus_hdl) { + msm_bus_scale_unregister_client(pdbus->data_bus_hdl); + pdbus->data_bus_hdl = 0; + } +} + +static int dpu_power_data_bus_parse(struct platform_device *pdev, + struct dpu_power_data_bus_handle *pdbus, const char *name) +{ + struct device_node *node; + int rc = 0; + int paths; + + pdbus->bus_channels = 1; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,dpu-dram-channels", &pdbus->bus_channels); + if (rc) { + pr_debug("number of channels property not specified\n"); + rc = 0; + } + + pdbus->nrt_axi_port_cnt = 0; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,dpu-num-nrt-paths", + &pdbus->nrt_axi_port_cnt); + if (rc) { + pr_debug("number of axi port property not specified\n"); + rc = 0; + } + + node = of_get_child_by_name(pdev->dev.of_node, name); + if (node) { + rc = of_property_read_u32(node, + "qcom,msm-bus,num-paths", &paths); + if (rc) { + pr_err("Error. qcom,msm-bus,num-paths not found\n"); + return rc; + } + pdbus->axi_port_cnt = paths; + + pdbus->data_bus_scale_table = + msm_bus_pdata_from_node(pdev, node); + if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) { + pr_err("reg bus handle parsing failed\n"); + rc = PTR_ERR(pdbus->data_bus_scale_table); + if (!pdbus->data_bus_scale_table) + rc = -EINVAL; + goto end; + } + pdbus->data_bus_hdl = msm_bus_scale_register_client( + pdbus->data_bus_scale_table); + if (!pdbus->data_bus_hdl) { + pr_err("data_bus_client register failed\n"); + rc = -EINVAL; + goto end; + } + pr_debug("register %s data_bus_hdl=%x\n", name, + pdbus->data_bus_hdl); + } + +end: + return rc; +} + +static int dpu_power_reg_bus_parse(struct platform_device *pdev, + struct dpu_power_handle *phandle) +{ + struct device_node *node; + struct msm_bus_scale_pdata *bus_scale_table; + int rc = 0; + + node = of_get_child_by_name(pdev->dev.of_node, "qcom,dpu-reg-bus"); + if (node) { + bus_scale_table = msm_bus_pdata_from_node(pdev, node); + if (IS_ERR_OR_NULL(bus_scale_table)) { + pr_err("reg bus handle parsing failed\n"); + rc = PTR_ERR(bus_scale_table); + if (!bus_scale_table) + rc = -EINVAL; + goto end; + } + phandle->reg_bus_hdl = msm_bus_scale_register_client( + bus_scale_table); + if (!phandle->reg_bus_hdl) { + pr_err("reg_bus_client register failed\n"); + rc = -EINVAL; + goto end; + } + pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl); + } + +end: + return rc; +} + +static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) +{ + if (reg_bus_hdl) + msm_bus_scale_unregister_client(reg_bus_hdl); +} + +int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, + bool enable) +{ + int i; + + if (!phandle) { + pr_err("invalid param\n"); + return -EINVAL; + } + + for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; + i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) + phandle->data_bus_handle[i].enable = enable; + + return 0; +} + +static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, + bool enable) +{ + int rc = 0; + + pdbus->enable = enable; + + if (pdbus->data_bus_hdl) + rc = _dpu_power_data_bus_set_quota(pdbus, pdbus->ab_rt, + pdbus->ab_nrt, pdbus->ib_rt, pdbus->ib_nrt); + + if (rc) + pr_err("failed to set data bus vote rc=%d enable:%d\n", + rc, enable); + + return rc; +} + +static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) +{ + int rc = 0; + + if (reg_bus_hdl) + rc = msm_bus_scale_client_update_request(reg_bus_hdl, + usecase_ndx); + if (rc) + pr_err("failed to set reg bus vote rc=%d\n", rc); + + return rc; +} +#else +static int dpu_power_data_bus_parse(struct platform_device *pdev, + struct dpu_power_data_bus_handle *pdbus, const char *name) +{ + return 0; +} + +static void dpu_power_data_bus_unregister( + struct dpu_power_data_bus_handle *pdbus) +{ +} + +int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, + int bus_client, u32 bus_id, + u64 ab_quota, u64 ib_quota) +{ + return 0; +} + +static int dpu_power_reg_bus_parse(struct platform_device *pdev, + struct dpu_power_handle *phandle) +{ + return 0; +} + +static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) +{ +} + +static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) +{ + return 0; +} + +static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, + bool enable) +{ + return 0; +} + +int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, + bool enable) +{ + return 0; +} +#endif + +int dpu_power_resource_init(struct platform_device *pdev, + struct dpu_power_handle *phandle) +{ + int rc = 0, i; + + if (!phandle || !pdev) { + pr_err("invalid input param\n"); + return -EINVAL; + } + + phandle->dev = &pdev->dev; + + rc = dpu_power_reg_bus_parse(pdev, phandle); + if (rc) { + pr_err("register bus parse failed rc=%d\n", rc); + return rc; + } + + for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; + i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + rc = dpu_power_data_bus_parse(pdev, + &phandle->data_bus_handle[i], + data_bus_name[i]); + if (rc) { + pr_err("register data bus parse failed id=%d rc=%d\n", + i, rc); + goto data_bus_err; + } + } + + INIT_LIST_HEAD(&phandle->power_client_clist); + INIT_LIST_HEAD(&phandle->event_list); + + mutex_init(&phandle->phandle_lock); + + return rc; + +data_bus_err: + for (i--; i >= 0; i--) + dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); + dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); + return rc; +} + +void dpu_power_resource_deinit(struct platform_device *pdev, + struct dpu_power_handle *phandle) +{ + struct dpu_power_client *curr_client, *next_client; + struct dpu_power_event *curr_event, *next_event; + int i; + + if (!phandle || !pdev) { + pr_err("invalid input param\n"); + return; + } + + mutex_lock(&phandle->phandle_lock); + list_for_each_entry_safe(curr_client, next_client, + &phandle->power_client_clist, list) { + pr_err("cliend:%s-%d still registered with refcount:%d\n", + curr_client->name, curr_client->id, + curr_client->refcount); + curr_client->active = false; + list_del(&curr_client->list); + } + + list_for_each_entry_safe(curr_event, next_event, + &phandle->event_list, list) { + pr_err("event:%d, client:%s still registered\n", + curr_event->event_type, + curr_event->client_name); + curr_event->active = false; + list_del(&curr_event->list); + } + mutex_unlock(&phandle->phandle_lock); + + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) + dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); + + dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); +} + +int dpu_power_resource_enable(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, bool enable) +{ + int rc = 0, i; + bool changed = false; + u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx; + struct dpu_power_client *client; + + if (!phandle || !pclient) { + pr_err("invalid input argument\n"); + return -EINVAL; + } + + mutex_lock(&phandle->phandle_lock); + if (enable) + pclient->refcount++; + else if (pclient->refcount) + pclient->refcount--; + + if (pclient->refcount) + pclient->usecase_ndx = VOTE_INDEX_LOW; + else + pclient->usecase_ndx = VOTE_INDEX_DISABLE; + + list_for_each_entry(client, &phandle->power_client_clist, list) { + if (client->usecase_ndx < VOTE_INDEX_MAX && + client->usecase_ndx > max_usecase_ndx) + max_usecase_ndx = client->usecase_ndx; + } + + if (phandle->current_usecase_ndx != max_usecase_ndx) { + changed = true; + prev_usecase_ndx = phandle->current_usecase_ndx; + phandle->current_usecase_ndx = max_usecase_ndx; + } + + pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n", + __builtin_return_address(0), changed, max_usecase_ndx, + pclient->name, pclient->id, enable, pclient->refcount); + + if (!changed) + goto end; + + if (enable) { + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_PRE_ENABLE); + + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + rc = dpu_power_data_bus_update( + &phandle->data_bus_handle[i], enable); + if (rc) { + pr_err("failed to set data bus vote id=%d rc=%d\n", + i, rc); + goto data_bus_hdl_err; + } + } + + rc = dpu_power_reg_bus_update(phandle->reg_bus_hdl, + max_usecase_ndx); + if (rc) { + pr_err("failed to set reg bus vote rc=%d\n", rc); + goto reg_bus_hdl_err; + } + + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_POST_ENABLE); + + } else { + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_PRE_DISABLE); + + dpu_power_reg_bus_update(phandle->reg_bus_hdl, + max_usecase_ndx); + + for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) + dpu_power_data_bus_update(&phandle->data_bus_handle[i], + enable); + + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_POST_DISABLE); + } + +end: + mutex_unlock(&phandle->phandle_lock); + return rc; + +reg_bus_hdl_err: + for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) + dpu_power_data_bus_update(&phandle->data_bus_handle[i], 0); +data_bus_hdl_err: + phandle->current_usecase_ndx = prev_usecase_ndx; + mutex_unlock(&phandle->phandle_lock); + return rc; +} + +struct dpu_power_event *dpu_power_handle_register_event( + struct dpu_power_handle *phandle, + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), + void *usr, char *client_name) +{ + struct dpu_power_event *event; + + if (!phandle) { + pr_err("invalid power handle\n"); + return ERR_PTR(-EINVAL); + } else if (!cb_fnc || !event_type) { + pr_err("no callback fnc or event type\n"); + return ERR_PTR(-EINVAL); + } + + event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL); + if (!event) + return ERR_PTR(-ENOMEM); + + event->event_type = event_type; + event->cb_fnc = cb_fnc; + event->usr = usr; + strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); + event->active = true; + + mutex_lock(&phandle->phandle_lock); + list_add(&event->list, &phandle->event_list); + mutex_unlock(&phandle->phandle_lock); + + return event; +} + +void dpu_power_handle_unregister_event( + struct dpu_power_handle *phandle, + struct dpu_power_event *event) +{ + if (!phandle || !event) { + pr_err("invalid phandle or event\n"); + } else if (!event->active) { + pr_err("power handle deinit already done\n"); + kfree(event); + } else { + mutex_lock(&phandle->phandle_lock); + list_del_init(&event->list); + mutex_unlock(&phandle->phandle_lock); + kfree(event); + } +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h new file mode 100644 index 0000000..9a6d4b9 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DPU_POWER_HANDLE_H_ +#define _DPU_POWER_HANDLE_H_ + +#define MAX_CLIENT_NAME_LEN 128 + +#define DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0 +#define DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0 +#define DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 1600000000 +#define DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0 + +#include <linux/dpu_io_util.h> + +/* event will be triggered before power handler disable */ +#define DPU_POWER_EVENT_PRE_DISABLE 0x1 + +/* event will be triggered after power handler disable */ +#define DPU_POWER_EVENT_POST_DISABLE 0x2 + +/* event will be triggered before power handler enable */ +#define DPU_POWER_EVENT_PRE_ENABLE 0x4 + +/* event will be triggered after power handler enable */ +#define DPU_POWER_EVENT_POST_ENABLE 0x8 + +/** + * mdss_bus_vote_type: register bus vote type + * VOTE_INDEX_DISABLE: removes the client vote + * VOTE_INDEX_LOW: keeps the lowest vote for register bus + * VOTE_INDEX_MAX: invalid + */ +enum mdss_bus_vote_type { + VOTE_INDEX_DISABLE, + VOTE_INDEX_LOW, + VOTE_INDEX_MAX, +}; + +/** + * enum dpu_power_handle_data_bus_client - type of axi bus clients + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type + */ +enum dpu_power_handle_data_bus_client { + DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, + DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, + DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX +}; + +/** + * enum DPU_POWER_HANDLE_DBUS_ID - data bus identifier + * @DPU_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus + * @DPU_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus + * @DPU_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus + */ +enum DPU_POWER_HANDLE_DBUS_ID { + DPU_POWER_HANDLE_DBUS_ID_MNOC, + DPU_POWER_HANDLE_DBUS_ID_LLCC, + DPU_POWER_HANDLE_DBUS_ID_EBI, + DPU_POWER_HANDLE_DBUS_ID_MAX, +}; + +/** + * struct dpu_power_client: stores the power client for dpu driver + * @name: name of the client + * @usecase_ndx: current regs bus vote type + * @refcount: current refcount if multiple modules are using same + * same client for enable/disable. Power module will + * aggregate the refcount and vote accordingly for this + * client. + * @id: assigned during create. helps for debugging. + * @list: list to attach power handle master list + * @ab: arbitrated bandwidth for each bus client + * @ib: instantaneous bandwidth for each bus client + * @active: inidcates the state of dpu power handle + */ +struct dpu_power_client { + char name[MAX_CLIENT_NAME_LEN]; + short usecase_ndx; + short refcount; + u32 id; + struct list_head list; + u64 ab[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; + u64 ib[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; + bool active; +}; + +/** + * struct dpu_power_data_handle: power handle struct for data bus + * @data_bus_scale_table: pointer to bus scaling table + * @data_bus_hdl: current data bus handle + * @axi_port_cnt: number of rt axi ports + * @nrt_axi_port_cnt: number of nrt axi ports + * @bus_channels: number of memory bus channels + * @curr_bw_uc_idx: current use case index of data bus + * @ao_bw_uc_idx: active only use case index of data bus + * @ab_rt: realtime ab quota + * @ib_rt: realtime ib quota + * @ab_nrt: non-realtime ab quota + * @ib_nrt: non-realtime ib quota + * @enable: true if bus is enabled + */ +struct dpu_power_data_bus_handle { + struct msm_bus_scale_pdata *data_bus_scale_table; + u32 data_bus_hdl; + u32 axi_port_cnt; + u32 nrt_axi_port_cnt; + u32 bus_channels; + u32 curr_bw_uc_idx; + u32 ao_bw_uc_idx; + u64 ab_rt; + u64 ib_rt; + u64 ab_nrt; + u64 ib_nrt; + bool enable; +}; + +/* + * struct dpu_power_event - local event registration structure + * @client_name: name of the client registering + * @cb_fnc: pointer to desired callback function + * @usr: user pointer to pass to callback event trigger + * @event: refer to DPU_POWER_HANDLE_EVENT_* + * @list: list to attach event master list + * @active: indicates the state of dpu power handle + */ +struct dpu_power_event { + char client_name[MAX_CLIENT_NAME_LEN]; + void (*cb_fnc)(u32 event_type, void *usr); + void *usr; + u32 event_type; + struct list_head list; + bool active; +}; + +/** + * struct dpu_power_handle: power handle main struct + * @client_clist: master list to store all clients + * @phandle_lock: lock to synchronize the enable/disable + * @dev: pointer to device structure + * @usecase_ndx: current usecase index + * @reg_bus_hdl: current register bus handle + * @data_bus_handle: context structure for data bus control + * @event_list: current power handle event list + */ +struct dpu_power_handle { + struct list_head power_client_clist; + struct mutex phandle_lock; + struct device *dev; + u32 current_usecase_ndx; + u32 reg_bus_hdl; + struct dpu_power_data_bus_handle data_bus_handle + [DPU_POWER_HANDLE_DBUS_ID_MAX]; + struct list_head event_list; +}; + +/** + * dpu_power_resource_init() - initializes the dpu power handle + * @pdev: platform device to search the power resources + * @pdata: power handle to store the power resources + * + * Return: error code. + */ +int dpu_power_resource_init(struct platform_device *pdev, + struct dpu_power_handle *pdata); + +/** + * dpu_power_resource_deinit() - release the dpu power handle + * @pdev: platform device for power resources + * @pdata: power handle containing the resources + * + * Return: error code. + */ +void dpu_power_resource_deinit(struct platform_device *pdev, + struct dpu_power_handle *pdata); + +/** + * dpu_power_client_create() - create the client on power handle + * @pdata: power handle containing the resources + * @client_name: new client name for registration + * + * Return: error code. + */ +struct dpu_power_client *dpu_power_client_create(struct dpu_power_handle *pdata, + char *client_name); + +/** + * dpu_power_client_destroy() - destroy the client on power handle + * @pdata: power handle containing the resources + * @client_name: new client name for registration + * + * Return: none + */ +void dpu_power_client_destroy(struct dpu_power_handle *phandle, + struct dpu_power_client *client); + +/** + * dpu_power_resource_enable() - enable/disable the power resources + * @pdata: power handle containing the resources + * @client: client information to enable/disable its vote + * @enable: boolean request for enable/disable + * + * Return: error code. + */ +int dpu_power_resource_enable(struct dpu_power_handle *pdata, + struct dpu_power_client *pclient, bool enable); + +/** + * dpu_power_data_bus_state_update() - update data bus state + * @pdata: power handle containing the resources + * @enable: take enable vs disable path + * + * Return: error code. + */ +int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, + bool enable); + +/** + * dpu_power_data_bus_set_quota() - set data bus quota for power client + * @phandle: power handle containing the resources + * @client: client information to set quota + * @bus_client: real-time or non-real-time bus client + * @bus_id: identifier of data bus, see DPU_POWER_HANDLE_DBUS_ID + * @ab_quota: arbitrated bus bandwidth + * @ib_quota: instantaneous bus bandwidth + * + * Return: zero if success, or error code otherwise + */ +int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, + int bus_client, u32 bus_id, + u64 ab_quota, u64 ib_quota); + +/** + * dpu_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable + * @phandle: power handle containing the resources + * @client: client information to bandwidth control + * @enable: true to enable bandwidth for data base + * + * Return: none + */ +void dpu_power_data_bus_bandwidth_ctrl(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, int enable); + +/** + * dpu_power_handle_register_event - register a callback function for an event. + * Clients can register for multiple events with a single register. + * Any block with access to phandle can register for the event + * notification. + * @phandle: power handle containing the resources + * @event_type: event type to register; refer DPU_POWER_HANDLE_EVENT_* + * @cb_fnc: pointer to desired callback function + * @usr: user pointer to pass to callback on event trigger + * + * Return: event pointer if success, or error code otherwise + */ +struct dpu_power_event *dpu_power_handle_register_event( + struct dpu_power_handle *phandle, + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), + void *usr, char *client_name); +/** + * dpu_power_handle_unregister_event - unregister callback for event(s) + * @phandle: power handle containing the resources + * @event: event pointer returned after power handle register + */ +void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle, + struct dpu_power_event *event); + +/** + * dpu_power_handle_get_dbus_name - get name of given data bus identifier + * @bus_id: data bus identifier + * Return: Pointer to name string if success; NULL otherwise + */ +const char *dpu_power_handle_get_dbus_name(u32 bus_id); + +#endif /* _DPU_POWER_HANDLE_H_ */ diff --git a/drivers/gpu/drm/msm/dpu_power_handle.c b/drivers/gpu/drm/msm/dpu_power_handle.c deleted file mode 100644 index 77be106..0000000 --- a/drivers/gpu/drm/msm/dpu_power_handle.c +++ /dev/null @@ -1,693 +0,0 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__ - -#include <linux/kernel.h> -#include <linux/of.h> -#include <linux/string.h> -#include <linux/of_address.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <linux/of_platform.h> -#ifdef CONFIG_QCOM_BUS_SCALING -#include <linux/msm-bus.h> -#include <linux/msm-bus-board.h> -#endif -#include <linux/dpu_io_util.h> - -#include "dpu_power_handle.h" -#include "dpu_trace.h" - -static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = { - [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus", - [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus", - [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus", -}; - -const char *dpu_power_handle_get_dbus_name(u32 bus_id) -{ - if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX) - return data_bus_name[bus_id]; - - return NULL; -} - -static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, - u32 event_type) -{ - struct dpu_power_event *event; - - list_for_each_entry(event, &phandle->event_list, list) { - if (event->event_type & event_type) - event->cb_fnc(event_type, event->usr); - } -} - -struct dpu_power_client *dpu_power_client_create( - struct dpu_power_handle *phandle, char *client_name) -{ - struct dpu_power_client *client; - static u32 id; - - if (!client_name || !phandle) { - pr_err("client name is null or invalid power data\n"); - return ERR_PTR(-EINVAL); - } - - client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL); - if (!client) - return ERR_PTR(-ENOMEM); - - mutex_lock(&phandle->phandle_lock); - strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); - client->usecase_ndx = VOTE_INDEX_DISABLE; - client->id = id; - client->active = true; - pr_debug("client %s created:%pK id :%d\n", client_name, - client, id); - id++; - list_add(&client->list, &phandle->power_client_clist); - mutex_unlock(&phandle->phandle_lock); - - return client; -} - -void dpu_power_client_destroy(struct dpu_power_handle *phandle, - struct dpu_power_client *client) -{ - if (!client || !phandle) { - pr_err("reg bus vote: invalid client handle\n"); - } else if (!client->active) { - pr_err("dpu power deinit already done\n"); - kfree(client); - } else { - pr_debug("bus vote client %s destroyed:%pK id:%u\n", - client->name, client, client->id); - mutex_lock(&phandle->phandle_lock); - list_del_init(&client->list); - mutex_unlock(&phandle->phandle_lock); - kfree(client); - } -} - -#ifdef CONFIG_QCOM_BUS_SCALING - -#define MAX_AXI_PORT_COUNT 3 - -static int _dpu_power_data_bus_set_quota( - struct dpu_power_data_bus_handle *pdbus, - u64 ab_quota_rt, u64 ab_quota_nrt, - u64 ib_quota_rt, u64 ib_quota_nrt) -{ - int new_uc_idx; - u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0}; - u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0}; - int rc; - - if (pdbus->data_bus_hdl < 1) { - pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl); - return -EINVAL; - } - - pdbus->ab_rt = ab_quota_rt; - pdbus->ib_rt = ib_quota_rt; - pdbus->ab_nrt = ab_quota_nrt; - pdbus->ib_nrt = ib_quota_nrt; - - if (pdbus->enable) { - ab_quota_rt = max_t(u64, ab_quota_rt, - DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); - ib_quota_rt = max_t(u64, ib_quota_rt, - DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); - ab_quota_nrt = max_t(u64, ab_quota_nrt, - DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA); - ib_quota_nrt = max_t(u64, ib_quota_nrt, - DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); - } else { - ab_quota_rt = min_t(u64, ab_quota_rt, - DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); - ib_quota_rt = min_t(u64, ib_quota_rt, - DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); - ab_quota_nrt = min_t(u64, ab_quota_nrt, - DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA); - ib_quota_nrt = min_t(u64, ib_quota_nrt, - DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); - } - - if (!ab_quota_rt && !ab_quota_nrt && !ib_quota_rt && !ib_quota_nrt) { - new_uc_idx = 0; - } else { - int i; - struct msm_bus_vectors *vect = NULL; - struct msm_bus_scale_pdata *bw_table = - pdbus->data_bus_scale_table; - u32 nrt_axi_port_cnt = pdbus->nrt_axi_port_cnt; - u32 total_axi_port_cnt = pdbus->axi_port_cnt; - u32 rt_axi_port_cnt = total_axi_port_cnt - nrt_axi_port_cnt; - - if (!bw_table || !total_axi_port_cnt || - total_axi_port_cnt > MAX_AXI_PORT_COUNT) { - pr_err("invalid input\n"); - return -EINVAL; - } - - if (pdbus->bus_channels) { - ib_quota_rt = div_u64(ib_quota_rt, - pdbus->bus_channels); - ib_quota_nrt = div_u64(ib_quota_nrt, - pdbus->bus_channels); - } - - if (nrt_axi_port_cnt) { - - ab_quota_rt = div_u64(ab_quota_rt, rt_axi_port_cnt); - ab_quota_nrt = div_u64(ab_quota_nrt, nrt_axi_port_cnt); - - for (i = 0; i < total_axi_port_cnt; i++) { - if (i < rt_axi_port_cnt) { - ab_quota[i] = ab_quota_rt; - ib_quota[i] = ib_quota_rt; - } else { - ab_quota[i] = ab_quota_nrt; - ib_quota[i] = ib_quota_nrt; - } - } - } else { - ab_quota[0] = div_u64(ab_quota_rt + ab_quota_nrt, - total_axi_port_cnt); - ib_quota[0] = ib_quota_rt + ib_quota_nrt; - - for (i = 1; i < total_axi_port_cnt; i++) { - ab_quota[i] = ab_quota[0]; - ib_quota[i] = ib_quota[0]; - } - } - - new_uc_idx = (pdbus->curr_bw_uc_idx % - (bw_table->num_usecases - 1)) + 1; - - for (i = 0; i < total_axi_port_cnt; i++) { - vect = &bw_table->usecase[new_uc_idx].vectors[i]; - vect->ab = ab_quota[i]; - vect->ib = ib_quota[i]; - - pr_debug( - "%s uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n", - bw_table->name, - new_uc_idx, (i < rt_axi_port_cnt) ? "rt" : "nrt" - , i, vect->ab, vect->ib); - } - } - pdbus->curr_bw_uc_idx = new_uc_idx; - pdbus->ao_bw_uc_idx = new_uc_idx; - - DPU_ATRACE_BEGIN("msm_bus_scale_req"); - rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl, - new_uc_idx); - DPU_ATRACE_END("msm_bus_scale_req"); - - return rc; -} - -int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, - struct dpu_power_client *pclient, - int bus_client, u32 bus_id, - u64 ab_quota, u64 ib_quota) -{ - int rc = 0; - int i; - u64 total_ab_rt = 0, total_ib_rt = 0; - u64 total_ab_nrt = 0, total_ib_nrt = 0; - struct dpu_power_client *client; - - if (!phandle || !pclient || - bus_client >= DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX || - bus_id >= DPU_POWER_HANDLE_DBUS_ID_MAX) { - pr_err("invalid parameters\n"); - return -EINVAL; - } - - mutex_lock(&phandle->phandle_lock); - - pclient->ab[bus_client] = ab_quota; - pclient->ib[bus_client] = ib_quota; - trace_dpu_perf_update_bus(bus_client, ab_quota, ib_quota); - - list_for_each_entry(client, &phandle->power_client_clist, list) { - for (i = 0; i < DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) { - if (i == DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT) { - total_ab_nrt += client->ab[i]; - total_ib_nrt += client->ib[i]; - } else { - total_ab_rt += client->ab[i]; - total_ib_rt = max(total_ib_rt, client->ib[i]); - } - } - } - - if (phandle->data_bus_handle[bus_id].data_bus_hdl) - rc = _dpu_power_data_bus_set_quota( - &phandle->data_bus_handle[bus_id], - total_ab_rt, total_ab_nrt, - total_ib_rt, total_ib_nrt); - - mutex_unlock(&phandle->phandle_lock); - - return rc; -} - -static void dpu_power_data_bus_unregister( - struct dpu_power_data_bus_handle *pdbus) -{ - if (pdbus->data_bus_hdl) { - msm_bus_scale_unregister_client(pdbus->data_bus_hdl); - pdbus->data_bus_hdl = 0; - } -} - -static int dpu_power_data_bus_parse(struct platform_device *pdev, - struct dpu_power_data_bus_handle *pdbus, const char *name) -{ - struct device_node *node; - int rc = 0; - int paths; - - pdbus->bus_channels = 1; - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,dpu-dram-channels", &pdbus->bus_channels); - if (rc) { - pr_debug("number of channels property not specified\n"); - rc = 0; - } - - pdbus->nrt_axi_port_cnt = 0; - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,dpu-num-nrt-paths", - &pdbus->nrt_axi_port_cnt); - if (rc) { - pr_debug("number of axi port property not specified\n"); - rc = 0; - } - - node = of_get_child_by_name(pdev->dev.of_node, name); - if (node) { - rc = of_property_read_u32(node, - "qcom,msm-bus,num-paths", &paths); - if (rc) { - pr_err("Error. qcom,msm-bus,num-paths not found\n"); - return rc; - } - pdbus->axi_port_cnt = paths; - - pdbus->data_bus_scale_table = - msm_bus_pdata_from_node(pdev, node); - if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) { - pr_err("reg bus handle parsing failed\n"); - rc = PTR_ERR(pdbus->data_bus_scale_table); - if (!pdbus->data_bus_scale_table) - rc = -EINVAL; - goto end; - } - pdbus->data_bus_hdl = msm_bus_scale_register_client( - pdbus->data_bus_scale_table); - if (!pdbus->data_bus_hdl) { - pr_err("data_bus_client register failed\n"); - rc = -EINVAL; - goto end; - } - pr_debug("register %s data_bus_hdl=%x\n", name, - pdbus->data_bus_hdl); - } - -end: - return rc; -} - -static int dpu_power_reg_bus_parse(struct platform_device *pdev, - struct dpu_power_handle *phandle) -{ - struct device_node *node; - struct msm_bus_scale_pdata *bus_scale_table; - int rc = 0; - - node = of_get_child_by_name(pdev->dev.of_node, "qcom,dpu-reg-bus"); - if (node) { - bus_scale_table = msm_bus_pdata_from_node(pdev, node); - if (IS_ERR_OR_NULL(bus_scale_table)) { - pr_err("reg bus handle parsing failed\n"); - rc = PTR_ERR(bus_scale_table); - if (!bus_scale_table) - rc = -EINVAL; - goto end; - } - phandle->reg_bus_hdl = msm_bus_scale_register_client( - bus_scale_table); - if (!phandle->reg_bus_hdl) { - pr_err("reg_bus_client register failed\n"); - rc = -EINVAL; - goto end; - } - pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl); - } - -end: - return rc; -} - -static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) -{ - if (reg_bus_hdl) - msm_bus_scale_unregister_client(reg_bus_hdl); -} - -int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, - bool enable) -{ - int i; - - if (!phandle) { - pr_err("invalid param\n"); - return -EINVAL; - } - - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) - phandle->data_bus_handle[i].enable = enable; - - return 0; -} - -static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, - bool enable) -{ - int rc = 0; - - pdbus->enable = enable; - - if (pdbus->data_bus_hdl) - rc = _dpu_power_data_bus_set_quota(pdbus, pdbus->ab_rt, - pdbus->ab_nrt, pdbus->ib_rt, pdbus->ib_nrt); - - if (rc) - pr_err("failed to set data bus vote rc=%d enable:%d\n", - rc, enable); - - return rc; -} - -static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) -{ - int rc = 0; - - if (reg_bus_hdl) - rc = msm_bus_scale_client_update_request(reg_bus_hdl, - usecase_ndx); - if (rc) - pr_err("failed to set reg bus vote rc=%d\n", rc); - - return rc; -} -#else -static int dpu_power_data_bus_parse(struct platform_device *pdev, - struct dpu_power_data_bus_handle *pdbus, const char *name) -{ - return 0; -} - -static void dpu_power_data_bus_unregister( - struct dpu_power_data_bus_handle *pdbus) -{ -} - -int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, - struct dpu_power_client *pclient, - int bus_client, u32 bus_id, - u64 ab_quota, u64 ib_quota) -{ - return 0; -} - -static int dpu_power_reg_bus_parse(struct platform_device *pdev, - struct dpu_power_handle *phandle) -{ - return 0; -} - -static void dpu_power_reg_bus_unregister(u32 reg_bus_hdl) -{ -} - -static int dpu_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) -{ - return 0; -} - -static int dpu_power_data_bus_update(struct dpu_power_data_bus_handle *pdbus, - bool enable) -{ - return 0; -} - -int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, - bool enable) -{ - return 0; -} -#endif - -int dpu_power_resource_init(struct platform_device *pdev, - struct dpu_power_handle *phandle) -{ - int rc = 0, i; - - if (!phandle || !pdev) { - pr_err("invalid input param\n"); - return -EINVAL; - } - - phandle->dev = &pdev->dev; - - rc = dpu_power_reg_bus_parse(pdev, phandle); - if (rc) { - pr_err("register bus parse failed rc=%d\n", rc); - return rc; - } - - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { - rc = dpu_power_data_bus_parse(pdev, - &phandle->data_bus_handle[i], - data_bus_name[i]); - if (rc) { - pr_err("register data bus parse failed id=%d rc=%d\n", - i, rc); - goto data_bus_err; - } - } - - INIT_LIST_HEAD(&phandle->power_client_clist); - INIT_LIST_HEAD(&phandle->event_list); - - mutex_init(&phandle->phandle_lock); - - return rc; - -data_bus_err: - for (i--; i >= 0; i--) - dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); - dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); - return rc; -} - -void dpu_power_resource_deinit(struct platform_device *pdev, - struct dpu_power_handle *phandle) -{ - struct dpu_power_client *curr_client, *next_client; - struct dpu_power_event *curr_event, *next_event; - int i; - - if (!phandle || !pdev) { - pr_err("invalid input param\n"); - return; - } - - mutex_lock(&phandle->phandle_lock); - list_for_each_entry_safe(curr_client, next_client, - &phandle->power_client_clist, list) { - pr_err("cliend:%s-%d still registered with refcount:%d\n", - curr_client->name, curr_client->id, - curr_client->refcount); - curr_client->active = false; - list_del(&curr_client->list); - } - - list_for_each_entry_safe(curr_event, next_event, - &phandle->event_list, list) { - pr_err("event:%d, client:%s still registered\n", - curr_event->event_type, - curr_event->client_name); - curr_event->active = false; - list_del(&curr_event->list); - } - mutex_unlock(&phandle->phandle_lock); - - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) - dpu_power_data_bus_unregister(&phandle->data_bus_handle[i]); - - dpu_power_reg_bus_unregister(phandle->reg_bus_hdl); -} - -int dpu_power_resource_enable(struct dpu_power_handle *phandle, - struct dpu_power_client *pclient, bool enable) -{ - int rc = 0, i; - bool changed = false; - u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx; - struct dpu_power_client *client; - - if (!phandle || !pclient) { - pr_err("invalid input argument\n"); - return -EINVAL; - } - - mutex_lock(&phandle->phandle_lock); - if (enable) - pclient->refcount++; - else if (pclient->refcount) - pclient->refcount--; - - if (pclient->refcount) - pclient->usecase_ndx = VOTE_INDEX_LOW; - else - pclient->usecase_ndx = VOTE_INDEX_DISABLE; - - list_for_each_entry(client, &phandle->power_client_clist, list) { - if (client->usecase_ndx < VOTE_INDEX_MAX && - client->usecase_ndx > max_usecase_ndx) - max_usecase_ndx = client->usecase_ndx; - } - - if (phandle->current_usecase_ndx != max_usecase_ndx) { - changed = true; - prev_usecase_ndx = phandle->current_usecase_ndx; - phandle->current_usecase_ndx = max_usecase_ndx; - } - - pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n", - __builtin_return_address(0), changed, max_usecase_ndx, - pclient->name, pclient->id, enable, pclient->refcount); - - if (!changed) - goto end; - - if (enable) { - dpu_power_event_trigger_locked(phandle, - DPU_POWER_EVENT_PRE_ENABLE); - - for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { - rc = dpu_power_data_bus_update( - &phandle->data_bus_handle[i], enable); - if (rc) { - pr_err("failed to set data bus vote id=%d rc=%d\n", - i, rc); - goto data_bus_hdl_err; - } - } - - rc = dpu_power_reg_bus_update(phandle->reg_bus_hdl, - max_usecase_ndx); - if (rc) { - pr_err("failed to set reg bus vote rc=%d\n", rc); - goto reg_bus_hdl_err; - } - - dpu_power_event_trigger_locked(phandle, - DPU_POWER_EVENT_POST_ENABLE); - - } else { - dpu_power_event_trigger_locked(phandle, - DPU_POWER_EVENT_PRE_DISABLE); - - dpu_power_reg_bus_update(phandle->reg_bus_hdl, - max_usecase_ndx); - - for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) - dpu_power_data_bus_update(&phandle->data_bus_handle[i], - enable); - - dpu_power_event_trigger_locked(phandle, - DPU_POWER_EVENT_POST_DISABLE); - } - -end: - mutex_unlock(&phandle->phandle_lock); - return rc; - -reg_bus_hdl_err: - for (i = 0 ; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) - dpu_power_data_bus_update(&phandle->data_bus_handle[i], 0); -data_bus_hdl_err: - phandle->current_usecase_ndx = prev_usecase_ndx; - mutex_unlock(&phandle->phandle_lock); - return rc; -} - -struct dpu_power_event *dpu_power_handle_register_event( - struct dpu_power_handle *phandle, - u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), - void *usr, char *client_name) -{ - struct dpu_power_event *event; - - if (!phandle) { - pr_err("invalid power handle\n"); - return ERR_PTR(-EINVAL); - } else if (!cb_fnc || !event_type) { - pr_err("no callback fnc or event type\n"); - return ERR_PTR(-EINVAL); - } - - event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL); - if (!event) - return ERR_PTR(-ENOMEM); - - event->event_type = event_type; - event->cb_fnc = cb_fnc; - event->usr = usr; - strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); - event->active = true; - - mutex_lock(&phandle->phandle_lock); - list_add(&event->list, &phandle->event_list); - mutex_unlock(&phandle->phandle_lock); - - return event; -} - -void dpu_power_handle_unregister_event( - struct dpu_power_handle *phandle, - struct dpu_power_event *event) -{ - if (!phandle || !event) { - pr_err("invalid phandle or event\n"); - } else if (!event->active) { - pr_err("power handle deinit already done\n"); - kfree(event); - } else { - mutex_lock(&phandle->phandle_lock); - list_del_init(&event->list); - mutex_unlock(&phandle->phandle_lock); - kfree(event); - } -} diff --git a/drivers/gpu/drm/msm/dpu_power_handle.h b/drivers/gpu/drm/msm/dpu_power_handle.h deleted file mode 100644 index 9a6d4b9..0000000 --- a/drivers/gpu/drm/msm/dpu_power_handle.h +++ /dev/null @@ -1,288 +0,0 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DPU_POWER_HANDLE_H_ -#define _DPU_POWER_HANDLE_H_ - -#define MAX_CLIENT_NAME_LEN 128 - -#define DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0 -#define DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0 -#define DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 1600000000 -#define DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0 - -#include <linux/dpu_io_util.h> - -/* event will be triggered before power handler disable */ -#define DPU_POWER_EVENT_PRE_DISABLE 0x1 - -/* event will be triggered after power handler disable */ -#define DPU_POWER_EVENT_POST_DISABLE 0x2 - -/* event will be triggered before power handler enable */ -#define DPU_POWER_EVENT_PRE_ENABLE 0x4 - -/* event will be triggered after power handler enable */ -#define DPU_POWER_EVENT_POST_ENABLE 0x8 - -/** - * mdss_bus_vote_type: register bus vote type - * VOTE_INDEX_DISABLE: removes the client vote - * VOTE_INDEX_LOW: keeps the lowest vote for register bus - * VOTE_INDEX_MAX: invalid - */ -enum mdss_bus_vote_type { - VOTE_INDEX_DISABLE, - VOTE_INDEX_LOW, - VOTE_INDEX_MAX, -}; - -/** - * enum dpu_power_handle_data_bus_client - type of axi bus clients - * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client - * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client - * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type - */ -enum dpu_power_handle_data_bus_client { - DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, - DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, - DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX -}; - -/** - * enum DPU_POWER_HANDLE_DBUS_ID - data bus identifier - * @DPU_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus - * @DPU_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus - * @DPU_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus - */ -enum DPU_POWER_HANDLE_DBUS_ID { - DPU_POWER_HANDLE_DBUS_ID_MNOC, - DPU_POWER_HANDLE_DBUS_ID_LLCC, - DPU_POWER_HANDLE_DBUS_ID_EBI, - DPU_POWER_HANDLE_DBUS_ID_MAX, -}; - -/** - * struct dpu_power_client: stores the power client for dpu driver - * @name: name of the client - * @usecase_ndx: current regs bus vote type - * @refcount: current refcount if multiple modules are using same - * same client for enable/disable. Power module will - * aggregate the refcount and vote accordingly for this - * client. - * @id: assigned during create. helps for debugging. - * @list: list to attach power handle master list - * @ab: arbitrated bandwidth for each bus client - * @ib: instantaneous bandwidth for each bus client - * @active: inidcates the state of dpu power handle - */ -struct dpu_power_client { - char name[MAX_CLIENT_NAME_LEN]; - short usecase_ndx; - short refcount; - u32 id; - struct list_head list; - u64 ab[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; - u64 ib[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; - bool active; -}; - -/** - * struct dpu_power_data_handle: power handle struct for data bus - * @data_bus_scale_table: pointer to bus scaling table - * @data_bus_hdl: current data bus handle - * @axi_port_cnt: number of rt axi ports - * @nrt_axi_port_cnt: number of nrt axi ports - * @bus_channels: number of memory bus channels - * @curr_bw_uc_idx: current use case index of data bus - * @ao_bw_uc_idx: active only use case index of data bus - * @ab_rt: realtime ab quota - * @ib_rt: realtime ib quota - * @ab_nrt: non-realtime ab quota - * @ib_nrt: non-realtime ib quota - * @enable: true if bus is enabled - */ -struct dpu_power_data_bus_handle { - struct msm_bus_scale_pdata *data_bus_scale_table; - u32 data_bus_hdl; - u32 axi_port_cnt; - u32 nrt_axi_port_cnt; - u32 bus_channels; - u32 curr_bw_uc_idx; - u32 ao_bw_uc_idx; - u64 ab_rt; - u64 ib_rt; - u64 ab_nrt; - u64 ib_nrt; - bool enable; -}; - -/* - * struct dpu_power_event - local event registration structure - * @client_name: name of the client registering - * @cb_fnc: pointer to desired callback function - * @usr: user pointer to pass to callback event trigger - * @event: refer to DPU_POWER_HANDLE_EVENT_* - * @list: list to attach event master list - * @active: indicates the state of dpu power handle - */ -struct dpu_power_event { - char client_name[MAX_CLIENT_NAME_LEN]; - void (*cb_fnc)(u32 event_type, void *usr); - void *usr; - u32 event_type; - struct list_head list; - bool active; -}; - -/** - * struct dpu_power_handle: power handle main struct - * @client_clist: master list to store all clients - * @phandle_lock: lock to synchronize the enable/disable - * @dev: pointer to device structure - * @usecase_ndx: current usecase index - * @reg_bus_hdl: current register bus handle - * @data_bus_handle: context structure for data bus control - * @event_list: current power handle event list - */ -struct dpu_power_handle { - struct list_head power_client_clist; - struct mutex phandle_lock; - struct device *dev; - u32 current_usecase_ndx; - u32 reg_bus_hdl; - struct dpu_power_data_bus_handle data_bus_handle - [DPU_POWER_HANDLE_DBUS_ID_MAX]; - struct list_head event_list; -}; - -/** - * dpu_power_resource_init() - initializes the dpu power handle - * @pdev: platform device to search the power resources - * @pdata: power handle to store the power resources - * - * Return: error code. - */ -int dpu_power_resource_init(struct platform_device *pdev, - struct dpu_power_handle *pdata); - -/** - * dpu_power_resource_deinit() - release the dpu power handle - * @pdev: platform device for power resources - * @pdata: power handle containing the resources - * - * Return: error code. - */ -void dpu_power_resource_deinit(struct platform_device *pdev, - struct dpu_power_handle *pdata); - -/** - * dpu_power_client_create() - create the client on power handle - * @pdata: power handle containing the resources - * @client_name: new client name for registration - * - * Return: error code. - */ -struct dpu_power_client *dpu_power_client_create(struct dpu_power_handle *pdata, - char *client_name); - -/** - * dpu_power_client_destroy() - destroy the client on power handle - * @pdata: power handle containing the resources - * @client_name: new client name for registration - * - * Return: none - */ -void dpu_power_client_destroy(struct dpu_power_handle *phandle, - struct dpu_power_client *client); - -/** - * dpu_power_resource_enable() - enable/disable the power resources - * @pdata: power handle containing the resources - * @client: client information to enable/disable its vote - * @enable: boolean request for enable/disable - * - * Return: error code. - */ -int dpu_power_resource_enable(struct dpu_power_handle *pdata, - struct dpu_power_client *pclient, bool enable); - -/** - * dpu_power_data_bus_state_update() - update data bus state - * @pdata: power handle containing the resources - * @enable: take enable vs disable path - * - * Return: error code. - */ -int dpu_power_data_bus_state_update(struct dpu_power_handle *phandle, - bool enable); - -/** - * dpu_power_data_bus_set_quota() - set data bus quota for power client - * @phandle: power handle containing the resources - * @client: client information to set quota - * @bus_client: real-time or non-real-time bus client - * @bus_id: identifier of data bus, see DPU_POWER_HANDLE_DBUS_ID - * @ab_quota: arbitrated bus bandwidth - * @ib_quota: instantaneous bus bandwidth - * - * Return: zero if success, or error code otherwise - */ -int dpu_power_data_bus_set_quota(struct dpu_power_handle *phandle, - struct dpu_power_client *pclient, - int bus_client, u32 bus_id, - u64 ab_quota, u64 ib_quota); - -/** - * dpu_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable - * @phandle: power handle containing the resources - * @client: client information to bandwidth control - * @enable: true to enable bandwidth for data base - * - * Return: none - */ -void dpu_power_data_bus_bandwidth_ctrl(struct dpu_power_handle *phandle, - struct dpu_power_client *pclient, int enable); - -/** - * dpu_power_handle_register_event - register a callback function for an event. - * Clients can register for multiple events with a single register. - * Any block with access to phandle can register for the event - * notification. - * @phandle: power handle containing the resources - * @event_type: event type to register; refer DPU_POWER_HANDLE_EVENT_* - * @cb_fnc: pointer to desired callback function - * @usr: user pointer to pass to callback on event trigger - * - * Return: event pointer if success, or error code otherwise - */ -struct dpu_power_event *dpu_power_handle_register_event( - struct dpu_power_handle *phandle, - u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), - void *usr, char *client_name); -/** - * dpu_power_handle_unregister_event - unregister callback for event(s) - * @phandle: power handle containing the resources - * @event: event pointer returned after power handle register - */ -void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle, - struct dpu_power_event *event); - -/** - * dpu_power_handle_get_dbus_name - get name of given data bus identifier - * @bus_id: data bus identifier - * Return: Pointer to name string if success; NULL otherwise - */ -const char *dpu_power_handle_get_dbus_name(u32 bus_id); - -#endif /* _DPU_POWER_HANDLE_H_ */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 5c267cd..60b6919 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -340,7 +340,6 @@ static int msm_drm_uninit(struct device *dev) component_unbind_all(dev, ddev); #ifdef CONFIG_DRM_MSM_DPU - dpu_power_resource_deinit(pdev, &priv->phandle); dpu_dbg_destroy(); #endif @@ -519,12 +518,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) drm_mode_config_init(ddev); #ifdef CONFIG_DRM_MSM_DPU - ret = dpu_power_resource_init(pdev, &priv->phandle); - if (ret) { - pr_err("dpu power resource init failed\n"); - goto power_init_fail; - } - ret = dpu_dbg_init(&pdev->dev); if (ret) { dev_err(dev, "failed to init dpu dbg: %d\n", ret); @@ -733,8 +726,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) #ifdef CONFIG_DRM_MSM_DPU dpu_dbg_destroy(); dbg_init_fail: - dpu_power_resource_deinit(pdev, &priv->phandle); -power_init_fail: #endif if (mdss && mdss->funcs) mdss->funcs->destroy(ddev); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index f9ae96f..27a73a8 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -46,8 +46,6 @@ #include <drm/msm_drm.h> #include <drm/drm_gem.h> -#include "dpu_power_handle.h" - #define GET_MAJOR_REV(rev) ((rev) >> 28) #define GET_MINOR_REV(rev) (((rev) >> 16) & 0xFFF) #define GET_STEP_REV(rev) ((rev) & 0xFFFF) @@ -375,8 +373,6 @@ struct msm_drm_private { struct msm_kms *kms; - struct dpu_power_handle phandle; - /* subordinate devices, if present: */ struct platform_device *gpu_pdev;
Now, since dpu_power_handle manages only bus scaling and power enable/disable notifications which are restricted to dpu driver, move dpu_power_handle to dpu folder. Changes in v2: - resolved conflict in dpu_unbind - dropped (Reviewed-by: Sean Paul) due to above change Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> --- drivers/gpu/drm/msm/Makefile | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 5 +- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 7 +- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 39 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c | 693 +++++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 288 ++++++++++ drivers/gpu/drm/msm/dpu_power_handle.c | 693 ----------------------- drivers/gpu/drm/msm/dpu_power_handle.h | 288 ---------- drivers/gpu/drm/msm/msm_drv.c | 9 - drivers/gpu/drm/msm/msm_drv.h | 4 - 14 files changed, 1013 insertions(+), 1020 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h delete mode 100644 drivers/gpu/drm/msm/dpu_power_handle.c delete mode 100644 drivers/gpu/drm/msm/dpu_power_handle.h