diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 5097e994f483..0d9427b3e1b8 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -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. diff --git a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi index 7a12053bef70..f5fabf0851a8 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi @@ -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; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 830579d94bcf..51717373b821 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -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) diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 9d2c6ce0c269..0029c389484f 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -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];