]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
ARM: tegra: dvfs: Add SiMon grading to DFLL tuning
authorAlex Frid <afrid@nvidia.com>
Wed, 18 Jun 2014 02:57:15 +0000 (19:57 -0700)
committerHarshada Kale <hkale@nvidia.com>
Thu, 26 Jun 2014 16:29:18 +0000 (09:29 -0700)
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>
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra_cl_dvfs.c

index 8cf8357576a1f25fbcf68d4cc58c9f4188fd441e..3286255c56f8919f60c9d44797b4b896840a1336 100644 (file)
@@ -129,6 +129,7 @@ enum dfll_range {
 struct dvfs_dfll_data {
        u32             tune0;
        u32             tune0_high_mv;
+       u32             tune0_simon_mask;
        u32             tune1;
        bool            tune0_low_at_cold;
        unsigned long   droop_rate_min;
index e3c94c39d53620fe22291c63516554482cb9ee4b..6dd7712b7961888ef6cf7548a75ecee7dcec6838 100644 (file)
@@ -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++)