diff options
-rw-r--r-- | arch/arm/mach-ux500/timer.c | 11 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 22 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 3 | ||||
-rw-r--r-- | drivers/clocksource/db5500-mtimer.c | 52 | ||||
-rw-r--r-- | include/linux/clksrc-db5500-mtimer.h | 17 |
5 files changed, 100 insertions, 5 deletions
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c index d37df98b5c3..aa76dcec7a6 100644 --- a/arch/arm/mach-ux500/timer.c +++ b/arch/arm/mach-ux500/timer.c @@ -7,6 +7,7 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/clksrc-dbx500-prcmu.h> +#include <linux/clksrc-db5500-mtimer.h> #include <linux/of.h> #include <asm/smp_twd.h> @@ -70,12 +71,18 @@ static void __init ux500_timer_init(void) * depending on delay which is not yet calibrated. RTC-RTT is in the * always-on powerdomain and is used as clockevent instead of twd when * sleeping. - * The PRCMU timer 4(3 for DB5500) register a clocksource and - * sched_clock with higher rating then MTU since is always-on. * + * The PRCMU timer 4 (3 for DB5500) registers a clocksource and + * sched_clock with higher rating than the MTU since it is + * always-on. + * + * On DB5500, the MTIMER is the best clocksource since, unlike the + * PRCMU timer, it doesn't occasionally go backwards. */ nmdk_timer_init(mtu_timer_base); + if (cpu_is_u5500()) + db5500_mtimer_init(__io_address(U5500_MTIMER_BASE)); clksrc_dbx500_prcmu_init(prcmu_timer_base); ux500_twd_init(); } diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5138927a416..d3694821bac 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -19,13 +19,31 @@ config DW_APB_TIMER config CLKSRC_DBX500_PRCMU bool "Clocksource PRCMU Timer" depends on UX500_SOC_DB5500 || UX500_SOC_DB8500 - default y + default y if UX500_SOC_DB8500 help Use the always on PRCMU Timer as clocksource config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" - depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK) + depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK && \ + !CLKSRC_DB5500_MTIMER_SCHED_CLOCK) + select HAVE_SCHED_CLOCK + default y + help + Use the always on PRCMU Timer as sched_clock + +config CLKSRC_DB5500_MTIMER + bool "Clocksource MTIMER" + depends on UX500_SOC_DB5500 + default y + help + Use the always on MTIMER as clocksource + +config CLKSRC_DB5500_MTIMER_SCHED_CLOCK + bool "Clocksource MTIMER sched_clock" + depends on (CLKSRC_DB5500_MTIMER && !NOMADIK_MTU_SCHED_CLOCK && \ + !CLKSRC_DBX500_PRCMU_SCHED_CLOCK) + select HAVE_SCHED_CLOCK default y help Use the always on PRCMU Timer as sched_clock diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 8d81a1d3265..9b10f6b7536 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o -obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
\ No newline at end of file +obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o +obj-$(CONFIG_CLKSRC_DB5500_MTIMER) += db5500-mtimer.o diff --git a/drivers/clocksource/db5500-mtimer.c b/drivers/clocksource/db5500-mtimer.c new file mode 100644 index 00000000000..641279707a8 --- /dev/null +++ b/drivers/clocksource/db5500-mtimer.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ + +#include <linux/io.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/clockchips.h> +#include <linux/clksrc-db5500-mtimer.h> + +#include <asm/sched_clock.h> + +#define MTIMER_PRIMARY_COUNTER 0x18 + +static void __iomem *db5500_mtimer_base; + +#ifdef CONFIG_CLKSRC_DB5500_MTIMER_SCHED_CLOCK +static DEFINE_CLOCK_DATA(cd); + +unsigned long long notrace sched_clock(void) +{ + u32 cyc; + + if (unlikely(!db5500_mtimer_base)) + return 0; + + cyc = readl_relaxed(db5500_mtimer_base + MTIMER_PRIMARY_COUNTER); + + return cyc_to_sched_clock(&cd, cyc, (u32)~0); +} + +static void notrace db5500_mtimer_update_sched_clock(void) +{ + u32 cyc = readl_relaxed(db5500_mtimer_base + MTIMER_PRIMARY_COUNTER); + update_sched_clock(&cd, cyc, (u32)~0); +} +#endif + +void __init db5500_mtimer_init(void __iomem *base) +{ + db5500_mtimer_base = base; + + clocksource_mmio_init(base + MTIMER_PRIMARY_COUNTER, "mtimer", 32768, + 400, 32, clocksource_mmio_readl_up); + +#ifdef CONFIG_CLKSRC_DB5500_MTIMER_SCHED_CLOCK + init_sched_clock(&cd, db5500_mtimer_update_sched_clock, + 32, 32768); +#endif +} diff --git a/include/linux/clksrc-db5500-mtimer.h b/include/linux/clksrc-db5500-mtimer.h new file mode 100644 index 00000000000..3112c7f2709 --- /dev/null +++ b/include/linux/clksrc-db5500-mtimer.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + */ +#ifndef __CLKSRC_DB5500_MTIMER_H +#define __CLKSRC_DB5500_MTIMER_H + +#include <linux/io.h> + +#ifdef CONFIG_CLKSRC_DB5500_MTIMER +void db5500_mtimer_init(void __iomem *base); +#else +static inline void db5500_mtimer_init(void __iomem *base) {} +#endif + +#endif |