diff options
author | Mattias Wallin <mattias.wallin@stericsson.com> | 2011-05-27 04:30:12 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2011-09-22 09:42:57 -0400 |
commit | 489bccea6334514a8e13436f10d0a274777bf17a (patch) | |
tree | 16ef60894e87bc95e1e44e975667325bb46f6679 /drivers/clocksource | |
parent | cba13830d3fcb1e025e224c496a10515a39a7f80 (diff) |
clocksource: add DBX500 PRCMU Timer support
This patch adds the DBX500 PRCMU Timer driver as a clocksource
and as sched_clock.
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Mattias Wallin <mattias.wallin@stericsson.com>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/Kconfig | 15 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
-rw-r--r-- | drivers/clocksource/clksrc-dbx500-prcmu.c | 104 |
3 files changed, 120 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 34e9c4f88926..999d6a03e436 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -15,3 +15,18 @@ config CLKSRC_MMIO | |||
15 | 15 | ||
16 | config DW_APB_TIMER | 16 | config DW_APB_TIMER |
17 | bool | 17 | bool |
18 | |||
19 | config CLKSRC_DBX500_PRCMU | ||
20 | bool "Clocksource PRCMU Timer" | ||
21 | depends on UX500_SOC_DB5500 || UX500_SOC_DB8500 | ||
22 | default y | ||
23 | help | ||
24 | Use the always on PRCMU Timer as clocksource | ||
25 | |||
26 | config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | ||
27 | bool "Clocksource PRCMU Timer sched_clock" | ||
28 | depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK) | ||
29 | select HAVE_SCHED_CLOCK | ||
30 | default y | ||
31 | help | ||
32 | Use the always on PRCMU Timer as sched_clock | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 85ad1646a7b7..8d81a1d32653 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -9,3 +9,4 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o | |||
9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o | 9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o |
10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o | 10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o |
11 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | 11 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o |
12 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o \ No newline at end of file | ||
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c new file mode 100644 index 000000000000..0ac5093a053a --- /dev/null +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2011 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson | ||
6 | * Author: Sundar Iyer for ST-Ericsson | ||
7 | * sched_clock implementation is based on: | ||
8 | * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com> | ||
9 | * | ||
10 | * DBx500-PRCMU Timer | ||
11 | * The PRCMU has 5 timers which are available in a always-on | ||
12 | * power domain. We use the Timer 4 for our always-on clock | ||
13 | * source on DB8500 and Timer 3 on DB5500. | ||
14 | */ | ||
15 | #include <linux/clockchips.h> | ||
16 | #include <linux/clksrc-dbx500-prcmu.h> | ||
17 | |||
18 | #include <asm/sched_clock.h> | ||
19 | |||
20 | #include <mach/setup.h> | ||
21 | #include <mach/hardware.h> | ||
22 | |||
23 | #define RATE_32K 32768 | ||
24 | |||
25 | #define TIMER_MODE_CONTINOUS 0x1 | ||
26 | #define TIMER_DOWNCOUNT_VAL 0xffffffff | ||
27 | |||
28 | #define PRCMU_TIMER_REF 0 | ||
29 | #define PRCMU_TIMER_DOWNCOUNT 0x4 | ||
30 | #define PRCMU_TIMER_MODE 0x8 | ||
31 | |||
32 | #define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */ | ||
33 | |||
34 | void __iomem *clksrc_dbx500_timer_base; | ||
35 | |||
36 | static cycle_t clksrc_dbx500_prcmu_read(struct clocksource *cs) | ||
37 | { | ||
38 | u32 count, count2; | ||
39 | |||
40 | do { | ||
41 | count = readl(clksrc_dbx500_timer_base + | ||
42 | PRCMU_TIMER_DOWNCOUNT); | ||
43 | count2 = readl(clksrc_dbx500_timer_base + | ||
44 | PRCMU_TIMER_DOWNCOUNT); | ||
45 | } while (count2 != count); | ||
46 | |||
47 | /* Negate because the timer is a decrementing counter */ | ||
48 | return ~count; | ||
49 | } | ||
50 | |||
51 | static struct clocksource clocksource_dbx500_prcmu = { | ||
52 | .name = "dbx500-prcmu-timer", | ||
53 | .rating = 300, | ||
54 | .read = clksrc_dbx500_prcmu_read, | ||
55 | .shift = 10, | ||
56 | .mask = CLOCKSOURCE_MASK(32), | ||
57 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
58 | }; | ||
59 | |||
60 | #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK | ||
61 | static DEFINE_CLOCK_DATA(cd); | ||
62 | |||
63 | unsigned long long notrace sched_clock(void) | ||
64 | { | ||
65 | u32 cyc; | ||
66 | |||
67 | if (unlikely(!clksrc_dbx500_timer_base)) | ||
68 | return 0; | ||
69 | |||
70 | cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu); | ||
71 | |||
72 | return cyc_to_sched_clock(&cd, cyc, (u32)~0); | ||
73 | } | ||
74 | |||
75 | static void notrace clksrc_dbx500_prcmu_update_sched_clock(void) | ||
76 | { | ||
77 | u32 cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu); | ||
78 | update_sched_clock(&cd, cyc, (u32)~0); | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | void __init clksrc_dbx500_prcmu_init(void) | ||
83 | { | ||
84 | /* | ||
85 | * The A9 sub system expects the timer to be configured as | ||
86 | * a continous looping timer. | ||
87 | * The PRCMU should configure it but if it for some reason | ||
88 | * don't we do it here. | ||
89 | */ | ||
90 | if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) != | ||
91 | TIMER_MODE_CONTINOUS) { | ||
92 | writel(TIMER_MODE_CONTINOUS, | ||
93 | clksrc_dbx500_timer_base + PRCMU_TIMER_MODE); | ||
94 | writel(TIMER_DOWNCOUNT_VAL, | ||
95 | clksrc_dbx500_timer_base + PRCMU_TIMER_REF); | ||
96 | } | ||
97 | #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK | ||
98 | init_sched_clock(&cd, clksrc_dbx500_prcmu_update_sched_clock, | ||
99 | 32, RATE_32K); | ||
100 | #endif | ||
101 | clocksource_calc_mult_shift(&clocksource_dbx500_prcmu, | ||
102 | RATE_32K, SCHED_CLOCK_MIN_WRAP); | ||
103 | clocksource_register(&clocksource_dbx500_prcmu); | ||
104 | } | ||