timer-sp804.c 6.5 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 *  linux/drivers/clocksource/timer-sp.c
4 5 6 7
 *
 *  Copyright (C) 1999 - 2003 ARM Limited
 *  Copyright (C) 2000 Deep Blue Solutions Ltd
 */
8
#include <linux/clk.h>
9 10
#include <linux/clocksource.h>
#include <linux/clockchips.h>
11
#include <linux/err.h>
12 13 14
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
15 16
#include <linux/of.h>
#include <linux/of_address.h>
17
#include <linux/of_clk.h>
18
#include <linux/of_irq.h>
19
#include <linux/sched_clock.h>
20

21
#include "timer-sp.h"
22

23
static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
24 25 26 27
{
	long rate;
	int err;

28 29 30 31 32 33 34
	if (!clk)
		clk = clk_get_sys("sp804", name);
	if (IS_ERR(clk)) {
		pr_err("sp804: %s clock not found: %ld\n", name, PTR_ERR(clk));
		return PTR_ERR(clk);
	}

35 36
	err = clk_prepare(clk);
	if (err) {
37
		pr_err("sp804: clock failed to prepare: %d\n", err);
38 39 40 41
		clk_put(clk);
		return err;
	}

42 43
	err = clk_enable(clk);
	if (err) {
44
		pr_err("sp804: clock failed to enable: %d\n", err);
45
		clk_unprepare(clk);
46 47 48 49 50 51
		clk_put(clk);
		return err;
	}

	rate = clk_get_rate(clk);
	if (rate < 0) {
52
		pr_err("sp804: clock failed to get rate: %ld\n", rate);
53
		clk_disable(clk);
54
		clk_unprepare(clk);
55 56 57 58 59 60
		clk_put(clk);
	}

	return rate;
}

61 62
static void __iomem *sched_clock_base;

63
static u64 notrace sp804_read(void)
64 65 66 67
{
	return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
}

68 69 70 71
int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
						  const char *name,
						  struct clk *clk,
						  int use_sched_clock)
72
{
73 74
	long rate;

75
	rate = sp804_get_clock_rate(clk, name);
76
	if (rate < 0)
77
		return -EINVAL;
78

79 80 81
	writel(0, base + TIMER_CTRL);
	writel(0xffffffff, base + TIMER_LOAD);
	writel(0xffffffff, base + TIMER_VALUE);
82
	writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
83
		base + TIMER_CTRL);
84

85
	clocksource_mmio_init(base + TIMER_VALUE, name,
86
		rate, 200, 32, clocksource_mmio_readl_down);
87 88 89

	if (use_sched_clock) {
		sched_clock_base = base;
90
		sched_clock_register(sp804_read, 32, rate);
91
	}
92 93

	return 0;
94 95 96 97
}


static void __iomem *clkevt_base;
98
static unsigned long clkevt_reload;
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

/*
 * IRQ handler for the timer
 */
static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = dev_id;

	/* clear the interrupt */
	writel(1, clkevt_base + TIMER_INTCLR);

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

115
static inline void timer_shutdown(struct clock_event_device *evt)
116
{
117 118
	writel(0, clkevt_base + TIMER_CTRL);
}
119

120 121 122 123 124
static int sp804_shutdown(struct clock_event_device *evt)
{
	timer_shutdown(evt);
	return 0;
}
125

126 127 128 129
static int sp804_set_periodic(struct clock_event_device *evt)
{
	unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
			     TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
130

131 132
	timer_shutdown(evt);
	writel(clkevt_reload, clkevt_base + TIMER_LOAD);
133
	writel(ctrl, clkevt_base + TIMER_CTRL);
134
	return 0;
135 136 137 138 139
}

static int sp804_set_next_event(unsigned long next,
	struct clock_event_device *evt)
{
140 141
	unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
			     TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
142 143

	writel(next, clkevt_base + TIMER_LOAD);
144
	writel(ctrl, clkevt_base + TIMER_CTRL);
145 146 147 148 149

	return 0;
}

static struct clock_event_device sp804_clockevent = {
150 151 152 153 154 155 156 157 158
	.features		= CLOCK_EVT_FEAT_PERIODIC |
				  CLOCK_EVT_FEAT_ONESHOT |
				  CLOCK_EVT_FEAT_DYNIRQ,
	.set_state_shutdown	= sp804_shutdown,
	.set_state_periodic	= sp804_set_periodic,
	.set_state_oneshot	= sp804_shutdown,
	.tick_resume		= sp804_shutdown,
	.set_next_event		= sp804_set_next_event,
	.rating			= 300,
159 160
};

