timer.c 8.7 KB
Newer Older
1
/*
2
 * linux/arch/arm/mach-omap2/timer.c
3 4 5
 *
 * OMAP2 GP timer support.
 *
6 7
 * Copyright (C) 2009 Nokia Corporation
 *
8 9 10 11 12
 * Update to use new clocksource/clockevent layers
 * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
 * Copyright (C) 2007 MontaVista Software, Inc.
 *
 * Original driver:
13 14
 * Copyright (C) 2005 Nokia Corporation
 * Author: Paul Mundt <paul.mundt@nokia.com>
15
 *         Juha Yrjölä <juha.yrjola@nokia.com>
16
 * OMAP Dual-mode timer framework support by Timo Teras
17 18 19
 *
 * Some parts based off of TI's 24xx code:
 *
20
 * Copyright (C) 2004-2009 Texas Instruments, Inc.
21 22
 *
 * Roughly modelled after the OMAP1 MPU timer code.
23
 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
24 25 26 27 28 29 30 31 32
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/err.h>
33
#include <linux/clk.h>
34
#include <linux/delay.h>
35
#include <linux/irq.h>
36 37
#include <linux/clocksource.h>
#include <linux/clockchips.h>
38

39
#include <asm/mach/time.h>
40
#include <plat/dmtimer.h>
41
#include <asm/localtimer.h>
42
#include <asm/sched_clock.h>
43 44
#include <plat/common.h>
#include <plat/omap_hwmod.h>
45

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
/* Parent clocks, eventually these will come from the clock framework */

#define OMAP2_MPU_SOURCE	"sys_ck"
#define OMAP3_MPU_SOURCE	OMAP2_MPU_SOURCE
#define OMAP4_MPU_SOURCE	"sys_clkin_ck"
#define OMAP2_32K_SOURCE	"func_32k_ck"
#define OMAP3_32K_SOURCE	"omap_32k_fck"
#define OMAP4_32K_SOURCE	"sys_32k_ck"

#ifdef CONFIG_OMAP_32K_TIMER
#define OMAP2_CLKEV_SOURCE	OMAP2_32K_SOURCE
#define OMAP3_CLKEV_SOURCE	OMAP3_32K_SOURCE
#define OMAP4_CLKEV_SOURCE	OMAP4_32K_SOURCE
#define OMAP3_SECURE_TIMER	12
#else
#define OMAP2_CLKEV_SOURCE	OMAP2_MPU_SOURCE
#define OMAP3_CLKEV_SOURCE	OMAP3_MPU_SOURCE
#define OMAP4_CLKEV_SOURCE	OMAP4_MPU_SOURCE
#define OMAP3_SECURE_TIMER	1
#endif
66

67 68 69
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
#define MAX_GPTIMER_ID		12

70 71
u32 sys_timer_reserved;

72 73 74
/* Clockevent code */

static struct omap_dm_timer clkev;
75
static struct clock_event_device clockevent_gpt;
76

77
static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
78
{
79 80
	struct clock_event_device *evt = &clockevent_gpt;

81
	__omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
82

83
	evt->event_handler(evt);
84 85 86 87 88
	return IRQ_HANDLED;
}

static struct irqaction omap2_gp_timer_irq = {
	.name		= "gp timer",
B
Bernhard Walle 已提交
89
	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
90 91 92
	.handler	= omap2_gp_timer_interrupt,
};

93 94
static int omap2_gp_timer_set_next_event(unsigned long cycles,
					 struct clock_event_device *evt)
95
{
96 97
	__omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
						0xffffffff - cycles, 1);
98 99 100 101 102 103 104 105 106

	return 0;
}

static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
				    struct clock_event_device *evt)
{
	u32 period;

107
	__omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
108 109 110

	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
111
		period = clkev.rate / HZ;
112
		period -= 1;
113 114 115 116 117 118
		/* Looks like we need to first set the load value separately */
		__omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
					0xffffffff - period, 1);
		__omap_dm_timer_load_start(clkev.io_base,
					OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
						0xffffffff - period, 1);
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
		break;
	case CLOCK_EVT_MODE_ONESHOT:
		break;
	case CLOCK_EVT_MODE_UNUSED:
	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_RESUME:
		break;
	}
}

static struct clock_event_device clockevent_gpt = {
	.name		= "gp timer",
	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
	.shift		= 32,
	.set_next_event	= omap2_gp_timer_set_next_event,
	.set_mode	= omap2_gp_timer_set_mode,
};

137 138 139
static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
						int gptimer_id,
						const char *fck_source)
