summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2017-05-18 16:17:04 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2017-06-12 04:45:10 -0400
commitec14ba1ec537d530208c3ba3b3738349d386850f (patch)
tree593311ad6b8eabbf4c89ac9b0ec12b3369da57f9
parentb589da8b26f4b5cc3c3a84183dee33a73871522b (diff)
clocksource/drivers/fttmr010: Merge Moxa into FTTMR010
This merges the Moxa Art timer driver into the Faraday FTTMR010 driver and replaces all Kconfig symbols to use the Faraday driver instead. We are now so similar that the drivers can be merged by just adding a few lines to the Faraday timer. Differences: - The Faraday driver explicitly sets the counter to count upwards for the clocksource, removing the need for the clocksource core to invert the value. - The Faraday driver also handles sched_clock() On the Aspeed, the counter can only count downwards, so support the timers in downward-counting mode as well, and flag the Aspeed to use this mode. This mode was tested on the Gemini so I have high hopes that it'll work fine on the Aspeed as well. After this we have one driver for all three SoCs and a generic Faraday FTTMR010 timer driver, which is nice. Cc: Joel Stanley <joel@jms.id.au> Cc: Jonas Jensen <jonas.jensen@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Joel Stanley <joel@jms.id.au> Tested-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r--arch/arm/mach-aspeed/Kconfig2
-rw-r--r--arch/arm/mach-moxart/Kconfig2
-rw-r--r--drivers/clocksource/Kconfig7
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/moxart_timer.c256
-rw-r--r--drivers/clocksource/timer-fttmr010.c143
6 files changed, 108 insertions, 303 deletions
diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig
index f3f8c5c658db..2d5570e6e186 100644
--- a/arch/arm/mach-aspeed/Kconfig
+++ b/arch/arm/mach-aspeed/Kconfig
@@ -4,7 +4,7 @@ menuconfig ARCH_ASPEED
4 select SRAM 4 select SRAM
5 select WATCHDOG 5 select WATCHDOG
6 select ASPEED_WATCHDOG 6 select ASPEED_WATCHDOG
7 select MOXART_TIMER 7 select FTTMR010_TIMER
8 select MFD_SYSCON 8 select MFD_SYSCON
9 select PINCTRL 9 select PINCTRL
10 help 10 help
diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig
index 70db2abf6163..a4a91f9a3301 100644
--- a/arch/arm/mach-moxart/Kconfig
+++ b/arch/arm/mach-moxart/Kconfig
@@ -4,7 +4,7 @@ menuconfig ARCH_MOXART
4 select CPU_FA526 4 select CPU_FA526
5 select ARM_DMA_MEM_BUFFERABLE 5 select ARM_DMA_MEM_BUFFERABLE
6 select FARADAY_FTINTC010 6 select FARADAY_FTINTC010
7 select MOXART_TIMER 7 select FTTMR010_TIMER
8 select GPIOLIB 8 select GPIOLIB
9 select PHYLIB if NETDEVICES 9 select PHYLIB if NETDEVICES
10 help 10 help
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 545d541ae20e..1b22ade4c8f1 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -188,13 +188,6 @@ config ATLAS7_TIMER
188 help 188 help
189 Enables support for the Atlas7 timer. 189 Enables support for the Atlas7 timer.
190 190
191config MOXART_TIMER
192 bool "Moxart timer driver" if COMPILE_TEST
193 depends on GENERIC_CLOCKEVENTS
194 select CLKSRC_MMIO
195 help
196 Enables support for the Moxart timer.
197
198config MXS_TIMER 191config MXS_TIMER
199 bool "Mxs timer driver" if COMPILE_TEST 192 bool "Mxs timer driver" if COMPILE_TEST
200 depends on GENERIC_CLOCKEVENTS 193 depends on GENERIC_CLOCKEVENTS
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 2b5b56a6f00f..cf0c30b6ec1f 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -26,7 +26,6 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o
26obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o 26obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o
27obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o 27obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o
28obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o 28obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o
29obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o
30obj-$(CONFIG_MXS_TIMER) += mxs_timer.o 29obj-$(CONFIG_MXS_TIMER) += mxs_timer.o
31obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o 30obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
32obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o 31obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o
diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c
deleted file mode 100644
index 7f3430654fbd..000000000000
--- a/drivers/clocksource/moxart_timer.c
+++ /dev/null
@@ -1,256 +0,0 @@
1/*
2 * MOXA ART SoCs timer handling.
3 *
4 * Copyright (C) 2013 Jonas Jensen
5 *
6 * Jonas Jensen <jonas.jensen@gmail.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/clk.h>
14#include <linux/clockchips.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/irqreturn.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/of_irq.h>
21#include <linux/io.h>
22#include <linux/clocksource.h>
23#include <linux/bitops.h>
24#include <linux/slab.h>
25
26#define TIMER1_BASE 0x00
27#define TIMER2_BASE 0x10
28#define TIMER3_BASE 0x20
29
30#define REG_COUNT 0x0 /* writable */
31#define REG_LOAD 0x4
32#define REG_MATCH1 0x8
33#define REG_MATCH2 0xC
34
35#define TIMER_CR 0x30
36#define TIMER_INTR_STATE 0x34
37#define TIMER_INTR_MASK 0x38
38
39/*
40 * Moxart TIMER_CR flags:
41 *
42 * MOXART_CR_*_CLOCK 0: PCLK, 1: EXT1CLK
43 * MOXART_CR_*_INT overflow interrupt enable bit
44 */
45#define MOXART_CR_1_ENABLE BIT(0)
46#define MOXART_CR_1_CLOCK BIT(1)
47#define MOXART_CR_1_INT BIT(2)
48#define MOXART_CR_2_ENABLE BIT(3)
49#define MOXART_CR_2_CLOCK BIT(4)
50#define MOXART_CR_2_INT BIT(5)
51#define MOXART_CR_3_ENABLE BIT(6)
52#define MOXART_CR_3_CLOCK BIT(7)
53#define MOXART_CR_3_INT BIT(8)
54#define MOXART_CR_COUNT_UP BIT(9)
55
56#define MOXART_TIMER1_ENABLE (MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE)
57#define MOXART_TIMER1_DISABLE (MOXART_CR_2_ENABLE)
58
59/*
60 * The ASpeed variant of the IP block has a different layout
61 * for the control register
62 */
63#define ASPEED_CR_1_ENABLE BIT(0)
64#define ASPEED_CR_1_CLOCK BIT(1)
65#define ASPEED_CR_1_INT BIT(2)
66#define ASPEED_CR_2_ENABLE BIT(4)
67#define ASPEED_CR_2_CLOCK BIT(5)
68#define ASPEED_CR_2_INT BIT(6)
69#define ASPEED_CR_3_ENABLE BIT(8)
70#define ASPEED_CR_3_CLOCK BIT(9)
71#define ASPEED_CR_3_INT BIT(10)
72
73#define ASPEED_TIMER1_ENABLE (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE)
74#define ASPEED_TIMER1_DISABLE (ASPEED_CR_2_ENABLE)
75
76struct moxart_timer {
77 void __iomem *base;
78 unsigned int t1_disable_val;
79 unsigned int t1_enable_val;
80 unsigned int count_per_tick;
81 struct clock_event_device clkevt;
82};
83
84static inline struct moxart_timer *to_moxart(struct clock_event_device *evt)
85{
86 return container_of(evt, struct moxart_timer, clkevt);
87}
88
89static inline void moxart_disable(struct clock_event_device *evt)
90{
91 struct moxart_timer *timer = to_moxart(evt);
92
93 writel(timer->t1_disable_val, timer->base + TIMER_CR);
94}
95
96static inline void moxart_enable(struct clock_event_device *evt)
97{
98 struct moxart_timer *timer = to_moxart(evt);
99
100 writel(timer->t1_enable_val, timer->base + TIMER_CR);
101}
102
103static int moxart_shutdown(struct clock_event_device *evt)
104{
105 moxart_disable(evt);
106 return 0;
107}
108
109static int moxart_set_oneshot(struct clock_event_device *evt)
110{
111 moxart_disable(evt);
112 writel(~0, to_moxart(evt)->base + TIMER1_BASE + REG_LOAD);
113 return 0;
114}
115
116static int moxart_set_periodic(struct clock_event_device *evt)
117{
118 struct moxart_timer *timer = to_moxart(evt);
119
120 moxart_disable(evt);
121 writel(timer->count_per_tick, timer->base + TIMER1_BASE + REG_LOAD);
122 writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
123 moxart_enable(evt);
124 return 0;
125}
126
127static int moxart_clkevt_next_event(unsigned long cycles,
128 struct clock_event_device *evt)
129{
130 struct moxart_timer *timer = to_moxart(evt);
131 u32 u;
132
133 moxart_disable(evt);
134
135 u = readl(timer->base + TIMER1_BASE + REG_COUNT) - cycles;
136 writel(u, timer->base + TIMER1_BASE + REG_MATCH1);
137
138 moxart_enable(evt);
139
140 return 0;
141}
142
143static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
144{
145 struct clock_event_device *evt = dev_id;
146 evt->event_handler(evt);
147 return IRQ_HANDLED;
148}
149
150static int __init moxart_timer_init(struct device_node *node)
151{
152 int ret, irq;
153 unsigned long pclk;
154 struct clk *clk;
155 struct moxart_timer *timer;
156
157 timer = kzalloc(sizeof(*timer), GFP_KERNEL);
158 if (!timer)
159 return -ENOMEM;
160
161 timer->base = of_iomap(node, 0);
162 if (!timer->base) {
163 pr_err("%s: of_iomap failed\n", node->full_name);
164 ret = -ENXIO;
165 goto out_free;
166 }
167
168 irq = irq_of_parse_and_map(node, 0);
169 if (irq <= 0) {
170 pr_err("%s: irq_of_parse_and_map failed\n", node->full_name);
171 ret = -EINVAL;
172 goto out_unmap;
173 }
174
175 clk = of_clk_get(node, 0);
176 if (IS_ERR(clk)) {
177 pr_err("%s: of_clk_get failed\n", node->full_name);
178 ret = PTR_ERR(clk);
179 goto out_unmap;
180 }
181
182 pclk = clk_get_rate(clk);
183
184 if (of_device_is_compatible(node, "moxa,moxart-timer")) {
185 timer->t1_enable_val = MOXART_TIMER1_ENABLE;
186 timer->t1_disable_val = MOXART_TIMER1_DISABLE;
187 } else if (of_device_is_compatible(node, "aspeed,ast2400-timer")) {
188 timer->t1_enable_val = ASPEED_TIMER1_ENABLE;
189 timer->t1_disable_val = ASPEED_TIMER1_DISABLE;
190 } else {
191 pr_err("%s: unknown platform\n", node->full_name);
192 ret = -EINVAL;
193 goto out_unmap;
194 }
195
196 timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
197
198 timer->clkevt.name = node->name;
199 timer->clkevt.rating = 200;
200 timer->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
201 CLOCK_EVT_FEAT_ONESHOT;
202 timer->clkevt.set_state_shutdown = moxart_shutdown;
203 timer->clkevt.set_state_periodic = moxart_set_periodic;
204 timer->clkevt.set_state_oneshot = moxart_set_oneshot;
205 timer->clkevt.tick_resume = moxart_set_oneshot;
206 timer->clkevt.set_next_event = moxart_clkevt_next_event;
207 timer->clkevt.cpumask = cpumask_of(0);
208 timer->clkevt.irq = irq;
209
210 ret = clocksource_mmio_init(timer->base + TIMER2_BASE + REG_COUNT,
211 "moxart_timer", pclk, 200, 32,
212 clocksource_mmio_readl_down);
213 if (ret) {
214 pr_err("%s: clocksource_mmio_init failed\n", node->full_name);
215 goto out_unmap;
216 }
217
218 ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER,
219 node->name, &timer->clkevt);
220 if (ret) {
221 pr_err("%s: setup_irq failed\n", node->full_name);
222 goto out_unmap;
223 }
224
225 /* Clear match registers */
226 writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
227 writel(0, timer->base + TIMER1_BASE + REG_MATCH2);
228 writel(0, timer->base + TIMER2_BASE + REG_MATCH1);
229 writel(0, timer->base + TIMER2_BASE + REG_MATCH2);
230
231 /*
232 * Start timer 2 rolling as our main wall clock source, keep timer 1
233 * disabled
234 */
235 writel(0, timer->base + TIMER_CR);
236 writel(~0, timer->base + TIMER2_BASE + REG_LOAD);
237 writel(timer->t1_disable_val, timer->base + TIMER_CR);
238
239 /*
240 * documentation is not publicly available:
241 * min_delta / max_delta obtained by trial-and-error,
242 * max_delta 0xfffffffe should be ok because count
243 * register size is u32
244 */
245 clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe);
246
247 return 0;
248
249out_unmap:
250 iounmap(timer->base);
251out_free:
252 kfree(timer);
253 return ret;
254}
255CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
256CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init);
diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
index 2d915d1455ab..f8801507a687 100644
--- a/drivers/clocksource/timer-fttmr010.c
+++ b/drivers/clocksource/timer-fttmr010.c
@@ -50,6 +50,20 @@
50#define TIMER_2_CR_UPDOWN BIT(10) 50#define TIMER_2_CR_UPDOWN BIT(10)
51#define TIMER_3_CR_UPDOWN BIT(11) 51#define TIMER_3_CR_UPDOWN BIT(11)
52 52
53/*
54 * The Aspeed AST2400 moves bits around in the control register
55 * and lacks bits for setting the timer to count upwards.
56 */
57#define TIMER_1_CR_ASPEED_ENABLE BIT(0)
58#define TIMER_1_CR_ASPEED_CLOCK BIT(1)
59#define TIMER_1_CR_ASPEED_INT BIT(2)
60#define TIMER_2_CR_ASPEED_ENABLE BIT(4)
61#define TIMER_2_CR_ASPEED_CLOCK BIT(5)
62#define TIMER_2_CR_ASPEED_INT BIT(6)
63#define TIMER_3_CR_ASPEED_ENABLE BIT(8)
64#define TIMER_3_CR_ASPEED_CLOCK BIT(9)
65#define TIMER_3_CR_ASPEED_INT BIT(10)
66
53#define TIMER_1_INT_MATCH1 BIT(0) 67#define TIMER_1_INT_MATCH1 BIT(0)
54#define TIMER_1_INT_MATCH2 BIT(1) 68#define TIMER_1_INT_MATCH2 BIT(1)
55#define TIMER_1_INT_OVERFLOW BIT(2) 69#define TIMER_1_INT_OVERFLOW BIT(2)
@@ -64,6 +78,8 @@
64struct fttmr010 { 78struct fttmr010 {
65 void __iomem *base; 79 void __iomem *base;
66 unsigned int tick_rate; 80 unsigned int tick_rate;
81 bool count_down;
82 u32 t1_enable_val;
67 struct clock_event_device clkevt; 83 struct clock_event_device clkevt;
68}; 84};
69 85
@@ -77,6 +93,8 @@ static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt)
77 93
78static u64 notrace fttmr010_read_sched_clock(void) 94static u64 notrace fttmr010_read_sched_clock(void)
79{ 95{
96 if (local_fttmr->count_down)
97 return ~readl(local_fttmr->base + TIMER2_COUNT);
80 return readl(local_fttmr->base + TIMER2_COUNT); 98 return readl(local_fttmr->base + TIMER2_COUNT);
81} 99}
82 100
@@ -86,11 +104,23 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
86 struct fttmr010 *fttmr010 = to_fttmr010(evt); 104 struct fttmr010 *fttmr010 = to_fttmr010(evt);
87 u32 cr; 105 u32 cr;
88 106
89 /* Setup the match register */ 107 /* Stop */
108 cr = readl(fttmr010->base + TIMER_CR);
109 cr &= ~fttmr010->t1_enable_val;
110 writel(cr, fttmr010->base + TIMER_CR);
111
112 /* Setup the match register forward/backward in time */
90 cr = readl(fttmr010->base + TIMER1_COUNT); 113 cr = readl(fttmr010->base + TIMER1_COUNT);
91 writel(cr + cycles, fttmr010->base + TIMER1_MATCH1); 114 if (fttmr010->count_down)
92 if (readl(fttmr010->base + TIMER1_COUNT) - cr > cycles) 115 cr -= cycles;
93 return -ETIME; 116 else
117 cr += cycles;
118 writel(cr, fttmr010->base + TIMER1_MATCH1);
119
120 /* Start */
121 cr = readl(fttmr010->base + TIMER_CR);
122 cr |= fttmr010->t1_enable_val;
123 writel(cr, fttmr010->base + TIMER_CR);
94 124
95 return 0; 125 return 0;
96} 126}
@@ -100,9 +130,9 @@ static int fttmr010_timer_shutdown(struct clock_event_device *evt)
100 struct fttmr010 *fttmr010 = to_fttmr010(evt); 130 struct fttmr010 *fttmr010 = to_fttmr010(evt);
101 u32 cr; 131 u32 cr;
102 132
103 /* Stop timer and interrupt. */ 133 /* Stop */
104 cr = readl(fttmr010->base + TIMER_CR); 134 cr = readl(fttmr010->base + TIMER_CR);
105 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 135 cr &= ~fttmr010->t1_enable_val;
106 writel(cr, fttmr010->base + TIMER_CR); 136 writel(cr, fttmr010->base + TIMER_CR);
107 137
108 return 0; 138 return 0;
@@ -113,14 +143,17 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
113 struct fttmr010 *fttmr010 = to_fttmr010(evt); 143 struct fttmr010 *fttmr010 = to_fttmr010(evt);
114 u32 cr; 144 u32 cr;
115 145
116 /* Stop timer and interrupt. */ 146 /* Stop */
117 cr = readl(fttmr010->base + TIMER_CR); 147 cr = readl(fttmr010->base + TIMER_CR);
118 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 148 cr &= ~fttmr010->t1_enable_val;
119 writel(cr, fttmr010->base + TIMER_CR); 149 writel(cr, fttmr010->base + TIMER_CR);
120 150
121 /* Setup counter start from 0 */ 151 /* Setup counter start from 0 or ~0 */
122 writel(0, fttmr010->base + TIMER1_COUNT); 152 writel(0, fttmr010->base + TIMER1_COUNT);
123 writel(0, fttmr010->base + TIMER1_LOAD); 153 if (fttmr010->count_down)
154 writel(~0, fttmr010->base + TIMER1_LOAD);
155 else
156 writel(0, fttmr010->base + TIMER1_LOAD);
124 157
125 /* Enable interrupt */ 158 /* Enable interrupt */
126 cr = readl(fttmr010->base + TIMER_INTR_MASK); 159 cr = readl(fttmr010->base + TIMER_INTR_MASK);
@@ -128,11 +161,6 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
128 cr |= TIMER_1_INT_MATCH1; 161 cr |= TIMER_1_INT_MATCH1;
129 writel(cr, fttmr010->base + TIMER_INTR_MASK); 162 writel(cr, fttmr010->base + TIMER_INTR_MASK);
130 163
131 /* Start the timer */
132 cr = readl(fttmr010->base + TIMER_CR);
133 cr |= TIMER_1_CR_ENABLE;
134 writel(cr, fttmr010->base + TIMER_CR);
135
136 return 0; 164 return 0;
137} 165}
138 166
@@ -142,26 +170,30 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
142 u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); 170 u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ);
143 u32 cr; 171 u32 cr;
144 172
145 /* Stop timer and interrupt */ 173 /* Stop */
146 cr = readl(fttmr010->base + TIMER_CR); 174 cr = readl(fttmr010->base + TIMER_CR);
147 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 175 cr &= ~fttmr010->t1_enable_val;
148 writel(cr, fttmr010->base + TIMER_CR); 176 writel(cr, fttmr010->base + TIMER_CR);
149 177
150 /* Setup timer to fire at 1/HT intervals. */ 178 /* Setup timer to fire at 1/HZ intervals. */
151 cr = 0xffffffff - (period - 1); 179 if (fttmr010->count_down) {
152 writel(cr, fttmr010->base + TIMER1_COUNT); 180 writel(period, fttmr010->base + TIMER1_LOAD);
153 writel(cr, fttmr010->base + TIMER1_LOAD); 181 writel(0, fttmr010->base + TIMER1_MATCH1);
154 182 } else {
155 /* enable interrupt on overflow */ 183 cr = 0xffffffff - (period - 1);
156 cr = readl(fttmr010->base + TIMER_INTR_MASK); 184 writel(cr, fttmr010->base + TIMER1_COUNT);
157 cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); 185 writel(cr, fttmr010->base + TIMER1_LOAD);
158 cr |= TIMER_1_INT_OVERFLOW; 186
159 writel(cr, fttmr010->base + TIMER_INTR_MASK); 187 /* Enable interrupt on overflow */
188 cr = readl(fttmr010->base + TIMER_INTR_MASK);
189 cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
190 cr |= TIMER_1_INT_OVERFLOW;
191 writel(cr, fttmr010->base + TIMER_INTR_MASK);
192 }
160 193
161 /* Start the timer */ 194 /* Start the timer */
162 cr = readl(fttmr010->base + TIMER_CR); 195 cr = readl(fttmr010->base + TIMER_CR);
163 cr |= TIMER_1_CR_ENABLE; 196 cr |= fttmr010->t1_enable_val;
164 cr |= TIMER_1_CR_INT;
165 writel(cr, fttmr010->base + TIMER_CR); 197 writel(cr, fttmr010->base + TIMER_CR);
166 198
167 return 0; 199 return 0;
@@ -181,9 +213,11 @@ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
181static int __init fttmr010_timer_init(struct device_node *np) 213static int __init fttmr010_timer_init(struct device_node *np)
182{ 214{
183 struct fttmr010 *fttmr010; 215 struct fttmr010 *fttmr010;
216 bool is_ast2400;
184 int irq; 217 int irq;
185 struct clk *clk; 218 struct clk *clk;
186 int ret; 219 int ret;
220 u32 val;
187 221
188 /* 222 /*
189 * These implementations require a clock reference. 223 * These implementations require a clock reference.
@@ -223,13 +257,37 @@ static int __init fttmr010_timer_init(struct device_node *np)
223 } 257 }
224 258
225 /* 259 /*
260 * The Aspeed AST2400 moves bits around in the control register,
261 * otherwise it works the same.
262 */
263 is_ast2400 = of_device_is_compatible(np, "aspeed,ast2400-timer");
264 if (is_ast2400) {
265 fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE |
266 TIMER_1_CR_ASPEED_INT;
267 /* Downward not available */
268 fttmr010->count_down = true;
269 } else {
270 fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT;
271 }
272
273 /*
226 * Reset the interrupt mask and status 274 * Reset the interrupt mask and status
227 */ 275 */
228 writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); 276 writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
229 writel(0, fttmr010->base + TIMER_INTR_STATE); 277 writel(0, fttmr010->base + TIMER_INTR_STATE);
230 /* Enable timer 1 count up, timer 2 count up */ 278
231 writel((TIMER_1_CR_UPDOWN | TIMER_2_CR_ENABLE | TIMER_2_CR_UPDOWN), 279 /*
232 fttmr010->base + TIMER_CR); 280 * Enable timer 1 count up, timer 2 count up, except on Aspeed,
281 * where everything just counts down.
282 */
283 if (is_ast2400)
284 val = TIMER_2_CR_ASPEED_ENABLE;
285 else {
286 val = TIMER_2_CR_ENABLE;
287 if (!fttmr010->count_down)
288 val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN;
289 }
290 writel(val, fttmr010->base + TIMER_CR);
233 291
234 /* 292 /*
235 * Setup free-running clocksource timer (interrupts 293 * Setup free-running clocksource timer (interrupts
@@ -237,13 +295,22 @@ static int __init fttmr010_timer_init(struct device_node *np)
237 */ 295 */
238 local_fttmr = fttmr010; 296 local_fttmr = fttmr010;
239 writel(0, fttmr010->base + TIMER2_COUNT); 297 writel(0, fttmr010->base + TIMER2_COUNT);
240 writel(0, fttmr010->base + TIMER2_LOAD);
241 writel(0, fttmr010->base + TIMER2_MATCH1); 298 writel(0, fttmr010->base + TIMER2_MATCH1);
242 writel(0, fttmr010->base + TIMER2_MATCH2); 299 writel(0, fttmr010->base + TIMER2_MATCH2);
243 clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 300
244 "FTTMR010-TIMER2", 301 if (fttmr010->count_down) {
245 fttmr010->tick_rate, 302 writel(~0, fttmr010->base + TIMER2_LOAD);
246 300, 32, clocksource_mmio_readl_up); 303 clocksource_mmio_init(fttmr010->base + TIMER2_COUNT,
304 "FTTMR010-TIMER2",
305 fttmr010->tick_rate,
306 300, 32, clocksource_mmio_readl_down);
307 } else {
308 writel(0, fttmr010->base + TIMER2_LOAD);
309 clocksource_mmio_init(fttmr010->base + TIMER2_COUNT,
310 "FTTMR010-TIMER2",
311 fttmr010->tick_rate,
312 300, 32, clocksource_mmio_readl_up);
313 }
247 sched_clock_register(fttmr010_read_sched_clock, 32, 314 sched_clock_register(fttmr010_read_sched_clock, 32,
248 fttmr010->tick_rate); 315 fttmr010->tick_rate);
249 316
@@ -290,3 +357,5 @@ out_disable_clock:
290} 357}
291CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); 358CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
292CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); 359CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);
360CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init);
361CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", fttmr010_timer_init);