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@xxxxxxxxxxxx> > Signed-off-by: Rajesh Yadav <ryadav@xxxxxxxxxxxxxx> > --- > 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 > -- Sean Paul, Software Engineer, Google / Chromium OS _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel