1 /* linux/arch/arm/mach-s5pv310/time.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * S5PV310 (and compatible) HRT support
7 * System timer is used for this feature
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.
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>
23 #include <asm/smp_twd.h>
25 #include <mach/cpu_revision.h>
26 #include <mach/regs-systimer.h>
27 #include <plat/regs-timer.h>
28 #include <asm/mach/time.h>
35 static unsigned long systimer_clk_cnt_per_tick;
36 static unsigned long pwm_clk_cnt_per_tick;
38 static struct clk *systimer_clk;
39 static struct clk *pwm_clk;
40 static struct clk *tin4;
41 static struct clk *tdiv4;
44 * Clockevent handling.
46 static void s5pv310_systimer_write(unsigned int value, void *reg_offset)
48 unsigned int temp_regs;
50 /* TODO: EVT1 Has Different System Timer */
51 if (cpu_revision >= 1)
54 __raw_writel(value, reg_offset);
56 if (reg_offset == S5PV310_TCON) {
57 while (!(__raw_readl(S5PV310_INT_CSTAT) & 1<<7));
59 temp_regs = __raw_readl(S5PV310_INT_CSTAT);
61 __raw_writel(temp_regs, S5PV310_INT_CSTAT);
63 } else if (reg_offset == S5PV310_TICNTB) {
64 while (!(__raw_readl(S5PV310_INT_CSTAT) & 1<<3));
66 temp_regs = __raw_readl(S5PV310_INT_CSTAT);
68 __raw_writel(temp_regs, S5PV310_INT_CSTAT);
70 } else if (reg_offset == S5PV310_FRCNTB) {
71 while (!(__raw_readl(S5PV310_INT_CSTAT) & 1<<6));
73 temp_regs = __raw_readl(S5PV310_INT_CSTAT);
75 __raw_writel(temp_regs, S5PV310_INT_CSTAT);
79 static void s5pv310_systimer_stop(enum systimer_type type)
83 tcon = __raw_readl(S5PV310_TCON);
87 tcon &= ~S5PV310_TCON_FRC_START;
91 tcon &= ~(S5PV310_TCON_TICK_START | S5PV310_TCON_TICK_INT_START);
98 s5pv310_systimer_write(tcon, S5PV310_TCON);
101 static void s5pv310_systimer_init(enum systimer_type type, unsigned long tcnt)
103 /* timers reload after counting zero, so reduce the count by 1 */
106 s5pv310_systimer_stop(type);
110 s5pv310_systimer_write(tcnt, S5PV310_FRCNTB);
114 s5pv310_systimer_write(tcnt, S5PV310_TICNTB);
115 s5pv310_systimer_write(0, S5PV310_TFCNTB);
123 static inline void s5pv310_systimer_start(enum systimer_type type)
128 tcon = __raw_readl(S5PV310_TCON);
132 tcon |= S5PV310_TCON_FRC_START;
135 tcfg = __raw_readl(S5PV310_TCFG);
136 tcfg |= S5PV310_TCFG_TICK_SWRST;
137 s5pv310_systimer_write(tcfg, S5PV310_TCFG);
139 tcon |= S5PV310_TCON_TICK_START | S5PV310_TCON_TICK_INT_START;
144 s5pv310_systimer_write(tcon, S5PV310_TCON);
148 static int s5pv310_systimer_set_next_event(unsigned long cycles,
149 struct clock_event_device *evt)
151 s5pv310_systimer_init(SYS_TICK, cycles);
152 s5pv310_systimer_start(SYS_TICK);
156 static void s5pv310_systimer_set_mode(enum clock_event_mode mode,
157 struct clock_event_device *evt)
159 s5pv310_systimer_stop(SYS_TICK);
162 case CLOCK_EVT_MODE_PERIODIC:
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
168 s5pv310_systimer_init(SYS_TICK, systimer_clk_cnt_per_tick / 2);
169 s5pv310_systimer_start(SYS_TICK);
171 case CLOCK_EVT_MODE_ONESHOT:
172 case CLOCK_EVT_MODE_UNUSED:
173 case CLOCK_EVT_MODE_SHUTDOWN:
174 case CLOCK_EVT_MODE_RESUME:
179 static struct clock_event_device sys_tick_event_device = {
181 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
184 .set_next_event = s5pv310_systimer_set_next_event,
185 .set_mode = s5pv310_systimer_set_mode,
188 irqreturn_t s5pv310_systimer_event_isr(int irq, void *dev_id)
190 struct clock_event_device *evt = &sys_tick_event_device;
191 unsigned long int_status;
193 if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
194 s5pv310_systimer_stop(SYS_TICK);
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);
201 evt->event_handler(evt);
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,
212 static void __init systimer_clockevent_init(void)
214 unsigned long clock_rate;
216 clock_rate = clk_get_rate(systimer_clk);
218 systimer_clk_cnt_per_tick = clock_rate / HZ;
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);
227 sys_tick_event_device.cpumask = cpumask_of(0);
228 clockevents_register_device(&sys_tick_event_device);
230 s5pv310_systimer_write(S5PV310_INT_TICK_EN | S5PV310_INT_EN, S5PV310_INT_CSTAT);
231 setup_irq(IRQ_SYSTEM_TIMER, &s5pv310_systimer_event_irq);
234 static void s5pv310_pwm_stop(unsigned int pwm_id)
238 tcon = __raw_readl(S3C2410_TCON);
242 tcon &= ~S3C2410_TCON_T2START;
245 tcon &= ~S3C2410_TCON_T4START;
250 __raw_writel(tcon, S3C2410_TCON);
253 static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
257 tcon = __raw_readl(S3C2410_TCON);
259 /* timers reload after counting zero, so reduce the count by 1 */
262 /* ensure timer is stopped... */
266 tcon |= S3C2410_TCON_T2MANUALUPD;
268 __raw_writel(tcnt, S3C2410_TCNTB(2));
269 __raw_writel(tcnt, S3C2410_TCMPB(2));
270 __raw_writel(tcon, S3C2410_TCON);
275 tcon |= S3C2410_TCON_T4MANUALUPD;
277 __raw_writel(tcnt, S3C2410_TCNTB(4));
278 __raw_writel(tcnt, S3C2410_TCMPB(4));
279 __raw_writel(tcon, S3C2410_TCON);
287 static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
291 tcon = __raw_readl(S3C2410_TCON);
295 tcon |= S3C2410_TCON_T2START;
296 tcon &= ~S3C2410_TCON_T2MANUALUPD;
299 tcon |= S3C2410_TCON_T2RELOAD;
301 tcon &= ~S3C2410_TCON_T2RELOAD;
304 tcon |= S3C2410_TCON_T4START;
305 tcon &= ~S3C2410_TCON_T4MANUALUPD;
308 tcon |= S3C2410_TCON_T4RELOAD;
310 tcon &= ~S3C2410_TCON_T4RELOAD;
315 __raw_writel(tcon, S3C2410_TCON);
318 static int s5pv310_pwm_set_next_event(unsigned long cycles,
319 struct clock_event_device *evt)
321 s5pv310_pwm_init(4, cycles);
322 s5pv310_pwm_start(4, 0);
326 static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
327 struct clock_event_device *evt)
332 case CLOCK_EVT_MODE_PERIODIC:
333 s5pv310_pwm_init(4, pwm_clk_cnt_per_tick);
334 s5pv310_pwm_start(4, 1);
336 case CLOCK_EVT_MODE_ONESHOT:
337 case CLOCK_EVT_MODE_UNUSED:
338 case CLOCK_EVT_MODE_SHUTDOWN:
339 case CLOCK_EVT_MODE_RESUME:
344 static struct clock_event_device pwm_event_device = {
345 .name = "pwm_timer4",
346 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
349 .set_next_event = s5pv310_pwm_set_next_event,
350 .set_mode = s5pv310_pwm_set_mode,
353 irqreturn_t s5pv310_pwm_event_isr(int irq, void *dev_id)
355 struct clock_event_device *evt = &pwm_event_device;
357 evt->event_handler(evt);
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,
368 static void __init pwm_clockevent_init(void)
371 unsigned long clock_rate;
374 unsigned int stat = __raw_readl(S3C64XX_TINT_CSTAT) & 0x1f;
376 pclk = clk_get_rate(pwm_clk);
378 /* configure clock tick */
379 tscaler = clk_get_parent(tdiv4);
381 clk_set_rate(tscaler, pclk / 2);
382 clk_set_rate(tdiv4, pclk / 2);
383 clk_set_parent(tin4, tdiv4);
385 clock_rate = clk_get_rate(tin4);
387 pwm_clk_cnt_per_tick = clock_rate / HZ;
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);
396 pwm_event_device.cpumask = cpumask_of(1);
399 __raw_writel(stat, S3C64XX_TINT_CSTAT);
402 static void __init s5pv310_clockevent_init(void)
404 systimer_clockevent_init();
405 pwm_clockevent_init();
408 #ifdef CONFIG_LOCAL_TIMERS
410 * * Setup the local clock events for a CPU.
412 void __cpuinit local_timer_setup_evt0(struct clock_event_device *evt)
414 unsigned int cpu = smp_processor_id();
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);
423 stat = __raw_readl(S3C64XX_TINT_CSTAT) & 0x1f;
425 __raw_writel(stat, S3C64XX_TINT_CSTAT);
429 int local_timer_ack_evt0(void)
434 #ifdef CONFIG_HOTPLUG_CPU
435 void local_timer_stop_evt0(void)
437 unsigned int stat = __raw_readl(S3C64XX_TINT_CSTAT) & 0x1f;
444 __raw_writel(stat, S3C64XX_TINT_CSTAT);
451 * Clocksource handling
453 static cycle_t s5pv310_frc_read(struct clocksource *cs)
455 return (cycle_t) (0xffffffff - __raw_readl(S5PV310_FRCNTO));
458 struct clocksource sys_frc_clksrc = {
461 .read = s5pv310_frc_read,
462 .mask = CLOCKSOURCE_MASK(32),
464 .flags = CLOCK_SOURCE_IS_CONTINUOUS ,
467 static void __init s5pv310_clocksource_init(void)
469 unsigned long clock_rate;
471 clock_rate = clk_get_rate(systimer_clk);
473 sys_frc_clksrc.mult =
474 clocksource_khz2mult(clock_rate/1000, sys_frc_clksrc.shift);
476 s5pv310_systimer_init(SYS_FRC, 0);
477 s5pv310_systimer_start(SYS_FRC);
479 if (clocksource_register(&sys_frc_clksrc))
480 panic("%s: can't register clocksource\n", sys_frc_clksrc.name);
483 static void __init s5pv310_timer_resources(void)
486 struct platform_device tmpdev;
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);
493 /* get system timer source clock and enable */
494 systimer_clk = clk_get(NULL, "ext_xtal");
496 if (IS_ERR(systimer_clk))
497 panic("failed to get ext_xtal clock for system timer");
499 clk_enable(systimer_clk);
501 /* get pwm timer4 source clock and enable */
502 pwm_clk = clk_get(NULL, "timers");
504 panic("failed to get timers clock for pwm timer");
508 tmpdev.dev.bus = &platform_bus_type;
511 tin4 = clk_get(&tmpdev.dev, "pwm-tin");
513 panic("failed to get pwm-tin4 clock for system timer");
515 tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
517 panic("failed to get pwm-tdiv4 clock for system timer");
523 * S5PV310's sched_clock implementation.
524 * (Inspired by ORION implementation)
526 #define TCLK2NS_SCALE_FACTOR 8
528 static unsigned long tclk2ns_scale;
530 unsigned long long sched_clock_evt0(void)
532 unsigned long long v;
534 if (tclk2ns_scale == 0)
537 v = cnt32_to_63(0xffffffff - __raw_readl(S5PV310_FRCNTO));
539 return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR;
542 static void __init s5pv310_setup_sched_clock(void)
544 unsigned long long v;
545 unsigned long clock_rate;
547 clock_rate = clk_get_rate(systimer_clk);
550 v <<= TCLK2NS_SCALE_FACTOR;
552 do_div(v, clock_rate);
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.
563 static void __init s5pv310_timer_init(void)
565 s5pv310_timer_resources();
567 s5pv310_clockevent_init();
568 s5pv310_clocksource_init();
570 s5pv310_setup_sched_clock();
573 struct sys_timer s5pv310_evt0_timer = {
574 .init = s5pv310_timer_init,
577 static int __init s5pv310_lpj_update(void)
584 for_each_online_cpu(cpu)
585 smp_store_cpu_info(cpu);
589 /* before cpufreq(late_initcall) and after timer select(fs_initcall) */
590 device_initcall(s5pv310_lpj_update);