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/cpu.h>
 14#include <linux/bitops.h>
 15#include <linux/irq.h>
 16#include <linux/clk.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 SIRFSOC_TIMER_32COUNTER_0_CTRL			0x0000
 24#define SIRFSOC_TIMER_32COUNTER_1_CTRL			0x0004
 25#define SIRFSOC_TIMER_MATCH_0				0x0018
 26#define SIRFSOC_TIMER_MATCH_1				0x001c
 27#define SIRFSOC_TIMER_COUNTER_0				0x0048
 28#define SIRFSOC_TIMER_COUNTER_1				0x004c
 29#define SIRFSOC_TIMER_INTR_STATUS			0x0060
 30#define SIRFSOC_TIMER_WATCHDOG_EN			0x0064
 31#define SIRFSOC_TIMER_64COUNTER_CTRL			0x0068
 32#define SIRFSOC_TIMER_64COUNTER_LO			0x006c
 33#define SIRFSOC_TIMER_64COUNTER_HI			0x0070
 34#define SIRFSOC_TIMER_64COUNTER_LOAD_LO			0x0074
 35#define SIRFSOC_TIMER_64COUNTER_LOAD_HI			0x0078
 36#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO		0x007c
 37#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI		0x0080
 38
 39#define SIRFSOC_TIMER_REG_CNT 6
 40
 41static unsigned long atlas7_timer_rate;
 42
 43static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
 44	SIRFSOC_TIMER_WATCHDOG_EN,
 45	SIRFSOC_TIMER_32COUNTER_0_CTRL,
 46	SIRFSOC_TIMER_32COUNTER_1_CTRL,
 47	SIRFSOC_TIMER_64COUNTER_CTRL,
 48	SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
 49	SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
 50};
 51
 52static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
 53
 54static void __iomem *sirfsoc_timer_base;
 55
 56/* disable count and interrupt */
 57static inline void sirfsoc_timer_count_disable(int idx)
 58{
 59	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
 60		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
 61}
 62
 63/* enable count and interrupt */
 64static inline void sirfsoc_timer_count_enable(int idx)
 65{
 66	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3,
 67		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
 68}
 69
 70/* timer interrupt handler */
 71static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
 72{
 73	struct clock_event_device *ce = dev_id;
 74	int cpu = smp_processor_id();
 75
 76	/* clear timer interrupt */
 77	writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
 78
 79	if (clockevent_state_oneshot(ce))
 80		sirfsoc_timer_count_disable(cpu);
 81
 82	ce->event_handler(ce);
 83
 84	return IRQ_HANDLED;
 85}
 86
 87/* read 64-bit timer counter */
 88static u64 sirfsoc_timer_read(struct clocksource *cs)
 89{
 90	u64 cycles;
 91
 92	writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
 93			BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
 94
 95	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
 96	cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
 97
 98	return cycles;
 99}
