time.c 8.0 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/mach/time.h>
31
#include <mach/common.h>
32

33 34 35 36 37 38
/*
 * 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
 */

39 40
/* defines common for all i.MX */
#define MXC_TCTL		0x00
41
#define MXC_TCTL_TEN		(1 << 0) /* Enable module */
42 43 44 45 46 47 48 49 50 51 52 53 54 55
#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)

56
/* MX31, MX35, MX25, MXC91231, MX5 */
57 58 59 60 61 62 63 64
#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
65

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

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

72
static void __iomem *timer_base;
73

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

78
	if (timer_is_v2())
79
		__raw_writel(0, timer_base + V2_IR);
80 81 82 83 84 85 86 87
	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)
{
88
	if (timer_is_v2())
89
		__raw_writel(1<<0, timer_base + V2_IR);
90 91 92 93 94 95 96 97
	else {
		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
			timer_base + MXC_TCTL);
	}
}

static void gpt_irq_acknowledge(void)
{
98 99 100 101 102 103 104
	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())
105 106 107 108 109 110 111 112
		__raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT);
}

static cycle_t mx1_2_get_cycles(struct clocksource *cs)
{
	return __raw_readl(timer_base + MX1_2_TCN);
}

113
static cycle_t v2_get_cycles(struct clocksource *cs)
114
{
115
	return __raw_readl(timer_base + V2_TCN);
116 117 118 119 120
}

static struct clocksource clocksource_mxc = {
	.name 		= "mxc_timer1",
	.rating		= 200,
121
	.read		= mx1_2_get_cycles,
122 123 124 125 126
	.mask		= CLOCKSOURCE_MASK(32),
	.shift 		= 20,
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

127
static int __init mxc_clocksource_init(struct clk *timer_clk)
128
{
129
	unsigned int c = clk_get_rate(timer_clk);
130

131
	if (timer_is_v2())
132
		clocksource_mxc.read = v2_get_cycles;
133

134
	clocksource_mxc.mult = clocksource_hz2mult(c,
135 136 137 138 139 140 141 142
					clocksource_mxc.shift);
	clocksource_register(&clocksource_mxc);

	return 0;
}

/* clock event */

143
static int mx1_2_set_next_event(unsigned long evt,
144 145 146 147
			      struct clock_event_device *unused)
{
	unsigned long tcmp;

148
	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
149

150 151 152 153 154 155
	__raw_writel(tcmp, timer_base + MX1_2_TCMP);

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

156
static int v2_set_next_event(unsigned long evt,
157 158 159 160
			      struct clock_event_device *unused)
{
	unsigned long tcmp;

161
	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
162

163
	__raw_writel(tcmp, timer_base + V2_TCMP);
164

165
	return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
				-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 */
194
		if (timer_is_v2())
195 196
			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
					timer_base + V2_TCMP);
197 198 199 200
		else
			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
					timer_base + MX1_2_TCMP);

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 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
		/* 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;

247
	if (timer_is_v2())
248
		tstat = __raw_readl(timer_base + V2_TSTAT);
249 250
	else
		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

	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,
270
	.set_next_event	= mx1_2_set_next_event,
271 272 273
	.rating		= 200,
};

274
static int __init mxc_clockevent_init(struct clk *timer_clk)
275
{
276
	unsigned int c = clk_get_rate(timer_clk);
277

278
	if (timer_is_v2())
279
		clockevent_mxc.set_next_event = v2_set_next_event;
280

281
	clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
282 283 284 285 286 287
					clockevent_mxc.shift);
	clockevent_mxc.max_delta_ns =
			clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
	clockevent_mxc.min_delta_ns =
			clockevent_delta2ns(0xff, &clockevent_mxc);

288
	clockevent_mxc.cpumask = cpumask_of(0);
289 290 291 292 293 294

	clockevents_register_device(&clockevent_mxc);

	return 0;
}

295
void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
296
{
297 298
	uint32_t tctl_val;

299 300
	clk_enable(timer_clk);

301
	timer_base = base;
302

303 304 305 306
	/*
	 * Initialise to a known state (all timers off, and timing reset)
	 */

307 308 309
	__raw_writel(0, timer_base + MXC_TCTL);
	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */

310
	if (timer_is_v2())
311
		tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
312 313 314 315
	else
		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;

	__raw_writel(tctl_val, timer_base + MXC_TCTL);
316 317

	/* init and register the timer to the framework */
318 319
	mxc_clocksource_init(timer_clk);
	mxc_clockevent_init(timer_clk);
320 321

	/* Make irqs happen */
322
	setup_irq(irq, &mxc_timer_irq);
323
}