time.c 8.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 *  linux/arch/arm/plat-mxc/time.c
 *
 *  Copyright (C) 2000-2001 Deep Blue Solutions
 *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
 *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
 *  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>

29
#include <mach/hardware.h>
30
#include <asm/sched_clock.h>
31
#include <asm/mach/time.h>
32
#include <mach/common.h>
33

34 35 36 37 38 39
/*
 * There are 2 versions of the timer hardware on Freescale MXC hardware.
 * Version 1: MX1/MXL, MX21, MX27.
 * Version 2: MX25, MX31, MX35, MX37, MX51
 */

40 41
/* defines common for all i.MX */
#define MXC_TCTL		0x00
42
#define MXC_TCTL_TEN		(1 << 0) /* Enable module */
43 44 45 46 47 48 49 50 51 52 53 54 55 56
#define MXC_TPRER		0x04

/* MX1, MX21, MX27 */
#define MX1_2_TCTL_CLK_PCLK1	(1 << 1)
#define MX1_2_TCTL_IRQEN	(1 << 4)
#define MX1_2_TCTL_FRR		(1 << 8)
#define MX1_2_TCMP		0x08
#define MX1_2_TCN		0x10
#define MX1_2_TSTAT		0x14

/* MX21, MX27 */
#define MX2_TSTAT_CAPT		(1 << 1)
#define MX2_TSTAT_COMP		(1 << 0)

57
/* MX31, MX35, MX25, MXC91231, MX5 */
58 59 60 61 62 63 64 65
#define V2_TCTL_WAITEN		(1 << 3) /* Wait enable mode */
#define V2_TCTL_CLK_IPG		(1 << 6)
#define V2_TCTL_FRR		(1 << 9)
#define V2_IR			0x0c
#define V2_TSTAT		0x08
#define V2_TSTAT_OF1		(1 << 0)
#define V2_TCN			0x24
#define V2_TCMP			0x10
66

67 68 69
#define timer_is_v1()	(cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
#define timer_is_v2()	(!timer_is_v1())

70 71 72
static struct clock_event_device clockevent_mxc;
static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;

73
static void __iomem *timer_base;
74

75
static inline void gpt_irq_disable(void)
76
{
77 78
	unsigned int tmp;

79
	if (timer_is_v2())
80
		__raw_writel(0, timer_base + V2_IR);
81 82 83 84 85 86 87 88
	else {
		tmp = __raw_readl(timer_base + MXC_TCTL);
		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
	}
}

static inline void gpt_irq_enable(void)
{
89
	if (timer_is_v2())
90
		__raw_writel(1<<0, timer_base + V2_IR);
91 92 93 94 95 96 97 98
	else {
		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
			timer_base + MXC_TCTL);
	}
}

static void gpt_irq_acknowledge(void)
{
99 100 101 102 103 104 105
	if (timer_is_v1()) {
		if (cpu_is_mx1())
			__raw_writel(0, timer_base + MX1_2_TSTAT);
		else
			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
				timer_base + MX1_2_TSTAT);
	} else if (timer_is_v2())
106
		__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
107 108
}

109 110 111 112 113
static cycle_t dummy_get_cycles(struct clocksource *cs)
{
	return 0;
}

114 115 116 117 118
static cycle_t mx1_2_get_cycles(struct clocksource *cs)
{
	return __raw_readl(timer_base + MX1_2_TCN);
}

119
static cycle_t v2_get_cycles(struct clocksource *cs)
120
{
121
	return __raw_readl(timer_base + V2_TCN);
122 123 124 125 126
}

static struct clocksource clocksource_mxc = {
	.name 		= "mxc_timer1",
	.rating		= 200,
127
	.read		= dummy_get_cycles,
128 129 130 131
	.mask		= CLOCKSOURCE_MASK(32),
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

132 133 134 135 136 137 138 139 140 141 142 143 144 145
static DEFINE_CLOCK_DATA(cd);
unsigned long long notrace sched_clock(void)
{
	cycle_t cyc = clocksource_mxc.read(&clocksource_mxc);

	return cyc_to_sched_clock(&cd, cyc, (u32)~0);
}

static void notrace mxc_update_sched_clock(void)
{
	cycle_t cyc = clocksource_mxc.read(&clocksource_mxc);
	update_sched_clock(&cd, cyc, (u32)~0);
}

146
static int __init mxc_clocksource_init(struct clk *timer_clk)
147
{
148
	unsigned int c = clk_get_rate(timer_clk);
149

150
	if (timer_is_v2())
151
		clocksource_mxc.read = v2_get_cycles;
152 153
	else
		clocksource_mxc.read = mx1_2_get_cycles;
154

155
	init_sched_clock(&cd, mxc_update_sched_clock, 32, c);
156
	clocksource_register_hz(&clocksource_mxc, c);
157 158 159 160 161 162

	return 0;
}

/* clock event */

163
static int mx1_2_set_next_event(unsigned long evt,
164 165 166 167
			      struct clock_event_device *unused)
{
	unsigned long tcmp;

168
	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
169

170 171 172 173 174 175
	__raw_writel(tcmp, timer_base + MX1_2_TCMP);

	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
				-ETIME : 0;
}

176
static int v2_set_next_event(unsigned long evt,
177 178 179 180
			      struct clock_event_device *unused)
{
	unsigned long tcmp;

181
	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
182

183
	__raw_writel(tcmp, timer_base + V2_TCMP);
184

185
	return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
				-ETIME : 0;
}

#ifdef DEBUG
static const char *clock_event_mode_label[] = {
	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
};
#endif /* DEBUG */

static void mxc_set_mode(enum clock_event_mode mode,
				struct clock_event_device *evt)
{
	unsigned long flags;

