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> 241da177e4SLinus Torvalds #include <linux/timer.h> 25*f414f13fSArnd Bergmann #include <linux/clocksource.h> 26e317c8ccSFrederik Deweerdt #include <linux/irq.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <asm/thread_info.h> 29211baa70SRussell King #include <asm/sched_clock.h> 302d7c11bfSCatalin Marinas #include <asm/stacktrace.h> 318ff1443cSRussell King #include <asm/mach/arch.h> 321da177e4SLinus Torvalds #include <asm/mach/time.h> 331da177e4SLinus Torvalds 3463216d3cSArnd Bergmann #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \ 3563216d3cSArnd Bergmann defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) 361da177e4SLinus Torvalds /* this needs a better home */ 371da177e4SLinus Torvalds DEFINE_SPINLOCK(rtc_lock); 381da177e4SLinus Torvalds EXPORT_SYMBOL(rtc_lock); 399dd34948SDavid Brownell #endif /* pc-style 'CMOS' RTC support */ 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* change this if you have some constant time drift */ 421da177e4SLinus Torvalds #define USECS_PER_JIFFY (1000000/HZ) 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #ifdef CONFIG_SMP 451da177e4SLinus Torvalds unsigned long profile_pc(struct pt_regs *regs) 461da177e4SLinus Torvalds { 472d7c11bfSCatalin Marinas struct stackframe frame; 481da177e4SLinus Torvalds 492d7c11bfSCatalin Marinas if (!in_lock_functions(regs->ARM_pc)) 502d7c11bfSCatalin Marinas return regs->ARM_pc; 511da177e4SLinus Torvalds 522d7c11bfSCatalin Marinas frame.fp = regs->ARM_fp; 532d7c11bfSCatalin Marinas frame.sp = regs->ARM_sp; 542d7c11bfSCatalin Marinas frame.lr = regs->ARM_lr; 552d7c11bfSCatalin Marinas frame.pc = regs->ARM_pc; 562d7c11bfSCatalin Marinas do { 572d7c11bfSCatalin Marinas int ret = unwind_frame(&frame); 582d7c11bfSCatalin Marinas if (ret < 0) 592d7c11bfSCatalin Marinas return 0; 602d7c11bfSCatalin Marinas } while (in_lock_functions(frame.pc)); 612d7c11bfSCatalin Marinas 622d7c11bfSCatalin Marinas return frame.pc; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds EXPORT_SYMBOL(profile_pc); 651da177e4SLinus Torvalds #endif 661da177e4SLinus Torvalds 679e4559ddSKevin Hilman #ifndef CONFIG_GENERIC_CLOCKEVENTS 681da177e4SLinus Torvalds /* 691da177e4SLinus Torvalds * Kernel system timer support. 701da177e4SLinus Torvalds */ 710cd61b68SLinus Torvalds void timer_tick(void) 721da177e4SLinus Torvalds { 73e317c8ccSFrederik Deweerdt profile_tick(CPU_PROFILING); 746906e33cSTorben Hohn xtime_update(1); 751da177e4SLinus Torvalds #ifndef CONFIG_SMP 76c97d4869SRussell King update_process_times(user_mode(get_irq_regs())); 771da177e4SLinus Torvalds #endif 781da177e4SLinus Torvalds } 799e4559ddSKevin Hilman #endif 801da177e4SLinus Torvalds 81bd0493eaSMarc Zyngier static void dummy_clock_access(struct timespec *ts) 82bd0493eaSMarc Zyngier { 83bd0493eaSMarc Zyngier ts->tv_sec = 0; 84bd0493eaSMarc Zyngier ts->tv_nsec = 0; 85bd0493eaSMarc Zyngier } 86bd0493eaSMarc Zyngier 87bd0493eaSMarc Zyngier static clock_access_fn __read_persistent_clock = dummy_clock_access; 88bd0493eaSMarc Zyngier static clock_access_fn __read_boot_clock = dummy_clock_access;; 89bd0493eaSMarc Zyngier 90bd0493eaSMarc Zyngier void read_persistent_clock(struct timespec *ts) 91bd0493eaSMarc Zyngier { 92bd0493eaSMarc Zyngier __read_persistent_clock(ts); 93bd0493eaSMarc Zyngier } 94bd0493eaSMarc Zyngier 95bd0493eaSMarc Zyngier void read_boot_clock(struct timespec *ts) 96bd0493eaSMarc Zyngier { 97bd0493eaSMarc Zyngier __read_boot_clock(ts); 98bd0493eaSMarc Zyngier } 99bd0493eaSMarc Zyngier 100bd0493eaSMarc Zyngier int __init register_persistent_clock(clock_access_fn read_boot, 101bd0493eaSMarc Zyngier clock_access_fn read_persistent) 102bd0493eaSMarc Zyngier { 103bd0493eaSMarc Zyngier /* Only allow the clockaccess functions to be registered once */ 104bd0493eaSMarc Zyngier if (__read_persistent_clock == dummy_clock_access && 105bd0493eaSMarc Zyngier __read_boot_clock == dummy_clock_access) { 106bd0493eaSMarc Zyngier if (read_boot) 107bd0493eaSMarc Zyngier __read_boot_clock = read_boot; 108bd0493eaSMarc Zyngier if (read_persistent) 109bd0493eaSMarc Zyngier __read_persistent_clock = read_persistent; 110bd0493eaSMarc Zyngier 111bd0493eaSMarc Zyngier return 0; 112bd0493eaSMarc Zyngier } 113bd0493eaSMarc Zyngier 114bd0493eaSMarc Zyngier return -EINVAL; 115bd0493eaSMarc Zyngier } 116bd0493eaSMarc Zyngier 1171da177e4SLinus Torvalds void __init time_init(void) 1181da177e4SLinus Torvalds { 119*f414f13fSArnd Bergmann if (machine_desc->init_time) 1206bb27d73SStephen Warren machine_desc->init_time(); 121*f414f13fSArnd Bergmann else 122*f414f13fSArnd Bergmann clocksource_of_init(); 123*f414f13fSArnd Bergmann 124211baa70SRussell King sched_clock_postinit(); 1251da177e4SLinus Torvalds } 126