From eef17de50b013f477f13f8404a165eda948ac448 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 25 Nov 2020 14:56:45 -0700 Subject: [PATCH] msm: kgsl: Set DDR qos level based on GPU bus IB vote For the highest IB vote, enable DDR qos level which increases performance by disabling certain DDR low power states. Change-Id: Iaabc99f724ca6f2b8de2a95da00f73608209e97f Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx.c | 32 +++++++++++++++++++++++++ drivers/gpu/msm/kgsl_bus.c | 44 ++++++++++++++++++++++++++++++++-- drivers/gpu/msm/kgsl_pwrctrl.h | 2 ++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 89dd85db28d1..bee7f499a6f4 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -129,6 +129,36 @@ static void a6xx_gmu_wrapper_init(struct adreno_device *adreno_dev) dev_warn(device->dev, "gmu_wrapper ioremap failed\n"); } +static int match_name(struct device *dev, void *data) +{ + struct device *parent = data; + + return (!strcmp(dev_name(dev), dev_name(parent))); +} + +static void find_ddr_qos_device(struct adreno_device *adreno_dev) +{ + struct device *devfreq_dev, *ddr_qos_dev; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (device->pwrctrl.ddr_qos_devfreq) + return; + + ddr_qos_dev = bus_find_device_by_name(&platform_bus_type, NULL, + "soc:qcom,kgsl-ddr-qos"); + + if (!ddr_qos_dev) + return; + + /* Devfreq device has the same name as its parent device */ + devfreq_dev = device_find_child(ddr_qos_dev, ddr_qos_dev, match_name); + if (!devfreq_dev) + return; + + device->pwrctrl.ddr_qos_devfreq = container_of(devfreq_dev, + struct devfreq, dev); +} + int a6xx_init(struct adreno_device *adreno_dev) { const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); @@ -157,6 +187,8 @@ int a6xx_init(struct adreno_device *adreno_dev) return PTR_ERR(adreno_dev->pwrup_reglist); } + find_ddr_qos_device(adreno_dev); + return a6xx_get_cp_init_cmds(adreno_dev); } diff --git a/drivers/gpu/msm/kgsl_bus.c b/drivers/gpu/msm/kgsl_bus.c index 2320ae603430..d3fccebb9f21 100644 --- a/drivers/gpu/msm/kgsl_bus.c +++ b/drivers/gpu/msm/kgsl_bus.c @@ -5,7 +5,9 @@ #include #include +#include +#include "../../devfreq/governor.h" #include "kgsl_bus.h" #include "kgsl_device.h" #include "kgsl_trace.h" @@ -30,6 +32,36 @@ static u32 _ab_buslevel_update(struct kgsl_pwrctrl *pwr, return (pwr->bus_percent_ab * pwr->bus_max) / 100; } +static void set_ddr_qos(struct kgsl_device *device, int buslevel) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct devfreq *dev = pwr->ddr_qos_devfreq; + static unsigned long cur_min_freq; + unsigned long new_min_freq = DEVFREQ_MIN_FREQ; + int ret; + + if (!dev) + return; + + /* + * Instead of creating a new dummy governor, we are using powersave + * governor for this devfreq device. Therefore, modify the minimum + * frequency to point to the desired QOS level. + */ + if (buslevel == pwr->pwrlevels[0].bus_max) + new_min_freq = DEVFREQ_MAX_FREQ; + + if (new_min_freq == cur_min_freq) + return; + + mutex_lock(&dev->lock); + dev->min_freq = new_min_freq; + ret = update_devfreq(dev); + mutex_unlock(&dev->lock); + + if (!ret) + cur_min_freq = new_min_freq; +} int kgsl_bus_update(struct kgsl_device *device, enum kgsl_bus_vote vote_state) @@ -37,7 +69,7 @@ int kgsl_bus_update(struct kgsl_device *device, struct kgsl_pwrctrl *pwr = &device->pwrctrl; /* FIXME: this might be wrong? */ int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq; - int buslevel = 0; + int ret, buslevel = 0; u32 ab; /* the bus should be ON to update the active frequency */ @@ -68,7 +100,13 @@ int kgsl_bus_update(struct kgsl_device *device, /* buslevel is the IB vote, update the AB */ ab = _ab_buslevel_update(pwr, pwr->ddr_table[buslevel]); - return device->ftbl->gpu_bus_set(device, buslevel, ab); + ret = device->ftbl->gpu_bus_set(device, buslevel, ab); + if (ret) + return ret; + + set_ddr_qos(device, buslevel); + + return 0; } static void validate_pwrlevels(struct kgsl_device *device, u32 *ibs, @@ -175,4 +213,6 @@ void kgsl_bus_close(struct kgsl_device *device) kfree(device->pwrctrl.ddr_table); device->pwrctrl.ddr_table = NULL; icc_put(device->pwrctrl.icc_path); + if (device->pwrctrl.ddr_qos_devfreq) + put_device(&device->pwrctrl.ddr_qos_devfreq->dev); } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index c0666596617a..ae1899d76ac6 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -169,6 +169,8 @@ struct kgsl_pwrctrl { struct timer_list minbw_timer; /** @minbw_timeout - Timeout for entering minimum bandwidth state */ u32 minbw_timeout; + /** @ddr_qos_devfreq: Devfreq device for setting DDR qos policy */ + struct devfreq *ddr_qos_devfreq; }; int kgsl_pwrctrl_init(struct kgsl_device *device);