2013-03-08 12:54:53

by Johan Hovold

[permalink] [raw]
Subject: [PATCH 0/3] ARM: at91: fix hanged boot

These patches fix a few severe issues affecting most AT91 SOCs where
boot can hang after a non-general reset, and where the only way to get
the system booting again is to do a general reset -- something which
could require physically removing any backup battery.

The problems stem from the fact that the RTC and RTT-peripherals are
powered by backup power (VDDBU) and are not reset on wake-up, user,
watchdog or software reset. Consequently, RTC and RTT-alarms and their
interrupts may be enabled at boot, leading to a system lock-up when an
interrupt arrives on the shared system-interrupt line before the
appropriate handler (e.g. RTC-driver) has been installed.

The easiest way to trigger this is to simply wake up from an RTC-alarm
on at91sam9g45. The RTC-driver currently does not disable interrupts at
shutdown so even after a clean shut-down the system will always hang
after waking up.

The first patch fixes this very general case of RTC-wake up after a
clean shutdown in the RTC-driver and is marked for stable as it is
perfectly straight-forward. [ Note that the other, RTT-based, AT91
RTC-driver already disables its interrupts at shutdown. ]

The more general problem can be triggered, for example, by doing a
user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
off after a non-clean shutdown.

To fix this I propose that arch-code should mask the relevant interrupts
at early boot, and this is what the third patch does. To access the
RTC-registers I choose to revert a recent patch that moved the register
definitions to drivers/rtc.

Arguably, the interrupts could also be disabled in bootloaders, but I
strongly suggest fixing it in the kernel once and for all. By adding a
new, mandatory AT91 SOC-initialiser (rather extending init) it will not
be overlooked when adding new SOCs either.

The patches have been tested on at91sam9263 and at91sam9g45, and
compile-tested for the other SOCs.

Johan


Johan Hovold (3):
ARM: at91/rtc: fix boot after RTC wake-up
Revert "arm: at91: move at91rm9200 rtc header in drivers/rtc"
ARM: at91: fix hanged boot

arch/arm/mach-at91/at91rm9200.c | 9 ++++
arch/arm/mach-at91/at91sam9260.c | 6 +++
arch/arm/mach-at91/at91sam9261.c | 6 +++
arch/arm/mach-at91/at91sam9263.c | 7 +++
arch/arm/mach-at91/at91sam9g45.c | 7 +++
arch/arm/mach-at91/at91sam9n12.c | 6 +++
arch/arm/mach-at91/at91sam9rl.c | 7 +++
arch/arm/mach-at91/at91sam9x5.c | 6 +++
arch/arm/mach-at91/generic.h | 2 +
arch/arm/mach-at91/include/mach/at91_rtc.h | 75 +++++++++++++++++++++++++++
arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 ++
arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 ++
arch/arm/mach-at91/setup.c | 31 +++++++++++
arch/arm/mach-at91/soc.h | 1 +
drivers/rtc/rtc-at91rm9200.c | 11 +++-
drivers/rtc/rtc-at91rm9200.h | 75 ---------------------------
16 files changed, 183 insertions(+), 76 deletions(-)
create mode 100644 arch/arm/mach-at91/include/mach/at91_rtc.h
delete mode 100644 drivers/rtc/rtc-at91rm9200.h

--
1.8.1.1


2013-03-08 12:54:08

by Johan Hovold

[permalink] [raw]
Subject: [PATCH 3/3] ARM: at91: fix hanged boot

Make sure the RTC and RTT-interrupts are masked at boot by adding a new
SOC-initialiser and helpers functions.

This fixes hanged boot on all AT91 SOCs but RM9200, for example, after a
reset during an RTC-update or if an RTC or RTT-alarm goes off after a
non-clean shutdown.

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, 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.

Tested on at91sam9263 and at91sam9g45.

Signed-off-by: Johan Hovold <[email protected]>
---
arch/arm/mach-at91/at91rm9200.c | 9 ++++++++
arch/arm/mach-at91/at91sam9260.c | 6 ++++++
arch/arm/mach-at91/at91sam9261.c | 6 ++++++
arch/arm/mach-at91/at91sam9263.c | 7 ++++++
arch/arm/mach-at91/at91sam9g45.c | 7 ++++++
arch/arm/mach-at91/at91sam9n12.c | 6 ++++++
arch/arm/mach-at91/at91sam9rl.c | 7 ++++++
arch/arm/mach-at91/at91sam9x5.c | 6 ++++++
arch/arm/mach-at91/generic.h | 2 ++
arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 +++++
arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 +++++
arch/arm/mach-at91/setup.c | 31 +++++++++++++++++++++++++++
arch/arm/mach-at91/soc.h | 1 +
13 files changed, 98 insertions(+)

diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 7aeb473..4651ebb 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -325,6 +325,14 @@ static void __init at91rm9200_ioremap_registers(void)
at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256);
}

+static void __init at91rm9200_sysirq_mask(void)
+{
+ /*
+ * No need to mask any system interrupts as the RM9200 has no backup
+ * power and resets all system peripherals at every reset.
+ */
+}
+
static void __init at91rm9200_initialize(void)
{
arm_pm_idle = at91rm9200_idle;
@@ -387,5 +395,6 @@ AT91_SOC_START(rm9200)
.default_irq_priority = at91rm9200_default_irq_priority,
.ioremap_registers = at91rm9200_ioremap_registers,
.register_clocks = at91rm9200_register_clocks,
+ .sysirq_mask = at91rm9200_sysirq_mask,
.init = at91rm9200_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index b67cd53..c47a0db 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -342,6 +342,11 @@ static void __init at91sam9260_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX);
}

+static void __init at91sam9260_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
+}
+
static void __init at91sam9260_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -400,5 +405,6 @@ AT91_SOC_START(sam9260)
.default_irq_priority = at91sam9260_default_irq_priority,
.ioremap_registers = at91sam9260_ioremap_registers,
.register_clocks = at91sam9260_register_clocks,
+ .sysirq_mask = at91sam9260_sysirq_mask,
.init = at91sam9260_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 0204f4c..396e4cb 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -286,6 +286,11 @@ static void __init at91sam9261_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX);
}

+static void __init at91sam9261_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
+}
+
static void __init at91sam9261_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -344,5 +349,6 @@ AT91_SOC_START(sam9261)
.default_irq_priority = at91sam9261_default_irq_priority,
.ioremap_registers = at91sam9261_ioremap_registers,
.register_clocks = at91sam9261_register_clocks,
+ .sysirq_mask = at91sam9261_sysirq_mask,
.init = at91sam9261_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index c0cbb81..a0166a3 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -325,6 +325,12 @@ static void __init at91sam9263_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX);
}

+static void __init at91sam9263_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
+ at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
+}
+
static void __init at91sam9263_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -382,5 +388,6 @@ AT91_SOC_START(sam9263)
.default_irq_priority = at91sam9263_default_irq_priority,
.ioremap_registers = at91sam9263_ioremap_registers,
.register_clocks = at91sam9263_register_clocks,
+ .sysirq_mask = at91sam9263_sysirq_mask,
.init = at91sam9263_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index b4968aa..3d5498e 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -370,6 +370,12 @@ static void __init at91sam9g45_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX);
}

+static void __init at91sam9g45_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
+ at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
+}
+
static void __init at91sam9g45_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -427,5 +433,6 @@ AT91_SOC_START(sam9g45)
.default_irq_priority = at91sam9g45_default_irq_priority,
.ioremap_registers = at91sam9g45_ioremap_registers,
.register_clocks = at91sam9g45_register_clocks,
+ .sysirq_mask = at91sam9g45_sysirq_mask,
.init = at91sam9g45_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index 5dfc8fd..e2ddb89 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -221,6 +221,11 @@ static void __init at91sam9n12_map_io(void)
at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
}

+static void __init at91sam9n12_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9N12_BASE_RTC);
+}
+
void __init at91sam9n12_initialize(void)
{
at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
@@ -229,5 +234,6 @@ void __init at91sam9n12_initialize(void)
AT91_SOC_START(sam9n12)
.map_io = at91sam9n12_map_io,
.register_clocks = at91sam9n12_register_clocks,
+ .sysirq_mask = at91sam9n12_sysirq_mask,
.init = at91sam9n12_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 3de3e04..bde999f 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -289,6 +289,12 @@ static void __init at91sam9rl_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX);
}

+static void __init at91sam9rl_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
+ at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
+}
+
static void __init at91sam9rl_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -346,5 +352,6 @@ AT91_SOC_START(sam9rl)
.default_irq_priority = at91sam9rl_default_irq_priority,
.ioremap_registers = at91sam9rl_ioremap_registers,
.register_clocks = at91sam9rl_register_clocks,
+ .sysirq_mask = at91sam9rl_sysirq_mask,
.init = at91sam9rl_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 44a9a62..20a214f 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -316,6 +316,11 @@ static void __init at91sam9x5_map_io(void)
at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
}

+static void __init at91sam9x5_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9X5_BASE_RTC);
+}
+
/* --------------------------------------------------------------------
* Interrupt initialization
* -------------------------------------------------------------------- */
@@ -323,4 +328,5 @@ static void __init at91sam9x5_map_io(void)
AT91_SOC_START(sam9x5)
.map_io = at91sam9x5_map_io,
.register_clocks = at91sam9x5_register_clocks,
+ .sysirq_mask = at91sam9x5_sysirq_mask,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index fc593d6..90a854d 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -33,6 +33,8 @@ extern int __init at91_aic_of_init(struct device_node *node,
struct device_node *parent);
extern int __init at91_aic5_of_init(struct device_node *node,
struct device_node *parent);
+extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
+extern void __init at91_sysirq_mask_rtt(u32 rtt_base);


/* Timer */
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
index d374b87..0151bcf 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9n12.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
@@ -49,6 +49,11 @@
#define AT91SAM9N12_BASE_USART3 0xf8028000

/*
+ * System Peripherals
+ */
+#define AT91SAM9N12_BASE_RTC 0xfffffeb0
+
+/*
* Internal Memory.
*/
#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 c75ee19..2fc76c4 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
@@ -55,6 +55,11 @@
#define AT91SAM9X5_BASE_USART2 0xf8024000

/*
+ * System Peripherals
+ */
+#define AT91SAM9X5_BASE_RTC 0xfffffeb0
+
+/*
* Internal Memory.
*/
#define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 4b67847..ac05453 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -19,6 +19,8 @@
#include <mach/cpu.h>
#include <mach/at91_dbgu.h>
#include <mach/at91_pmc.h>
+#include <mach/at91_rtc.h>
+#include <mach/at91_rtt.h>

#include "at91_shdwc.h"
#include "soc.h"
@@ -311,6 +313,31 @@ void __init at91_ioremap_matrix(u32 base_addr)
panic("Impossible to ioremap at91_matrix_base\n");
}

+void __init at91_sysirq_mask_rtc(u32 rtc_base)
+{
+ void *base = AT91_IO_P2V(rtc_base);
+ u32 mask;
+
+ mask = __raw_readl(base + AT91_RTC_IMR);
+ if (mask) {
+ pr_info("AT91: Disabling rtc irq\n");
+ __raw_writel(mask, base + AT91_RTC_IDR);
+ }
+}
+
+void __init at91_sysirq_mask_rtt(u32 rtt_base)
+{
+ void *base = AT91_IO_P2V(rtt_base);
+ u32 mr;
+
+ mr = __raw_readl(base + AT91_RTT_MR);
+ if (mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) {
+ pr_info("AT91: Disabling rtt irq\n");
+ mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ __raw_writel(mr, base + AT91_RTT_MR);
+ }
+}
+
#if defined(CONFIG_OF)
static struct of_device_id rstc_ids[] = {
{ .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart },
@@ -467,6 +494,8 @@ void __init at91_dt_initialize(void)

if (at91_boot_soc.init)
at91_boot_soc.init();
+
+ at91_boot_soc.sysirq_mask();
}
#endif

