diff options
-rw-r--r-- | arch/arm/include/asm/arch_timer.h | 36 | ||||
-rw-r--r-- | arch/arm/include/uapi/asm/hwcap.h | 1 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 1 | ||||
-rw-r--r-- | arch/arm64/include/asm/arch_timer.h | 42 | ||||
-rw-r--r-- | arch/arm64/include/asm/hwcap.h | 11 | ||||
-rw-r--r-- | arch/arm64/include/uapi/asm/hwcap.h | 1 | ||||
-rw-r--r-- | arch/arm64/kernel/setup.c | 11 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 15 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 49 | ||||
-rw-r--r-- | drivers/clocksource/tcb_clksrc.c | 61 | ||||
-rw-r--r-- | include/clocksource/arm_arch_timer.h | 10 |
11 files changed, 211 insertions, 27 deletions
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 5665134bfa3e..0704e0cf5571 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h | |||
@@ -87,17 +87,43 @@ static inline u64 arch_counter_get_cntvct(void) | |||
87 | return cval; | 87 | return cval; |
88 | } | 88 | } |
89 | 89 | ||
90 | static inline void arch_counter_set_user_access(void) | 90 | static inline u32 arch_timer_get_cntkctl(void) |
91 | { | 91 | { |
92 | u32 cntkctl; | 92 | u32 cntkctl; |
93 | |||
94 | asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); | 93 | asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); |
94 | return cntkctl; | ||
95 | } | ||
95 | 96 | ||
96 | /* disable user access to everything */ | 97 | static inline void arch_timer_set_cntkctl(u32 cntkctl) |
97 | cntkctl &= ~((3 << 8) | (7 << 0)); | 98 | { |
98 | |||
99 | asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); | 99 | asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); |
100 | } | 100 | } |
101 | |||
102 | static inline void arch_counter_set_user_access(void) | ||
103 | { | ||
104 | u32 cntkctl = arch_timer_get_cntkctl(); | ||
105 | |||
106 | /* Disable user access to both physical/virtual counters/timers */ | ||
107 | /* Also disable virtual event stream */ | ||
108 | cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN | ||
109 | | ARCH_TIMER_USR_VT_ACCESS_EN | ||
110 | | ARCH_TIMER_VIRT_EVT_EN | ||
111 | | ARCH_TIMER_USR_VCT_ACCESS_EN | ||
112 | | ARCH_TIMER_USR_PCT_ACCESS_EN); | ||
113 | arch_timer_set_cntkctl(cntkctl); | ||
114 | } | ||
115 | |||
116 | static inline void arch_timer_evtstrm_enable(int divider) | ||
117 | { | ||
118 | u32 cntkctl = arch_timer_get_cntkctl(); | ||
119 | cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; | ||
120 | /* Set the divider and enable virtual event stream */ | ||
121 | cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) | ||
122 | | ARCH_TIMER_VIRT_EVT_EN; | ||
123 | arch_timer_set_cntkctl(cntkctl); | ||
124 | elf_hwcap |= HWCAP_EVTSTRM; | ||
125 | } | ||
126 | |||
101 | #endif | 127 | #endif |
102 | 128 | ||
103 | #endif | 129 | #endif |
diff --git a/arch/arm/include/uapi/asm/hwcap.h b/arch/arm/include/uapi/asm/hwcap.h index 6d34d080372a..7dcc10d67253 100644 --- a/arch/arm/include/uapi/asm/hwcap.h +++ b/arch/arm/include/uapi/asm/hwcap.h | |||
@@ -26,5 +26,6 @@ | |||
26 | #define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ | 26 | #define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ |
27 | #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) | 27 | #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) |
28 | #define HWCAP_LPAE (1 << 20) | 28 | #define HWCAP_LPAE (1 << 20) |
29 | #define HWCAP_EVTSTRM (1 << 21) | ||
29 | 30 | ||
30 | #endif /* _UAPI__ASMARM_HWCAP_H */ | 31 | #endif /* _UAPI__ASMARM_HWCAP_H */ |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0e1e2b3afa45..5d65438685d8 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -975,6 +975,7 @@ static const char *hwcap_str[] = { | |||
975 | "idivt", | 975 | "idivt", |
976 | "vfpd32", | 976 | "vfpd32", |
977 | "lpae", | 977 | "lpae", |
978 | "evtstrm", | ||
978 | NULL | 979 | NULL |
979 | }; | 980 | }; |
980 | 981 | ||
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index c9f1d2816c2b..9400596a0f39 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h | |||
@@ -92,19 +92,49 @@ static inline u32 arch_timer_get_cntfrq(void) | |||
92 | return val; | 92 | return val; |
93 | } | 93 | } |
94 | 94 | ||
95 | static inline void arch_counter_set_user_access(void) | 95 | static inline u32 arch_timer_get_cntkctl(void) |
96 | { | 96 | { |
97 | u32 cntkctl; | 97 | u32 cntkctl; |
98 | |||
99 | /* Disable user access to the timers and the physical counter. */ | ||
100 | asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl)); | 98 | asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl)); |
101 | cntkctl &= ~((3 << 8) | (1 << 0)); | 99 | return cntkctl; |
100 | } | ||
102 | 101 | ||
103 | /* Enable user access to the virtual counter and frequency. */ | 102 | static inline void arch_timer_set_cntkctl(u32 cntkctl) |
104 | cntkctl |= (1 << 1); | 103 | { |
105 | asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); | 104 | asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); |
106 | } | 105 | } |
107 | 106 | ||
107 | static inline void arch_counter_set_user_access(void) | ||
108 | { | ||
109 | u32 cntkctl = arch_timer_get_cntkctl(); | ||
110 | |||
111 | /* Disable user access to the timers and the physical counter */ | ||
112 | /* Also disable virtual event stream */ | ||
113 | cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN | ||
114 | | ARCH_TIMER_USR_VT_ACCESS_EN | ||
115 | | ARCH_TIMER_VIRT_EVT_EN | ||
116 | | ARCH_TIMER_USR_PCT_ACCESS_EN); | ||
117 | |||
118 | /* Enable user access to the virtual counter */ | ||
119 | cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; | ||
120 | |||
121 | arch_timer_set_cntkctl(cntkctl); | ||
122 | } | ||
123 | |||
124 | static inline void arch_timer_evtstrm_enable(int divider) | ||
125 | { | ||
126 | u32 cntkctl = arch_timer_get_cntkctl(); | ||
127 | cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; | ||
128 | /* Set the divider and enable virtual event stream */ | ||
129 | cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) | ||
130 | | ARCH_TIMER_VIRT_EVT_EN; | ||
131 | arch_timer_set_cntkctl(cntkctl); | ||
132 | elf_hwcap |= HWCAP_EVTSTRM; | ||
133 | #ifdef CONFIG_COMPAT | ||
134 | compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; | ||
135 | #endif | ||
136 | } | ||
137 | |||
108 | static inline u64 arch_counter_get_cntvct(void) | 138 | static inline u64 arch_counter_get_cntvct(void) |
109 | { | 139 | { |
110 | u64 cval; | 140 | u64 cval; |
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h index e2950b098e76..6cddbb0c9f54 100644 --- a/arch/arm64/include/asm/hwcap.h +++ b/arch/arm64/include/asm/hwcap.h | |||
@@ -30,6 +30,7 @@ | |||
30 | #define COMPAT_HWCAP_IDIVA (1 << 17) | 30 | #define COMPAT_HWCAP_IDIVA (1 << 17) |
31 | #define COMPAT_HWCAP_IDIVT (1 << 18) | 31 | #define COMPAT_HWCAP_IDIVT (1 << 18) |
32 | #define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT) | 32 | #define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT) |
33 | #define COMPAT_HWCAP_EVTSTRM (1 << 21) | ||
33 | 34 | ||
34 | #ifndef __ASSEMBLY__ | 35 | #ifndef __ASSEMBLY__ |
35 | /* | 36 | /* |
@@ -37,11 +38,11 @@ | |||
37 | * instruction set this cpu supports. | 38 | * instruction set this cpu supports. |
38 | */ | 39 | */ |
39 | #define ELF_HWCAP (elf_hwcap) | 40 | #define ELF_HWCAP (elf_hwcap) |
40 | #define COMPAT_ELF_HWCAP (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ | 41 | |
41 | COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ | 42 | #ifdef CONFIG_COMPAT |
42 | COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ | 43 | #define COMPAT_ELF_HWCAP (compat_elf_hwcap) |
43 | COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ | 44 | extern unsigned int compat_elf_hwcap; |
44 | COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV) | 45 | #endif |
45 | 46 | ||
46 | extern unsigned long elf_hwcap; | 47 | extern unsigned long elf_hwcap; |
47 | #endif | 48 | #endif |
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h index eea497578b87..9b12476e9c85 100644 --- a/arch/arm64/include/uapi/asm/hwcap.h +++ b/arch/arm64/include/uapi/asm/hwcap.h | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | #define HWCAP_FP (1 << 0) | 22 | #define HWCAP_FP (1 << 0) |
23 | #define HWCAP_ASIMD (1 << 1) | 23 | #define HWCAP_ASIMD (1 << 1) |
24 | #define HWCAP_EVTSTRM (1 << 2) | ||
24 | 25 | ||
25 | 26 | ||
26 | #endif /* _UAPI__ASM_HWCAP_H */ | 27 | #endif /* _UAPI__ASM_HWCAP_H */ |
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 055cfb80e05c..d355b7b9710b 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c | |||
@@ -60,6 +60,16 @@ EXPORT_SYMBOL(processor_id); | |||
60 | unsigned long elf_hwcap __read_mostly; | 60 | unsigned long elf_hwcap __read_mostly; |
61 | EXPORT_SYMBOL_GPL(elf_hwcap); | 61 | EXPORT_SYMBOL_GPL(elf_hwcap); |
62 | 62 | ||
63 | #ifdef CONFIG_COMPAT | ||
64 | #define COMPAT_ELF_HWCAP_DEFAULT \ | ||
65 | (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ | ||
66 | COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ | ||
67 | COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ | ||
68 | COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ | ||
69 | COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV) | ||
70 | unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; | ||
71 | #endif | ||
72 | |||
63 | static const char *cpu_name; | 73 | static const char *cpu_name; |
64 | static const char *machine_name; | 74 | static const char *machine_name; |
65 | phys_addr_t __fdt_pointer __initdata; | 75 | phys_addr_t __fdt_pointer __initdata; |
@@ -304,6 +314,7 @@ subsys_initcall(topology_init); | |||
304 | static const char *hwcap_str[] = { | 314 | static const char *hwcap_str[] = { |
305 | "fp", | 315 | "fp", |
306 | "asimd", | 316 | "asimd", |
317 | "evtstrm", | ||
307 | NULL | 318 | NULL |
308 | }; | 319 | }; |
309 | 320 | ||
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 971d796e071d..5e940f839a2d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -75,6 +75,21 @@ config ARM_ARCH_TIMER | |||
75 | bool | 75 | bool |
76 | select CLKSRC_OF if OF | 76 | select CLKSRC_OF if OF |
77 | 77 | ||
78 | config ARM_ARCH_TIMER_EVTSTREAM | ||
79 | bool "Support for ARM architected timer event stream generation" | ||
80 | default y if ARM_ARCH_TIMER | ||
81 | help | ||
82 | This option enables support for event stream generation based on | ||
83 | the ARM architected timer. It is used for waking up CPUs executing | ||
84 | the wfe instruction at a frequency represented as a power-of-2 | ||
85 | divisor of the clock rate. | ||
86 | The main use of the event stream is wfe-based timeouts of userspace | ||
87 | locking implementations. It might also be useful for imposing timeout | ||
88 | on wfe to safeguard against any programming errors in case an expected | ||
89 | event is not generated. | ||
90 | This must be disabled for hardware validation purposes to detect any | ||
91 | hardware anomalies of missing events. | ||
92 | |||
78 | config ARM_GLOBAL_TIMER | 93 | config ARM_GLOBAL_TIMER |
79 | bool | 94 | bool |
80 | select CLKSRC_OF if OF | 95 | select CLKSRC_OF if OF |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index ce98d5e70927..b94b0d44c158 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
15 | #include <linux/cpu.h> | 15 | #include <linux/cpu.h> |
16 | #include <linux/cpu_pm.h> | ||
16 | #include <linux/clockchips.h> | 17 | #include <linux/clockchips.h> |
17 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
18 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
@@ -294,6 +295,19 @@ static void __arch_timer_setup(unsigned type, | |||
294 | clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); | 295 | clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); |
295 | } | 296 | } |
296 | 297 | ||
298 | static void arch_timer_configure_evtstream(void) | ||
299 | { | ||
300 | int evt_stream_div, pos; | ||
301 | |||
302 | /* Find the closest power of two to the divisor */ | ||
303 | evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ; | ||
304 | pos = fls(evt_stream_div); | ||
305 | if (pos > 1 && !(evt_stream_div & (1 << (pos - 2)))) | ||
306 | pos--; | ||
307 | /* enable event stream */ | ||
308 | arch_timer_evtstrm_enable(min(pos, 15)); | ||
309 | } | ||
310 | |||
297 | static int arch_timer_setup(struct clock_event_device *clk) | 311 | static int arch_timer_setup(struct clock_event_device *clk) |
298 | { | 312 | { |
299 | __arch_timer_setup(ARCH_CP15_TIMER, clk); | 313 | __arch_timer_setup(ARCH_CP15_TIMER, clk); |
@@ -307,6 +321,8 @@ static int arch_timer_setup(struct clock_event_device *clk) | |||
307 | } | 321 | } |
308 | 322 | ||
309 | arch_counter_set_user_access(); | 323 | arch_counter_set_user_access(); |
324 | if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) | ||
325 | arch_timer_configure_evtstream(); | ||
310 | 326 | ||
311 | return 0; | 327 | return 0; |
312 | } | 328 | } |
@@ -460,6 +476,33 @@ static struct notifier_block arch_timer_cpu_nb = { | |||
460 | .notifier_call = arch_timer_cpu_notify, | 476 | .notifier_call = arch_timer_cpu_notify, |
461 | }; | 477 | }; |
462 | 478 | ||
479 | #ifdef CONFIG_CPU_PM | ||
480 | static unsigned int saved_cntkctl; | ||
481 | static int arch_timer_cpu_pm_notify(struct notifier_block *self, | ||
482 | unsigned long action, void *hcpu) | ||
483 | { | ||
484 | if (action == CPU_PM_ENTER) | ||
485 | saved_cntkctl = arch_timer_get_cntkctl(); | ||
486 | else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) | ||
487 | arch_timer_set_cntkctl(saved_cntkctl); | ||
488 | return NOTIFY_OK; | ||
489 | } | ||
490 | |||
491 | static struct notifier_block arch_timer_cpu_pm_notifier = { | ||
492 | .notifier_call = arch_timer_cpu_pm_notify, | ||
493 | }; | ||
494 | |||
495 | static int __init arch_timer_cpu_pm_init(void) | ||
496 | { | ||
497 | return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier); | ||
498 | } | ||
499 | #else | ||
500 | static int __init arch_timer_cpu_pm_init(void) | ||
501 | { | ||
502 | return 0; | ||
503 | } | ||
504 | #endif | ||
505 | |||
463 | static int __init arch_timer_register(void) | 506 | static int __init arch_timer_register(void) |
464 | { | 507 | { |
465 | int err; | 508 | int err; |
@@ -499,11 +542,17 @@ static int __init arch_timer_register(void) | |||
499 | if (err) | 542 | if (err) |
500 | goto out_free_irq; | 543 | goto out_free_irq; |
501 | 544 | ||
545 | err = arch_timer_cpu_pm_init(); | ||
546 | if (err) | ||
547 | goto out_unreg_notify; | ||
548 | |||
502 | /* Immediately configure the timer on the boot CPU */ | 549 | /* Immediately configure the timer on the boot CPU */ |
503 | arch_timer_setup(this_cpu_ptr(arch_timer_evt)); | 550 | arch_timer_setup(this_cpu_ptr(arch_timer_evt)); |
504 | 551 | ||
505 | return 0; | 552 | return 0; |
506 | 553 | ||
554 | out_unreg_notify: | ||
555 | unregister_cpu_notifier(&arch_timer_cpu_nb); | ||
507 | out_free_irq: | 556 | out_free_irq: |
508 | if (arch_timer_use_virtual) | 557 | if (arch_timer_use_virtual) |
509 | free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); | 558 | free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); |
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 8a6187225dd0..00fdd1170284 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c | |||
@@ -100,7 +100,7 @@ static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) | |||
100 | || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { | 100 | || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { |
101 | __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); | 101 | __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); |
102 | __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); | 102 | __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); |
103 | clk_disable(tcd->clk); | 103 | clk_disable_unprepare(tcd->clk); |
104 | } | 104 | } |
105 | 105 | ||
106 | switch (m) { | 106 | switch (m) { |
@@ -109,7 +109,7 @@ static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) | |||
109 | * of oneshot, we get lower overhead and improved accuracy. | 109 | * of oneshot, we get lower overhead and improved accuracy. |
110 | */ | 110 | */ |
111 | case CLOCK_EVT_MODE_PERIODIC: | 111 | case CLOCK_EVT_MODE_PERIODIC: |
112 | clk_enable(tcd->clk); | 112 | clk_prepare_enable(tcd->clk); |
113 | 113 | ||
114 | /* slow clock, count up to RC, then irq and restart */ | 114 | /* slow clock, count up to RC, then irq and restart */ |
115 | __raw_writel(timer_clock | 115 | __raw_writel(timer_clock |
@@ -126,7 +126,7 @@ static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) | |||
126 | break; | 126 | break; |
127 | 127 | ||
128 | case CLOCK_EVT_MODE_ONESHOT: | 128 | case CLOCK_EVT_MODE_ONESHOT: |
129 | clk_enable(tcd->clk); | 129 | clk_prepare_enable(tcd->clk); |
130 | 130 | ||
131 | /* slow clock, count up to RC, then irq and stop */ | 131 | /* slow clock, count up to RC, then irq and stop */ |
132 | __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | 132 | __raw_writel(timer_clock | ATMEL_TC_CPCSTOP |
@@ -180,15 +180,22 @@ static irqreturn_t ch2_irq(int irq, void *handle) | |||
180 | 180 | ||
181 | static struct irqaction tc_irqaction = { | 181 | static struct irqaction tc_irqaction = { |
182 | .name = "tc_clkevt", | 182 | .name = "tc_clkevt", |
183 | .flags = IRQF_TIMER | IRQF_DISABLED, | 183 | .flags = IRQF_TIMER, |
184 | .handler = ch2_irq, | 184 | .handler = ch2_irq, |
185 | }; | 185 | }; |
186 | 186 | ||
187 | static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) | 187 | static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) |
188 | { | 188 | { |
189 | int ret; | ||
189 | struct clk *t2_clk = tc->clk[2]; | 190 | struct clk *t2_clk = tc->clk[2]; |
190 | int irq = tc->irq[2]; | 191 | int irq = tc->irq[2]; |
191 | 192 | ||
193 | /* try to enable t2 clk to avoid future errors in mode change */ | ||
194 | ret = clk_prepare_enable(t2_clk); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | clk_disable_unprepare(t2_clk); | ||
198 | |||
192 | clkevt.regs = tc->regs; | 199 | clkevt.regs = tc->regs; |
193 | clkevt.clk = t2_clk; | 200 | clkevt.clk = t2_clk; |
194 | tc_irqaction.dev_id = &clkevt; | 201 | tc_irqaction.dev_id = &clkevt; |
@@ -197,16 +204,21 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) | |||
197 | 204 | ||
198 | clkevt.clkevt.cpumask = cpumask_of(0); | 205 | clkevt.clkevt.cpumask = cpumask_of(0); |
199 | 206 | ||
207 | ret = setup_irq(irq, &tc_irqaction); | ||
208 | if (ret) | ||
209 | return ret; | ||
210 | |||
200 | clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); | 211 | clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); |
201 | 212 | ||
202 | setup_irq(irq, &tc_irqaction); | 213 | return ret; |
203 | } | 214 | } |
204 | 215 | ||
205 | #else /* !CONFIG_GENERIC_CLOCKEVENTS */ | 216 | #else /* !CONFIG_GENERIC_CLOCKEVENTS */ |
206 | 217 | ||
207 | static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) | 218 | static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) |
208 | { | 219 | { |
209 | /* NOTHING */ | 220 | /* NOTHING */ |
221 | return 0; | ||
210 | } | 222 | } |
211 | 223 | ||
212 | #endif | 224 | #endif |
@@ -265,6 +277,7 @@ static int __init tcb_clksrc_init(void) | |||
265 | int best_divisor_idx = -1; | 277 | int best_divisor_idx = -1; |
266 | int clk32k_divisor_idx = -1; | 278 | int clk32k_divisor_idx = -1; |
267 | int i; | 279 | int i; |
280 | int ret; | ||
268 | 281 | ||
269 | tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name); | 282 | tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name); |
270 | if (!tc) { | 283 | if (!tc) { |
@@ -275,7 +288,11 @@ static int __init tcb_clksrc_init(void) | |||
275 | pdev = tc->pdev; | 288 | pdev = tc->pdev; |
276 | 289 | ||
277 | t0_clk = tc->clk[0]; | 290 | t0_clk = tc->clk[0]; |
278 | clk_enable(t0_clk); | 291 | ret = clk_prepare_enable(t0_clk); |
292 | if (ret) { | ||
293 | pr_debug("can't enable T0 clk\n"); | ||
294 | goto err_free_tc; | ||
295 | } | ||
279 | 296 | ||
280 | /* How fast will we be counting? Pick something over 5 MHz. */ | 297 | /* How fast will we be counting? Pick something over 5 MHz. */ |
281 | rate = (u32) clk_get_rate(t0_clk); | 298 | rate = (u32) clk_get_rate(t0_clk); |
@@ -313,17 +330,39 @@ static int __init tcb_clksrc_init(void) | |||
313 | /* tclib will give us three clocks no matter what the | 330 | /* tclib will give us three clocks no matter what the |
314 | * underlying platform supports. | 331 | * underlying platform supports. |
315 | */ | 332 | */ |
316 | clk_enable(tc->clk[1]); | 333 | ret = clk_prepare_enable(tc->clk[1]); |
334 | if (ret) { | ||
335 | pr_debug("can't enable T1 clk\n"); | ||
336 | goto err_disable_t0; | ||
337 | } | ||
317 | /* setup both channel 0 & 1 */ | 338 | /* setup both channel 0 & 1 */ |
318 | tcb_setup_dual_chan(tc, best_divisor_idx); | 339 | tcb_setup_dual_chan(tc, best_divisor_idx); |
319 | } | 340 | } |
320 | 341 | ||
321 | /* and away we go! */ | 342 | /* and away we go! */ |
322 | clocksource_register_hz(&clksrc, divided_rate); | 343 | ret = clocksource_register_hz(&clksrc, divided_rate); |
344 | if (ret) | ||
345 | goto err_disable_t1; | ||
323 | 346 | ||
324 | /* channel 2: periodic and oneshot timer support */ | 347 | /* channel 2: periodic and oneshot timer support */ |
325 | setup_clkevents(tc, clk32k_divisor_idx); | 348 | ret = setup_clkevents(tc, clk32k_divisor_idx); |
349 | if (ret) | ||
350 | goto err_unregister_clksrc; | ||
326 | 351 | ||
327 | return 0; | 352 | return 0; |
353 | |||
354 | err_unregister_clksrc: | ||
355 | clocksource_unregister(&clksrc); | ||
356 | |||
357 | err_disable_t1: | ||
358 | if (!tc->tcb_config || tc->tcb_config->counter_width != 32) | ||
359 | clk_disable_unprepare(tc->clk[1]); | ||
360 | |||
361 | err_disable_t0: | ||
362 | clk_disable_unprepare(t0_clk); | ||
363 | |||
364 | err_free_tc: | ||
365 | atmel_tc_free(tc); | ||
366 | return ret; | ||
328 | } | 367 | } |
329 | arch_initcall(tcb_clksrc_init); | 368 | arch_initcall(tcb_clksrc_init); |
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 93b7f96f9c59..6d26b40cbf5d 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h | |||
@@ -33,6 +33,16 @@ enum arch_timer_reg { | |||
33 | #define ARCH_TIMER_MEM_PHYS_ACCESS 2 | 33 | #define ARCH_TIMER_MEM_PHYS_ACCESS 2 |
34 | #define ARCH_TIMER_MEM_VIRT_ACCESS 3 | 34 | #define ARCH_TIMER_MEM_VIRT_ACCESS 3 |
35 | 35 | ||
36 | #define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */ | ||
37 | #define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */ | ||
38 | #define ARCH_TIMER_VIRT_EVT_EN (1 << 2) | ||
39 | #define ARCH_TIMER_EVT_TRIGGER_SHIFT (4) | ||
40 | #define ARCH_TIMER_EVT_TRIGGER_MASK (0xF << ARCH_TIMER_EVT_TRIGGER_SHIFT) | ||
41 | #define ARCH_TIMER_USR_VT_ACCESS_EN (1 << 8) /* virtual timer registers */ | ||
42 | #define ARCH_TIMER_USR_PT_ACCESS_EN (1 << 9) /* physical timer registers */ | ||
43 | |||
44 | #define ARCH_TIMER_EVT_STREAM_FREQ 10000 /* 100us */ | ||
45 | |||
36 | #ifdef CONFIG_ARM_ARCH_TIMER | 46 | #ifdef CONFIG_ARM_ARCH_TIMER |
37 | 47 | ||
38 | extern u32 arch_timer_get_rate(void); | 48 | extern u32 arch_timer_get_rate(void); |