Merge "msm: kgsl: Add GPU Cx ipeak client support on SDM660"
This commit is contained in:
commit
eee829e625
3 changed files with 86 additions and 1 deletions
|
@ -110,6 +110,17 @@ Optional Properties:
|
||||||
- qcom,l2pc-cpu-mask-latency:
|
- qcom,l2pc-cpu-mask-latency:
|
||||||
The CPU mask latency in microseconds to avoid L2PC
|
The CPU mask latency in microseconds to avoid L2PC
|
||||||
on masked CPUs.
|
on masked CPUs.
|
||||||
|
|
||||||
|
- qcom,gpu-cx-ipeak:
|
||||||
|
To handle Cx peak current limit.
|
||||||
|
<phandle bit>
|
||||||
|
phandle - phandle of cx ipeak device node
|
||||||
|
bit - bit number of client in relevant register
|
||||||
|
- qcom,gpu-cx-ipeak-clk:
|
||||||
|
GPU clock threshold for Cx Ipeak voting. KGSL votes
|
||||||
|
to Cx Ipeak driver when GPU clock crosses this threshold.
|
||||||
|
Cx Ipeak can limit peak current based on voting from other clients.
|
||||||
|
|
||||||
- qcom,force-32bit:
|
- qcom,force-32bit:
|
||||||
Force the GPU to use 32 bit data sizes even if
|
Force the GPU to use 32 bit data sizes even if
|
||||||
it is capable of doing 64 bit.
|
it is capable of doing 64 bit.
|
||||||
|
|
|
@ -361,6 +361,26 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
||||||
if (new_level == old_level)
|
if (new_level == old_level)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (pwr->gpu_cx_ipeak) {
|
||||||
|
unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq;
|
||||||
|
unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set Cx ipeak vote for GPU if it tries to cross
|
||||||
|
* threshold frequency.
|
||||||
|
*/
|
||||||
|
if (old_freq < pwr->gpu_cx_ipeak_clk &&
|
||||||
|
new_freq >= pwr->gpu_cx_ipeak_clk) {
|
||||||
|
int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
KGSL_PWR_ERR(device,
|
||||||
|
"cx_ipeak_update failed %d\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kgsl_pwrscale_update_stats(device);
|
kgsl_pwrscale_update_stats(device);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -422,6 +442,24 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
||||||
|
|
||||||
/* Timestamp the frequency change */
|
/* Timestamp the frequency change */
|
||||||
device->pwrscale.freq_change_time = ktime_to_ms(ktime_get());
|
device->pwrscale.freq_change_time = ktime_to_ms(ktime_get());
|
||||||
|
|
||||||
|
if (pwr->gpu_cx_ipeak) {
|
||||||
|
unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq;
|
||||||
|
unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset Cx ipeak vote for GPU if it goes below
|
||||||
|
* threshold frequency.
|
||||||
|
*/
|
||||||
|
if (old_freq >= pwr->gpu_cx_ipeak_clk &&
|
||||||
|
new_freq < pwr->gpu_cx_ipeak_clk) {
|
||||||
|
int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
KGSL_PWR_ERR(device,
|
||||||
|
"cx_ipeak_update failed %d\n", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
|
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
|
||||||
|
|
||||||
|
@ -2217,8 +2255,37 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
|
||||||
of_property_read_string(pdev->dev.of_node, "qcom,tsens-name",
|
of_property_read_string(pdev->dev.of_node, "qcom,tsens-name",
|
||||||
&pwr->tsens_name);
|
&pwr->tsens_name);
|
||||||
|
|
||||||
|
/* Cx ipeak client support */
|
||||||
|
if (of_find_property(pdev->dev.of_node, "qcom,gpu-cx-ipeak", NULL)) {
|
||||||
|
if (!of_property_read_u32(pdev->dev.of_node,
|
||||||
|
"qcom,gpu-cx-ipeak-clk", &pwr->gpu_cx_ipeak_clk)) {
|
||||||
|
pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node,
|
||||||
|
"qcom,gpu-cx-ipeak");
|
||||||
|
} else {
|
||||||
|
KGSL_PWR_ERR(device, "failed to get gpu cxip clk\n");
|
||||||
|
result = -EINVAL;
|
||||||
|
goto error_cleanup_pwr_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ERR(pwr->gpu_cx_ipeak)) {
|
||||||
|
result = PTR_ERR(pwr->gpu_cx_ipeak);
|
||||||
|
KGSL_PWR_ERR(device,
|
||||||
|
"Failed to register Cx ipeak client %d\n",
|
||||||
|
result);
|
||||||
|
goto error_cleanup_pwr_limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
error_cleanup_pwr_limit:
|
||||||
|
pwr->power_flags = 0;
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
|
||||||
|
list_del(&pwr->sysfs_pwr_limit->node);
|
||||||
|
kfree(pwr->sysfs_pwr_limit);
|
||||||
|
pwr->sysfs_pwr_limit = NULL;
|
||||||
|
}
|
||||||
|
kfree(pwr->bus_ib);
|
||||||
error_cleanup_pcl:
|
error_cleanup_pcl:
|
||||||
_close_pcl(pwr);
|
_close_pcl(pwr);
|
||||||
error_cleanup_ocmem_pcl:
|
error_cleanup_ocmem_pcl:
|
||||||
|
@ -2238,6 +2305,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)
|
||||||
|
|
||||||
KGSL_PWR_INFO(device, "close device %d\n", device->id);
|
KGSL_PWR_INFO(device, "close device %d\n", device->id);
|
||||||
|
|
||||||
|
cx_ipeak_unregister(pwr->gpu_cx_ipeak);
|
||||||
|
|
||||||
pwr->power_flags = 0;
|
pwr->power_flags = 0;
|
||||||
|
|
||||||
if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
|
if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
#define __KGSL_PWRCTRL_H
|
#define __KGSL_PWRCTRL_H
|
||||||
|
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
|
#include <soc/qcom/cx_ipeak.h>
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
** power flags
|
** power flags
|
||||||
|
@ -153,6 +154,8 @@ struct kgsl_regulator {
|
||||||
* isense_clk_indx - index of isense clock, 0 if no isense
|
* isense_clk_indx - index of isense clock, 0 if no isense
|
||||||
* isense_clk_on_level - isense clock rate is XO rate below this level.
|
* isense_clk_on_level - isense clock rate is XO rate below this level.
|
||||||
* tsens_name - pointer to temperature sensor name of GPU temperature sensor
|
* tsens_name - pointer to temperature sensor name of GPU temperature sensor
|
||||||
|
* gpu_cx_ipeak - pointer to cx ipeak client used by GPU
|
||||||
|
* gpu_cx_ipeak_clk - GPU threshold frequency to call cx ipeak driver API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct kgsl_pwrctrl {
|
struct kgsl_pwrctrl {
|
||||||
|
@ -206,6 +209,8 @@ struct kgsl_pwrctrl {
|
||||||
unsigned int gpu_bimc_int_clk_freq;
|
unsigned int gpu_bimc_int_clk_freq;
|
||||||
bool gpu_bimc_interface_enabled;
|
bool gpu_bimc_interface_enabled;
|
||||||
const char *tsens_name;
|
const char *tsens_name;
|
||||||
|
struct cx_ipeak_client *gpu_cx_ipeak;
|
||||||
|
unsigned int gpu_cx_ipeak_clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
int kgsl_pwrctrl_init(struct kgsl_device *device);
|
int kgsl_pwrctrl_init(struct kgsl_device *device);
|
||||||
|
|
Loading…
Add table
Reference in a new issue