@@ -482,5 +511,7 @@ void __init at91_initialize(unsigned long main_clock)

at91_boot_soc.init();

+ at91_boot_soc.sysirq_mask();
+
pinctrl_provide_dummies();
}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 9c6d3d4..134f4c4 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -10,6 +10,7 @@ struct at91_init_soc {
void (*map_io)(void);
void (*ioremap_registers)(void);
void (*register_clocks)(void);
+ void (*sysirq_mask)(void);
void (*init)(void);
};

--
1.8.1.1

2013-03-08 12:54:10

by Johan Hovold

[permalink] [raw]
Subject: [PATCH 1/3] ARM: at91/rtc: fix boot after RTC wake-up

Fix failed boot after RTC wake-up by making sure RTC-interrupts are
disabled at shutdown.

The RTC-registers are not reset at shutdown when there is backup power
available, and hence the RTC-interrupt, which uses the shared system
interrupt, may be enabled during early boot. If an RTC-alarm goes off
before the RTC-driver is initialised (e.g. when waking up from an
RTC-alarm) this results in disabled system interrupts.

Without earlyprintk boot hangs after

Uncompressing Linux... done, booting the kernel.

and earlyprintk reveals that the shared system interrupt gets disabled:

irq 17: nobody cared (try booting with the "irqpoll" option)
[<c000cf8c>] (unwind_backtrace+0x0/0xf0) from [<c00513ec>] (__report_bad_irq+0x20/0xe8)
[<c00513ec>] (__report_bad_irq+0x20/0xe8) from [<c00516fc>] (note_interrupt+0x1e0/0x244)
[<c00516fc>] (note_interrupt+0x1e0/0x244) from [<c004f980>] (handle_irq_event_percpu+0xac/0x1c4)
[<c004f980>] (handle_irq_event_percpu+0xac/0x1c4) from [<c004faec>] (handle_irq_event+0x54/0x84)
[<c004faec>] (handle_irq_event+0x54/0x84) from [<c0052364>] (handle_fasteoi_irq+0x84/0x154)
[<c0052364>] (handle_fasteoi_irq+0x84/0x154) from [<c004f1f8>] (generic_handle_irq+0x20/0x30)
[<c004f1f8>] (generic_handle_irq+0x20/0x30) from [<c0009b8c>] (handle_IRQ+0x30/0x84)
[<c0009b8c>] (handle_IRQ+0x30/0x84) from [<c0008fa0>] (__irq_svc+0x40/0x6c)
[<c0008fa0>] (__irq_svc+0x40/0x6c) from [<c001cd6c>] (__do_softirq+0x5c/0x164)
[<c001cd6c>] (__do_softirq+0x5c/0x164) from [<c001d268>] (irq_exit+0x58/0x60)
[<c001d268>] (irq_exit+0x58/0x60) from [<c0009b90>] (handle_IRQ+0x34/0x84)
[<c0009b90>] (handle_IRQ+0x34/0x84) from [<c0008fa0>] (__irq_svc+0x40/0x6c)
[<c0008fa0>] (__irq_svc+0x40/0x6c) from [<c03e668c>] (start_kernel+0x1d8/0x29c)
[<c03e668c>] (start_kernel+0x1d8/0x29c) from [<70008040>] (0x70008040)
handlers:
[<c0012df0>] at91sam926x_pit_interrupt
Disabling IRQ #17

Note that disabling the RTC-interrupts at shutdown fixes boot after a
clean shutdown, but that an RTC-alarm after a user (or watchdog) reset
could still prevent the system from booting.

Note also that the only way to recover from a failed boot after an
RTC-alarm is to remove any backup power (e.g. backup battery) or to
disable (or acknowledge) the RTC-interrupt manually from the bootloader.
In particular, a user-reset is not sufficient.

Tested on at91sam9g45.

Cc: stable <[email protected]>
Signed-off-by: Johan Hovold <[email protected]>
---
drivers/rtc/rtc-at91rm9200.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index b6469e2..936c75a 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -338,6 +338,14 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
return 0;
}

+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+ /* Disable all interrupts */
+ at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+}
+
#ifdef CONFIG_PM

