aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ns9xxx/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ns9xxx/time.c')
-rw-r--r--arch/arm/mach-ns9xxx/time.c172
1 files changed, 134 insertions, 38 deletions
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c
index b97d0c54a388..c3dd1f4acb99 100644
--- a/arch/arm/mach-ns9xxx/time.c
+++ b/arch/arm/mach-ns9xxx/time.c
@@ -11,78 +11,174 @@
11#include <linux/jiffies.h> 11#include <linux/jiffies.h>
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/irq.h> 13#include <linux/irq.h>
14#include <linux/stringify.h>
15#include <linux/clocksource.h>
16#include <linux/clockchips.h>
17
14#include <asm/arch-ns9xxx/regs-sys.h> 18#include <asm/arch-ns9xxx/regs-sys.h>
15#include <asm/arch-ns9xxx/clock.h> 19#include <asm/arch-ns9xxx/clock.h>
16#include <asm/arch-ns9xxx/irqs.h> 20#include <asm/arch-ns9xxx/irqs.h>
17#include <asm/arch/system.h> 21#include <asm/arch/system.h>
18#include "generic.h" 22#include "generic.h"
19 23
20#define TIMERCLOCKSELECT 64 24#define TIMER_CLOCKSOURCE 0
25#define TIMER_CLOCKEVENT 1
26static u32 latch;
27
28static cycle_t ns9xxx_clocksource_read(void)
29{
30 return __raw_readl(SYS_TR(TIMER_CLOCKSOURCE));
31}
21 32
22static u32 usecs_per_tick; 33static struct clocksource ns9xxx_clocksource = {
34 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE),
35 .rating = 300,
36 .read = ns9xxx_clocksource_read,
37 .mask = CLOCKSOURCE_MASK(32),
38 .shift = 20,
39 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
40};
23 41
24static irqreturn_t 42static void ns9xxx_clockevent_setmode(enum clock_event_mode mode,
25ns9xxx_timer_interrupt(int irq, void *dev_id) 43 struct clock_event_device *clk)
26{ 44{
27 write_seqlock(&xtime_lock); 45 u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
28 timer_tick(); 46
29 write_sequnlock(&xtime_lock); 47 switch(mode) {
48 case CLOCK_EVT_MODE_PERIODIC:
49 __raw_writel(latch, SYS_TRC(TIMER_CLOCKEVENT));
50 REGSET(tc, SYS_TCx, REN, EN);
51 REGSET(tc, SYS_TCx, INTS, EN);
52 REGSET(tc, SYS_TCx, TEN, EN);
53 break;
54
55 case CLOCK_EVT_MODE_ONESHOT:
56 REGSET(tc, SYS_TCx, REN, DIS);
57 REGSET(tc, SYS_TCx, INTS, EN);
58
59 /* fall through */
60
61 case CLOCK_EVT_MODE_UNUSED:
62 case CLOCK_EVT_MODE_SHUTDOWN:
63 case CLOCK_EVT_MODE_RESUME:
64 default:
65 REGSET(tc, SYS_TCx, TEN, DIS);
66 break;
67 }
68
69 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
70}
30 71
31 return IRQ_HANDLED; 72static int ns9xxx_clockevent_setnextevent(unsigned long evt,
73 struct clock_event_device *clk)
74{
75 u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
76
77 if (REGGET(tc, SYS_TCx, TEN)) {
78 REGSET(tc, SYS_TCx, TEN, DIS);
79 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
80 }
81
82 REGSET(tc, SYS_TCx, TEN, EN);
83
84 __raw_writel(evt, SYS_TRC(TIMER_CLOCKEVENT));
85
86 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
87
88 return 0;
32} 89}
33 90
34static unsigned long ns9xxx_timer_gettimeoffset(void) 91static struct clock_event_device ns9xxx_clockevent_device = {
92 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT),
93 .shift = 20,
94 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
95 .set_mode = ns9xxx_clockevent_setmode,
96 .set_next_event = ns9xxx_clockevent_setnextevent,
97};
98
99static irqreturn_t ns9xxx_clockevent_handler(int irq, void *dev_id)
35{ 100{
36 /* return the microseconds which have passed since the last interrupt 101 int timerno = irq - IRQ_TIMER0;
37 * was _serviced_. That is, if an interrupt is pending or the counter 102 u32 tc;
38 * reloads, return one period more. */
39 103
40 u32 counter1 = SYS_TR(0); 104 struct clock_event_device *evt = &ns9xxx_clockevent_device;
41 int pending = SYS_ISR & (1 << IRQ_TIMER0);
42 u32 counter2 = SYS_TR(0);
43 u32 elapsed;
44 105
45 if (pending || counter2 > counter1) 106 /* clear irq */
46 elapsed = 2 * SYS_TRC(0) - counter2; 107 tc = __raw_readl(SYS_TC(timerno));
47 else 108 if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) {
48 elapsed = SYS_TRC(0) - counter1; 109 REGSET(tc, SYS_TCx, TEN, DIS);
110 __raw_writel(tc, SYS_TC(timerno));
111 }
112 REGSET(tc, SYS_TCx, INTC, SET);
113 __raw_writel(tc, SYS_TC(timerno));
114 REGSET(tc, SYS_TCx, INTC, UNSET);
115 __raw_writel(tc, SYS_TC(timerno));
49 116
50 return (elapsed * usecs_per_tick) >> 16; 117 evt->event_handler(evt);
51 118
119 return IRQ_HANDLED;
52} 120}
53 121
54static struct irqaction ns9xxx_timer_irq = { 122static struct irqaction ns9xxx_clockevent_action = {
55 .name = "NS9xxx Timer Tick", 123 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT),
56 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 124 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
57 .handler = ns9xxx_timer_interrupt, 125 .handler = ns9xxx_clockevent_handler,
58}; 126};
59 127
60static void __init ns9xxx_timer_init(void) 128static void __init ns9xxx_timer_init(void)
61{ 129{
62 int tc; 130 int tc;
63 131
64 usecs_per_tick = 132 tc = __raw_readl(SYS_TC(TIMER_CLOCKSOURCE));
65 SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); 133 if (REGGET(tc, SYS_TCx, TEN)) {
134 REGSET(tc, SYS_TCx, TEN, DIS);
135 __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE));
136 }
66 137
67 /* disable timer */ 138 __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE));
68 if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
69 SYS_TC(0) = tc & ~SYS_TCx_TEN;
70
71 SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0);
72 139
73 REGSET(tc, SYS_TCx, TEN, EN); 140 REGSET(tc, SYS_TCx, TEN, EN);
74 REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */
75 REGSET(tc, SYS_TCx, INTS, EN);
76 REGSET(tc, SYS_TCx, UDS, DOWN);
77 REGSET(tc, SYS_TCx, TDBG, STOP); 141 REGSET(tc, SYS_TCx, TDBG, STOP);
142 REGSET(tc, SYS_TCx, TLCS, CPU);
143 REGSET(tc, SYS_TCx, TM, IEE);
144 REGSET(tc, SYS_TCx, INTS, DIS);
145 REGSET(tc, SYS_TCx, UDS, UP);
78 REGSET(tc, SYS_TCx, TSZ, 32); 146 REGSET(tc, SYS_TCx, TSZ, 32);
79 REGSET(tc, SYS_TCx, REN, EN); 147 REGSET(tc, SYS_TCx, REN, EN);
80 SYS_TC(0) = tc;
81 148
82 setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); 149 __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE));
150
151 ns9xxx_clocksource.mult = clocksource_hz2mult(ns9xxx_cpuclock(),
152 ns9xxx_clocksource.shift);
153
154 clocksource_register(&ns9xxx_clocksource);
155
156 latch = SH_DIV(ns9xxx_cpuclock(), HZ, 0);
157
158 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
159 REGSET(tc, SYS_TCx, TEN, DIS);
160 REGSET(tc, SYS_TCx, TDBG, STOP);
161 REGSET(tc, SYS_TCx, TLCS, CPU);
162 REGSET(tc, SYS_TCx, TM, IEE);
163 REGSET(tc, SYS_TCx, INTS, DIS);
164 REGSET(tc, SYS_TCx, UDS, DOWN);
165 REGSET(tc, SYS_TCx, TSZ, 32);
166 REGSET(tc, SYS_TCx, REN, EN);
167 __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
168
169 ns9xxx_clockevent_device.mult = div_sc(ns9xxx_cpuclock(),
170 NSEC_PER_SEC, ns9xxx_clockevent_device.shift);
171 ns9xxx_clockevent_device.max_delta_ns =
172 clockevent_delta2ns(-1, &ns9xxx_clockevent_device);
173 ns9xxx_clockevent_device.min_delta_ns =
174 clockevent_delta2ns(1, &ns9xxx_clockevent_device);
175
176 ns9xxx_clockevent_device.cpumask = cpumask_of_cpu(0);
177 clockevents_register_device(&ns9xxx_clockevent_device);
178
179 setup_irq(IRQ_TIMER0 + TIMER_CLOCKEVENT, &ns9xxx_clockevent_action);
83} 180}
84 181
85struct sys_timer ns9xxx_timer = { 182struct sys_timer ns9xxx_timer = {
86 .init = ns9xxx_timer_init, 183 .init = ns9xxx_timer_init,
87 .offset = ns9xxx_timer_gettimeoffset,
88}; 184};