blob: 9df14cf13808e03e20db382f3b363eaf15d768ed [file] [log] [blame]
Linus Walleij47505352017-01-22 13:17:17 +01001/*
Linus Walleijf5bf0ee2017-03-24 22:32:34 +01002 * Faraday Technology FTTMR010 timer driver
Linus Walleij47505352017-01-22 13:17:17 +01003 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
4 *
5 * Based on a rewrite of arch/arm/mach-gemini/timer.c:
6 * Copyright (C) 2001-2006 Storlink, Corp.
7 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
8 */
9#include <linux/interrupt.h>
10#include <linux/io.h>
11#include <linux/of.h>
12#include <linux/of_address.h>
13#include <linux/of_irq.h>
Linus Walleij47505352017-01-22 13:17:17 +010014#include <linux/clockchips.h>
15#include <linux/clocksource.h>
16#include <linux/sched_clock.h>
Linus Walleij28e71e22017-03-24 22:32:35 +010017#include <linux/clk.h>
Linus Walleije7bad212017-05-18 22:17:01 +020018#include <linux/slab.h>
Linus Walleijd0d76d52017-05-18 22:17:02 +020019#include <linux/bitops.h>
Linus Walleij47505352017-01-22 13:17:17 +010020
21/*
22 * Register definitions for the timers
23 */
24#define TIMER1_COUNT (0x00)
25#define TIMER1_LOAD (0x04)
26#define TIMER1_MATCH1 (0x08)
27#define TIMER1_MATCH2 (0x0c)
28#define TIMER2_COUNT (0x10)
29#define TIMER2_LOAD (0x14)
30#define TIMER2_MATCH1 (0x18)
31#define TIMER2_MATCH2 (0x1c)
32#define TIMER3_COUNT (0x20)
33#define TIMER3_LOAD (0x24)
34#define TIMER3_MATCH1 (0x28)
35#define TIMER3_MATCH2 (0x2c)
36#define TIMER_CR (0x30)
37#define TIMER_INTR_STATE (0x34)
38#define TIMER_INTR_MASK (0x38)
39
Linus Walleijd0d76d52017-05-18 22:17:02 +020040#define TIMER_1_CR_ENABLE BIT(0)
41#define TIMER_1_CR_CLOCK BIT(1)
42#define TIMER_1_CR_INT BIT(2)
43#define TIMER_2_CR_ENABLE BIT(3)
44#define TIMER_2_CR_CLOCK BIT(4)
45#define TIMER_2_CR_INT BIT(5)
46#define TIMER_3_CR_ENABLE BIT(6)
47#define TIMER_3_CR_CLOCK BIT(7)
48#define TIMER_3_CR_INT BIT(8)
49#define TIMER_1_CR_UPDOWN BIT(9)
50#define TIMER_2_CR_UPDOWN BIT(10)
51#define TIMER_3_CR_UPDOWN BIT(11)
Linus Walleij47505352017-01-22 13:17:17 +010052#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \
53 TIMER_3_CR_ENABLE | \
54 TIMER_3_CR_UPDOWN)
55
Linus Walleijd0d76d52017-05-18 22:17:02 +020056#define TIMER_1_INT_MATCH1 BIT(0)
57#define TIMER_1_INT_MATCH2 BIT(1)
58#define TIMER_1_INT_OVERFLOW BIT(2)
59#define TIMER_2_INT_MATCH1 BIT(3)
60#define TIMER_2_INT_MATCH2 BIT(4)
61#define TIMER_2_INT_OVERFLOW BIT(5)
62#define TIMER_3_INT_MATCH1 BIT(6)
63#define TIMER_3_INT_MATCH2 BIT(7)
64#define TIMER_3_INT_OVERFLOW BIT(8)
Linus Walleij47505352017-01-22 13:17:17 +010065#define TIMER_INT_ALL_MASK 0x1ff
66
Linus Walleije7bad212017-05-18 22:17:01 +020067struct fttmr010 {
68 void __iomem *base;
69 unsigned int tick_rate;
70 struct clock_event_device clkevt;
71};
72
73/* A local singleton used by sched_clock, which is stateless */
74static struct fttmr010 *local_fttmr;
75
76static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt)
77{
78 return container_of(evt, struct fttmr010, clkevt);
79}
Linus Walleij47505352017-01-22 13:17:17 +010080
Linus Walleijf5bf0ee2017-03-24 22:32:34 +010081static u64 notrace fttmr010_read_sched_clock(void)
Linus Walleij47505352017-01-22 13:17:17 +010082{
Linus Walleije7bad212017-05-18 22:17:01 +020083 return readl(local_fttmr->base + TIMER3_COUNT);
Linus Walleij47505352017-01-22 13:17:17 +010084}
85
Linus Walleijf5bf0ee2017-03-24 22:32:34 +010086static int fttmr010_timer_set_next_event(unsigned long cycles,
Linus Walleij47505352017-01-22 13:17:17 +010087 struct clock_event_device *evt)
88{
Linus Walleije7bad212017-05-18 22:17:01 +020089 struct fttmr010 *fttmr010 = to_fttmr010(evt);
Linus Walleij47505352017-01-22 13:17:17 +010090 u32 cr;
91
92 /* Setup the match register */
Linus Walleije7bad212017-05-18 22:17:01 +020093 cr = readl(fttmr010->base + TIMER1_COUNT);
94 writel(cr + cycles, fttmr010->base + TIMER1_MATCH1);
95 if (readl(fttmr010->base + TIMER1_COUNT) - cr > cycles)
Linus Walleij47505352017-01-22 13:17:17 +010096 return -ETIME;
97
98 return 0;
99}
100
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100101static int fttmr010_timer_shutdown(struct clock_event_device *evt)
Linus Walleij47505352017-01-22 13:17:17 +0100102{
Linus Walleije7bad212017-05-18 22:17:01 +0200103 struct fttmr010 *fttmr010 = to_fttmr010(evt);
Linus Walleij47505352017-01-22 13:17:17 +0100104 u32 cr;
105
Linus Walleij47505352017-01-22 13:17:17 +0100106 /* Stop timer and interrupt. */
Linus Walleije7bad212017-05-18 22:17:01 +0200107 cr = readl(fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100108 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
Linus Walleije7bad212017-05-18 22:17:01 +0200109 writel(cr, fttmr010->base + TIMER_CR);
110
111 return 0;
112}
113
114static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
115{
116 struct fttmr010 *fttmr010 = to_fttmr010(evt);
117 u32 cr;
118
119 /* Stop timer and interrupt. */
120 cr = readl(fttmr010->base + TIMER_CR);
121 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
122 writel(cr, fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100123
124 /* Setup counter start from 0 */
Linus Walleije7bad212017-05-18 22:17:01 +0200125 writel(0, fttmr010->base + TIMER1_COUNT);
126 writel(0, fttmr010->base + TIMER1_LOAD);
Linus Walleij47505352017-01-22 13:17:17 +0100127
Linus Walleije7bad212017-05-18 22:17:01 +0200128 /* Enable interrupt */
129 cr = readl(fttmr010->base + TIMER_INTR_MASK);
Linus Walleij47505352017-01-22 13:17:17 +0100130 cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
131 cr |= TIMER_1_INT_MATCH1;
Linus Walleije7bad212017-05-18 22:17:01 +0200132 writel(cr, fttmr010->base + TIMER_INTR_MASK);
Linus Walleij47505352017-01-22 13:17:17 +0100133
Linus Walleije7bad212017-05-18 22:17:01 +0200134 /* Start the timer */
135 cr = readl(fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100136 cr |= TIMER_1_CR_ENABLE;
Linus Walleije7bad212017-05-18 22:17:01 +0200137 writel(cr, fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100138
139 return 0;
140}
141
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100142static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
Linus Walleij47505352017-01-22 13:17:17 +0100143{
Linus Walleije7bad212017-05-18 22:17:01 +0200144 struct fttmr010 *fttmr010 = to_fttmr010(evt);
145 u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ);
Linus Walleij47505352017-01-22 13:17:17 +0100146 u32 cr;
147
148 /* Stop timer and interrupt */
Linus Walleije7bad212017-05-18 22:17:01 +0200149 cr = readl(fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100150 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
Linus Walleije7bad212017-05-18 22:17:01 +0200151 writel(cr, fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100152
153 /* Setup timer to fire at 1/HT intervals. */
154 cr = 0xffffffff - (period - 1);
Linus Walleije7bad212017-05-18 22:17:01 +0200155 writel(cr, fttmr010->base + TIMER1_COUNT);
156 writel(cr, fttmr010->base + TIMER1_LOAD);
Linus Walleij47505352017-01-22 13:17:17 +0100157
158 /* enable interrupt on overflow */
Linus Walleije7bad212017-05-18 22:17:01 +0200159 cr = readl(fttmr010->base + TIMER_INTR_MASK);
Linus Walleij47505352017-01-22 13:17:17 +0100160 cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
161 cr |= TIMER_1_INT_OVERFLOW;
Linus Walleije7bad212017-05-18 22:17:01 +0200162 writel(cr, fttmr010->base + TIMER_INTR_MASK);
Linus Walleij47505352017-01-22 13:17:17 +0100163
164 /* Start the timer */
Linus Walleije7bad212017-05-18 22:17:01 +0200165 cr = readl(fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100166 cr |= TIMER_1_CR_ENABLE;
167 cr |= TIMER_1_CR_INT;
Linus Walleije7bad212017-05-18 22:17:01 +0200168 writel(cr, fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100169
170 return 0;
171}
172
Linus Walleij47505352017-01-22 13:17:17 +0100173/*
174 * IRQ handler for the timer
175 */
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100176static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
Linus Walleij47505352017-01-22 13:17:17 +0100177{
Linus Walleije7bad212017-05-18 22:17:01 +0200178 struct clock_event_device *evt = dev_id;
Linus Walleij47505352017-01-22 13:17:17 +0100179
180 evt->event_handler(evt);
181 return IRQ_HANDLED;
182}
183
Linus Walleijdd984422017-05-18 22:17:00 +0200184static int __init fttmr010_timer_init(struct device_node *np)
Linus Walleij47505352017-01-22 13:17:17 +0100185{
Linus Walleije7bad212017-05-18 22:17:01 +0200186 struct fttmr010 *fttmr010;
Linus Walleij47505352017-01-22 13:17:17 +0100187 int irq;
Linus Walleijdd984422017-05-18 22:17:00 +0200188 struct clk *clk;
189 int ret;
190
191 /*
192 * These implementations require a clock reference.
193 * FIXME: we currently only support clocking using PCLK
194 * and using EXTCLK is not supported in the driver.
195 */
196 clk = of_clk_get_by_name(np, "PCLK");
197 if (IS_ERR(clk)) {
198 pr_err("could not get PCLK\n");
199 return PTR_ERR(clk);
200 }
201 ret = clk_prepare_enable(clk);
202 if (ret) {
203 pr_err("failed to enable PCLK\n");
204 return ret;
205 }
Linus Walleij47505352017-01-22 13:17:17 +0100206
Linus Walleije7bad212017-05-18 22:17:01 +0200207 fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL);
208 if (!fttmr010) {
209 ret = -ENOMEM;
210 goto out_disable_clock;
211 }
212 fttmr010->tick_rate = clk_get_rate(clk);
213
214 fttmr010->base = of_iomap(np, 0);
215 if (!fttmr010->base) {
Linus Walleij47505352017-01-22 13:17:17 +0100216 pr_err("Can't remap registers");
Linus Walleije7bad212017-05-18 22:17:01 +0200217 ret = -ENXIO;
218 goto out_free;
Linus Walleij47505352017-01-22 13:17:17 +0100219 }
220 /* IRQ for timer 1 */
221 irq = irq_of_parse_and_map(np, 0);
222 if (irq <= 0) {
223 pr_err("Can't parse IRQ");
Linus Walleije7bad212017-05-18 22:17:01 +0200224 ret = -EINVAL;
225 goto out_unmap;
Linus Walleij47505352017-01-22 13:17:17 +0100226 }
227
Linus Walleij47505352017-01-22 13:17:17 +0100228 /*
229 * Reset the interrupt mask and status
230 */
Linus Walleije7bad212017-05-18 22:17:01 +0200231 writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
232 writel(0, fttmr010->base + TIMER_INTR_STATE);
233 writel(TIMER_DEFAULT_FLAGS, fttmr010->base + TIMER_CR);
Linus Walleij47505352017-01-22 13:17:17 +0100234
235 /*
236 * Setup free-running clocksource timer (interrupts
237 * disabled.)
238 */
Linus Walleije7bad212017-05-18 22:17:01 +0200239 local_fttmr = fttmr010;
240 writel(0, fttmr010->base + TIMER3_COUNT);
241 writel(0, fttmr010->base + TIMER3_LOAD);
242 writel(0, fttmr010->base + TIMER3_MATCH1);
243 writel(0, fttmr010->base + TIMER3_MATCH2);
244 clocksource_mmio_init(fttmr010->base + TIMER3_COUNT,
245 "FTTMR010-TIMER3",
246 fttmr010->tick_rate,
Linus Walleij47505352017-01-22 13:17:17 +0100247 300, 32, clocksource_mmio_readl_up);
Linus Walleije7bad212017-05-18 22:17:01 +0200248 sched_clock_register(fttmr010_read_sched_clock, 32,
249 fttmr010->tick_rate);
Linus Walleij47505352017-01-22 13:17:17 +0100250
251 /*
Linus Walleije7bad212017-05-18 22:17:01 +0200252 * Setup clockevent timer (interrupt-driven) on timer 1.
Linus Walleij47505352017-01-22 13:17:17 +0100253 */
Linus Walleije7bad212017-05-18 22:17:01 +0200254 writel(0, fttmr010->base + TIMER1_COUNT);
255 writel(0, fttmr010->base + TIMER1_LOAD);
256 writel(0, fttmr010->base + TIMER1_MATCH1);
257 writel(0, fttmr010->base + TIMER1_MATCH2);
258 ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER,
259 "FTTMR010-TIMER1", &fttmr010->clkevt);
260 if (ret) {
261 pr_err("FTTMR010-TIMER1 no IRQ\n");
262 goto out_unmap;
263 }
264
265 fttmr010->clkevt.name = "FTTMR010-TIMER1";
266 /* Reasonably fast and accurate clock event */
267 fttmr010->clkevt.rating = 300;
268 fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
269 CLOCK_EVT_FEAT_ONESHOT;
270 fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event;
271 fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown;
272 fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic;
273 fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot;
274 fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown;
275 fttmr010->clkevt.cpumask = cpumask_of(0);
276 fttmr010->clkevt.irq = irq;
277 clockevents_config_and_register(&fttmr010->clkevt,
278 fttmr010->tick_rate,
Linus Walleij47505352017-01-22 13:17:17 +0100279 1, 0xffffffff);
280
281 return 0;
Linus Walleije7bad212017-05-18 22:17:01 +0200282
283out_unmap:
284 iounmap(fttmr010->base);
285out_free:
286 kfree(fttmr010);
287out_disable_clock:
288 clk_disable_unprepare(clk);
289
290 return ret;
Linus Walleij47505352017-01-22 13:17:17 +0100291}
Linus Walleijdd984422017-05-18 22:17:00 +0200292CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
293CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);