diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 8db5b7286ac3..bce171e05685 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2021 XiaoMi, Inc. */ #include @@ -60,8 +61,8 @@ static struct nvmem_cell *nvmem_cell; static int download_mode = 1; static struct kobject dload_kobj; -static int in_panic; -static int dload_type = SCM_DLOAD_FULLDUMP; +static int in_panic = 0; +static int dload_type = SCM_DLOAD_BOTHDUMPS; static void *dload_mode_addr; static bool dload_mode_enabled; static void *emergency_dload_mode_addr; @@ -431,7 +432,10 @@ static void msm_restart_prepare(const char *cmd) else qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); - if (cmd != NULL) { + if (in_panic) { + reason = PON_RESTART_REASON_PANIC; + } + else if (cmd != NULL) { if (!strncmp(cmd, "bootloader", 10)) { reason = PON_RESTART_REASON_BOOTLOADER; __raw_writel(0x77665500, restart_reason); @@ -461,15 +465,19 @@ static void msm_restart_prepare(const char *cmd) } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); } else { + reason = PON_RESTART_REASON_NORMAL; __raw_writel(0x77665501, restart_reason); } - if (reason && nvmem_cell) - nvmem_cell_write(nvmem_cell, &reason, sizeof(reason)); - else - qpnp_pon_set_restart_reason( - (enum pon_restart_reason)reason); + } else { + reason = PON_RESTART_REASON_NORMAL; + __raw_writel(0x77665501, restart_reason); } + if (reason && nvmem_cell) + nvmem_cell_write(nvmem_cell, &reason, sizeof(reason)); + else + qpnp_pon_set_restart_reason( + (enum pon_restart_reason)reason); /*outer_flush_all is not supported by 64bit kernel*/ #ifndef CONFIG_ARM64 diff --git a/drivers/power/reset/qcom-dload-mode.c b/drivers/power/reset/qcom-dload-mode.c index ec181d36f373..24aeeb02e9bb 100644 --- a/drivers/power/reset/qcom-dload-mode.c +++ b/drivers/power/reset/qcom-dload-mode.c @@ -38,7 +38,7 @@ struct qcom_dload { static bool enable_dump = IS_ENABLED(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT); static enum qcom_download_mode current_download_mode = QCOM_DOWNLOAD_NODUMP; -static enum qcom_download_mode dump_mode = QCOM_DOWNLOAD_FULLDUMP; +static enum qcom_download_mode dump_mode = QCOM_DOWNLOAD_BOTHDUMP; static bool early_pcie_init_enable; static int set_download_mode(enum qcom_download_mode mode) @@ -328,6 +328,26 @@ static void check_pci_edl(struct device_node *np) iounmap(mem); } +#define DISPLAY_CONFIG_OFFSET_PROP "qcom,msm-imem-display_config_offset" +/* + ** set display config imem first 4 bytes to 0xdead4ead, because imem context + ** will not lost when warm reset. if panic, xbl ramdump will display orange + ** screen, and framebuffer addr is determined by these four bytes in + ** MDP_GetDisplayBootConfig function. so set these four bytes to a invalid + ** value and let the framebuffer of orange screen use + ** RAMDUMP_FRAME_BUFFER_ADDRESS(0xE1000000) + **/ +static void clear_display_config(void) +{ + void *display_config_imem_addr = map_prop_mem(DISPLAY_CONFIG_OFFSET_PROP); + + if (display_config_imem_addr) { + __raw_writel(0xdead4ead, display_config_imem_addr); + iounmap(display_config_imem_addr); + pr_err("%s clear display config\n", __func__); + } +} + static int qcom_dload_probe(struct platform_device *pdev) { struct qcom_dload *poweroff; @@ -358,6 +378,7 @@ static int qcom_dload_probe(struct platform_device *pdev) poweroff->dload_dest_addr = map_prop_mem("qcom,msm-imem-dload-type"); store_kaslr_offset(); check_pci_edl(pdev->dev.of_node); + clear_display_config(); msm_enable_dump_mode(enable_dump); if (!enable_dump) diff --git a/drivers/power/reset/qcom-reboot-reason.c b/drivers/power/reset/qcom-reboot-reason.c index 483e974121fc..46af8461222c 100644 --- a/drivers/power/reset/qcom-reboot-reason.c +++ b/drivers/power/reset/qcom-reboot-reason.c @@ -17,6 +17,8 @@ struct qcom_reboot_reason { struct device *dev; struct notifier_block reboot_nb; + struct notifier_block panic_nb; + struct notifier_block restart_nb; struct nvmem_cell *nvmem_cell; }; @@ -32,9 +34,19 @@ static struct poweroff_reason reasons[] = { { "dm-verity device corrupted", 0x04 }, { "dm-verity enforcing", 0x05 }, { "keys clear", 0x06 }, + { "panic", 0x21 }, + { NULL, 0x20 }, {} }; +static struct poweroff_reason restart_reasons[] = { + { "lp_kthread", 0x28 }, + { NULL, 0x00 }, //end loop flag, not reset reason +}; + +#define RESTART_REASON_PANIC 6 +#define RESTART_REASON_NORMAL 7 + static int qcom_reboot_reason_reboot(struct notifier_block *this, unsigned long event, void *ptr) { @@ -43,20 +55,67 @@ static int qcom_reboot_reason_reboot(struct notifier_block *this, struct qcom_reboot_reason, reboot_nb); struct poweroff_reason *reason; - if (!cmd) + if (!cmd) { + nvmem_cell_write(reboot->nvmem_cell, + &reasons[RESTART_REASON_NORMAL].pon_reason, + sizeof(reasons[RESTART_REASON_NORMAL].pon_reason)); 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; + } + } + nvmem_cell_write(reboot->nvmem_cell, + &reason->pon_reason, + sizeof(reason->pon_reason)); + return NOTIFY_OK; +} + +/* + * this function only used in restart chain for limited reset reasons + * eg: long press power key kthread, because it cannot trigger + * reboot chain to set reset reason +*/ +static int qcom_restart_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, restart_nb); + struct poweroff_reason *reason; + + if (!cmd) { + return NOTIFY_OK; + } + for (reason = restart_reasons; reason->cmd; reason++) { + if (!strcmp(cmd, reason->cmd)) { + nvmem_cell_write(reboot->nvmem_cell, + &reason->pon_reason, + sizeof(reason->pon_reason)); + pr_info("restart reason: %s\n", cmd); + return NOTIFY_OK; } } return NOTIFY_OK; } + +static int panic_prep_restart(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct qcom_reboot_reason *reboot = container_of(this, + struct qcom_reboot_reason, panic_nb); + nvmem_cell_write(reboot->nvmem_cell, + &reasons[RESTART_REASON_PANIC].pon_reason, + sizeof(reasons[RESTART_REASON_PANIC].pon_reason)); + return NOTIFY_DONE; +} + static int qcom_reboot_reason_probe(struct platform_device *pdev) { struct qcom_reboot_reason *reboot; @@ -78,6 +137,15 @@ static int qcom_reboot_reason_probe(struct platform_device *pdev) platform_set_drvdata(pdev, reboot); + reboot->panic_nb.notifier_call = panic_prep_restart; + reboot->panic_nb.priority = INT_MAX; + atomic_notifier_chain_register(&panic_notifier_list, &reboot->panic_nb); + + /*register restart chain for set restart reason*/ + reboot->restart_nb.notifier_call = qcom_restart_reason_reboot; + reboot->restart_nb.priority = 200; + register_restart_handler(&reboot->restart_nb); + return 0; } @@ -85,8 +153,9 @@ static int qcom_reboot_reason_remove(struct platform_device *pdev) { struct qcom_reboot_reason *reboot = platform_get_drvdata(pdev); + atomic_notifier_chain_unregister(&panic_notifier_list, &reboot->panic_nb); unregister_reboot_notifier(&reboot->reboot_nb); - + unregister_restart_handler(&reboot->restart_nb); return 0; } diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index 5e4f39ac9298..491c9e257f10 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. + * Copyright (C) 2021 XiaoMi, Inc. * All rights reserved. */ @@ -55,6 +56,8 @@ enum pon_restart_reason { PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x04, PON_RESTART_REASON_DMVERITY_ENFORCE = 0x05, PON_RESTART_REASON_KEYS_CLEAR = 0x06, + PON_RESTART_REASON_NORMAL = 0x20, + PON_RESTART_REASON_PANIC = 0x21, }; #if IS_ENABLED(CONFIG_INPUT_QPNP_POWER_ON) @@ -106,4 +109,9 @@ static inline int qpnp_pon_modem_pwr_off(enum pon_power_off_type type) #endif +#ifdef CONFIG_MTD_BLOCK2MTD +extern struct Scsi_Host *g_shost; +extern void machine_restart(char *cmd); +#endif + #endif