ARM: tegra: dvfs: Allow boot or run time disabling of dvfs rails
authorColin Cross <ccross@android.com>
Wed, 1 Dec 2010 23:45:30 +0000 (15:45 -0800)
committerColin Cross <ccross@android.com>
Thu, 2 Dec 2010 02:14:07 +0000 (18:14 -0800)
Change-Id: Ie56cbf4ade1bbdb5835851f3c09668c1e0941a2c
Signed-off-by: Colin Cross <ccross@android.com>
arch/arm/mach-tegra/board.h
arch/arm/mach-tegra/dvfs.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra2_dvfs.c

index c47a21f712607b5e580b4b588124262c8b9b3682..04f1538b1a37df97d296eec83b409a4fcad77b02 100644 (file)
@@ -32,6 +32,7 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
 void __init tegra_protected_aperture_init(unsigned long aperture);
 void tegra_move_framebuffer(unsigned long to, unsigned long from,
        unsigned long size);
+int tegra_dvfs_rail_disable_by_name(const char *reg_id);
 
 extern unsigned long tegra_bootloader_fb_start;
 extern unsigned long tegra_bootloader_fb_size;
index ff48ea0c64f05bcfcb206ad85d59d7c656cad89b..bc1e1a391b5a5d42d02e9c84e20e08e8a6bf1471 100644 (file)
@@ -395,6 +395,64 @@ static struct notifier_block tegra_dvfs_nb = {
        .notifier_call = tegra_dvfs_pm_notify,
 };
 
+/* must be called with dvfs lock held */
+static void __tegra_dvfs_rail_disable(struct dvfs_rail *rail)
+{
+       int ret;
+
+       if (!rail->disabled) {
+               ret = dvfs_rail_set_voltage(rail, rail->nominal_millivolts);
+               if (ret)
+                       pr_info("dvfs: failed to set regulator %s to disable "
+                               "voltage %d\n", rail->reg_id,
+                               rail->nominal_millivolts);
+               rail->disabled = true;
+       }
+}
+
+/* must be called with dvfs lock held */
+static void __tegra_dvfs_rail_enable(struct dvfs_rail *rail)
+{
+       if (rail->disabled) {
+               rail->disabled = false;
+               dvfs_rail_update(rail);
+       }
+}
+
+void tegra_dvfs_rail_enable(struct dvfs_rail *rail)
+{
+       mutex_lock(&dvfs_lock);
+       __tegra_dvfs_rail_enable(rail);
+       mutex_unlock(&dvfs_lock);
+}
+
+void tegra_dvfs_rail_disable(struct dvfs_rail *rail)
+{
+       mutex_lock(&dvfs_lock);
+       __tegra_dvfs_rail_disable(rail);
+       mutex_unlock(&dvfs_lock);
+}
+
+int tegra_dvfs_rail_disable_by_name(const char *reg_id)
+{
+       struct dvfs_rail *rail;
+       int ret = 0;
+
+       mutex_lock(&dvfs_lock);
+       list_for_each_entry(rail, &dvfs_rail_list, node) {
+               if (!strcmp(reg_id, rail->reg_id)) {
+                       __tegra_dvfs_rail_disable(rail);
+                       goto out;
+               }
+       }
+
+       ret = -EINVAL;
+
+out:
+       mutex_unlock(&dvfs_lock);
+       return ret;
+}
+
 /*
  * Iterate through all the dvfs regulators, finding the regulator exported
  * by the regulator api for each one.  Must be called in late init, after
index 85764580c39d6c5e581c880f9f01c661b1d72429..68622b899c5944ee8a9ba28da49c304ab30bed65 100644 (file)
@@ -87,5 +87,7 @@ int dvfs_debugfs_init(struct dentry *clk_debugfs_root);
 int tegra_dvfs_late_init(void);
 int tegra_dvfs_init_rails(struct dvfs_rail *dvfs_rails[], int n);
 void tegra_dvfs_add_relationships(struct dvfs_relationship *rels, int n);
+void tegra_dvfs_rail_enable(struct dvfs_rail *rail);
+void tegra_dvfs_rail_disable(struct dvfs_rail *rail);
 
 #endif
index 1734e5ee700bbec3413c4378064ca6bb9dc97f82..1bc1c4dce0d25acb7840bc297b49a18d203145ff 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
+#include <linux/module.h>
 
 #include "clock.h"
 #include "dvfs.h"
 #include "fuse.h"
 
+#ifdef CONFIG_TEGRA_CORE_DVFS
+static bool tegra_dvfs_core_disabled;
+#else
+static bool tegra_dvfs_core_disabled = true;
+#endif
+#ifdef CONFIG_TEGRA_CPU_DVFS
+static bool tegra_dvfs_cpu_disabled;
+#else
+static bool tegra_dvfs_cpu_disabled = true;
+#endif
+
 static const int core_millivolts[MAX_DVFS_FREQS] =
        {950, 1000, 1100, 1200, 1275};
 static const int cpu_millivolts[MAX_DVFS_FREQS] =
@@ -38,9 +50,6 @@ static struct dvfs_rail tegra2_dvfs_rail_vdd_cpu = {
        .max_millivolts = 1100,
        .min_millivolts = 750,
        .nominal_millivolts = 1100,
-#ifndef CONFIG_TEGRA_CPU_DVFS
-       .disabled = true,
-#endif
 };
 
 static struct dvfs_rail tegra2_dvfs_rail_vdd_core = {
@@ -49,9 +58,6 @@ static struct dvfs_rail tegra2_dvfs_rail_vdd_core = {
        .min_millivolts = 950,
        .nominal_millivolts = 1200,
        .step = 150, /* step vdd_core by 150 mV to allow vdd_aon to follow */
