mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:22:09 -04:00
Merge "msm: kgsl: Vote for l3 via icc_set_bw"
This commit is contained in:
commit
2cf3ec57be
11 changed files with 122 additions and 17 deletions
|
|
@ -1034,13 +1034,11 @@ l3_pwrlevel_probe(struct kgsl_device *device, struct device_node *node)
|
|||
&device->l3_freq[index]);
|
||||
}
|
||||
|
||||
device->l3_clk = devm_clk_get(&device->pdev->dev, "l3_vote");
|
||||
device->l3_icc = of_icc_get(&device->pdev->dev, "l3_path");
|
||||
|
||||
if (IS_ERR_OR_NULL(device->l3_clk)) {
|
||||
if (IS_ERR(device->l3_icc))
|
||||
dev_err(&device->pdev->dev,
|
||||
"Unable to get the l3_vote clock\n");
|
||||
device->l3_clk = NULL;
|
||||
}
|
||||
"Unable to get the l3 icc path\n");
|
||||
}
|
||||
|
||||
static int adreno_of_get_power(struct adreno_device *adreno_dev,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3103,6 +3103,8 @@ no_gx_power:
|
|||
|
||||
kgsl_pwrscale_sleep(device);
|
||||
|
||||
kgsl_pwrctrl_clear_l3_vote(device);
|
||||
|
||||
trace_kgsl_pwr_set_state(device, KGSL_STATE_SLUMBER);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -654,6 +654,8 @@ no_gx_power:
|
|||
|
||||
kgsl_pwrscale_sleep(device);
|
||||
|
||||
kgsl_pwrctrl_clear_l3_vote(device);
|
||||
|
||||
trace_kgsl_pwr_set_state(device, KGSL_STATE_SLUMBER);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -711,6 +711,7 @@ static void a6xx_rgmu_power_off(struct adreno_device *adreno_dev)
|
|||
a6xx_rgmu_disable_clks(adreno_dev);
|
||||
a6xx_rgmu_disable_gdsc(adreno_dev);
|
||||
|
||||
kgsl_pwrctrl_clear_l3_vote(device);
|
||||
}
|
||||
|
||||
static int a6xx_rgmu_clock_set(struct adreno_device *adreno_dev,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/sched/clock.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
@ -753,9 +754,9 @@ static void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
|
|||
((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
|
||||
(flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {
|
||||
|
||||
if (device->l3_clk == NULL) {
|
||||
if (IS_ERR(device->l3_icc)) {
|
||||
dev_err_once(device->dev,
|
||||
"l3_vote clk not available\n");
|
||||
"l3_icc path not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -776,15 +777,21 @@ static void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
|
|||
new_l3 = min_t(unsigned int, new_l3,
|
||||
device->num_l3_pwrlevels - 1);
|
||||
|
||||
ret = clk_set_rate(device->l3_clk,
|
||||
if (device->cur_l3_pwrlevel == new_l3)
|
||||
return;
|
||||
|
||||
ret = icc_set_bw(device->l3_icc, 0,
|
||||
device->l3_freq[new_l3]);
|
||||
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
trace_kgsl_constraint(device,
|
||||
KGSL_CONSTRAINT_L3_PWRLEVEL, new_l3, 1);
|
||||
device->cur_l3_pwrlevel = new_l3;
|
||||
else
|
||||
} else {
|
||||
dev_err_ratelimited(device->dev,
|
||||
"Could not set l3_vote: %d\n",
|
||||
ret);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/devfreq.h>
|
||||
|
||||
#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,
|
||||
|
|
@ -158,7 +196,7 @@ done:
|
|||
|
||||
validate_pwrlevels(device, pwr->ddr_table, pwr->ddr_table_count);
|
||||
|
||||
pwr->icc_path = of_icc_get(&pdev->dev, NULL);
|
||||
pwr->icc_path = of_icc_get(&pdev->dev, "gpu_icc_path");
|
||||
if (IS_ERR(pwr->icc_path) && !gmu_core_scales_bandwidth(device)) {
|
||||
WARN(1, "The CPU has no way to set the GPU bus levels\n");
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,7 +288,8 @@ struct kgsl_device {
|
|||
/* Number of active contexts seen globally for this device */
|
||||
int active_context_count;
|
||||
struct kobject gpu_sysfs_kobj;
|
||||
struct clk *l3_clk;
|
||||
/** @icc_path: Interconnect path for scaling l3 frequency */
|
||||
struct icc_path *l3_icc;
|
||||
unsigned int l3_freq[MAX_L3_LEVELS];
|
||||
unsigned int num_l3_pwrlevels;
|
||||
/* store current L3 vote to determine if we should change our vote */
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (c) 2010-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
@ -1617,6 +1618,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)
|
|||
kgsl_bus_close(device);
|
||||
|
||||
pm_runtime_disable(&device->pdev->dev);
|
||||
|
||||
icc_put(device->l3_icc);
|
||||
}
|
||||
|
||||
void kgsl_idle_check(struct work_struct *work)
|
||||
|
|
@ -1752,16 +1755,24 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device)
|
|||
return device->ftbl->regulator_enable(device);
|
||||
}
|
||||
|
||||
static void kgsl_pwrctrl_disable(struct kgsl_device *device)
|
||||
void kgsl_pwrctrl_clear_l3_vote(struct kgsl_device *device)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = clk_set_rate(device->l3_clk, device->l3_freq[0]);
|
||||
if (IS_ERR(device->l3_icc))
|
||||
return;
|
||||
|
||||
status = icc_set_bw(device->l3_icc, 0, device->l3_freq[0]);
|
||||
if (!status)
|
||||
device->cur_l3_pwrlevel = 0;
|
||||
else
|
||||
dev_err(device->dev, "Could not clear l3_vote: %d\n",
|
||||
status);
|
||||
}
|
||||
|
||||
static void kgsl_pwrctrl_disable(struct kgsl_device *device)
|
||||
{
|
||||
kgsl_pwrctrl_clear_l3_vote(device);
|
||||
|
||||
/* Order pwrrail/clk sequence based upon platform */
|
||||
device->ftbl->regulator_disable(device);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -251,4 +253,11 @@ void kgsl_idle_check(struct work_struct *work);
|
|||
*
|
||||
*/
|
||||
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
|
||||
/**
|
||||
* kgsl_pwrctrl_clear_l3_vote - Relinquish l3 vote
|
||||
* @device: Handle to the kgsl device
|
||||
*
|
||||
* Clear the l3 vote when going into slumber
|
||||
*/
|
||||
void kgsl_pwrctrl_clear_l3_vote(struct kgsl_device *device);
|
||||
#endif /* __KGSL_PWRCTRL_H */
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@
|
|||
#define show_constraint(type) \
|
||||
__print_symbolic(type, \
|
||||
{ KGSL_CONSTRAINT_NONE, "None" }, \
|
||||
{ KGSL_CONSTRAINT_PWRLEVEL, "Pwrlevel" })
|
||||
{ KGSL_CONSTRAINT_PWRLEVEL, "Pwrlevel" }, \
|
||||
{ KGSL_CONSTRAINT_L3_NONE, "L3_none" }, \
|
||||
{ KGSL_CONSTRAINT_L3_PWRLEVEL, "L3_pwrlevel" })
|
||||
|
||||
struct kgsl_ringbuffer_issueibcmds;
|
||||
struct kgsl_device_waittimestamp;
|
||||
|
|
|
|||
Loading…
Reference in a new issue