ARM: tegra: dvfs: Add debugfs voltage offset knob
Alex Frid [Thu, 6 Sep 2012 02:01:55 +0000 (19:01 -0700)]
Added debugfs voltage offset knob for cpu and core rails.

Change-Id: Ied18aefa6b98ccf44b48be54bae479dc73833247
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/130355
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

arch/arm/mach-tegra/dvfs.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/pm.c

index 07f9dc8..7921ffb 100644 (file)
@@ -45,6 +45,9 @@
 #define DVFS_RAIL_STATS_RANGE   ((DVFS_RAIL_STATS_TOP_BIN - 1) * \
                                 DVFS_RAIL_STATS_BIN / DVFS_RAIL_STATS_SCALE)
 
+struct dvfs_rail *tegra_cpu_rail;
+struct dvfs_rail *tegra_core_rail;
+
 static LIST_HEAD(dvfs_rail_list);
 static DEFINE_MUTEX(dvfs_lock);
 static DEFINE_MUTEX(rail_disable_lock);
@@ -83,6 +86,11 @@ int tegra_dvfs_init_rails(struct dvfs_rail *rails[], int n)
                        rails[i]->step = rails[i]->max_millivolts;
 
                list_add_tail(&rails[i]->node, &dvfs_rail_list);
+
+               if (!strcmp("vdd_cpu", rails[i]->reg_id))
+                       tegra_cpu_rail = rails[i];
+               else if (!strcmp("vdd_core", rails[i]->reg_id))
+                       tegra_core_rail = rails[i];
        }
 
        mutex_unlock(&dvfs_lock);
@@ -275,6 +283,15 @@ static int dvfs_rail_update(struct dvfs_rail *rail)
        list_for_each_entry(d, &rail->dvfs, reg_node)
                millivolts = max(d->cur_millivolts, millivolts);
 
+       /* Apply offset if any clock is requesting voltage */
+       if (millivolts) {
+               millivolts += rail->offs_millivolts;
+               if (millivolts > rail->max_millivolts)
+                       millivolts = rail->max_millivolts;
+               else if (millivolts < rail->min_millivolts)
+                       millivolts = rail->min_millivolts;
+       }
+
        /* retry update if limited by from-relationship to account for
           circular dependencies */
        steps = DIV_ROUND_UP(abs(millivolts - rail->millivolts), rail->step);
@@ -757,6 +774,7 @@ static int dvfs_tree_show(struct seq_file *s, void *data)
                                rel->from->millivolts,
                                dvfs_solve_relationship(rel));
                }
+               seq_printf(s, "   offset     %-7d mV\n", rail->offs_millivolts);
 
                list_sort(NULL, &rail->dvfs, dvfs_tree_sort_cmp);
 
@@ -830,6 +848,50 @@ static const struct file_operations rail_stats_fops = {
        .release        = single_release,
 };
 
+static int cpu_offs_get(void *data, u64 *val)
+{
+       if (tegra_cpu_rail) {
+               *val = (u64)tegra_cpu_rail->offs_millivolts;
+               return 0;
+       }
+       *val = 0;
+       return -ENOENT;
+}
+static int cpu_offs_set(void *data, u64 val)
+{
+       if (tegra_cpu_rail) {
+               mutex_lock(&dvfs_lock);
+               tegra_cpu_rail->offs_millivolts = (int)val;
+               dvfs_rail_update(tegra_cpu_rail);
+               mutex_unlock(&dvfs_lock);
+               return 0;
+       }
+       return -ENOENT;
+}
+DEFINE_SIMPLE_ATTRIBUTE(cpu_offs_fops, cpu_offs_get, cpu_offs_set, "%lld\n");
+
+static int core_offs_get(void *data, u64 *val)
+{
+       if (tegra_core_rail) {
+               *val = (u64)tegra_core_rail->offs_millivolts;
+               return 0;
+       }
+       *val = 0;
+       return -ENOENT;
+}
+static int core_offs_set(void *data, u64 val)
+{
+       if (tegra_core_rail) {
+               mutex_lock(&dvfs_lock);
+               tegra_core_rail->offs_millivolts = (int)val;
+               dvfs_rail_update(tegra_core_rail);
+               mutex_unlock(&dvfs_lock);
+               return 0;
+       }
+       return -ENOENT;
+}
+DEFINE_SIMPLE_ATTRIBUTE(core_offs_fops, core_offs_get, core_offs_set, "%lld\n");
+
 int __init dvfs_debugfs_init(struct dentry *clk_debugfs_root)
 {
        struct dentry *d;
@@ -844,6 +906,16 @@ int __init dvfs_debugfs_init(struct dentry *clk_debugfs_root)
        if (!d)
                return -ENOMEM;
 
+       d = debugfs_create_file("vdd_cpu_offs", S_IRUGO | S_IWUSR,
+               clk_debugfs_root, NULL, &cpu_offs_fops);
+       if (!d)
+               return -ENOMEM;
+
+       d = debugfs_create_file("vdd_core_offs", S_IRUGO | S_IWUSR,
+               clk_debugfs_root, NULL, &core_offs_fops);
+       if (!d)
+               return -ENOMEM;
+
        return 0;
 }
 
index 6b00c90..5f76964 100644 (file)
@@ -69,6 +69,7 @@ struct dvfs_rail {
        struct regulator *reg;
        int millivolts;
        int new_millivolts;
+       int offs_millivolts;
        bool suspended;
        bool auto_control;
        struct rail_stats stats;
@@ -119,6 +120,7 @@ struct cpu_cvb_dvfs {
 };
 
 extern struct dvfs_rail *tegra_cpu_rail;
+extern struct dvfs_rail *tegra_core_rail;
 
 void tegra2_init_dvfs(void);
 void tegra3_init_dvfs(void);
index 95c0458..8621789 100644 (file)
@@ -188,8 +188,6 @@ struct suspend_context tegra_sctx;
 #define AWAKE_CPU_FREQ_MIN     51000
 static struct pm_qos_request awake_cpu_freq_req;
 
-struct dvfs_rail *tegra_cpu_rail;
-static struct dvfs_rail *tegra_core_rail;
 static struct clk *tegra_pclk;
 static const struct tegra_suspend_platform_data *pdata;
 static enum tegra_suspend_mode current_suspend_mode = TEGRA_SUSPEND_NONE;
@@ -1071,8 +1069,6 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
        u32 reg;
        u32 mode;
 
-       tegra_cpu_rail = tegra_dvfs_get_rail_by_name("vdd_cpu");
-       tegra_core_rail = tegra_dvfs_get_rail_by_name("vdd_core");
        pm_qos_add_request(&awake_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
                           AWAKE_CPU_FREQ_MIN);