upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / time.c
1 /* linux/arch/arm/mach-s5pv310/time.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * S5PV310 (and compatible) HRT support
7  * System timer is used for this feature
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12 */
13
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/err.h>
17 #include <linux/clk.h>
18 #include <linux/clockchips.h>
19 #include <linux/cnt32_to_63.h>
20 #include <linux/platform_device.h>
21 #include <linux/delay.h>
22
23 #include <asm/smp_twd.h>
24
25 #include <mach/cpu_revision.h>
26 #include <mach/regs-systimer.h>
27 #include <plat/regs-timer.h>
28 #include <asm/mach/time.h>
29
30 enum systimer_type {
31         SYS_FRC,
32         SYS_TICK,
33 };
34
35 static unsigned long systimer_clk_cnt_per_tick;
36 static unsigned long pwm_clk_cnt_per_tick;
37
38 static struct clk *systimer_clk;
39 static struct clk *pwm_clk;
40 static struct clk *tin4;
41 static struct clk *tdiv4;
42
43 /*
44  * Clockevent handling.
45  */
46 static void s5pv310_systimer_write(unsigned int value,  void *reg_offset)
47 {
48         unsigned int temp_regs;
49
50         /* TODO: EVT1 Has Different System Timer */
51         if (cpu_revision >= 1)
52                 return;
53
54         __raw_writel(value, reg_offset);
55
56         if (reg_offset == S5PV310_TCON) {
57                 while (!(__raw_readl(S5PV310_INT_CSTAT) & 1<<7));
58
59                 temp_regs = __raw_readl(S5PV310_INT_CSTAT);
60                 temp_regs |= 1<<7;
61                 __raw_writel(temp_regs, S5PV310_INT_CSTAT);
62
63         } else if (reg_offset == S5PV310_TICNTB) {
64                 while (!(__raw_readl(S5PV310_INT_CSTAT) & 1<<3));
65
66                 temp_regs = __raw_readl(S5PV310_INT_CSTAT);
67                 temp_regs |= 1<<3;
68                 __raw_writel(temp_regs, S5PV310_INT_CSTAT);
69
70         } else if (reg_offset == S5PV310_FRCNTB) {
71                 while (!(__raw_readl(S5PV310_INT_CSTAT) & 1<<6));
72
73                 temp_regs = __raw_readl(S5PV310_INT_CSTAT);
74                 temp_regs |= 1<<6;
75                 __raw_writel(temp_regs, S5PV310_INT_CSTAT);
76         }
77 }
78
79 static void s5pv310_systimer_stop(enum systimer_type type)
80 {
81         unsigned long tcon;
82
83         tcon = __raw_readl(S5PV310_TCON);
84
85         switch (type) {
86         case SYS_FRC:
87                 tcon &= ~S5PV310_TCON_FRC_START;
88                 break;
89
90         case SYS_TICK:
91                 tcon &= ~(S5PV310_TCON_TICK_START | S5PV310_TCON_TICK_INT_START);
92                 break;
93
94         default:
95                 break;
96         }
97
98         s5pv310_systimer_write(tcon, S5PV310_TCON);
99 }
100
101 static void s5pv310_systimer_init(enum systimer_type type, unsigned long tcnt)
102 {
103         /* timers reload after counting zero, so reduce the count by 1 */
104         tcnt--;
105
106         s5pv310_systimer_stop(type);
107
108         switch (type) {
109         case SYS_FRC:
110                 s5pv310_systimer_write(tcnt, S5PV310_FRCNTB);
111                 break;
112
113         case SYS_TICK:
114                 s5pv310_systimer_write(tcnt, S5PV310_TICNTB);
115                 s5pv310_systimer_write(0, S5PV310_TFCNTB);
116                 break;
117
118         default:
119                 break;
120         }
121 }
122
123 static inline void s5pv310_systimer_start(enum systimer_type type)
124 {
125         unsigned long tcon;
126         unsigned long tcfg;
127
128         tcon = __raw_readl(S5PV310_TCON);
129
130         switch (type) {
131         case SYS_FRC:
132                 tcon |= S5PV310_TCON_FRC_START;
133                 break;
134         case SYS_TICK:
135                 tcfg = __raw_readl(S5PV310_TCFG);
136                 tcfg |= S5PV310_TCFG_TICK_SWRST;
137                 s5pv310_systimer_write(tcfg, S5PV310_TCFG);
138
139                 tcon |= S5PV310_TCON_TICK_START | S5PV310_TCON_TICK_INT_START;
140                 break;
141         default:
142                 break;
143         }
144         s5pv310_systimer_write(tcon, S5PV310_TCON);
145
146 }
147
148 static int s5pv310_systimer_set_next_event(unsigned long cycles,
149                                         struct clock_event_device *evt)
150 {
151         s5pv310_systimer_init(SYS_TICK, cycles);
152         s5pv310_systimer_start(SYS_TICK);
153         return 0;
154 }
155
156 static void s5pv310_systimer_set_mode(enum clock_event_mode mode,
157                                 struct clock_event_device *evt)
158 {
159         s5pv310_systimer_stop(SYS_TICK);
160
161         switch (mode) {
162         case CLOCK_EVT_MODE_PERIODIC:
163                 /*
164                  * S5PC210 User Manual REV0.1 29-7 says when TCFG[14]=1, TCFG[15]=0
165                  * as the U-boot does, The result freq = TCLKB / 2 / Value. Thus,
166                  * we need to add the divider
167                  */
168                 s5pv310_systimer_init(SYS_TICK, systimer_clk_cnt_per_tick / 2);
169                 s5pv310_systimer_start(SYS_TICK);
170                 break;
171         case CLOCK_EVT_MODE_ONESHOT:
172         case CLOCK_EVT_MODE_UNUSED:
173         case CLOCK_EVT_MODE_SHUTDOWN:
174         case CLOCK_EVT_MODE_RESUME:
175                 break;
176         }
177 }
178
179 static struct clock_event_device sys_tick_event_device = {
180         .name           = "sys_tick",
181         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
182         .rating         = 250,
183         .shift          = 32,
184         .set_next_event = s5pv310_systimer_set_next_event,
185         .set_mode       = s5pv310_systimer_set_mode,
186 };
187
188 irqreturn_t s5pv310_systimer_event_isr(int irq, void *dev_id)
189 {
190         struct clock_event_device *evt = &sys_tick_event_device;
191         unsigned long int_status;
192
193         if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
194                 s5pv310_systimer_stop(SYS_TICK);
195
196         /* Clear the system tick interrupt */
197         int_status = __raw_readl(S5PV310_INT_CSTAT);
198         int_status |= S5PV310_INT_TICK_STATUS;
199         s5pv310_systimer_write(int_status, S5PV310_INT_CSTAT);
200
201         evt->event_handler(evt);
202
203         return IRQ_HANDLED;
204 }
205
206 static struct irqaction s5pv310_systimer_event_irq = {
207         .name           = "sys_tick_irq",
208         .flags          = IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
209         .handler        = s5pv310_systimer_event_isr,
210 };
211
212 static void __init systimer_clockevent_init(void)
213 {
214         unsigned long clock_rate;
215
216         clock_rate = clk_get_rate(systimer_clk);
217
218         systimer_clk_cnt_per_tick = clock_rate / HZ;
219
220         sys_tick_event_device.mult =
221                 div_sc(clock_rate, NSEC_PER_SEC, sys_tick_event_device.shift);
222         sys_tick_event_device.max_delta_ns =
223                 clockevent_delta2ns(-1, &sys_tick_event_device);
224         sys_tick_event_device.min_delta_ns =
225                 clockevent_delta2ns(0x1, &sys_tick_event_device);
226
227         sys_tick_event_device.cpumask = cpumask_of(0);
228         clockevents_register_device(&sys_tick_event_device);
229
230         s5pv310_systimer_write(S5PV310_INT_TICK_EN | S5PV310_INT_EN, S5PV310_INT_CSTAT);
231         setup_irq(IRQ_SYSTEM_TIMER, &s5pv310_systimer_event_irq);
232 }
233
234 static void s5pv310_pwm_stop(unsigned int pwm_id)
235 {
236         unsigned long tcon;
237
238         tcon = __raw_readl(S3C2410_TCON);
239
240         switch (pwm_id) {
241         case 2:
242                 tcon &= ~S3C2410_TCON_T2START;
243                 break;
244         case 4:
245                 tcon &= ~S3C2410_TCON_T4START;
246                 break;
247         default:
248                 break;
249         }
250         __raw_writel(tcon, S3C2410_TCON);
251 }
252
253 static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
254 {
255         unsigned long tcon;
256
257         tcon = __raw_readl(S3C2410_TCON);
258
259         /* timers reload after counting zero, so reduce the count by 1 */
260         tcnt--;
261
262         /* ensure timer is stopped... */
263         switch (pwm_id) {
264         case 2:
265                 tcon &= ~(0xf<<12);
266                 tcon |= S3C2410_TCON_T2MANUALUPD;
267
268                 __raw_writel(tcnt, S3C2410_TCNTB(2));
269                 __raw_writel(tcnt, S3C2410_TCMPB(2));
270                 __raw_writel(tcon, S3C2410_TCON);
271
272                 break;
273         case 4:
274                 tcon &= ~(7<<20);
275                 tcon |= S3C2410_TCON_T4MANUALUPD;
276
277                 __raw_writel(tcnt, S3C2410_TCNTB(4));
278                 __raw_writel(tcnt, S3C2410_TCMPB(4));
279                 __raw_writel(tcon, S3C2410_TCON);
280
281                 break;
282         default:
283                 break;
284         }
285 }
286
287 static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
288 {
289         unsigned long tcon;
290
291         tcon  = __raw_readl(S3C2410_TCON);
292
293         switch (pwm_id) {
294         case 2:
295                 tcon |= S3C2410_TCON_T2START;
296                 tcon &= ~S3C2410_TCON_T2MANUALUPD;
297
298                 if (periodic)
299                         tcon |= S3C2410_TCON_T2RELOAD;
300                 else
301                         tcon &= ~S3C2410_TCON_T2RELOAD;
302                 break;
303         case 4:
304                 tcon |= S3C2410_TCON_T4START;
305                 tcon &= ~S3C2410_TCON_T4MANUALUPD;
306
307                 if (periodic)
308                         tcon |= S3C2410_TCON_T4RELOAD;
309                 else
310                         tcon &= ~S3C2410_TCON_T4RELOAD;
311                 break;
312         default:
313                 break;
314         }
315         __raw_writel(tcon, S3C2410_TCON);
316 }
317
318 static int s5pv310_pwm_set_next_event(unsigned long cycles,
319                                         struct clock_event_device *evt)
320 {
321         s5pv310_pwm_init(4, cycles);
322         s5pv310_pwm_start(4, 0);
323         return 0;
324 }
325
326 static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
327                                 struct clock_event_device *evt)
328 {
329         s5pv310_pwm_stop(4);
330
331         switch (mode) {
332         case CLOCK_EVT_MODE_PERIODIC:
333                 s5pv310_pwm_init(4, pwm_clk_cnt_per_tick);
334                 s5pv310_pwm_start(4, 1);
335                 break;
336         case CLOCK_EVT_MODE_ONESHOT:
337         case CLOCK_EVT_MODE_UNUSED:
338         case CLOCK_EVT_MODE_SHUTDOWN:
339         case CLOCK_EVT_MODE_RESUME:
340                 break;
341         }
342 }
343
344 static struct clock_event_device pwm_event_device = {
345         .name           = "pwm_timer4",
346         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
347         .rating         = 250,
348         .shift          = 32,
349         .set_next_event = s5pv310_pwm_set_next_event,
350         .set_mode       = s5pv310_pwm_set_mode,
351 };
352
353 irqreturn_t s5pv310_pwm_event_isr(int irq, void *dev_id)
354 {
355         struct clock_event_device *evt = &pwm_event_device;
356
357         evt->event_handler(evt);
358
359         return IRQ_HANDLED;
360 }
361
362 static struct irqaction s5pv310_pwm_event_irq = {
363         .name           = "pwm_timer4_irq",
364         .flags          = IRQF_TIMER | IRQF_NOBALANCING,
365         .handler        = s5pv310_pwm_event_isr,
366 };
367
368 static void __init pwm_clockevent_init(void)
369 {
370         unsigned long pclk;
371         unsigned long clock_rate;
372         struct clk *tscaler;
373
374         unsigned int stat = __raw_readl(S3C64XX_TINT_CSTAT) & 0x1f;
375
376         pclk = clk_get_rate(pwm_clk);
377
378         /* configure clock tick */
379         tscaler = clk_get_parent(tdiv4);
380
381         clk_set_rate(tscaler, pclk / 2);
382         clk_set_rate(tdiv4, pclk / 2);
383         clk_set_parent(tin4, tdiv4);
384
385         clock_rate = clk_get_rate(tin4);
386
387         pwm_clk_cnt_per_tick = clock_rate / HZ;
388
389         pwm_event_device.mult =
390                 div_sc(clock_rate, NSEC_PER_SEC, pwm_event_device.shift);
391         pwm_event_device.max_delta_ns =
392                 clockevent_delta2ns(-1, &pwm_event_device);
393         pwm_event_device.min_delta_ns =
394                 clockevent_delta2ns(1, &pwm_event_device);
395
396         pwm_event_device.cpumask = cpumask_of(1);
397
398         stat |= 1 << 9;
399         __raw_writel(stat, S3C64XX_TINT_CSTAT);
400 }
401
402 static void __init s5pv310_clockevent_init(void)
403 {
404         systimer_clockevent_init();
405         pwm_clockevent_init();
406 }
407
408 #ifdef CONFIG_LOCAL_TIMERS
409 /*
410  *  * Setup the local clock events for a CPU.
411  *   */
412 void __cpuinit local_timer_setup_evt0(struct clock_event_device *evt)
413 {
414         unsigned int cpu = smp_processor_id();
415         unsigned int stat;
416
417         /* For cpu 1 */
418         if (cpu == 1) {
419                 clockevents_register_device(&pwm_event_device);
420                 irq_set_affinity(IRQ_SPI(22), cpumask_of(1));
421                 setup_irq(IRQ_TIMER4, &s5pv310_pwm_event_irq);
422
423                 stat = __raw_readl(S3C64XX_TINT_CSTAT) & 0x1f;
424                 stat |= 1 << 4;
425                 __raw_writel(stat, S3C64XX_TINT_CSTAT);
426         }
427 }
428
429 int local_timer_ack_evt0(void)
430 {
431         return 0;
432 }
433
434 #ifdef CONFIG_HOTPLUG_CPU
435 void local_timer_stop_evt0(void)
436 {
437         unsigned int stat = __raw_readl(S3C64XX_TINT_CSTAT) & 0x1f;
438
439         s5pv310_pwm_stop(4);
440
441         stat &= ~(1 << 4);
442         stat |= 1 << 9;
443
444         __raw_writel(stat, S3C64XX_TINT_CSTAT);
445 }
446 #endif
447
448 #endif
449
450 /*
451  * Clocksource handling
452  */
453 static cycle_t s5pv310_frc_read(struct clocksource *cs)
454 {
455         return (cycle_t) (0xffffffff - __raw_readl(S5PV310_FRCNTO));
456 }
457
458 struct clocksource sys_frc_clksrc = {
459         .name           = "sys_frc",
460         .rating         = 250,
461         .read           = s5pv310_frc_read,
462         .mask           = CLOCKSOURCE_MASK(32),
463         .shift          = 20,
464         .flags          = CLOCK_SOURCE_IS_CONTINUOUS ,
465 };
466
467 static void __init s5pv310_clocksource_init(void)
468 {
469         unsigned long clock_rate;
470
471         clock_rate = clk_get_rate(systimer_clk);
472
473         sys_frc_clksrc.mult =
474                 clocksource_khz2mult(clock_rate/1000, sys_frc_clksrc.shift);
475
476         s5pv310_systimer_init(SYS_FRC, 0);
477         s5pv310_systimer_start(SYS_FRC);
478
479         if (clocksource_register(&sys_frc_clksrc))
480                 panic("%s: can't register clocksource\n", sys_frc_clksrc.name);
481 }
482
483 static void __init s5pv310_timer_resources(void)
484 {
485         unsigned long tcfg;
486         struct platform_device tmpdev;
487
488         tcfg = __raw_readl(S5PV310_TCFG);
489         tcfg &= ~S5PV310_TCFG_CLKBASE_MASK;
490         tcfg |= S5PV310_TCFG_CLKBASE_SYS_MAIN;
491         s5pv310_systimer_write(tcfg, S5PV310_TCFG);
492
493         /* get system timer source clock and enable */
494         systimer_clk = clk_get(NULL, "ext_xtal");
495
496         if (IS_ERR(systimer_clk))
497                 panic("failed to get ext_xtal clock for system timer");
498
499         clk_enable(systimer_clk);
500
501         /* get pwm timer4 source clock and enable */
502         pwm_clk = clk_get(NULL, "timers");
503         if (IS_ERR(pwm_clk))
504                 panic("failed to get timers clock for pwm timer");
505
506         clk_enable(pwm_clk);
507
508         tmpdev.dev.bus = &platform_bus_type;
509         tmpdev.id = 4;
510
511         tin4 = clk_get(&tmpdev.dev, "pwm-tin");
512         if (IS_ERR(tin4))
513                 panic("failed to get pwm-tin4 clock for system timer");
514
515         tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
516         if (IS_ERR(tdiv4))
517                 panic("failed to get pwm-tdiv4 clock for system timer");
518
519         clk_enable(tin4);
520 }
521
522 /*
523  * S5PV310's sched_clock implementation.
524  * (Inspired by ORION implementation)
525  */
526 #define TCLK2NS_SCALE_FACTOR 8
527
528 static unsigned long tclk2ns_scale;
529
530 unsigned long long sched_clock_evt0(void)
531 {
532         unsigned long long v;
533
534         if (tclk2ns_scale == 0)
535                 return 0;
536
537         v = cnt32_to_63(0xffffffff - __raw_readl(S5PV310_FRCNTO));
538
539         return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR;
540 }
541
542 static void __init s5pv310_setup_sched_clock(void)
543 {
544         unsigned long long v;
545         unsigned long clock_rate;
546
547         clock_rate = clk_get_rate(systimer_clk);
548
549         v = NSEC_PER_SEC;
550         v <<= TCLK2NS_SCALE_FACTOR;
551         v += clock_rate/2;
552         do_div(v, clock_rate);
553         /*
554          * We want an even value to automatically clear the top bit
555          * returned by cnt32_to_63() without an additional run time
556          * instruction. So if the LSB is 1 then round it up.
557          */
558         if (v & 1)
559                 v++;
560         tclk2ns_scale = v;
561 }
562
563 static void __init s5pv310_timer_init(void)
564 {
565         s5pv310_timer_resources();
566
567         s5pv310_clockevent_init();
568         s5pv310_clocksource_init();
569
570         s5pv310_setup_sched_clock();
571 }
572
573 struct sys_timer s5pv310_evt0_timer = {
574         .init           = s5pv310_timer_init,
575 };
576
577 static int __init s5pv310_lpj_update(void)
578 {
579 #ifdef CONFIG_SMP
580         int cpu;
581 #endif
582         calibrate_delay();
583 #ifdef CONFIG_SMP
584         for_each_online_cpu(cpu)
585                 smp_store_cpu_info(cpu);
586 #endif
587         return 0;
588 }
589 /* before cpufreq(late_initcall) and after timer select(fs_initcall) */
590 device_initcall(s5pv310_lpj_update);
591