diff options
author | Colin Cross <ccross@android.com> | 2010-09-08 19:49:54 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-25 14:57:44 -0700 |
commit | 9655d3117ecceff87649beba5dc6451c5524bfe5 (patch) | |
tree | 53332b7d9efb48bac1ed5996f47a5b2bf29be84a /arch | |
parent | d86613c6494b4f2e237f031a46385d83a9c0f4cd (diff) |
[ARM] tegra: dvfs: Convert cpu to new dvfs, add core dvfs tables
Change-Id: I4020943ee10026866b29302aac177a5bdc259184
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_dvfs.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c new file mode 100644 index 000000000000..854bb77107df --- /dev/null +++ b/arch/arm/mach-tegra/tegra2_dvfs.c @@ -0,0 +1,177 @@ +/* + * arch/arm/mach-tegra/tegra2_dvfs.c + * + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Colin Cross <ccross@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/string.h> + +#include "clock.h" +#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 + +#define CPU_DVFS(_clk_name, _process_id, _mult, _freqs...) \ + { \ + .clk_name = _clk_name, \ + .reg_id = CORE_REGULATOR, \ + .cpu = false, \ + .process_id = _process_id, \ + .freqs = {_freqs}, \ + .freqs_mult = _mult, \ + .auto_dvfs = true, \ + .higher = true, \ + .max_millivolts = CORE_MAX_MILLIVOLTS \ + }, \ + { \ + .clk_name = _clk_name, \ + .reg_id = CPU_REGULATOR, \ + .cpu = true, \ + .process_id = _process_id, \ + .freqs = {_freqs}, \ + .freqs_mult = _mult, \ + .auto_dvfs = true, \ + .max_millivolts = CPU_MAX_MILLIVOLTS \ + } + +#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 \ + } + +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), + + /* Core voltages (mV): 950, 1000, 1100, 1200, 1275 */ + 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("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("hdmi", 1, KHZ, 0, 0, 0, 148500, 148500), + + /* + * The clock rate for the display controllers that determines the + * necessary core voltage depends on a divider that is internal + * 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), + + /* + * 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), + /* What is this? */ + CORE_DVFS("NVRM_DEVID_CLK_SRC", 1, MHZ, 480, 600, 800, 1067, 1067), +}; + +void 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(); + + /* + * 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); + continue; + } + + c = tegra_get_clock_by_name(d->clk_name); + + if (!c) { + pr_debug("tegra_dvfs: no clock found for %s\n", + d->clk_name); + 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", + c->name); + } +} |