ARM: tegra11x: CPUID virtualization support
[linux-3.10.git] / arch / arm / mach-tegra / timer-t3.c
1 /*
2  * arch/arch/mach-tegra/timer-t3.c
3  *
4  * Copyright (c) 2011-2012, NVIDIA Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20
21 #include <linux/init.h>
22 #include <linux/err.h>
23 #include <linux/sched.h>
24 #include <linux/time.h>
25 #include <linux/interrupt.h>
26 #include <linux/irq.h>
27 #include <linux/clockchips.h>
28 #include <linux/clocksource.h>
29 #include <linux/clk.h>
30 #include <linux/io.h>
31 #include <linux/smp.h>
32 #include <linux/syscore_ops.h>
33 #include <linux/cpu.h>
34 #include <linux/export.h>
35
36 #include <asm/mach/time.h>
37 #include <asm/localtimer.h>
38 #include <asm/sched_clock.h>
39 #include <asm/smp_plat.h>
40
41 #include <mach/iomap.h>
42 #include <mach/irqs.h>
43 #include <mach/hardware.h>
44
45 #include "board.h"
46 #include "clock.h"
47 #include "cpuidle.h"
48 #include "timer.h"
49 #include "fuse.h"
50
51 #define TEST_LP2_WAKE_TIMERS    0
52
53 /*
54  * Timers usage:
55  * TMR1 - used as general CPU timer.
56  * TMR2 - used by AVP.
57  * TMR3 - used by CPU0 for LP2 wakeup.
58  * TMR4 - used by CPU1 for LP2 wakeup.
59  * TMR5 - used by CPU2 for LP2 wakeup.
60  * TMR6 - used by CPU3 for LP2 wakeup.
61  * TMR7 - Free.
62  * TMR8 - Free.
63  * TMR9 - Free.
64  * TMR10 - used as source for watchdog controller 0.
65 */
66
67 #define TIMER1_OFFSET (TEGRA_TMR1_BASE-TEGRA_TMR1_BASE)
68 #define TIMER2_OFFSET (TEGRA_TMR2_BASE-TEGRA_TMR1_BASE)
69 #define TIMER3_OFFSET (TEGRA_TMR3_BASE-TEGRA_TMR1_BASE)
70 #define TIMER4_OFFSET (TEGRA_TMR4_BASE-TEGRA_TMR1_BASE)
71 #define TIMER5_OFFSET (TEGRA_TMR5_BASE-TEGRA_TMR1_BASE)
72 #define TIMER6_OFFSET (TEGRA_TMR6_BASE-TEGRA_TMR1_BASE)
73
74 static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE);
75
76 #if defined(CONFIG_PM_SLEEP)
77 static cpumask_t wake_timer_canceled;
78 static cpumask_t wake_timer_ready;
79 #endif
80
81 static inline void timer_writel(u32 value, unsigned long reg)
82 {
83         __raw_writel(value, timer_reg_base + (reg));
84 }
85
86 static inline unsigned int timer_readl(unsigned long reg)
87 {
88         return __raw_readl(timer_reg_base + (reg));
89 }
90
91 #ifdef CONFIG_PM_SLEEP
92 static u32 lp2_wake_timers[] = {
93         TIMER3_OFFSET,
94 #ifdef CONFIG_SMP
95         TIMER4_OFFSET,
96         TIMER5_OFFSET,
97         TIMER6_OFFSET,
98 #endif
99 };
100
101 static irqreturn_t tegra_lp2wake_interrupt(int irq, void *dev_id)
102 {
103         int cpu = (int)dev_id;
104         int base;
105
106         base = lp2_wake_timers[cpu];
107         timer_writel(1<<30, base + TIMER_PCR);
108         return IRQ_HANDLED;
109 }
110
111 #define LP2_TIMER_IRQ_ACTION(cpu, irqnum) {                     \
112         .name           = "tmr_lp2wake_cpu" __stringify(cpu),   \
113         .flags          = IRQF_DISABLED,                        \
114         .handler        = tegra_lp2wake_interrupt,              \
115         .dev_id         = (void*)cpu,                           \
116         .irq            = irqnum }
117
118 static struct irqaction tegra_lp2wake_irq[] = {
119         LP2_TIMER_IRQ_ACTION(0, INT_TMR3),
120 #ifdef CONFIG_SMP
121         LP2_TIMER_IRQ_ACTION(1, INT_TMR4),
122         LP2_TIMER_IRQ_ACTION(2, INT_TMR5),
123         LP2_TIMER_IRQ_ACTION(3, INT_TMR6),
124 #endif
125 };
126
127 /*
128  * To sanity test LP2 timer interrupts for CPU 0-3, enable this flag and check
129  * /proc/interrupts for timer interrupts. CPUs 0-3 should have one interrupt
130  * counted against them for tmr_lp2wake_cpu<n>, where <n> is the CPU number.
131  */
132 #if TEST_LP2_WAKE_TIMERS
133 static void test_lp2_wake_timer(unsigned int cpu)
134 {
135         unsigned long cycles = 50000;
136         unsigned int base = lp2_wake_timers[cpu];
137         static bool tested[4] = {false, false, false, false};
138
139         /* Don't repeat the test process on hotplug restart. */
140         if (!tested[cpu]) {
141                 timer_writel(0, base + TIMER_PTV);
142                 if (cycles) {
143                         u32 reg = 0x80000000ul | min(0x1ffffffful, cycles);
144                         timer_writel(reg, base + TIMER_PTV);
145                         tested[cpu] = true;
146                 }
147         }
148 }
149 #else
150 static inline void test_lp2_wake_timer(unsigned int cpu) {}
151 #endif
152
153 static int tegra3_resume_wake_timer(unsigned int cpu)
154 {
155 #ifdef CONFIG_SMP
156         int ret = irq_set_affinity(tegra_lp2wake_irq[cpu].irq, cpumask_of(cpu));
157         if (ret) {
158                 pr_err("Failed to set affinity for LP2 timer IRQ to "
159                         "CPU %d: irq=%d, ret=%d\n", cpu,
160                         tegra_lp2wake_irq[cpu].irq, ret);
161                 return ret;
162         }
163 #endif
164         cpumask_set_cpu(cpu, &wake_timer_ready);
165         return 0;
166 }
167
168 static void tegra3_register_wake_timer(unsigned int cpu)
169 {
170         int ret;
171
172         ret = setup_irq(tegra_lp2wake_irq[cpu].irq, &tegra_lp2wake_irq[cpu]);
173         if (ret) {
174                 pr_err("Failed to register LP2 timer IRQ for CPU %d: "
175                         "irq=%d, ret=%d\n", cpu,
176                         tegra_lp2wake_irq[cpu].irq, ret);
177                 goto fail;
178         }
179
180         ret = tegra3_resume_wake_timer(cpu);
181         if (ret)
182                 goto fail;
183
184         test_lp2_wake_timer(cpu);
185         return;
186 fail:
187         tegra_lp2_in_idle(false);
188 }
189
190 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_HOTPLUG_CPU)
191 static void tegra3_suspend_wake_timer(unsigned int cpu)
192 {
193         cpumask_clear_cpu(cpu, &wake_timer_ready);
194 #ifdef CONFIG_SMP
195         /* Reassign the affinity of the wake IRQ to any ready CPU. */
196         for_each_cpu_not(cpu, &wake_timer_ready)
197         {
198                 (void)irq_set_affinity(tegra_lp2wake_irq[cpu].irq,
199                         cpumask_of(cpumask_any(&wake_timer_ready)));
200         }
201 #endif
202 }
203
204 static void tegra3_unregister_wake_timer(unsigned int cpu)
205 {
206         tegra3_suspend_wake_timer(cpu);
207
208         /* Dispose of this IRQ. */
209         remove_irq(tegra_lp2wake_irq[cpu].irq, &tegra_lp2wake_irq[cpu]);
210 }
211 #endif
212
213 void tegra3_lp2_set_trigger(unsigned long cycles)
214 {
215         int cpu = cpu_logical_map(smp_processor_id());
216         int base;
217
218         base = lp2_wake_timers[cpu];
219         timer_writel(0, base + TIMER_PTV);
220         if (cycles) {
221                 u32 reg = 0x80000000ul | min(0x1ffffffful, cycles);
222                 timer_writel(reg, base + TIMER_PTV);
223         }
224 }
225 EXPORT_SYMBOL(tegra3_lp2_set_trigger);
226
227 unsigned long tegra3_lp2_timer_remain(void)
228 {
229         int cpu = cpu_logical_map(smp_processor_id());
230
231         if (cpumask_test_and_clear_cpu(cpu, &wake_timer_canceled))
232                 return -ETIME;
233
234         return timer_readl(lp2_wake_timers[cpu] + TIMER_PCR) & 0x1ffffffful;
235 }
236
237 int tegra3_is_lp2_timer_ready(unsigned int cpu)
238 {
239         return cpumask_test_cpu(cpu, &wake_timer_ready);
240 }
241
242 void tegra3_lp2_timer_cancel_secondary(void)
243 {
244         int cpu;
245         int base;
246
247         for (cpu = 1; cpu < ARRAY_SIZE(lp2_wake_timers); cpu++) {
248                 base = lp2_wake_timers[cpu];
249                 cpumask_set_cpu(cpu, &wake_timer_canceled);
250                 timer_writel(0, base + TIMER_PTV);
251                 timer_writel(1<<30, base + TIMER_PCR);
252         }
253 }
254 #endif
255
256 void __init tegra30_init_timer(void)
257 {
258 #ifdef CONFIG_PM_SLEEP
259 #ifdef CONFIG_SMP
260         /* For T30.A01 use INT_TMR_SHARED instead of INT_TMR6 for CPU3. */
261         if ((tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) &&
262                 (tegra_revision == TEGRA_REVISION_A01))
263                         tegra_lp2wake_irq[3].irq = INT_TMR_SHARED;
264 #endif
265
266         tegra3_register_wake_timer(0);
267 #endif
268 }
269
270 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_HOTPLUG_CPU)
271 static int hotplug_notify(struct notifier_block *self,
272                                       unsigned long action, void *cpu)
273 {
274         switch (action) {
275         case CPU_ONLINE:
276                 tegra3_register_wake_timer((unsigned int)cpu);
277                 break;
278         case CPU_ONLINE_FROZEN:
279                 tegra3_resume_wake_timer((unsigned int)cpu);
280                 break;
281         case CPU_DOWN_PREPARE:
282                 tegra3_unregister_wake_timer((unsigned int)cpu);
283                 break;
284         case CPU_DOWN_PREPARE_FROZEN:
285                 tegra3_suspend_wake_timer((unsigned int)cpu);
286                 break;
287         default:
288                 break;
289         }
290
291         return NOTIFY_OK;
292 }
293
294 static struct notifier_block __cpuinitdata hotplug_notifier_block = {
295         .notifier_call = hotplug_notify,
296 };
297
298 static int __init hotplug_cpu_register(void)
299 {
300         return register_cpu_notifier(&hotplug_notifier_block);
301 }
302 early_initcall(hotplug_cpu_register);
303 #endif