1eedbdab9SMichal Simek /*
21e529803SMichal Simek * Copyright (C) 2007-2013 Michal Simek <[email protected]>
31e529803SMichal Simek * Copyright (C) 2012-2013 Xilinx, Inc.
4eedbdab9SMichal Simek * Copyright (C) 2007-2009 PetaLogix
5eedbdab9SMichal Simek * Copyright (C) 2006 Atmark Techno, Inc.
6eedbdab9SMichal Simek *
7eedbdab9SMichal Simek * This file is subject to the terms and conditions of the GNU General Public
8eedbdab9SMichal Simek * License. See the file "COPYING" in the main directory of this archive
9eedbdab9SMichal Simek * for more details.
10eedbdab9SMichal Simek */
11eedbdab9SMichal Simek
12eedbdab9SMichal Simek #include <linux/interrupt.h>
13eedbdab9SMichal Simek #include <linux/delay.h>
14eedbdab9SMichal Simek #include <linux/sched.h>
15e6017571SIngo Molnar #include <linux/sched/clock.h>
16839396abSMichal Simek #include <linux/sched_clock.h>
17eedbdab9SMichal Simek #include <linux/clk.h>
18eedbdab9SMichal Simek #include <linux/clockchips.h>
19cfd4eaefSMichal Simek #include <linux/of_address.h>
205c9f303eSRob Herring #include <linux/of_irq.h>
215ce07a5cSRichard Cochran #include <linux/timecounter.h>
22eedbdab9SMichal Simek #include <asm/cpuinfo.h>
23eedbdab9SMichal Simek
24cfd4eaefSMichal Simek static void __iomem *timer_baseaddr;
25eedbdab9SMichal Simek
2629e3dbb1SMichal Simek static unsigned int freq_div_hz;
2729e3dbb1SMichal Simek static unsigned int timer_clock_freq;
28ccea0e6eSMichal Simek
29eedbdab9SMichal Simek #define TCSR0 (0x00)
30eedbdab9SMichal Simek #define TLR0 (0x04)
31eedbdab9SMichal Simek #define TCR0 (0x08)
32eedbdab9SMichal Simek #define TCSR1 (0x10)
33eedbdab9SMichal Simek #define TLR1 (0x14)
34eedbdab9SMichal Simek #define TCR1 (0x18)
35eedbdab9SMichal Simek
36eedbdab9SMichal Simek #define TCSR_MDT (1<<0)
37eedbdab9SMichal Simek #define TCSR_UDT (1<<1)
38eedbdab9SMichal Simek #define TCSR_GENT (1<<2)
39eedbdab9SMichal Simek #define TCSR_CAPT (1<<3)
40eedbdab9SMichal Simek #define TCSR_ARHT (1<<4)
41eedbdab9SMichal Simek #define TCSR_LOAD (1<<5)
42eedbdab9SMichal Simek #define TCSR_ENIT (1<<6)
43eedbdab9SMichal Simek #define TCSR_ENT (1<<7)
44eedbdab9SMichal Simek #define TCSR_TINT (1<<8)
45eedbdab9SMichal Simek #define TCSR_PWMA (1<<9)
46eedbdab9SMichal Simek #define TCSR_ENALL (1<<10)
47eedbdab9SMichal Simek
48a1715bb7SMichal Simek static unsigned int (*read_fn)(void __iomem *);
49a1715bb7SMichal Simek static void (*write_fn)(u32, void __iomem *);
50a1715bb7SMichal Simek
timer_write32(u32 val,void __iomem * addr)51a1715bb7SMichal Simek static void timer_write32(u32 val, void __iomem *addr)
52a1715bb7SMichal Simek {
53a1715bb7SMichal Simek iowrite32(val, addr);
54a1715bb7SMichal Simek }
55a1715bb7SMichal Simek
timer_read32(void __iomem * addr)56a1715bb7SMichal Simek static unsigned int timer_read32(void __iomem *addr)
57a1715bb7SMichal Simek {
58a1715bb7SMichal Simek return ioread32(addr);
59a1715bb7SMichal Simek }
60a1715bb7SMichal Simek
timer_write32_be(u32 val,void __iomem * addr)61a1715bb7SMichal Simek static void timer_write32_be(u32 val, void __iomem *addr)
62a1715bb7SMichal Simek {
63a1715bb7SMichal Simek iowrite32be(val, addr);
64a1715bb7SMichal Simek }
65a1715bb7SMichal Simek
timer_read32_be(void __iomem * addr)66a1715bb7SMichal Simek static unsigned int timer_read32_be(void __iomem *addr)
67a1715bb7SMichal Simek {
68a1715bb7SMichal Simek return ioread32be(addr);
69a1715bb7SMichal Simek }
70a1715bb7SMichal Simek
xilinx_timer0_stop(void)715955563aSMichal Simek static inline void xilinx_timer0_stop(void)
72eedbdab9SMichal Simek {
73a1715bb7SMichal Simek write_fn(read_fn(timer_baseaddr + TCSR0) & ~TCSR_ENT,
74a1715bb7SMichal Simek timer_baseaddr + TCSR0);
75eedbdab9SMichal Simek }
76eedbdab9SMichal Simek
xilinx_timer0_start_periodic(unsigned long load_val)775955563aSMichal Simek static inline void xilinx_timer0_start_periodic(unsigned long load_val)
78eedbdab9SMichal Simek {
79eedbdab9SMichal Simek if (!load_val)
80eedbdab9SMichal Simek load_val = 1;
819e77dab6SMichal Simek /* loading value to timer reg */
82a1715bb7SMichal Simek write_fn(load_val, timer_baseaddr + TLR0);
83eedbdab9SMichal Simek
84eedbdab9SMichal Simek /* load the initial value */
85a1715bb7SMichal Simek write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
86eedbdab9SMichal Simek
87eedbdab9SMichal Simek /* see timer data sheet for detail
88eedbdab9SMichal Simek * !ENALL - don't enable 'em all
89eedbdab9SMichal Simek * !PWMA - disable pwm
90eedbdab9SMichal Simek * TINT - clear interrupt status
91eedbdab9SMichal Simek * ENT- enable timer itself
92f7f4786cSMichal Simek * ENIT - enable interrupt
93eedbdab9SMichal Simek * !LOAD - clear the bit to let go
94eedbdab9SMichal Simek * ARHT - auto reload
95eedbdab9SMichal Simek * !CAPT - no external trigger
96eedbdab9SMichal Simek * !GENT - no external signal
97eedbdab9SMichal Simek * UDT - set the timer as down counter
98eedbdab9SMichal Simek * !MDT0 - generate mode
99eedbdab9SMichal Simek */
100a1715bb7SMichal Simek write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
101a1715bb7SMichal Simek timer_baseaddr + TCSR0);
102eedbdab9SMichal Simek }
103eedbdab9SMichal Simek
xilinx_timer0_start_oneshot(unsigned long load_val)1045955563aSMichal Simek static inline void xilinx_timer0_start_oneshot(unsigned long load_val)
105eedbdab9SMichal Simek {
106eedbdab9SMichal Simek if (!load_val)
107eedbdab9SMichal Simek load_val = 1;
1089e77dab6SMichal Simek /* loading value to timer reg */
109a1715bb7SMichal Simek write_fn(load_val, timer_baseaddr + TLR0);
110eedbdab9SMichal Simek
111eedbdab9SMichal Simek /* load the initial value */
112a1715bb7SMichal Simek write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
113eedbdab9SMichal Simek
114a1715bb7SMichal Simek write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
115a1715bb7SMichal Simek timer_baseaddr + TCSR0);
116eedbdab9SMichal Simek }
117eedbdab9SMichal Simek
xilinx_timer_set_next_event(unsigned long delta,struct clock_event_device * dev)1185955563aSMichal Simek static int xilinx_timer_set_next_event(unsigned long delta,
119eedbdab9SMichal Simek struct clock_event_device *dev)
120eedbdab9SMichal Simek {
121eedbdab9SMichal Simek pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
1225955563aSMichal Simek xilinx_timer0_start_oneshot(delta);
123eedbdab9SMichal Simek return 0;
124eedbdab9SMichal Simek }
125eedbdab9SMichal Simek
xilinx_timer_shutdown(struct clock_event_device * evt)1269797529dSViresh Kumar static int xilinx_timer_shutdown(struct clock_event_device *evt)
127eedbdab9SMichal Simek {
1289797529dSViresh Kumar pr_info("%s\n", __func__);
1295955563aSMichal Simek xilinx_timer0_stop();
1309797529dSViresh Kumar return 0;
131eedbdab9SMichal Simek }
1329797529dSViresh Kumar
xilinx_timer_set_periodic(struct clock_event_device * evt)1339797529dSViresh Kumar static int xilinx_timer_set_periodic(struct clock_event_device *evt)
1349797529dSViresh Kumar {
1359797529dSViresh Kumar pr_info("%s\n", __func__);
1369797529dSViresh Kumar xilinx_timer0_start_periodic(freq_div_hz);
1379797529dSViresh Kumar return 0;
138eedbdab9SMichal Simek }
139eedbdab9SMichal Simek
1405955563aSMichal Simek static struct clock_event_device clockevent_xilinx_timer = {
1415955563aSMichal Simek .name = "xilinx_clockevent",
1429797529dSViresh Kumar .features = CLOCK_EVT_FEAT_ONESHOT |
1439797529dSViresh Kumar CLOCK_EVT_FEAT_PERIODIC,
144c8f77436SMichal Simek .shift = 8,
145eedbdab9SMichal Simek .rating = 300,
1465955563aSMichal Simek .set_next_event = xilinx_timer_set_next_event,
1479797529dSViresh Kumar .set_state_shutdown = xilinx_timer_shutdown,
1489797529dSViresh Kumar .set_state_periodic = xilinx_timer_set_periodic,
149eedbdab9SMichal Simek };
150eedbdab9SMichal Simek
timer_ack(void)151eedbdab9SMichal Simek static inline void timer_ack(void)
152eedbdab9SMichal Simek {
153a1715bb7SMichal Simek write_fn(read_fn(timer_baseaddr + TCSR0), timer_baseaddr + TCSR0);
154eedbdab9SMichal Simek }
155eedbdab9SMichal Simek
timer_interrupt(int irq,void * dev_id)156eedbdab9SMichal Simek static irqreturn_t timer_interrupt(int irq, void *dev_id)
157eedbdab9SMichal Simek {
1585955563aSMichal Simek struct clock_event_device *evt = &clockevent_xilinx_timer;
159eedbdab9SMichal Simek timer_ack();
160eedbdab9SMichal Simek evt->event_handler(evt);
161eedbdab9SMichal Simek return IRQ_HANDLED;
162eedbdab9SMichal Simek }
163eedbdab9SMichal Simek
xilinx_clockevent_init(void)16405864217SDaniel Lezcano static __init int xilinx_clockevent_init(void)
165eedbdab9SMichal Simek {
1665955563aSMichal Simek clockevent_xilinx_timer.mult =
167ccea0e6eSMichal Simek div_sc(timer_clock_freq, NSEC_PER_SEC,
1685955563aSMichal Simek clockevent_xilinx_timer.shift);
1695955563aSMichal Simek clockevent_xilinx_timer.max_delta_ns =
1705955563aSMichal Simek clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer);
171bb26081aSNicolai Stange clockevent_xilinx_timer.max_delta_ticks = (u32)~0;
1725955563aSMichal Simek clockevent_xilinx_timer.min_delta_ns =
1735955563aSMichal Simek clockevent_delta2ns(1, &clockevent_xilinx_timer);
174bb26081aSNicolai Stange clockevent_xilinx_timer.min_delta_ticks = 1;
1755955563aSMichal Simek clockevent_xilinx_timer.cpumask = cpumask_of(0);
1765955563aSMichal Simek clockevents_register_device(&clockevent_xilinx_timer);
17705864217SDaniel Lezcano
17805864217SDaniel Lezcano return 0;
179eedbdab9SMichal Simek }
180eedbdab9SMichal Simek
xilinx_clock_read(void)181839396abSMichal Simek static u64 xilinx_clock_read(void)
182839396abSMichal Simek {
183a1715bb7SMichal Simek return read_fn(timer_baseaddr + TCR1);
184839396abSMichal Simek }
185839396abSMichal Simek
xilinx_read(struct clocksource * cs)186a5a1d1c2SThomas Gleixner static u64 xilinx_read(struct clocksource *cs)
187eedbdab9SMichal Simek {
188eedbdab9SMichal Simek /* reading actual value of timer 1 */
189a5a1d1c2SThomas Gleixner return (u64)xilinx_clock_read();
190eedbdab9SMichal Simek }
191eedbdab9SMichal Simek
1925955563aSMichal Simek static struct timecounter xilinx_tc = {
193519e9f41SMichal Simek .cc = NULL,
194519e9f41SMichal Simek };
195519e9f41SMichal Simek
xilinx_cc_read(const struct cyclecounter * cc)196a5a1d1c2SThomas Gleixner static u64 xilinx_cc_read(const struct cyclecounter *cc)
197519e9f41SMichal Simek {
1985955563aSMichal Simek return xilinx_read(NULL);
199519e9f41SMichal Simek }
200519e9f41SMichal Simek
2015955563aSMichal Simek static struct cyclecounter xilinx_cc = {
2025955563aSMichal Simek .read = xilinx_cc_read,
203519e9f41SMichal Simek .mask = CLOCKSOURCE_MASK(32),
204c8f77436SMichal Simek .shift = 8,
205519e9f41SMichal Simek };
206519e9f41SMichal Simek
init_xilinx_timecounter(void)2075955563aSMichal Simek static int __init init_xilinx_timecounter(void)
208519e9f41SMichal Simek {
2095955563aSMichal Simek xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
2105955563aSMichal Simek xilinx_cc.shift);
211519e9f41SMichal Simek
2125955563aSMichal Simek timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());
213519e9f41SMichal Simek
214519e9f41SMichal Simek return 0;
215519e9f41SMichal Simek }
216519e9f41SMichal Simek
217eedbdab9SMichal Simek static struct clocksource clocksource_microblaze = {
2185955563aSMichal Simek .name = "xilinx_clocksource",
219eedbdab9SMichal Simek .rating = 300,
2205955563aSMichal Simek .read = xilinx_read,
221eedbdab9SMichal Simek .mask = CLOCKSOURCE_MASK(32),
222eedbdab9SMichal Simek .flags = CLOCK_SOURCE_IS_CONTINUOUS,
223eedbdab9SMichal Simek };
224eedbdab9SMichal Simek
xilinx_clocksource_init(void)2255955563aSMichal Simek static int __init xilinx_clocksource_init(void)
226eedbdab9SMichal Simek {
22705864217SDaniel Lezcano int ret;
22805864217SDaniel Lezcano
22905864217SDaniel Lezcano ret = clocksource_register_hz(&clocksource_microblaze,
23005864217SDaniel Lezcano timer_clock_freq);
23105864217SDaniel Lezcano if (ret) {
23205864217SDaniel Lezcano pr_err("failed to register clocksource");
23305864217SDaniel Lezcano return ret;
23405864217SDaniel Lezcano }
235eedbdab9SMichal Simek
236eedbdab9SMichal Simek /* stop timer1 */
237a1715bb7SMichal Simek write_fn(read_fn(timer_baseaddr + TCSR1) & ~TCSR_ENT,
238a1715bb7SMichal Simek timer_baseaddr + TCSR1);
239eedbdab9SMichal Simek /* start timer1 - up counting without interrupt */
240a1715bb7SMichal Simek write_fn(TCSR_TINT|TCSR_ENT|TCSR_ARHT, timer_baseaddr + TCSR1);
241519e9f41SMichal Simek
242519e9f41SMichal Simek /* register timecounter - for ftrace support */
24305864217SDaniel Lezcano return init_xilinx_timecounter();
244eedbdab9SMichal Simek }
245eedbdab9SMichal Simek
xilinx_timer_init(struct device_node * timer)24605864217SDaniel Lezcano static int __init xilinx_timer_init(struct device_node *timer)
247eedbdab9SMichal Simek {
248c1120542SMichal Simek struct clk *clk;
24903fe0d3cSMichal Simek static int initialized;
2505a26cd69SMichal Simek u32 irq;
251eedbdab9SMichal Simek u32 timer_num = 1;
25205864217SDaniel Lezcano int ret;
2539e77dab6SMichal Simek
254*bc1ce713SSean Anderson /* If this property is present, the device is a PWM and not a timer */
255*bc1ce713SSean Anderson if (of_property_read_bool(timer, "#pwm-cells"))
256*bc1ce713SSean Anderson return 0;
257*bc1ce713SSean Anderson
25803fe0d3cSMichal Simek if (initialized)
25963b7c83eSMichal Simek return -EINVAL;
26003fe0d3cSMichal Simek
26103fe0d3cSMichal Simek initialized = 1;
26203fe0d3cSMichal Simek
263cfd4eaefSMichal Simek timer_baseaddr = of_iomap(timer, 0);
264cfd4eaefSMichal Simek if (!timer_baseaddr) {
265cfd4eaefSMichal Simek pr_err("ERROR: invalid timer base address\n");
26605864217SDaniel Lezcano return -ENXIO;
267cfd4eaefSMichal Simek }
268cfd4eaefSMichal Simek
269a1715bb7SMichal Simek write_fn = timer_write32;
270a1715bb7SMichal Simek read_fn = timer_read32;
271a1715bb7SMichal Simek
272a1715bb7SMichal Simek write_fn(TCSR_MDT, timer_baseaddr + TCSR0);
273a1715bb7SMichal Simek if (!(read_fn(timer_baseaddr + TCSR0) & TCSR_MDT)) {
274a1715bb7SMichal Simek write_fn = timer_write32_be;
275a1715bb7SMichal Simek read_fn = timer_read32_be;
276a1715bb7SMichal Simek }
277a1715bb7SMichal Simek
2789d0ced00SMichal Simek irq = irq_of_parse_and_map(timer, 0);
27905864217SDaniel Lezcano if (irq <= 0) {
28005864217SDaniel Lezcano pr_err("Failed to parse and map irq");
28105864217SDaniel Lezcano return -EINVAL;
28205864217SDaniel Lezcano }
283cfd4eaefSMichal Simek
284cfd4eaefSMichal Simek of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);
285eedbdab9SMichal Simek if (timer_num) {
28605864217SDaniel Lezcano pr_err("Please enable two timers in HW\n");
28705864217SDaniel Lezcano return -EINVAL;
288eedbdab9SMichal Simek }
289eedbdab9SMichal Simek
290f2b8ae0eSRob Herring pr_info("%pOF: irq=%d\n", timer, irq);
291eedbdab9SMichal Simek
292c1120542SMichal Simek clk = of_clk_get(timer, 0);
293c1120542SMichal Simek if (IS_ERR(clk)) {
294c1120542SMichal Simek pr_err("ERROR: timer CCF input clock not found\n");
295ccea0e6eSMichal Simek /* If there is clock-frequency property than use it */
296c1120542SMichal Simek of_property_read_u32(timer, "clock-frequency",
297c1120542SMichal Simek &timer_clock_freq);
298c1120542SMichal Simek } else {
299c1120542SMichal Simek timer_clock_freq = clk_get_rate(clk);
300c1120542SMichal Simek }
301c1120542SMichal Simek
302c1120542SMichal Simek if (!timer_clock_freq) {
303c1120542SMichal Simek pr_err("ERROR: Using CPU clock frequency\n");
304ccea0e6eSMichal Simek timer_clock_freq = cpuinfo.cpu_clock_freq;
305c1120542SMichal Simek }
306ccea0e6eSMichal Simek
307ccea0e6eSMichal Simek freq_div_hz = timer_clock_freq / HZ;
308eedbdab9SMichal Simek
3099fd1a1c9Safzal mohammed ret = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer",
3109fd1a1c9Safzal mohammed &clockevent_xilinx_timer);
31105864217SDaniel Lezcano if (ret) {
31205864217SDaniel Lezcano pr_err("Failed to setup IRQ");
31305864217SDaniel Lezcano return ret;
31405864217SDaniel Lezcano }
31505864217SDaniel Lezcano
31605864217SDaniel Lezcano ret = xilinx_clocksource_init();
31705864217SDaniel Lezcano if (ret)
31805864217SDaniel Lezcano return ret;
31905864217SDaniel Lezcano
32005864217SDaniel Lezcano ret = xilinx_clockevent_init();
32105864217SDaniel Lezcano if (ret)
32205864217SDaniel Lezcano return ret;
3236f34b08fSMichal Simek
324839396abSMichal Simek sched_clock_register(xilinx_clock_read, 32, timer_clock_freq);
32505864217SDaniel Lezcano
32605864217SDaniel Lezcano return 0;
327eedbdab9SMichal Simek }
3284bcd943eSMichal Simek
32917273395SDaniel Lezcano TIMER_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
3304bcd943eSMichal Simek xilinx_timer_init);
331