/* AT91RM9200 RTC Power management control */
@@ -384,6 +392,7 @@ static const struct dev_pm_ops at91_rtc_pm = {

static struct platform_driver at91_rtc_driver = {
.remove = __exit_p(at91_rtc_remove),
+ .shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
.owner = THIS_MODULE,
--
1.8.1.1

2013-03-08 12:54:31

by Johan Hovold

[permalink] [raw]
Subject: [PATCH 2/3] Revert "arm: at91: move at91rm9200 rtc header in drivers/rtc"

This reverts commit 75984df05d86956541795f01e62d7dc67bc522fd.

A couple of these register definitions are needed by arch code as the
RTC-interrupts must be disabled at early boot.

Signed-off-by: Johan Hovold <[email protected]>
---
arch/arm/mach-at91/include/mach/at91_rtc.h | 75 ++++++++++++++++++++++++++++++
drivers/rtc/rtc-at91rm9200.c | 2 +-
drivers/rtc/rtc-at91rm9200.h | 75 ------------------------------
3 files changed, 76 insertions(+), 76 deletions(-)
create mode 100644 arch/arm/mach-at91/include/mach/at91_rtc.h
delete mode 100644 drivers/rtc/rtc-at91rm9200.h

diff --git a/arch/arm/mach-at91/include/mach/at91_rtc.h b/arch/arm/mach-at91/include/mach/at91_rtc.h
new file mode 100644
index 0000000..da1945e
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91_rtc.h
@@ -0,0 +1,75 @@
+/*
+ * arch/arm/mach-at91/include/mach/at91_rtc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Real Time Clock (RTC) - System peripheral registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91_RTC_H
+#define AT91_RTC_H
+
+#define AT91_RTC_CR 0x00 /* Control Register */
+#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */
+#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */
+#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */
+#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8)
+#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
+#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
+#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
+#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */
+#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
+#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
+#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
+
+#define AT91_RTC_MR 0x04 /* Mode Register */
+#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
+
+#define AT91_RTC_TIMR 0x08 /* Time Register */
+#define AT91_RTC_SEC (0x7f << 0) /* Current Second */
+#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */
+#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
+#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */
+
+#define AT91_RTC_CALR 0x0c /* Calendar Register */
+#define AT91_RTC_CENT (0x7f << 0) /* Current Century */
+#define AT91_RTC_YEAR (0xff << 8) /* Current Year */
+#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */
+#define AT91_RTC_DAY (7 << 21) /* Current Day */
+#define AT91_RTC_DATE (0x3f << 24) /* Current Date */
+
+#define AT91_RTC_TIMALR 0x10 /* Time Alarm Register */
+#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */
+#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */
+#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */
+
+#define AT91_RTC_CALALR 0x14 /* Calendar Alarm Register */
+#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */
+#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */
+
+#define AT91_RTC_SR 0x18 /* Status Register */
+#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */
+#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */
+#define AT91_RTC_SECEV (1 << 2) /* Second Event */
+#define AT91_RTC_TIMEV (1 << 3) /* Time Event */
+#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */
+
+#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
+#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
+#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
+#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
+
+#define AT91_RTC_VER 0x2c /* Valid Entry Register */
+#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */
+#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */
+#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */
+#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */
+
+#endif
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 936c75a..1ed0433 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -31,7 +31,7 @@

#include <asm/uaccess.h>

-#include "rtc-at91rm9200.h"
+#include <mach/at91_rtc.h>

#define at91_rtc_read(field) \
__raw_readl(at91_rtc_regs + field)
diff --git a/drivers/rtc/rtc-at91rm9200.h b/drivers/rtc/rtc-at91rm9200.h
deleted file mode 100644
index da1945e..0000000
--- a/drivers/rtc/rtc-at91rm9200.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_rtc.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Real Time Clock (RTC) - System peripheral registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_RTC_H
-#define AT91_RTC_H
-
-#define AT91_RTC_CR 0x00 /* Control Register */
-#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */
-#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */
-#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */
-#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8)
-#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
-#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
-#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
-#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */
-#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
-#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
-#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
-
-#define AT91_RTC_MR 0x04 /* Mode Register */
-#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
-
-#define AT91_RTC_TIMR 0x08 /* Time Register */
-#define AT91_RTC_SEC (0x7f << 0) /* Current Second */
-#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */
-#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
-#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */
-
-#define AT91_RTC_CALR 0x0c /* Calendar Register */
-#define AT91_RTC_CENT (0x7f << 0) /* Current Century */
-#define AT91_RTC_YEAR (0xff << 8) /* Current Year */
-#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */
-#define AT91_RTC_DAY (7 << 21) /* Current Day */
-#define AT91_RTC_DATE (0x3f << 24) /* Current Date */
-
-#define AT91_RTC_TIMALR 0x10 /* Time Alarm Register */
-#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */
-#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */
-#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */
-
-#define AT91_RTC_CALALR 0x14 /* Calendar Alarm Register */
-#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */
-#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */
-
-#define AT91_RTC_SR 0x18 /* Status Register */
-#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */
-#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */
-#define AT91_RTC_SECEV (1 << 2) /* Second Event */
-#define AT91_RTC_TIMEV (1 << 3) /* Time Event */
-#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */
-
-#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
-#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
-#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
-#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
-
-#define AT91_RTC_VER 0x2c /* Valid Entry Register */
-#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */
-#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */
-#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */
-#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */
-
-#endif
--
1.8.1.1

Subject: Re: [rtc-linux] [PATCH 3/3] ARM: at91: fix hanged boot

On 13:51 Fri 08 Mar , Johan Hovold wrote:
> Make sure the RTC and RTT-interrupts are masked at boot by adding a new
> SOC-initialiser and helpers functions.
>
> This fixes hanged boot on all AT91 SOCs but RM9200, for example, after a
> reset during an RTC-update or if an RTC or RTT-alarm goes off after a
> non-clean shutdown.
>
> 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, 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.
>
> Tested on at91sam9263 and at91sam9g45.
>
> Signed-off-by: Johan Hovold <[email protected]>
> ---
> arch/arm/mach-at91/at91rm9200.c | 9 ++++++++
> arch/arm/mach-at91/at91sam9260.c | 6 ++++++
> arch/arm/mach-at91/at91sam9261.c | 6 ++++++
> arch/arm/mach-at91/at91sam9263.c | 7 ++++++
> arch/arm/mach-at91/at91sam9g45.c | 7 ++++++
> arch/arm/mach-at91/at91sam9n12.c | 6 ++++++
> arch/arm/mach-at91/at91sam9rl.c | 7 ++++++
> arch/arm/mach-at91/at91sam9x5.c | 6 ++++++
> arch/arm/mach-at91/generic.h | 2 ++
> arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 +++++
> arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 +++++
nack for DT probe te address via DT
> arch/arm/mach-at91/setup.c | 31 +++++++++++++++++++++++++++
> arch/arm/mach-at91/soc.h | 1 +
> 13 files changed, 98 insertions(+)

at boot time we can disable all the irq as we need none of them
>
> diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> index 7aeb473..4651ebb 100644
> --- a/arch/arm/mach-at91/at91rm9200.c
> +++ b/arch/arm/mach-at91/at91rm9200.c
> @@ -325,6 +325,14 @@ static void __init at91rm9200_ioremap_registers(void)
> at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256);
> }
>
> +static void __init at91rm9200_sysirq_mask(void)
> +{
> + /*
> + * No need to mask any system interrupts as the RM9200 has no backup
> + * power and resets all system peripherals at every reset.
> + */
> +}
no need drop it
> +
> static void __init at91rm9200_initialize(void)
> {
> arm_pm_idle = at91rm9200_idle;
> @@ -387,5 +395,6 @@ AT91_SOC_START(rm9200)
> .default_irq_priority = at91rm9200_default_irq_priority,
> .ioremap_registers = at91rm9200_ioremap_registers,
> .register_clocks = at91rm9200_register_clocks,
> + .sysirq_mask = at91rm9200_sysirq_mask,
> .init = at91rm9200_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
> index b67cd53..c47a0db 100644
> --- a/arch/arm/mach-at91/at91sam9260.c
> +++ b/arch/arm/mach-at91/at91sam9260.c
> @@ -342,6 +342,11 @@ static void __init at91sam9260_ioremap_registers(void)
> at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX);
> }
>
> +static void __init at91sam9260_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
> +}
> +
> static void __init at91sam9260_initialize(void)
> {
> arm_pm_idle = at91sam9_idle;
> @@ -400,5 +405,6 @@ AT91_SOC_START(sam9260)
> .default_irq_priority = at91sam9260_default_irq_priority,
> .ioremap_registers = at91sam9260_ioremap_registers,
> .register_clocks = at91sam9260_register_clocks,
> + .sysirq_mask = at91sam9260_sysirq_mask,
> .init = at91sam9260_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
> index 0204f4c..396e4cb 100644
> --- a/arch/arm/mach-at91/at91sam9261.c
> +++ b/arch/arm/mach-at91/at91sam9261.c
> @@ -286,6 +286,11 @@ static void __init at91sam9261_ioremap_registers(void)
> at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX);
> }
>
> +static void __init at91sam9261_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
> +}
> +
> static void __init at91sam9261_initialize(void)
> {
> arm_pm_idle = at91sam9_idle;
> @@ -344,5 +349,6 @@ AT91_SOC_START(sam9261)
> .default_irq_priority = at91sam9261_default_irq_priority,
> .ioremap_registers = at91sam9261_ioremap_registers,
> .register_clocks = at91sam9261_register_clocks,
> + .sysirq_mask = at91sam9261_sysirq_mask,
> .init = at91sam9261_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
> index c0cbb81..a0166a3 100644
> --- a/arch/arm/mach-at91/at91sam9263.c
> +++ b/arch/arm/mach-at91/at91sam9263.c
> @@ -325,6 +325,12 @@ static void __init at91sam9263_ioremap_registers(void)
> at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX);
> }
>
> +static void __init at91sam9263_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
> + at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
> +}
> +
> static void __init at91sam9263_initialize(void)
> {
> arm_pm_idle = at91sam9_idle;
> @@ -382,5 +388,6 @@ AT91_SOC_START(sam9263)
> .default_irq_priority = at91sam9263_default_irq_priority,
> .ioremap_registers = at91sam9263_ioremap_registers,
> .register_clocks = at91sam9263_register_clocks,
> + .sysirq_mask = at91sam9263_sysirq_mask,
> .init = at91sam9263_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
> index b4968aa..3d5498e 100644
> --- a/arch/arm/mach-at91/at91sam9g45.c
> +++ b/arch/arm/mach-at91/at91sam9g45.c
> @@ -370,6 +370,12 @@ static void __init at91sam9g45_ioremap_registers(void)
> at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX);
> }
>
> +static void __init at91sam9g45_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
> + at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
> +}
> +
> static void __init at91sam9g45_initialize(void)
> {
> arm_pm_idle = at91sam9_idle;
> @@ -427,5 +433,6 @@ AT91_SOC_START(sam9g45)
> .default_irq_priority = at91sam9g45_default_irq_priority,
> .ioremap_registers = at91sam9g45_ioremap_registers,
> .register_clocks = at91sam9g45_register_clocks,
> + .sysirq_mask = at91sam9g45_sysirq_mask,
> .init = at91sam9g45_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
> index 5dfc8fd..e2ddb89 100644
> --- a/arch/arm/mach-at91/at91sam9n12.c
> +++ b/arch/arm/mach-at91/at91sam9n12.c
> @@ -221,6 +221,11 @@ static void __init at91sam9n12_map_io(void)
> at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
> }
>
> +static void __init at91sam9n12_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtc(AT91SAM9N12_BASE_RTC);
> +}
> +
> void __init at91sam9n12_initialize(void)
> {
> at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
> @@ -229,5 +234,6 @@ void __init at91sam9n12_initialize(void)
> AT91_SOC_START(sam9n12)
> .map_io = at91sam9n12_map_io,
> .register_clocks = at91sam9n12_register_clocks,
> + .sysirq_mask = at91sam9n12_sysirq_mask,
> .init = at91sam9n12_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
> index 3de3e04..bde999f 100644
> --- a/arch/arm/mach-at91/at91sam9rl.c
> +++ b/arch/arm/mach-at91/at91sam9rl.c
> @@ -289,6 +289,12 @@ static void __init at91sam9rl_ioremap_registers(void)
> at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX);
> }
>
> +static void __init at91sam9rl_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
> + at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
> +}
> +
> static void __init at91sam9rl_initialize(void)
> {
> arm_pm_idle = at91sam9_idle;
> @@ -346,5 +352,6 @@ AT91_SOC_START(sam9rl)
> .default_irq_priority = at91sam9rl_default_irq_priority,
> .ioremap_registers = at91sam9rl_ioremap_registers,
> .register_clocks = at91sam9rl_register_clocks,
> + .sysirq_mask = at91sam9rl_sysirq_mask,
> .init = at91sam9rl_initialize,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
> index 44a9a62..20a214f 100644
> --- a/arch/arm/mach-at91/at91sam9x5.c
> +++ b/arch/arm/mach-at91/at91sam9x5.c
> @@ -316,6 +316,11 @@ static void __init at91sam9x5_map_io(void)
> at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
> }
>
> +static void __init at91sam9x5_sysirq_mask(void)
> +{
> + at91_sysirq_mask_rtc(AT91SAM9X5_BASE_RTC);
> +}
> +
> /* --------------------------------------------------------------------
> * Interrupt initialization
> * -------------------------------------------------------------------- */
> @@ -323,4 +328,5 @@ static void __init at91sam9x5_map_io(void)
> AT91_SOC_START(sam9x5)
> .map_io = at91sam9x5_map_io,
> .register_clocks = at91sam9x5_register_clocks,
> + .sysirq_mask = at91sam9x5_sysirq_mask,
> AT91_SOC_END
> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
> index fc593d6..90a854d 100644
> --- a/arch/arm/mach-at91/generic.h
> +++ b/arch/arm/mach-at91/generic.h
> @@ -33,6 +33,8 @@ extern int __init at91_aic_of_init(struct device_node *node,
> struct device_node *parent);
> extern int __init at91_aic5_of_init(struct device_node *node,
> struct device_node *parent);
> +extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
> +extern void __init at91_sysirq_mask_rtt(u32 rtt_base);
>
>
> /* Timer */
> diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
> index d374b87..0151bcf 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9n12.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
> @@ -49,6 +49,11 @@
> #define AT91SAM9N12_BASE_USART3 0xf8028000
>
> /*
> + * System Peripherals
> + */
> +#define AT91SAM9N12_BASE_RTC 0xfffffeb0
> +
> +/*
> * Internal Memory.
> */
> #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 c75ee19..2fc76c4 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
> @@ -55,6 +55,11 @@
> #define AT91SAM9X5_BASE_USART2 0xf8024000
>
> /*
> + * System Peripherals
> + */
> +#define AT91SAM9X5_BASE_RTC 0xfffffeb0
> +
> +/*
> * Internal Memory.
> */
> #define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */
> diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
> index 4b67847..ac05453 100644
> --- a/arch/arm/mach-at91/setup.c
> +++ b/arch/arm/mach-at91/setup.c
> @@ -19,6 +19,8 @@
> #include <mach/cpu.h>
> #include <mach/at91_dbgu.h>
> #include <mach/at91_pmc.h>
> +#include <mach/at91_rtc.h>
> +#include <mach/at91_rtt.h>
>
> #include "at91_shdwc.h"
> #include "soc.h"
> @@ -311,6 +313,31 @@ void __init at91_ioremap_matrix(u32 base_addr)
> panic("Impossible to ioremap at91_matrix_base\n");
> }
>
> +void __init at91_sysirq_mask_rtc(u32 rtc_base)
> +{
> + void *base = AT91_IO_P2V(rtc_base);
> + u32 mask;
> +
> + mask = __raw_readl(base + AT91_RTC_IMR);
> + if (mask) {
> + pr_info("AT91: Disabling rtc irq\n");
> + __raw_writel(mask, base + AT91_RTC_IDR);
> + }
> +}
> +
> +void __init at91_sysirq_mask_rtt(u32 rtt_base)
> +{
> + void *base = AT91_IO_P2V(rtt_base);
> + u32 mr;
> +
> + mr = __raw_readl(base + AT91_RTT_MR);
> + if (mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) {
> + pr_info("AT91: Disabling rtt irq\n");
> + mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
> + __raw_writel(mr, base + AT91_RTT_MR);
> + }
> +}
> +
> #if defined(CONFIG_OF)
> static struct of_device_id rstc_ids[] = {
> { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart },
> @@ -467,6 +494,8 @@ void __init at91_dt_initialize(void)
>
> if (at91_boot_soc.init)
> at91_boot_soc.init();
> +
> + at91_boot_soc.sysirq_mask();
> }
> #endif
>
> @@ -482,5 +511,7 @@ void __init at91_initialize(unsigned long main_clock)
>
> at91_boot_soc.init();
>
> + at91_boot_soc.sysirq_mask();
> +
> pinctrl_provide_dummies();
> }
> diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
> index 9c6d3d4..134f4c4 100644
> --- a/arch/arm/mach-at91/soc.h
> +++ b/arch/arm/mach-at91/soc.h
> @@ -10,6 +10,7 @@ struct at91_init_soc {
> void (*map_io)(void);
> void (*ioremap_registers)(void);
> void (*register_clocks)(void);
> + void (*sysirq_mask)(void);
> void (*init)(void);
> };
>
> --
> 1.8.1.1
>
> --
> --
> You received this message because you are subscribed to "rtc-linux".
> Membership options at http://groups.google.com/group/rtc-linux .
> Please read http://groups.google.com/group/rtc-linux/web/checklist
> before submitting a driver.
> ---
> You received this message because you are subscribed to the Google Groups "rtc-linux" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

2013-03-11 10:03:39

by Johan Hovold

[permalink] [raw]
Subject: Re: [rtc-linux] [PATCH 3/3] ARM: at91: fix hanged boot

On Fri, Mar 08, 2013 at 05:02:58PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 13:51 Fri 08 Mar , Johan Hovold wrote:
> > Make sure the RTC and RTT-interrupts are masked at boot by adding a new
> > SOC-initialiser and helpers functions.
> >
> > This fixes hanged boot on all AT91 SOCs but RM9200, for example, after a
> > reset during an RTC-update or if an RTC or RTT-alarm goes off after a
> > non-clean shutdown.
> >
> > 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, 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.
> >
> > Tested on at91sam9263 and at91sam9g45.
> >
> > Signed-off-by: Johan Hovold <[email protected]>
> > ---
> > arch/arm/mach-at91/at91rm9200.c | 9 ++++++++
> > arch/arm/mach-at91/at91sam9260.c | 6 ++++++
> > arch/arm/mach-at91/at91sam9261.c | 6 ++++++
> > arch/arm/mach-at91/at91sam9263.c | 7 ++++++
> > arch/arm/mach-at91/at91sam9g45.c | 7 ++++++
> > arch/arm/mach-at91/at91sam9n12.c | 6 ++++++
> > arch/arm/mach-at91/at91sam9rl.c | 7 ++++++
> > arch/arm/mach-at91/at91sam9x5.c | 6 ++++++
> > arch/arm/mach-at91/generic.h | 2 ++
> > arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 +++++
> > arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 +++++
> nack for DT probe te address via DT

