Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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_address.h>
 20#include <mach/map.h>
 21#include <asm/mach/time.h>
 22
 23#define SIRFSOC_TIMER_COUNTER_LO	0x0000
 24#define SIRFSOC_TIMER_COUNTER_HI	0x0004
 25#define SIRFSOC_TIMER_MATCH_0		0x0008
 26#define SIRFSOC_TIMER_MATCH_1		0x000C
 27#define SIRFSOC_TIMER_MATCH_2		0x0010
 28#define SIRFSOC_TIMER_MATCH_3		0x0014
 29#define SIRFSOC_TIMER_MATCH_4		0x0018
 30#define SIRFSOC_TIMER_MATCH_5		0x001C
 31#define SIRFSOC_TIMER_STATUS		0x0020
 32#define SIRFSOC_TIMER_INT_EN		0x0024
 33#define SIRFSOC_TIMER_WATCHDOG_EN	0x0028
 34#define SIRFSOC_TIMER_DIV		0x002C
 35#define SIRFSOC_TIMER_LATCH		0x0030
 36#define SIRFSOC_TIMER_LATCHED_LO	0x0034
 37#define SIRFSOC_TIMER_LATCHED_HI	0x0038
 38
 39#define SIRFSOC_TIMER_WDT_INDEX		5
 40
 41#define SIRFSOC_TIMER_LATCH_BIT	 BIT(0)
 42
 43static void __iomem *sirfsoc_timer_base;
 44static void __init sirfsoc_of_timer_map(void);
 45
 46/* timer0 interrupt handler */
 47static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
 48{
 49	struct clock_event_device *ce = dev_id;
 50
 51	WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0)));
 52
 53	/* clear timer0 interrupt */
 54	writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
 55
 56	ce->event_handler(ce);
 57
 58	return IRQ_HANDLED;
 59}
 60
 61/* read 64-bit timer counter */
 62static cycle_t sirfsoc_timer_read(struct clocksource *cs)
 63{
 64	u64 cycles;
 65
 66	/* latch the 64-bit timer counter */
 67	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 68	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
 69	cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 70
 71	return cycles;
 72}
 73
 74static int sirfsoc_timer_set_next_event(unsigned long delta,
 75	struct clock_event_device *ce)
 76{
 77	unsigned long now, next;
 78
 79	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 80	now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 81	next = now + delta;
 82	writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
 83	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 84	now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 85
 86	return next - now > delta ? -ETIME : 0;
 87}
 88
 89static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
 90	struct clock_event_device *ce)
 91{
 92	u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 93	switch (mode) {
 94	case CLOCK_EVT_MODE_PERIODIC:
 95		WARN_ON(1);
 96		break;
 97	case CLOCK_EVT_MODE_ONESHOT:
 98		writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 99		break;
100	case CLOCK_EVT_MODE_SHUTDOWN:
101		writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
102		break;
103	case CLOCK_EVT_MODE_UNUSED:
104	case CLOCK_EVT_MODE_RESUME:
105		break;
106	}
107}
108
109static struct clock_event_device sirfsoc_clockevent = {
110	.name = "sirfsoc_clockevent",
111	.rating = 200,
112	.features = CLOCK_EVT_FEAT_ONESHOT,
113	.set_mode = sirfsoc_timer_set_mode,
114	.set_next_event = sirfsoc_timer_set_next_event,
115};
116
117static struct clocksource sirfsoc_clocksource = {
118	.name = "sirfsoc_clocksource",
119	.rating = 200,
120	.mask = CLOCKSOURCE_MASK(64),
121	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
122	.read = sirfsoc_timer_read,
123};
124
125static struct irqaction sirfsoc_timer_irq = {
126	.name = "sirfsoc_timer0",
127	.flags = IRQF_TIMER,
128	.irq = 0,
129	.handler = sirfsoc_timer_interrupt,
130	.dev_id = &sirfsoc_clockevent,
131};
132
133/* Overwrite weak default sched_clock with more precise one */
134unsigned long long notrace sched_clock(void)
135{
136	static int is_mapped = 0;
137
138	/*
139	 * sched_clock is called earlier than .init of sys_timer
140	 * if we map timer memory in .init of sys_timer, system
141	 * will panic due to illegal memory access
142	 */
143	if(!is_mapped) {
144		sirfsoc_of_timer_map();
145		is_mapped = 1;
146	}
147
148	return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE);
149}
150
151static void __init sirfsoc_clockevent_init(void)
152{
153	clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
154
155	sirfsoc_clockevent.max_delta_ns =
156		clockevent_delta2ns(-2, &sirfsoc_clockevent);
157	sirfsoc_clockevent.min_delta_ns =
158		clockevent_delta2ns(2, &sirfsoc_clockevent);
159
160	sirfsoc_clockevent.cpumask = cpumask_of(0);
161	clockevents_register_device(&sirfsoc_clockevent);
162}
163
164/* initialize the kernel jiffy timer source */
165static void __init sirfsoc_timer_init(void)
166{
167	unsigned long rate;
168
169	/* timer's input clock is io clock */
170	struct clk *clk = clk_get_sys("io", NULL);
171
172	BUG_ON(IS_ERR(clk));
173
174	rate = clk_get_rate(clk);
175
176	BUG_ON(rate < CLOCK_TICK_RATE);
177	BUG_ON(rate % CLOCK_TICK_RATE);
178
179	writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
180	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
181	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
182	writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
183
184	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
185
186	BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
187
188	sirfsoc_clockevent_init();
189}
190
191static struct of_device_id timer_ids[] = {
192	{ .compatible = "sirf,prima2-tick" },
193	{},
194};
195
196static void __init sirfsoc_of_timer_map(void)
197{
198	struct device_node *np;
199	const unsigned int *intspec;
200
201	np = of_find_matching_node(NULL, timer_ids);
202	if (!np)
203		panic("unable to find compatible timer node in dtb\n");
204	sirfsoc_timer_base = of_iomap(np, 0);
205	if (!sirfsoc_timer_base)
206		panic("unable to map timer cpu registers\n");
207
208	/* Get the interrupts property */
209	intspec = of_get_property(np, "interrupts", NULL);
210	BUG_ON(!intspec);
211	sirfsoc_timer_irq.irq = be32_to_cpup(intspec);
212
213	of_node_put(np);
214}
215
216struct sys_timer sirfsoc_timer = {
217	.init = sirfsoc_timer_init,
218};