1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Integrator/AP timer driver
4 * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5 * Copyright (c) 2014, Linaro Limited
9 #include <linux/clocksource.h>
10 #include <linux/of_irq.h>
11 #include <linux/of_address.h>
12 #include <linux/of_platform.h>
13 #include <linux/clockchips.h>
14 #include <linux/interrupt.h>
15 #include <linux/sched_clock.h>
19 static void __iomem
* sched_clk_base
;
21 static u64 notrace
integrator_read_sched_clock(void)
23 return -readl(sched_clk_base
+ TIMER_VALUE
);
26 static int __init
integrator_clocksource_init(unsigned long inrate
,
29 u32 ctrl
= TIMER_CTRL_ENABLE
| TIMER_CTRL_PERIODIC
;
30 unsigned long rate
= inrate
;
33 if (rate
>= 1500000) {
35 ctrl
|= TIMER_CTRL_DIV16
;
38 writel(0xffff, base
+ TIMER_LOAD
);
39 writel(ctrl
, base
+ TIMER_CTRL
);
41 ret
= clocksource_mmio_init(base
+ TIMER_VALUE
, "timer2",
42 rate
, 200, 16, clocksource_mmio_readl_down
);
46 sched_clk_base
= base
;
47 sched_clock_register(integrator_read_sched_clock
, 16, rate
);
52 static unsigned long timer_reload
;
53 static void __iomem
* clkevt_base
;
56 * IRQ handler for the timer
58 static irqreturn_t
integrator_timer_interrupt(int irq
, void *dev_id
)
60 struct clock_event_device
*evt
= dev_id
;
62 /* clear the interrupt */
63 writel(1, clkevt_base
+ TIMER_INTCLR
);
65 evt
->event_handler(evt
);
70 static int clkevt_shutdown(struct clock_event_device
*evt
)
72 u32 ctrl
= readl(clkevt_base
+ TIMER_CTRL
) & ~TIMER_CTRL_ENABLE
;
75 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
79 static int clkevt_set_oneshot(struct clock_event_device
*evt
)
81 u32 ctrl
= readl(clkevt_base
+ TIMER_CTRL
) &
82 ~(TIMER_CTRL_ENABLE
| TIMER_CTRL_PERIODIC
);
84 /* Leave the timer disabled, .set_next_event will enable it */
85 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
89 static int clkevt_set_periodic(struct clock_event_device
*evt
)
91 u32 ctrl
= readl(clkevt_base
+ TIMER_CTRL
) & ~TIMER_CTRL_ENABLE
;
94 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
96 /* Enable the timer and start the periodic tick */
97 writel(timer_reload
, clkevt_base
+ TIMER_LOAD
);
98 ctrl
|= TIMER_CTRL_PERIODIC
| TIMER_CTRL_ENABLE
;
99 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
103 static int clkevt_set_next_event(unsigned long next
, struct clock_event_device
*evt
)
105 unsigned long ctrl
= readl(clkevt_base
+ TIMER_CTRL
);
107 writel(ctrl
& ~TIMER_CTRL_ENABLE
, clkevt_base
+ TIMER_CTRL
);
108 writel(next
, clkevt_base
+ TIMER_LOAD
);
109 writel(ctrl
| TIMER_CTRL_ENABLE
, clkevt_base
+ TIMER_CTRL
);
114 static struct clock_event_device integrator_clockevent
= {
116 .features
= CLOCK_EVT_FEAT_PERIODIC
|
117 CLOCK_EVT_FEAT_ONESHOT
,
118 .set_state_shutdown
= clkevt_shutdown
,
119 .set_state_periodic
= clkevt_set_periodic
,
120 .set_state_oneshot
= clkevt_set_oneshot
,
121 .tick_resume
= clkevt_shutdown
,
122 .set_next_event
= clkevt_set_next_event
,
126 static struct irqaction integrator_timer_irq
= {
128 .flags
= IRQF_TIMER
| IRQF_IRQPOLL
,
129 .handler
= integrator_timer_interrupt
,
130 .dev_id
= &integrator_clockevent
,
133 static int integrator_clockevent_init(unsigned long inrate
,
134 void __iomem
*base
, int irq
)
136 unsigned long rate
= inrate
;
137 unsigned int ctrl
= 0;
141 /* Calculate and program a divisor */
142 if (rate
> 0x100000 * HZ
) {
144 ctrl
|= TIMER_CTRL_DIV256
;
145 } else if (rate
> 0x10000 * HZ
) {
147 ctrl
|= TIMER_CTRL_DIV16
;
149 timer_reload
= rate
/ HZ
;
150 writel(ctrl
, clkevt_base
+ TIMER_CTRL
);
152 ret
= setup_irq(irq
, &integrator_timer_irq
);
156 clockevents_config_and_register(&integrator_clockevent
,
163 static int __init
integrator_ap_timer_init_of(struct device_node
*node
)
171 struct device_node
*alias_node
;
173 base
= of_io_request_and_map(node
, 0, "integrator-timer");
175 return PTR_ERR(base
);
177 clk
= of_clk_get(node
, 0);
179 pr_err("No clock for %pOFn\n", node
);
182 clk_prepare_enable(clk
);
183 rate
= clk_get_rate(clk
);
184 writel(0, base
+ TIMER_CTRL
);
186 err
= of_property_read_string(of_aliases
,
187 "arm,timer-primary", &path
);
189 pr_warn("Failed to read property\n");
193 alias_node
= of_find_node_by_path(path
);
196 * The pointer is used as an identifier not as a pointer, we
197 * can drop the refcount on the of__node immediately after
200 of_node_put(alias_node
);
202 if (node
== alias_node
)
203 /* The primary timer lacks IRQ, use as clocksource */
204 return integrator_clocksource_init(rate
, base
);
206 err
= of_property_read_string(of_aliases
,
207 "arm,timer-secondary", &path
);
209 pr_warn("Failed to read property\n");
213 alias_node
= of_find_node_by_path(path
);
215 of_node_put(alias_node
);
217 if (node
== alias_node
) {
218 /* The secondary timer will drive the clock event */
219 irq
= irq_of_parse_and_map(node
, 0);
220 return integrator_clockevent_init(rate
, base
, irq
);
223 pr_info("Timer @%p unused\n", base
);
224 clk_disable_unprepare(clk
);
229 TIMER_OF_DECLARE(integrator_ap_timer
, "arm,integrator-timer",
230 integrator_ap_timer_init_of
);