140
{
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	char name[10]; /* 10 = sizeof("gptXX_Xck0") */
	struct omap_hwmod *oh;
	size_t size;
	int res = 0;

	sprintf(name, "timer%d", gptimer_id);
	omap_hwmod_setup_one(name);
	oh = omap_hwmod_lookup(name);
	if (!oh)
		return -ENODEV;

	timer->irq = oh->mpu_irqs[0].irq;
	timer->phys_base = oh->slaves[0]->addr->pa_start;
	size = oh->slaves[0]->addr->pa_end - timer->phys_base;

	/* Static mapping, never released */
	timer->io_base = ioremap(timer->phys_base, size);
	if (!timer->io_base)
		return -ENXIO;

	/* After the dmtimer is using hwmod these clocks won't be needed */
	sprintf(name, "gpt%d_fck", gptimer_id);
	timer->fclk = clk_get(NULL, name);
	if (IS_ERR(timer->fclk))
		return -ENODEV;

	sprintf(name, "gpt%d_ick", gptimer_id);
	timer->iclk = clk_get(NULL, name);
	if (IS_ERR(timer->iclk)) {
		clk_put(timer->fclk);
		return -ENODEV;
	}
173

174 175
	omap_hwmod_enable(oh);

176 177
	sys_timer_reserved |= (1 << (gptimer_id - 1));

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	if (gptimer_id != 12) {
		struct clk *src;

		src = clk_get(NULL, fck_source);
		if (IS_ERR(src)) {
			res = -EINVAL;
		} else {
			res = __omap_dm_timer_set_source(timer->fclk, src);
			if (IS_ERR_VALUE(res))
				pr_warning("%s: timer%i cannot set source\n",
						__func__, gptimer_id);
			clk_put(src);
		}
	}
	__omap_dm_timer_reset(timer->io_base, 1, 1);
	timer->posted = 1;

	timer->rate = clk_get_rate(timer->fclk);
196

197
	timer->reserved = 1;
198

199 200
	return res;
}
201

202 203 204 205
static void __init omap2_gp_clockevent_init(int gptimer_id,
						const char *fck_source)
{
	int res;
206

207 208
	res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source);
	BUG_ON(res);
209

210
	omap2_gp_timer_irq.dev_id = (void *)&clkev;
211
	setup_irq(clkev.irq, &omap2_gp_timer_irq);
212

213 214 215
	__omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);

	clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
216 217 218 219
				     clockevent_gpt.shift);
	clockevent_gpt.max_delta_ns =
		clockevent_delta2ns(0xffffffff, &clockevent_gpt);
	clockevent_gpt.min_delta_ns =
220 221
		clockevent_delta2ns(3, &clockevent_gpt);
		/* Timer internal resynch latency. */
222

223
	clockevent_gpt.cpumask = cpumask_of(0);
224
	clockevents_register_device(&clockevent_gpt);
225 226 227

	pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n",
		gptimer_id, clkev.rate);
228 229
}

230 231
/* Clocksource code */

232
#ifdef CONFIG_OMAP_32K_TIMER
233
/*
234 235
 * When 32k-timer is enabled, don't use GPTimer for clocksource
 * instead, just leave default clocksource which uses the 32k
236
 * sync counter.  See clocksource setup in plat-omap/counter_32k.c
237 238
 */

239
static void __init omap2_gp_clocksource_init(int unused, const char *dummy)
240 241 242 243
{
	omap_init_clocksource_32k();
}

244
#else
245 246 247

static struct omap_dm_timer clksrc;

248 249 250
/*
 * clocksource
 */
251
static DEFINE_CLOCK_DATA(cd);
252
static cycle_t clocksource_read_cycles(struct clocksource *cs)
253
{
254
	return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
255 256 257 258 259 260 261 262 263 264
}

static struct clocksource clocksource_gpt = {
	.name		= "gp timer",
	.rating		= 300,
	.read		= clocksource_read_cycles,
	.mask		= CLOCKSOURCE_MASK(32),
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

265 266 267 268
static void notrace dmtimer_update_sched_clock(void)
{
	u32 cyc;

269
	cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
270 271 272 273

	update_sched_clock(&cd, cyc, (u32)~0);
}

274
unsigned long long notrace sched_clock(void)
275
{
276
	u32 cyc = 0;
277

278 279
	if (clksrc.reserved)
		cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
280

281 282 283 284 285 286 287 288 289 290 291
	return cyc_to_sched_clock(&cd, cyc, (u32)~0);
}

/* Setup free-running counter for clocksource */
static void __init omap2_gp_clocksource_init(int gptimer_id,
						const char *fck_source)
{
	int res;

	res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source);
	BUG_ON(res);
292

293 294
	pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
		gptimer_id, clksrc.rate);
295

296 297
	__omap_dm_timer_load_start(clksrc.io_base,
			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
298
	init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
299

300 301 302
	if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
		pr_err("Could not register clocksource %s\n",
			clocksource_gpt.name);
303 304 305
}
#endif

306 307
#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src,			\
				clksrc_nr, clksrc_src)			\
308 309
static void __init omap##name##_timer_init(void)			\
{									\
310
	omap2_gp_clockevent_init((clkev_nr), clkev_src);		\
311
	omap2_gp_clocksource_init((clksrc_nr), clksrc_src);		\
312 313 314 315 316 317 318 319
}

#define OMAP_SYS_TIMER(name)						\
struct sys_timer omap##name##_timer = {					\
	.init	= omap##name##_timer_init,				\
};

#ifdef CONFIG_ARCH_OMAP2
320
OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, 2, OMAP2_MPU_SOURCE)
321 322 323 324
OMAP_SYS_TIMER(2)
#endif

#ifdef CONFIG_ARCH_OMAP3
325
OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, 2, OMAP3_MPU_SOURCE)
326
OMAP_SYS_TIMER(3)
327 328
OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE,
			2, OMAP3_MPU_SOURCE)
329 330 331 332 333
OMAP_SYS_TIMER(3_secure)
#endif

#ifdef CONFIG_ARCH_OMAP4
static void __init omap4_timer_init(void)
334
{
335
#ifdef CONFIG_LOCAL_TIMERS
336 337
	twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
	BUG_ON(!twd_base);
338
#endif
339
	omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
340
	omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE);
341
}
342 343
OMAP_SYS_TIMER(4)
#endif