diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-10-16 05:56:15 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-12-04 13:55:47 -0500 |
commit | 6ce3ee9af1ad697c71766067ffa1a35352dfdcfd (patch) | |
tree | 0d4a7c41d141b297e50e33cf57b32d46175f9c34 | |
parent | 54f830b7337ed016b6708cf5a2ac297d4cee227d (diff) |
ARM: at91: fix hanged boot due to early rtt-interrupt
commit 94c4c79f2f1acca6e69a50bff5a7d9027509c16b upstream.
Make sure the RTT-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 RTT, for example, if an
RTT-alarm goes off after a non-clean 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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | arch/arm/mach-at91/at91sam9260.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9261.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9263.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9g45.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9rl.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-at91/generic.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-at91/sysirq_mask.c | 24 |
7 files changed, 34 insertions, 0 deletions
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index a8ce24538da6..cdb1fb695edf 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c | |||
@@ -351,6 +351,8 @@ static void __init at91sam9260_initialize(void) | |||
351 | at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1) | 351 | at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1) |
352 | | (1 << AT91SAM9260_ID_IRQ2); | 352 | | (1 << AT91SAM9260_ID_IRQ2); |
353 | 353 | ||
354 | at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT); | ||
355 | |||
354 | /* Register GPIO subsystem */ | 356 | /* Register GPIO subsystem */ |
355 | at91_gpio_init(at91sam9260_gpio, 3); | 357 | at91_gpio_init(at91sam9260_gpio, 3); |
356 | } | 358 | } |
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 25efb5ac30f1..7c9d2ea5bb88 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c | |||
@@ -293,6 +293,8 @@ static void __init at91sam9261_initialize(void) | |||
293 | at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1) | 293 | at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1) |
294 | | (1 << AT91SAM9261_ID_IRQ2); | 294 | | (1 << AT91SAM9261_ID_IRQ2); |
295 | 295 | ||
296 | at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT); | ||
297 | |||
296 | /* Register GPIO subsystem */ | 298 | /* Register GPIO subsystem */ |
297 | at91_gpio_init(at91sam9261_gpio, 3); | 299 | at91_gpio_init(at91sam9261_gpio, 3); |
298 | } | 300 | } |
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index f44ffd2105a7..c6b2f477c71f 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c | |||
@@ -329,6 +329,9 @@ static void __init at91sam9263_initialize(void) | |||
329 | arm_pm_restart = at91sam9_alt_restart; | 329 | arm_pm_restart = at91sam9_alt_restart; |
330 | at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1); | 330 | at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1); |
331 | 331 | ||
332 | at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0); | ||
333 | at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1); | ||
334 | |||
332 | /* Register GPIO subsystem */ | 335 | /* Register GPIO subsystem */ |
333 | at91_gpio_init(at91sam9263_gpio, 5); | 336 | at91_gpio_init(at91sam9263_gpio, 5); |
334 | } | 337 | } |
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index eebfe3818812..e381fa125011 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c | |||
@@ -377,6 +377,7 @@ static void __init at91sam9g45_initialize(void) | |||
377 | at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0); | 377 | at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0); |
378 | 378 | ||
379 | at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC); | 379 | at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC); |
380 | at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT); | ||
380 | 381 | ||
381 | /* Register GPIO subsystem */ | 382 | /* Register GPIO subsystem */ |
382 | at91_gpio_init(at91sam9g45_gpio, 5); | 383 | at91_gpio_init(at91sam9g45_gpio, 5); |
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 297613944c93..5615d28a5b96 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c | |||
@@ -296,6 +296,7 @@ static void __init at91sam9rl_initialize(void) | |||
296 | at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0); | 296 | at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0); |
297 | 297 | ||
298 | at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC); | 298 | at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC); |
299 | at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT); | ||
299 | 300 | ||
300 | /* Register GPIO subsystem */ | 301 | /* Register GPIO subsystem */ |
301 | at91_gpio_init(at91sam9rl_gpio, 4); | 302 | at91_gpio_init(at91sam9rl_gpio, 4); |
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 325a4d1fb736..d949ab4e26fa 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 | extern int __init at91_aic5_of_init(struct device_node *node, | 34 | extern int __init at91_aic5_of_init(struct device_node *node, |
35 | struct device_node *parent); | 35 | struct device_node *parent); |
36 | extern void __init at91_sysirq_mask_rtc(u32 rtc_base); | 36 | extern void __init at91_sysirq_mask_rtc(u32 rtc_base); |
37 | extern void __init at91_sysirq_mask_rtt(u32 rtt_base); | ||
37 | 38 | ||
38 | 39 | ||
39 | /* Timer */ | 40 | /* Timer */ |
diff --git a/arch/arm/mach-at91/sysirq_mask.c b/arch/arm/mach-at91/sysirq_mask.c index ee3e22c66ce8..2ba694f9626b 100644 --- a/arch/arm/mach-at91/sysirq_mask.c +++ b/arch/arm/mach-at91/sysirq_mask.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <mach/at91_rtt.h> | ||
24 | 25 | ||
25 | #include "generic.h" | 26 | #include "generic.h" |
26 | 27 | ||
@@ -45,3 +46,26 @@ void __init at91_sysirq_mask_rtc(u32 rtc_base) | |||
45 | 46 | ||
46 | iounmap(base); | 47 | iounmap(base); |
47 | } | 48 | } |
49 | |||
50 | void __init at91_sysirq_mask_rtt(u32 rtt_base) | ||
51 | { | ||
52 | void __iomem *base; | ||
53 | void __iomem *reg; | ||
54 | u32 mode; | ||
55 | |||
56 | base = ioremap(rtt_base, 16); | ||
57 | if (!base) | ||
58 | return; | ||
59 | |||
60 | reg = base + AT91_RTT_MR; | ||
61 | |||
62 | mode = readl_relaxed(reg); | ||
63 | if (mode & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) { | ||
64 | pr_info("AT91: Disabling rtt irq\n"); | ||
65 | mode &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); | ||
66 | writel_relaxed(mode, reg); | ||
67 | (void)readl_relaxed(reg); /* flush */ | ||
68 | } | ||
69 | |||
70 | iounmap(base); | ||
71 | } | ||