Fair enough. I'll respin and add proper DT-support.

> > arch/arm/mach-at91/setup.c | 31 +++++++++++++++++++++++++++
> > arch/arm/mach-at91/soc.h | 1 +
> > 13 files changed, 98 insertions(+)
>
> at boot time we can disable all the irq as we need none of them

Yes, but all but the VDDBU-powered-peripheral ones will already have
been disabled at reset. If a buggy bootloader enables something it
should not, then the bootloader should be fixed.

> > diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> > index 7aeb473..4651ebb 100644
> > --- a/arch/arm/mach-at91/at91rm9200.c
> > +++ b/arch/arm/mach-at91/at91rm9200.c
> > @@ -325,6 +325,14 @@ static void __init at91rm9200_ioremap_registers(void)
> > at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256);
> > }
> >
> > +static void __init at91rm9200_sysirq_mask(void)
> > +{
> > + /*
> > + * No need to mask any system interrupts as the RM9200 has no backup
> > + * power and resets all system peripherals at every reset.
> > + */
> > +}
> no need drop it

Ok.

Thanks,
Johan

> > +
> > static void __init at91rm9200_initialize(void)
> > {
> > arm_pm_idle = at91rm9200_idle;
> > @@ -387,5 +395,6 @@ AT91_SOC_START(rm9200)
> > .default_irq_priority = at91rm9200_default_irq_priority,
> > .ioremap_registers = at91rm9200_ioremap_registers,
> > .register_clocks = at91rm9200_register_clocks,
> > + .sysirq_mask = at91rm9200_sysirq_mask,
> > .init = at91rm9200_initialize,
> > AT91_SOC_END

Subject: Re: [rtc-linux] [PATCH 3/3] ARM: at91: fix hanged boot

On 11:02 Mon 11 Mar , Johan Hovold wrote:
> On Fri, Mar 08, 2013 at 05:02:58PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > On 13:51 Fri 08 Mar , Johan Hovold wrote:
> > > Make sure the RTC and RTT-interrupts are masked at boot by adding a new
> > > SOC-initialiser and helpers functions.
> > >
> > > This fixes hanged boot on all AT91 SOCs but RM9200, for example, after a
> > > reset during an RTC-update or if an RTC or RTT-alarm goes off after a
> > > non-clean shutdown.
> > >
> > > 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, 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.
> > >
> > > Tested on at91sam9263 and at91sam9g45.
> > >
> > > Signed-off-by: Johan Hovold <[email protected]>
> > > ---
> > > arch/arm/mach-at91/at91rm9200.c | 9 ++++++++
> > > arch/arm/mach-at91/at91sam9260.c | 6 ++++++
> > > arch/arm/mach-at91/at91sam9261.c | 6 ++++++
> > > arch/arm/mach-at91/at91sam9263.c | 7 ++++++
> > > arch/arm/mach-at91/at91sam9g45.c | 7 ++++++
> > > arch/arm/mach-at91/at91sam9n12.c | 6 ++++++
> > > arch/arm/mach-at91/at91sam9rl.c | 7 ++++++
> > > arch/arm/mach-at91/at91sam9x5.c | 6 ++++++
> > > arch/arm/mach-at91/generic.h | 2 ++
> > > arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 +++++
> > > arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 +++++
> > nack for DT probe te address via DT
>
> Fair enough. I'll respin and add proper DT-support.
>
> > > arch/arm/mach-at91/setup.c | 31 +++++++++++++++++++++++++++
> > > arch/arm/mach-at91/soc.h | 1 +
> > > 13 files changed, 98 insertions(+)
> >
> > at boot time we can disable all the irq as we need none of them
>
> Yes, but all but the VDDBU-powered-peripheral ones will already have
> been disabled at reset. If a buggy bootloader enables something it
> should not, then the bootloader should be fixed.
so fix the bootloader NACK in the kernel
it's too much ugly

the kernel requirere the interrupt to be disabled

Best Regards,
J.

2013-03-11 18:07:09

by Johan Hovold

[permalink] [raw]
Subject: Re: [rtc-linux] [PATCH 3/3] ARM: at91: fix hanged boot

On Mon, Mar 11, 2013 at 12:06:37PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 11:02 Mon 11 Mar , Johan Hovold wrote:
> > On Fri, Mar 08, 2013 at 05:02:58PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > > On 13:51 Fri 08 Mar , Johan Hovold wrote:
> > > > Make sure the RTC and RTT-interrupts are masked at boot by adding a new
> > > > SOC-initialiser and helpers functions.
> > > >
> > > > This fixes hanged boot on all AT91 SOCs but RM9200, for example, after a
> > > > reset during an RTC-update or if an RTC or RTT-alarm goes off after a
> > > > non-clean shutdown.
> > > >
> > > > 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, 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.
> > > >
> > > > Tested on at91sam9263 and at91sam9g45.
> > > >
> > > > Signed-off-by: Johan Hovold <[email protected]>
> > > > ---
> > > > arch/arm/mach-at91/at91rm9200.c | 9 ++++++++
> > > > arch/arm/mach-at91/at91sam9260.c | 6 ++++++
> > > > arch/arm/mach-at91/at91sam9261.c | 6 ++++++
> > > > arch/arm/mach-at91/at91sam9263.c | 7 ++++++
> > > > arch/arm/mach-at91/at91sam9g45.c | 7 ++++++
> > > > arch/arm/mach-at91/at91sam9n12.c | 6 ++++++
> > > > arch/arm/mach-at91/at91sam9rl.c | 7 ++++++
> > > > arch/arm/mach-at91/at91sam9x5.c | 6 ++++++
> > > > arch/arm/mach-at91/generic.h | 2 ++
> > > > arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 +++++
> > > > arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 +++++
> > > nack for DT probe te address via DT
> >
> > Fair enough. I'll respin and add proper DT-support.
> >
> > > > arch/arm/mach-at91/setup.c | 31 +++++++++++++++++++++++++++
> > > > arch/arm/mach-at91/soc.h | 1 +
> > > > 13 files changed, 98 insertions(+)
> > >
> > > at boot time we can disable all the irq as we need none of them
> >
> > Yes, but all but the VDDBU-powered-peripheral ones will already have
> > been disabled at reset. If a buggy bootloader enables something it
> > should not, then the bootloader should be fixed.
> so fix the bootloader NACK in the kernel

If it had been enabled by the bootloader, it would no doubt be a
bootloader bug. The problem is that bootloader may not know anything
about RTT/RTC and it was Linux that enabled the interrupts in the first
place. The question is whether it should still be the bootloader's
responsibility to clean it up.

> it's too much ugly

Agreed, but this needs to be fixed somewhere.

> the kernel requirere the interrupt to be disabled

And this is the problem -- the interrupts _are_ disabled when the kernel
is executed. It is Linux that enables the system interrupt without
making sure it can handle the interrupts that could arrive.

But sure, I can see arguments in favor of either solution (fix in
bootloader or kernel).

It is a severe bug, which affects all AT91 systems (but RM9200). It's
fairly hard to track down, and this has apparently already been done
over and over again. In my opinion, fixing it once and for all in the
kernel has some appeal.

To give an idea of what it could look like, I'm responding to this mail
with with a v2 of my series with added DT-support (the DT-bits are
compile-only tested).

Thanks,
Johan

2013-03-11 18:11:23

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 0/5] ARM: at91: fix hanged boot

These patches fix a few severe issues affecting most AT91 SOCs where
boot can hang after a non-general reset, and where the only way to get
the system booting again is to do a general reset -- something which
could require physically removing any backup battery.

The problems stem from the fact that the RTC and RTT-peripherals are
powered by backup power (VDDBU) and are not reset on wake-up, user,
watchdog or software reset. Consequently, RTC and RTT-alarms and their
interrupts may be enabled at boot, leading to a system lock-up when an
interrupt arrives on the shared system-interrupt line before the
appropriate handler (e.g. RTC-driver) has been installed.

The easiest way to trigger this is to simply wake up from an RTC-alarm
on at91sam9g45. The RTC-driver currently does not disable interrupts at
shutdown so even after a clean shut-down the system will always hang
after waking up.

The first patch fixes this very general case of RTC-wake up after a
clean shutdown in the RTC-driver and is marked for stable as it is
perfectly straight-forward. [ Note that the other, RTT-based, AT91
RTC-driver already disables its interrupts at shutdown. ]

The more general problem can be triggered, for example, by doing a
user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
off after a non-clean shutdown.

To fix this I propose that arch-code should mask the relevant interrupts
before enabling the system interrupt at early boot, and this is what
the fifth patch does. To access the RTC-registers I choose to revert a
recent patch that moved the register definitions to drivers/rtc.

Arguably, the relevant interrupts could also be disabled in bootloaders,
but I suggest fixing it in the kernel once and for all.

The patches have been tested on at91sam9263 and at91sam9g45 (non-DT),
and compile-tested for the other SOCs and DT.

Johan


v2:
- add DT-support
- make sys_irq_mask non-mandatory


Johan Hovold (5):
ARM: at91/rtc: fix boot after RTC wake-up
ARM: at91/dts: add RTC nodes
ARM: at91/dts: add RTT nodes
Revert "arm: at91: move at91rm9200 rtc header in drivers/rtc"
ARM: at91: fix hanged boot

arch/arm/boot/dts/at91rm9200.dtsi | 5 ++
arch/arm/boot/dts/at91sam9260.dtsi | 5 ++
arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++
arch/arm/boot/dts/at91sam9g45.dtsi | 10 ++++
arch/arm/boot/dts/at91sam9n12.dtsi | 5 ++
arch/arm/boot/dts/at91sam9x5.dtsi | 5 ++
arch/arm/mach-at91/at91sam9260.c | 6 ++
arch/arm/mach-at91/at91sam9261.c | 6 ++
arch/arm/mach-at91/at91sam9263.c | 7 +++
arch/arm/mach-at91/at91sam9g45.c | 7 +++
arch/arm/mach-at91/at91sam9rl.c | 7 +++
arch/arm/mach-at91/generic.h | 2 +
arch/arm/mach-at91/include/mach/at91_rtc.h | 75 +++++++++++++++++++++++++
arch/arm/mach-at91/setup.c | 88 ++++++++++++++++++++++++++++++
arch/arm/mach-at91/soc.h | 1 +
drivers/rtc/rtc-at91rm9200.c | 11 +++-
drivers/rtc/rtc-at91rm9200.h | 75 -------------------------
17 files changed, 249 insertions(+), 76 deletions(-)
create mode 100644 arch/arm/mach-at91/include/mach/at91_rtc.h
delete mode 100644 drivers/rtc/rtc-at91rm9200.h

--
1.8.1.5

2013-03-11 18:11:31

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 5/5] ARM: at91: fix hanged boot

Make sure the RTC and RTT-interrupts are masked at boot by adding a new
SOC-initialiser and helpers functions.

This fixes hanged boot on all AT91 SOCs but RM9200, for example, after a
reset during an RTC-update or if an RTC or RTT-alarm goes off after a
non-clean shutdown.

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, 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.

