diff options
author | Alex Frid <afrid@nvidia.com> | 2014-04-04 22:11:19 -0700 |
---|---|---|
committer | Gerrit Code Review <gerrit2@nvidia.com> | 2014-04-08 16:31:32 -0700 |
commit | 17b60a1a36811caa3db6b06fbd9a7b3ce742dc17 (patch) | |
tree | aa60ac3add3488e1e9c3509dc8305398a91b38c6 /arch/arm/mach-tegra/tegra_cl_dvfs.c | |
parent | 75dc22d17e2aa49599668d838cd3dcab0df3990f (diff) |
ARM: tegra: dvfs: Update DFLL calibration
- Added DVCO minimum rate and output skipper update to DFLL calibration
timer callback (rather than updating skipper exclusively on new rate
request, or temperature change).
- Re-started calibration timer whenever rate request is crossing down
DVCO minimum rate level
- Made sure calibration timer delay never falls below specified
interval
- Increased calibration down range (necessary if characterized DVCO
minimum rate is overestimated - may now be the case on Tegra13 parts)
- Added calibrated rate before clipping to range boundaries to debug
print.
Bug 1492902
Change-Id: I095b04f1f18511652a19c776fa003474c8c1109c
Signed-off-by: Alex Frid <afrid@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra_cl_dvfs.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra_cl_dvfs.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/tegra_cl_dvfs.c b/arch/arm/mach-tegra/tegra_cl_dvfs.c index 13719cd48e10..2183f5cfae4e 100644 --- a/arch/arm/mach-tegra/tegra_cl_dvfs.c +++ b/arch/arm/mach-tegra/tegra_cl_dvfs.c @@ -864,7 +864,8 @@ static inline void calibration_timer_update(struct tegra_cl_dvfs *cld) { if (!cld->calibration_delay) return; - mod_timer(&cld->calibration_timer, jiffies + cld->calibration_delay); + mod_timer(&cld->calibration_timer, + jiffies + cld->calibration_delay + 1); } static void cl_dvfs_calibrate(struct tegra_cl_dvfs *cld) @@ -952,19 +953,24 @@ static void cl_dvfs_calibrate(struct tegra_cl_dvfs *cld) cld->dvco_rate_min = clamp(rate_min, cld->calibration_range_min, cld->calibration_range_max); calibration_timer_update(cld); - pr_debug("%s: calibrated dvco_rate_min %lu\n", - __func__, cld->dvco_rate_min); + pr_debug("%s: calibrated dvco_rate_min %lu (%lu)\n", + __func__, cld->dvco_rate_min, rate_min); } static void calibration_timer_cb(unsigned long data) { - unsigned long flags; + unsigned long flags, rate_min; struct tegra_cl_dvfs *cld = (struct tegra_cl_dvfs *)data; pr_debug("%s\n", __func__); clk_lock_save(cld->dfll_clk, &flags); + rate_min = cld->dvco_rate_min; cl_dvfs_calibrate(cld); + if (rate_min != cld->dvco_rate_min) { + tegra_cl_dvfs_request_rate(cld, + tegra_cl_dvfs_request_get(cld)); + } clk_unlock_restore(cld->dfll_clk, &flags); } @@ -1080,7 +1086,7 @@ static void cl_dvfs_set_dvco_rate_min(struct tegra_cl_dvfs *cld) __func__, cld->dvco_rate_min); /* dvco min rate is under-estimated - skewed range up */ - cld->calibration_range_min = cld->dvco_rate_min - 4 * RATE_STEP(cld); + cld->calibration_range_min = cld->dvco_rate_min - 8 * RATE_STEP(cld); if (cld->calibration_range_min < cld->safe_dvfs->freqs[0]) cld->calibration_range_min = cld->safe_dvfs->freqs[0]; cld->calibration_range_max = cld->dvco_rate_min + 24 * RATE_STEP(cld); @@ -2622,6 +2628,7 @@ int tegra_cl_dvfs_unlock(struct tegra_cl_dvfs *cld) int tegra_cl_dvfs_request_rate(struct tegra_cl_dvfs *cld, unsigned long rate) { u32 val; + bool dvco_min_crossed; struct dfll_rate_req req; req.rate = rate; @@ -2647,6 +2654,8 @@ int tegra_cl_dvfs_request_rate(struct tegra_cl_dvfs *cld, unsigned long rate) req.scale = scale - 1; rate = cld->dvco_rate_min; } + dvco_min_crossed = (rate == cld->dvco_rate_min) && + (cld->last_req.rate > cld->dvco_rate_min); /* Convert requested rate into frequency request and scale settings */ val = GET_REQUEST_FREQ(rate, cld->ref_rate); @@ -2675,6 +2684,8 @@ int tegra_cl_dvfs_request_rate(struct tegra_cl_dvfs *cld, unsigned long rate) if (cld->mode == TEGRA_CL_DVFS_CLOSED_LOOP) { set_cl_config(cld, &cld->last_req); set_request(cld, &cld->last_req); + if (dvco_min_crossed) + calibration_timer_update(cld); } return 0; } |