• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-mmp/
1/*
2 * linux/arch/arm/mach-mmp/time.c
3 *
4 *   Support for clocksource and clockevents
5 *
6 * Copyright (C) 2008 Marvell International Ltd.
7 * All rights reserved.
8 *
9 *   2008-04-11: Jason Chagas <Jason.chagas@marvell.com>
10 *   2008-10-08: Bin Yang <bin.yang@marvell.com>
11 *
12 * The timers module actually includes three timers, each timer with upto
13 * three match comparators. Timer #0 is used here in free-running mode as
14 * the clock source, and match comparator #1 used as clock event device.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
20
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/interrupt.h>
24#include <linux/clockchips.h>
25
26#include <linux/io.h>
27#include <linux/irq.h>
28#include <linux/sched.h>
29#include <linux/cnt32_to_63.h>
30
31#include <mach/addr-map.h>
32#include <mach/regs-timers.h>
33#include <mach/regs-apbc.h>
34#include <mach/irqs.h>
35#include <mach/cputype.h>
36#include <asm/mach/time.h>
37
38#include "clock.h"
39
40#define TIMERS_VIRT_BASE	TIMERS1_VIRT_BASE
41
42#define MAX_DELTA		(0xfffffffe)
43#define MIN_DELTA		(16)
44
45#define TCR2NS_SCALE_FACTOR	10
46
47static unsigned long tcr2ns_scale;
48
49static void __init set_tcr2ns_scale(unsigned long tcr_rate)
50{
51	unsigned long long v = 1000000000ULL << TCR2NS_SCALE_FACTOR;
52	do_div(v, tcr_rate);
53	tcr2ns_scale = v;
54	/*
55	 * We want an even value to automatically clear the top bit
56	 * returned by cnt32_to_63() without an additional run time
57	 * instruction. So if the LSB is 1 then round it up.
58	 */
59	if (tcr2ns_scale & 1)
60		tcr2ns_scale++;
61}
62
63static inline uint32_t timer_read(void)
64{
65	int delay = 100;
66
67	__raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(0));
68
69	while (delay--)
70		cpu_relax();
71
72	return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(0));
73}
74
75unsigned long long sched_clock(void)
76{
77	unsigned long long v = cnt32_to_63(timer_read());
78	return (v * tcr2ns_scale) >> TCR2NS_SCALE_FACTOR;
79}
80
81static irqreturn_t timer_interrupt(int irq, void *dev_id)
82{
83	struct clock_event_device *c = dev_id;
84
85	/* disable and clear pending interrupt status */
86	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
87	__raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0));
88	c->event_handler(c);
89	return IRQ_HANDLED;
90}
91
92static int timer_set_next_event(unsigned long delta,
93				struct clock_event_device *dev)
94{
95	unsigned long flags, next;
96
97	local_irq_save(flags);
98
99	/* clear pending interrupt status and enable */
100	__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
101	__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
102
103	next = timer_read() + delta;
104	__raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
105
106	local_irq_restore(flags);
107	return 0;
108}
109
110static void timer_set_mode(enum clock_event_mode mode,
111			   struct clock_event_device *dev)
112{
113	unsigned long flags;
114
115	local_irq_save(flags);
116	switch (mode) {
117	case CLOCK_EVT_MODE_ONESHOT:
118	case CLOCK_EVT_MODE_UNUSED:
119	case CLOCK_EVT_MODE_SHUTDOWN:
120		/* disable the matching interrupt */
121		__raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0));
122		break;
123	case CLOCK_EVT_MODE_RESUME:
124	case CLOCK_EVT_MODE_PERIODIC:
125		break;
126	}
127	local_irq_restore(flags);
128}
129
130static struct clock_event_device ckevt = {
131	.name		= "clockevent",
132	.features	= CLOCK_EVT_FEAT_ONESHOT,
133	.shift		= 32,
134	.rating		= 200,
135	.set_next_event	= timer_set_next_event,
136	.set_mode	= timer_set_mode,
137};
138
139static cycle_t clksrc_read(struct clocksource *cs)
140{
141	return timer_read();
142}
143
144static struct clocksource cksrc = {
145	.name		= "clocksource",
146	.shift		= 20,
147	.rating		= 200,
148	.read		= clksrc_read,
149	.mask		= CLOCKSOURCE_MASK(32),
150	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
151};
152
153static void __init timer_config(void)
154{
155	uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
156	uint32_t cer = __raw_readl(TIMERS_VIRT_BASE + TMR_CER);
157	uint32_t cmr = __raw_readl(TIMERS_VIRT_BASE + TMR_CMR);
158
159	__raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */
160
161	ccr &= (cpu_is_mmp2()) ? TMR_CCR_CS_0(0) : TMR_CCR_CS_0(3);
162	__raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
163
164	/* free-running mode */
165	__raw_writel(cmr | 0x01, TIMERS_VIRT_BASE + TMR_CMR);
166
167	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */
168	__raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0));  /* clear status */
169	__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
170
171	/* enable timer counter */
172	__raw_writel(cer | 0x01, TIMERS_VIRT_BASE + TMR_CER);
173}
174
175static struct irqaction timer_irq = {
176	.name		= "timer",
177	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
178	.handler	= timer_interrupt,
179	.dev_id		= &ckevt,
180};
181
182void __init timer_init(int irq)
183{
184	timer_config();
185
186	set_tcr2ns_scale(CLOCK_TICK_RATE);
187
188	ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift);
189	ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt);
190	ckevt.min_delta_ns = clockevent_delta2ns(MIN_DELTA, &ckevt);
191	ckevt.cpumask = cpumask_of(0);
192
193	cksrc.mult = clocksource_hz2mult(CLOCK_TICK_RATE, cksrc.shift);
194
195	setup_irq(irq, &timer_irq);
196
197	clocksource_register(&cksrc);
198	clockevents_register_device(&ckevt);
199}
200