msm: kgsl: Disable GPU isense clock below nominal power level

By disabling isense clock below nominal level we'll remove
vote for CX rail and save power.

CRs-Fixed: 973565
Change-Id: If4a13b3eca117fc2ff9c32ca3a24eb8b8e70b4fe
Signed-off-by: Oleg Perelet <operelet@codeaurora.org>
This commit is contained in:
Oleg Perelet 2016-07-07 09:41:20 -07:00
parent 400520a6e2
commit fb1c6ee3ac
4 changed files with 42 additions and 6 deletions

View file

@ -31,6 +31,8 @@ Required properties:
- qcom,base-leakage-coefficient: Dynamic leakage coefficient.
- qcom,lm-limit: Current limit for GPU limit management.
- qcom,isense-clk-on-level: below or equal this power level isense clock is at XO rate,
above this powerlevel isense clock is at working frequency.
Bus Scaling Data:
- qcom,msm-bus,name: String property to describe the name of the 3D graphics processor.

View file

@ -91,6 +91,7 @@
"mem_clk", "mem_iface_clk", "isense_clk", "rbcpr_clk",
"iref_clk";
qcom,isense-clk-on-level = <1>;
/* Bus Scale Settings */
qcom,gpubw-dev = <&gpubw>;
qcom,bus-control;

View file

@ -81,6 +81,8 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device,
static void kgsl_pwrctrl_request_state(struct kgsl_device *device,
unsigned int state);
static void kgsl_pwrctrl_retention_clk(struct kgsl_device *device, int state);
static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level);
/**
* _record_pwrevent() - Record the history of the new event
@ -387,6 +389,8 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
/* Change register settings if any BEFORE pwrlevel change*/
kgsl_pwrctrl_pwrlevel_change_settings(device, 0);
clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq);
_isense_clk_set_rate(pwr, pwr->active_pwrlevel);
trace_kgsl_pwrlevel(device,
pwr->active_pwrlevel, pwrlevel->gpu_freq,
pwr->previous_pwrlevel,
@ -1374,15 +1378,20 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
_isense_clk_set_rate(pwr,
pwr->num_pwrlevels - 1);
}
} else if (requested_state == KGSL_STATE_SLEEP) {
/* High latency clock maintenance. */
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
clk_unprepare(pwr->grp_clks[i]);
if ((pwr->pwrlevels[0].gpu_freq > 0))
if ((pwr->pwrlevels[0].gpu_freq > 0)) {
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
_isense_clk_set_rate(pwr,
pwr->num_pwrlevels - 1);
}
}
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
@ -1392,11 +1401,15 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
/* High latency clock maintenance. */
if ((device->state != KGSL_STATE_NAP) &&
(device->state != KGSL_STATE_DEEP_NAP)) {
if (pwr->pwrlevels[0].gpu_freq > 0)
if (pwr->pwrlevels[0].gpu_freq > 0) {
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels
[pwr->active_pwrlevel].
gpu_freq);
_isense_clk_set_rate(pwr,
pwr->active_pwrlevel);
}
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
clk_prepare(pwr->grp_clks[i]);
}
@ -1720,9 +1733,27 @@ static int _get_clocks(struct kgsl_device *device)
}
}
if (pwr->isense_clk_indx && of_property_read_u32(dev->of_node,
"qcom,isense-clk-on-level", &pwr->isense_clk_on_level)) {
KGSL_CORE_ERR("Couldn't get isense clock on level\n");
return -ENXIO;
}
return 0;
}
static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level)
{
int rate;
if (!pwr->isense_clk_indx)
return -EINVAL;
rate = clk_round_rate(pwr->grp_clks[pwr->isense_clk_indx],
level > pwr->isense_clk_on_level ?
KGSL_XO_CLK_FREQ : KGSL_ISENSE_CLK_FREQ);
return clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], rate);
}
int kgsl_pwrctrl_init(struct kgsl_device *device)
{
int i, k, m, n = 0, result;
@ -1799,9 +1830,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
clk_set_rate(pwr->grp_clks[6],
clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ));
if (pwr->isense_clk_indx)
clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx],
KGSL_ISENSE_CLK_FREQ);
_isense_clk_set_rate(pwr, pwr->num_pwrlevels - 1);
result = get_regulators(device);
if (result)

View file

@ -33,7 +33,8 @@
/* Only two supported levels, min & max */
#define KGSL_CONSTRAINT_PWR_MAXLEVELS 2
#define KGSL_RBBMTIMER_CLK_FREQ 19200000
#define KGSL_XO_CLK_FREQ 19200000
#define KGSL_RBBMTIMER_CLK_FREQ KGSL_XO_CLK_FREQ
#define KGSL_ISENSE_CLK_FREQ 200000000
/* Symbolic table for the constraint type */
@ -154,6 +155,8 @@ struct kgsl_regulator {
* @deep_nap_timer - Timer struct for entering deep nap
* @deep_nap_timeout - Timeout for entering deep nap
* @gx_retention - true if retention voltage is allowed
* isense_clk_indx - index of isense clock, 0 if no isense
* isense_clk_on_level - isense clock rate is XO rate below this level.
*/
struct kgsl_pwrctrl {
@ -162,6 +165,7 @@ struct kgsl_pwrctrl {
struct clk *dummy_mx_clk;
struct clk *gpu_bimc_int_clk;
int isense_clk_indx;
int isense_clk_on_level;
unsigned long power_flags;
unsigned long ctrl_flags;
struct kgsl_pwrlevel pwrlevels[KGSL_MAX_PWRLEVELS];