Tested on at91sam9263 and at91sam9g45.

Signed-off-by: Johan Hovold <[email protected]>
---
arch/arm/mach-at91/at91sam9260.c | 6 +++
arch/arm/mach-at91/at91sam9261.c | 6 +++
arch/arm/mach-at91/at91sam9263.c | 7 ++++
arch/arm/mach-at91/at91sam9g45.c | 7 ++++
arch/arm/mach-at91/at91sam9rl.c | 7 ++++
arch/arm/mach-at91/generic.h | 2 +
arch/arm/mach-at91/setup.c | 88 ++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-at91/soc.h | 1 +
8 files changed, 124 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index b67cd53..c47a0db 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -342,6 +342,11 @@ static void __init at91sam9260_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX);
}

+static void __init at91sam9260_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
+}
+
static void __init at91sam9260_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -400,5 +405,6 @@ AT91_SOC_START(sam9260)
.default_irq_priority = at91sam9260_default_irq_priority,
.ioremap_registers = at91sam9260_ioremap_registers,
.register_clocks = at91sam9260_register_clocks,
+ .sysirq_mask = at91sam9260_sysirq_mask,
.init = at91sam9260_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 0204f4c..396e4cb 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -286,6 +286,11 @@ static void __init at91sam9261_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX);
}

+static void __init at91sam9261_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
+}
+
static void __init at91sam9261_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -344,5 +349,6 @@ AT91_SOC_START(sam9261)
.default_irq_priority = at91sam9261_default_irq_priority,
.ioremap_registers = at91sam9261_ioremap_registers,
.register_clocks = at91sam9261_register_clocks,
+ .sysirq_mask = at91sam9261_sysirq_mask,
.init = at91sam9261_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index c0cbb81..a0166a3 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -325,6 +325,12 @@ static void __init at91sam9263_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX);
}

+static void __init at91sam9263_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
+ at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
+}
+
static void __init at91sam9263_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -382,5 +388,6 @@ AT91_SOC_START(sam9263)
.default_irq_priority = at91sam9263_default_irq_priority,
.ioremap_registers = at91sam9263_ioremap_registers,
.register_clocks = at91sam9263_register_clocks,
+ .sysirq_mask = at91sam9263_sysirq_mask,
.init = at91sam9263_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index b4968aa..3d5498e 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -370,6 +370,12 @@ static void __init at91sam9g45_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX);
}

+static void __init at91sam9g45_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
+ at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
+}
+
static void __init at91sam9g45_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -427,5 +433,6 @@ AT91_SOC_START(sam9g45)
.default_irq_priority = at91sam9g45_default_irq_priority,
.ioremap_registers = at91sam9g45_ioremap_registers,
.register_clocks = at91sam9g45_register_clocks,
+ .sysirq_mask = at91sam9g45_sysirq_mask,
.init = at91sam9g45_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 3de3e04..bde999f 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -289,6 +289,12 @@ static void __init at91sam9rl_ioremap_registers(void)
at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX);
}

+static void __init at91sam9rl_sysirq_mask(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
+ at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
+}
+
static void __init at91sam9rl_initialize(void)
{
arm_pm_idle = at91sam9_idle;
@@ -346,5 +352,6 @@ AT91_SOC_START(sam9rl)
.default_irq_priority = at91sam9rl_default_irq_priority,
.ioremap_registers = at91sam9rl_ioremap_registers,
.register_clocks = at91sam9rl_register_clocks,
+ .sysirq_mask = at91sam9rl_sysirq_mask,
.init = at91sam9rl_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index fc593d6..90a854d 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -33,6 +33,8 @@ extern int __init at91_aic_of_init(struct device_node *node,
struct device_node *parent);
extern int __init at91_aic5_of_init(struct device_node *node,
struct device_node *parent);
+extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
+extern void __init at91_sysirq_mask_rtt(u32 rtt_base);


/* Timer */
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 4b67847..4c5790f 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -19,6 +19,8 @@
#include <mach/cpu.h>
#include <mach/at91_dbgu.h>
#include <mach/at91_pmc.h>
+#include <mach/at91_rtc.h>
+#include <mach/at91_rtt.h>

#include "at91_shdwc.h"
#include "soc.h"
@@ -311,6 +313,39 @@ void __init at91_ioremap_matrix(u32 base_addr)
panic("Impossible to ioremap at91_matrix_base\n");
}

+void __init __at91_sysirq_mask_rtc(void __iomem *rtc_base)
+{
+ u32 mask;
+
+ mask = __raw_readl(rtc_base + AT91_RTC_IMR);
+ if (mask) {
+ pr_info("AT91: Disabling rtc irq\n");
+ __raw_writel(mask, rtc_base + AT91_RTC_IDR);
+ }
+}
+
+void __init __at91_sysirq_mask_rtt(void __iomem *rtt_base)
+{
+ u32 mr;
+
+ mr = __raw_readl(rtt_base + AT91_RTT_MR);
+ if (mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) {
+ pr_info("AT91: Disabling rtt irq\n");
+ mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ __raw_writel(mr, rtt_base + AT91_RTT_MR);
+ }
+}
+
+void __init at91_sysirq_mask_rtc(u32 rtc_base)
+{
+ __at91_sysirq_mask_rtc(AT91_IO_P2V(rtc_base));
+}
+
+void __init at91_sysirq_mask_rtt(u32 rtt_base)
+{
+ __at91_sysirq_mask_rtt(AT91_IO_P2V(rtt_base));
+}
+
#if defined(CONFIG_OF)
static struct of_device_id rstc_ids[] = {
{ .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart },
@@ -440,6 +475,54 @@ end:
of_node_put(np);
}

+static struct of_device_id sysirq_mask_rtc_ids[] = {
+ { .compatible = "atmel,at91sam9g45-rtc" },
+ { /* sentinel */ }
+};
+
+static void at91_dt_sysirq_mask_rtc(void)
+{
+ struct device_node *np;
+ void __iomem *base;
+
+ for_each_matching_node(np, sysirq_mask_rtc_ids) {
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("AT91: unable to map rtc cpu registers\n");
+ continue;
+ }
+ __at91_sysirq_mask_rtc(base);
+ iounmap(base);
+ }
+}
+
+static struct of_device_id sysirq_mask_rtt_ids[] = {
+ { .compatible = "atmel,at91sam9260-rtt" },
+ { /* sentinel */ }
+};
+
+static void at91_dt_sysirq_mask_rtt(void)
+{
+ struct device_node *np;
+ void __iomem *base;
+
+ for_each_matching_node(np, sysirq_mask_rtt_ids) {
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("AT91: unable to map rtt cpu registers\n");
+ continue;
+ }
+ __at91_sysirq_mask_rtt(base);
+ iounmap(base);
+ }
+}
+
+static void at91_dt_sysirq_mask(void)
+{
+ at91_dt_sysirq_mask_rtc();
+ at91_dt_sysirq_mask_rtt();
+}
+
void __init at91rm9200_dt_initialize(void)
{
at91_dt_ramc();
@@ -467,6 +550,8 @@ void __init at91_dt_initialize(void)

if (at91_boot_soc.init)
at91_boot_soc.init();
+
+ at91_dt_sysirq_mask();
}
#endif

@@ -482,5 +567,8 @@ void __init at91_initialize(unsigned long main_clock)

at91_boot_soc.init();

+ if (at91_boot_soc.sysirq_mask)
+ at91_boot_soc.sysirq_mask();
+
pinctrl_provide_dummies();
}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 9c6d3d4..134f4c4 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -10,6 +10,7 @@ struct at91_init_soc {
void (*map_io)(void);
void (*ioremap_registers)(void);
void (*register_clocks)(void);
+ void (*sysirq_mask)(void);
void (*init)(void);
};

--
1.8.1.5

2013-03-11 18:11:29

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 3/5] ARM: at91/dts: add RTT nodes

Add RTT nodes for Atmel SOCs.

Signed-off-by: Johan Hovold <[email protected]>
---
arch/arm/boot/dts/at91sam9260.dtsi | 5 +++++
arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++++++++
arch/arm/boot/dts/at91sam9g45.dtsi | 5 +++++
3 files changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index cb7bcc5..3a7a8dd 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -462,6 +462,11 @@
status = "disabled";
};

+ rtt@fffffd20 {
+ compatible = "atmel,at91sam9260-rtt";
+ reg = <0xfffffd20 0x10>;
+ };
+
ssc0: ssc@fffbc000 {
compatible = "atmel,at91rm9200-ssc";
reg = <0xfffbc000 0x4000>;
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 271d4de..3a44382 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -457,6 +457,16 @@
status = "disabled";
};

+ rtt@fffffd20 {
+ compatible = "atmel,at91sam9260-rtt";
+ reg = <0xfffffd20 0x10>;
+ };
+
+ rtt@fffffd50 {
+ compatible = "atmel,at91sam9260-rtt";
+ reg = <0xfffffd50 0x10>;
+ };
+
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index c1ad522..750b696 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -531,6 +531,11 @@
reg = <0xfffffdb0 0x30>;
};

+ rtt@fffffd20 {
+ compatible = "atmel,at91sam9260-rtt";
+ reg = <0xfffffd20 0x10>;
+ };
+
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
--
1.8.1.5

2013-03-11 18:11:28

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 4/5] Revert "arm: at91: move at91rm9200 rtc header in drivers/rtc"

This reverts commit 75984df05d86956541795f01e62d7dc67bc522fd.

A couple of these register definitions are needed by arch code as the
RTC-interrupts must be disabled at early boot.

Signed-off-by: Johan Hovold <[email protected]>
---
arch/arm/mach-at91/include/mach/at91_rtc.h | 75 ++++++++++++++++++++++++++++++
drivers/rtc/rtc-at91rm9200.c | 2 +-
drivers/rtc/rtc-at91rm9200.h | 75 ------------------------------
3 files changed, 76 insertions(+), 76 deletions(-)
create mode 100644 arch/arm/mach-at91/include/mach/at91_rtc.h
delete mode 100644 drivers/rtc/rtc-at91rm9200.h

diff --git a/arch/arm/mach-at91/include/mach/at91_rtc.h b/arch/arm/mach-at91/include/mach/at91_rtc.h
new file mode 100644
index 0000000..da1945e
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91_rtc.h
@@ -0,0 +1,75 @@
+/*
+ * arch/arm/mach-at91/include/mach/at91_rtc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Real Time Clock (RTC) - System peripheral registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91_RTC_H
+#define AT91_RTC_H
+
+#define AT91_RTC_CR 0x00 /* Control Register */
+#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */
+#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */
+#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */
+#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8)
+#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
+#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
+#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
+#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */
+#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
+#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
+#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
+
+#define AT91_RTC_MR 0x04 /* Mode Register */
+#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
+
+#define AT91_RTC_TIMR 0x08 /* Time Register */
+#define AT91_RTC_SEC (0x7f << 0) /* Current Second */
+#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */
+#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
+#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */
+
+#define AT91_RTC_CALR 0x0c /* Calendar Register */
+#define AT91_RTC_CENT (0x7f << 0) /* Current Century */
+#define AT91_RTC_YEAR (0xff << 8) /* Current Year */
+#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */
+#define AT91_RTC_DAY (7 << 21) /* Current Day */
+#define AT91_RTC_DATE (0x3f << 24) /* Current Date */
+
+#define AT91_RTC_TIMALR 0x10 /* Time Alarm Register */
+#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */
+#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */
+#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */
+
+#define AT91_RTC_CALALR 0x14 /* Calendar Alarm Register */
+#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */
+#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */
+
+#define AT91_RTC_SR 0x18 /* Status Register */
+#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */
+#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */
+#define AT91_RTC_SECEV (1 << 2) /* Second Event */
+#define AT91_RTC_TIMEV (1 << 3) /* Time Event */
+#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */
+
+#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
+#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
+#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
+#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
+
+#define AT91_RTC_VER 0x2c /* Valid Entry Register */
+#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */
+#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */
+#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */
+#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */
+
+#endif
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 936c75a..1ed0433 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -31,7 +31,7 @@

