From patchwork Mon Mar 11 18:07:59 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johan Hovold X-Patchwork-Id: 2249801 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id EE4D63FCF6 for ; Mon, 11 Mar 2013 18:16:25 +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 1UF7D9-0007se-3v; Mon, 11 Mar 2013 18:12:35 +0000 Received: from mail-lb0-f181.google.com ([209.85.217.181]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UF7Bz-0007Zc-Gm for linux-arm-kernel@lists.infradead.org; Mon, 11 Mar 2013 18:11:29 +0000 Received: by mail-lb0-f181.google.com with SMTP id gm6so3384103lbb.12 for ; Mon, 11 Mar 2013 11:11:21 -0700 (PDT) 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=U0r7GFriCf59COu/ZnA7yzRKQGGNVwx2xsdLRYhvlS0=; b=zwdFlzTg/EX28oW9mI/+ZrUKEAwOZ27BMM/+JEegzLcKvJeOLRbg3fSIsaAt41as/N zyS38cHBKHrVgnefjOWgUAR2OqwXPZ1hzsiq1llhYGvXgZl29YbEbFW4YU/1AMB5tk62 ynFHLWZVP0yAJUs6sf67rzUHNv/AQzoZTFOtX1Z0Lxsh2uJ8xLuG/bEDFEFoBttZhh2d o5KXcs68imPUr5TiC4euwvn1Q6ymiRnbmlwEo97O0VGyuBj6+VwJGefrHf6mUUhCkCX7 ZAiWivUCp8aCfd+BgtXntRc6is53Yonln/1B0VXdmHxhOq/mqK8Y3l9sGX2T0iNZRiUL CNIQ== X-Received: by 10.112.28.101 with SMTP id a5mr5023317lbh.0.1363025481010; Mon, 11 Mar 2013 11:11:21 -0700 (PDT) Received: from omicron.terra (c83-179-13-247.cust.tele2.se. [83.179.13.247]) by mx.google.com with ESMTPS id ng6sm7685209lab.2.2013.03.11.11.11.18 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 11 Mar 2013 11:11:19 -0700 (PDT) Received: from johan by omicron.terra with local (Exim 4.80.1) (envelope-from ) id 1UF7B7-0004dI-RR; Mon, 11 Mar 2013 19:10:29 +0100 From: Johan Hovold To: Nicolas Ferre Subject: [PATCH v2 5/5] ARM: at91: fix hanged boot Date: Mon, 11 Mar 2013 19:07:59 +0100 Message-Id: <1363025279-17615-6-git-send-email-jhovold@gmail.com> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1363025279-17615-1-git-send-email-jhovold@gmail.com> References: <20130311180611.GF8797@localhost> <1363025279-17615-1-git-send-email-jhovold@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130311_141124_002395_3010E2C8 X-CRM114-Status: GOOD ( 21.18 ) 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.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (jhovold[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.217.181 listed in list.dnswl.org] -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/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 #include #include +#include +#include #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); };