summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill McVicker <willmcvicker@google.com>2022-04-14 12:45:43 -0700
committerWill McVicker <willmcvicker@google.com>2022-04-14 12:45:43 -0700
commitddc3c28349674f70ab7c20cae4a17e10a4ac6abb (patch)
treebdb7a4643d15cf4a8672343b936ba1e5152816c7
parentf9b3d860c4153ad3b8d6b715ddf6fae1c544daff (diff)
parentbf4c58df75b256a697d5e0a08124baa620357f13 (diff)
downloadreset-ddc3c28349674f70ab7c20cae4a17e10a4ac6abb.tar.gz
Merge 'android13-gs-pixel-5.10' into android-gs-pixel-mainline
* 'android13-gs-pixel-5.10' of sso://partner-android/kernel/private/google-modules/power/reset: power: reset: remove all unused changes power: reset: add shutdown method power: reset: gs101: raise restart_handler priority power: reset: support psci sys reset and poweroff power: reset: raise restart_handler priority Kleaf: add power_reset kernel module for cloudripper power: reset: add in_panic and in_warm for swreset power: reset: add in_panic for swreset power: reset: add in_panic and in_warm for swreset power: reset: support emergency_restart swreset power: reset: support emergency_restart swreset power: reset: support emergency_restart swreset power: reset: gs201: support PS_HOLD cold reboot power: reset: gs201: fix power key detection power: reset: gs201: fix power_off function power: reset: use warm reboot by swreset power: reset: remove dead code power: reset: exynos-reboot: Initialize gs201 reset driver. power:reset:exynos-reboot: fix reboot reasons power: reset: exynos-reboot: coding style fixes power: reset: exynos-reboot: Add shutdown-thermal, rescue, fastboot power: reset: exynos-reboot: add dm-verity reboot reason power: reset: handle all of known reboot command messages Signed-off-by: Will McVicker <willmcvicker@google.com> Change-Id: Ib8c612a71544256228c17a1142ad1fee8ad5df13
-rw-r--r--BUILD.bazel30
-rw-r--r--Kbuild3
-rw-r--r--Kconfig2
-rw-r--r--exynos-gs101-reboot.c (renamed from exynos-reboot.c)139
-rw-r--r--exynos-gs201-reboot.c220
5 files changed, 325 insertions, 69 deletions
diff --git a/BUILD.bazel b/BUILD.bazel
new file mode 100644
index 0000000..3c29912
--- /dev/null
+++ b/BUILD.bazel
@@ -0,0 +1,30 @@
+# NOTE: THIS FILE IS EXPERIMENTAL FOR THE BAZEL MIGRATION AND NOT USED FOR
+# YOUR BUILDS CURRENTLY.
+#
+# It is not yet the source of truth for your build. If you're looking to modify
+# the build file, modify the Android.bp file instead. Do *not* modify this file
+# unless you have coordinated with the team managing the Soong to Bazel
+# migration.
+
+load("//build/kleaf:kernel.bzl", "kernel_module")
+
+kernel_module(
+ name = "reset.cloudripper",
+ srcs = glob([
+ "**/*.c",
+ "**/*.h",
+ "Kbuild",
+ ]) + [
+ "//private/google-modules/bms:headers",
+ ],
+ outs = [
+ "exynos-reboot.ko",
+ ],
+ kernel_build = "//private/gs-google:cloudripper",
+ kernel_module_deps = [
+ "//private/google-modules/bms:bms.cloudripper",
+ ],
+ visibility = [
+ "//private/gs-google:__pkg__",
+ ],
+)
diff --git a/Kbuild b/Kbuild
index 50a7688..3191986 100644
--- a/Kbuild
+++ b/Kbuild
@@ -1 +1,4 @@
+exynos-reboot-$(CONFIG_SOC_GS101) += exynos-gs101-reboot.o
+exynos-reboot-$(CONFIG_SOC_GS201) += exynos-gs201-reboot.o
+
obj-$(CONFIG_POWER_RESET_EXYNOS) += exynos-reboot.o
diff --git a/Kconfig b/Kconfig
index df5c74e..1bc5122 100644
--- a/Kconfig
+++ b/Kconfig
@@ -1,5 +1,5 @@
config POWER_RESET_EXYNOS
» tristate "Samsung Exynos power-off driver"
-» depends on SOC_GS101
+» depends on SOC_GS101 || SOC_GS201
» help
» Reboot support for Samsung Exynos boards.
diff --git a/exynos-reboot.c b/exynos-gs101-reboot.c
index c52dfcd..12de215 100644
--- a/exynos-reboot.c
+++ b/exynos-gs101-reboot.c
@@ -26,11 +26,11 @@
#endif
#include <soc/google/exynos-el3_mon.h>
#include <soc/google/debug-snapshot.h>
-/* TODO: temporary workaround. must remove. see b/169128860 */
-#include <linux/soc/samsung/exynos-smc.h>
#include "../../bms/google_bms.h"
-#define BMS_RSBM_VALID BIT(31)
+#define EXYNOS_PMU_SYSIP_DAT0 (0x0810)
+
+#define BMS_RSBM_VALID BIT(31)
static struct regmap *pmureg;
static u32 warm_reboot_offset, warm_reboot_trigger;
@@ -40,13 +40,26 @@ static u32 shutdown_offset, shutdown_trigger;
static phys_addr_t pmu_alive_base;
static bool rsbm_supported;
+enum pon_reboot_mode {
+ REBOOT_MODE_NORMAL = 0x00,
+ REBOOT_MODE_CHARGE = 0x0A,
+
+ REBOOT_MODE_DMVERITY_CORRUPTED = 0x50,
+ REBOOT_MODE_SHUTDOWN_THERMAL = 0x51,
+
+ REBOOT_MODE_RESCUE = 0xF9,
+ REBOOT_MODE_FASTBOOT = 0xFA,
+ REBOOT_MODE_BOOTLOADER = 0xFC,
+ REBOOT_MODE_FACTORY = 0xFD,
+ REBOOT_MODE_RECOVERY = 0xFF,
+};
+
static void exynos_power_off(void)
{
u32 poweroff_try = 0;
int power_gpio = -1;
unsigned int keycode = 0;
struct device_node *np, *pp;
- int ret;
np = of_find_node_by_path("/gpio_keys");
if (!np)
@@ -57,7 +70,7 @@ static void exynos_power_off(void)
continue;
of_property_read_u32(pp, "linux,code", &keycode);
if (keycode == KEY_POWER) {
- pr_info("%s: <%u>\n", __func__, keycode);
+ pr_info("%s: <%u>\n", __func__, keycode);
power_gpio = of_get_gpio(pp, 0);
break;
}
@@ -77,16 +90,9 @@ static void exynos_power_off(void)
exynos_acpm_reboot();
#endif
pr_emerg("Set PS_HOLD Low.\n");
- ret = rmw_priv_reg(pmu_alive_base + shutdown_offset,
- shutdown_trigger, 0);
- /* TODO: remove following fallback. see b/169128860 */
- if (ret)
- regmap_update_bits(pmureg, shutdown_offset,
- shutdown_trigger, 0);
-
+ rmw_priv_reg(pmu_alive_base + shutdown_offset, shutdown_trigger, 0);
++poweroff_try;
- pr_emerg("Should not reach here! (poweroff_try:%d)\n",
- poweroff_try);
+ pr_emerg("Should not reach here! (poweroff_try:%d)\n", poweroff_try);
} else {
/*
* if power button is not released,
@@ -98,66 +104,67 @@ static void exynos_power_off(void)
}
}
-#define EXYNOS_PMU_SYSIP_DAT0 (0x0810)
-#define REBOOT_MODE_NORMAL (0x00)
-#define REBOOT_MODE_CHARGE (0x0A)
-#define REBOOT_MODE_FASTBOOT (0xFC)
-#define REBOOT_MODE_FACTORY (0xFD)
-#define REBOOT_MODE_RECOVERY (0xFF)
-
static void exynos_reboot_mode_set(u32 val)
{
int ret;
u32 reboot_mode;
phys_addr_t reboot_cmd_addr = pmu_alive_base + reboot_cmd_offset;
- ret = set_priv_reg(reboot_cmd_addr, val);
- /* TODO: remove following fallback. see b/169128860 */
- if (ret) {
- pr_info("%s(): failed to set addr %pap via set_priv_reg, using regmap\n",
- __func__, &reboot_cmd_addr);
- regmap_write(pmureg, reboot_cmd_offset, val);
- }
+ set_priv_reg(reboot_cmd_addr, val);
if (s2mpg10_get_rev_id() > S2MPG10_EVT0 && rsbm_supported) {
reboot_mode = val | BMS_RSBM_VALID;
ret = gbms_storage_write(GBMS_TAG_RSBM, &reboot_mode, sizeof(reboot_mode));
if (ret < 0)
pr_err("%s(): failed to write gbms storage: %d(%d)\n", __func__,
- GBMS_TAG_RSBM, ret);
+ GBMS_TAG_RSBM, ret);
}
}
static void exynos_reboot_parse(const char *cmd)
{
if (cmd) {
+ u32 value = U32_MAX;
+
pr_info("Reboot command: '%s'\n", cmd);
- if (!strcmp(cmd, "charge")) {
- exynos_reboot_mode_set(REBOOT_MODE_CHARGE);
- } else if (!strcmp(cmd, "bootloader") ||
- !strcmp(cmd, "fastboot") ||
- !strcmp(cmd, "bl") ||
- !strcmp(cmd, "fb")) {
- exynos_reboot_mode_set(REBOOT_MODE_FASTBOOT);
- } else if (!strcmp(cmd, "recovery")) {
- exynos_reboot_mode_set(REBOOT_MODE_RECOVERY);
- } else {
+ if (!strcmp(cmd, "charge"))
+ value = REBOOT_MODE_CHARGE;
+ else if (!strcmp(cmd, "bootloader"))
+ value = REBOOT_MODE_BOOTLOADER;
+ else if (!strcmp(cmd, "fastboot"))
+ value = REBOOT_MODE_FASTBOOT;
+ else if (!strcmp(cmd, "recovery"))
+ value = REBOOT_MODE_RECOVERY;
+ else if (!strcmp(cmd, "dm-verity device corrupted"))
+ value = REBOOT_MODE_DMVERITY_CORRUPTED;
+ else if (!strcmp(cmd, "rescue"))
+ value = REBOOT_MODE_RESCUE;
+ else if (!strcmp(cmd, "shutdown-thermal"))
+ value = REBOOT_MODE_SHUTDOWN_THERMAL;
+ else if (!strcmp(cmd, "from_fastboot") ||
+ !strcmp(cmd, "shell") ||
+ !strcmp(cmd, "userrequested") ||
+ !strcmp(cmd, "userrequested,fastboot") ||
+ !strcmp(cmd, "userrequested,recovery") ||
+ !strcmp(cmd, "userrequested,recovery,ui"))
+ value = REBOOT_MODE_NORMAL;
+ else
pr_err("Unknown reboot command: '%s'\n", cmd);
- }
+
+ if (value != U32_MAX)
+ exynos_reboot_mode_set(value);
}
}
-static int exynos_reboot_handler(struct notifier_block *nb,
- unsigned long mode, void *cmd)
+static int exynos_reboot_handler(struct notifier_block *nb, unsigned long mode, void *cmd)
{
u32 data;
int ret;
ret = gbms_storage_read(GBMS_TAG_RSBM, &data, sizeof(data));
if (ret < 0)
- pr_err("%s(): failed to read gbms storage: %d(%d)\n", __func__,
- GBMS_TAG_RSBM, ret);
+ pr_err("%s(): failed to read gbms storage: %d(%d)\n", __func__, GBMS_TAG_RSBM, ret);
rsbm_supported = ret != -ENOENT;
@@ -173,7 +180,6 @@ static struct notifier_block exynos_reboot_nb = {
static int exynos_restart_handler(struct notifier_block *this, unsigned long mode, void *cmd)
{
- int ret;
#if IS_ENABLED(CONFIG_GS_ACPM)
exynos_acpm_reboot();
#endif
@@ -182,13 +188,9 @@ static int exynos_restart_handler(struct notifier_block *this, unsigned long mod
pr_emerg("%s: Exynos SoC reset right now\n", __func__);
if (s2mpg10_get_rev_id() == S2MPG10_EVT0 ||
- !rsbm_supported ||
- dbg_snapshot_get_panic_status()) {
- ret = set_priv_reg(pmu_alive_base + warm_reboot_offset, warm_reboot_trigger);
-
- /* TODO: this is a temporary workaround. must remove. see b/169128860 */
- if (ret == SMC_CMD_PRIV_REG || ret == -EINVAL)
- regmap_write(pmureg, warm_reboot_offset, warm_reboot_trigger);
+ !rsbm_supported || !dbg_snapshot_get_reboot_status() ||
+ dbg_snapshot_get_panic_status() || dbg_snapshot_get_warm_status()) {
+ set_priv_reg(pmu_alive_base + warm_reboot_offset, warm_reboot_trigger);
} else {
pr_emerg("Set PS_HOLD Low.\n");
mdelay(2);
@@ -203,7 +205,7 @@ static int exynos_restart_handler(struct notifier_block *this, unsigned long mod
static struct notifier_block exynos_restart_nb = {
.notifier_call = exynos_restart_handler,
- .priority = 128,
+ .priority = 130,
};
static int exynos_reboot_probe(struct platform_device *pdev)
@@ -234,49 +236,50 @@ static int exynos_reboot_probe(struct platform_device *pdev)
pmu_alive_base = res.start;
if (of_property_read_u32(np, "swreset-system-offset", &warm_reboot_offset) < 0) {
- pr_err("failed to find swreset-system-offset property\n");
+ dev_err(dev, "failed to find swreset-system-offset property\n");
return -EINVAL;
}
if (of_property_read_u32(np, "swreset-system-trigger", &warm_reboot_trigger) < 0) {
- pr_err("failed to find swreset-system-trigger property\n");
+ dev_err(dev, "failed to find swreset-system-trigger property\n");
return -EINVAL;
}
if (of_property_read_u32(np, "pshold-control-offset", &cold_reboot_offset) < 0) {
- pr_err("failed to find pshold-control-offset property\n");
+ dev_err(dev, "failed to find pshold-control-offset property\n");
return -EINVAL;
}
- if (of_property_read_u32(np, "pshold-control-trigger",
- &cold_reboot_trigger) < 0) {
- pr_err("failed to find shutdown-trigger property\n");
+ if (of_property_read_u32(np, "pshold-control-trigger", &cold_reboot_trigger) < 0) {
+ dev_err(dev, "failed to find shutdown-trigger property\n");
return -EINVAL;
}
shutdown_offset = cold_reboot_offset;
shutdown_trigger = cold_reboot_trigger;
- if (of_property_read_u32(np, "reboot-cmd-offset",
- &reboot_cmd_offset) < 0) {
- pr_info("failed to find reboot-offset property, using default\n");
+ if (of_property_read_u32(np, "reboot-cmd-offset", &reboot_cmd_offset) < 0) {
+ dev_info(dev, "failed to find reboot-offset property, using default\n");
reboot_cmd_offset = EXYNOS_PMU_SYSIP_DAT0;
}
err = register_reboot_notifier(&exynos_reboot_nb);
- if (err)
+ if (err) {
dev_err(dev, "cannot register reboot handler (err=%d)\n", err);
+ return err;
+ }
err = register_restart_handler(&exynos_restart_nb);
- if (err)
+ if (err) {
dev_err(dev, "cannot register restart handler (err=%d)\n", err);
+ unregister_reboot_notifier(&exynos_reboot_nb);
+ return err;
+ }
pm_power_off = exynos_power_off;
+ dev_info(dev, "register restart handler successfully\n");
- if (!err)
- dev_info(dev, "register restart handler successfully\n");
-
- return err;
+ return 0;
}
static const struct of_device_id exynos_reboot_of_match[] = {
diff --git a/exynos-gs201-reboot.c b/exynos-gs201-reboot.c
new file mode 100644
index 0000000..af9c948
--- /dev/null
+++ b/exynos-gs201-reboot.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * exynos-reboot.c - Samsung Exynos SoC reset code
+ *
+ * Copyright (c) 2019-2021 Samsung Electronics Co., Ltd.
+ *
+ * Author: Hyunki Koo <hyunki00.koo@samsung.com>
+ * Youngmin Nam <youngmin.nam@samsung.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/samsung/s2mpg12.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#if IS_ENABLED(CONFIG_GS_ACPM)
+#include <soc/google/acpm_ipc_ctrl.h>
+#endif
+#include <soc/google/exynos-el3_mon.h>
+#include "../../bms/google_bms.h"
+
+#define EXYNOS_PMU_SYSIP_DAT0 (0x0810)
+
+#define BMS_RSBM_VALID BIT(31)
+
+static u32 reboot_cmd_offset;
+static phys_addr_t pmu_alive_base;
+
+enum pon_reboot_mode {
+ REBOOT_MODE_NORMAL = 0x00,
+ REBOOT_MODE_CHARGE = 0x0A,
+
+ REBOOT_MODE_DMVERITY_CORRUPTED = 0x50,
+ REBOOT_MODE_SHUTDOWN_THERMAL = 0x51,
+
+ REBOOT_MODE_RESCUE = 0xF9,
+ REBOOT_MODE_FASTBOOT = 0xFA,
+ REBOOT_MODE_BOOTLOADER = 0xFC,
+ REBOOT_MODE_FACTORY = 0xFD,
+ REBOOT_MODE_RECOVERY = 0xFF,
+};
+
+static void exynos_reboot_mode_set(u32 val)
+{
+ int ret;
+ phys_addr_t reboot_cmd_addr = pmu_alive_base + reboot_cmd_offset;
+ u32 reboot_mode;
+
+ ret = set_priv_reg(reboot_cmd_addr, val);
+ if (ret) {
+ pr_info("%s(): failed to set addr %pap via set_priv_reg, using regmap\n",
+ __func__, &reboot_cmd_addr);
+ }
+
+ reboot_mode = val | BMS_RSBM_VALID;
+ ret = gbms_storage_write(GBMS_TAG_RSBM, &reboot_mode, sizeof(reboot_mode));
+ if (ret < 0)
+ pr_err("%s(): failed to write gbms storage: %d(%d)\n", __func__,
+ GBMS_TAG_RSBM, ret);
+}
+
+static void exynos_reboot_parse(const char *cmd)
+{
+ if (cmd) {
+ u32 value = U32_MAX;
+
+ pr_info("Reboot command: '%s'\n", cmd);
+
+ if (!strcmp(cmd, "charge"))
+ value = REBOOT_MODE_CHARGE;
+ else if (!strcmp(cmd, "bootloader"))
+ value = REBOOT_MODE_BOOTLOADER;
+ else if (!strcmp(cmd, "fastboot"))
+ value = REBOOT_MODE_FASTBOOT;
+ else if (!strcmp(cmd, "recovery"))
+ value = REBOOT_MODE_RECOVERY;
+ else if (!strcmp(cmd, "dm-verity device corrupted"))
+ value = REBOOT_MODE_DMVERITY_CORRUPTED;
+ else if (!strcmp(cmd, "rescue"))
+ value = REBOOT_MODE_RESCUE;
+ else if (!strcmp(cmd, "shutdown-thermal"))
+ value = REBOOT_MODE_SHUTDOWN_THERMAL;
+ else if (!strcmp(cmd, "from_fastboot") ||
+ !strcmp(cmd, "shell") ||
+ !strcmp(cmd, "userrequested") ||
+ !strcmp(cmd, "userrequested,fastboot") ||
+ !strcmp(cmd, "userrequested,recovery") ||
+ !strcmp(cmd, "userrequested,recovery,ui"))
+ value = REBOOT_MODE_NORMAL;
+ else
+ pr_err("Unknown reboot command: '%s'\n", cmd);
+
+ if (value != U32_MAX)
+ exynos_reboot_mode_set(value);
+ }
+}
+
+static int exynos_reboot_handler(struct notifier_block *nb, unsigned long mode, void *cmd)
+{
+ exynos_reboot_parse(cmd);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block exynos_reboot_nb = {
+ .notifier_call = exynos_reboot_handler,
+ .priority = INT_MAX,
+};
+
+static int exynos_restart_handler(struct notifier_block *this, unsigned long mode, void *cmd)
+{
+#if IS_ENABLED(CONFIG_GS_ACPM)
+ acpm_prepare_reboot();
+#endif
+
+ pr_info("ready to do restart.\n");
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block exynos_restart_nb = {
+ .notifier_call = exynos_restart_handler,
+ .priority = 130,
+};
+
+static void exynos_power_off(struct platform_device *pdev)
+{
+ while (1) {
+ /* wait for power button release */
+ if (!pmic_read_pwrkey_status()) {
+#if IS_ENABLED(CONFIG_GS_ACPM)
+ acpm_prepare_reboot();
+#endif
+ pr_info("ready to do power off.\n");
+ break;
+ } else {
+ /*
+ * if power button is not released,
+ * wait and check TA again
+ */
+ pr_info("PWR Key is not released.\n");
+ }
+ mdelay(1000);
+ }
+}
+
+static int exynos_reboot_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct regmap *pmureg;
+ struct device_node *syscon_np;
+ struct resource res;
+ int err;
+
+ pmureg = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(pmureg)) {
+ dev_err(dev, "Fail to get regmap of PMU\n");
+ return PTR_ERR(pmureg);
+ }
+
+ syscon_np = of_parse_phandle(np, "syscon", 0);
+ if (!syscon_np) {
+ dev_err(dev, "syscon device node not found\n");
+ return -EINVAL;
+ }
+
+ if (of_address_to_resource(syscon_np, 0, &res)) {
+ dev_err(dev, "failed to get syscon base address\n");
+ return -ENOMEM;
+ }
+
+ pmu_alive_base = res.start;
+
+ if (of_property_read_u32(np, "reboot-cmd-offset", &reboot_cmd_offset) < 0) {
+ dev_info(dev, "failed to find reboot-offset property, using default\n");
+ reboot_cmd_offset = EXYNOS_PMU_SYSIP_DAT0;
+ }
+
+ err = register_reboot_notifier(&exynos_reboot_nb);
+ if (err) {
+ dev_err(dev, "cannot register reboot handler (err=%d)\n", err);
+ return err;
+ }
+
+ err = register_restart_handler(&exynos_restart_nb);
+ if (err) {
+ dev_err(dev, "cannot register restart handler (err=%d)\n", err);
+ unregister_reboot_notifier(&exynos_reboot_nb);
+ return err;
+ }
+
+ dev_info(dev, "register restart handler successfully\n");
+
+ return 0;
+}
+
+static const struct of_device_id exynos_reboot_of_match[] = {
+ { .compatible = "samsung,exynos-reboot" },
+ {}
+};
+
+static struct platform_driver exynos_reboot_driver = {
+ .probe = exynos_reboot_probe,
+ .shutdown = exynos_power_off,
+ .driver = {
+ .name = "exynos-reboot",
+ .of_match_table = exynos_reboot_of_match,
+ },
+};
+module_platform_driver(exynos_reboot_driver);
+
+MODULE_DESCRIPTION("Exynos Reboot driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:exynos-reboot");