summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra_cl_dvfs.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-04-23 20:22:34 -0700
committerVarun Wadekar <vwadekar@nvidia.com>2012-06-27 17:15:08 +0530
commit9fab47cbacace4459bc8500673abfc9ca6874f5c (patch)
tree5e7dcd0fffa2868ce55704e77270fa01ceb8ea97 /arch/arm/mach-tegra/tegra_cl_dvfs.c
parent5494283a809899e70741b44a153c71ba5575ea69 (diff)
ARM: tegra11: dvfs: Update CL-DVFS rate calculations
Updated CL-DVFS rate calculations to avoid 64-bit arithmetic and make sure that the rate stays the same after get_rate=>set_rate call chain. Set minimum CL-DVFS rate to exact multiple of reference rate units, so that minimum rate won't be crossed as a result of set rate round down operation. Bug 871124 Change-Id: Iafd73b94e7d68694a93f411d919e687ec165b451 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/98579 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bo Yan <byan@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra_cl_dvfs.c')
-rw-r--r--arch/arm/mach-tegra/tegra_cl_dvfs.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/tegra_cl_dvfs.c b/arch/arm/mach-tegra/tegra_cl_dvfs.c
index cadd71eddd33..1e42b71724b7 100644
--- a/arch/arm/mach-tegra/tegra_cl_dvfs.c
+++ b/arch/arm/mach-tegra/tegra_cl_dvfs.c
@@ -126,8 +126,11 @@
/* Conversion macros (different scales for frequency request, and monitored
rate is not a typo)*/
#define GET_REQUEST_FREQ(rate, ref_rate) ((rate) / ((ref_rate) / 2))
+#define GET_REQUEST_RATE(freq, ref_rate) ((freq) * ((ref_rate) / 2))
#define GET_MONITORED_RATE(freq, ref_rate) ((freq) * ((ref_rate) / 4))
#define GET_DROOP_FREQ(rate, ref_rate) ((rate) / ((ref_rate) / 4))
+#define ROUND_MIN_RATE(rate, ref_rate) \
+ (DIV_ROUND_UP(rate, (ref_rate) / 2) * ((ref_rate) / 2))
#define GET_DIV(ref_rate, out_rate, scale) \
DIV_ROUND_CLOSEST((ref_rate), (out_rate) * (scale))
@@ -352,7 +355,9 @@ static void cl_dvfs_init_cntrl_logic(struct tegra_cl_dvfs *cld)
cl_dvfs_writel(cld, val, CL_DVFS_DROOP_CTRL);
/* FIXME: does dfll_rate_min require separate charact entry ? */
+ /* round minimum rate to request unit (ref_rate/2) boundary */
cld->dfll_rate_min = cld->soc_data->droop_cpu_rate_min;
+ cld->dfll_rate_min = ROUND_MIN_RATE(cld->dfll_rate_min, cld->ref_rate);
cld->last_req.freq = 0;
cld->last_req.output = 0;
@@ -566,7 +571,8 @@ int tegra_cl_dvfs_request_rate(struct tegra_cl_dvfs *cld, unsigned long rate)
/* Determine DFLL output scale */
req.scale = SCALE_MAX - 1;
if (rate < cld->dfll_rate_min) {
- req.scale = rate / DIV_ROUND_UP(cld->dfll_rate_min, SCALE_MAX);
+ req.scale = rate / 1000 * SCALE_MAX /
+ (cld->dfll_rate_min / 1000);
if (!req.scale) {
pr_err("%s: Rate %lu is below scalable range\n",
__func__, rate);
@@ -583,6 +589,7 @@ int tegra_cl_dvfs_request_rate(struct tegra_cl_dvfs *cld, unsigned long rate)
return -EINVAL;
}
req.freq = val;
+ rate = GET_REQUEST_RATE(val, cld->ref_rate);
/* Find safe voltage for requested rate */
if (find_safe_output(cld, rate, &req.output)) {
@@ -615,7 +622,12 @@ int tegra_cl_dvfs_request_rate(struct tegra_cl_dvfs *cld, unsigned long rate)
unsigned long tegra_cl_dvfs_request_get(struct tegra_cl_dvfs *cld)
{
struct dfll_rate_req *req = &cld->last_req;
- return (cld->ref_rate / 2) * req->freq / SCALE_MAX * (req->scale + 1);
+ u32 rate = GET_REQUEST_RATE(req->freq, cld->ref_rate);
+ if ((req->scale + 1) < SCALE_MAX) {
+ rate = DIV_ROUND_UP(rate / 1000 * (req->scale + 1), SCALE_MAX);
+ rate *= 1000;
+ }
+ return rate;
}
#ifdef CONFIG_DEBUG_FS