#include <asm/uaccess.h>

-#include "rtc-at91rm9200.h"
+#include <mach/at91_rtc.h>

#define at91_rtc_read(field) \
__raw_readl(at91_rtc_regs + field)
diff --git a/drivers/rtc/rtc-at91rm9200.h b/drivers/rtc/rtc-at91rm9200.h
deleted file mode 100644
index da1945e..0000000
--- a/drivers/rtc/rtc-at91rm9200.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_rtc.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Real Time Clock (RTC) - System peripheral registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_RTC_H
-#define AT91_RTC_H
-
-#define AT91_RTC_CR 0x00 /* Control Register */
-#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */
-#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */
-#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */
-#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8)
-#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
-#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
-#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
-#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */
-#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
-#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
-#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
-
-#define AT91_RTC_MR 0x04 /* Mode Register */
-#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
-
-#define AT91_RTC_TIMR 0x08 /* Time Register */
-#define AT91_RTC_SEC (0x7f << 0) /* Current Second */
-#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */
-#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
-#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */
-
-#define AT91_RTC_CALR 0x0c /* Calendar Register */
-#define AT91_RTC_CENT (0x7f << 0) /* Current Century */
-#define AT91_RTC_YEAR (0xff << 8) /* Current Year */
-#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */
-#define AT91_RTC_DAY (7 << 21) /* Current Day */
-#define AT91_RTC_DATE (0x3f << 24) /* Current Date */
-
-#define AT91_RTC_TIMALR 0x10 /* Time Alarm Register */
-#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */
-#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */
-#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */
-
-#define AT91_RTC_CALALR 0x14 /* Calendar Alarm Register */
-#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */
-#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */
-
-#define AT91_RTC_SR 0x18 /* Status Register */
-#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */
-#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */
-#define AT91_RTC_SECEV (1 << 2) /* Second Event */
-#define AT91_RTC_TIMEV (1 << 3) /* Time Event */
-#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */
-
-#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
-#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
-#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
-#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
-
-#define AT91_RTC_VER 0x2c /* Valid Entry Register */
-#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */
-#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */
-#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */
-#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */
-
-#endif
--
1.8.1.5

2013-03-11 18:11:26

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 1/5] ARM: at91/rtc: fix boot after RTC wake-up

Fix failed boot after RTC wake-up by making sure RTC-interrupts are
disabled at shutdown.

The RTC-registers are not reset at shutdown when there is backup power
available, and hence the RTC-interrupt, which uses the shared system
interrupt, may be enabled during early boot. If an RTC-alarm goes off
before the RTC-driver is initialised (e.g. when waking up from an
RTC-alarm) this results in disabled system interrupts.

Without earlyprintk boot hangs after

Uncompressing Linux... done, booting the kernel.

and earlyprintk reveals that the shared system interrupt gets disabled:

irq 17: nobody cared (try booting with the "irqpoll" option)
[<c000cf8c>] (unwind_backtrace+0x0/0xf0) from [<c00513ec>] (__report_bad_irq+0x20/0xe8)
[<c00513ec>] (__report_bad_irq+0x20/0xe8) from [<c00516fc>] (note_interrupt+0x1e0/0x244)
[<c00516fc>] (note_interrupt+0x1e0/0x244) from [<c004f980>] (handle_irq_event_percpu+0xac/0x1c4)
[<c004f980>] (handle_irq_event_percpu+0xac/0x1c4) from [<c004faec>] (handle_irq_event+0x54/0x84)
[<c004faec>] (handle_irq_event+0x54/0x84) from [<c0052364>] (handle_fasteoi_irq+0x84/0x154)
[<c0052364>] (handle_fasteoi_irq+0x84/0x154) from [<c004f1f8>] (generic_handle_irq+0x20/0x30)
[<c004f1f8>] (generic_handle_irq+0x20/0x30) from [<c0009b8c>] (handle_IRQ+0x30/0x84)
[<c0009b8c>] (handle_IRQ+0x30/0x84) from [<c0008fa0>] (__irq_svc+0x40/0x6c)
[<c0008fa0>] (__irq_svc+0x40/0x6c) from [<c001cd6c>] (__do_softirq+0x5c/0x164)
[<c001cd6c>] (__do_softirq+0x5c/0x164) from [<c001d268>] (irq_exit+0x58/0x60)
[<c001d268>] (irq_exit+0x58/0x60) from [<c0009b90>] (handle_IRQ+0x34/0x84)
[<c0009b90>] (handle_IRQ+0x34/0x84) from [<c0008fa0>] (__irq_svc+0x40/0x6c)
[<c0008fa0>] (__irq_svc+0x40/0x6c) from [<c03e668c>] (start_kernel+0x1d8/0x29c)
[<c03e668c>] (start_kernel+0x1d8/0x29c) from [<70008040>] (0x70008040)
handlers:
[<c0012df0>] at91sam926x_pit_interrupt
Disabling IRQ #17

Note that disabling the RTC-interrupts at shutdown fixes boot after a
clean shutdown, but that an RTC-alarm after a user (or watchdog) reset
could still prevent the system from booting.

Note also that the only way to recover from a failed boot after an
RTC-alarm is to remove any backup power (e.g. backup battery) or to
disable (or acknowledge) the RTC-interrupt manually from the bootloader.
In particular, a user-reset is not sufficient.

Tested on at91sam9g45.

Cc: stable <[email protected]>
Signed-off-by: Johan Hovold <[email protected]>
---
drivers/rtc/rtc-at91rm9200.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index b6469e2..936c75a 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -338,6 +338,14 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
return 0;
}

+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+ /* Disable all interrupts */
+ at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+}
+
#ifdef CONFIG_PM

/* AT91RM9200 RTC Power management control */
@@ -384,6 +392,7 @@ static const struct dev_pm_ops at91_rtc_pm = {

static struct platform_driver at91_rtc_driver = {
.remove = __exit_p(at91_rtc_remove),
+ .shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
.owner = THIS_MODULE,
--
1.8.1.5

2013-03-11 18:12:37

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 2/5] ARM: at91/dts: add RTC nodes

Add RTC nodes for Atmel SOCs.

Use two different compatible properties to reflect the fact that the
RTC-peripherals are backup powered (VDDBU) and are thus not reset on
wake-up, user, watchdog or software reset on all SOCs but at91rm9200.

Signed-off-by: Johan Hovold <[email protected]>
---
arch/arm/boot/dts/at91rm9200.dtsi | 5 +++++
arch/arm/boot/dts/at91sam9g45.dtsi | 5 +++++
arch/arm/boot/dts/at91sam9n12.dtsi | 5 +++++
arch/arm/boot/dts/at91sam9x5.dtsi | 5 +++++
4 files changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 222047f..96b4e30 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -326,6 +326,11 @@
status = "disabled";
};

+ rtc@fffffe00 {
+ compatible = "atmel,at91rm9200-rtc";
+ reg = <0xfffffe00 0x30>;
+ };
+
usb0: ohci@00300000 {
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00300000 0x100000>;
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 6b1d4ca..c1ad522 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -526,6 +526,11 @@
status = "disabled";
};

+ rtc@fffffdb0 {
+ compatible = "atmel,at91sam9g45-rtc";
+ reg = <0xfffffdb0 0x30>;
+ };
+
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 4801717..802e92f 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -311,6 +311,11 @@
status = "disabled";
};

+ rtc@fffffeb0 {
+ compatible = "atmel,at91sam9g45-rtc";
+ reg = <0xfffffeb0 0x30>;
+ };
+
ssc0: ssc@f0010000 {
compatible = "atmel,at91sam9g45-ssc";
reg = <0xf0010000 0x4000>;
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index c461e11..432fbfb 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -362,6 +362,11 @@
};
};

+ rtc@fffffeb0 {
+ compatible = "atmel,at91sam9g45-rtc";
+ reg = <0xfffffeb0 0x30>;
+ };
+
ssc0: ssc@f0010000 {
compatible = "atmel,at91sam9g45-ssc";
reg = <0xf0010000 0x4000>;
--
1.8.1.5

2013-04-11 15:56:08

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] ARM: at91: fix hanged boot

On Mon, Mar 11, 2013 at 07:07:54PM +0100, Johan Hovold wrote:
> These patches fix a few severe issues affecting most AT91 SOCs where
> boot can hang after a non-general reset, and where the only way to get
> the system booting again is to do a general reset -- something which
> could require physically removing any backup battery.

Have you had time to look at these patches yet, Nicolas?

I don't think not having decided on the path forward for DT-support for
rtc-at91sam9 needs to be a blocker. The rtt-nodes will be needed in any
case.

I could respin the series on top of the DT-patch for rtc-at91rm9200, and
add interrupt and status-disabled properties to the DT-nodes as well.

Thanks,
Johan

> The problems stem from the fact that the RTC and RTT-peripherals are
> powered by backup power (VDDBU) and are not reset on wake-up, user,
> watchdog or software reset. Consequently, RTC and RTT-alarms and their
> interrupts may be enabled at boot, leading to a system lock-up when an
> interrupt arrives on the shared system-interrupt line before the
> appropriate handler (e.g. RTC-driver) has been installed.
>
> The easiest way to trigger this is to simply wake up from an RTC-alarm
> on at91sam9g45. The RTC-driver currently does not disable interrupts at
> shutdown so even after a clean shut-down the system will always hang
> after waking up.
>
> The first patch fixes this very general case of RTC-wake up after a
> clean shutdown in the RTC-driver and is marked for stable as it is
> perfectly straight-forward. [ Note that the other, RTT-based, AT91
> RTC-driver already disables its interrupts at shutdown. ]
>
> The more general problem can be triggered, for example, by doing a
> user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
> off after a non-clean shutdown.
>
> To fix this I propose that arch-code should mask the relevant interrupts
> before enabling the system interrupt at early boot, and this is what
> the fifth patch does. To access the RTC-registers I choose to revert a
> recent patch that moved the register definitions to drivers/rtc.
>
> Arguably, the relevant interrupts could also be disabled in bootloaders,
> but I suggest fixing it in the kernel once and for all.
>
> The patches have been tested on at91sam9263 and at91sam9g45 (non-DT),
> and compile-tested for the other SOCs and DT.
>
> Johan
>
>
> v2:
> - add DT-support
> - make sys_irq_mask non-mandatory
>
>
> Johan Hovold (5):
> ARM: at91/rtc: fix boot after RTC wake-up
> ARM: at91/dts: add RTC nodes
> ARM: at91/dts: add RTT nodes
> Revert "arm: at91: move at91rm9200 rtc header in drivers/rtc"
> ARM: at91: fix hanged boot

Subject: Re: [rtc-linux] Re: [PATCH v2 0/5] ARM: at91: fix hanged boot

