diff options
author | Will McVicker <willmcvicker@google.com> | 2022-04-14 12:45:43 -0700 |
---|---|---|
committer | Will McVicker <willmcvicker@google.com> | 2022-04-14 12:45:43 -0700 |
commit | ddc3c28349674f70ab7c20cae4a17e10a4ac6abb (patch) | |
tree | bdb7a4643d15cf4a8672343b936ba1e5152816c7 | |
parent | f9b3d860c4153ad3b8d6b715ddf6fae1c544daff (diff) | |
parent | bf4c58df75b256a697d5e0a08124baa620357f13 (diff) | |
download | reset-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.bazel | 30 | ||||
-rw-r--r-- | Kbuild | 3 | ||||
-rw-r--r-- | Kconfig | 2 | ||||
-rw-r--r-- | exynos-gs101-reboot.c (renamed from exynos-reboot.c) | 139 | ||||
-rw-r--r-- | exynos-gs201-reboot.c | 220 |
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__", + ], +) @@ -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 @@ -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"); |