From patchwork Sat Oct 3 21:54:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harald Geyer X-Patchwork-Id: 526028 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-lb0-x23a.google.com (mail-lb0-x23a.google.com [IPv6:2a00:1450:4010:c04::23a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 862831402B6 for ; Sun, 4 Oct 2015 08:54:40 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.b=S7WNqlS3; dkim-atps=neutral Received: by lbbpc3 with SMTP id pc3sf19495697lbb.0 for ; Sat, 03 Oct 2015 14:54:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20120806; h=mime-version:from:to:cc:subject:date:message-id:x-original-sender :x-original-authentication-results:reply-to:content-type:precedence :mailing-list:list-id:x-spam-checked-in-group:list-post:list-help :list-archive:sender:list-subscribe:list-unsubscribe; bh=Rx+KJB1x0r/FDDeRCMVZed969h8e97FUSTsZnFAKkOM=; b=S7WNqlS34BFVJAGyGqjHzyrhkbGFln0KPfspR7KYCYGnP/AAOoQcNCFvVg9Sww787U HBXcWxlgHCmqrhV918nx0XsMj3pOfwrNDnhgcLTlvu3lb157hIkOp0xRcHPcmVjHPO4C bIOOBfrqeMqcWAiD2KZdsH7Ii04sLKBzCjKKFJRUAn5re9cA+mrqnD6WDTYop8gaPNCc ZNAoRnLR1uArEyKjcjZc3qOLqSxjq9Q1zBoLXyPgnRueklquvJRKuGWEJqFSo9xqkXYK UXYPoYjCkrqp8u1HmBm4GlsrpYH2I1WglRlQU2to2MR8hdOVZFRRUKPXV9VwZhXgDxoH os7A== X-Received: by 10.180.105.98 with SMTP id gl2mr24428wib.8.1443909277641; Sat, 03 Oct 2015 14:54:37 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: rtc-linux@googlegroups.com Received: by 10.180.106.4 with SMTP id gq4ls596991wib.25.gmail; Sat, 03 Oct 2015 14:54:36 -0700 (PDT) X-Received: by 10.180.210.212 with SMTP id mw20mr1051983wic.3.1443909276931; Sat, 03 Oct 2015 14:54:36 -0700 (PDT) Received: from mail.cosmopool.net (mail.cosmopool.net. [2a01:4f8:160:20c1::10:107]) by gmr-mx.google.com with ESMTP id ch7si151108wib.2.2015.10.03.14.54.36 for ; Sat, 03 Oct 2015 14:54:36 -0700 (PDT) Received-SPF: neutral (google.com: 2a01:4f8:160:20c1::10:107 is neither permitted nor denied by best guess record for domain of harald@ccbib.org) client-ip=2a01:4f8:160:20c1::10:107; Received: from localhost (localhost [127.0.0.1]) by mail.cosmopool.net (Postfix) with ESMTP id 720F190909F; Sat, 3 Oct 2015 23:54:36 +0200 (CEST) Received: from mail.cosmopool.net ([127.0.0.1]) by localhost (mail.your-server.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id B45hqGwNo1kG; Sat, 3 Oct 2015 23:54:35 +0200 (CEST) Received: from huygens.ccbib.org (unknown [10.0.10.106]) by mail.cosmopool.net (Postfix) with SMTP id 84433902445; Sat, 3 Oct 2015 23:54:34 +0200 (CEST) Received: by huygens.ccbib.org (sSMTP sendmail emulation); Sat, 03 Oct 2015 21:54:34 +0000 From: Harald Geyer To: Alessandro Zummo , Alexandre Belloni , Wim Van Sebroeck Cc: rtc-linux@googlegroups.com, linux-watchdog@vger.kernel.org, kernel@pengutronix.de, Wolfram Sang , Fabio Estevam , Harald Geyer Subject: [rtc-linux] [PATCHv2] watchdog: stmp3xxx: Implement GETBOOTSTATUS Date: Sat, 3 Oct 2015 21:54:18 +0000 Message-Id: <1443909258-24914-1-git-send-email-harald@ccbib.org> X-Mailer: git-send-email 1.7.10.4 X-Original-Sender: harald@ccbib.org X-Original-Authentication-Results: gmr-mx.google.com; spf=neutral (google.com: 2a01:4f8:160:20c1::10:107 is neither permitted nor denied by best guess record for domain of harald@ccbib.org) smtp.mailfrom=harald@ccbib.org Reply-To: rtc-linux@googlegroups.com Precedence: list Mailing-list: list rtc-linux@googlegroups.com; contact rtc-linux+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: rtc-linux@googlegroups.com X-Google-Group-Id: 712029733259 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , When the watchdog is enabled, we set a persitent bit. After booting we query the bit and see if the system was reset by the watchdog. This is somewhat similar to what the legacy driver from freescale does. However we use STMP3XXX_RTC_PERSISTENT2 instead of STMP3XXX_RTC_PERSISTENT1. I tried that first, but it seems I can't clear the bit there once it is set. I didn't find any documentation what this register does - only vague hints that it is meant to control the boot ROM. Part of the code from the legacy driver touching this register is still included. Maybe this is stale, but this patch doesn't touch any of it because I don't know what it really does or is meant to do. Signed-off-by: Harald Geyer --- Changes since v1: * make code formatting more consistent with the rest of the driver * Cc some people who might have better documentation then I do Changes since initially posting this patch on 08/04/2015: * fix a spelling error in the commit message * rebase to a recent version drivers/rtc/rtc-stmp3xxx.c | 23 +++++++++++++++++++++++ drivers/watchdog/stmp3xxx_rtc_wdt.c | 34 +++++++++++++++++++++++++++++++++- include/linux/stmp3xxx_rtc_wdt.h | 2 ++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index ca54d03..4ab0aeb 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -30,6 +30,7 @@ #include #include #include +#include #define STMP3XXX_RTC_CTRL 0x0 #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 @@ -62,6 +63,9 @@ /* missing bitmask in headers */ #define STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER 0x80000000 +#define STMP3XXX_RTC_PERSISTENT2 0x80 +#define STMP3XXX_RTC_PERSISTENT2_WDT_ACTIVE 0x00000001 + struct stmp3xxx_rtc_data { struct rtc_device *rtc; void __iomem *io; @@ -83,6 +87,14 @@ struct stmp3xxx_rtc_data { * registers is atomic. */ +static void stmp3xxx_wdt_clear_bootstatus(struct device *dev) +{ + struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); + + writel(STMP3XXX_RTC_PERSISTENT2_WDT_ACTIVE, + rtc_data->io + STMP3XXX_RTC_PERSISTENT2 + STMP_OFFSET_REG_CLR); +} + static void stmp3xxx_wdt_set_timeout(struct device *dev, u32 timeout) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); @@ -93,16 +105,22 @@ static void stmp3xxx_wdt_set_timeout(struct device *dev, u32 timeout) rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_SET); writel(STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER, rtc_data->io + STMP3XXX_RTC_PERSISTENT1 + STMP_OFFSET_REG_SET); + writel(STMP3XXX_RTC_PERSISTENT2_WDT_ACTIVE, + rtc_data->io + STMP3XXX_RTC_PERSISTENT2 + STMP_OFFSET_REG_SET); } else { writel(STMP3XXX_RTC_CTRL_WATCHDOGEN, rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); writel(STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER, rtc_data->io + STMP3XXX_RTC_PERSISTENT1 + STMP_OFFSET_REG_CLR); + writel(STMP3XXX_RTC_PERSISTENT2_WDT_ACTIVE, + rtc_data->io + STMP3XXX_RTC_PERSISTENT2 + STMP_OFFSET_REG_CLR); } } static struct stmp3xxx_wdt_pdata wdt_pdata = { .wdt_set_timeout = stmp3xxx_wdt_set_timeout, + .wdt_clear_bootstatus = stmp3xxx_wdt_clear_bootstatus, + .bootstatus = 0, }; static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev) @@ -110,6 +128,8 @@ static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev) struct platform_device *wdt_pdev = platform_device_alloc("stmp3xxx_rtc_wdt", rtc_pdev->id); + stmp3xxx_wdt_clear_bootstatus(&rtc_pdev->dev); + if (wdt_pdev) { wdt_pdev->dev.parent = &rtc_pdev->dev; wdt_pdev->dev.platform_data = &wdt_pdata; @@ -357,6 +377,9 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) return err; } + if (readl(STMP3XXX_RTC_PERSISTENT2 + rtc_data->io) & + STMP3XXX_RTC_PERSISTENT2_WDT_ACTIVE) + wdt_pdata.bootstatus |= WDIOF_CARDRESET; stmp3xxx_wdt_register(pdev); return 0; } diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c index 3ee6128..7609f78 100644 --- a/drivers/watchdog/stmp3xxx_rtc_wdt.c +++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #define WDOG_TICK_RATE 1000 /* 1 kHz clock */ #define STMP3XXX_DEFAULT_TIMEOUT 19 @@ -50,7 +52,8 @@ static int wdt_set_timeout(struct watchdog_device *wdd, unsigned new_timeout) } static const struct watchdog_info stmp3xxx_wdt_ident = { - .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_CARDRESET, .identity = "STMP3XXX RTC Watchdog", }; @@ -69,14 +72,39 @@ static struct watchdog_device stmp3xxx_wdd = { .status = WATCHDOG_NOWAYOUT_INIT_STATUS, }; +static int wdt_notify_sys(struct notifier_block *nb, unsigned long code, + void *unused) +{ + struct device *dev = watchdog_get_drvdata(&stmp3xxx_wdd); + struct stmp3xxx_wdt_pdata *pdata = dev_get_platdata(dev); + + switch (code) { + case SYS_DOWN: /* keep enabled, system might crash while going down */ + pdata->wdt_clear_bootstatus(dev->parent); + break; + case SYS_HALT: /* allow the system to actually halt */ + case SYS_POWER_OFF: + wdt_stop(&stmp3xxx_wdd); + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block wdt_notifier = { + .notifier_call = wdt_notify_sys, +}; + static int stmp3xxx_wdt_probe(struct platform_device *pdev) { + struct stmp3xxx_wdt_pdata *pdata = dev_get_platdata(&pdev->dev); int ret; watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev); stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT); stmp3xxx_wdd.parent = &pdev->dev; + stmp3xxx_wdd.bootstatus = pdata->bootstatus; ret = watchdog_register_device(&stmp3xxx_wdd); if (ret < 0) { @@ -84,6 +112,9 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev) return ret; } + if (register_reboot_notifier(&wdt_notifier)) + dev_warn(&pdev->dev, "cannot register reboot notifier\n"); + dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n", stmp3xxx_wdd.timeout); return 0; @@ -91,6 +122,7 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev) static int stmp3xxx_wdt_remove(struct platform_device *pdev) { + unregister_reboot_notifier(&wdt_notifier); watchdog_unregister_device(&stmp3xxx_wdd); return 0; } diff --git a/include/linux/stmp3xxx_rtc_wdt.h b/include/linux/stmp3xxx_rtc_wdt.h index 1dd12c9..62dd9e6 100644 --- a/include/linux/stmp3xxx_rtc_wdt.h +++ b/include/linux/stmp3xxx_rtc_wdt.h @@ -10,6 +10,8 @@ struct stmp3xxx_wdt_pdata { void (*wdt_set_timeout)(struct device *dev, u32 timeout); + void (*wdt_clear_bootstatus)(struct device *dev); + unsigned int bootstatus; }; #endif /* __LINUX_STMP3XXX_RTC_WDT_H */