From d8328f3b85f34c0dc5866f10bf6e7842fb511d62 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 15 Jan 2011 21:32:01 -0700 Subject: OMAP: counter_32k: init clocksource as part of machine timer init After commit dc548fbbd2ecd0fc3b02301d551e5f8e19ae58fd ("ARM: omap: convert sched_clock() to use new infrastructure"), OMAPs that use the 32KiHz "synchronization timer" as their clocksource crash during boot: [ 0.000000] OMAP clockevent source: GPTIMER1 at 32768 Hz [ 0.000000] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 0.000000] pgd = c0004000 [ 0.000000] [00000000] *pgd=00000000 [ 0.000000] Internal error: Oops: 80000005 [#1] SMP [ 0.000000] last sysfs file: [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 Tainted: G W (2.6.37-07734-g2467802 #7) [ 0.000000] PC is at 0x0 [ 0.000000] LR is at sched_clock_poll+0x2c/0x3c [ 0.000000] pc : [<00000000>] lr : [] psr: 600001d3 [ 0.000000] sp : c058bfd0 ip : c058a000 fp : 00000000 [ 0.000000] r10: 00000000 r9 : 411fc092 r8 : 800330c8 [ 0.000000] r7 : c05a08e0 r6 : c0034c48 r5 : c05ffc40 r4 : c0034c4c [ 0.000000] r3 : c05ffe6c r2 : c05a0bc0 r1 : c059f098 r0 : 00000000 [ 0.000000] Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel [ 0.000000] Control: 10c53c7f Table: 8000404a DAC: 00000017 This is due to the recent ARM init_sched_clock() changes and the late initialization of the counter_32k clock source. More information here: http://marc.info/?l=linux-omap&m=129513468605208&w=2 Fix by initializing the counter_32k clocksource during the machine timer initialization. Reported-by: Russell King Tested-by: Thomas Weber Signed-off-by: Paul Walmsley --- arch/arm/mach-omap1/time.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/arm/mach-omap1') diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index ed7a61ff916a..6ec65e599997 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -244,6 +244,13 @@ static void __init omap_timer_init(void) omap_init_mpu_timer(rate); omap_init_clocksource(rate); + /* + * XXX Since this file seems to deal mostly with the MPU timer, + * this doesn't seem like the correct place for the sync timer + * clocksource init. + */ + if (!cpu_is_omap7xx() && !cpu_is_omap15xx()) + omap_init_clocksource_32k(); } struct sys_timer omap_timer = { -- cgit v1.2.1 From f376ea1780085196fcfff6bc27e8f6ddb324ae57 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 18 Jan 2011 13:25:39 -0800 Subject: omap1: Fix sched_clock for the MPU timer Otherwise systems using the MPU timer will hang. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/time.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap1') diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 6ec65e599997..a39a15e4f3f9 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -44,11 +44,14 @@ #include #include #include +#include #include #include #include #include +#include + #include #include @@ -67,7 +70,7 @@ typedef struct { ((volatile omap_mpu_timer_regs_t*)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \ (n)*OMAP_MPU_TIMER_OFFSET)) -static inline unsigned long omap_mpu_timer_read(int nr) +static inline unsigned long notrace omap_mpu_timer_read(int nr) { volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); return timer->read_tim; @@ -212,6 +215,14 @@ static struct clocksource clocksource_mpu = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +static DEFINE_CLOCK_DATA(cd); + +static void notrace mpu_update_sched_clock(void) +{ + u32 cyc = mpu_read(&clocksource_mpu); + update_sched_clock(&cd, cyc, (u32)~0); +} + static void __init omap_init_clocksource(unsigned long rate) { static char err[] __initdata = KERN_ERR @@ -219,6 +230,7 @@ static void __init omap_init_clocksource(unsigned long rate) setup_irq(INT_TIMER2, &omap_mpu_timer2_irq); omap_mpu_timer_start(1, ~0, 1); + init_sched_clock(&cd, mpu_update_sched_clock, 32, rate); if (clocksource_register_hz(&clocksource_mpu, rate)) printk(err, clocksource_mpu.name); -- cgit v1.2.1 From 05b5ca9b100300c8b98429962071aa66c5d2460e Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 18 Jan 2011 12:42:23 -0800 Subject: omap1: Fix booting for 15xx and 730 with omap1_defconfig For omap15xx and 730 we need to use the MPU timer as the 32K timer is not available. For omap16xx we want to use the 32K timer because of PM. Fix this by allowing to build in both timers. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/Kconfig | 2 ++ arch/arm/mach-omap1/Makefile | 3 +-- arch/arm/mach-omap1/time.c | 48 ++++++++++++++++++++++++++++++------------ arch/arm/mach-omap1/timer32k.c | 13 ++++++------ 4 files changed, 44 insertions(+), 22 deletions(-) (limited to 'arch/arm/mach-omap1') diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 8d2f2daba0c0..e0a028161dde 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -9,6 +9,7 @@ config ARCH_OMAP730 depends on ARCH_OMAP1 bool "OMAP730 Based System" select CPU_ARM926T + select OMAP_MPU_TIMER select ARCH_OMAP_OTG config ARCH_OMAP850 @@ -22,6 +23,7 @@ config ARCH_OMAP15XX default y bool "OMAP15xx Based System" select CPU_ARM925T + select OMAP_MPU_TIMER config ARCH_OMAP16XX depends on ARCH_OMAP1 diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 6ee19504845f..ba6009f27677 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -3,12 +3,11 @@ # # Common support -obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o dma.o +obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o obj-y += clock.o clock_data.o opp_data.o obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o -obj-$(CONFIG_OMAP_MPU_TIMER) += time.o obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o # Power Management diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index a39a15e4f3f9..b03f34d55d88 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -57,6 +57,8 @@ #include +#ifdef CONFIG_OMAP_MPU_TIMER + #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE #define OMAP_MPU_TIMER_OFFSET 0x100 @@ -236,12 +238,7 @@ static void __init omap_init_clocksource(unsigned long rate) printk(err, clocksource_mpu.name); } -/* - * --------------------------------------------------------------------------- - * Timer initialization - * --------------------------------------------------------------------------- - */ -static void __init omap_timer_init(void) +static void __init omap_mpu_timer_init(void) { struct clk *ck_ref = clk_get(NULL, "ck_ref"); unsigned long rate; @@ -256,13 +253,38 @@ static void __init omap_timer_init(void) omap_init_mpu_timer(rate); omap_init_clocksource(rate); - /* - * XXX Since this file seems to deal mostly with the MPU timer, - * this doesn't seem like the correct place for the sync timer - * clocksource init. - */ - if (!cpu_is_omap7xx() && !cpu_is_omap15xx()) - omap_init_clocksource_32k(); +} + +#else +static inline void omap_mpu_timer_init(void) +{ + pr_err("Bogus timer, should not happen\n"); +} +#endif /* CONFIG_OMAP_MPU_TIMER */ + +static inline int omap_32k_timer_usable(void) +{ + int res = false; + + if (cpu_is_omap730() || cpu_is_omap15xx()) + return res; + +#ifdef CONFIG_OMAP_32K_TIMER + res = omap_32k_timer_init(); +#endif + + return res; +} + +/* + * --------------------------------------------------------------------------- + * Timer initialization + * --------------------------------------------------------------------------- + */ +static void __init omap_timer_init(void) +{ + if (!omap_32k_timer_usable()) + omap_mpu_timer_init(); } struct sys_timer omap_timer = { diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c index 20cfbcc6c60c..13d7b8f145bd 100644 --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -52,10 +52,9 @@ #include #include #include +#include #include -struct sys_timer omap_timer; - /* * --------------------------------------------------------------------------- * 32KHz OS timer @@ -181,14 +180,14 @@ static __init void omap_init_32k_timer(void) * Timer initialization * --------------------------------------------------------------------------- */ -static void __init omap_timer_init(void) +bool __init omap_32k_timer_init(void) { + omap_init_clocksource_32k(); + #ifdef CONFIG_OMAP_DM_TIMER omap_dm_timer_init(); #endif omap_init_32k_timer(); -} -struct sys_timer omap_timer = { - .init = omap_timer_init, -}; + return true; +} -- cgit v1.2.1 From 4912cf04b202a9d0bdc4082ecb9247943584450d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 18 Jan 2011 17:00:00 -0800 Subject: omap1: Fix sched_clock implementation when both MPU timer and 32K timer are used Earlier patches select HAVE_SCHED_CLOCK for omaps. To have working sched_clock also for MPU timer, we need to implement it in a way where the right one gets selected during the runtime. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/time.c | 48 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap1') diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index b03f34d55d88..f83fc335c613 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -219,6 +219,24 @@ static struct clocksource clocksource_mpu = { static DEFINE_CLOCK_DATA(cd); +static inline unsigned long long notrace _omap_mpu_sched_clock(void) +{ + u32 cyc = mpu_read(&clocksource_mpu); + return cyc_to_sched_clock(&cd, cyc, (u32)~0); +} + +#ifndef CONFIG_OMAP_32K_TIMER +unsigned long long notrace sched_clock(void) +{ + return _omap_mpu_sched_clock(); +} +#else +static unsigned long long notrace omap_mpu_sched_clock(void) +{ + return _omap_mpu_sched_clock(); +} +#endif + static void notrace mpu_update_sched_clock(void) { u32 cyc = mpu_read(&clocksource_mpu); @@ -262,6 +280,30 @@ static inline void omap_mpu_timer_init(void) } #endif /* CONFIG_OMAP_MPU_TIMER */ +#if defined(CONFIG_OMAP_MPU_TIMER) && defined(CONFIG_OMAP_32K_TIMER) +static unsigned long long (*preferred_sched_clock)(void); + +unsigned long long notrace sched_clock(void) +{ + if (!preferred_sched_clock) + return 0; + + return preferred_sched_clock(); +} + +static inline void preferred_sched_clock_init(bool use_32k_sched_clock) +{ + if (use_32k_sched_clock) + preferred_sched_clock = omap_32k_sched_clock; + else + preferred_sched_clock = omap_mpu_sched_clock; +} +#else +static inline void preferred_sched_clock_init(bool use_32k_sched_clcok) +{ +} +#endif + static inline int omap_32k_timer_usable(void) { int res = false; @@ -283,8 +325,12 @@ static inline int omap_32k_timer_usable(void) */ static void __init omap_timer_init(void) { - if (!omap_32k_timer_usable()) + if (omap_32k_timer_usable()) { + preferred_sched_clock_init(1); + } else { omap_mpu_timer_init(); + preferred_sched_clock_init(0); + } } struct sys_timer omap_timer = { -- cgit v1.2.1