summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra_cl_dvfs.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2014-06-17 19:57:15 -0700
committerHarshada Kale <hkale@nvidia.com>2014-06-26 09:29:18 -0700
commitbd98759fd122bf15bf41debd0e324d9538737335 (patch)
treed2110afb3d90d846c66f8ad08fef98e562d49751 /arch/arm/mach-tegra/tegra_cl_dvfs.c
parent1dfa2cb0af9ad6d8c4e20b350150a5c933371ac7 (diff)
ARM: tegra: dvfs: Add SiMon grading to DFLL tuning
Added dependency of DFLL tuning settings on SiMon grading as follows: - Selected set of tuning bits specified by platform specific SiMon mask is toggled when SiMon grade is changing from zero to non-zero (high) grade, or vice versa. - The same toggle mask is applied to settings in low and high voltage tuning ranges. - SiMon mask can be applied only while DFLL is tuned for low voltage range Bug 1511506 Change-Id: I10cb69ea30c7773042c640d41e0dc0c99038ab7d Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/424906 Reviewed-by: Sai Gurrappadi <sgurrappadi@nvidia.com> Tested-by: Sai Gurrappadi <sgurrappadi@nvidia.com> Reviewed-by: Thomas Cherry <tcherry@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra_cl_dvfs.c')
-rw-r--r--arch/arm/mach-tegra/tegra_cl_dvfs.c56
1 files changed, 51 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/tegra_cl_dvfs.c b/arch/arm/mach-tegra/tegra_cl_dvfs.c
index e3c94c39d536..6dd7712b7961 100644
--- a/arch/arm/mach-tegra/tegra_cl_dvfs.c
+++ b/arch/arm/mach-tegra/tegra_cl_dvfs.c
@@ -213,6 +213,9 @@ struct tegra_cl_dvfs {
u8 num_voltages;
u8 safe_output;
+ u32 tune0_low;
+ u32 tune0_high;
+
u8 tune_high_out_start;
u8 tune_high_out_min;
unsigned long tune_high_dvco_rate_min;
@@ -687,7 +690,7 @@ static void cl_dvfs_load_lut(struct tegra_cl_dvfs *cld)
static inline void tune_low(struct tegra_cl_dvfs *cld)
{
/* a must order: 1st tune dfll low, then tune trimmers low */
- cl_dvfs_writel(cld, cld->safe_dvfs->dfll_data.tune0, CL_DVFS_TUNE0);
+ cl_dvfs_writel(cld, cld->tune0_low, CL_DVFS_TUNE0);
cl_dvfs_wmb(cld);
if (cld->safe_dvfs->dfll_data.tune_trimmers)
cld->safe_dvfs->dfll_data.tune_trimmers(false);
@@ -698,8 +701,7 @@ static inline void tune_high(struct tegra_cl_dvfs *cld)
/* a must order: 1st tune trimmers high, then tune dfll high */
if (cld->safe_dvfs->dfll_data.tune_trimmers)
cld->safe_dvfs->dfll_data.tune_trimmers(true);
- cl_dvfs_writel(cld, cld->safe_dvfs->dfll_data.tune0_high_mv,
- CL_DVFS_TUNE0);
+ cl_dvfs_writel(cld, cld->tune0_high, CL_DVFS_TUNE0);
cl_dvfs_wmb(cld);
}
@@ -1543,7 +1545,7 @@ static void cl_dvfs_init_cntrl_logic(struct tegra_cl_dvfs *cld)
(param->cg_scale ? CL_DVFS_PARAMS_CG_SCALE : 0);
cl_dvfs_writel(cld, val, CL_DVFS_PARAMS);
- cl_dvfs_writel(cld, cld->safe_dvfs->dfll_data.tune0, CL_DVFS_TUNE0);
+ cl_dvfs_writel(cld, cld->tune0_low, CL_DVFS_TUNE0);
cl_dvfs_writel(cld, cld->safe_dvfs->dfll_data.tune1, CL_DVFS_TUNE1);
cl_dvfs_wmb(cld);
if (cld->safe_dvfs->dfll_data.tune_trimmers)
@@ -1651,6 +1653,10 @@ static int cl_dvfs_init(struct tegra_cl_dvfs *cld)
cld->calibration_timer.data = (unsigned long)cld;
cld->calibration_delay = usecs_to_jiffies(CL_DVFS_CALIBR_TIME);
+ /* Init tune0 settings */
+ cld->tune0_low = cld->safe_dvfs->dfll_data.tune0;
+ cld->tune0_high = cld->safe_dvfs->dfll_data.tune0_high_mv;
+
/* Get ready ouput voltage mapping*/
cl_dvfs_init_maps(cld);
@@ -1921,8 +1927,45 @@ static void tegra_cl_dvfs_bypass_dev_register(struct tegra_cl_dvfs *cld,
* The Silicon Monitor (SiMon) notification provides grade information on
* the DFLL controlled rail. The resepctive minimum voltage offset is applied
* to thermal floors profile. SiMon offsets are negative, the higher the grade
- * the lower the floor.
+ * the lower the floor. In addition SiMon grade may affect tuning settings: more
+ * aggressive settings may be used at grades above zero.
*/
+static void update_simon_tuning(struct tegra_cl_dvfs *cld, unsigned long grade)
+{
+
+ struct dvfs_dfll_data *dfll_data = &cld->safe_dvfs->dfll_data;
+ u32 mask = dfll_data->tune0_simon_mask;
+
+ if (!mask)
+ return;
+
+ /*
+ * Safe order:
+ * - switch to settings for low voltage tuning range at current grade
+ * - update both low/high voltage range settings to match new grade
+ * notification (note that same toggle mask is applied to settings
+ * in both low and high voltage ranges).
+ * - switch to settings for low voltage tuning range at new grade
+ * - switch to settings for high voltage range at new grade if tuning
+ * state was high
+ */
+ tune_low(cld);
+ udelay(1);
+ pr_debug("tune0: 0x%x\n", cl_dvfs_readl(cld, CL_DVFS_TUNE0));
+
+ cld->tune0_low = dfll_data->tune0 ^ (grade ? mask : 0);
+ cld->tune0_high = dfll_data->tune0_high_mv ^ (grade ? mask : 0);
+
+ tune_low(cld);
+ udelay(1);
+ pr_debug("tune0: 0x%x\n", cl_dvfs_readl(cld, CL_DVFS_TUNE0));
+
+ if (cld->tune_state == TEGRA_CL_DVFS_TUNE_HIGH) {
+ tune_high(cld);
+ pr_debug("tune0: 0x%x\n", cl_dvfs_readl(cld, CL_DVFS_TUNE0));
+ }
+}
+
static int cl_dvfs_simon_grade_notify_cb(struct notifier_block *nb,
unsigned long grade, void *v)
{
@@ -1943,6 +1986,9 @@ static int cl_dvfs_simon_grade_notify_cb(struct notifier_block *nb,
clk_lock_save(cld->dfll_clk, &flags);
+ /* Update tuning based on SiMon grade */
+ update_simon_tuning(cld, grade);
+
/* Convert new floors and invalidate minimum rates */
cl_dvfs_convert_cold_output_floor(cld, simon_offset);
for (i = 0; i < cld->therm_floors_num; i++)