blob: db097db346e3f48ecc467fff694d44dfafa3b4cf [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 Walleij47505352017-01-22 13:17:17 +010018
19/*
20 * Register definitions for the timers
21 */
22#define TIMER1_COUNT (0x00)
23#define TIMER1_LOAD (0x04)
24#define TIMER1_MATCH1 (0x08)
25#define TIMER1_MATCH2 (0x0c)
26#define TIMER2_COUNT (0x10)
27#define TIMER2_LOAD (0x14)
28#define TIMER2_MATCH1 (0x18)
29#define TIMER2_MATCH2 (0x1c)
30#define TIMER3_COUNT (0x20)
31#define TIMER3_LOAD (0x24)
32#define TIMER3_MATCH1 (0x28)
33#define TIMER3_MATCH2 (0x2c)
34#define TIMER_CR (0x30)
35#define TIMER_INTR_STATE (0x34)
36#define TIMER_INTR_MASK (0x38)
37
38#define TIMER_1_CR_ENABLE (1 << 0)
39#define TIMER_1_CR_CLOCK (1 << 1)
40#define TIMER_1_CR_INT (1 << 2)
41#define TIMER_2_CR_ENABLE (1 << 3)
42#define TIMER_2_CR_CLOCK (1 << 4)
43#define TIMER_2_CR_INT (1 << 5)
44#define TIMER_3_CR_ENABLE (1 << 6)
45#define TIMER_3_CR_CLOCK (1 << 7)
46#define TIMER_3_CR_INT (1 << 8)
47#define TIMER_1_CR_UPDOWN (1 << 9)
48#define TIMER_2_CR_UPDOWN (1 << 10)
49#define TIMER_3_CR_UPDOWN (1 << 11)
50#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \
51 TIMER_3_CR_ENABLE | \
52 TIMER_3_CR_UPDOWN)
53
54#define TIMER_1_INT_MATCH1 (1 << 0)
55#define TIMER_1_INT_MATCH2 (1 << 1)
56#define TIMER_1_INT_OVERFLOW (1 << 2)
57#define TIMER_2_INT_MATCH1 (1 << 3)
58#define TIMER_2_INT_MATCH2 (1 << 4)
59#define TIMER_2_INT_OVERFLOW (1 << 5)
60#define TIMER_3_INT_MATCH1 (1 << 6)
61#define TIMER_3_INT_MATCH2 (1 << 7)
62#define TIMER_3_INT_OVERFLOW (1 << 8)
63#define TIMER_INT_ALL_MASK 0x1ff
64
65static unsigned int tick_rate;
66static void __iomem *base;
67
Linus Walleijf5bf0ee2017-03-24 22:32:34 +010068static u64 notrace fttmr010_read_sched_clock(void)
Linus Walleij47505352017-01-22 13:17:17 +010069{
70 return readl(base + TIMER3_COUNT);
71}
72
Linus Walleijf5bf0ee2017-03-24 22:32:34 +010073static int fttmr010_timer_set_next_event(unsigned long cycles,
Linus Walleij47505352017-01-22 13:17:17 +010074 struct clock_event_device *evt)
75{
76 u32 cr;
77
78 /* Setup the match register */
79 cr = readl(base + TIMER1_COUNT);
80 writel(cr + cycles, base + TIMER1_MATCH1);
81 if (readl(base + TIMER1_COUNT) - cr > cycles)
82 return -ETIME;
83
84 return 0;
85}
86
Linus Walleijf5bf0ee2017-03-24 22:32:34 +010087static int fttmr010_timer_shutdown(struct clock_event_device *evt)
Linus Walleij47505352017-01-22 13:17:17 +010088{
89 u32 cr;
90
91 /*
92 * Disable also for oneshot: the set_next() call will arm the timer
93 * instead.
94 */
95 /* Stop timer and interrupt. */
96 cr = readl(base + TIMER_CR);
97 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
98 writel(cr, base + TIMER_CR);
99
100 /* Setup counter start from 0 */
101 writel(0, base + TIMER1_COUNT);
102 writel(0, base + TIMER1_LOAD);
103
104 /* enable interrupt */
105 cr = readl(base + TIMER_INTR_MASK);
106 cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
107 cr |= TIMER_1_INT_MATCH1;
108 writel(cr, base + TIMER_INTR_MASK);
109
110 /* start the timer */
111 cr = readl(base + TIMER_CR);
112 cr |= TIMER_1_CR_ENABLE;
113 writel(cr, base + TIMER_CR);
114
115 return 0;
116}
117
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100118static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
Linus Walleij47505352017-01-22 13:17:17 +0100119{
120 u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
121 u32 cr;
122
123 /* Stop timer and interrupt */
124 cr = readl(base + TIMER_CR);
125 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
126 writel(cr, base + TIMER_CR);
127
128 /* Setup timer to fire at 1/HT intervals. */
129 cr = 0xffffffff - (period - 1);
130 writel(cr, base + TIMER1_COUNT);
131 writel(cr, base + TIMER1_LOAD);
132
133 /* enable interrupt on overflow */
134 cr = readl(base + TIMER_INTR_MASK);
135 cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
136 cr |= TIMER_1_INT_OVERFLOW;
137 writel(cr, base + TIMER_INTR_MASK);
138
139 /* Start the timer */
140 cr = readl(base + TIMER_CR);
141 cr |= TIMER_1_CR_ENABLE;
142 cr |= TIMER_1_CR_INT;
143 writel(cr, base + TIMER_CR);
144
145 return 0;
146}
147
148/* Use TIMER1 as clock event */
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100149static struct clock_event_device fttmr010_clockevent = {
Linus Walleij47505352017-01-22 13:17:17 +0100150 .name = "TIMER1",
151 /* Reasonably fast and accurate clock event */
152 .rating = 300,
153 .shift = 32,
154 .features = CLOCK_EVT_FEAT_PERIODIC |
155 CLOCK_EVT_FEAT_ONESHOT,
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100156 .set_next_event = fttmr010_timer_set_next_event,
157 .set_state_shutdown = fttmr010_timer_shutdown,
158 .set_state_periodic = fttmr010_timer_set_periodic,
159 .set_state_oneshot = fttmr010_timer_shutdown,
160 .tick_resume = fttmr010_timer_shutdown,
Linus Walleij47505352017-01-22 13:17:17 +0100161};
162
163/*
164 * IRQ handler for the timer
165 */
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100166static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
Linus Walleij47505352017-01-22 13:17:17 +0100167{
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100168 struct clock_event_device *evt = &fttmr010_clockevent;
Linus Walleij47505352017-01-22 13:17:17 +0100169
170 evt->event_handler(evt);
171 return IRQ_HANDLED;
172}
173
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100174static struct irqaction fttmr010_timer_irq = {
175 .name = "Faraday FTTMR010 Timer Tick",
Linus Walleij47505352017-01-22 13:17:17 +0100176 .flags = IRQF_TIMER,
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100177 .handler = fttmr010_timer_interrupt,
Linus Walleij47505352017-01-22 13:17:17 +0100178};
179
Linus Walleijdd984422017-05-18 22:17:00 +0200180static int __init fttmr010_timer_init(struct device_node *np)
Linus Walleij47505352017-01-22 13:17:17 +0100181{
Linus Walleij47505352017-01-22 13:17:17 +0100182 int irq;
Linus Walleijdd984422017-05-18 22:17:00 +0200183 struct clk *clk;
184 int ret;
185
186 /*
187 * These implementations require a clock reference.
188 * FIXME: we currently only support clocking using PCLK
189 * and using EXTCLK is not supported in the driver.
190 */
191 clk = of_clk_get_by_name(np, "PCLK");
192 if (IS_ERR(clk)) {
193 pr_err("could not get PCLK\n");
194 return PTR_ERR(clk);
195 }
196 ret = clk_prepare_enable(clk);
197 if (ret) {
198 pr_err("failed to enable PCLK\n");
199 return ret;
200 }
201 tick_rate = clk_get_rate(clk);
Linus Walleij47505352017-01-22 13:17:17 +0100202
203 base = of_iomap(np, 0);
204 if (!base) {
205 pr_err("Can't remap registers");
206 return -ENXIO;
207 }
208 /* IRQ for timer 1 */
209 irq = irq_of_parse_and_map(np, 0);
210 if (irq <= 0) {
211 pr_err("Can't parse IRQ");
212 return -EINVAL;
213 }
214
Linus Walleij47505352017-01-22 13:17:17 +0100215 /*
216 * Reset the interrupt mask and status
217 */
218 writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK);
219 writel(0, base + TIMER_INTR_STATE);
220 writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR);
221
222 /*
223 * Setup free-running clocksource timer (interrupts
224 * disabled.)
225 */
226 writel(0, base + TIMER3_COUNT);
227 writel(0, base + TIMER3_LOAD);
228 writel(0, base + TIMER3_MATCH1);
229 writel(0, base + TIMER3_MATCH2);
230 clocksource_mmio_init(base + TIMER3_COUNT,
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100231 "fttmr010_clocksource", tick_rate,
Linus Walleij47505352017-01-22 13:17:17 +0100232 300, 32, clocksource_mmio_readl_up);
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100233 sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate);
Linus Walleij47505352017-01-22 13:17:17 +0100234
235 /*
236 * Setup clockevent timer (interrupt-driven.)
237 */
238 writel(0, base + TIMER1_COUNT);
239 writel(0, base + TIMER1_LOAD);
240 writel(0, base + TIMER1_MATCH1);
241 writel(0, base + TIMER1_MATCH2);
Linus Walleijf5bf0ee2017-03-24 22:32:34 +0100242 setup_irq(irq, &fttmr010_timer_irq);
243 fttmr010_clockevent.cpumask = cpumask_of(0);
244 clockevents_config_and_register(&fttmr010_clockevent, tick_rate,
Linus Walleij47505352017-01-22 13:17:17 +0100245 1, 0xffffffff);
246
247 return 0;
248}
Linus Walleijdd984422017-05-18 22:17:00 +0200249CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
250CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);