aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Makefile13
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra20.c23
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra30.c25
-rw-r--r--arch/arm/mach-tegra/common.c22
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c66
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c188
-rw-r--r--arch/arm/mach-tegra/cpuidle.c83
-rw-r--r--arch/arm/mach-tegra/cpuidle.h32
-rw-r--r--arch/arm/mach-tegra/flowctrl.c47
-rw-r--r--arch/arm/mach-tegra/flowctrl.h8
-rw-r--r--arch/arm/mach-tegra/fuse.c49
-rw-r--r--arch/arm/mach-tegra/fuse.h16
-rw-r--r--arch/arm/mach-tegra/headsmp.S71
-rw-r--r--arch/arm/mach-tegra/pm.c216
-rw-r--r--arch/arm/mach-tegra/pm.h35
-rw-r--r--arch/arm/mach-tegra/reset.c6
-rw-r--r--arch/arm/mach-tegra/reset.h9
-rw-r--r--arch/arm/mach-tegra/sleep-tegra20.S (renamed from arch/arm/mach-tegra/sleep-t20.S)0
-rw-r--r--arch/arm/mach-tegra/sleep-tegra30.S (renamed from arch/arm/mach-tegra/sleep-t30.S)66
-rw-r--r--arch/arm/mach-tegra/sleep.S78
-rw-r--r--arch/arm/mach-tegra/sleep.h37
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks_data.c11
-rw-r--r--arch/arm/mach-tegra/tegra20_speedo.c109
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.c214
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.h1
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks_data.c51
-rw-r--r--arch/arm/mach-tegra/tegra30_speedo.c292
-rw-r--r--arch/arm/mach-tegra/tegra_cpu_car.h37
28 files changed, 1709 insertions, 96 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 9aa653b3eb32..0979e8bba78a 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -8,15 +8,24 @@ obj-y += pmc.o
8obj-y += flowctrl.o 8obj-y += flowctrl.o
9obj-y += powergate.o 9obj-y += powergate.o
10obj-y += apbio.o 10obj-y += apbio.o
11obj-y += pm.o
11obj-$(CONFIG_CPU_IDLE) += cpuidle.o 12obj-$(CONFIG_CPU_IDLE) += cpuidle.o
12obj-$(CONFIG_CPU_IDLE) += sleep.o 13obj-$(CONFIG_CPU_IDLE) += sleep.o
13obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o 14obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
14obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o 15obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
16obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
15obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o 17obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
16obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t20.o 18obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o
19ifeq ($(CONFIG_CPU_IDLE),y)
20obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o
21endif
17obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o 22obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
18obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o 23obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
19obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-t30.o 24obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o
25obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o
26ifeq ($(CONFIG_CPU_IDLE),y)
27obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
28endif
20obj-$(CONFIG_SMP) += platsmp.o headsmp.o 29obj-$(CONFIG_SMP) += platsmp.o headsmp.o
21obj-$(CONFIG_SMP) += reset.o 30obj-$(CONFIG_SMP) += reset.o
22obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 31obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 71569c01afd2..734d9cc87f2e 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -89,6 +89,17 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
89 &tegra_ehci3_pdata), 89 &tegra_ehci3_pdata),
90 OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL), 90 OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL),
91 OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), 91 OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
92 OF_DEV_AUXDATA("nvidia,tegra20-sflash", 0x7000c380, "spi", NULL),
93 OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D400, "spi_tegra.0", NULL),
94 OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D600, "spi_tegra.1", NULL),
95 OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D800, "spi_tegra.2", NULL),
96 OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000DA00, "spi_tegra.3", NULL),
97 OF_DEV_AUXDATA("nvidia,tegra20-host1x", 0x50000000, "host1x", NULL),
98 OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54200000, "tegradc.0", NULL),
99 OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54240000, "tegradc.1", NULL),
100 OF_DEV_AUXDATA("nvidia,tegra20-hdmi", 0x54280000, "hdmi", NULL),
101 OF_DEV_AUXDATA("nvidia,tegra20-dsi", 0x54300000, "dsi", NULL),
102 OF_DEV_AUXDATA("nvidia,tegra20-tvo", 0x542c0000, "tvo", NULL),
92 {} 103 {}
93}; 104};
94 105
@@ -102,8 +113,20 @@ static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
102 { "pll_a", "pll_p_out1", 56448000, true }, 113 { "pll_a", "pll_p_out1", 56448000, true },
103 { "pll_a_out0", "pll_a", 11289600, true }, 114 { "pll_a_out0", "pll_a", 11289600, true },
104 { "cdev1", NULL, 0, true }, 115 { "cdev1", NULL, 0, true },
116 { "blink", "clk_32k", 32768, true },
105 { "i2s1", "pll_a_out0", 11289600, false}, 117 { "i2s1", "pll_a_out0", 11289600, false},
106 { "i2s2", "pll_a_out0", 11289600, false}, 118 { "i2s2", "pll_a_out0", 11289600, false},
119 { "sdmmc1", "pll_p", 48000000, false},
120 { "sdmmc3", "pll_p", 48000000, false},
121 { "sdmmc4", "pll_p", 48000000, false},
122 { "spi", "pll_p", 20000000, false },
123 { "sbc1", "pll_p", 100000000, false },
124 { "sbc2", "pll_p", 100000000, false },
125 { "sbc3", "pll_p", 100000000, false },
126 { "sbc4", "pll_p", 100000000, false },
127 { "host1x", "pll_c", 150000000, false },
128 { "disp1", "pll_p", 600000000, false },
129 { "disp2", "pll_p", 600000000, false },
107 { NULL, NULL, 0, 0}, 130 { NULL, NULL, 0, 0},
108}; 131};
109 132
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index e56170393a5b..6497d1236b08 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -51,6 +51,18 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
51 OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), 51 OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL),
52 OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL), 52 OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL),
53 OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), 53 OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
54 OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D400, "spi_tegra.0", NULL),
55 OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D600, "spi_tegra.1", NULL),
56 OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D800, "spi_tegra.2", NULL),
57 OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DA00, "spi_tegra.3", NULL),
58 OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DC00, "spi_tegra.4", NULL),
59 OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DE00, "spi_tegra.5", NULL),
60 OF_DEV_AUXDATA("nvidia,tegra30-host1x", 0x50000000, "host1x", NULL),
61 OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54200000, "tegradc.0", NULL),
62 OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54240000, "tegradc.1", NULL),
63 OF_DEV_AUXDATA("nvidia,tegra30-hdmi", 0x54280000, "hdmi", NULL),
64 OF_DEV_AUXDATA("nvidia,tegra30-dsi", 0x54300000, "dsi", NULL),
65 OF_DEV_AUXDATA("nvidia,tegra30-tvo", 0x542c0000, "tvo", NULL),
54 {} 66 {}
55}; 67};
56 68
@@ -61,11 +73,24 @@ static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
61 { "pll_a_out0", "pll_a", 11289600, true }, 73 { "pll_a_out0", "pll_a", 11289600, true },
62 { "extern1", "pll_a_out0", 0, true }, 74 { "extern1", "pll_a_out0", 0, true },
63 { "clk_out_1", "extern1", 0, true }, 75 { "clk_out_1", "extern1", 0, true },
76 { "blink", "clk_32k", 32768, true },
64 { "i2s0", "pll_a_out0", 11289600, false}, 77 { "i2s0", "pll_a_out0", 11289600, false},
65 { "i2s1", "pll_a_out0", 11289600, false}, 78 { "i2s1", "pll_a_out0", 11289600, false},
66 { "i2s2", "pll_a_out0", 11289600, false}, 79 { "i2s2", "pll_a_out0", 11289600, false},
67 { "i2s3", "pll_a_out0", 11289600, false}, 80 { "i2s3", "pll_a_out0", 11289600, false},
68 { "i2s4", "pll_a_out0", 11289600, false}, 81 { "i2s4", "pll_a_out0", 11289600, false},
82 { "sdmmc1", "pll_p", 48000000, false},
83 { "sdmmc3", "pll_p", 48000000, false},
84 { "sdmmc4", "pll_p", 48000000, false},
85 { "sbc1", "pll_p", 100000000, false},
86 { "sbc2", "pll_p", 100000000, false},
87 { "sbc3", "pll_p", 100000000, false},
88 { "sbc4", "pll_p", 100000000, false},
89 { "sbc5", "pll_p", 100000000, false},
90 { "sbc6", "pll_p", 100000000, false},
91 { "host1x", "pll_c", 150000000, false},
92 { "disp1", "pll_p", 600000000, false},
93 { "disp2", "pll_p", 600000000, false},
69 { NULL, NULL, 0, 0}, 94 { NULL, NULL, 0, 0},
70}; 95};
71 96
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index f688daa74978..11a74db51e5d 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -36,6 +36,7 @@
36#include "pmc.h" 36#include "pmc.h"
37#include "apbio.h" 37#include "apbio.h"
38#include "sleep.h" 38#include "sleep.h"
39#include "pm.h"
39 40
40/* 41/*
41 * Storage for debug-macro.S's state. 42 * Storage for debug-macro.S's state.
@@ -104,25 +105,30 @@ static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = {
104 { "clk_m", NULL, 0, true }, 105 { "clk_m", NULL, 0, true },
105 { "pll_p", "clk_m", 408000000, true }, 106 { "pll_p", "clk_m", 408000000, true },
106 { "pll_p_out1", "pll_p", 9600000, true }, 107 { "pll_p_out1", "pll_p", 9600000, true },
108 { "pll_p_out4", "pll_p", 102000000, true },
109 { "sclk", "pll_p_out4", 102000000, true },
110 { "hclk", "sclk", 102000000, true },
111 { "pclk", "hclk", 51000000, true },
112 { "csite", NULL, 0, true },
107 { NULL, NULL, 0, 0}, 113 { NULL, NULL, 0, 0},
108}; 114};
109#endif 115#endif
110 116
111 117
112static void __init tegra_init_cache(u32 tag_latency, u32 data_latency) 118static void __init tegra_init_cache(void)
113{ 119{
114#ifdef CONFIG_CACHE_L2X0 120#ifdef CONFIG_CACHE_L2X0
121 int ret;
115 void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; 122 void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
116 u32 aux_ctrl, cache_type; 123 u32 aux_ctrl, cache_type;
117 124
118 writel_relaxed(tag_latency, p + L2X0_TAG_LATENCY_CTRL);
119 writel_relaxed(data_latency, p + L2X0_DATA_LATENCY_CTRL);
120
121 cache_type = readl(p + L2X0_CACHE_TYPE); 125 cache_type = readl(p + L2X0_CACHE_TYPE);
122 aux_ctrl = (cache_type & 0x700) << (17-8); 126 aux_ctrl = (cache_type & 0x700) << (17-8);
123 aux_ctrl |= 0x6C000001; 127 aux_ctrl |= 0x7C400001;
124 128
125 l2x0_init(p, aux_ctrl, 0x8200c3fe); 129 ret = l2x0_of_init(aux_ctrl, 0x8200c3fe);
130 if (!ret)
131 l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs);
126#endif 132#endif
127 133
128} 134}
@@ -134,7 +140,7 @@ void __init tegra20_init_early(void)
134 tegra_init_fuse(); 140 tegra_init_fuse();
135 tegra2_init_clocks(); 141 tegra2_init_clocks();
136 tegra_clk_init_from_table(tegra20_clk_init_table); 142 tegra_clk_init_from_table(tegra20_clk_init_table);
137 tegra_init_cache(0x331, 0x441); 143 tegra_init_cache();
138 tegra_pmc_init(); 144 tegra_pmc_init();
139 tegra_powergate_init(); 145 tegra_powergate_init();
140 tegra20_hotplug_init(); 146 tegra20_hotplug_init();
@@ -147,7 +153,7 @@ void __init tegra30_init_early(void)
147 tegra_init_fuse(); 153 tegra_init_fuse();
148 tegra30_init_clocks(); 154 tegra30_init_clocks();
149 tegra_clk_init_from_table(tegra30_clk_init_table); 155 tegra_clk_init_from_table(tegra30_clk_init_table);
150 tegra_init_cache(0x441, 0x551); 156 tegra_init_cache();
151 tegra_pmc_init(); 157 tegra_pmc_init();
152 tegra_powergate_init(); 158 tegra_powergate_init();
153 tegra30_hotplug_init(); 159 tegra30_hotplug_init();
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
new file mode 100644
index 000000000000..d32e8b0dbd4f
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -0,0 +1,66 @@
1/*
2 * CPU idle driver for Tegra CPUs
3 *
4 * Copyright (c) 2010-2012, NVIDIA Corporation.
5 * Copyright (c) 2011 Google, Inc.
6 * Author: Colin Cross <ccross@android.com>
7 * Gary King <gking@nvidia.com>
8 *
9 * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 */
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/cpuidle.h>
25
26#include <asm/cpuidle.h>
27
28static struct cpuidle_driver tegra_idle_driver = {
29 .name = "tegra_idle",
30 .owner = THIS_MODULE,
31 .en_core_tk_irqen = 1,
32 .state_count = 1,
33 .states = {
34 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
35 },
36};
37
38static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
39
40int __init tegra20_cpuidle_init(void)
41{
42 int ret;
43 unsigned int cpu;
44 struct cpuidle_device *dev;
45 struct cpuidle_driver *drv = &tegra_idle_driver;
46
47 ret = cpuidle_register_driver(&tegra_idle_driver);
48 if (ret) {
49 pr_err("CPUidle driver registration failed\n");
50 return ret;
51 }
52
53 for_each_possible_cpu(cpu) {
54 dev = &per_cpu(tegra_idle_device, cpu);
55 dev->cpu = cpu;
56
57 dev->state_count = drv->state_count;
58 ret = cpuidle_register_device(dev);
59 if (ret) {
60 pr_err("CPU%u: CPUidle device registration failed\n",
61 cpu);
62 return ret;
63 }
64 }
65 return 0;
66}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
new file mode 100644
index 000000000000..5e8cbf5b799f
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -0,0 +1,188 @@
1/*
2 * CPU idle driver for Tegra CPUs
3 *
4 * Copyright (c) 2010-2012, NVIDIA Corporation.
5 * Copyright (c) 2011 Google, Inc.
6 * Author: Colin Cross <ccross@android.com>
7 * Gary King <gking@nvidia.com>
8 *
9 * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 */
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/cpuidle.h>
25#include <linux/cpu_pm.h>
26#include <linux/clockchips.h>
27
28#include <asm/cpuidle.h>
29#include <asm/proc-fns.h>
30#include <asm/suspend.h>
31#include <asm/smp_plat.h>
32
33#include "pm.h"
34#include "sleep.h"
35#include "tegra_cpu_car.h"
36
37#ifdef CONFIG_PM_SLEEP
38static int tegra30_idle_lp2(struct cpuidle_device *dev,
39 struct cpuidle_driver *drv,
40 int index);
41#endif
42
43static struct cpuidle_driver tegra_idle_driver = {
44 .name = "tegra_idle",
45 .owner = THIS_MODULE,
46 .en_core_tk_irqen = 1,
47#ifdef CONFIG_PM_SLEEP
48 .state_count = 2,
49#else
50 .state_count = 1,
51#endif
52 .states = {
53 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
54#ifdef CONFIG_PM_SLEEP
55 [1] = {
56 .enter = tegra30_idle_lp2,
57 .exit_latency = 2000,
58 .target_residency = 2200,
59 .power_usage = 0,
60 .flags = CPUIDLE_FLAG_TIME_VALID,
61 .name = "powered-down",
62 .desc = "CPU power gated",
63 },
64#endif
65 },
66};
67
68static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
69
70#ifdef CONFIG_PM_SLEEP
71static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
72 struct cpuidle_driver *drv,
73 int index)
74{
75 struct cpuidle_state *state = &drv->states[index];
76 u32 cpu_on_time = state->exit_latency;
77 u32 cpu_off_time = state->target_residency - state->exit_latency;
78
79 /* All CPUs entering LP2 is not working.
80 * Don't let CPU0 enter LP2 when any secondary CPU is online.
81 */
82 if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) {
83 cpu_do_idle();
84 return false;
85 }
86
87 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
88
89 tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
90
91 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
92
93 return true;
94}
95
96#ifdef CONFIG_SMP
97static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
98 struct cpuidle_driver *drv,
99 int index)
100{
101 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
102
103 smp_wmb();
104
105 save_cpu_arch_register();
106
107 cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
108
109 restore_cpu_arch_register();
110
111 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
112
113 return true;
114}
115#else
116static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
117 struct cpuidle_driver *drv,
118 int index)
119{
120 return true;
121}
122#endif
123
124static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev,
125 struct cpuidle_driver *drv,
126 int index)
127{
128 u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
129 bool entered_lp2 = false;
130 bool last_cpu;
131
132 local_fiq_disable();
133
134 last_cpu = tegra_set_cpu_in_lp2(cpu);
135 cpu_pm_enter();
136
137 if (cpu == 0) {
138 if (last_cpu)
139 entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv,
140 index);
141 else
142 cpu_do_idle();
143 } else {
144 entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
145 }
146
147 cpu_pm_exit();
148 tegra_clear_cpu_in_lp2(cpu);
149
150 local_fiq_enable();
151
152 smp_rmb();
153
154 return (entered_lp2) ? index : 0;
155}
156#endif
157
158int __init tegra30_cpuidle_init(void)
159{
160 int ret;
161 unsigned int cpu;
162 struct cpuidle_device *dev;
163 struct cpuidle_driver *drv = &tegra_idle_driver;
164
165#ifdef CONFIG_PM_SLEEP
166 tegra_tear_down_cpu = tegra30_tear_down_cpu;
167#endif
168
169 ret = cpuidle_register_driver(&tegra_idle_driver);
170 if (ret) {
171 pr_err("CPUidle driver registration failed\n");
172 return ret;
173 }
174
175 for_each_possible_cpu(cpu) {
176 dev = &per_cpu(tegra_idle_device, cpu);
177 dev->cpu = cpu;
178
179 dev->state_count = drv->state_count;
180 ret = cpuidle_register_device(dev);
181 if (ret) {
182 pr_err("CPU%u: CPUidle device registration failed\n",
183 cpu);
184 return ret;
185 }
186 }
187 return 0;
188}
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index 9a6f051b382e..d0651397aec7 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -23,83 +23,26 @@
23 23
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/cpu.h>
27#include <linux/cpuidle.h>
28#include <linux/hrtimer.h>
29 26
30#include <asm/proc-fns.h> 27#include "fuse.h"
31 28#include "cpuidle.h"
32static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
33 struct cpuidle_driver *drv, int index);
34
35struct cpuidle_driver tegra_idle_driver = {
36 .name = "tegra_idle",
37 .owner = THIS_MODULE,
38 .state_count = 1,
39 .states = {
40 [0] = {
41 .enter = tegra_idle_enter_lp3,
42 .exit_latency = 10,
43 .target_residency = 10,
44 .power_usage = 600,
45 .flags = CPUIDLE_FLAG_TIME_VALID,
46 .name = "LP3",
47 .desc = "CPU flow-controlled",
48 },
49 },
50};
51
52static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
53
54static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
55 struct cpuidle_driver *drv, int index)
56{
57 ktime_t enter, exit;
58 s64 us;
59
60 local_irq_disable();
61 local_fiq_disable();
62
63 enter = ktime_get();
64
65 cpu_do_idle();
66
67 exit = ktime_sub(ktime_get(), enter);
68 us = ktime_to_us(exit);
69
70 local_fiq_enable();
71 local_irq_enable();
72
73 dev->last_residency = us;
74
75 return index;
76}
77 29
78static int __init tegra_cpuidle_init(void) 30static int __init tegra_cpuidle_init(void)
79{ 31{
80 int ret; 32 int ret;
81 unsigned int cpu;
82 struct cpuidle_device *dev;
83 struct cpuidle_driver *drv = &tegra_idle_driver;
84 33
85 ret = cpuidle_register_driver(&tegra_idle_driver); 34 switch (tegra_chip_id) {
86 if (ret) { 35 case TEGRA20:
87 pr_err("CPUidle driver registration failed\n"); 36 ret = tegra20_cpuidle_init();
88 return ret; 37 break;
38 case TEGRA30:
39 ret = tegra30_cpuidle_init();
40 break;
41 default:
42 ret = -ENODEV;
43 break;
89 } 44 }
90 45
91 for_each_possible_cpu(cpu) { 46 return ret;
92 dev = &per_cpu(tegra_idle_device, cpu);
93 dev->cpu = cpu;
94
95 dev->state_count = drv->state_count;
96 ret = cpuidle_register_device(dev);
97 if (ret) {
98 pr_err("CPU%u: CPUidle device registration failed\n",
99 cpu);
100 return ret;
101 }
102 }
103 return 0;
104} 47}
105device_initcall(tegra_cpuidle_init); 48device_initcall(tegra_cpuidle_init);
diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h
new file mode 100644
index 000000000000..496204d34e55
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __MACH_TEGRA_CPUIDLE_H
18#define __MACH_TEGRA_CPUIDLE_H
19
20#ifdef CONFIG_ARCH_TEGRA_2x_SOC
21int tegra20_cpuidle_init(void);
22#else
23static inline int tegra20_cpuidle_init(void) { return -ENODEV; }
24#endif
25
26#ifdef CONFIG_ARCH_TEGRA_3x_SOC
27int tegra30_cpuidle_init(void);
28#else
29static inline int tegra30_cpuidle_init(void) { return -ENODEV; }
30#endif
31
32#endif
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
index ffaa286a71e1..a2250ddae797 100644
--- a/arch/arm/mach-tegra/flowctrl.c
+++ b/arch/arm/mach-tegra/flowctrl.c
@@ -21,6 +21,7 @@
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/kernel.h> 22#include <linux/kernel.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/cpumask.h>
24 25
25#include "flowctrl.h" 26#include "flowctrl.h"
26#include "iomap.h" 27#include "iomap.h"
@@ -50,6 +51,14 @@ static void flowctrl_update(u8 offset, u32 value)
50 readl_relaxed(addr); 51 readl_relaxed(addr);
51} 52}
52 53
54u32 flowctrl_read_cpu_csr(unsigned int cpuid)
55{
56 u8 offset = flowctrl_offset_cpu_csr[cpuid];
57 void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset;
58
59 return readl(addr);
60}
61
53void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value) 62void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
54{ 63{
55 return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value); 64 return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
@@ -59,3 +68,41 @@ void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
59{ 68{
60 return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value); 69 return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
61} 70}
71
72void flowctrl_cpu_suspend_enter(unsigned int cpuid)
73{
74 unsigned int reg;
75 int i;
76
77 reg = flowctrl_read_cpu_csr(cpuid);
78 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; /* clear wfe bitmap */
79 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; /* clear wfi bitmap */
80 reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr flag */
81 reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event flag */
82 reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid; /* pwr gating on wfi */
83 reg |= FLOW_CTRL_CSR_ENABLE; /* pwr gating */
84 flowctrl_write_cpu_csr(cpuid, reg);
85
86 for (i = 0; i < num_possible_cpus(); i++) {
87 if (i == cpuid)
88 continue;
89 reg = flowctrl_read_cpu_csr(i);
90 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
91 reg |= FLOW_CTRL_CSR_INTR_FLAG;
92 flowctrl_write_cpu_csr(i, reg);
93 }
94}
95
96void flowctrl_cpu_suspend_exit(unsigned int cpuid)
97{
98 unsigned int reg;
99
100 /* Disable powergating via flow controller for CPU0 */
101 reg = flowctrl_read_cpu_csr(cpuid);
102 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; /* clear wfe bitmap */
103 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; /* clear wfi bitmap */
104 reg &= ~FLOW_CTRL_CSR_ENABLE; /* clear enable */
105 reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr */
106 reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event */
107 flowctrl_write_cpu_csr(cpuid, reg);
108}
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
index 19428173855e..0798dec1832d 100644
--- a/arch/arm/mach-tegra/flowctrl.h
+++ b/arch/arm/mach-tegra/flowctrl.h
@@ -34,9 +34,17 @@
34#define FLOW_CTRL_HALT_CPU1_EVENTS 0x14 34#define FLOW_CTRL_HALT_CPU1_EVENTS 0x14
35#define FLOW_CTRL_CPU1_CSR 0x18 35#define FLOW_CTRL_CPU1_CSR 0x18
36 36
37#define TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 (1 << 8)
38#define TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP (0xF << 4)
39#define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP (0xF << 8)
40
37#ifndef __ASSEMBLY__ 41#ifndef __ASSEMBLY__
42u32 flowctrl_read_cpu_csr(unsigned int cpuid);
38void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value); 43void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);
39void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value); 44void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value);
45
46void flowctrl_cpu_suspend_enter(unsigned int cpuid);
47void flowctrl_cpu_suspend_exit(unsigned int cpuid);
40#endif 48#endif
41 49
42#endif 50#endif
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 6c752e8f1f06..8121742711fe 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -28,14 +28,21 @@
28#define FUSE_UID_LOW 0x108 28#define FUSE_UID_LOW 0x108
29#define FUSE_UID_HIGH 0x10c 29#define FUSE_UID_HIGH 0x10c
30#define FUSE_SKU_INFO 0x110 30#define FUSE_SKU_INFO 0x110
31#define FUSE_SPARE_BIT 0x200 31
32#define TEGRA20_FUSE_SPARE_BIT 0x200
33#define TEGRA30_FUSE_SPARE_BIT 0x244
32 34
33int tegra_sku_id; 35int tegra_sku_id;
34int tegra_cpu_process_id; 36int tegra_cpu_process_id;
35int tegra_core_process_id; 37int tegra_core_process_id;
36int tegra_chip_id; 38int tegra_chip_id;
39int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
40int tegra_soc_speedo_id;
37enum tegra_revision tegra_revision; 41enum tegra_revision tegra_revision;
38 42
43static int tegra_fuse_spare_bit;
44static void (*tegra_init_speedo_data)(void);
45
39/* The BCT to use at boot is specified by board straps that can be read 46/* The BCT to use at boot is specified by board straps that can be read
40 * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. 47 * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
41 */ 48 */
@@ -56,14 +63,14 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
56 [TEGRA_REVISION_A04] = "A04", 63 [TEGRA_REVISION_A04] = "A04",
57}; 64};
58 65
59static inline u32 tegra_fuse_readl(unsigned long offset) 66u32 tegra_fuse_readl(unsigned long offset)
60{ 67{
61 return tegra_apb_readl(TEGRA_FUSE_BASE + offset); 68 return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
62} 69}
63 70
64static inline bool get_spare_fuse(int bit) 71bool tegra_spare_fuse(int bit)
65{ 72{
66 return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4); 73 return tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);
67} 74}
68 75
69static enum tegra_revision tegra_get_revision(u32 id) 76static enum tegra_revision tegra_get_revision(u32 id)
@@ -77,7 +84,7 @@ static enum tegra_revision tegra_get_revision(u32 id)
77 return TEGRA_REVISION_A02; 84 return TEGRA_REVISION_A02;
78 case 3: 85 case 3:
79 if (tegra_chip_id == TEGRA20 && 86 if (tegra_chip_id == TEGRA20 &&
80 (get_spare_fuse(18) || get_spare_fuse(19))) 87 (tegra_spare_fuse(18) || tegra_spare_fuse(19)))
81 return TEGRA_REVISION_A03p; 88 return TEGRA_REVISION_A03p;
82 else 89 else
83 return TEGRA_REVISION_A03; 90 return TEGRA_REVISION_A03;
@@ -88,6 +95,16 @@ static enum tegra_revision tegra_get_revision(u32 id)
88 } 95 }
89} 96}
90 97
98static void tegra_get_process_id(void)
99{
100 u32 reg;
101
102 reg = tegra_fuse_readl(tegra_fuse_spare_bit);
103 tegra_cpu_process_id = (reg >> 6) & 3;
104 reg = tegra_fuse_readl(tegra_fuse_spare_bit);
105 tegra_core_process_id = (reg >> 12) & 3;
106}
107
91void tegra_init_fuse(void) 108void tegra_init_fuse(void)
92{ 109{
93 u32 id; 110 u32 id;
@@ -99,19 +116,29 @@ void tegra_init_fuse(void)
99 reg = tegra_fuse_readl(FUSE_SKU_INFO); 116 reg = tegra_fuse_readl(FUSE_SKU_INFO);
100 tegra_sku_id = reg & 0xFF; 117 tegra_sku_id = reg & 0xFF;
101 118
102 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
103 tegra_cpu_process_id = (reg >> 6) & 3;
104
105 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
106 tegra_core_process_id = (reg >> 12) & 3;
107
108 reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); 119 reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
109 tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; 120 tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
110 121
111 id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); 122 id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
112 tegra_chip_id = (id >> 8) & 0xff; 123 tegra_chip_id = (id >> 8) & 0xff;
113 124
125 switch (tegra_chip_id) {
126 case TEGRA20:
127 tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
128 tegra_init_speedo_data = &tegra20_init_speedo_data;
129 break;
130 case TEGRA30:
131 tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
132 tegra_init_speedo_data = &tegra30_init_speedo_data;
133 break;
134 default:
135 pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
136 tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
137 tegra_init_speedo_data = &tegra_get_process_id;
138 }
139
114 tegra_revision = tegra_get_revision(id); 140 tegra_revision = tegra_get_revision(id);
141 tegra_init_speedo_data();
115 142
116 pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", 143 pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
117 tegra_revision_name[tegra_revision], 144 tegra_revision_name[tegra_revision],
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index d2107b2cb85a..ff1383dd61a7 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -42,11 +42,27 @@ extern int tegra_sku_id;
42extern int tegra_cpu_process_id; 42extern int tegra_cpu_process_id;
43extern int tegra_core_process_id; 43extern int tegra_core_process_id;
44extern int tegra_chip_id; 44extern int tegra_chip_id;
45extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
46extern int tegra_soc_speedo_id;
45extern enum tegra_revision tegra_revision; 47extern enum tegra_revision tegra_revision;
46 48
47extern int tegra_bct_strapping; 49extern int tegra_bct_strapping;
48 50
49unsigned long long tegra_chip_uid(void); 51unsigned long long tegra_chip_uid(void);
50void tegra_init_fuse(void); 52void tegra_init_fuse(void);
53bool tegra_spare_fuse(int bit);
54u32 tegra_fuse_readl(unsigned long offset);
55
56#ifdef CONFIG_ARCH_TEGRA_2x_SOC
57void tegra20_init_speedo_data(void);
58#else
59static inline void tegra20_init_speedo_data(void) {}
60#endif
61
62#ifdef CONFIG_ARCH_TEGRA_3x_SOC
63void tegra30_init_speedo_data(void);
64#else
65static inline void tegra30_init_speedo_data(void) {}
66#endif
51 67
52#endif 68#endif
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index 93f0370cc95b..4a317fae6860 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -2,6 +2,8 @@
2#include <linux/init.h> 2#include <linux/init.h>
3 3
4#include <asm/cache.h> 4#include <asm/cache.h>
5#include <asm/asm-offsets.h>
6#include <asm/hardware/cache-l2x0.h>
5 7
6#include "flowctrl.h" 8#include "flowctrl.h"
7#include "iomap.h" 9#include "iomap.h"
@@ -68,6 +70,64 @@ ENTRY(tegra_secondary_startup)
68 b secondary_startup 70 b secondary_startup
69ENDPROC(tegra_secondary_startup) 71ENDPROC(tegra_secondary_startup)
70 72
73#ifdef CONFIG_PM_SLEEP
74/*
75 * tegra_resume
76 *
77 * CPU boot vector when restarting the a CPU following
78 * an LP2 transition. Also branched to by LP0 and LP1 resume after
79 * re-enabling sdram.
80 */
81ENTRY(tegra_resume)
82 bl v7_invalidate_l1
83 /* Enable coresight */
84 mov32 r0, 0xC5ACCE55
85 mcr p14, 0, r0, c7, c12, 6
86
87 cpu_id r0
88 cmp r0, #0 @ CPU0?
89 bne cpu_resume @ no
90
91#ifdef CONFIG_ARCH_TEGRA_3x_SOC
92 /* Are we on Tegra20? */
93 mov32 r6, TEGRA_APB_MISC_BASE
94 ldr r0, [r6, #APB_MISC_GP_HIDREV]
95 and r0, r0, #0xff00
96 cmp r0, #(0x20 << 8)
97 beq 1f @ Yes
98 /* Clear the flow controller flags for this CPU. */
99 mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
100 ldr r1, [r2]
101 /* Clear event & intr flag */
102 orr r1, r1, \
103 #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
104 movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
105 bic r1, r1, r0
106 str r1, [r2]
1071:
108#endif
109
110#ifdef CONFIG_HAVE_ARM_SCU
111 /* enable SCU */
112 mov32 r0, TEGRA_ARM_PERIF_BASE
113 ldr r1, [r0]
114 orr r1, r1, #1
115 str r1, [r0]
116#endif
117
118 /* L2 cache resume & re-enable */
119 l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
120
121 b cpu_resume
122ENDPROC(tegra_resume)
123#endif
124
125#ifdef CONFIG_CACHE_L2X0
126 .globl l2x0_saved_regs_addr
127l2x0_saved_regs_addr:
128 .long 0
129#endif
130
71 .align L1_CACHE_SHIFT 131 .align L1_CACHE_SHIFT
72ENTRY(__tegra_cpu_reset_handler_start) 132ENTRY(__tegra_cpu_reset_handler_start)
73 133
@@ -121,6 +181,17 @@ ENTRY(__tegra_cpu_reset_handler)
1211: 1811:
122#endif 182#endif
123 183
184 /* Waking up from LP2? */
185 ldr r9, [r12, #RESET_DATA(MASK_LP2)]
186 tst r9, r11 @ if in_lp2
187 beq __is_not_lp2
188 ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
189 cmp lr, #0
190 bleq __die @ no LP2 startup handler
191 bx lr
192
193__is_not_lp2:
194
124#ifdef CONFIG_SMP 195#ifdef CONFIG_SMP
125 /* 196 /*
126 * Can only be secondary boot (initial or hotplug) but CPU 0 197 * Can only be secondary boot (initial or hotplug) but CPU 0
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
new file mode 100644
index 000000000000..1b11707eaca0
--- /dev/null
+++ b/arch/arm/mach-tegra/pm.c
@@ -0,0 +1,216 @@
1/*
2 * CPU complex suspend & resume functions for Tegra SoCs
3 *
4 * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/kernel.h>
20#include <linux/spinlock.h>
21#include <linux/io.h>
22#include <linux/cpumask.h>
23#include <linux/delay.h>
24#include <linux/cpu_pm.h>
25#include <linux/clk.h>
26#include <linux/err.h>
27
28#include <asm/smp_plat.h>
29#include <asm/cacheflush.h>
30#include <asm/suspend.h>
31#include <asm/idmap.h>
32#include <asm/proc-fns.h>
33#include <asm/tlbflush.h>
34
35#include "iomap.h"
36#include "reset.h"
37#include "flowctrl.h"
38#include "sleep.h"
39#include "tegra_cpu_car.h"
40
41#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
42
43#define PMC_CTRL 0x0
44#define PMC_CPUPWRGOOD_TIMER 0xc8
45#define PMC_CPUPWROFF_TIMER 0xcc
46
47#ifdef CONFIG_PM_SLEEP
48static unsigned int g_diag_reg;
49static DEFINE_SPINLOCK(tegra_lp2_lock);
50static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
51static struct clk *tegra_pclk;
52void (*tegra_tear_down_cpu)(void);
53
54void save_cpu_arch_register(void)
55{
56 /* read diagnostic register */
57 asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
58 return;
59}
60
61void restore_cpu_arch_register(void)
62{
63 /* write diagnostic register */
64 asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
65 return;
66}
67
68static void set_power_timers(unsigned long us_on, unsigned long us_off)
69{
70 unsigned long long ticks;
71 unsigned long long pclk;
72 unsigned long rate;
73 static unsigned long tegra_last_pclk;
74
75 if (tegra_pclk == NULL) {
76 tegra_pclk = clk_get_sys(NULL, "pclk");
77 WARN_ON(IS_ERR(tegra_pclk));
78 }
79
80 rate = clk_get_rate(tegra_pclk);
81
82 if (WARN_ON_ONCE(rate <= 0))
83 pclk = 100000000;
84 else
85 pclk = rate;
86
87 if ((rate != tegra_last_pclk)) {
88 ticks = (us_on * pclk) + 999999ull;
89 do_div(ticks, 1000000);
90 writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
91
92 ticks = (us_off * pclk) + 999999ull;
93 do_div(ticks, 1000000);
94 writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
95 wmb();
96 }
97 tegra_last_pclk = pclk;
98}
99
100/*
101 * restore_cpu_complex
102 *
103 * restores cpu clock setting, clears flow controller
104 *
105 * Always called on CPU 0.
106 */
107static void restore_cpu_complex(void)
108{
109 int cpu = smp_processor_id();
110
111 BUG_ON(cpu != 0);
112
113#ifdef CONFIG_SMP
114 cpu = cpu_logical_map(cpu);
115#endif
116
117 /* Restore the CPU clock settings */
118 tegra_cpu_clock_resume();
119
120 flowctrl_cpu_suspend_exit(cpu);
121
122 restore_cpu_arch_register();
123}
124
125/*
126 * suspend_cpu_complex
127 *
128 * saves pll state for use by restart_plls, prepares flow controller for
129 * transition to suspend state
130 *
131 * Must always be called on cpu 0.
132 */
133static void suspend_cpu_complex(void)
134{
135 int cpu = smp_processor_id();
136
137 BUG_ON(cpu != 0);
138
139#ifdef CONFIG_SMP
140 cpu = cpu_logical_map(cpu);
141#endif
142
143 /* Save the CPU clock settings */
144 tegra_cpu_clock_suspend();
145
146 flowctrl_cpu_suspend_enter(cpu);
147
148 save_cpu_arch_register();
149}
150
151void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id)
152{
153 u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
154
155 spin_lock(&tegra_lp2_lock);
156
157 BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id)));
158 *cpu_in_lp2 &= ~BIT(phy_cpu_id);
159
160 spin_unlock(&tegra_lp2_lock);
161}
162
163bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id)
164{
165 bool last_cpu = false;
166 cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
167 u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
168
169 spin_lock(&tegra_lp2_lock);
170
171 BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
172 *cpu_in_lp2 |= BIT(phy_cpu_id);
173
174 if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
175 last_cpu = true;
176
177 spin_unlock(&tegra_lp2_lock);
178 return last_cpu;
179}
180
181static int tegra_sleep_cpu(unsigned long v2p)
182{
183 /* Switch to the identity mapping. */
184 cpu_switch_mm(idmap_pgd, &init_mm);
185
186 /* Flush the TLB. */
187 local_flush_tlb_all();
188
189 tegra_sleep_cpu_finish(v2p);
190
191 /* should never here */
192 BUG();
193
194 return 0;
195}
196
197void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
198{
199 u32 mode;
200
201 /* Only the last cpu down does the final suspend steps */
202 mode = readl(pmc + PMC_CTRL);
203 mode |= TEGRA_POWER_CPU_PWRREQ_OE;
204 writel(mode, pmc + PMC_CTRL);
205
206 set_power_timers(cpu_on_time, cpu_off_time);
207
208 cpu_cluster_pm_enter();
209 suspend_cpu_complex();
210
211 cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
212
213 restore_cpu_complex();
214 cpu_cluster_pm_exit();
215}
216#endif
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
new file mode 100644
index 000000000000..787335cc964c
--- /dev/null
+++ b/arch/arm/mach-tegra/pm.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2010 Google, Inc.
3 * Copyright (c) 2010-2012 NVIDIA Corporation. All rights reserved.
4 *
5 * Author:
6 * Colin Cross <ccross@google.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef _MACH_TEGRA_PM_H_
22#define _MACH_TEGRA_PM_H_
23
24extern unsigned long l2x0_saved_regs_addr;
25
26void save_cpu_arch_register(void);
27void restore_cpu_arch_register(void);
28
29void tegra_clear_cpu_in_lp2(int phy_cpu_id);
30bool tegra_set_cpu_in_lp2(int phy_cpu_id);
31
32void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time);
33extern void (*tegra_tear_down_cpu)(void);
34
35#endif /* _MACH_TEGRA_PM_H_ */
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index e05da7d10c3b..3fd89ecd158e 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -25,6 +25,7 @@
25#include "iomap.h" 25#include "iomap.h"
26#include "irammap.h" 26#include "irammap.h"
27#include "reset.h" 27#include "reset.h"
28#include "sleep.h"
28#include "fuse.h" 29#include "fuse.h"
29 30
30#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \ 31#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
@@ -79,5 +80,10 @@ void __init tegra_cpu_reset_handler_init(void)
79 virt_to_phys((void *)tegra_secondary_startup); 80 virt_to_phys((void *)tegra_secondary_startup);
80#endif 81#endif
81 82
83#ifdef CONFIG_PM_SLEEP
84 __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] =
85 virt_to_phys((void *)tegra_resume);
86#endif
87
82 tegra_cpu_reset_handler_enable(); 88 tegra_cpu_reset_handler_enable();
83} 89}
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
index de88bf851dd3..c90d8e9c4ad2 100644
--- a/arch/arm/mach-tegra/reset.h
+++ b/arch/arm/mach-tegra/reset.h
@@ -29,6 +29,8 @@
29 29
30#ifndef __ASSEMBLY__ 30#ifndef __ASSEMBLY__
31 31
32#include "irammap.h"
33
32extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE]; 34extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
33 35
34void __tegra_cpu_reset_handler_start(void); 36void __tegra_cpu_reset_handler_start(void);
@@ -36,6 +38,13 @@ void __tegra_cpu_reset_handler(void);
36void __tegra_cpu_reset_handler_end(void); 38void __tegra_cpu_reset_handler_end(void);
37void tegra_secondary_startup(void); 39void tegra_secondary_startup(void);
38 40
41#ifdef CONFIG_PM_SLEEP
42#define tegra_cpu_lp2_mask \
43 (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
44 ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
45 (u32)__tegra_cpu_reset_handler_start)))
46#endif
47
39#define tegra_cpu_reset_handler_offset \ 48#define tegra_cpu_reset_handler_offset \
40 ((u32)__tegra_cpu_reset_handler - \ 49 ((u32)__tegra_cpu_reset_handler - \
41 (u32)__tegra_cpu_reset_handler_start) 50 (u32)__tegra_cpu_reset_handler_start)
diff --git a/arch/arm/mach-tegra/sleep-t20.S b/arch/arm/mach-tegra/sleep-tegra20.S
index 72ce709799da..72ce709799da 100644
--- a/arch/arm/mach-tegra/sleep-t20.S
+++ b/arch/arm/mach-tegra/sleep-tegra20.S
diff --git a/arch/arm/mach-tegra/sleep-t30.S b/arch/arm/mach-tegra/sleep-tegra30.S
index be7614b7c5cb..562a8e7e413d 100644
--- a/arch/arm/mach-tegra/sleep-t30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -17,6 +17,7 @@
17#include <linux/linkage.h> 17#include <linux/linkage.h>
18 18
19#include <asm/assembler.h> 19#include <asm/assembler.h>
20#include <asm/asm-offsets.h>
20 21
21#include "sleep.h" 22#include "sleep.h"
22#include "flowctrl.h" 23#include "flowctrl.h"
@@ -80,6 +81,7 @@ delay_1:
80 ldr r3, [r1] @ read CSR 81 ldr r3, [r1] @ read CSR
81 str r3, [r1] @ clear CSR 82 str r3, [r1] @ clear CSR
82 tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN 83 tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
84 moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2
83 movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug 85 movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug
84 str r3, [r2] 86 str r3, [r2]
85 ldr r0, [r2] 87 ldr r0, [r2]
@@ -103,3 +105,67 @@ wfe_war:
103 105
104ENDPROC(tegra30_cpu_shutdown) 106ENDPROC(tegra30_cpu_shutdown)
105#endif 107#endif
108
109#ifdef CONFIG_PM_SLEEP
110/*
111 * tegra30_sleep_cpu_secondary_finish(unsigned long v2p)
112 *
113 * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU.
114 */
115ENTRY(tegra30_sleep_cpu_secondary_finish)
116 mov r7, lr
117
118 /* Flush and disable the L1 data cache */
119 bl tegra_disable_clean_inv_dcache
120
121 /* Powergate this CPU. */
122 mov r0, #0 @ power mode flags (!hotplug)
123 bl tegra30_cpu_shutdown
124 mov r0, #1 @ never return here
125 mov pc, r7
126ENDPROC(tegra30_sleep_cpu_secondary_finish)
127
128/*
129 * tegra30_tear_down_cpu
130 *
131 * Switches the CPU to enter sleep.
132 */
133ENTRY(tegra30_tear_down_cpu)
134 mov32 r6, TEGRA_FLOW_CTRL_BASE
135
136 b tegra30_enter_sleep
137ENDPROC(tegra30_tear_down_cpu)
138
139/*
140 * tegra30_enter_sleep
141 *
142 * uses flow controller to enter sleep state
143 * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
144 * executes from SDRAM with target state is LP2
145 * r6 = TEGRA_FLOW_CTRL_BASE
146 */
147tegra30_enter_sleep:
148 cpu_id r1
149
150 cpu_to_csr_reg r2, r1
151 ldr r0, [r6, r2]
152 orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
153 orr r0, r0, #FLOW_CTRL_CSR_ENABLE
154 str r0, [r6, r2]
155
156 mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
157 orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
158 cpu_to_halt_reg r2, r1
159 str r0, [r6, r2]
160 dsb
161 ldr r0, [r6, r2] /* memory barrier */
162
163halted:
164 isb
165 dsb
166 wfi /* CPU should be power gated here */
167
168 /* !!!FIXME!!! Implement halt failure handler */
169 b halted
170
171#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index 08e9481c049e..26afa7cbed11 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -25,9 +25,87 @@
25#include <linux/linkage.h> 25#include <linux/linkage.h>
26 26
27#include <asm/assembler.h> 27#include <asm/assembler.h>
28#include <asm/cache.h>
29#include <asm/cp15.h>
30#include <asm/hardware/cache-l2x0.h>
28 31
29#include "iomap.h" 32#include "iomap.h"
30 33
31#include "flowctrl.h" 34#include "flowctrl.h"
32#include "sleep.h" 35#include "sleep.h"
33 36
37#ifdef CONFIG_PM_SLEEP
38/*
39 * tegra_disable_clean_inv_dcache
40 *
41 * disable, clean & invalidate the D-cache
42 *
43 * Corrupted registers: r1-r3, r6, r8, r9-r11
44 */
45ENTRY(tegra_disable_clean_inv_dcache)
46 stmfd sp!, {r0, r4-r5, r7, r9-r11, lr}
47 dmb @ ensure ordering
48
49 /* Disable the D-cache */
50 mrc p15, 0, r2, c1, c0, 0
51 bic r2, r2, #CR_C
52 mcr p15, 0, r2, c1, c0, 0
53 isb
54
55 /* Flush the D-cache */
56 bl v7_flush_dcache_louis
57
58 /* Trun off coherency */
59 exit_smp r4, r5
60
61 ldmfd sp!, {r0, r4-r5, r7, r9-r11, pc}
62ENDPROC(tegra_disable_clean_inv_dcache)
63
64/*
65 * tegra_sleep_cpu_finish(unsigned long v2p)
66 *
67 * enters suspend in LP2 by turning off the mmu and jumping to
68 * tegra?_tear_down_cpu
69 */
70ENTRY(tegra_sleep_cpu_finish)
71 /* Flush and disable the L1 data cache */
72 bl tegra_disable_clean_inv_dcache
73
74 mov32 r6, tegra_tear_down_cpu
75 ldr r1, [r6]
76 add r1, r1, r0
77
78 mov32 r3, tegra_shut_off_mmu
79 add r3, r3, r0
80 mov r0, r1
81
82 mov pc, r3
83ENDPROC(tegra_sleep_cpu_finish)
84
85/*
86 * tegra_shut_off_mmu
87 *
88 * r0 = physical address to jump to with mmu off
89 *
90 * called with VA=PA mapping
91 * turns off MMU, icache, dcache and branch prediction
92 */
93 .align L1_CACHE_SHIFT
94 .pushsection .idmap.text, "ax"
95ENTRY(tegra_shut_off_mmu)
96 mrc p15, 0, r3, c1, c0, 0
97 movw r2, #CR_I | CR_Z | CR_C | CR_M
98 bic r3, r3, r2
99 dsb
100 mcr p15, 0, r3, c1, c0, 0
101 isb
102#ifdef CONFIG_CACHE_L2X0
103 /* Disable L2 cache */
104 mov32 r4, TEGRA_ARM_PERIF_BASE + 0x3000
105 mov r5, #0
106 str r5, [r4, #L2X0_CTRL]
107#endif
108 mov pc, r0
109ENDPROC(tegra_shut_off_mmu)
110 .popsection
111#endif
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 4889b281c5f9..9821ee725420 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -71,7 +71,41 @@
71 str \tmp2, [\tmp1] @ invalidate SCU tags for CPU 71 str \tmp2, [\tmp1] @ invalidate SCU tags for CPU
72 dsb 72 dsb
73.endm 73.endm
74
75/* Macro to resume & re-enable L2 cache */
76#ifndef L2X0_CTRL_EN
77#define L2X0_CTRL_EN 1
78#endif
79
80#ifdef CONFIG_CACHE_L2X0
81.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs
82 adr \tmp1, \phys_l2x0_saved_regs
83 ldr \tmp1, [\tmp1]
84 ldr \tmp2, [\tmp1, #L2X0_R_PHY_BASE]
85 ldr \tmp3, [\tmp2, #L2X0_CTRL]
86 tst \tmp3, #L2X0_CTRL_EN
87 bne exit_l2_resume
88 ldr \tmp3, [\tmp1, #L2X0_R_TAG_LATENCY]
89 str \tmp3, [\tmp2, #L2X0_TAG_LATENCY_CTRL]
90 ldr \tmp3, [\tmp1, #L2X0_R_DATA_LATENCY]
91 str \tmp3, [\tmp2, #L2X0_DATA_LATENCY_CTRL]
92 ldr \tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL]
93 str \tmp3, [\tmp2, #L2X0_PREFETCH_CTRL]
94 ldr \tmp3, [\tmp1, #L2X0_R_PWR_CTRL]
95 str \tmp3, [\tmp2, #L2X0_POWER_CTRL]
96 ldr \tmp3, [\tmp1, #L2X0_R_AUX_CTRL]
97 str \tmp3, [\tmp2, #L2X0_AUX_CTRL]
98 mov \tmp3, #L2X0_CTRL_EN
99 str \tmp3, [\tmp2, #L2X0_CTRL]
100exit_l2_resume:
101.endm
102#else /* CONFIG_CACHE_L2X0 */
103.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs
104.endm
105#endif /* CONFIG_CACHE_L2X0 */
74#else 106#else
107void tegra_resume(void);
108int tegra_sleep_cpu_finish(unsigned long);
75 109
76#ifdef CONFIG_HOTPLUG_CPU 110#ifdef CONFIG_HOTPLUG_CPU
77void tegra20_hotplug_init(void); 111void tegra20_hotplug_init(void);
@@ -81,5 +115,8 @@ static inline void tegra20_hotplug_init(void) {}
81static inline void tegra30_hotplug_init(void) {} 115static inline void tegra30_hotplug_init(void) {}
82#endif 116#endif
83 117
118int tegra30_sleep_cpu_secondary_finish(unsigned long);
119void tegra30_tear_down_cpu(void);
120
84#endif 121#endif
85#endif 122#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c
index 9615ee39c353..a23a0734e352 100644
--- a/arch/arm/mach-tegra/tegra20_clocks_data.c
+++ b/arch/arm/mach-tegra/tegra20_clocks_data.c
@@ -246,11 +246,16 @@ static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
246 { 19200000, 216000000, 135, 12, 1, 3}, 246 { 19200000, 216000000, 135, 12, 1, 3},
247 { 26000000, 216000000, 216, 26, 1, 4}, 247 { 26000000, 216000000, 216, 26, 1, 4},
248 248
249 { 12000000, 297000000, 99, 4, 1, 4 },
250 { 12000000, 339000000, 113, 4, 1, 4 },
251
249 { 12000000, 594000000, 594, 12, 1, 8}, 252 { 12000000, 594000000, 594, 12, 1, 8},
250 { 13000000, 594000000, 594, 13, 1, 8}, 253 { 13000000, 594000000, 594, 13, 1, 8},
251 { 19200000, 594000000, 495, 16, 1, 8}, 254 { 19200000, 594000000, 495, 16, 1, 8},
252 { 26000000, 594000000, 594, 26, 1, 8}, 255 { 26000000, 594000000, 594, 26, 1, 8},
253 256
257 { 12000000, 616000000, 616, 12, 1, 8},
258
254 { 12000000, 1000000000, 1000, 12, 1, 12}, 259 { 12000000, 1000000000, 1000, 12, 1, 12},
255 { 13000000, 1000000000, 1000, 13, 1, 12}, 260 { 13000000, 1000000000, 1000, 13, 1, 12},
256 { 19200000, 1000000000, 625, 12, 1, 8}, 261 { 19200000, 1000000000, 625, 12, 1, 8},
@@ -1036,9 +1041,6 @@ static struct clk_duplicate tegra_clk_duplicates[] = {
1036 CLK_DUPLICATE("usbd", "utmip-pad", NULL), 1041 CLK_DUPLICATE("usbd", "utmip-pad", NULL),
1037 CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), 1042 CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
1038 CLK_DUPLICATE("usbd", "tegra-otg", NULL), 1043 CLK_DUPLICATE("usbd", "tegra-otg", NULL),
1039 CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
1040 CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
1041 CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
1042 CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"), 1044 CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
1043 CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"), 1045 CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
1044 CLK_DUPLICATE("epp", "tegra_grhost", "epp"), 1046 CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
@@ -1051,6 +1053,9 @@ static struct clk_duplicate tegra_clk_duplicates[] = {
1051 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), 1053 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"),
1052 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), 1054 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),
1053 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), 1055 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),
1056 CLK_DUPLICATE("pll_p", "tegradc.0", "parent"),
1057 CLK_DUPLICATE("pll_p", "tegradc.1", "parent"),
1058 CLK_DUPLICATE("pll_d_out0", "hdmi", "parent"),
1054}; 1059};
1055 1060
1056#define CLK(dev, con, ck) \ 1061#define CLK(dev, con, ck) \
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
new file mode 100644
index 000000000000..fa6eb570623f
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_speedo.c
@@ -0,0 +1,109 @@
1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/kernel.h>
18#include <linux/bug.h>
19
20#include "fuse.h"
21
22#define CPU_SPEEDO_LSBIT 20
23#define CPU_SPEEDO_MSBIT 29
24#define CPU_SPEEDO_REDUND_LSBIT 30
25#define CPU_SPEEDO_REDUND_MSBIT 39
26#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
27
28#define CORE_SPEEDO_LSBIT 40
29#define CORE_SPEEDO_MSBIT 47
30#define CORE_SPEEDO_REDUND_LSBIT 48
31#define CORE_SPEEDO_REDUND_MSBIT 55
32#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
33
34#define SPEEDO_MULT 4
35
36#define PROCESS_CORNERS_NUM 4
37
38#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2)
39#define SPEEDO_ID_SELECT_1(sku) \
40 (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
41 ((sku) != 27) && ((sku) != 28))
42
43enum {
44 SPEEDO_ID_0,
45 SPEEDO_ID_1,
46 SPEEDO_ID_2,
47 SPEEDO_ID_COUNT,
48};
49
50static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
51 {315, 366, 420, UINT_MAX},
52 {303, 368, 419, UINT_MAX},
53 {316, 331, 383, UINT_MAX},
54};
55
56static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
57 {165, 195, 224, UINT_MAX},
58 {165, 195, 224, UINT_MAX},
59 {165, 195, 224, UINT_MAX},
60};
61
62void tegra20_init_speedo_data(void)
63{
64 u32 reg;
65 u32 val;
66 int i;
67
68 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
69 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT);
70
71 if (SPEEDO_ID_SELECT_0(tegra_revision))
72 tegra_soc_speedo_id = SPEEDO_ID_0;
73 else if (SPEEDO_ID_SELECT_1(tegra_sku_id))
74 tegra_soc_speedo_id = SPEEDO_ID_1;
75 else
76 tegra_soc_speedo_id = SPEEDO_ID_2;
77
78 val = 0;
79 for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
80 reg = tegra_spare_fuse(i) |
81 tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS);
82 val = (val << 1) | (reg & 0x1);
83 }
84 val = val * SPEEDO_MULT;
85 pr_debug("%s CPU speedo value %u\n", __func__, val);
86
87 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
88 if (val <= cpu_process_speedos[tegra_soc_speedo_id][i])
89 break;
90 }
91 tegra_cpu_process_id = i;
92
93 val = 0;
94 for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
95 reg = tegra_spare_fuse(i) |
96 tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS);
97 val = (val << 1) | (reg & 0x1);
98 }
99 val = val * SPEEDO_MULT;
100 pr_debug("%s Core speedo value %u\n", __func__, val);
101
102 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
103 if (val <= core_process_speedos[tegra_soc_speedo_id][i])
104 break;
105 }
106 tegra_core_process_id = i;
107
108 pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id);
109}
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
index 000239d68393..efc000e32e1c 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -31,6 +31,8 @@
31 31
32#include <asm/clkdev.h> 32#include <asm/clkdev.h>
33 33
34#include <mach/powergate.h>
35
34#include "clock.h" 36#include "clock.h"
35#include "fuse.h" 37#include "fuse.h"
36#include "iomap.h" 38#include "iomap.h"
@@ -309,6 +311,31 @@
309#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) 311#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
310#define CPU_RESET(cpu) (0x1111ul << (cpu)) 312#define CPU_RESET(cpu) (0x1111ul << (cpu))
311 313
314#define CLK_RESET_CCLK_BURST 0x20
315#define CLK_RESET_CCLK_DIVIDER 0x24
316#define CLK_RESET_PLLX_BASE 0xe0
317#define CLK_RESET_PLLX_MISC 0xe4
318
319#define CLK_RESET_SOURCE_CSITE 0x1d4
320
321#define CLK_RESET_CCLK_BURST_POLICY_SHIFT 28
322#define CLK_RESET_CCLK_RUN_POLICY_SHIFT 4
323#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT 0
324#define CLK_RESET_CCLK_IDLE_POLICY 1
325#define CLK_RESET_CCLK_RUN_POLICY 2
326#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8
327
328#ifdef CONFIG_PM_SLEEP
329static struct cpu_clk_suspend_context {
330 u32 pllx_misc;
331 u32 pllx_base;
332
333 u32 cpu_burst;
334 u32 clk_csite_src;
335 u32 cclk_divider;
336} tegra30_cpu_clk_sctx;
337#endif
338
312/** 339/**
313* Structure defining the fields for USB UTMI clocks Parameters. 340* Structure defining the fields for USB UTMI clocks Parameters.
314*/ 341*/
@@ -791,6 +818,112 @@ struct clk_ops tegra30_twd_ops = {
791 .recalc_rate = tegra30_twd_clk_recalc_rate, 818 .recalc_rate = tegra30_twd_clk_recalc_rate,
792}; 819};
793 820
821/* bus clock functions */
822static int tegra30_bus_clk_is_enabled(struct clk_hw *hw)
823{
824 struct clk_tegra *c = to_clk_tegra(hw);
825 u32 val = clk_readl(c->reg);
826
827 c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
828 return c->state;
829}
830
831static int tegra30_bus_clk_enable(struct clk_hw *hw)
832{
833 struct clk_tegra *c = to_clk_tegra(hw);
834 u32 val;
835
836 val = clk_readl(c->reg);
837 val &= ~(BUS_CLK_DISABLE << c->reg_shift);
838 clk_writel(val, c->reg);
839
840 return 0;
841}
842
843static void tegra30_bus_clk_disable(struct clk_hw *hw)
844{
845 struct clk_tegra *c = to_clk_tegra(hw);
846 u32 val;
847
848 val = clk_readl(c->reg);
849 val |= BUS_CLK_DISABLE << c->reg_shift;
850 clk_writel(val, c->reg);
851}
852
853static unsigned long tegra30_bus_clk_recalc_rate(struct clk_hw *hw,
854 unsigned long prate)
855{
856 struct clk_tegra *c = to_clk_tegra(hw);
857 u32 val = clk_readl(c->reg);
858 u64 rate = prate;
859
860 c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
861 c->mul = 1;
862
863 if (c->mul != 0 && c->div != 0) {
864 rate *= c->mul;
865 rate += c->div - 1; /* round up */
866 do_div(rate, c->div);
867 }
868 return rate;
869}
870
871static int tegra30_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
872 unsigned long parent_rate)
873{
874 struct clk_tegra *c = to_clk_tegra(hw);
875 int ret = -EINVAL;
876 u32 val;
877 int i;
878
879 val = clk_readl(c->reg);
880 for (i = 1; i <= 4; i++) {
881 if (rate == parent_rate / i) {
882 val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
883 val |= (i - 1) << c->reg_shift;
884 clk_writel(val, c->reg);
885 c->div = i;
886 c->mul = 1;
887 ret = 0;
888 break;
889 }
890 }
891
892 return ret;
893}
894
895static long tegra30_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
896 unsigned long *prate)
897{
898 unsigned long parent_rate = *prate;
899 s64 divider;
900
901 if (rate >= parent_rate)
902 return parent_rate;
903
904 divider = parent_rate;
905 divider += rate - 1;
906 do_div(divider, rate);
907
908 if (divider < 0)
909 return divider;
910
911 if (divider > 4)
912 divider = 4;
913 do_div(parent_rate, divider);
914
915 return parent_rate;
916}
917
918struct clk_ops tegra30_bus_ops = {
919 .is_enabled = tegra30_bus_clk_is_enabled,
920 .enable = tegra30_bus_clk_enable,
921 .disable = tegra30_bus_clk_disable,
922 .set_rate = tegra30_bus_clk_set_rate,
923 .round_rate = tegra30_bus_clk_round_rate,
924 .recalc_rate = tegra30_bus_clk_recalc_rate,
925};
926
794/* Blink output functions */ 927/* Blink output functions */
795static int tegra30_blink_clk_is_enabled(struct clk_hw *hw) 928static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
796{ 929{
@@ -2280,12 +2413,93 @@ static void tegra30_disable_cpu_clock(u32 cpu)
2280 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); 2413 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
2281} 2414}
2282 2415
2416#ifdef CONFIG_PM_SLEEP
2417static bool tegra30_cpu_rail_off_ready(void)
2418{
2419 unsigned int cpu_rst_status;
2420 int cpu_pwr_status;
2421
2422 cpu_rst_status = readl(reg_clk_base +
2423 TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
2424 cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) ||
2425 tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) ||
2426 tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3);
2427
2428 if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status)
2429 return false;
2430
2431 return true;
2432}
2433
2434static void tegra30_cpu_clock_suspend(void)
2435{
2436 /* switch coresite to clk_m, save off original source */
2437 tegra30_cpu_clk_sctx.clk_csite_src =
2438 readl(reg_clk_base + CLK_RESET_SOURCE_CSITE);
2439 writel(3<<30, reg_clk_base + CLK_RESET_SOURCE_CSITE);
2440
2441 tegra30_cpu_clk_sctx.cpu_burst =
2442 readl(reg_clk_base + CLK_RESET_CCLK_BURST);
2443 tegra30_cpu_clk_sctx.pllx_base =
2444 readl(reg_clk_base + CLK_RESET_PLLX_BASE);
2445 tegra30_cpu_clk_sctx.pllx_misc =
2446 readl(reg_clk_base + CLK_RESET_PLLX_MISC);
2447 tegra30_cpu_clk_sctx.cclk_divider =
2448 readl(reg_clk_base + CLK_RESET_CCLK_DIVIDER);
2449}
2450
2451static void tegra30_cpu_clock_resume(void)
2452{
2453 unsigned int reg, policy;
2454
2455 /* Is CPU complex already running on PLLX? */
2456 reg = readl(reg_clk_base + CLK_RESET_CCLK_BURST);
2457 policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF;
2458
2459 if (policy == CLK_RESET_CCLK_IDLE_POLICY)
2460 reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF;
2461 else if (policy == CLK_RESET_CCLK_RUN_POLICY)
2462 reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF;
2463 else
2464 BUG();
2465
2466 if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) {
2467 /* restore PLLX settings if CPU is on different PLL */
2468 writel(tegra30_cpu_clk_sctx.pllx_misc,
2469 reg_clk_base + CLK_RESET_PLLX_MISC);
2470 writel(tegra30_cpu_clk_sctx.pllx_base,
2471 reg_clk_base + CLK_RESET_PLLX_BASE);
2472
2473 /* wait for PLL stabilization if PLLX was enabled */
2474 if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30))
2475 udelay(300);
2476 }
2477
2478 /*
2479 * Restore original burst policy setting for calls resulting from CPU
2480 * LP2 in idle or system suspend.
2481 */
2482 writel(tegra30_cpu_clk_sctx.cclk_divider,
2483 reg_clk_base + CLK_RESET_CCLK_DIVIDER);
2484 writel(tegra30_cpu_clk_sctx.cpu_burst,
2485 reg_clk_base + CLK_RESET_CCLK_BURST);
2486
2487 writel(tegra30_cpu_clk_sctx.clk_csite_src,
2488 reg_clk_base + CLK_RESET_SOURCE_CSITE);
2489}
2490#endif
2491
2283static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { 2492static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
2284 .wait_for_reset = tegra30_wait_cpu_in_reset, 2493 .wait_for_reset = tegra30_wait_cpu_in_reset,
2285 .put_in_reset = tegra30_put_cpu_in_reset, 2494 .put_in_reset = tegra30_put_cpu_in_reset,
2286 .out_of_reset = tegra30_cpu_out_of_reset, 2495 .out_of_reset = tegra30_cpu_out_of_reset,
2287 .enable_clock = tegra30_enable_cpu_clock, 2496 .enable_clock = tegra30_enable_cpu_clock,
2288 .disable_clock = tegra30_disable_cpu_clock, 2497 .disable_clock = tegra30_disable_cpu_clock,
2498#ifdef CONFIG_PM_SLEEP
2499 .rail_off_ready = tegra30_cpu_rail_off_ready,
2500 .suspend = tegra30_cpu_clock_suspend,
2501 .resume = tegra30_cpu_clock_resume,
2502#endif
2289}; 2503};
2290 2504
2291void __init tegra30_cpu_car_ops_init(void) 2505void __init tegra30_cpu_car_ops_init(void)
diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h
index f2f88fef6b8b..7a34adb2f72d 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.h
+++ b/arch/arm/mach-tegra/tegra30_clocks.h
@@ -34,6 +34,7 @@ extern struct clk_ops tegra_clk_out_ops;
34extern struct clk_ops tegra30_super_ops; 34extern struct clk_ops tegra30_super_ops;
35extern struct clk_ops tegra30_blink_clk_ops; 35extern struct clk_ops tegra30_blink_clk_ops;
36extern struct clk_ops tegra30_twd_ops; 36extern struct clk_ops tegra30_twd_ops;
37extern struct clk_ops tegra30_bus_ops;
37extern struct clk_ops tegra30_periph_clk_ops; 38extern struct clk_ops tegra30_periph_clk_ops;
38extern struct clk_ops tegra30_dsib_clk_ops; 39extern struct clk_ops tegra30_dsib_clk_ops;
39extern struct clk_ops tegra_nand_clk_ops; 40extern struct clk_ops tegra_nand_clk_ops;
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c
index 3d2e5532a9ea..6942c7add3bb 100644
--- a/arch/arm/mach-tegra/tegra30_clocks_data.c
+++ b/arch/arm/mach-tegra/tegra30_clocks_data.c
@@ -711,6 +711,50 @@ static struct clk tegra_clk_sclk = {
711 .num_parents = ARRAY_SIZE(mux_sclk), 711 .num_parents = ARRAY_SIZE(mux_sclk),
712}; 712};
713 713
714static const char *tegra_hclk_parent_names[] = {
715 "tegra_sclk",
716};
717
718static struct clk *tegra_hclk_parents[] = {
719 &tegra_clk_sclk,
720};
721
722static struct clk tegra_hclk;
723static struct clk_tegra tegra_hclk_hw = {
724 .hw = {
725 .clk = &tegra_hclk,
726 },
727 .flags = DIV_BUS,
728 .reg = 0x30,
729 .reg_shift = 4,
730 .max_rate = 378000000,
731 .min_rate = 12000000,
732};
733DEFINE_CLK_TEGRA(hclk, 0, &tegra30_bus_ops, 0, tegra_hclk_parent_names,
734 tegra_hclk_parents, &tegra_clk_sclk);
735
736static const char *tegra_pclk_parent_names[] = {
737 "tegra_hclk",
738};
739
740static struct clk *tegra_pclk_parents[] = {
741 &tegra_hclk,
742};
743
744static struct clk tegra_pclk;
745static struct clk_tegra tegra_pclk_hw = {
746 .hw = {
747 .clk = &tegra_pclk,
748 },
749 .flags = DIV_BUS,
750 .reg = 0x30,
751 .reg_shift = 0,
752 .max_rate = 167000000,
753 .min_rate = 12000000,
754};
755DEFINE_CLK_TEGRA(pclk, 0, &tegra30_bus_ops, 0, tegra_pclk_parent_names,
756 tegra_pclk_parents, &tegra_hclk);
757
714static const char *mux_blink[] = { 758static const char *mux_blink[] = {
715 "clk_32k", 759 "clk_32k",
716}; 760};
@@ -1254,8 +1298,6 @@ struct clk_duplicate tegra_clk_duplicates[] = {
1254 CLK_DUPLICATE("usbd", "utmip-pad", NULL), 1298 CLK_DUPLICATE("usbd", "utmip-pad", NULL),
1255 CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), 1299 CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
1256 CLK_DUPLICATE("usbd", "tegra-otg", NULL), 1300 CLK_DUPLICATE("usbd", "tegra-otg", NULL),
1257 CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
1258 CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
1259 CLK_DUPLICATE("dsib", "tegradc.0", "dsib"), 1301 CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
1260 CLK_DUPLICATE("dsia", "tegradc.1", "dsia"), 1302 CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
1261 CLK_DUPLICATE("bsev", "tegra-avp", "bsev"), 1303 CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
@@ -1293,6 +1335,9 @@ struct clk_duplicate tegra_clk_duplicates[] = {
1293 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), 1335 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),
1294 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), 1336 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),
1295 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"), 1337 CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"),
1338 CLK_DUPLICATE("pll_p", "tegradc.0", "parent"),
1339 CLK_DUPLICATE("pll_p", "tegradc.1", "parent"),
1340 CLK_DUPLICATE("pll_d2_out0", "hdmi", "parent"),
1296}; 1341};
1297 1342
1298struct clk *tegra_ptr_clks[] = { 1343struct clk *tegra_ptr_clks[] = {
@@ -1325,6 +1370,8 @@ struct clk *tegra_ptr_clks[] = {
1325 &tegra_cml1, 1370 &tegra_cml1,
1326 &tegra_pciex, 1371 &tegra_pciex,
1327 &tegra_clk_sclk, 1372 &tegra_clk_sclk,
1373 &tegra_hclk,
1374 &tegra_pclk,
1328 &tegra_clk_blink, 1375 &tegra_clk_blink,
1329 &tegra30_clk_twd, 1376 &tegra30_clk_twd,
1330}; 1377};
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
new file mode 100644
index 000000000000..125cb16424a6
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_speedo.c
@@ -0,0 +1,292 @@
1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/kernel.h>
18#include <linux/bug.h>
19
20#include "fuse.h"
21
22#define CORE_PROCESS_CORNERS_NUM 1
23#define CPU_PROCESS_CORNERS_NUM 6
24
25#define FUSE_SPEEDO_CALIB_0 0x114
26#define FUSE_PACKAGE_INFO 0X1FC
27#define FUSE_TEST_PROG_VER 0X128
28
29#define G_SPEEDO_BIT_MINUS1 58
30#define G_SPEEDO_BIT_MINUS1_R 59
31#define G_SPEEDO_BIT_MINUS2 60
32#define G_SPEEDO_BIT_MINUS2_R 61
33#define LP_SPEEDO_BIT_MINUS1 62
34#define LP_SPEEDO_BIT_MINUS1_R 63
35#define LP_SPEEDO_BIT_MINUS2 64
36#define LP_SPEEDO_BIT_MINUS2_R 65
37
38enum {
39 THRESHOLD_INDEX_0,
40 THRESHOLD_INDEX_1,
41 THRESHOLD_INDEX_2,
42 THRESHOLD_INDEX_3,
43 THRESHOLD_INDEX_4,
44 THRESHOLD_INDEX_5,
45 THRESHOLD_INDEX_6,
46 THRESHOLD_INDEX_7,
47 THRESHOLD_INDEX_8,
48 THRESHOLD_INDEX_9,
49 THRESHOLD_INDEX_10,
50 THRESHOLD_INDEX_11,
51 THRESHOLD_INDEX_COUNT,
52};
53
54static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
55 {180},
56 {170},
57 {195},
58 {180},
59 {168},
60 {192},
61 {180},
62 {170},
63 {195},
64 {180},
65 {180},
66 {180},
67};
68
69static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
70 {306, 338, 360, 376, UINT_MAX},
71 {295, 336, 358, 375, UINT_MAX},
72 {325, 325, 358, 375, UINT_MAX},
73 {325, 325, 358, 375, UINT_MAX},
74 {292, 324, 348, 364, UINT_MAX},
75 {324, 324, 348, 364, UINT_MAX},
76 {324, 324, 348, 364, UINT_MAX},
77 {295, 336, 358, 375, UINT_MAX},
78 {358, 358, 358, 358, 397, UINT_MAX},
79 {364, 364, 364, 364, 397, UINT_MAX},
80 {295, 336, 358, 375, 391, UINT_MAX},
81 {295, 336, 358, 375, 391, UINT_MAX},
82};
83
84static int threshold_index;
85static int package_id;
86
87static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
88{
89 u32 reg;
90 int ate_ver;
91 int bit_minus1;
92 int bit_minus2;
93
94 reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
95
96 *speedo_lp = (reg & 0xFFFF) * 4;
97 *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
98
99 ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER);
100 pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
101
102 if (ate_ver >= 26) {
103 bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1);
104 bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
105 bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2);
106 bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
107 *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
108
109 bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1);
110 bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
111 bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2);
112 bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
113 *speedo_g |= (bit_minus1 << 1) | bit_minus2;
114 } else {
115 *speedo_lp |= 0x3;
116 *speedo_g |= 0x3;
117 }
118}
119
120static void rev_sku_to_speedo_ids(int rev, int sku)
121{
122 switch (rev) {
123 case TEGRA_REVISION_A01:
124 tegra_cpu_speedo_id = 0;
125 tegra_soc_speedo_id = 0;
126 threshold_index = THRESHOLD_INDEX_0;
127 break;
128 case TEGRA_REVISION_A02:
129 case TEGRA_REVISION_A03:
130 switch (sku) {
131 case 0x87:
132 case 0x82:
133 tegra_cpu_speedo_id = 1;
134 tegra_soc_speedo_id = 1;
135 threshold_index = THRESHOLD_INDEX_1;
136 break;
137 case 0x81:
138 switch (package_id) {
139 case 1:
140 tegra_cpu_speedo_id = 2;
141 tegra_soc_speedo_id = 2;
142 threshold_index = THRESHOLD_INDEX_2;
143 break;
144 case 2:
145 tegra_cpu_speedo_id = 4;
146 tegra_soc_speedo_id = 1;
147 threshold_index = THRESHOLD_INDEX_7;
148 break;
149 default:
150 pr_err("Tegra30: Unknown pkg %d\n", package_id);
151 BUG();
152 break;
153 }
154 break;
155 case 0x80:
156 switch (package_id) {
157 case 1:
158 tegra_cpu_speedo_id = 5;
159 tegra_soc_speedo_id = 2;
160 threshold_index = THRESHOLD_INDEX_8;
161 break;
162 case 2:
163 tegra_cpu_speedo_id = 6;
164 tegra_soc_speedo_id = 2;
165 threshold_index = THRESHOLD_INDEX_9;
166 break;
167 default:
168 pr_err("Tegra30: Unknown pkg %d\n", package_id);
169 BUG();
170 break;
171 }
172 break;
173 case 0x83:
174 switch (package_id) {
175 case 1:
176 tegra_cpu_speedo_id = 7;
177 tegra_soc_speedo_id = 1;
178 threshold_index = THRESHOLD_INDEX_10;
179 break;
180 case 2:
181 tegra_cpu_speedo_id = 3;
182 tegra_soc_speedo_id = 2;
183 threshold_index = THRESHOLD_INDEX_3;
184 break;
185 default:
186 pr_err("Tegra30: Unknown pkg %d\n", package_id);
187 BUG();
188 break;
189 }
190 break;
191 case 0x8F:
192 tegra_cpu_speedo_id = 8;
193 tegra_soc_speedo_id = 1;
194 threshold_index = THRESHOLD_INDEX_11;
195 break;
196 case 0x08:
197 tegra_cpu_speedo_id = 1;
198 tegra_soc_speedo_id = 1;
199 threshold_index = THRESHOLD_INDEX_4;
200 break;
201 case 0x02:
202 tegra_cpu_speedo_id = 2;
203 tegra_soc_speedo_id = 2;
204 threshold_index = THRESHOLD_INDEX_5;
205 break;
206 case 0x04:
207 tegra_cpu_speedo_id = 3;
208 tegra_soc_speedo_id = 2;
209 threshold_index = THRESHOLD_INDEX_6;
210 break;
211 case 0:
212 switch (package_id) {
213 case 1:
214 tegra_cpu_speedo_id = 2;
215 tegra_soc_speedo_id = 2;
216 threshold_index = THRESHOLD_INDEX_2;
217 break;
218 case 2:
219 tegra_cpu_speedo_id = 3;
220 tegra_soc_speedo_id = 2;
221 threshold_index = THRESHOLD_INDEX_3;
222 break;
223 default:
224 pr_err("Tegra30: Unknown pkg %d\n", package_id);
225 BUG();
226 break;
227 }
228 break;
229 default:
230 pr_warn("Tegra30: Unknown SKU %d\n", sku);
231 tegra_cpu_speedo_id = 0;
232 tegra_soc_speedo_id = 0;
233 threshold_index = THRESHOLD_INDEX_0;
234 break;
235 }
236 break;
237 default:
238 pr_warn("Tegra30: Unknown chip rev %d\n", rev);
239 tegra_cpu_speedo_id = 0;
240 tegra_soc_speedo_id = 0;
241 threshold_index = THRESHOLD_INDEX_0;
242 break;
243 }
244}
245
246void tegra30_init_speedo_data(void)
247{
248 u32 cpu_speedo_val;
249 u32 core_speedo_val;
250 int i;
251
252 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
253 THRESHOLD_INDEX_COUNT);
254 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
255 THRESHOLD_INDEX_COUNT);
256
257 package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
258
259 rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
260 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
261 pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
262 pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
263
264 for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
265 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
266 break;
267 }
268 tegra_cpu_process_id = i - 1;
269
270 if (tegra_cpu_process_id == -1) {
271 pr_warn("Tegra30: CPU speedo value %3d out of range",
272 cpu_speedo_val);
273 tegra_cpu_process_id = 0;
274 tegra_cpu_speedo_id = 1;
275 }
276
277 for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
278 if (core_speedo_val < core_process_speedos[threshold_index][i])
279 break;
280 }
281 tegra_core_process_id = i - 1;
282
283 if (tegra_core_process_id == -1) {
284 pr_warn("Tegra30: CORE speedo value %3d out of range",
285 core_speedo_val);
286 tegra_core_process_id = 0;
287 tegra_soc_speedo_id = 1;
288 }
289
290 pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
291 tegra_cpu_speedo_id, tegra_soc_speedo_id);
292}
diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/arch/arm/mach-tegra/tegra_cpu_car.h
index 30d063ad2bef..9764d31032b7 100644
--- a/arch/arm/mach-tegra/tegra_cpu_car.h
+++ b/arch/arm/mach-tegra/tegra_cpu_car.h
@@ -30,6 +30,12 @@
30 * CPU clock un-gate 30 * CPU clock un-gate
31 * disable_clock: 31 * disable_clock:
32 * CPU clock gate 32 * CPU clock gate
33 * rail_off_ready:
34 * CPU is ready for rail off
35 * suspend:
36 * save the clock settings when CPU go into low-power state
37 * resume:
38 * restore the clock settings when CPU exit low-power state
33 */ 39 */
34struct tegra_cpu_car_ops { 40struct tegra_cpu_car_ops {
35 void (*wait_for_reset)(u32 cpu); 41 void (*wait_for_reset)(u32 cpu);
@@ -37,6 +43,11 @@ struct tegra_cpu_car_ops {
37 void (*out_of_reset)(u32 cpu); 43 void (*out_of_reset)(u32 cpu);
38 void (*enable_clock)(u32 cpu); 44 void (*enable_clock)(u32 cpu);
39 void (*disable_clock)(u32 cpu); 45 void (*disable_clock)(u32 cpu);
46#ifdef CONFIG_PM_SLEEP
47 bool (*rail_off_ready)(void);
48 void (*suspend)(void);
49 void (*resume)(void);
50#endif
40}; 51};
41 52
42extern struct tegra_cpu_car_ops *tegra_cpu_car_ops; 53extern struct tegra_cpu_car_ops *tegra_cpu_car_ops;
@@ -81,6 +92,32 @@ static inline void tegra_disable_cpu_clock(u32 cpu)
81 tegra_cpu_car_ops->disable_clock(cpu); 92 tegra_cpu_car_ops->disable_clock(cpu);
82} 93}
83 94
95#ifdef CONFIG_PM_SLEEP
96static inline bool tegra_cpu_rail_off_ready(void)
97{
98 if (WARN_ON(!tegra_cpu_car_ops->rail_off_ready))
99 return false;
100
101 return tegra_cpu_car_ops->rail_off_ready();
102}
103
104static inline void tegra_cpu_clock_suspend(void)
105{
106 if (WARN_ON(!tegra_cpu_car_ops->suspend))
107 return;
108
109 tegra_cpu_car_ops->suspend();
110}
111
112static inline void tegra_cpu_clock_resume(void)
113{
114 if (WARN_ON(!tegra_cpu_car_ops->resume))
115 return;
116
117 tegra_cpu_car_ops->resume();
118}
119#endif
120
84void tegra20_cpu_car_ops_init(void); 121void tegra20_cpu_car_ops_init(void);
85void tegra30_cpu_car_ops_init(void); 122void tegra30_cpu_car_ops_init(void);
86 123