	/*
	 * The timer interrupt generation is disabled at least
	 * for enough time to call mxc_set_next_event()
	 */
	local_irq_save(flags);

	/* Disable interrupt in GPT module */
	gpt_irq_disable();

	if (mode != clockevent_mode) {
		/* Set event time into far-far future */
214
		if (timer_is_v2())
215 216
			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
					timer_base + V2_TCMP);
217 218 219 220
		else
			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
					timer_base + MX1_2_TCMP);

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
		/* Clear pending interrupt */
		gpt_irq_acknowledge();
	}

#ifdef DEBUG
	printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
		clock_event_mode_label[clockevent_mode],
		clock_event_mode_label[mode]);
#endif /* DEBUG */

	/* Remember timer mode */
	clockevent_mode = mode;
	local_irq_restore(flags);

	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
				"supported for i.MX\n");
		break;
	case CLOCK_EVT_MODE_ONESHOT:
	/*
	 * Do not put overhead of interrupt enable/disable into
	 * mxc_set_next_event(), the core has about 4 minutes
	 * to call mxc_set_next_event() or shutdown clock after
	 * mode switching
	 */
		local_irq_save(flags);
		gpt_irq_enable();
		local_irq_restore(flags);
		break;
	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_UNUSED:
	case CLOCK_EVT_MODE_RESUME:
		/* Left event sources disabled, no more interrupts appear */
		break;
	}
}

/*
 * IRQ handler for the timer
 */
static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = &clockevent_mxc;
	uint32_t tstat;

267
	if (timer_is_v2())
268
		tstat = __raw_readl(timer_base + V2_TSTAT);
269 270
	else
		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289

	gpt_irq_acknowledge();

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

static struct irqaction mxc_timer_irq = {
	.name		= "i.MX Timer Tick",
	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
	.handler	= mxc_timer_interrupt,
};

static struct clock_event_device clockevent_mxc = {
	.name		= "mxc_timer1",
	.features	= CLOCK_EVT_FEAT_ONESHOT,
	.shift		= 32,
	.set_mode	= mxc_set_mode,
290
	.set_next_event	= mx1_2_set_next_event,
291 292 293
	.rating		= 200,
};

294
static int __init mxc_clockevent_init(struct clk *timer_clk)
295
{
296
	unsigned int c = clk_get_rate(timer_clk);
297

298
	if (timer_is_v2())
299
		clockevent_mxc.set_next_event = v2_set_next_event;
300

301
	clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
302 303 304 305 306 307
					clockevent_mxc.shift);
	clockevent_mxc.max_delta_ns =
			clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
	clockevent_mxc.min_delta_ns =
			clockevent_delta2ns(0xff, &clockevent_mxc);

308
	clockevent_mxc.cpumask = cpumask_of(0);
309 310 311 312 313 314

	clockevents_register_device(&clockevent_mxc);

	return 0;
}

315
void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
316
{
317 318
	uint32_t tctl_val;

319 320
	clk_enable(timer_clk);

321
	timer_base = base;
322

323 324 325 326
	/*
	 * Initialise to a known state (all timers off, and timing reset)
	 */

327 328 329
	__raw_writel(0, timer_base + MXC_TCTL);
	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */

330
	if (timer_is_v2())
331
		tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
332 333 334 335
	else
		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;

	__raw_writel(tctl_val, timer_base + MXC_TCTL);
336 337

	/* init and register the timer to the framework */
338 339
	mxc_clocksource_init(timer_clk);
	mxc_clockevent_init(timer_clk);
340 341

	/* Make irqs happen */
342
	setup_irq(irq, &mxc_timer_irq);
343
}