From patchwork Tue Dec 8 21:29:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 57910 Delivered-To: patches@linaro.org Received: by 10.112.147.194 with SMTP id tm2csp285447lbb; Tue, 8 Dec 2015 13:29:29 -0800 (PST) X-Received: by 10.98.9.194 with SMTP id 63mr8140330pfj.30.1449610169252; Tue, 08 Dec 2015 13:29:29 -0800 (PST) Return-Path: Received: from mail-pf0-x22c.google.com (mail-pf0-x22c.google.com. [2607:f8b0:400e:c00::22c]) by mx.google.com with ESMTPS id wy9si7536416pab.27.2015.12.08.13.29.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 08 Dec 2015 13:29:29 -0800 (PST) Received-SPF: pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::22c as permitted sender) client-ip=2607:f8b0:400e:c00::22c; Authentication-Results: mx.google.com; spf=pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::22c as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dkim=pass header.i=@linaro-org.20150623.gappssmtp.com Received: by pfdd184 with SMTP id d184so18059662pfd.3 for ; Tue, 08 Dec 2015 13:29:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=6+QH0QuyLBzjoOIupntgleawH/0L/oAXn1aYVcMurck=; b=KK/4stSGq8pU2uaEir5Hzmud7hIUpd1kbUm8oC4QDBJK3yAZpdNzn2Dqd4AljHUDYK pY5R3nZKLhTVfvdtKkFkY+MnmqvT1iFeVliyWLItIsHYPGMkkS3c0te+SNil1AJE0Ypl QA2zOOS7f3hlfeGFEFC3jhPBTXk2g9EmkMg5w0vMRHoSdJX2ZcB0wlOFhcbasWnQ/6ZN lvgJFIXF5AZ0Ms023U8Xa31XQvahvAkwLXkmpDc496SCQMt1DSbqKAkTgb35BwcTb8Az 2UN285aqSZq0qPkbdZ72qRsmGb48WOHhZIwZBFBuKyAVnNZtWvexWRr8BM9XR17GI5uF X/Pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=6+QH0QuyLBzjoOIupntgleawH/0L/oAXn1aYVcMurck=; b=T/T2/+j1fMQ3sjY0vwT423VEunJg2ala/GZMxn4MxyDf+D/sq7mMEOxI8S6KYE93FT x/tdQqSwXtd5R208trHkspKuVEfqUtpIAH2oh9Np1c68jZ5nTssL9ashbynv8VE4Jvzc XdVRyro170QdZugcQN9WiGEQ9JGXKpu/CS4S15xIJuKKScCBQM1dKCeUkhpVtc+YKPnQ +ZdypOnBNO6pDHpBWIe2xYXnQPKwE9UG4xSz8KgXx3JRatdGo85t3x03Gq1yi1UHj/9t P3HYHaOVFxu1aFklwQV/zeR52UGUXgWa0j+h6d0xqY89WWD+e8LZTeIahqmrlOVcV8T3 yLlQ== X-Gm-Message-State: ALoCoQnfRNLiqGuz9YxG7vdyjI9eUCFJwCgInrOnJV6AaoNqomfTJ/oGlyP+y1JDjwkU2GjO28SAQ+fuIv1lhHKcVQXim+/TuQ== X-Received: by 10.98.86.210 with SMTP id h79mr8079468pfj.87.1449610168809; Tue, 08 Dec 2015 13:29:28 -0800 (PST) Return-Path: Received: from localhost.localdomain (c-76-115-103-22.hsd1.or.comcast.net. [76.115.103.22]) by smtp.gmail.com with ESMTPSA id ix2sm6854654pac.15.2015.12.08.13.29.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 08 Dec 2015 13:29:28 -0800 (PST) From: John Stultz To: lkml Cc: John Stultz , Rob Herring , Pawel Moll , Mark Rutland , Ian Campbell , Kumar Gala , Vinay Simha BN , Bjorn Andersson , Haojian Zhuang , devicetree@vger.kernel.org, Android Kernel Team Subject: [RFC][PATCH] misc: Introduce reboot_reason driver Date: Tue, 8 Dec 2015 13:29:22 -0800 Message-Id: <1449610162-30543-1-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.9.1 This patch adds a basic driver to allow for commands like "reboot bootloader" and "reboot recovery" to communicate this reboot-reason to the bootloader. This is commonly done on Android devices, in order to reboot the device into fastboot or recovery mode. It also supports custom OEM specific commands, via "reboot oem-". This driver pulls the phys memory address from DT as well as the magic reason values that are written to the address for each mode. For an example, this patch also adds the DT support for the nexus7 device via its dts (which is not yet upstream). Thoughts and feedback would be appreciated! Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: Vinay Simha BN Cc: Bjorn Andersson Cc: Haojian Zhuang Cc: devicetree@vger.kernel.org Cc: Android Kernel Team Signed-off-by: John Stultz --- arch/arm/boot/dts/qcom-apq8064-nexus7-flo.dts | 9 ++ drivers/misc/Kconfig | 8 ++ drivers/misc/Makefile | 1 + drivers/misc/reboot_reason.c | 117 ++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 drivers/misc/reboot_reason.c -- 1.9.1 diff --git a/arch/arm/boot/dts/qcom-apq8064-nexus7-flo.dts b/arch/arm/boot/dts/qcom-apq8064-nexus7-flo.dts index 5183d18..ee5dcb7 100644 --- a/arch/arm/boot/dts/qcom-apq8064-nexus7-flo.dts +++ b/arch/arm/boot/dts/qcom-apq8064-nexus7-flo.dts @@ -282,6 +282,15 @@ }; }; + reboot_reason: reboot_reason@2a03f65c { + compatible = "reboot_reason"; + reg = <0x2A03F65C 0x4>; + reason,none = <0x77665501>; + reason,bootloader = <0x77665500>; + reason,recovery = <0x77665502>; + reason,oem = <0x6f656d00>; + }; + gpio-keys { compatible = "gpio-keys"; power { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 22892c7..b5c141b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -525,6 +525,14 @@ config VEXPRESS_SYSCFG bus. System Configuration interface is one of the possible means of generating transactions on this bus. +config REBOOT_REASON + bool "Pass reboot reason to bootloader" + default n + help + On many systems there is a desire to provide a reboot reason to + the bootloader, so that the bootloader can boot into a desired + mode on the next boot. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 537d7f3..4581e62 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ +obj-$(CONFIG_REBOOT_REASON) += reboot_reason.o diff --git a/drivers/misc/reboot_reason.c b/drivers/misc/reboot_reason.c new file mode 100644 index 0000000..5c9b55eb --- /dev/null +++ b/drivers/misc/reboot_reason.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Types of reasons */ +static enum { + NONE, + BOOTLOADER, + RECOVERY, + OEM, + MAX_REASONS +} __maybe_unused reason_types; + +static u32 reasons[MAX_REASONS]; +static void __iomem *reboot_reason_addr; +static struct notifier_block restart_nb; + +static int reboot_reason(struct notifier_block *nb, unsigned long action, + void *data) +{ + char *cmd = (char *)data; + long reason = reasons[NONE]; + + if (!reboot_reason_addr) + return NOTIFY_DONE; + + if (cmd != NULL) { + if (!strncmp(cmd, "bootloader", 10)) + reason = reasons[BOOTLOADER]; + else if (!strncmp(cmd, "recovery", 8)) + reason = reasons[RECOVERY]; + else if (!strncmp(cmd, "oem-", 4)) { + unsigned long code; + + if (!kstrtoul(cmd+4, 0, &code)) + reason = reasons[OEM] | (code & 0xff); + } + } + + if (reason != -1) + writel(reason, reboot_reason_addr); + return NOTIFY_DONE; +} + +static int reboot_reason_probe(struct platform_device *pdev) +{ + struct resource *res; + u32 val; + int i; + + /* initialize the reasons */ + for (i = 0; i < MAX_REASONS; i++) + reasons[i] = -1; + + /* Try to grab the reason io address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reboot_reason_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reboot_reason_addr)) + return PTR_ERR(reboot_reason_addr); + + /* initialize specified reasons from DT */ + if (!of_property_read_u32(pdev->dev.of_node, "reason,none", &val)) + reasons[NONE] = val; + if (!of_property_read_u32(pdev->dev.of_node, "reason,bootloader", &val)) + reasons[BOOTLOADER] = val; + if (!of_property_read_u32(pdev->dev.of_node, "reason,recovery", &val)) + reasons[RECOVERY] = val; + if (!of_property_read_u32(pdev->dev.of_node, "reason,oem", &val)) + reasons[OEM] = val; + + /* Install the notifier */ + restart_nb.notifier_call = reboot_reason; + restart_nb.priority = 256; + if (register_restart_handler(&restart_nb)) { + dev_err(&pdev->dev, + "failed to setup restart handler.\n"); + } + return 0; +} + +int reboot_reason_remove(struct platform_device *pdev) +{ + unregister_restart_handler(&restart_nb); + return 0; +} + +static const struct of_device_id reboot_reason_of_match[] = { + { .compatible = "reboot_reason", }, + { }, +}; + +static struct platform_driver reboot_reason_driver = { + .driver = { + .name = "reboot_reason", + .of_match_table = reboot_reason_of_match, + }, + .probe = reboot_reason_probe, + .remove = reboot_reason_remove, +}; + +static int __init reboot_reason_init(void) +{ + return platform_driver_register(&reboot_reason_driver); +} +arch_initcall(reboot_reason_init); + +static void __exit reboot_reason_exit(void) +{ + platform_driver_unregister(&reboot_reason_driver); +} +module_exit(reboot_reason_exit);