diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-10-16 05:56:14 -0400 |
---|---|---|
committer | Nicolas Ferre <nicolas.ferre@atmel.com> | 2013-11-15 06:13:33 -0500 |
commit | 6de714c21a8ea315fffba6a93bbe537f4c1bf4f0 (patch) | |
tree | c3e0e05dfb0a222220516dd54e4a4f35f817355e /arch/arm | |
parent | 15c03dd4859ab16f9212238f29dd315654aa94f6 (diff) |
ARM: at91: fix hanged boot due to early rtc-interrupt
Make sure the RTC-interrupts are masked at boot by adding a new helper
function to be used at SOC-init.
This fixes hanged boot on all AT91 SOCs with an RTC (but RM9200), for
example, after a reset during an RTC-update or if an RTC-alarm goes off
after shutdown (e.g. when using RTC wakeup).
The RTC and RTT-peripherals are powered by backup power (VDDBU) (on all
AT91 SOCs but RM9200) and are not reset on wake-up, user, watchdog or
software reset. This means that their interrupts may be enabled during
early boot if, for example, they where not disabled during a previous
shutdown (e.g. due to a buggy driver or a non-clean shutdown such as a
user reset). Furthermore, an RTC or RTT-alarm may also be active.
The RTC and RTT-interrupts use the shared system-interrupt line, which
is also used by the PIT, and if an interrupt occurs before a handler
(e.g. RTC-driver) has been installed this leads to the system interrupt
being disabled and prevents the system from booting.
Note that when boot hangs due to an early RTC or RTT-interrupt, the only
way to get the system to start again is to remove the backup power (e.g.
battery) or to disable the interrupt manually from the bootloader. In
particular, a user reset is not sufficient.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: stable@vger.kernel.org # 3.11.x
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-at91/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9g45.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9n12.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9rl.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9x5.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-at91/generic.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-at91/include/mach/sama5d3.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-at91/sama5d3.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-at91/sysirq_mask.c | 47 |
11 files changed, 86 insertions, 1 deletions
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 3b0a9538093c..e0fda04e6aa1 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := irq.o gpio.o setup.o | 5 | obj-y := irq.o gpio.o setup.o sysirq_mask.o |
6 | obj-m := | 6 | obj-m := |
7 | obj-n := | 7 | obj-n := |
8 | obj- := | 8 | obj- := |
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 474ee04d24b9..ff662af77fee 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c | |||
@@ -377,6 +377,8 @@ static void __init at91sam9g45_initialize(void) | |||
377 | arm_pm_idle = at91sam9_idle; | 377 | arm_pm_idle = at91sam9_idle; |
378 | arm_pm_restart = at91sam9g45_restart; | 378 | arm_pm_restart = at91sam9g45_restart; |
379 | 379 | ||
380 | at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC); | ||
381 | |||
380 | /* Register GPIO subsystem */ | 382 | /* Register GPIO subsystem */ |
381 | at91_gpio_init(at91sam9g45_gpio, 5); | 383 | at91_gpio_init(at91sam9g45_gpio, 5); |
382 | } | 384 | } |
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c index c7d670d11802..4d6001c355f5 100644 --- a/arch/arm/mach-at91/at91sam9n12.c +++ b/arch/arm/mach-at91/at91sam9n12.c | |||
@@ -223,7 +223,13 @@ static void __init at91sam9n12_map_io(void) | |||
223 | at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE); | 223 | at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE); |
224 | } | 224 | } |
225 | 225 | ||
226 | static void __init at91sam9n12_initialize(void) | ||
227 | { | ||
228 | at91_sysirq_mask_rtc(AT91SAM9N12_BASE_RTC); | ||
229 | } | ||
230 | |||
226 | AT91_SOC_START(at91sam9n12) | 231 | AT91_SOC_START(at91sam9n12) |
227 | .map_io = at91sam9n12_map_io, | 232 | .map_io = at91sam9n12_map_io, |
228 | .register_clocks = at91sam9n12_register_clocks, | 233 | .register_clocks = at91sam9n12_register_clocks, |
234 | .init = at91sam9n12_initialize, | ||
229 | AT91_SOC_END | 235 | AT91_SOC_END |
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index d4ec0d9a9872..b5a8c9d81bc8 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c | |||
@@ -294,6 +294,8 @@ static void __init at91sam9rl_initialize(void) | |||
294 | arm_pm_idle = at91sam9_idle; | 294 | arm_pm_idle = at91sam9_idle; |
295 | arm_pm_restart = at91sam9_alt_restart; | 295 | arm_pm_restart = at91sam9_alt_restart; |
296 | 296 | ||
297 | at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC); | ||
298 | |||
297 | /* Register GPIO subsystem */ | 299 | /* Register GPIO subsystem */ |
298 | at91_gpio_init(at91sam9rl_gpio, 4); | 300 | at91_gpio_init(at91sam9rl_gpio, 4); |
299 | } | 301 | } |
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index 916e5a142917..e8a2e075a1b8 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c | |||
@@ -322,6 +322,11 @@ static void __init at91sam9x5_map_io(void) | |||
322 | at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE); | 322 | at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE); |
323 | } | 323 | } |
324 | 324 | ||
325 | static void __init at91sam9x5_initialize(void) | ||
326 | { | ||
327 | at91_sysirq_mask_rtc(AT91SAM9X5_BASE_RTC); | ||
328 | } | ||
329 | |||
325 | /* -------------------------------------------------------------------- | 330 | /* -------------------------------------------------------------------- |
326 | * Interrupt initialization | 331 | * Interrupt initialization |
327 | * -------------------------------------------------------------------- */ | 332 | * -------------------------------------------------------------------- */ |
@@ -329,4 +334,5 @@ static void __init at91sam9x5_map_io(void) | |||
329 | AT91_SOC_START(at91sam9x5) | 334 | AT91_SOC_START(at91sam9x5) |
330 | .map_io = at91sam9x5_map_io, | 335 | .map_io = at91sam9x5_map_io, |
331 | .register_clocks = at91sam9x5_register_clocks, | 336 | .register_clocks = at91sam9x5_register_clocks, |
337 | .init = at91sam9x5_initialize, | ||
332 | AT91_SOC_END | 338 | AT91_SOC_END |
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index dc6e2f5f804d..80269bda0dd7 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h | |||
@@ -34,6 +34,7 @@ extern int __init at91_aic_of_init(struct device_node *node, | |||
34 | struct device_node *parent); | 34 | struct device_node *parent); |
35 | extern int __init at91_aic5_of_init(struct device_node *node, | 35 | extern int __init at91_aic5_of_init(struct device_node *node, |
36 | struct device_node *parent); | 36 | struct device_node *parent); |
37 | extern void __init at91_sysirq_mask_rtc(u32 rtc_base); | ||
37 | 38 | ||
38 | 39 | ||
39 | /* Timer */ | 40 | /* Timer */ |
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h index d374b87c0459..0151bcf6163c 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9n12.h +++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h | |||
@@ -49,6 +49,11 @@ | |||
49 | #define AT91SAM9N12_BASE_USART3 0xf8028000 | 49 | #define AT91SAM9N12_BASE_USART3 0xf8028000 |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * System Peripherals | ||
53 | */ | ||
54 | #define AT91SAM9N12_BASE_RTC 0xfffffeb0 | ||
55 | |||
56 | /* | ||
52 | * Internal Memory. | 57 | * Internal Memory. |
53 | */ | 58 | */ |
54 | #define AT91SAM9N12_SRAM_BASE 0x00300000 /* Internal SRAM base address */ | 59 | #define AT91SAM9N12_SRAM_BASE 0x00300000 /* Internal SRAM base address */ |
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h index c75ee19b58d3..2fc76c49e97c 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9x5.h +++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h | |||
@@ -55,6 +55,11 @@ | |||
55 | #define AT91SAM9X5_BASE_USART2 0xf8024000 | 55 | #define AT91SAM9X5_BASE_USART2 0xf8024000 |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * System Peripherals | ||
59 | */ | ||
60 | #define AT91SAM9X5_BASE_RTC 0xfffffeb0 | ||
61 | |||
62 | /* | ||
58 | * Internal Memory. | 63 | * Internal Memory. |
59 | */ | 64 | */ |
60 | #define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */ | 65 | #define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */ |
diff --git a/arch/arm/mach-at91/include/mach/sama5d3.h b/arch/arm/mach-at91/include/mach/sama5d3.h index 31096a8aaf1d..25613d8c6dcd 100644 --- a/arch/arm/mach-at91/include/mach/sama5d3.h +++ b/arch/arm/mach-at91/include/mach/sama5d3.h | |||
@@ -73,6 +73,11 @@ | |||
73 | #define SAMA5D3_BASE_USART3 0xf8024000 | 73 | #define SAMA5D3_BASE_USART3 0xf8024000 |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * System Peripherals | ||
77 | */ | ||
78 | #define SAMA5D3_BASE_RTC 0xfffffeb0 | ||
79 | |||
80 | /* | ||
76 | * Internal Memory | 81 | * Internal Memory |
77 | */ | 82 | */ |
78 | #define SAMA5D3_SRAM_BASE 0x00300000 /* Internal SRAM base address */ | 83 | #define SAMA5D3_SRAM_BASE 0x00300000 /* Internal SRAM base address */ |
diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c index 401279715ab1..3ea86428ee09 100644 --- a/arch/arm/mach-at91/sama5d3.c +++ b/arch/arm/mach-at91/sama5d3.c | |||
@@ -371,7 +371,13 @@ static void __init sama5d3_map_io(void) | |||
371 | at91_init_sram(0, SAMA5D3_SRAM_BASE, SAMA5D3_SRAM_SIZE); | 371 | at91_init_sram(0, SAMA5D3_SRAM_BASE, SAMA5D3_SRAM_SIZE); |
372 | } | 372 | } |
373 | 373 | ||
374 | static void __init sama5d3_initialize(void) | ||
375 | { | ||
376 | at91_sysirq_mask_rtc(SAMA5D3_BASE_RTC); | ||
377 | } | ||
378 | |||
374 | AT91_SOC_START(sama5d3) | 379 | AT91_SOC_START(sama5d3) |
375 | .map_io = sama5d3_map_io, | 380 | .map_io = sama5d3_map_io, |
376 | .register_clocks = sama5d3_register_clocks, | 381 | .register_clocks = sama5d3_register_clocks, |
382 | .init = sama5d3_initialize, | ||
377 | AT91_SOC_END | 383 | AT91_SOC_END |
diff --git a/arch/arm/mach-at91/sysirq_mask.c b/arch/arm/mach-at91/sysirq_mask.c new file mode 100644 index 000000000000..ee3e22c66ce8 --- /dev/null +++ b/arch/arm/mach-at91/sysirq_mask.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * sysirq_mask.c - System-interrupt masking | ||
3 | * | ||
4 | * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com> | ||
5 | * | ||
6 | * Functions to disable system interrupts from backup-powered peripherals. | ||
7 | * | ||
8 | * The RTC and RTT-peripherals are generally powered by backup power (VDDBU) | ||
9 | * and are not reset on wake-up, user, watchdog or software reset. This means | ||
10 | * that their interrupts may be enabled during early boot (e.g. after a user | ||
11 | * reset). | ||
12 | * | ||
13 | * As the RTC and RTT share the system-interrupt line with the PIT, an | ||
14 | * interrupt occurring before a handler has been installed would lead to the | ||
15 | * system interrupt being disabled and prevent the system from booting. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | */ | ||
22 | |||
23 | #include <linux/io.h> | ||
24 | |||
25 | #include "generic.h" | ||
26 | |||
27 | #define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */ | ||
28 | #define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */ | ||
29 | |||
30 | void __init at91_sysirq_mask_rtc(u32 rtc_base) | ||
31 | { | ||
32 | void __iomem *base; | ||
33 | u32 mask; | ||
34 | |||
35 | base = ioremap(rtc_base, 64); | ||
36 | if (!base) | ||
37 | return; | ||
38 | |||
39 | mask = readl_relaxed(base + AT91_RTC_IMR); | ||
40 | if (mask) { | ||
41 | pr_info("AT91: Disabling rtc irq\n"); | ||
42 | writel_relaxed(mask, base + AT91_RTC_IDR); | ||
43 | (void)readl_relaxed(base + AT91_RTC_IMR); /* flush */ | ||
44 | } | ||
45 | |||
46 | iounmap(base); | ||
47 | } | ||