ARM: tegra: dvfs: Allow boot or run time disabling of dvfs rails

Change-Id: Ie56cbf4ade1bbdb5835851f3c09668c1e0941a2c
Signed-off-by: Colin Cross <ccross@android.com>
This commit is contained in:
Colin Cross
2010-12-01 15:45:30 -08:00
parent 6270fe1708
commit 4e6feb548e
4 changed files with 131 additions and 6 deletions

View 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;

View 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

View 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

View File

@@ -20,11 +20,23 @@
#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);
}