From patchwork Fri Mar 8 12:51:43 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johan Hovold X-Patchwork-Id: 2237831 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 0F703DF215 for ; Fri, 8 Mar 2013 12:58:47 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UDwoT-0006qD-40; Fri, 08 Mar 2013 12:54:17 +0000 Received: from mail-lb0-f174.google.com ([209.85.217.174]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UDwoH-0006mo-Fj for linux-arm-kernel@lists.infradead.org; Fri, 08 Mar 2013 12:54:07 +0000 Received: by mail-lb0-f174.google.com with SMTP id l12so1289119lbo.5 for ; Fri, 08 Mar 2013 04:54:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=MqZ+HGjQi3YUR12SlOeRKaXv4+WOVOt2xj3ivRtfUqU=; b=0Khee3FtZyDB3Tga335PQ1nAczVV0mMM4XCr8B3fSDn9rcETkbaF0uRqN7ZJfIkutM IRuTKE/RpZEVywlizvmRoW8XtjSLyesAZ2zDyLUzH87uxV8LaDqnXKATH4C4lWrku9CC /FcACahr9L43L5/dc2UUfrRmSecC2MOxTWI4EBh83cyMN/NYTo6d7Lxx+pM1H3WNO8Kp gyUmj8aeUe/oRzZUtOuu2a3qXhpXoZes2mldo9+vvonvpJcDU4W4Azx6iCdN+5jD0Q0o dbrnjfZr91jm3k+j/rUdLXsttUo/0vICbk/f0yh5r8Q7s7L4oziHby/wp5QgRVdTJogL EHhA== X-Received: by 10.112.29.1 with SMTP id f1mr1052291lbh.30.1362747242366; Fri, 08 Mar 2013 04:54:02 -0800 (PST) Received: from omicron.terra (c83-179-13-247.cust.tele2.se. [83.179.13.247]) by mx.google.com with ESMTPS id iq6sm2523500lab.10.2013.03.08.04.53.59 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 08 Mar 2013 04:54:00 -0800 (PST) Received: from johan by omicron.terra with local (Exim 4.80.1) (envelope-from ) id 1UDwnP-0005bx-08; Fri, 08 Mar 2013 13:53:11 +0100 From: Johan Hovold To: Nicolas Ferre Subject: [PATCH 3/3] ARM: at91: fix hanged boot Date: Fri, 8 Mar 2013 13:51:43 +0100 Message-Id: <1362747103-21445-4-git-send-email-jhovold@gmail.com> X-Mailer: git-send-email 1.8.1.1 In-Reply-To: <1362747103-21445-1-git-send-email-jhovold@gmail.com> References: <1362747103-21445-1-git-send-email-jhovold@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130308_075405_880304_08EF7A8B X-CRM114-Status: GOOD ( 21.98 ) X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.217.174 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (jhovold[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Alessandro Zummo , rtc-linux@googlegroups.com, Johan Hovold , linux-kernel@vger.kernel.org, Jean-Christophe Plagniol-Villard , Andrew Victor , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 --- 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 #include #include +#include +#include #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); };