100
101static int sirfsoc_timer_set_next_event(unsigned long delta,
102	struct clock_event_device *ce)
103{
104	int cpu = smp_processor_id();
105
106	/* disable timer first, then modify the related registers */
107	sirfsoc_timer_count_disable(cpu);
108
109	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
110		4 * cpu);
111	writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
112		4 * cpu);
113
114	/* enable the tick */
115	sirfsoc_timer_count_enable(cpu);
116
117	return 0;
118}
119
120/* Oneshot is enabled in set_next_event */
121static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
122{
123	sirfsoc_timer_count_disable(smp_processor_id());
124	return 0;
125}
126
127static void sirfsoc_clocksource_suspend(struct clocksource *cs)
128{
129	int i;
130
131	for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
132		sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
133}
134
135static void sirfsoc_clocksource_resume(struct clocksource *cs)
136{
137	int i;
138
139	for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
140		writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
141
142	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
143		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
144	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
145		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
146
147	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
148		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
149}
150
151static struct clock_event_device __percpu *sirfsoc_clockevent;
152
153static struct clocksource sirfsoc_clocksource = {
154	.name = "sirfsoc_clocksource",
155	.rating = 200,
156	.mask = CLOCKSOURCE_MASK(64),
157	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
158	.read = sirfsoc_timer_read,
159	.suspend = sirfsoc_clocksource_suspend,
160	.resume = sirfsoc_clocksource_resume,
161};
162
163static struct irqaction sirfsoc_timer_irq = {
164	.name = "sirfsoc_timer0",
165	.flags = IRQF_TIMER | IRQF_NOBALANCING,
166	.handler = sirfsoc_timer_interrupt,
167};
168
169static struct irqaction sirfsoc_timer1_irq = {
170	.name = "sirfsoc_timer1",
171	.flags = IRQF_TIMER | IRQF_NOBALANCING,
172	.handler = sirfsoc_timer_interrupt,
173};
174
175static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
176{
177	struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu);
178	struct irqaction *action;
179
180	if (cpu == 0)
181		action = &sirfsoc_timer_irq;
182	else
183		action = &sirfsoc_timer1_irq;
184
185	ce->irq = action->irq;
186	ce->name = "local_timer";
187	ce->features = CLOCK_EVT_FEAT_ONESHOT;
188	ce->rating = 200;
189	ce->set_state_shutdown = sirfsoc_timer_shutdown;
190	ce->set_state_oneshot = sirfsoc_timer_shutdown;
191	ce->tick_resume = sirfsoc_timer_shutdown;
192	ce->set_next_event = sirfsoc_timer_set_next_event;
193	clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
194	ce->max_delta_ns = clockevent_delta2ns(-2, ce);
195	ce->max_delta_ticks = (unsigned long)-2;
196	ce->min_delta_ns = clockevent_delta2ns(2, ce);
197	ce->min_delta_ticks = 2;
198	ce->cpumask = cpumask_of(cpu);
199
200	action->dev_id = ce;
201	BUG_ON(setup_irq(ce->irq, action));
202	irq_force_affinity(action->irq, cpumask_of(cpu));
203
204	clockevents_register_device(ce);
205	return 0;
206}
207
208static int sirfsoc_local_timer_dying_cpu(unsigned int cpu)
209{
210	sirfsoc_timer_count_disable(1);
211
212	if (cpu == 0)
213		remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
214	else
215		remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
216	return 0;
217}
218
219static int __init sirfsoc_clockevent_init(void)
220{
221	sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
222	BUG_ON(!sirfsoc_clockevent);
223
224	/* Install and invoke hotplug callbacks */
225	return cpuhp_setup_state(CPUHP_AP_MARCO_TIMER_STARTING,
226				 "clockevents/marco:starting",
227				 sirfsoc_local_timer_starting_cpu,
228				 sirfsoc_local_timer_dying_cpu);
229}
230
231/* initialize the kernel jiffy timer source */
232static int __init sirfsoc_atlas7_timer_init(struct device_node *np)
233{
234	struct clk *clk;
235
236	clk = of_clk_get(np, 0);
237	BUG_ON(IS_ERR(clk));
238
239	BUG_ON(clk_prepare_enable(clk));
240
241	atlas7_timer_rate = clk_get_rate(clk);
242
243	/* timer dividers: 0, not divided */
244	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
245	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
246	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
247
248	/* Initialize timer counters to 0 */
249	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
250	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
251	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
252		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
253	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
254	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
255
256	/* Clear all interrupts */
257	writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
258
259	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate));
260
261	return sirfsoc_clockevent_init();
262}
263
264static int __init sirfsoc_of_timer_init(struct device_node *np)
265{
266	sirfsoc_timer_base = of_iomap(np, 0);
267	if (!sirfsoc_timer_base) {
268		pr_err("unable to map timer cpu registers\n");
269		return -ENXIO;
270	}
271
272	sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
273	if (!sirfsoc_timer_irq.irq) {
274		pr_err("No irq passed for timer0 via DT\n");
275		return -EINVAL;
276	}
277
278	sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
279	if (!sirfsoc_timer1_irq.irq) {
280		pr_err("No irq passed for timer1 via DT\n");
281		return -EINVAL;
282	}
283
284	return sirfsoc_atlas7_timer_init(np);
285}
286TIMER_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);