-#ifndef CONFIG_TEGRA_CORE_DVFS
-       .disabled = true,
-#endif
 };
 
 static struct dvfs_rail tegra2_dvfs_rail_vdd_aon = {
@@ -195,6 +201,58 @@ static struct dvfs dvfs_init[] = {
        CORE_DVFS("NVRM_DEVID_CLK_SRC", 1, MHZ, 480, 600, 800, 1067, 1067),
 };
 
+int tegra_dvfs_disable_core_set(const char *arg, const struct kernel_param *kp)
+{
+       int ret;
+
+       ret = param_set_bool(arg, kp);
+       if (ret)
+               return ret;
+
+       if (tegra_dvfs_core_disabled)
+               tegra_dvfs_rail_disable(&tegra2_dvfs_rail_vdd_core);
+       else
+               tegra_dvfs_rail_enable(&tegra2_dvfs_rail_vdd_core);
+
+       return 0;
+}
+
+int tegra_dvfs_disable_cpu_set(const char *arg, const struct kernel_param *kp)
+{
+       int ret;
+
+       ret = param_set_bool(arg, kp);
+       if (ret)
+               return ret;
+
+       if (tegra_dvfs_cpu_disabled)
+               tegra_dvfs_rail_disable(&tegra2_dvfs_rail_vdd_cpu);
+       else
+               tegra_dvfs_rail_enable(&tegra2_dvfs_rail_vdd_cpu);
+
+       return 0;
+}
+
+int tegra_dvfs_disable_get(char *buffer, const struct kernel_param *kp)
+{
+       return param_get_bool(buffer, kp);
+}
+
+static struct kernel_param_ops tegra_dvfs_disable_core_ops = {
+       .set = tegra_dvfs_disable_core_set,
+       .get = tegra_dvfs_disable_get,
+};
+
+static struct kernel_param_ops tegra_dvfs_disable_cpu_ops = {
+       .set = tegra_dvfs_disable_cpu_set,
+       .get = tegra_dvfs_disable_get,
+};
+
+module_param_cb(disable_core, &tegra_dvfs_disable_core_ops,
+       &tegra_dvfs_core_disabled, 0644);
+module_param_cb(disable_cpu, &tegra_dvfs_disable_cpu_ops,
+       &tegra_dvfs_cpu_disabled, 0644);
+
 void __init tegra2_init_dvfs(void)
 {
        int i;
@@ -230,4 +288,10 @@ void __init tegra2_init_dvfs(void)
                        pr_err("tegra_dvfs: failed to enable dvfs on %s\n",
                                c->name);
        }
+
+       if (tegra_dvfs_core_disabled)
+               tegra_dvfs_rail_disable(&tegra2_dvfs_rail_vdd_core);
+
+       if (tegra_dvfs_cpu_disabled)
+               tegra_dvfs_rail_disable(&tegra2_dvfs_rail_vdd_cpu);
 }