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
29
30
31
32
33
34
35#include <linux/types.h>
36#include <linux/init.h>
37#include <linux/kernel_stat.h>
38#include <linux/sched.h>
39#include <linux/spinlock.h>
40#include <linux/hardirq.h>
41
42#include <asm/compiler.h>
43#include <asm/mipsregs.h>
44#include <asm/time.h>
45#include <asm/div64.h>
46#include <asm/mach-au1x00/au1000.h>
47
48#include <linux/mc146818rtc.h>
49#include <linux/timex.h>
50
51static unsigned long r4k_offset;
52static unsigned long r4k_cur;
53int no_au1xxx_32khz;
54extern int allow_au1k_wait;
55
56#ifdef CONFIG_PM
57#if HZ < 100 || HZ > 1000
58#error "unsupported HZ value! Must be in [100,1000]"
59#endif
60#define MATCH20_INC (328*100/HZ)
61extern void startup_match20_interrupt(irq_handler_t handler);
62static unsigned long last_pc0, last_match20;
63#endif
64
65static DEFINE_SPINLOCK(time_lock);
66
67unsigned long wtimer;
68
69#ifdef CONFIG_PM
70static irqreturn_t counter0_irq(int irq, void *dev_id)
71{
72 unsigned long pc0;
73 int time_elapsed;
74 static int jiffie_drift = 0;
75
76 if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
77
78 printk(KERN_WARNING "counter 0 w status error\n");
79 return IRQ_NONE;
80 }
81
82 pc0 = au_readl(SYS_TOYREAD);
83 if (pc0 < last_match20) {
84
85 time_elapsed = (0xffffffff - last_match20) + pc0;
86 }
87 else {
88 time_elapsed = pc0 - last_match20;
89 }
90
91 while (time_elapsed > 0) {
92 do_timer(1);
93#ifndef CONFIG_SMP
94 update_process_times(user_mode(get_irq_regs()));
95#endif
96 time_elapsed -= MATCH20_INC;
97 last_match20 += MATCH20_INC;
98 jiffie_drift++;
99 }
100
101 last_pc0 = pc0;
102 au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
103 au_sync();
104
105
106
107
108
109 if (jiffie_drift >= 999) {
110 jiffie_drift -= 999;
111 do_timer(1);
112#ifndef CONFIG_SMP
113 update_process_times(user_mode(get_irq_regs()));
114#endif
115 }
116
117 return IRQ_HANDLED;
118}
119
120struct irqaction counter0_action = {
121 .handler = counter0_irq,
122 .flags = IRQF_DISABLED,
123 .name = "alchemy-toy",
124 .dev_id = NULL,
125};
126
127
128
129
130void
131wakeup_counter0_adjust(void)
132{
133 unsigned long pc0;
134 int time_elapsed;
135
136 pc0 = au_readl(SYS_TOYREAD);
137 if (pc0 < last_match20) {
138
139 time_elapsed = (0xffffffff - last_match20) + pc0;
140 }
141 else {
142 time_elapsed = pc0 - last_match20;
143 }
144
145 while (time_elapsed > 0) {
146 time_elapsed -= MATCH20_INC;
147 last_match20 += MATCH20_INC;
148 }
149
150 last_pc0 = pc0;
151 au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
152 au_sync();
153
154}
155
156
157
158void
159wakeup_counter0_set(int ticks)
160{
161 unsigned long pc0;
162
163 pc0 = au_readl(SYS_TOYREAD);
164 last_pc0 = pc0;
165 au_writel(last_match20 + (MATCH20_INC * ticks), SYS_TOYMATCH2);
166 au_sync();
167}
168#endif
169
170
171
172
173#define AU1000_SRC_CLK 12000000
174
175
176
177
178
179
180
181
182
183
184
185
186
187unsigned long cal_r4koff(void)
188{
189 unsigned long cpu_speed;
190 unsigned long flags;
191 unsigned long counter;
192
193 spin_lock_irqsave(&time_lock, flags);
194
195
196
197 no_au1xxx_32khz = 0;
198 counter = au_readl(SYS_COUNTER_CNTRL);
199 if (counter & SYS_CNTRL_E0) {
200 int trim_divide = 16;
201
202 au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);
203
204 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
205
206 au_writel(trim_divide-1, SYS_RTCTRIM);
207 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
208
209 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
210 au_writel(0, SYS_TOYWRITE);
211 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
212
213 cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
214 AU1000_SRC_CLK;
215 }
216 else {
217
218
219
220
221 cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
222 no_au1xxx_32khz = 1;
223 }
224 mips_hpt_frequency = cpu_speed;
225
226 set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
227 spin_unlock_irqrestore(&time_lock, flags);
228 return (cpu_speed / HZ);
229}
230
231void __init plat_time_init(void)
232{
233 unsigned int est_freq;
234
235 printk("calculating r4koff... ");
236 r4k_offset = cal_r4koff();
237 printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
238
239
240 est_freq = r4k_offset*HZ;
241 est_freq += 5000;
242 est_freq -= est_freq%10000;
243 printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
244 (est_freq%1000000)*100/1000000);
245 set_au1x00_speed(est_freq);
246 set_au1x00_lcd_clock();
247
248 r4k_cur = (read_c0_count() + r4k_offset);
249 write_c0_compare(r4k_cur);
250
251#ifdef CONFIG_PM
252
253
254
255
256
257
258
259
260
261
262
263
264 if (no_au1xxx_32khz) {
265 printk("WARNING: no 32KHz clock found.\n");
266
267
268 set_c0_status(IE_IRQ5);
269 }
270 else {
271 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
272 au_writel(0, SYS_TOYWRITE);
273 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
274
275 au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK);
276 au_writel(~0, SYS_WAKESRC);
277 au_sync();
278 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
279
280
281 last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
282 au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
283 au_sync();
284 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
285 setup_irq(AU1000_TOY_MATCH2_INT, &counter0_action);
286
287
288
289 allow_au1k_wait = 1;
290 }
291
292#endif
293}
294