On 17:55 Thu 11 Apr , Johan Hovold wrote:
> On Mon, Mar 11, 2013 at 07:07:54PM +0100, Johan Hovold wrote:
> > These patches fix a few severe issues affecting most AT91 SOCs where
> > boot can hang after a non-general reset, and where the only way to get
> > the system booting again is to do a general reset -- something which
> > could require physically removing any backup battery.
>
> Have you had time to look at these patches yet, Nicolas?
>
> I don't think not having decided on the path forward for DT-support for
> rtc-at91sam9 needs to be a blocker. The rtt-nodes will be needed in any
> case.
>
> I could respin the series on top of the DT-patch for rtc-at91rm9200, and
> add interrupt and status-disabled properties to the DT-nodes as well.
for this this is still a no go

this way too much ugly

Best Regards,
J.
>
> Thanks,
> Johan
>
> > The problems stem from the fact that the RTC and RTT-peripherals are
> > powered by backup power (VDDBU) and are not reset on wake-up, user,
> > watchdog or software reset. Consequently, RTC and RTT-alarms and their
> > interrupts may be enabled at boot, leading to a system lock-up when an
> > interrupt arrives on the shared system-interrupt line before the
> > appropriate handler (e.g. RTC-driver) has been installed.
> >
> > The easiest way to trigger this is to simply wake up from an RTC-alarm
> > on at91sam9g45. The RTC-driver currently does not disable interrupts at
> > shutdown so even after a clean shut-down the system will always hang
> > after waking up.
> >
> > The first patch fixes this very general case of RTC-wake up after a
> > clean shutdown in the RTC-driver and is marked for stable as it is
> > perfectly straight-forward. [ Note that the other, RTT-based, AT91
> > RTC-driver already disables its interrupts at shutdown. ]
> >
> > The more general problem can be triggered, for example, by doing a
> > user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
> > off after a non-clean shutdown.
> >
> > To fix this I propose that arch-code should mask the relevant interrupts
> > before enabling the system interrupt at early boot, and this is what
> > the fifth patch does. To access the RTC-registers I choose to revert a
> > recent patch that moved the register definitions to drivers/rtc.
> >
> > Arguably, the relevant interrupts could also be disabled in bootloaders,
> > but I suggest fixing it in the kernel once and for all.
> >
> > The patches have been tested on at91sam9263 and at91sam9g45 (non-DT),
> > and compile-tested for the other SOCs and DT.
> >
> > Johan
> >
> >
> > v2:
> > - add DT-support
> > - make sys_irq_mask non-mandatory
> >
> >
> > Johan Hovold (5):
> > ARM: at91/rtc: fix boot after RTC wake-up
> > ARM: at91/dts: add RTC nodes
> > ARM: at91/dts: add RTT nodes
> > Revert "arm: at91: move at91rm9200 rtc header in drivers/rtc"
> > ARM: at91: fix hanged boot
>
> --
> --
> You received this message because you are subscribed to "rtc-linux".
> Membership options at http://groups.google.com/group/rtc-linux .
> Please read http://groups.google.com/group/rtc-linux/web/checklist
> before submitting a driver.
> ---
> You received this message because you are subscribed to the Google Groups "rtc-linux" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

2013-04-12 09:34:39

by Johan Hovold

[permalink] [raw]
Subject: Re: [rtc-linux] Re: [PATCH v2 0/5] ARM: at91: fix hanged boot

On Thu, Apr 11, 2013 at 06:54:14PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 17:55 Thu 11 Apr , Johan Hovold wrote:
> > On Mon, Mar 11, 2013 at 07:07:54PM +0100, Johan Hovold wrote:
> > > These patches fix a few severe issues affecting most AT91 SOCs where
> > > boot can hang after a non-general reset, and where the only way to get
> > > the system booting again is to do a general reset -- something which
> > > could require physically removing any backup battery.
> >
> > Have you had time to look at these patches yet, Nicolas?
> >
> > I don't think not having decided on the path forward for DT-support for
> > rtc-at91sam9 needs to be a blocker. The rtt-nodes will be needed in any
> > case.
> >
> > I could respin the series on top of the DT-patch for rtc-at91rm9200, and
> > add interrupt and status-disabled properties to the DT-nodes as well.
> for this this is still a no go
>
> this way too much ugly

I understand that you prefer fixing every bootloader. I was just making
sure everyone agrees that that is the best solution.

The two interrupt masks has to be cleared before the kernel enables the
system interrupt; either it needs to be done by the bootloader or by the
at91 arch code.

The various bootloaders may not know anything about RTT or RTC, but
have all made sure interrupts are disabled before executing the kernel.
That is, they have fulfilled the requirement that interrupts must be
disabled.

So the trade-off seems to be: Either we fix this once and for all using
the infrastructure already in place in the kernel (DT), or risk further
(apparently) bricked systems as there are bound to be bootloaders that
won't get updated.

[...]

> > > The problems stem from the fact that the RTC and RTT-peripherals are
> > > powered by backup power (VDDBU) and are not reset on wake-up, user,
> > > watchdog or software reset. Consequently, RTC and RTT-alarms and their
> > > interrupts may be enabled at boot, leading to a system lock-up when an
> > > interrupt arrives on the shared system-interrupt line before the
> > > appropriate handler (e.g. RTC-driver) has been installed.
> > >
> > > The easiest way to trigger this is to simply wake up from an RTC-alarm
> > > on at91sam9g45. The RTC-driver currently does not disable interrupts at
> > > shutdown so even after a clean shut-down the system will always hang
> > > after waking up.
> > >
> > > The first patch fixes this very general case of RTC-wake up after a
> > > clean shutdown in the RTC-driver and is marked for stable as it is
> > > perfectly straight-forward. [ Note that the other, RTT-based, AT91
> > > RTC-driver already disables its interrupts at shutdown. ]

And what about this patch? If it's decided that every bootloader needs
to be updated, then perhaps it's better to risk bricked systems also
after a clean shutdown to enforce those updates? Should we then remove
the corresponding disable of interrupts at shutdown from the rtc-at91sam9
driver by the same logic?

> > > The more general problem can be triggered, for example, by doing a
> > > user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
> > > off after a non-clean shutdown.
> > >
> > > To fix this I propose that arch-code should mask the relevant interrupts
> > > before enabling the system interrupt at early boot, and this is what
> > > the fifth patch does. To access the RTC-registers I choose to revert a
> > > recent patch that moved the register definitions to drivers/rtc.
> > >
> > > Arguably, the relevant interrupts could also be disabled in bootloaders,
> > > but I suggest fixing it in the kernel once and for all.

Thanks,
Johan

2013-04-12 12:09:34

by Nicolas Ferre

[permalink] [raw]
Subject: Re: [rtc-linux] Re: [PATCH v2 0/5] ARM: at91: fix hanged boot

On 04/12/2013 11:33 AM, Johan Hovold :
> On Thu, Apr 11, 2013 at 06:54:14PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
>> On 17:55 Thu 11 Apr , Johan Hovold wrote:
>>> On Mon, Mar 11, 2013 at 07:07:54PM +0100, Johan Hovold wrote:
>>>> These patches fix a few severe issues affecting most AT91 SOCs where
>>>> boot can hang after a non-general reset, and where the only way to get
>>>> the system booting again is to do a general reset -- something which
>>>> could require physically removing any backup battery.
>>>
>>> Have you had time to look at these patches yet, Nicolas?
>>>
>>> I don't think not having decided on the path forward for DT-support for
>>> rtc-at91sam9 needs to be a blocker. The rtt-nodes will be needed in any
>>> case.
>>>
>>> I could respin the series on top of the DT-patch for rtc-at91rm9200, and
>>> add interrupt and status-disabled properties to the DT-nodes as well.
>> for this this is still a no go
>>
>> this way too much ugly
>
> I understand that you prefer fixing every bootloader. I was just making
> sure everyone agrees that that is the best solution.
>
> The two interrupt masks has to be cleared before the kernel enables the
> system interrupt; either it needs to be done by the bootloader or by the
> at91 arch code.
>
> The various bootloaders may not know anything about RTT or RTC, but
> have all made sure interrupts are disabled before executing the kernel.
> That is, they have fulfilled the requirement that interrupts must be
> disabled.
>
> So the trade-off seems to be: Either we fix this once and for all using
> the infrastructure already in place in the kernel (DT), or risk further
> (apparently) bricked systems as there are bound to be bootloaders that
> won't get updated.

Note that I didn't read your patch series yet, so I am not commenting on
the implementation.

BUT, from my experience with customers facing this issue, I do thing
that we must provide a solution (even in Linux kernel itself).


> [...]
>
>>>> The problems stem from the fact that the RTC and RTT-peripherals are
>>>> powered by backup power (VDDBU) and are not reset on wake-up, user,
>>>> watchdog or software reset. Consequently, RTC and RTT-alarms and their
>>>> interrupts may be enabled at boot, leading to a system lock-up when an
>>>> interrupt arrives on the shared system-interrupt line before the
>>>> appropriate handler (e.g. RTC-driver) has been installed.
>>>>
>>>> The easiest way to trigger this is to simply wake up from an RTC-alarm
>>>> on at91sam9g45. The RTC-driver currently does not disable interrupts at
>>>> shutdown so even after a clean shut-down the system will always hang
>>>> after waking up.
>>>>
>>>> The first patch fixes this very general case of RTC-wake up after a
>>>> clean shutdown in the RTC-driver and is marked for stable as it is
>>>> perfectly straight-forward. [ Note that the other, RTT-based, AT91
>>>> RTC-driver already disables its interrupts at shutdown. ]
>
> And what about this patch? If it's decided that every bootloader needs
> to be updated, then perhaps it's better to risk bricked systems also
> after a clean shutdown to enforce those updates? Should we then remove
> the corresponding disable of interrupts at shutdown from the rtc-at91sam9
> driver by the same logic?
>
>>>> The more general problem can be triggered, for example, by doing a
>>>> user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
>>>> off after a non-clean shutdown.
>>>>
>>>> To fix this I propose that arch-code should mask the relevant interrupts
>>>> before enabling the system interrupt at early boot, and this is what
>>>> the fifth patch does. To access the RTC-registers I choose to revert a
>>>> recent patch that moved the register definitions to drivers/rtc.
>>>>
>>>> Arguably, the relevant interrupts could also be disabled in bootloaders,
>>>> but I suggest fixing it in the kernel once and for all.
>
> Thanks,
> Johan
>
>


--
Nicolas Ferre

2013-10-16 10:00:45

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v3 2/3] 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 <[email protected]>
---
arch/arm/mach-at91/at91sam9260.c | 2 ++
arch/arm/mach-at91/at91sam9261.c | 2 ++
arch/arm/mach-at91/at91sam9263.c | 3 +++
arch/arm/mach-at91/at91sam9g45.c | 1 +
arch/arm/mach-at91/at91sam9rl.c | 1 +
arch/arm/mach-at91/generic.h | 1 +
arch/arm/mach-at91/sysirq_mask.c | 24 ++++++++++++++++++++++++
7 files changed, 34 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 5de6074..ae10d14 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)
arm_pm_idle = at91sam9_idle;
arm_pm_restart = at91sam9_alt_restart;

+ at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
+
/* Register GPIO subsystem */
at91_gpio_init(at91sam9260_gpio, 3);
}
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 0e07932..e761e74 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)
arm_pm_idle = at91sam9_idle;
arm_pm_restart = at91sam9_alt_restart;

+ at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
+
/* Register GPIO subsystem */
at91_gpio_init(at91sam9261_gpio, 3);
}
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 962768b..ad02281 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -330,6 +330,9 @@ static void __init at91sam9263_initialize(void)
arm_pm_idle = at91sam9_idle;
arm_pm_restart = at91sam9_alt_restart;

+ at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
+ at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
+
/* Register GPIO subsystem */
at91_gpio_init(at91sam9263_gpio, 5);
}
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 8d4da6d..88e6f7b 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -380,6 +380,7 @@ static void __init at91sam9g45_initialize(void)
arm_pm_restart = at91sam9g45_restart;

