forked from Minki/linux
21884a83b2
Pull timer core updates from Thomas Gleixner: "The timer changes contain: - posix timer code consolidation and fixes for odd corner cases - sched_clock implementation moved from ARM to core code to avoid duplication by other architectures - alarm timer updates - clocksource and clockevents unregistration facilities - clocksource/events support for new hardware - precise nanoseconds RTC readout (Xen feature) - generic support for Xen suspend/resume oddities - the usual lot of fixes and cleanups all over the place The parts which touch other areas (ARM/XEN) have been coordinated with the relevant maintainers. Though this results in an handful of trivial to solve merge conflicts, which we preferred over nasty cross tree merge dependencies. The patches which have been committed in the last few days are bug fixes plus the posix timer lot. The latter was in akpms queue and next for quite some time; they just got forgotten and Frederic collected them last minute." * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (59 commits) hrtimer: Remove unused variable hrtimers: Move SMP function call to thread context clocksource: Reselect clocksource when watchdog validated high-res capability posix-cpu-timers: don't account cpu timer after stopped thread runtime accounting posix_timers: fix racy timer delta caching on task exit posix-timers: correctly get dying task time sample in posix_cpu_timer_schedule() selftests: add basic posix timers selftests posix_cpu_timers: consolidate expired timers check posix_cpu_timers: consolidate timer list cleanups posix_cpu_timer: consolidate expiry time type tick: Sanitize broadcast control logic tick: Prevent uncontrolled switch to oneshot mode tick: Make oneshot broadcast robust vs. CPU offlining x86: xen: Sync the CMOS RTC as well as the Xen wallclock x86: xen: Sync the wallclock when the system time is set timekeeping: Indicate that clock was set in the pvclock gtod notifier timekeeping: Pass flags instead of multiple bools to timekeeping_update() xen: Remove clock_was_set() call in the resume path hrtimers: Support resuming with two or more CPUs online (but stopped) timer: Fix jiffies wrap behavior of round_jiffies_common() ...
89 lines
2.4 KiB
C
89 lines
2.4 KiB
C
/*
|
|
* Copyright (C) ST-Ericsson SA 2011
|
|
*
|
|
* License Terms: GNU General Public License v2
|
|
* Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
|
|
* Author: Sundar Iyer for ST-Ericsson
|
|
* sched_clock implementation is based on:
|
|
* plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com>
|
|
*
|
|
* DBx500-PRCMU Timer
|
|
* The PRCMU has 5 timers which are available in a always-on
|
|
* power domain. We use the Timer 4 for our always-on clock
|
|
* source on DB8500.
|
|
*/
|
|
#include <linux/clockchips.h>
|
|
#include <linux/clksrc-dbx500-prcmu.h>
|
|
#include <linux/sched_clock.h>
|
|
|
|
#define RATE_32K 32768
|
|
|
|
#define TIMER_MODE_CONTINOUS 0x1
|
|
#define TIMER_DOWNCOUNT_VAL 0xffffffff
|
|
|
|
#define PRCMU_TIMER_REF 0
|
|
#define PRCMU_TIMER_DOWNCOUNT 0x4
|
|
#define PRCMU_TIMER_MODE 0x8
|
|
|
|
#define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */
|
|
|
|
static void __iomem *clksrc_dbx500_timer_base;
|
|
|
|
static cycle_t notrace clksrc_dbx500_prcmu_read(struct clocksource *cs)
|
|
{
|
|
void __iomem *base = clksrc_dbx500_timer_base;
|
|
u32 count, count2;
|
|
|
|
do {
|
|
count = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
|
|
count2 = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
|
|
} while (count2 != count);
|
|
|
|
/* Negate because the timer is a decrementing counter */
|
|
return ~count;
|
|
}
|
|
|
|
static struct clocksource clocksource_dbx500_prcmu = {
|
|
.name = "dbx500-prcmu-timer",
|
|
.rating = 300,
|
|
.read = clksrc_dbx500_prcmu_read,
|
|
.mask = CLOCKSOURCE_MASK(32),
|
|
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
|
};
|
|
|
|
#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK
|
|
|
|
static u32 notrace dbx500_prcmu_sched_clock_read(void)
|
|
{
|
|
if (unlikely(!clksrc_dbx500_timer_base))
|
|
return 0;
|
|
|
|
return clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu);
|
|
}
|
|
|
|
#endif
|
|
|
|
void __init clksrc_dbx500_prcmu_init(void __iomem *base)
|
|
{
|
|
clksrc_dbx500_timer_base = base;
|
|
|
|
/*
|
|
* The A9 sub system expects the timer to be configured as
|
|
* a continous looping timer.
|
|
* The PRCMU should configure it but if it for some reason
|
|
* don't we do it here.
|
|
*/
|
|
if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) !=
|
|
TIMER_MODE_CONTINOUS) {
|
|
writel(TIMER_MODE_CONTINOUS,
|
|
clksrc_dbx500_timer_base + PRCMU_TIMER_MODE);
|
|
writel(TIMER_DOWNCOUNT_VAL,
|
|
clksrc_dbx500_timer_base + PRCMU_TIMER_REF);
|
|
}
|
|
#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK
|
|
setup_sched_clock(dbx500_prcmu_sched_clock_read,
|
|
32, RATE_32K);
|
|
#endif
|
|
clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
|
|
}
|