xref: /linux-6.15/arch/microblaze/kernel/timer.c (revision bc1ce713)
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