diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-10-16 05:56:15 -0400 |
---|---|---|
committer | Nicolas Ferre <nicolas.ferre@atmel.com> | 2013-11-15 06:13:33 -0500 |
commit | 94c4c79f2f1acca6e69a50bff5a7d9027509c16b (patch) | |
tree | 85b5fdb02f99edb8b8f4368ea932c4d149fc9e1f | |
parent | 6de714c21a8ea315fffba6a93bbe537f4c1bf4f0 (diff) |
ARM: at91: fix hanged boot due to early rtt-interrupt
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>
Cc: stable@vger.kernel.org # 3.11.x
-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 5de6074b4f4f..ae10d14de700 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c | |||
@@ -349,6 +349,8 @@ static void __init at91sam9260_initialize(void) | |||
349 | arm_pm_idle = at91sam9_idle; | 349 | arm_pm_idle = at91sam9_idle; |
350 | arm_pm_restart = at91sam9_alt_restart; | 350 | arm_pm_restart = at91sam9_alt_restart; |
351 | 351 | ||
352 | at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT); | ||
353 | |||
352 | /* Register GPIO subsystem */ | 354 | /* Register GPIO subsystem */ |
353 | at91_gpio_init(at91sam9260_gpio, 3); | 355 | at91_gpio_init(at91sam9260_gpio, 3); |
354 | } | 356 | } |
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 0e0793241ab7..e761e74ac64b 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c | |||
@@ -291,6 +291,8 @@ static void __init at91sam9261_initialize(void) | |||
291 | arm_pm_idle = at91sam9_idle; | 291 | arm_pm_idle = at91sam9_idle; |
292 | arm_pm_restart = at91sam9_alt_restart; | 292 | arm_pm_restart = at91sam9_alt_restart; |
293 | 293 | ||
294 | at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT); | ||
295 | |||
294 | /* Register GPIO subsystem */ | 296 | /* Register GPIO subsystem */ |
295 | at91_gpio_init(at91sam9261_gpio, 3); | 297 | at91_gpio_init(at91sam9261_gpio, 3); |
296 | } | 298 | } |
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 6ce7d1850893..e6fed6253a7f 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c | |||
@@ -328,6 +328,9 @@ static void __init at91sam9263_initialize(void) | |||
328 | arm_pm_idle = at91sam9_idle; | 328 | arm_pm_idle = at91sam9_idle; |
329 | arm_pm_restart = at91sam9_alt_restart; | 329 | arm_pm_restart = at91sam9_alt_restart; |
330 | 330 | ||
331 | at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0); | ||
332 | at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1); | ||
333 | |||
331 | /* Register GPIO subsystem */ | 334 | /* Register GPIO subsystem */ |
332 | at91_gpio_init(at91sam9263_gpio, 5); | 335 | at91_gpio_init(at91sam9263_gpio, 5); |
333 | } | 336 | } |
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index ff662af77fee..9f7a97c84c12 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c | |||
@@ -378,6 +378,7 @@ static void __init at91sam9g45_initialize(void) | |||
378 | arm_pm_restart = at91sam9g45_restart; | 378 | arm_pm_restart = at91sam9g45_restart; |
379 | 379 | ||
380 | at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC); | 380 | at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC); |
381 | at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT); | ||
381 | 382 | ||
382 | /* Register GPIO subsystem */ | 383 | /* Register GPIO subsystem */ |
383 | at91_gpio_init(at91sam9g45_gpio, 5); | 384 | at91_gpio_init(at91sam9g45_gpio, 5); |
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index b5a8c9d81bc8..301e1728d353 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c | |||
@@ -295,6 +295,7 @@ static void __init at91sam9rl_initialize(void) | |||
295 | arm_pm_restart = at91sam9_alt_restart; | 295 | arm_pm_restart = at91sam9_alt_restart; |
296 | 296 | ||
297 | at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC); | 297 | at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC); |
298 | at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT); | ||
298 | 299 | ||
299 | /* Register GPIO subsystem */ | 300 | /* Register GPIO subsystem */ |
300 | at91_gpio_init(at91sam9rl_gpio, 4); | 301 | at91_gpio_init(at91sam9rl_gpio, 4); |
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 80269bda0dd7..26dee3ce9397 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h | |||
@@ -35,6 +35,7 @@ extern int __init at91_aic_of_init(struct device_node *node, | |||
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 | extern void __init at91_sysirq_mask_rtc(u32 rtc_base); |
38 | extern void __init at91_sysirq_mask_rtt(u32 rtt_base); | ||
38 | 39 | ||
39 | 40 | ||
40 | /* Timer */ | 41 | /* 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 | } | ||