11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/arm/kernel/time.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1991, 1992, 1995 Linus Torvalds 51da177e4SLinus Torvalds * Modifications for ARM (C) 1994-2001 Russell King 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 91da177e4SLinus Torvalds * published by the Free Software Foundation. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This file contains the ARM-specific time handling details: 121da177e4SLinus Torvalds * reading the RTC at bootup, etc... 131da177e4SLinus Torvalds */ 14ecea4ab6SPaul Gortmaker #include <linux/export.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/interrupt.h> 171da177e4SLinus Torvalds #include <linux/time.h> 181da177e4SLinus Torvalds #include <linux/init.h> 19d43c36dcSAlexey Dobriyan #include <linux/sched.h> 201da177e4SLinus Torvalds #include <linux/smp.h> 211da177e4SLinus Torvalds #include <linux/timex.h> 221da177e4SLinus Torvalds #include <linux/errno.h> 231da177e4SLinus Torvalds #include <linux/profile.h> 24328f5cc3SRafael J. Wysocki #include <linux/syscore_ops.h> 251da177e4SLinus Torvalds #include <linux/timer.h> 26e317c8ccSFrederik Deweerdt #include <linux/irq.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <asm/leds.h> 291da177e4SLinus Torvalds #include <asm/thread_info.h> 30211baa70SRussell King #include <asm/sched_clock.h> 312d7c11bfSCatalin Marinas #include <asm/stacktrace.h> 328ff1443cSRussell King #include <asm/mach/arch.h> 331da177e4SLinus Torvalds #include <asm/mach/time.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds /* 361da177e4SLinus Torvalds * Our system timer. 371da177e4SLinus Torvalds */ 388ff1443cSRussell King static struct sys_timer *system_timer; 391da177e4SLinus Torvalds 4063216d3cSArnd Bergmann #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \ 4163216d3cSArnd Bergmann defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) 421da177e4SLinus Torvalds /* this needs a better home */ 431da177e4SLinus Torvalds DEFINE_SPINLOCK(rtc_lock); 441da177e4SLinus Torvalds EXPORT_SYMBOL(rtc_lock); 459dd34948SDavid Brownell #endif /* pc-style 'CMOS' RTC support */ 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* change this if you have some constant time drift */ 481da177e4SLinus Torvalds #define USECS_PER_JIFFY (1000000/HZ) 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds #ifdef CONFIG_SMP 511da177e4SLinus Torvalds unsigned long profile_pc(struct pt_regs *regs) 521da177e4SLinus Torvalds { 532d7c11bfSCatalin Marinas struct stackframe frame; 541da177e4SLinus Torvalds 552d7c11bfSCatalin Marinas if (!in_lock_functions(regs->ARM_pc)) 562d7c11bfSCatalin Marinas return regs->ARM_pc; 571da177e4SLinus Torvalds 582d7c11bfSCatalin Marinas frame.fp = regs->ARM_fp; 592d7c11bfSCatalin Marinas frame.sp = regs->ARM_sp; 602d7c11bfSCatalin Marinas frame.lr = regs->ARM_lr; 612d7c11bfSCatalin Marinas frame.pc = regs->ARM_pc; 622d7c11bfSCatalin Marinas do { 632d7c11bfSCatalin Marinas int ret = unwind_frame(&frame); 642d7c11bfSCatalin Marinas if (ret < 0) 652d7c11bfSCatalin Marinas return 0; 662d7c11bfSCatalin Marinas } while (in_lock_functions(frame.pc)); 672d7c11bfSCatalin Marinas 682d7c11bfSCatalin Marinas return frame.pc; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds EXPORT_SYMBOL(profile_pc); 711da177e4SLinus Torvalds #endif 721da177e4SLinus Torvalds 735cfc8ee0SJohn Stultz #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET 745cfc8ee0SJohn Stultz u32 arch_gettimeoffset(void) 751da177e4SLinus Torvalds { 765cfc8ee0SJohn Stultz if (system_timer->offset != NULL) 775cfc8ee0SJohn Stultz return system_timer->offset() * 1000; 785cfc8ee0SJohn Stultz 791da177e4SLinus Torvalds return 0; 801da177e4SLinus Torvalds } 815cfc8ee0SJohn Stultz #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds #ifdef CONFIG_LEDS_TIMER 841da177e4SLinus Torvalds static inline void do_leds(void) 851da177e4SLinus Torvalds { 866d15cb42SDavid Brownell static unsigned int count = HZ/2; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds if (--count == 0) { 896d15cb42SDavid Brownell count = HZ/2; 901da177e4SLinus Torvalds leds_event(led_timer); 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds #else 941da177e4SLinus Torvalds #define do_leds() 951da177e4SLinus Torvalds #endif 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds 989e4559ddSKevin Hilman #ifndef CONFIG_GENERIC_CLOCKEVENTS 991da177e4SLinus Torvalds /* 1001da177e4SLinus Torvalds * Kernel system timer support. 1011da177e4SLinus Torvalds */ 1020cd61b68SLinus Torvalds void timer_tick(void) 1031da177e4SLinus Torvalds { 104e317c8ccSFrederik Deweerdt profile_tick(CPU_PROFILING); 1051da177e4SLinus Torvalds do_leds(); 1066906e33cSTorben Hohn xtime_update(1); 1071da177e4SLinus Torvalds #ifndef CONFIG_SMP 108c97d4869SRussell King update_process_times(user_mode(get_irq_regs())); 1091da177e4SLinus Torvalds #endif 1101da177e4SLinus Torvalds } 1119e4559ddSKevin Hilman #endif 1121da177e4SLinus Torvalds 113*bd0493eaSMarc Zyngier static void dummy_clock_access(struct timespec *ts) 114*bd0493eaSMarc Zyngier { 115*bd0493eaSMarc Zyngier ts->tv_sec = 0; 116*bd0493eaSMarc Zyngier ts->tv_nsec = 0; 117*bd0493eaSMarc Zyngier } 118*bd0493eaSMarc Zyngier 119*bd0493eaSMarc Zyngier static clock_access_fn __read_persistent_clock = dummy_clock_access; 120*bd0493eaSMarc Zyngier static clock_access_fn __read_boot_clock = dummy_clock_access;; 121*bd0493eaSMarc Zyngier 122*bd0493eaSMarc Zyngier void read_persistent_clock(struct timespec *ts) 123*bd0493eaSMarc Zyngier { 124*bd0493eaSMarc Zyngier __read_persistent_clock(ts); 125*bd0493eaSMarc Zyngier } 126*bd0493eaSMarc Zyngier 127*bd0493eaSMarc Zyngier void read_boot_clock(struct timespec *ts) 128*bd0493eaSMarc Zyngier { 129*bd0493eaSMarc Zyngier __read_boot_clock(ts); 130*bd0493eaSMarc Zyngier } 131*bd0493eaSMarc Zyngier 132*bd0493eaSMarc Zyngier int __init register_persistent_clock(clock_access_fn read_boot, 133*bd0493eaSMarc Zyngier clock_access_fn read_persistent) 134*bd0493eaSMarc Zyngier { 135*bd0493eaSMarc Zyngier /* Only allow the clockaccess functions to be registered once */ 136*bd0493eaSMarc Zyngier if (__read_persistent_clock == dummy_clock_access && 137*bd0493eaSMarc Zyngier __read_boot_clock == dummy_clock_access) { 138*bd0493eaSMarc Zyngier if (read_boot) 139*bd0493eaSMarc Zyngier __read_boot_clock = read_boot; 140*bd0493eaSMarc Zyngier if (read_persistent) 141*bd0493eaSMarc Zyngier __read_persistent_clock = read_persistent; 142*bd0493eaSMarc Zyngier 143*bd0493eaSMarc Zyngier return 0; 144*bd0493eaSMarc Zyngier } 145*bd0493eaSMarc Zyngier 146*bd0493eaSMarc Zyngier return -EINVAL; 147*bd0493eaSMarc Zyngier } 148*bd0493eaSMarc Zyngier 1499e4559ddSKevin Hilman #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) 150328f5cc3SRafael J. Wysocki static int timer_suspend(void) 1511da177e4SLinus Torvalds { 152328f5cc3SRafael J. Wysocki if (system_timer->suspend) 153328f5cc3SRafael J. Wysocki system_timer->suspend(); 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds return 0; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 158328f5cc3SRafael J. Wysocki static void timer_resume(void) 1591da177e4SLinus Torvalds { 160328f5cc3SRafael J. Wysocki if (system_timer->resume) 161328f5cc3SRafael J. Wysocki system_timer->resume(); 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds #else 1641da177e4SLinus Torvalds #define timer_suspend NULL 1651da177e4SLinus Torvalds #define timer_resume NULL 1661da177e4SLinus Torvalds #endif 1671da177e4SLinus Torvalds 168328f5cc3SRafael J. Wysocki static struct syscore_ops timer_syscore_ops = { 1691da177e4SLinus Torvalds .suspend = timer_suspend, 1701da177e4SLinus Torvalds .resume = timer_resume, 1711da177e4SLinus Torvalds }; 1721da177e4SLinus Torvalds 173328f5cc3SRafael J. Wysocki static int __init timer_init_syscore_ops(void) 1741da177e4SLinus Torvalds { 175328f5cc3SRafael J. Wysocki register_syscore_ops(&timer_syscore_ops); 176328f5cc3SRafael J. Wysocki 177328f5cc3SRafael J. Wysocki return 0; 1781da177e4SLinus Torvalds } 1798749af68SRussell King 180328f5cc3SRafael J. Wysocki device_initcall(timer_init_syscore_ops); 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds void __init time_init(void) 1831da177e4SLinus Torvalds { 1848ff1443cSRussell King system_timer = machine_desc->timer; 1851da177e4SLinus Torvalds system_timer->init(); 186211baa70SRussell King sched_clock_postinit(); 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 189