diff options
author | Alex Frid <afrid@nvidia.com> | 2012-04-23 20:22:34 -0700 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2012-06-27 17:15:08 +0530 |
commit | 9fab47cbacace4459bc8500673abfc9ca6874f5c (patch) | |
tree | 5e7dcd0fffa2868ce55704e77270fa01ceb8ea97 /arch/arm/mach-tegra/tegra_cl_dvfs.c | |
parent | 5494283a809899e70741b44a153c71ba5575ea69 (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.c | 16 |
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 |