File Index
Files and directories
Sign in
FILE

timer-rda.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clocksource/timer-rda.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * RDA8810PL SoC timer driver
  4 *
  5 * Copyright RDA Microelectronics Company Limited
  6 * Copyright (c) 2017 Andreas Färber
  7 * Copyright (c) 2018 Manivannan Sadhasivam
  8 *
  9 * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
 10 * Each timer provides optional interrupt support. In this driver, OSTIMER is
 11 * used for clockevents and HWTIMER is used for clocksource.
 12 */
 13
 14#include <linux/init.h>
 15#include <linux/interrupt.h>
 16#include <linux/sched_clock.h>
 17
 18#include "timer-of.h"
 19
 20#define RDA_OSTIMER_LOADVAL_L	0x000
 21#define RDA_OSTIMER_CTRL	0x004
 22#define RDA_HWTIMER_LOCKVAL_L	0x024
 23#define RDA_HWTIMER_LOCKVAL_H	0x028
 24#define RDA_TIMER_IRQ_MASK_SET	0x02c
 25#define RDA_TIMER_IRQ_MASK_CLR	0x030
 26#define RDA_TIMER_IRQ_CLR	0x034
 27
 28#define RDA_OSTIMER_CTRL_ENABLE		BIT(24)
 29#define RDA_OSTIMER_CTRL_REPEAT		BIT(28)
 30#define RDA_OSTIMER_CTRL_LOAD		BIT(30)
 31
 32#define RDA_TIMER_IRQ_MASK_OSTIMER	BIT(0)
 33
 34#define RDA_TIMER_IRQ_CLR_OSTIMER	BIT(0)
 35
 36static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)
 37{
 38	u32 ctrl, load_l;
 39
 40	load_l = (u32)cycles;
 41	ctrl = ((cycles >> 32) & 0xffffff);
 42	ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;
 43	if (periodic)
 44		ctrl |= RDA_OSTIMER_CTRL_REPEAT;
 45
 46	/* Enable ostimer interrupt first */
 47	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
 48		       base + RDA_TIMER_IRQ_MASK_SET);
 49
 50	/* Write low 32 bits first, high 24 bits are with ctrl */
 51	writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);
 52	writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);
 53
 54	return 0;
 55}
 56
 57static int rda_ostimer_stop(void __iomem *base)
 58{
 59	/* Disable ostimer interrupt first */
 60	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
 61		       base + RDA_TIMER_IRQ_MASK_CLR);
 62
 63	writel_relaxed(0, base + RDA_OSTIMER_CTRL);
 64
 65	return 0;
 66}
 67
 68static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)
 69{
 70	struct timer_of *to = to_timer_of(evt);
 71
 72	rda_ostimer_stop(timer_of_base(to));
 73
 74	return 0;
 75}
 76
 77static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)
 78{
 79	struct timer_of *to = to_timer_of(evt);
 80
 81	rda_ostimer_stop(timer_of_base(to));
 82
 83	return 0;
 84}
 85
 86static int rda_ostimer_set_state_periodic(struct clock_event_device *evt)
 87{
 88	struct timer_of *to = to_timer_of(evt);
 89	unsigned long cycles_per_jiffy;
 90
 91	rda_ostimer_stop(timer_of_base(to));
 92
 93	cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *
 94			     evt->mult) >> evt->shift;
 95	rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);
 96
 97	return 0;
 98}
 99
100static int rda_ostimer_tick_resume(struct clock_event_device *evt)
101{
102	return 0;
103}
104
105static int rda_ostimer_set_next_event(unsigned long evt,
106				      struct clock_event_device *ev)
107{
108	struct timer_of *to = to_timer_of(ev);
109
110	rda_ostimer_start(timer_of_base(to), false, evt);
111
112	return 0;
113}
114
115static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)
116{
117	struct clock_event_device *evt = dev_id;
118	struct timer_of *to = to_timer_of(evt);
119
120	/* clear timer int */
121	writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,
122		       timer_of_base(to) + RDA_TIMER_IRQ_CLR);
123
124	if (evt->event_handler)
125		evt->event_handler(evt);
126
127	return IRQ_HANDLED;
128}
129
130static struct timer_of rda_ostimer_of = {
131	.flags = TIMER_OF_IRQ | TIMER_OF_BASE,
132
133	.clkevt = {
134		.name = "rda-ostimer",
135		.rating = 250,
136		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
137			    CLOCK_EVT_FEAT_DYNIRQ,
138		.set_state_shutdown = rda_ostimer_set_state_shutdown,
139		.set_state_oneshot = rda_ostimer_set_state_oneshot,
140		.set_state_periodic = rda_ostimer_set_state_periodic,
141		.tick_resume = rda_ostimer_tick_resume,
142		.set_next_event	= rda_ostimer_set_next_event,
143	},
144
145	.of_base = {
146		.name = "rda-timer",
147		.index = 0,
148	},
149
150	.of_irq = {
151		.name = "ostimer",
152		.handler = rda_ostimer_interrupt,
153		.flags = IRQF_TIMER,
154	},
155};
156
157static u64 rda_hwtimer_clocksource_read(void)
158{
159	void __iomem *base = timer_of_base(&rda_ostimer_of);
160	u32 lo, hi;
161
162	/* Always read low 32 bits first */
163	do {
164		lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);
165		hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);
166	} while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));
167
168	return ((u64)hi << 32) | lo;
169}
170
171static u64 rda_hwtimer_read(struct clocksource *cs)
172{
173	return rda_hwtimer_clocksource_read();
174}
175
176static struct clocksource rda_hwtimer_clocksource = {
177	.name           = "rda-timer",
178	.rating         = 400,
179	.read           = rda_hwtimer_read,
180	.mask           = CLOCKSOURCE_MASK(64),
181	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
182};
183
184static int __init rda_timer_init(struct device_node *np)
185{
186	unsigned long rate = 2000000;
187	int ret;
188
189	ret = timer_of_init(np, &rda_ostimer_of);
190	if (ret)
191		return ret;
192
193	clocksource_register_hz(&rda_hwtimer_clocksource, rate);
194	sched_clock_register(rda_hwtimer_clocksource_read, 64, rate);
195
196	clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
197					0x2, UINT_MAX);
198
199	return 0;
200}
201
202TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);
~/ Read-only file preview.