Message ID | 1362747103-21445-4-git-send-email-jhovold@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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 <jhovold@gmail.com> > --- > 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 rtc-linux+unsubscribe@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > >
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 <jhovold@gmail.com> > > --- > > 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
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 <jhovold@gmail.com> > > > --- > > > 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.
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 <jhovold@gmail.com> > > > > --- > > > > 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
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
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
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 rtc-linux+unsubscribe@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > >
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
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 > >
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
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); };
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 <jhovold@gmail.com> --- 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(+)