Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * System timer for CSR SiRFprimaII
  3 *
  4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
  5 *
  6 * Licensed under GPLv2 or later.
  7 */
  8
  9#include <linux/kernel.h>
 10#include <linux/interrupt.h>
 11#include <linux/clockchips.h>
 12#include <linux/clocksource.h>
 13#include <linux/bitops.h>
 14#include <linux/irq.h>
 15#include <linux/clk.h>
 16#include <linux/err.h>
 17#include <linux/slab.h>
 18#include <linux/of.h>
 19#include <linux/of_irq.h>
 20#include <linux/of_address.h>
 21#include <linux/sched_clock.h>
 22
 23#define PRIMA2_CLOCK_FREQ 1000000
 24
 25#define SIRFSOC_TIMER_COUNTER_LO	0x0000
 26#define SIRFSOC_TIMER_COUNTER_HI	0x0004
 27#define SIRFSOC_TIMER_MATCH_0		0x0008
 28#define SIRFSOC_TIMER_MATCH_1		0x000C
 29#define SIRFSOC_TIMER_MATCH_2		0x0010
 30#define SIRFSOC_TIMER_MATCH_3		0x0014
 31#define SIRFSOC_TIMER_MATCH_4		0x0018
 32#define SIRFSOC_TIMER_MATCH_5		0x001C
 33#define SIRFSOC_TIMER_STATUS		0x0020
 34#define SIRFSOC_TIMER_INT_EN		0x0024
 35#define SIRFSOC_TIMER_WATCHDOG_EN	0x0028
 36#define SIRFSOC_TIMER_DIV		0x002C
 37#define SIRFSOC_TIMER_LATCH		0x0030
 38#define SIRFSOC_TIMER_LATCHED_LO	0x0034
 39#define SIRFSOC_TIMER_LATCHED_HI	0x0038
 40
 41#define SIRFSOC_TIMER_WDT_INDEX		5
 42
 43#define SIRFSOC_TIMER_LATCH_BIT	 BIT(0)
 44
 45#define SIRFSOC_TIMER_REG_CNT 11
 46
 47static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
 48	SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2,
 49	SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5,
 50	SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV,
 51	SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI,
 52};
 53
 54static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
 55
 56static void __iomem *sirfsoc_timer_base;
 57
 58/* timer0 interrupt handler */
 59static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
 60{
 61	struct clock_event_device *ce = dev_id;
 62
 63	WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) &
 64		BIT(0)));
 65
 66	/* clear timer0 interrupt */
 67	writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
 68
 69	ce->event_handler(ce);
 70
 71	return IRQ_HANDLED;
 72}
 73
 74/* read 64-bit timer counter */
 75static u64 notrace sirfsoc_timer_read(struct clocksource *cs)
 76{
 77	u64 cycles;
 78
 79	/* latch the 64-bit timer counter */
 80	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
 81		sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 82	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
 83	cycles = (cycles << 32) |
 84		readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 85
 86	return cycles;
 87}
 88
 89static int sirfsoc_timer_set_next_event(unsigned long delta,
 90	struct clock_event_device *ce)
 91{
 92	unsigned long now, next;
 93
 94	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
 95		sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 96	now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 97	next = now + delta;
 98	writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
 99	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
100		sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
101	now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
102
103	return next - now > delta ? -ETIME : 0;
104}
105
106static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
107{
108	u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
109
110	writel_relaxed(val & ~BIT(0),
111		       sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
112	return 0;
113}
114
115static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt)
116{
117	u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
118
119	writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
120	return 0;
121}
122
123static void sirfsoc_clocksource_suspend(struct clocksource *cs)
124{
125	int i;
126
127	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
128		sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
129
130	for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
131		sirfsoc_timer_reg_val[i] =
132			readl_relaxed(sirfsoc_timer_base +
133				sirfsoc_timer_reg_list[i]);
134}
135
136static void sirfsoc_clocksource_resume(struct clocksource *cs)
137{
138	int i;
139
140	for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
141		writel_relaxed(sirfsoc_timer_reg_val[i],
142			sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
143
144	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
145		sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
146	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
147		sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
148}
149
150static struct clock_event_device sirfsoc_clockevent = {
151	.name = "sirfsoc_clockevent",
152	.rating = 200,
153	.features = CLOCK_EVT_FEAT_ONESHOT,
154	.set_state_shutdown = sirfsoc_timer_shutdown,
155	.set_state_oneshot = sirfsoc_timer_set_oneshot,
156	.set_next_event = sirfsoc_timer_set_next_event,
157};
158
159static struct clocksource sirfsoc_clocksource = {
160	.name = "sirfsoc_clocksource",
161	.rating = 200,
162	.mask = CLOCKSOURCE_MASK(64),
163	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
164	.read = sirfsoc_timer_read,
165	.suspend = sirfsoc_clocksource_suspend,
166	.resume = sirfsoc_clocksource_resume,
167};
168
169static struct irqaction sirfsoc_timer_irq = {
170	.name = "sirfsoc_timer0",
171	.flags = IRQF_TIMER,
172	.irq = 0,
173	.handler = sirfsoc_timer_interrupt,
174	.dev_id = &sirfsoc_clockevent,
175};
176
177/* Overwrite weak default sched_clock with more precise one */
178static u64 notrace sirfsoc_read_sched_clock(void)
179{
180	return sirfsoc_timer_read(NULL);
181}
182
183static void __init sirfsoc_clockevent_init(void)
184{
185	sirfsoc_clockevent.cpumask = cpumask_of(0);
186	clockevents_config_and_register(&sirfsoc_clockevent, PRIMA2_CLOCK_FREQ,
187					2, -2);
188}
189
190/* initialize the kernel jiffy timer source */
191static int __init sirfsoc_prima2_timer_init(struct device_node *np)
192{
193	unsigned long rate;
194	struct clk *clk;
195	int ret;
196
197	clk = of_clk_get(np, 0);
198	if (IS_ERR(clk)) {
199		pr_err("Failed to get clock\n");
200		return PTR_ERR(clk);
201	}
202
203	ret = clk_prepare_enable(clk);
204	if (ret) {
205		pr_err("Failed to enable clock\n");
206		return ret;
207	}
208
209	rate = clk_get_rate(clk);
210
211	if (rate < PRIMA2_CLOCK_FREQ || rate % PRIMA2_CLOCK_FREQ) {
212		pr_err("Invalid clock rate\n");
213		return -EINVAL;
214	}
215
216	sirfsoc_timer_base = of_iomap(np, 0);
217	if (!sirfsoc_timer_base) {
218		pr_err("unable to map timer cpu registers\n");
219		return -ENXIO;
220	}
221
222	sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
223
224	writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1,
225		sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
226	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
227	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
228	writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
229
230	ret = clocksource_register_hz(&sirfsoc_clocksource, PRIMA2_CLOCK_FREQ);
231	if (ret) {
232		pr_err("Failed to register clocksource\n");
233		return ret;
234	}
235
236	sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ);
237
238	ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
239	if (ret) {
240		pr_err("Failed to setup irq\n");
241		return ret;
242	}
243
244	sirfsoc_clockevent_init();
245
246	return 0;
247}
248TIMER_OF_DECLARE(sirfsoc_prima2_timer,
249	"sirf,prima2-tick", sirfsoc_prima2_timer_init);