aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Kconfig5
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/exynos_mct.c556
3 files changed, 563 insertions, 1 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 3167fda9bbb3..73fcddb8314d 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -70,3 +70,8 @@ config CLKSRC_METAG_GENERIC
70 def_bool y if METAG 70 def_bool y if METAG
71 help 71 help
72 This option enables support for the Meta per-thread timers. 72 This option enables support for the Meta per-thread timers.
73
74config CLKSRC_EXYNOS_MCT
75 def_bool y if ARCH_EXYNOS
76 help
77 Support for Multi Core Timer controller on Exynos SoCs.
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index e74c8ce26bf0..cd1f09cbd61a 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -19,7 +19,8 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
19obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o 19obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
20obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o 20obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
21obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o 21obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
22obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o 22obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
23obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
23 24
24obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o 25obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
25obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o 26obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
new file mode 100644
index 000000000000..957af8636c9d
--- /dev/null
+++ b/drivers/clocksource/exynos_mct.c
@@ -0,0 +1,556 @@
1/* linux/arch/arm/mach-exynos4/mct.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 MCT(Multi-Core Timer) support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#include <linux/sched.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/err.h>
17#include <linux/clk.h>
18#include <linux/clockchips.h>
19#include <linux/platform_device.h>
20#include <linux/delay.h>
21#include <linux/percpu.h>
22#include <linux/of.h>
23#include <linux/of_irq.h>
24#include <linux/of_address.h>
25#include <linux/clocksource.h>
26
27#include <asm/arch_timer.h>
28#include <asm/localtimer.h>
29
30#include <plat/cpu.h>
31
32#include <mach/map.h>
33#include <mach/irqs.h>
34#include <asm/mach/time.h>
35
36#define EXYNOS4_MCTREG(x) (x)
37#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)
38#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)
39#define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110)
40#define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200)
41#define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204)
42#define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208)
43#define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240)
44#define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244)
45#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248)
46#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C)
47#define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300)
48#define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x))
49#define EXYNOS4_MCT_L_MASK (0xffffff00)
50
51#define MCT_L_TCNTB_OFFSET (0x00)
52#define MCT_L_ICNTB_OFFSET (0x08)
53#define MCT_L_TCON_OFFSET (0x20)
54#define MCT_L_INT_CSTAT_OFFSET (0x30)
55#define MCT_L_INT_ENB_OFFSET (0x34)
56#define MCT_L_WSTAT_OFFSET (0x40)
57#define MCT_G_TCON_START (1 << 8)
58#define MCT_G_TCON_COMP0_AUTO_INC (1 << 1)
59#define MCT_G_TCON_COMP0_ENABLE (1 << 0)
60#define MCT_L_TCON_INTERVAL_MODE (1 << 2)
61#define MCT_L_TCON_INT_START (1 << 1)
62#define MCT_L_TCON_TIMER_START (1 << 0)
63
64#define TICK_BASE_CNT 1
65
66enum {
67 MCT_INT_SPI,
68 MCT_INT_PPI
69};
70
71enum {
72 MCT_G0_IRQ,
73 MCT_G1_IRQ,
74 MCT_G2_IRQ,
75 MCT_G3_IRQ,
76 MCT_L0_IRQ,
77 MCT_L1_IRQ,
78 MCT_L2_IRQ,
79 MCT_L3_IRQ,
80 MCT_NR_IRQS,
81};
82
83static void __iomem *reg_base;
84static unsigned long clk_rate;
85static unsigned int mct_int_type;
86static int mct_irqs[MCT_NR_IRQS];
87
88struct mct_clock_event_device {
89 struct clock_event_device *evt;
90 unsigned long base;
91 char name[10];
92};
93
94static void exynos4_mct_write(unsigned int value, unsigned long offset)
95{
96 unsigned long stat_addr;
97 u32 mask;
98 u32 i;
99
100 __raw_writel(value, reg_base + offset);
101
102 if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) {
103 stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET;
104 switch (offset & EXYNOS4_MCT_L_MASK) {
105 case MCT_L_TCON_OFFSET:
106 mask = 1 << 3; /* L_TCON write status */
107 break;
108 case MCT_L_ICNTB_OFFSET:
109 mask = 1 << 1; /* L_ICNTB write status */
110 break;
111 case MCT_L_TCNTB_OFFSET:
112 mask = 1 << 0; /* L_TCNTB write status */
113 break;
114 default:
115 return;
116 }
117 } else {
118 switch (offset) {
119 case EXYNOS4_MCT_G_TCON:
120 stat_addr = EXYNOS4_MCT_G_WSTAT;
121 mask = 1 << 16; /* G_TCON write status */
122 break;
123 case EXYNOS4_MCT_G_COMP0_L:
124 stat_addr = EXYNOS4_MCT_G_WSTAT;
125 mask = 1 << 0; /* G_COMP0_L write status */
126 break;
127 case EXYNOS4_MCT_G_COMP0_U:
128 stat_addr = EXYNOS4_MCT_G_WSTAT;
129 mask = 1 << 1; /* G_COMP0_U write status */
130 break;
131 case EXYNOS4_MCT_G_COMP0_ADD_INCR:
132 stat_addr = EXYNOS4_MCT_G_WSTAT;
133 mask = 1 << 2; /* G_COMP0_ADD_INCR w status */
134 break;
135 case EXYNOS4_MCT_G_CNT_L:
136 stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
137 mask = 1 << 0; /* G_CNT_L write status */
138 break;
139 case EXYNOS4_MCT_G_CNT_U:
140 stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
141 mask = 1 << 1; /* G_CNT_U write status */
142 break;
143 default:
144 return;
145 }
146 }
147
148 /* Wait maximum 1 ms until written values are applied */
149 for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
150 if (__raw_readl(reg_base + stat_addr) & mask) {
151 __raw_writel(mask, reg_base + stat_addr);
152 return;
153 }
154
155 panic("MCT hangs after writing %d (offset:0x%lx)\n", value, offset);
156}
157
158/* Clocksource handling */
159static void exynos4_mct_frc_start(u32 hi, u32 lo)
160{
161 u32 reg;
162
163 exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
164 exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
165
166 reg = __raw_readl(reg_base + EXYNOS4_MC