at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
+ at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);

/* Register GPIO subsystem */
at91_gpio_init(at91sam9g45_gpio, 5);
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index b5a8c9d..301e172 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)
arm_pm_restart = at91sam9_alt_restart;

at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
+ at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);

/* Register GPIO subsystem */
at91_gpio_init(at91sam9rl_gpio, 4);
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 80269bd..26dee3c 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,
extern int __init at91_aic5_of_init(struct device_node *node,
struct device_node *parent);
extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
+extern void __init at91_sysirq_mask_rtt(u32 rtt_base);


/* Timer */
diff --git a/arch/arm/mach-at91/sysirq_mask.c b/arch/arm/mach-at91/sysirq_mask.c
index ee3e22c..2ba694f 100644
--- a/arch/arm/mach-at91/sysirq_mask.c
+++ b/arch/arm/mach-at91/sysirq_mask.c
@@ -21,6 +21,7 @@
*/

#include <linux/io.h>
+#include <mach/at91_rtt.h>

#include "generic.h"

@@ -45,3 +46,26 @@ void __init at91_sysirq_mask_rtc(u32 rtc_base)

iounmap(base);
}
+
+void __init at91_sysirq_mask_rtt(u32 rtt_base)
+{
+ void __iomem *base;
+ void __iomem *reg;
+ u32 mode;
+
+ base = ioremap(rtt_base, 16);
+ if (!base)
+ return;
+
+ reg = base + AT91_RTT_MR;
+
+ mode = readl_relaxed(reg);
+ if (mode & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) {
+ pr_info("AT91: Disabling rtt irq\n");
+ mode &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ writel_relaxed(mode, reg);
+ (void)readl_relaxed(reg); /* flush */
+ }
+
+ iounmap(base);
+}
--
1.8.4

2013-10-16 10:00:43

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v3 1/3] 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 <[email protected]>
---
arch/arm/mach-at91/Makefile | 2 +-
arch/arm/mach-at91/at91sam9g45.c | 2 ++
arch/arm/mach-at91/at91sam9n12.c | 6 ++++
arch/arm/mach-at91/at91sam9rl.c | 2 ++
arch/arm/mach-at91/at91sam9x5.c | 6 ++++
arch/arm/mach-at91/generic.h | 1 +
arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 +++
arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 +++
arch/arm/mach-at91/include/mach/sama5d3.h | 5 +++
arch/arm/mach-at91/sama5d3.c | 6 ++++
arch/arm/mach-at91/sysirq_mask.c | 47 +++++++++++++++++++++++++++
11 files changed, 86 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/mach-at91/sysirq_mask.c

diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index aa33b0f..8879a41 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel.
#

-obj-y := irq.o gpio.o setup.o
+obj-y := irq.o gpio.o setup.o sysirq_mask.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index b9fe138..8d4da6d 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -379,6 +379,8 @@ static void __init at91sam9g45_initialize(void)
arm_pm_idle = at91sam9_idle;
arm_pm_restart = at91sam9g45_restart;

+ at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
+
/* Register GPIO subsystem */
at91_gpio_init(at91sam9g45_gpio, 5);
}
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index c7d670d..4d6001c 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)
at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
}

+static void __init at91sam9n12_initialize(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9N12_BASE_RTC);
+}
+
AT91_SOC_START(at91sam9n12)
.map_io = at91sam9n12_map_io,
.register_clocks = at91sam9n12_register_clocks,
+ .init = at91sam9n12_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index d4ec0d9..b5a8c9d 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)
arm_pm_idle = at91sam9_idle;
arm_pm_restart = at91sam9_alt_restart;

+ at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
+
/* Register GPIO subsystem */
at91_gpio_init(at91sam9rl_gpio, 4);
}
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 916e5a1..e8a2e07 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)
at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
}

+static void __init at91sam9x5_initialize(void)
+{
+ at91_sysirq_mask_rtc(AT91SAM9X5_BASE_RTC);
+}
+
/* --------------------------------------------------------------------
* Interrupt initialization
* -------------------------------------------------------------------- */
@@ -329,4 +334,5 @@ static void __init at91sam9x5_map_io(void)
AT91_SOC_START(at91sam9x5)
.map_io = at91sam9x5_map_io,
.register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index dc6e2f5..80269bd 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,
struct device_node *parent);
extern int __init at91_aic5_of_init(struct device_node *node,
struct device_node *parent);
+extern void __init at91_sysirq_mask_rtc(u32 rtc_base);


/* Timer */
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
index d374b87..0151bcf 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9n12.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
@@ -49,6 +49,11 @@
#define AT91SAM9N12_BASE_USART3 0xf8028000

/*
+ * System Peripherals
+ */
+#define AT91SAM9N12_BASE_RTC 0xfffffeb0
+
+/*
* Internal Memory.
*/
#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 c75ee19..2fc76c4 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
@@ -55,6 +55,11 @@
#define AT91SAM9X5_BASE_USART2 0xf8024000

/*
+ * System Peripherals
+ */
+#define AT91SAM9X5_BASE_RTC 0xfffffeb0
+
+/*
* Internal Memory.
*/
#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 31096a8..25613d8 100644
--- a/arch/arm/mach-at91/include/mach/sama5d3.h
+++ b/arch/arm/mach-at91/include/mach/sama5d3.h
@@ -73,6 +73,11 @@
#define SAMA5D3_BASE_USART3 0xf8024000

/*
+ * System Peripherals
+ */
+#define SAMA5D3_BASE_RTC 0xfffffeb0
+
+/*
* Internal Memory
*/
#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 4012797..3ea8642 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)
at91_init_sram(0, SAMA5D3_SRAM_BASE, SAMA5D3_SRAM_SIZE);
}

+static void __init sama5d3_initialize(void)
+{
+ at91_sysirq_mask_rtc(SAMA5D3_BASE_RTC);
+}
+
AT91_SOC_START(sama5d3)
.map_io = sama5d3_map_io,
.register_clocks = sama5d3_register_clocks,
+ .init = sama5d3_initialize,
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 0000000..ee3e22c
--- /dev/null
+++ b/arch/arm/mach-at91/sysirq_mask.c
@@ -0,0 +1,47 @@
+/*
+ * sysirq_mask.c - System-interrupt masking
+ *
+ * Copyright (C) 2013 Johan Hovold <[email protected]>
+ *
+ * Functions to disable system interrupts from backup-powered peripherals.
+ *
+ * The RTC and RTT-peripherals are generally powered by backup power (VDDBU)
+ * and are not reset on wake-up, user, watchdog or software reset. This means
+ * that their interrupts may be enabled during early boot (e.g. after a user
+ * reset).
+ *
+ * As the RTC and RTT share the system-interrupt line with the PIT, an
+ * interrupt occurring before a handler has been installed would lead to the
+ * system interrupt being disabled and prevent the system from booting.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/io.h>
+
+#include "generic.h"
+
+#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
+#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
+
+void __init at91_sysirq_mask_rtc(u32 rtc_base)
+{
+ void __iomem *base;
+ u32 mask;
+
+ base = ioremap(rtc_base, 64);
+ if (!base)
+ return;
+
+ mask = readl_relaxed(base + AT91_RTC_IMR);
+ if (mask) {
+ pr_info("AT91: Disabling rtc irq\n");
+ writel_relaxed(mask, base + AT91_RTC_IDR);
+ (void)readl_relaxed(base + AT91_RTC_IMR); /* flush */
+ }
+
+ iounmap(base);
+}
--
1.8.4

2013-10-16 10:01:11

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v3 0/3] ARM: at91: fix hanged boot

These patches fix a few severe issues affecting most AT91 SOCs where
boot can hang after a non-general reset, and where the only way to get
the system booting again is to do a general reset -- something which
could require physically removing any backup battery.

The problems stem from the fact that the RTC and RTT-peripherals are
powered by backup power (VDDBU) and are not reset on wake-up, user,
watchdog or software reset. Consequently, RTC and RTT-alarms and their
interrupts may be enabled at boot, leading to a system lock-up when an
interrupt arrives on the shared system-interrupt line before the
appropriate handler (e.g. RTC-driver) has been installed.

The easiest way to trigger this is to simply wake up from an RTC-alarm
on at91sam9g45. The RTC-driver currently does not disable interrupts at
shutdown so even after a clean shut-down the system will always hang
after waking up.

The more general problem can be triggered, for example, by doing a
user-reset while updating the RTC-time or if an RTC or RTT-alarm goes
off after a non-clean shutdown.

To fix this I add two helper functions to be called called by arch-code
to mask the relevant interrupts before enabling the system interrupt at
early boot.

The patches have been tested on at91sam9g45 and compile-tested for the
other SOCs.

Johan


v2:
- add DT-support
- make sys_irq_mask non-mandatory

v3
- rebase on v3.12-rc5
- drop DT-support (interrupt masking is needed even if RTC or RTT nodes
are missing)
- drop dedicated SOC-initialiser and call helpers directly from init
- drop revert-patch of move of RTC-register definitions to drivers/ and
copy the two needed definitions instead
- move helper functions from setup.c to a separate file
- add fix for new sama5d3 SOC
- add a register read back to make sure write has reached the devices
- split fix in two patches for RTC and RTT, respectively


Johan Hovold (3):
ARM: at91: fix hanged boot due to early rtc-interrupt
ARM: at91: fix hanged boot due to early rtt-interrupt
ARM: at91/rtc: disable interrupts at shutdown

arch/arm/mach-at91/Makefile | 2 +-
arch/arm/mach-at91/at91sam9260.c | 2 +
arch/arm/mach-at91/at91sam9261.c | 2 +
arch/arm/mach-at91/at91sam9263.c | 3 ++
arch/arm/mach-at91/at91sam9g45.c | 3 ++
arch/arm/mach-at91/at91sam9n12.c | 6 +++
arch/arm/mach-at91/at91sam9rl.c | 3 ++
arch/arm/mach-at91/at91sam9x5.c | 6 +++
arch/arm/mach-at91/generic.h | 2 +
arch/arm/mach-at91/include/mach/at91sam9n12.h | 5 ++
arch/arm/mach-at91/include/mach/at91sam9x5.h | 5 ++
arch/arm/mach-at91/include/mach/sama5d3.h | 5 ++
arch/arm/mach-at91/sama5d3.c | 6 +++
arch/arm/mach-at91/sysirq_mask.c | 71 +++++++++++++++++++++++++++
drivers/rtc/rtc-at91rm9200.c | 9 ++++
15 files changed, 129 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/mach-at91/sysirq_mask.c

--
1.8.4

2013-10-16 10:01:10

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v3 3/3] ARM: at91/rtc: disable interrupts at shutdown

Make sure RTC-interrupts are disabled at shutdown.

As the RTC is generally powered by backup power (VDDBU), its interrupts
are not disabled on wake-up, user, watchdog or software reset. This
could cause troubles on other systems (e.g. older kernels) if an
interrupt occurs before a handler has been installed at next boot.

Let us be well-behaved and disable them on clean shutdowns at least (as
do the RTT-based rtc-at91sam9 driver).

Signed-off-by: Johan Hovold <[email protected]>
---
drivers/rtc/rtc-at91rm9200.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 7418926..ea088e9 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -442,6 +442,14 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
return 0;
}

+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+ /* Disable all interrupts */
+ at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+}
+
#ifdef CONFIG_PM_SLEEP

/* AT91RM9200 RTC Power management control */
@@ -480,6 +488,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);

static struct platform_driver at91_rtc_driver = {
.remove = __exit_p(at91_rtc_remove),
+ .shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
.owner = THIS_MODULE,
--
1.8.4