summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra2_dvfs.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-11-19 15:38:32 -0800
committerColin Cross <ccross@android.com>2010-12-01 18:14:06 -0800
commit6270fe170861d0be064c87e37e35fb71c5c0f165 (patch)
treee0dee8db1fc8c75c74c5e2ad4dfa99991aafa9e4 /arch/arm/mach-tegra/tegra2_dvfs.c
parent33745e8d519504487acf0daeccd0ad8a69cd4a18 (diff)
ARM: tegra: Add dvfs rails
The previous version of dvfs handled requirements between two different voltage rails by using two sets of dvfs tables, one for each rail. That method fails for vdd_aon, which must be within 170 mV of vdd_core. Instead, have each dvfs clock only set the voltage rail that it directly depends on, and add a relationship system to the voltage rails. When the voltage changes on one rail, it calls update on all the rails that depend on it. The dependent rails compare the new voltage of the original rail to their own voltage, and update their own voltage as necessary. Change-Id: I17b30a61c7c0c01e44702ab486238789abd47330 Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_dvfs.c')
-rw-r--r--arch/arm/mach-tegra/tegra2_dvfs.c229
1 files changed, 127 insertions, 102 deletions
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c
index 265a7b538f7f..1734e5ee700b 100644
--- a/arch/arm/mach-tegra/tegra2_dvfs.c
+++ b/arch/arm/mach-tegra/tegra2_dvfs.c
@@ -25,81 +25,123 @@
#include "dvfs.h"
#include "fuse.h"
-#define CORE_REGULATOR "vdd_core"
-#define CPU_REGULATOR "vdd_cpu"
-
static const int core_millivolts[MAX_DVFS_FREQS] =
{950, 1000, 1100, 1200, 1275};
static const int cpu_millivolts[MAX_DVFS_FREQS] =
{750, 775, 800, 825, 875, 900, 925, 975, 1000, 1050, 1100};
-static int cpu_core_millivolts[MAX_DVFS_FREQS];
-
-#define CORE_MAX_MILLIVOLTS 1275
-#define CPU_MAX_MILLIVOLTS 1100
#define KHZ 1000
#define MHZ 1000000
-#ifdef CONFIG_TEGRA_CPU_DVFS
-#define CPU_DVFS_CPU(_clk_name, _process_id, _mult, _freqs...) \
+static struct dvfs_rail tegra2_dvfs_rail_vdd_cpu = {
+ .reg_id = "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 = {
+ .reg_id = "vdd_core",
+ .max_millivolts = 1275,
+ .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 = {
+ .reg_id = "vdd_aon",
+ .max_millivolts = 1275,
+ .min_millivolts = 950,
+ .nominal_millivolts = 1200,
+#ifndef CONFIG_TEGRA_CORE_DVFS
+ .disabled = true,
+#endif
+};
+
+/* vdd_core and vdd_aon must be 50 mV higher than vdd_cpu */
+static int tegra2_dvfs_rel_vdd_cpu_vdd_core(struct dvfs_rail *vdd_cpu,
+ struct dvfs_rail *vdd_core)
+{
+ if (vdd_cpu->new_millivolts > vdd_cpu->millivolts &&
+ vdd_core->new_millivolts < vdd_cpu->new_millivolts + 50)
+ return vdd_cpu->new_millivolts + 50;
+
+ if (vdd_core->new_millivolts < vdd_cpu->millivolts + 50)
+ return vdd_cpu->millivolts + 50;
+
+ return vdd_core->new_millivolts;
+}
+
+/* vdd_aon must be within 170 mV of vdd_core */
+static int tegra2_dvfs_rel_vdd_core_vdd_aon(struct dvfs_rail *vdd_core,
+ struct dvfs_rail *vdd_aon)
+{
+ BUG_ON(abs(vdd_aon->millivolts - vdd_core->millivolts) >
+ vdd_aon->step);
+ return vdd_core->millivolts;
+}
+
+static struct dvfs_relationship tegra2_dvfs_relationships[] = {
+ {
+ /* vdd_core must be 50 mV higher than vdd_cpu */
+ .from = &tegra2_dvfs_rail_vdd_cpu,
+ .to = &tegra2_dvfs_rail_vdd_core,
+ .solve = tegra2_dvfs_rel_vdd_cpu_vdd_core,
+ },
+ {
+ /* vdd_aon must be 50 mV higher than vdd_cpu */
+ .from = &tegra2_dvfs_rail_vdd_cpu,
+ .to = &tegra2_dvfs_rail_vdd_aon,
+ .solve = tegra2_dvfs_rel_vdd_cpu_vdd_core,
+ },
+ {
+ /* vdd_aon must be within 170 mV of vdd_core */
+ .from = &tegra2_dvfs_rail_vdd_core,
+ .to = &tegra2_dvfs_rail_vdd_aon,
+ .solve = tegra2_dvfs_rel_vdd_core_vdd_aon,
+ },
+};
+
+static struct dvfs_rail *tegra2_dvfs_rails[] = {
+ &tegra2_dvfs_rail_vdd_cpu,
+ &tegra2_dvfs_rail_vdd_core,
+ &tegra2_dvfs_rail_vdd_aon,
+};
+
+#define CPU_DVFS(_clk_name, _process_id, _mult, _freqs...) \
{ \
.clk_name = _clk_name, \
- .reg_id = CPU_REGULATOR, \
- .cpu = true, \
- .process_id = _process_id, \
+ .cpu_process_id = _process_id, \
.freqs = {_freqs}, \
.freqs_mult = _mult, \
+ .millivolts = cpu_millivolts, \
.auto_dvfs = true, \
- .max_millivolts = CPU_MAX_MILLIVOLTS \
- },
+ .dvfs_rail = &tegra2_dvfs_rail_vdd_cpu, \
+ }
-#ifdef CONFIG_TEGRA_CORE_DVFS /* CPU_DVFS && CORE_DVFS */
-#define CPU_DVFS_CORE(_clk_name, _process_id, _mult, _freqs...) \
+#define CORE_DVFS(_clk_name, _auto, _mult, _freqs...) \
{ \
.clk_name = _clk_name, \
- .reg_id = CORE_REGULATOR, \
- .cpu = false, \
- .process_id = _process_id, \
+ .cpu_process_id = -1, \
.freqs = {_freqs}, \
.freqs_mult = _mult, \
- .auto_dvfs = true, \
- .higher = true, \
- .max_millivolts = CORE_MAX_MILLIVOLTS \
- },
-#else /* CPU_DVFS && !CORE_DVFS */
-#define CPU_DVFS_CORE(_clk_name, _process_id, _mult, _freqs...)
-#endif
-#else /* !CPU_DVFS */
-#define CPU_DVFS_CPU(_clk_name, _process_id, _mult, _freqs...)
-#define CPU_DVFS_CORE(_clk_name, _process_id, _mult, _freqs...)
-#endif
-
-#ifdef CONFIG_TEGRA_CORE_DVFS
-#define CORE_DVFS(_clk_name, _auto, _mult, _freqs...) \
- { \
- .clk_name = _clk_name, \
- .reg_id = CORE_REGULATOR, \
- .process_id = -1, \
- .freqs = {_freqs}, \
- .freqs_mult = _mult, \
- .auto_dvfs = _auto, \
- .max_millivolts = CORE_MAX_MILLIVOLTS \
- },
-#else
-#define CORE_DVFS(_clk_name, _process_id, _mult, _freqs...)
-#endif
-
-#define CPU_DVFS(_clk_name, _process_id, _mult, _freqs...) \
- CPU_DVFS_CORE(_clk_name, _process_id, _mult, _freqs) \
- CPU_DVFS_CPU(_clk_name, _process_id, _mult, _freqs) \
-
+ .millivolts = core_millivolts, \
+ .auto_dvfs = _auto, \
+ .dvfs_rail = &tegra2_dvfs_rail_vdd_core, \
+ }
static struct dvfs dvfs_init[] = {
/* Cpu voltages (mV): 750, 775, 800, 825, 875, 900, 925, 975, 1000, 1050, 1100 */
- CPU_DVFS("cpu", 0, MHZ, 314, 314, 314, 456, 456, 608, 608, 760, 817, 912, 1000)
- CPU_DVFS("cpu", 1, MHZ, 314, 314, 314, 456, 456, 618, 618, 770, 827, 922, 1000)
- CPU_DVFS("cpu", 2, MHZ, 494, 675, 675, 675, 817, 817, 922, 1000)
- CPU_DVFS("cpu", 3, MHZ, 730, 760, 845, 845, 1000)
+ CPU_DVFS("cpu", 0, MHZ, 314, 314, 314, 456, 456, 608, 608, 760, 817, 912, 1000),
+ CPU_DVFS("cpu", 1, MHZ, 314, 314, 314, 456, 456, 618, 618, 770, 827, 922, 1000),
+ CPU_DVFS("cpu", 2, MHZ, 494, 675, 675, 675, 817, 817, 922, 1000),
+ CPU_DVFS("cpu", 3, MHZ, 730, 760, 845, 845, 1000),
/* Core voltages (mV): 950, 1000, 1100, 1200, 1275 */
@@ -110,22 +152,22 @@ static struct dvfs dvfs_init[] = {
* For now, boards must ensure that the core voltage does not drop
* below 1V, or that the sdmmc busses are set to 44 MHz or less.
*/
- CORE_DVFS("sdmmc1", 1, KHZ, 44000, 52000, 52000, 52000, 52000)
- CORE_DVFS("sdmmc2", 1, KHZ, 44000, 52000, 52000, 52000, 52000)
- CORE_DVFS("sdmmc3", 1, KHZ, 44000, 52000, 52000, 52000, 52000)
- CORE_DVFS("sdmmc4", 1, KHZ, 44000, 52000, 52000, 52000, 52000)
+ CORE_DVFS("sdmmc1", 1, KHZ, 44000, 52000, 52000, 52000, 52000),
+ CORE_DVFS("sdmmc2", 1, KHZ, 44000, 52000, 52000, 52000, 52000),
+ CORE_DVFS("sdmmc3", 1, KHZ, 44000, 52000, 52000, 52000, 52000),
+ CORE_DVFS("sdmmc4", 1, KHZ, 44000, 52000, 52000, 52000, 52000),
#endif
- CORE_DVFS("ndflash", 1, KHZ, 130000, 150000, 158000, 164000, 164000)
- CORE_DVFS("nor", 1, KHZ, 0, 92000, 92000, 92000, 92000)
- CORE_DVFS("ide", 1, KHZ, 0, 0, 100000, 100000, 100000)
- CORE_DVFS("mipi", 1, KHZ, 0, 40000, 40000, 40000, 60000)
- CORE_DVFS("usbd", 1, KHZ, 0, 0, 480000, 480000, 480000)
- CORE_DVFS("usb2", 1, KHZ, 0, 0, 480000, 480000, 480000)
- CORE_DVFS("usb3", 1, KHZ, 0, 0, 480000, 480000, 480000)
- CORE_DVFS("pcie", 1, KHZ, 0, 0, 0, 250000, 250000)
- CORE_DVFS("dsi", 1, KHZ, 100000, 100000, 100000, 500000, 500000)
- CORE_DVFS("tvo", 1, KHZ, 0, 0, 0, 250000, 250000)
+ CORE_DVFS("ndflash", 1, KHZ, 130000, 150000, 158000, 164000, 164000),
+ CORE_DVFS("nor", 1, KHZ, 0, 92000, 92000, 92000, 92000),
+ CORE_DVFS("ide", 1, KHZ, 0, 0, 100000, 100000, 100000),
+ CORE_DVFS("mipi", 1, KHZ, 0, 40000, 40000, 40000, 60000),
+ CORE_DVFS("usbd", 1, KHZ, 0, 0, 480000, 480000, 480000),
+ CORE_DVFS("usb2", 1, KHZ, 0, 0, 480000, 480000, 480000),
+ CORE_DVFS("usb3", 1, KHZ, 0, 0, 480000, 480000, 480000),
+ CORE_DVFS("pcie", 1, KHZ, 0, 0, 0, 250000, 250000),
+ CORE_DVFS("dsi", 1, KHZ, 100000, 100000, 100000, 500000, 500000),
+ CORE_DVFS("tvo", 1, KHZ, 0, 0, 0, 250000, 250000),
/*
* The clock rate for the display controllers that determines the
@@ -133,24 +175,24 @@ static struct dvfs dvfs_init[] = {
* to the display block. Disable auto-dvfs on the display clocks,
* and let the display driver call tegra_dvfs_set_rate manually
*/
- CORE_DVFS("disp1", 0, KHZ, 158000, 158000, 190000, 190000, 190000)
- CORE_DVFS("disp2", 0, KHZ, 158000, 158000, 190000, 190000, 190000)
- CORE_DVFS("hdmi", 0, KHZ, 0, 0, 0, 148500, 148500)
+ CORE_DVFS("disp1", 0, KHZ, 158000, 158000, 190000, 190000, 190000),
+ CORE_DVFS("disp2", 0, KHZ, 158000, 158000, 190000, 190000, 190000),
+ CORE_DVFS("hdmi", 0, KHZ, 0, 0, 0, 148500, 148500),
/*
* These clocks technically depend on the core process id,
* but just use the worst case value for now
*/
- CORE_DVFS("host1x", 1, KHZ, 104500, 133000, 166000, 166000, 166000)
- CORE_DVFS("epp", 1, KHZ, 133000, 171000, 247000, 300000, 300000)
- CORE_DVFS("2d", 1, KHZ, 133000, 171000, 247000, 300000, 300000)
- CORE_DVFS("3d", 1, KHZ, 114000, 161500, 247000, 300000, 300000)
- CORE_DVFS("mpe", 1, KHZ, 104500, 152000, 228000, 250000, 250000)
- CORE_DVFS("vi", 1, KHZ, 85000, 100000, 150000, 150000, 150000)
- CORE_DVFS("sclk", 1, KHZ, 95000, 133000, 190000, 250000, 250000)
- CORE_DVFS("vde", 1, KHZ, 95000, 123500, 209000, 250000, 250000)
+ CORE_DVFS("host1x", 1, KHZ, 104500, 133000, 166000, 166000, 166000),
+ CORE_DVFS("epp", 1, KHZ, 133000, 171000, 247000, 300000, 300000),
+ CORE_DVFS("2d", 1, KHZ, 133000, 171000, 247000, 300000, 300000),
+ CORE_DVFS("3d", 1, KHZ, 114000, 161500, 247000, 300000, 300000),
+ CORE_DVFS("mpe", 1, KHZ, 104500, 152000, 228000, 250000, 250000),
+ CORE_DVFS("vi", 1, KHZ, 85000, 100000, 150000, 150000, 150000),
+ CORE_DVFS("sclk", 1, KHZ, 95000, 133000, 190000, 250000, 250000),
+ CORE_DVFS("vde", 1, KHZ, 95000, 123500, 209000, 250000, 250000),
/* What is this? */
- CORE_DVFS("NVRM_DEVID_CLK_SRC", 1, MHZ, 480, 600, 800, 1067, 1067)
+ CORE_DVFS("NVRM_DEVID_CLK_SRC", 1, MHZ, 480, 600, 800, 1067, 1067),
};
void __init tegra2_init_dvfs(void)
@@ -158,29 +200,22 @@ void __init tegra2_init_dvfs(void)
int i;
struct clk *c;
struct dvfs *d;
- int process_id;
int ret;
-
int cpu_process_id = tegra_cpu_process_id();
- int core_process_id = tegra_core_process_id();
+ tegra_dvfs_init_rails(tegra2_dvfs_rails, ARRAY_SIZE(tegra2_dvfs_rails));
+ tegra_dvfs_add_relationships(tegra2_dvfs_relationships,
+ ARRAY_SIZE(tegra2_dvfs_relationships));
/*
* VDD_CORE must always be at least 50 mV higher than VDD_CPU
* Fill out cpu_core_millivolts based on cpu_millivolts
*/
- for (i = 0; i < ARRAY_SIZE(cpu_millivolts); i++)
- if (cpu_millivolts[i])
- cpu_core_millivolts[i] = cpu_millivolts[i] + 50;
-
for (i = 0; i < ARRAY_SIZE(dvfs_init); i++) {
d = &dvfs_init[i];
- process_id = d->cpu ? cpu_process_id : core_process_id;
- if (d->process_id != -1 && d->process_id != process_id) {
- pr_debug("tegra_dvfs: rejected %s %d, process_id %d\n",
- d->clk_name, d->process_id, process_id);
+ if (d->cpu_process_id != -1 &&
+ d->cpu_process_id != cpu_process_id)
continue;
- }
c = tegra_get_clock_by_name(d->clk_name);
@@ -190,16 +225,6 @@ void __init tegra2_init_dvfs(void)
continue;
}
- if (d->cpu)
- memcpy(d->millivolts, cpu_millivolts,
- sizeof(cpu_millivolts));
- else if (!strcmp(d->clk_name, "cpu"))
- memcpy(d->millivolts, cpu_core_millivolts,
- sizeof(cpu_core_millivolts));
- else
- memcpy(d->millivolts, core_millivolts,
- sizeof(core_millivolts));
-
ret = tegra_enable_dvfs_on_clk(c, d);
if (ret)
pr_err("tegra_dvfs: failed to enable dvfs on %s\n",