mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 13:49:24 -04:00
Merge "msm: kgsl: Use bulk clock functions for GMU"
This commit is contained in:
commit
5202070c22
14 changed files with 170 additions and 251 deletions
|
|
@ -885,6 +885,40 @@ static void adreno_of_get_ca_aware_properties(struct adreno_device *adreno_dev,
|
|||
}
|
||||
}
|
||||
|
||||
/* Dynamically build the OPP table for the GPU device */
|
||||
static void adreno_build_opp_table(struct device *dev, struct kgsl_pwrctrl *pwr)
|
||||
{
|
||||
unsigned long freq = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* First an annoying step: Some targets have clock drivers that
|
||||
* "helpfully" builds a OPP table for us but usually it is wrong.
|
||||
* Go through and filter out unsupported frequencies
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
struct dev_pm_opp *opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||
|
||||
if (IS_ERR(opp))
|
||||
break;
|
||||
|
||||
for (i = 0; i < pwr->num_pwrlevels; i++) {
|
||||
if (freq == pwr->pwrlevels[i].gpu_freq)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == pwr->num_pwrlevels)
|
||||
dev_pm_opp_remove(dev, freq);
|
||||
|
||||
freq++;
|
||||
}
|
||||
|
||||
/* Now add all of our supported frequencies into the tree */
|
||||
for (i = 0; i < pwr->num_pwrlevels; i++)
|
||||
dev_pm_opp_add(dev, pwr->pwrlevels[i].gpu_freq, 0);
|
||||
}
|
||||
|
||||
static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
|
||||
struct device_node *node)
|
||||
{
|
||||
|
|
@ -893,45 +927,49 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
|
|||
struct device_node *child;
|
||||
int ret;
|
||||
|
||||
/* ADD the GPU OPP table if we define it */
|
||||
if (of_find_property(device->pdev->dev.of_node,
|
||||
"operating-points-v2", NULL)) {
|
||||
ret = dev_pm_opp_of_add_table(&device->pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(device->dev,
|
||||
"Unable to set the GPU OPP table: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pwr->num_pwrlevels = 0;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
unsigned int index, freq = 0;
|
||||
u32 index, freq = 0, voltage, bus;
|
||||
struct kgsl_pwrlevel *level;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &index)) {
|
||||
dev_err(device->dev,
|
||||
"%pOF: powerlevel index not found\n", child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
ret = of_property_read_u32(child, "reg", &index);
|
||||
if (ret) {
|
||||
dev_err(device->dev, "%pOF: powerlevel index not found\n",
|
||||
child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(child, "qcom,gpu-freq", &freq)) {
|
||||
dev_err(device->dev,
|
||||
"%pOF: Unable to read qcom,gpu-freq\n", child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
ret = of_property_read_u32(child, "qcom,gpu-freq", &freq);
|
||||
if (ret) {
|
||||
dev_err(device->dev, "%pOF: Unable to read qcom,gpu-freq\n",
|
||||
child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ignore "zero" powerlevels */
|
||||
if (!freq)
|
||||
continue;
|
||||
|
||||
ret = of_property_read_u32(child, "qcom,level", &voltage);
|
||||
if (ret) {
|
||||
dev_err(device->dev, "%pOF: Unable to read qcom,level\n",
|
||||
child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = kgsl_of_property_read_ddrtype(child, "qcom,bus-freq",
|
||||
&bus);
|
||||
if (ret) {
|
||||
dev_err(device->dev, "%pOF:Unable to read qcom,bus-freq\n",
|
||||
child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (index >= KGSL_MAX_PWRLEVELS) {
|
||||
dev_err(device->dev,
|
||||
"%pOF: Pwrlevel index %d is out of range\n",
|
||||
child, index);
|
||||
dev_err(device->dev, "%pOF: Pwrlevel index %d is out of range\n",
|
||||
child, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -941,20 +979,12 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
|
|||
level = &pwr->pwrlevels[index];
|
||||
|
||||
level->gpu_freq = freq;
|
||||
level->bus_freq = bus;
|
||||
level->voltage_level = voltage;
|
||||
|
||||
of_property_read_u32(child, "qcom,acd-level",
|
||||
&level->acd_level);
|
||||
|
||||
ret = kgsl_of_property_read_ddrtype(child,
|
||||
"qcom,bus-freq", &level->bus_freq);
|
||||
if (ret) {
|
||||
dev_err(device->dev,
|
||||
"%pOF: Couldn't read the bus frequency for power level %d\n",
|
||||
child, index);
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
level->bus_min = level->bus_freq;
|
||||
kgsl_of_property_read_ddrtype(child,
|
||||
"qcom,bus-min", &level->bus_min);
|
||||
|
|
@ -964,7 +994,11 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
|
|||
"qcom,bus-max", &level->bus_max);
|
||||
}
|
||||
|
||||
adreno_build_opp_table(&device->pdev->dev, pwr);
|
||||
return 0;
|
||||
out:
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void adreno_of_get_initial_pwrlevel(struct adreno_device *adreno_dev,
|
||||
|
|
|
|||
|
|
@ -2858,8 +2858,8 @@ int adreno_dispatcher_idle(struct adreno_device *adreno_dev)
|
|||
* Ensure that this function is not called when dispatcher
|
||||
* mutex is held and device is started
|
||||
*/
|
||||
if (mutex_is_locked(&dispatcher->mutex) &&
|
||||
(__mutex_owner(&dispatcher->mutex) == current))
|
||||
|
||||
if (WARN_ON(mutex_is_locked(&dispatcher->mutex)))
|
||||
return -EDEADLK;
|
||||
|
||||
adreno_get_gpu_halt(adreno_dev);
|
||||
|
|
|
|||
|
|
@ -4346,7 +4346,7 @@ static vm_fault_t
|
|||
kgsl_gpumem_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct kgsl_mem_entry *entry = vmf->vma->vm_private_data;
|
||||
int ret;
|
||||
vm_fault_t ret;
|
||||
|
||||
if (!entry)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
|
@ -4354,7 +4354,7 @@ kgsl_gpumem_vm_fault(struct vm_fault *vmf)
|
|||
return VM_FAULT_SIGBUS;
|
||||
|
||||
ret = entry->memdesc.ops->vmfault(&entry->memdesc, vmf->vma, vmf);
|
||||
if ((ret == 0) || (ret == VM_FAULT_NOPAGE))
|
||||
if (!ret || ret == VM_FAULT_NOPAGE)
|
||||
entry->priv->gpumem_mapped += PAGE_SIZE;
|
||||
|
||||
return ret;
|
||||
|
|
@ -4776,7 +4776,7 @@ static int _register_device(struct kgsl_device *device)
|
|||
}
|
||||
|
||||
device->dev->dma_mask = &dma_mask;
|
||||
arch_setup_dma_ops(device->dev, 0, 0, NULL, false);
|
||||
set_dma_ops(device->dev, NULL);
|
||||
|
||||
dev_set_drvdata(&device->pdev->dev, device);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ struct kgsl_memdesc;
|
|||
|
||||
struct kgsl_memdesc_ops {
|
||||
unsigned int vmflags;
|
||||
int (*vmfault)(struct kgsl_memdesc *memdesc, struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf);
|
||||
vm_fault_t (*vmfault)(struct kgsl_memdesc *memdesc,
|
||||
struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
void (*free)(struct kgsl_memdesc *memdesc);
|
||||
int (*map_kernel)(struct kgsl_memdesc *memdesc);
|
||||
void (*unmap_kernel)(struct kgsl_memdesc *memdesc);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/io.h>
|
||||
|
|
@ -559,7 +560,7 @@ static int gmu_dcvs_set(struct kgsl_device *device,
|
|||
|
||||
struct rpmh_arc_vals {
|
||||
unsigned int num;
|
||||
uint16_t val[MAX_GX_LEVELS];
|
||||
const u16 *val;
|
||||
};
|
||||
|
||||
static const char gfx_res_id[] = "gfx.lvl";
|
||||
|
|
@ -584,22 +585,9 @@ enum rpmh_vote_type {
|
|||
static int rpmh_arc_cmds(struct gmu_device *gmu,
|
||||
struct rpmh_arc_vals *arc, const char *res_id)
|
||||
{
|
||||
unsigned int len;
|
||||
size_t len = 0;
|
||||
|
||||
memset(arc, 0, sizeof(*arc));
|
||||
|
||||
len = cmd_db_read_aux_data_len(res_id);
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (len > (MAX_GX_LEVELS << 1)) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"gfx cmddb size %d larger than alloc buf %d of %s\n",
|
||||
len, (MAX_GX_LEVELS << 1), res_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd_db_read_aux_data(res_id, (uint8_t *)arc->val, len);
|
||||
arc->val = cmd_db_read_aux_data(res_id, &len);
|
||||
|
||||
/*
|
||||
* cmd_db_read_aux_data() gives us a zero-padded table of
|
||||
|
|
@ -703,45 +691,22 @@ static int rpmh_arc_votes_init(struct kgsl_device *device,
|
|||
{
|
||||
unsigned int num_freqs;
|
||||
u16 vlvl_tbl[MAX_GX_LEVELS];
|
||||
unsigned int *freq_tbl;
|
||||
int i;
|
||||
struct dev_pm_opp *opp;
|
||||
|
||||
if (type == GMU_ARC_VOTE)
|
||||
return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail);
|
||||
|
||||
num_freqs = gmu->num_gpupwrlevels;
|
||||
freq_tbl = gmu->gpu_freqs;
|
||||
|
||||
if (num_freqs > pri_rail->num || num_freqs > MAX_GX_LEVELS) {
|
||||
if (num_freqs > pri_rail->num) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Defined more GPU DCVS levels than RPMh can support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(vlvl_tbl, 0, sizeof(vlvl_tbl));
|
||||
|
||||
/* Get the values from OPP API */
|
||||
for (i = 0; i < num_freqs; i++) {
|
||||
/* Hardcode VLVL 0 because it is not present in OPP */
|
||||
if (freq_tbl[i] == 0) {
|
||||
vlvl_tbl[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
opp = dev_pm_opp_find_freq_exact(&device->pdev->dev,
|
||||
freq_tbl[i], true);
|
||||
|
||||
if (IS_ERR(opp)) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Failed to find opp freq %d for GPU\n",
|
||||
freq_tbl[i]);
|
||||
return PTR_ERR(opp);
|
||||
}
|
||||
|
||||
vlvl_tbl[i] = dev_pm_opp_get_voltage(opp);
|
||||
dev_pm_opp_put(opp);
|
||||
}
|
||||
for (i = 0; i < num_freqs; i++)
|
||||
vlvl_tbl[i] = gmu->pwrlevels[i].level;
|
||||
|
||||
return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail,
|
||||
sec_rail, vlvl_tbl, num_freqs);
|
||||
|
|
@ -978,34 +943,6 @@ static int gmu_reg_probe(struct kgsl_device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gmu_clocks_probe(struct gmu_device *gmu, struct device_node *node)
|
||||
{
|
||||
const char *cname;
|
||||
struct property *prop;
|
||||
struct clk *c;
|
||||
int i = 0;
|
||||
|
||||
of_property_for_each_string(node, "clock-names", prop, cname) {
|
||||
c = devm_clk_get(&gmu->pdev->dev, cname);
|
||||
|
||||
if (IS_ERR(c)) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"dt: Couldn't get GMU clock: %s\n", cname);
|
||||
return PTR_ERR(c);
|
||||
}
|
||||
|
||||
if (i >= MAX_GMU_CLKS) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"dt: too many GMU clocks defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gmu->clks[i++] = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gmu_regulators_probe(struct gmu_device *gmu,
|
||||
struct device_node *node)
|
||||
{
|
||||
|
|
@ -1218,7 +1155,7 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
|
|||
struct kgsl_hfi *hfi;
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
int i = 0, ret = -ENXIO, index = 0;
|
||||
int i = 0, ret = -ENXIO, index;
|
||||
|
||||
gmu = kzalloc(sizeof(struct gmu_device), GFP_KERNEL);
|
||||
|
||||
|
|
@ -1242,11 +1179,20 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* Set up GMU clocks */
|
||||
ret = gmu_clocks_probe(gmu, node);
|
||||
if (ret)
|
||||
ret = devm_clk_bulk_get_all(&gmu->pdev->dev, &gmu->clks);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
gmu->num_clks = ret;
|
||||
|
||||
/* Get a pointer to the GMU clock */
|
||||
gmu->gmu_clk = kgsl_of_clk_by_name(gmu->clks, gmu->num_clks, "gmu_clk");
|
||||
if (!gmu->gmu_clk) {
|
||||
dev_err(&gmu->pdev->dev, "Couldn't get gmu_clk\n");
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set up GMU IOMMU and shared memory with GMU */
|
||||
ret = gmu_iommu_init(gmu, node);
|
||||
if (ret)
|
||||
|
|
@ -1288,12 +1234,21 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
|
|||
tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu);
|
||||
hfi->kgsldev = device;
|
||||
|
||||
/* Add a dummy level for "off" that the GMU expects */
|
||||
gmu->gpu_freqs[index++] = 0;
|
||||
if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels),
|
||||
"Too many GPU powerlevels for the GMU HFI\n")) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Add a dummy level for "off" because the GMU expects it */
|
||||
gmu->pwrlevels[0].freq = 0;
|
||||
gmu->pwrlevels[0].level = 0;
|
||||
|
||||
/* GMU power levels are in ascending order */
|
||||
for (i = pwr->num_pwrlevels - 1; i >= 0; i--)
|
||||
gmu->gpu_freqs[index++] = pwr->pwrlevels[i].gpu_freq;
|
||||
for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) {
|
||||
gmu->pwrlevels[index].freq = pwr->pwrlevels[i].gpu_freq;
|
||||
gmu->pwrlevels[index].level = pwr->pwrlevels[i].voltage_level;
|
||||
}
|
||||
|
||||
gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1;
|
||||
|
||||
|
|
@ -1331,48 +1286,30 @@ error:
|
|||
static int gmu_enable_clks(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
int ret, j = 0;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(gmu->clks[0]))
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_set_rate(gmu->clks[0], GMU_FREQUENCY);
|
||||
ret = clk_set_rate(gmu->gmu_clk, GMU_FREQUENCY);
|
||||
if (ret) {
|
||||
dev_err(&gmu->pdev->dev, "fail to set default GMU clk freq %d\n",
|
||||
GMU_FREQUENCY);
|
||||
dev_err(&gmu->pdev->dev, "Unable to set GMU clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
|
||||
ret = clk_prepare_enable(gmu->clks[j]);
|
||||
if (ret) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"fail to enable gpucc clk idx %d\n",
|
||||
j);
|
||||
return ret;
|
||||
}
|
||||
j++;
|
||||
ret = clk_bulk_prepare_enable(gmu->num_clks, gmu->clks);
|
||||
if (ret) {
|
||||
dev_err(&gmu->pdev->dev, "Cannot enable GMU clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_bit(GMU_CLK_ON, &device->gmu_core.flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gmu_disable_clks(struct kgsl_device *device)
|
||||
static void gmu_disable_clks(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
int j = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(gmu->clks[0]))
|
||||
return 0;
|
||||
|
||||
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
|
||||
clk_disable_unprepare(gmu->clks[j]);
|
||||
j++;
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks);
|
||||
clear_bit(GMU_CLK_ON, &device->gmu_core.flags);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1619,7 +1556,6 @@ static void gmu_remove(struct kgsl_device *device)
|
|||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
struct kgsl_hfi *hfi;
|
||||
int i = 0;
|
||||
|
||||
if (gmu == NULL || gmu->pdev == NULL)
|
||||
return;
|
||||
|
|
@ -1635,11 +1571,6 @@ static void gmu_remove(struct kgsl_device *device)
|
|||
|
||||
clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag);
|
||||
|
||||
while ((i < MAX_GMU_CLKS) && gmu->clks[i]) {
|
||||
gmu->clks[i] = NULL;
|
||||
i++;
|
||||
}
|
||||
|
||||
icc_put(gmu->icc_path);
|
||||
|
||||
if (gmu->fw_image) {
|
||||
|
|
@ -1649,13 +1580,6 @@ static void gmu_remove(struct kgsl_device *device)
|
|||
|
||||
gmu_memory_close(gmu);
|
||||
|
||||
for (i = 0; i < MAX_GMU_CLKS; i++) {
|
||||
if (gmu->clks[i]) {
|
||||
devm_clk_put(&gmu->pdev->dev, gmu->clks[i]);
|
||||
gmu->clks[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (gmu->gx_gdsc) {
|
||||
devm_regulator_put(gmu->gx_gdsc);
|
||||
gmu->gx_gdsc = NULL;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,6 @@ struct icc_path;
|
|||
* @dump_mem: pointer to GMU debug dump memory
|
||||
* @gmu_log: gmu event log memory
|
||||
* @hfi: HFI controller
|
||||
* @gpu_freqs: GPU frequency table with lowest freq at index 0
|
||||
* @num_gpupwrlevels: number GPU frequencies in GPU freq table
|
||||
* @num_bwlevel: number of GPU BW levels
|
||||
* @num_cnocbwlevel: number CNOC BW levels
|
||||
|
|
@ -194,14 +193,24 @@ struct gmu_device {
|
|||
struct gmu_memdesc *dump_mem;
|
||||
struct gmu_memdesc *gmu_log;
|
||||
struct kgsl_hfi hfi;
|
||||
unsigned int gpu_freqs[MAX_GX_LEVELS];
|
||||
/** @pwrlevels: Array of GMU power levels */
|
||||
struct {
|
||||
/** @freq: GPU frequency */
|
||||
unsigned long freq;
|
||||
/** @level: Voltage level */
|
||||
u32 level;
|
||||
} pwrlevels[MAX_GX_LEVELS];
|
||||
unsigned int num_gpupwrlevels;
|
||||
unsigned int num_bwlevels;
|
||||
unsigned int num_cnocbwlevels;
|
||||
struct rpmh_votes_t rpmh_votes;
|
||||
struct regulator *cx_gdsc;
|
||||
struct regulator *gx_gdsc;
|
||||
struct clk *clks[MAX_GMU_CLKS];
|
||||
struct clk_bulk_data *clks;
|
||||
/** @num_clks: Number of entries in the @clks array */
|
||||
int num_clks;
|
||||
/** @gmu_clk: Pointer to the core GMU clock */
|
||||
struct clk *gmu_clk;
|
||||
enum gmu_load_mode load_mode;
|
||||
unsigned int wakeup_pwrlevel;
|
||||
unsigned int pcl;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@
|
|||
#error "CNOC levels cannot exceed GX levels"
|
||||
#endif
|
||||
|
||||
#define MAX_GMU_CLKS 6
|
||||
|
||||
/*
|
||||
* These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up
|
||||
* from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu)
|
|||
for (i = 0; i < gmu->num_gpupwrlevels; i++) {
|
||||
cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i];
|
||||
/* Divide by 1000 to convert to kHz */
|
||||
cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
|
||||
cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
|
||||
}
|
||||
|
||||
cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
|
||||
|
|
@ -483,7 +483,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu)
|
|||
/* Hardcode this to the max threshold since it is not used */
|
||||
cmd.gx_votes[i].acd = 0xFFFFFFFF;
|
||||
/* Divide by 1000 to convert to kHz */
|
||||
cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
|
||||
cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
|
||||
}
|
||||
|
||||
cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ _kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
|
|||
list_add_tail(&p->lru, &pool->page_list);
|
||||
pool->page_count++;
|
||||
spin_unlock(&pool->list_lock);
|
||||
mod_node_page_state(page_pgdat(p), NR_INDIRECTLY_RECLAIMABLE_BYTES,
|
||||
mod_node_page_state(page_pgdat(p), NR_KERNEL_MISC_RECLAIMABLE,
|
||||
(PAGE_SIZE << pool->pool_order));
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ _kgsl_pool_get_page(struct kgsl_page_pool *pool)
|
|||
list_del(&p->lru);
|
||||
}
|
||||
spin_unlock(&pool->list_lock);
|
||||
mod_node_page_state(page_pgdat(p), NR_INDIRECTLY_RECLAIMABLE_BYTES,
|
||||
mod_node_page_state(page_pgdat(p), NR_KERNEL_MISC_RECLAIMABLE,
|
||||
-(PAGE_SIZE << pool->pool_order));
|
||||
return p;
|
||||
}
|
||||
|
|
@ -256,20 +256,12 @@ void kgsl_pool_free_pages(struct page **pages, unsigned int pcount)
|
|||
if (!pages)
|
||||
return;
|
||||
|
||||
if (WARN(!kern_addr_valid((unsigned long)pages),
|
||||
"Address of pages=%pK is not valid\n", pages))
|
||||
return;
|
||||
|
||||
for (i = 0; i < pcount;) {
|
||||
/*
|
||||
* Free each page or compound page group individually.
|
||||
*/
|
||||
struct page *p = pages[i];
|
||||
|
||||
if (WARN(!kern_addr_valid((unsigned long)p),
|
||||
"Address of page=%pK is not valid\n", p))
|
||||
return;
|
||||
|
||||
i += 1 << compound_order(p);
|
||||
kgsl_pool_free_page(p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1584,43 +1584,6 @@ static int kgsl_pwrctrl_clk_set_rate(struct clk *grp_clk, unsigned int freq,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool _gpu_freq_supported(struct kgsl_pwrctrl *pwr, unsigned int freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = pwr->num_pwrlevels - 1; i >= 0; i--) {
|
||||
if (pwr->pwrlevels[i].gpu_freq == freq)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void kgsl_pwrctrl_disable_unused_opp(struct kgsl_device *device,
|
||||
struct device *dev)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long freq = 0;
|
||||
int ret;
|
||||
|
||||
ret = dev_pm_opp_get_opp_count(dev);
|
||||
/* Return early, If no OPP table or OPP count is zero */
|
||||
if (ret <= 0)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||
if (IS_ERR(opp))
|
||||
break;
|
||||
|
||||
if (!_gpu_freq_supported(&device->pwrctrl, freq))
|
||||
dev_pm_opp_disable(dev, freq);
|
||||
|
||||
dev_pm_opp_put(opp);
|
||||
freq++;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 *kgsl_bus_get_table(struct platform_device *pdev, int *count)
|
||||
{
|
||||
u32 *levels;
|
||||
|
|
@ -1702,8 +1665,6 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
|
|||
pwr->pwrlevels[i].gpu_freq = freq;
|
||||
}
|
||||
|
||||
kgsl_pwrctrl_disable_unused_opp(device, &pdev->dev);
|
||||
|
||||
kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
|
||||
|
||||
freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ struct kgsl_pwrlevel {
|
|||
unsigned int bus_min;
|
||||
unsigned int bus_max;
|
||||
unsigned int acd_level;
|
||||
/** @voltage_level: Voltage level used by the GMU to vote RPMh */
|
||||
u32 voltage_level;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -196,7 +198,5 @@ void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy);
|
|||
void kgsl_pwrctrl_set_constraint(struct kgsl_device *device,
|
||||
struct kgsl_pwr_constraint *pwrc, uint32_t id);
|
||||
int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device);
|
||||
void kgsl_pwrctrl_disable_unused_opp(struct kgsl_device *device,
|
||||
struct device *dev);
|
||||
|
||||
#endif /* __KGSL_PWRCTRL_H */
|
||||
|
|
|
|||
|
|
@ -357,32 +357,15 @@ kgsl_sharedmem_init_sysfs(void)
|
|||
return sysfs_create_files(&kgsl_driver.virtdev.kobj, drv_attr_list);
|
||||
}
|
||||
|
||||
static int kgsl_paged_vmfault(struct kgsl_memdesc *memdesc,
|
||||
static vm_fault_t kgsl_paged_vmfault(struct kgsl_memdesc *memdesc,
|
||||
struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
int pgoff;
|
||||
unsigned int offset;
|
||||
|
||||
offset = vmf->address - vma->vm_start;
|
||||
pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
|
||||
|
||||
if (offset >= memdesc->size)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
pgoff = offset >> PAGE_SHIFT;
|
||||
|
||||
if (pgoff < memdesc->page_count) {
|
||||
struct page *page = memdesc->pages[pgoff];
|
||||
|
||||
get_page(page);
|
||||
vmf->page = page;
|
||||
|
||||
memdesc->mapsize += PAGE_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return VM_FAULT_SIGBUS;
|
||||
return vmf_insert_page(vma, vmf->address, memdesc->pages[pgoff]);
|
||||
}
|
||||
|
||||
static void kgsl_paged_unmap_kernel(struct kgsl_memdesc *memdesc)
|
||||
|
|
@ -495,27 +478,17 @@ static int kgsl_paged_map_kernel(struct kgsl_memdesc *memdesc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
|
||||
static vm_fault_t kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
|
||||
struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
unsigned long offset, pfn;
|
||||
int ret;
|
||||
|
||||
offset = ((unsigned long) vmf->address - vma->vm_start) >>
|
||||
PAGE_SHIFT;
|
||||
|
||||
pfn = (memdesc->physaddr >> PAGE_SHIFT) + offset;
|
||||
ret = vm_insert_pfn(vma, (unsigned long) vmf->address, pfn);
|
||||
|
||||
if (ret == -ENOMEM || ret == -EAGAIN)
|
||||
return VM_FAULT_OOM;
|
||||
else if (ret == -EFAULT)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
memdesc->mapsize += PAGE_SIZE;
|
||||
|
||||
return VM_FAULT_NOPAGE;
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
|
|
@ -1054,7 +1027,7 @@ static struct kgsl_memdesc_ops kgsl_secure_pool_ops = {
|
|||
|
||||
static struct kgsl_memdesc_ops kgsl_pool_ops = {
|
||||
.free = kgsl_free_pool_pages,
|
||||
.vmflags = VM_DONTDUMP | VM_DONTEXPAND | VM_DONTCOPY,
|
||||
.vmflags = VM_DONTDUMP | VM_DONTEXPAND | VM_DONTCOPY | VM_MIXEDMAP,
|
||||
.vmfault = kgsl_paged_vmfault,
|
||||
.map_kernel = kgsl_paged_map_kernel,
|
||||
.unmap_kernel = kgsl_paged_unmap_kernel,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@
|
|||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "kgsl_util.h"
|
||||
|
||||
|
|
@ -25,3 +29,15 @@ bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout)
|
|||
usleep_range((100 >> 2) + 1, 100);
|
||||
}
|
||||
}
|
||||
|
||||
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
|
||||
const char *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; clks && i < count; i++)
|
||||
if (!strcmp(clks[i].id, id))
|
||||
return clks[i].clk;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define _KGSL_UTIL_H_
|
||||
|
||||
struct regulator;
|
||||
struct clk_bulk_data;
|
||||
|
||||
/**
|
||||
* kgsl_regulator_disable_wait - Disable a regulator and wait for it
|
||||
|
|
@ -20,4 +21,15 @@ struct regulator;
|
|||
*/
|
||||
bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout);
|
||||
|
||||
/**
|
||||
* kgsl_of_clk_by_name - Return a clock device for a given name
|
||||
* @clks: Pointer to an array of bulk clk data
|
||||
* @count: Number of entries in the array
|
||||
* @id: Name of the clock to search for
|
||||
*
|
||||
* Returns: A pointer to the clock device for the given name or NULL if not
|
||||
* found
|
||||
*/
|
||||
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
|
||||
const char *id);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue