xref: /linux/drivers/clocksource/renesas-ostm.c (revision fb6002a8268c493435d0e6d0d6ad17873919a7f6)
1*fb6002a8SChris Brandt /*
2*fb6002a8SChris Brandt  * Renesas Timer Support - OSTM
3*fb6002a8SChris Brandt  *
4*fb6002a8SChris Brandt  * Copyright (C) 2017 Renesas Electronics America, Inc.
5*fb6002a8SChris Brandt  * Copyright (C) 2017 Chris Brandt
6*fb6002a8SChris Brandt  *
7*fb6002a8SChris Brandt  * This program is free software; you can redistribute it and/or modify
8*fb6002a8SChris Brandt  * it under the terms of the GNU General Public License as published by
9*fb6002a8SChris Brandt  * the Free Software Foundation; either version 2 of the License
10*fb6002a8SChris Brandt  *
11*fb6002a8SChris Brandt  * This program is distributed in the hope that it will be useful,
12*fb6002a8SChris Brandt  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*fb6002a8SChris Brandt  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*fb6002a8SChris Brandt  * GNU General Public License for more details.
15*fb6002a8SChris Brandt  *
16*fb6002a8SChris Brandt  */
17*fb6002a8SChris Brandt 
18*fb6002a8SChris Brandt #include <linux/of_address.h>
19*fb6002a8SChris Brandt #include <linux/of_irq.h>
20*fb6002a8SChris Brandt #include <linux/clk.h>
21*fb6002a8SChris Brandt #include <linux/clockchips.h>
22*fb6002a8SChris Brandt #include <linux/interrupt.h>
23*fb6002a8SChris Brandt #include <linux/sched_clock.h>
24*fb6002a8SChris Brandt #include <linux/slab.h>
25*fb6002a8SChris Brandt 
26*fb6002a8SChris Brandt /*
27*fb6002a8SChris Brandt  * The OSTM contains independent channels.
28*fb6002a8SChris Brandt  * The first OSTM channel probed will be set up as a free running
29*fb6002a8SChris Brandt  * clocksource. Additionally we will use this clocksource for the system
30*fb6002a8SChris Brandt  * schedule timer sched_clock().
31*fb6002a8SChris Brandt  *
32*fb6002a8SChris Brandt  * The second (or more) channel probed will be set up as an interrupt
33*fb6002a8SChris Brandt  * driven clock event.
34*fb6002a8SChris Brandt  */
35*fb6002a8SChris Brandt 
36*fb6002a8SChris Brandt struct ostm_device {
37*fb6002a8SChris Brandt 	void __iomem *base;
38*fb6002a8SChris Brandt 	unsigned long ticks_per_jiffy;
39*fb6002a8SChris Brandt 	struct clock_event_device ced;
40*fb6002a8SChris Brandt };
41*fb6002a8SChris Brandt 
42*fb6002a8SChris Brandt static void __iomem *system_clock;	/* For sched_clock() */
43*fb6002a8SChris Brandt 
44*fb6002a8SChris Brandt /* OSTM REGISTERS */
45*fb6002a8SChris Brandt #define	OSTM_CMP		0x000	/* RW,32 */
46*fb6002a8SChris Brandt #define	OSTM_CNT		0x004	/* R,32 */
47*fb6002a8SChris Brandt #define	OSTM_TE			0x010	/* R,8 */
48*fb6002a8SChris Brandt #define	OSTM_TS			0x014	/* W,8 */
49*fb6002a8SChris Brandt #define	OSTM_TT			0x018	/* W,8 */
50*fb6002a8SChris Brandt #define	OSTM_CTL		0x020	/* RW,8 */
51*fb6002a8SChris Brandt 
52*fb6002a8SChris Brandt #define	TE			0x01
53*fb6002a8SChris Brandt #define	TS			0x01
54*fb6002a8SChris Brandt #define	TT			0x01
55*fb6002a8SChris Brandt #define	CTL_PERIODIC		0x00
56*fb6002a8SChris Brandt #define	CTL_ONESHOT		0x02
57*fb6002a8SChris Brandt #define	CTL_FREERUN		0x02
58*fb6002a8SChris Brandt 
59*fb6002a8SChris Brandt static struct ostm_device *ced_to_ostm(struct clock_event_device *ced)
60*fb6002a8SChris Brandt {
61*fb6002a8SChris Brandt 	return container_of(ced, struct ostm_device, ced);
62*fb6002a8SChris Brandt }
63*fb6002a8SChris Brandt 
64*fb6002a8SChris Brandt static void ostm_timer_stop(struct ostm_device *ostm)
65*fb6002a8SChris Brandt {
66*fb6002a8SChris Brandt 	if (readb(ostm->base + OSTM_TE) & TE) {
67*fb6002a8SChris Brandt 		writeb(TT, ostm->base + OSTM_TT);
68*fb6002a8SChris Brandt 
69*fb6002a8SChris Brandt 		/*
70*fb6002a8SChris Brandt 		 * Read back the register simply to confirm the write operation
71*fb6002a8SChris Brandt 		 * has completed since I/O writes can sometimes get queued by
72*fb6002a8SChris Brandt 		 * the bus architecture.
73*fb6002a8SChris Brandt 		 */
74*fb6002a8SChris Brandt 		while (readb(ostm->base + OSTM_TE) & TE)
75*fb6002a8SChris Brandt 			;
76*fb6002a8SChris Brandt 	}
77*fb6002a8SChris Brandt }
78*fb6002a8SChris Brandt 
79*fb6002a8SChris Brandt static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate)
80*fb6002a8SChris Brandt {
81*fb6002a8SChris Brandt 	/*
82*fb6002a8SChris Brandt 	 * irq not used (clock sources don't use interrupts)
83*fb6002a8SChris Brandt 	 */
84*fb6002a8SChris Brandt 
85*fb6002a8SChris Brandt 	ostm_timer_stop(ostm);
86*fb6002a8SChris Brandt 
87*fb6002a8SChris Brandt 	writel(0, ostm->base + OSTM_CMP);
88*fb6002a8SChris Brandt 	writeb(CTL_FREERUN, ostm->base + OSTM_CTL);
89*fb6002a8SChris Brandt 	writeb(TS, ostm->base + OSTM_TS);
90*fb6002a8SChris Brandt 
91*fb6002a8SChris Brandt 	return clocksource_mmio_init(ostm->base + OSTM_CNT,
92*fb6002a8SChris Brandt 			"ostm", rate,
93*fb6002a8SChris Brandt 			300, 32, clocksource_mmio_readl_up);
94*fb6002a8SChris Brandt }
95*fb6002a8SChris Brandt 
96*fb6002a8SChris Brandt static u64 notrace ostm_read_sched_clock(void)
97*fb6002a8SChris Brandt {
98*fb6002a8SChris Brandt 	return readl(system_clock);
99*fb6002a8SChris Brandt }
100*fb6002a8SChris Brandt 
101*fb6002a8SChris Brandt static void __init ostm_init_sched_clock(struct ostm_device *ostm,
102*fb6002a8SChris Brandt 			unsigned long rate)
103*fb6002a8SChris Brandt {
104*fb6002a8SChris Brandt 	system_clock = ostm->base + OSTM_CNT;
105*fb6002a8SChris Brandt 	sched_clock_register(ostm_read_sched_clock, 32, rate);
106*fb6002a8SChris Brandt }
107*fb6002a8SChris Brandt 
108*fb6002a8SChris Brandt static int ostm_clock_event_next(unsigned long delta,
109*fb6002a8SChris Brandt 				     struct clock_event_device *ced)
110*fb6002a8SChris Brandt {
111*fb6002a8SChris Brandt 	struct ostm_device *ostm = ced_to_ostm(ced);
112*fb6002a8SChris Brandt 
113*fb6002a8SChris Brandt 	ostm_timer_stop(ostm);
114*fb6002a8SChris Brandt 
115*fb6002a8SChris Brandt 	writel(delta, ostm->base + OSTM_CMP);
116*fb6002a8SChris Brandt 	writeb(CTL_ONESHOT, ostm->base + OSTM_CTL);
117*fb6002a8SChris Brandt 	writeb(TS, ostm->base + OSTM_TS);
118*fb6002a8SChris Brandt 
119*fb6002a8SChris Brandt 	return 0;
120*fb6002a8SChris Brandt }
121*fb6002a8SChris Brandt 
122*fb6002a8SChris Brandt static int ostm_shutdown(struct clock_event_device *ced)
123*fb6002a8SChris Brandt {
124*fb6002a8SChris Brandt 	struct ostm_device *ostm = ced_to_ostm(ced);
125*fb6002a8SChris Brandt 
126*fb6002a8SChris Brandt 	ostm_timer_stop(ostm);
127*fb6002a8SChris Brandt 
128*fb6002a8SChris Brandt 	return 0;
129*fb6002a8SChris Brandt }
130*fb6002a8SChris Brandt static int ostm_set_periodic(struct clock_event_device *ced)
131*fb6002a8SChris Brandt {
132*fb6002a8SChris Brandt 	struct ostm_device *ostm = ced_to_ostm(ced);
133*fb6002a8SChris Brandt 
134*fb6002a8SChris Brandt 	if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
135*fb6002a8SChris Brandt 		ostm_timer_stop(ostm);
136*fb6002a8SChris Brandt 
137*fb6002a8SChris Brandt 	writel(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP);
138*fb6002a8SChris Brandt 	writeb(CTL_PERIODIC, ostm->base + OSTM_CTL);
139*fb6002a8SChris Brandt 	writeb(TS, ostm->base + OSTM_TS);
140*fb6002a8SChris Brandt 
141*fb6002a8SChris Brandt 	return 0;
142*fb6002a8SChris Brandt }
143*fb6002a8SChris Brandt 
144*fb6002a8SChris Brandt static int ostm_set_oneshot(struct clock_event_device *ced)
145*fb6002a8SChris Brandt {
146*fb6002a8SChris Brandt 	struct ostm_device *ostm = ced_to_ostm(ced);
147*fb6002a8SChris Brandt 
148*fb6002a8SChris Brandt 	ostm_timer_stop(ostm);
149*fb6002a8SChris Brandt 
150*fb6002a8SChris Brandt 	return 0;
151*fb6002a8SChris Brandt }
152*fb6002a8SChris Brandt 
153*fb6002a8SChris Brandt static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id)
154*fb6002a8SChris Brandt {
155*fb6002a8SChris Brandt 	struct ostm_device *ostm = dev_id;
156*fb6002a8SChris Brandt 
157*fb6002a8SChris Brandt 	if (clockevent_state_oneshot(&ostm->ced))
158*fb6002a8SChris Brandt 		ostm_timer_stop(ostm);
159*fb6002a8SChris Brandt 
160*fb6002a8SChris Brandt 	/* notify clockevent layer */
161*fb6002a8SChris Brandt 	if (ostm->ced.event_handler)
162*fb6002a8SChris Brandt 		ostm->ced.event_handler(&ostm->ced);
163*fb6002a8SChris Brandt 
164*fb6002a8SChris Brandt 	return IRQ_HANDLED;
165*fb6002a8SChris Brandt }
166*fb6002a8SChris Brandt 
167*fb6002a8SChris Brandt static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq,
168*fb6002a8SChris Brandt 			unsigned long rate)
169*fb6002a8SChris Brandt {
170*fb6002a8SChris Brandt 	struct clock_event_device *ced = &ostm->ced;
171*fb6002a8SChris Brandt 	int ret = -ENXIO;
172*fb6002a8SChris Brandt 
173*fb6002a8SChris Brandt 	ret = request_irq(irq, ostm_timer_interrupt,
174*fb6002a8SChris Brandt 			  IRQF_TIMER | IRQF_IRQPOLL,
175*fb6002a8SChris Brandt 			  "ostm", ostm);
176*fb6002a8SChris Brandt 	if (ret) {
177*fb6002a8SChris Brandt 		pr_err("ostm: failed to request irq\n");
178*fb6002a8SChris Brandt 		return ret;
179*fb6002a8SChris Brandt 	}
180*fb6002a8SChris Brandt 
181*fb6002a8SChris Brandt 	ced->name = "ostm";
182*fb6002a8SChris Brandt 	ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
183*fb6002a8SChris Brandt 	ced->set_state_shutdown = ostm_shutdown;
184*fb6002a8SChris Brandt 	ced->set_state_periodic = ostm_set_periodic;
185*fb6002a8SChris Brandt 	ced->set_state_oneshot = ostm_set_oneshot;
186*fb6002a8SChris Brandt 	ced->set_next_event = ostm_clock_event_next;
187*fb6002a8SChris Brandt 	ced->shift = 32;
188*fb6002a8SChris Brandt 	ced->rating = 300;
189*fb6002a8SChris Brandt 	ced->cpumask = cpumask_of(0);
190*fb6002a8SChris Brandt 	clockevents_config_and_register(ced, rate, 0xf, 0xffffffff);
191*fb6002a8SChris Brandt 
192*fb6002a8SChris Brandt 	return 0;
193*fb6002a8SChris Brandt }
194*fb6002a8SChris Brandt 
195*fb6002a8SChris Brandt static int __init ostm_init(struct device_node *np)
196*fb6002a8SChris Brandt {
197*fb6002a8SChris Brandt 	struct ostm_device *ostm;
198*fb6002a8SChris Brandt 	int ret = -EFAULT;
199*fb6002a8SChris Brandt 	struct clk *ostm_clk = NULL;
200*fb6002a8SChris Brandt 	int irq;
201*fb6002a8SChris Brandt 	unsigned long rate;
202*fb6002a8SChris Brandt 
203*fb6002a8SChris Brandt 	ostm = kzalloc(sizeof(*ostm), GFP_KERNEL);
204*fb6002a8SChris Brandt 	if (!ostm)
205*fb6002a8SChris Brandt 		return -ENOMEM;
206*fb6002a8SChris Brandt 
207*fb6002a8SChris Brandt 	ostm->base = of_iomap(np, 0);
208*fb6002a8SChris Brandt 	if (!ostm->base) {
209*fb6002a8SChris Brandt 		pr_err("ostm: failed to remap I/O memory\n");
210*fb6002a8SChris Brandt 		goto err;
211*fb6002a8SChris Brandt 	}
212*fb6002a8SChris Brandt 
213*fb6002a8SChris Brandt 	irq = irq_of_parse_and_map(np, 0);
214*fb6002a8SChris Brandt 	if (irq < 0) {
215*fb6002a8SChris Brandt 		pr_err("ostm: Failed to get irq\n");
216*fb6002a8SChris Brandt 		goto err;
217*fb6002a8SChris Brandt 	}
218*fb6002a8SChris Brandt 
219*fb6002a8SChris Brandt 	ostm_clk = of_clk_get(np, 0);
220*fb6002a8SChris Brandt 	if (IS_ERR(ostm_clk)) {
221*fb6002a8SChris Brandt 		pr_err("ostm: Failed to get clock\n");
222*fb6002a8SChris Brandt 		ostm_clk = NULL;
223*fb6002a8SChris Brandt 		goto err;
224*fb6002a8SChris Brandt 	}
225*fb6002a8SChris Brandt 
226*fb6002a8SChris Brandt 	ret = clk_prepare_enable(ostm_clk);
227*fb6002a8SChris Brandt 	if (ret) {
228*fb6002a8SChris Brandt 		pr_err("ostm: Failed to enable clock\n");
229*fb6002a8SChris Brandt 		goto err;
230*fb6002a8SChris Brandt 	}
231*fb6002a8SChris Brandt 
232*fb6002a8SChris Brandt 	rate = clk_get_rate(ostm_clk);
233*fb6002a8SChris Brandt 	ostm->ticks_per_jiffy = (rate + HZ / 2) / HZ;
234*fb6002a8SChris Brandt 
235*fb6002a8SChris Brandt 	/*
236*fb6002a8SChris Brandt 	 * First probed device will be used as system clocksource. Any
237*fb6002a8SChris Brandt 	 * additional devices will be used as clock events.
238*fb6002a8SChris Brandt 	 */
239*fb6002a8SChris Brandt 	if (!system_clock) {
240*fb6002a8SChris Brandt 		ret = ostm_init_clksrc(ostm, rate);
241*fb6002a8SChris Brandt 
242*fb6002a8SChris Brandt 		if (!ret) {
243*fb6002a8SChris Brandt 			ostm_init_sched_clock(ostm, rate);
244*fb6002a8SChris Brandt 			pr_info("ostm: used for clocksource\n");
245*fb6002a8SChris Brandt 		}
246*fb6002a8SChris Brandt 
247*fb6002a8SChris Brandt 	} else {
248*fb6002a8SChris Brandt 		ret = ostm_init_clkevt(ostm, irq, rate);
249*fb6002a8SChris Brandt 
250*fb6002a8SChris Brandt 		if (!ret)
251*fb6002a8SChris Brandt 			pr_info("ostm: used for clock events\n");
252*fb6002a8SChris Brandt 	}
253*fb6002a8SChris Brandt 
254*fb6002a8SChris Brandt err:
255*fb6002a8SChris Brandt 	if (ret) {
256*fb6002a8SChris Brandt 		clk_disable_unprepare(ostm_clk);
257*fb6002a8SChris Brandt 		iounmap(ostm->base);
258*fb6002a8SChris Brandt 		kfree(ostm);
259*fb6002a8SChris Brandt 		return ret;
260*fb6002a8SChris Brandt 	}
261*fb6002a8SChris Brandt 
262*fb6002a8SChris Brandt 	return 0;
263*fb6002a8SChris Brandt }
264*fb6002a8SChris Brandt 
265*fb6002a8SChris Brandt CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init);
266