From d2e521397e8b9f67afc04fece92f6e65361e1184 Mon Sep 17 00:00:00 2001 From: Huang Yiwei Date: Wed, 6 Apr 2022 21:15:03 +0800 Subject: [PATCH] soc: qcom: Add snapshot of reboot reason driver This is a snapshot of the reboot reason driver as of msm-5.15 commit <908a517b050d> ("Merge "sched/walt: remove duplicate definitions of rt_task_arrival_time""). Change-Id: I7cf898ac8d4232d1e00a58f97091ebc2e52fcb5b Signed-off-by: Huang Yiwei --- drivers/power/reset/Kconfig | 9 ++ drivers/power/reset/Makefile | 1 + drivers/power/reset/qcom-reboot-reason.c | 111 +++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 drivers/power/reset/qcom-reboot-reason.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 4b563db3ab3e..bef35bdfbba6 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -134,6 +134,15 @@ config POWER_RESET_QCOM_PON power-on and reboot reason, Say Y. If unsure, Say N. +config POWER_RESET_QCOM_REBOOT_REASON + tristate "MSM reboot mode driver" + depends on ARCH_QCOM + help + Support for setting reboot reason on MSM boards. + This feature supports commands such as "reboot bootloader" + to boot the MSM board to fastboot mode. + If unsure, say Y. + config POWER_RESET_OCELOT_RESET bool "Microsemi Ocelot reset driver" depends on MSCC_OCELOT || ARCH_SPARX5 || COMPILE_TEST diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index f606a2f60539..8e632799abb5 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o +obj-$(CONFIG_POWER_RESET_QCOM_REBOOT_REASON) += qcom-reboot-reason.o obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o diff --git a/drivers/power/reset/qcom-reboot-reason.c b/drivers/power/reset/qcom-reboot-reason.c new file mode 100644 index 000000000000..be5a2ed6c4f3 --- /dev/null +++ b/drivers/power/reset/qcom-reboot-reason.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct qcom_reboot_reason { + struct device *dev; + struct notifier_block reboot_nb; + struct nvmem_cell *nvmem_cell; +}; + +struct poweroff_reason { + const char *cmd; + unsigned char pon_reason; +}; + +static struct poweroff_reason reasons[] = { + { "recovery", 0x01 }, + { "bootloader", 0x02 }, + { "rtc", 0x03 }, + { "dm-verity device corrupted", 0x04 }, + { "dm-verity enforcing", 0x05 }, + { "keys clear", 0x06 }, + {} +}; + +static int qcom_reboot_reason_reboot(struct notifier_block *this, + unsigned long event, void *ptr) +{ + char *cmd = ptr; + struct qcom_reboot_reason *reboot = container_of(this, + struct qcom_reboot_reason, reboot_nb); + struct poweroff_reason *reason; + + if (!cmd) + return NOTIFY_OK; + for (reason = reasons; reason->cmd; reason++) { + if (!strcmp(cmd, reason->cmd)) { + nvmem_cell_write(reboot->nvmem_cell, + &reason->pon_reason, + sizeof(reason->pon_reason)); + break; + } + } + + return NOTIFY_OK; +} + +static int qcom_reboot_reason_probe(struct platform_device *pdev) +{ + struct qcom_reboot_reason *reboot; + + reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL); + if (!reboot) + return -ENOMEM; + + reboot->dev = &pdev->dev; + + reboot->nvmem_cell = nvmem_cell_get(reboot->dev, "restart_reason"); + + if (IS_ERR(reboot->nvmem_cell)) + return PTR_ERR(reboot->nvmem_cell); + + reboot->reboot_nb.notifier_call = qcom_reboot_reason_reboot; + reboot->reboot_nb.priority = 255; + register_reboot_notifier(&reboot->reboot_nb); + + platform_set_drvdata(pdev, reboot); + + return 0; +} + +static int qcom_reboot_reason_remove(struct platform_device *pdev) +{ + struct qcom_reboot_reason *reboot = platform_get_drvdata(pdev); + + unregister_reboot_notifier(&reboot->reboot_nb); + + return 0; +} + +static const struct of_device_id of_qcom_reboot_reason_match[] = { + { .compatible = "qcom,reboot-reason", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_qcom_reboot_reason_match); + +static struct platform_driver qcom_reboot_reason_driver = { + .probe = qcom_reboot_reason_probe, + .remove = qcom_reboot_reason_remove, + .driver = { + .name = "qcom-reboot-reason", + .of_match_table = of_match_ptr(of_qcom_reboot_reason_match), + }, +}; + +module_platform_driver(qcom_reboot_reason_driver); + +MODULE_DESCRIPTION("MSM Reboot Reason Driver"); +MODULE_LICENSE("GPL v2");