diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_dvfs.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_dvfs.c | 229 |
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", |