161 162
int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
				  struct clk *clk, const char *name)
163 164
{
	struct clock_event_device *evt = &sp804_clockevent;
165 166
	long rate;

167
	rate = sp804_get_clock_rate(clk, name);
168
	if (rate < 0)
169
		return -EINVAL;
170 171

	clkevt_base = base;
172
	clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
173 174
	evt->name = name;
	evt->irq = irq;
175
	evt->cpumask = cpu_possible_mask;
176

177 178
	writel(0, base + TIMER_CTRL);

179 180 181
	if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
			"timer", &sp804_clockevent))
		pr_err("%s: request_irq() failed\n", "timer");
182
	clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
183 184

	return 0;
185
}
186

187
static int __init sp804_of_init(struct device_node *np)
188 189 190
{
	static bool initialized = false;
	void __iomem *base;
191
	int irq, ret = -EINVAL;
192 193 194 195 196
	u32 irq_num = 0;
	struct clk *clk1, *clk2;
	const char *name = of_get_property(np, "compatible", NULL);

	base = of_iomap(np, 0);
197 198
	if (!base)
		return -ENXIO;
199 200 201 202 203

	/* Ensure timers are disabled */
	writel(0, base + TIMER_CTRL);
	writel(0, base + TIMER_2_BASE + TIMER_CTRL);

204 205
	if (initialized || !of_device_is_available(np)) {
		ret = -EINVAL;
206
		goto err;
207
	}
208 209 210 211 212

	clk1 = of_clk_get(np, 0);
	if (IS_ERR(clk1))
		clk1 = NULL;

213
	/* Get the 2nd clock if the timer has 3 timer clocks */
214
	if (of_clk_get_parent_count(np) == 3) {
215 216
		clk2 = of_clk_get(np, 1);
		if (IS_ERR(clk2)) {
217
			pr_err("sp804: %pOFn clock not found: %d\n", np,
218
				(int)PTR_ERR(clk2));
219
			clk2 = NULL;
220 221 222 223 224 225 226 227 228 229
		}
	} else
		clk2 = clk1;

	irq = irq_of_parse_and_map(np, 0);
	if (irq <= 0)
		goto err;

	of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
	if (irq_num == 2) {
230

231
		ret = sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
232 233 234
		if (ret)
			goto err;

235 236
		ret = sp804_clocksource_and_sched_clock_init(base,
							     name, clk1, 1);
237 238
		if (ret)
			goto err;
239
	} else {
240

241
		ret = sp804_clockevents_init(base, irq, clk1, name);
242 243 244
		if (ret)
			goto err;

245 246
		ret = sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
							     name, clk2, 1);
247 248
		if (ret)
			goto err;
249 250 251
	}
	initialized = true;

252
	return 0;
253 254
err:
	iounmap(base);
255
	return ret;
256
}
257
TIMER_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
258

259
static int __init integrator_cp_of_init(struct device_node *np)
260 261 262
{
	static int init_count = 0;
	void __iomem *base;
263
	int irq, ret = -EINVAL;
264
	const char *name = of_get_property(np, "compatible", NULL);
265
	struct clk *clk;
266 267

	base = of_iomap(np, 0);
268
	if (!base) {
269
		pr_err("Failed to iomap\n");
270 271 272
		return -ENXIO;
	}

273
	clk = of_clk_get(np, 0);
274
	if (IS_ERR(clk)) {
275
		pr_err("Failed to get clock\n");
276 277
		return PTR_ERR(clk);
	}
278 279 280 281 282 283 284

	/* Ensure timer is disabled */
	writel(0, base + TIMER_CTRL);

	if (init_count == 2 || !of_device_is_available(np))
		goto err;

285
	if (!init_count) {
286 287
		ret = sp804_clocksource_and_sched_clock_init(base,
							     name, clk, 0);
288 289 290
		if (ret)
			goto err;
	} else {
291 292 293 294
		irq = irq_of_parse_and_map(np, 0);
		if (irq <= 0)
			goto err;

295
		ret = sp804_clockevents_init(base, irq, clk, name);
296 297
		if (ret)
			goto err;
298 299 300
	}

	init_count++;
301
	return 0;
302 303
err:
	iounmap(base);
304
	return ret;
305
}
306
TIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);