From 0f582756169c899fc1cbf5e33b84654f34dbe806 Mon Sep 17 00:00:00 2001 From: Lijuan Gao Date: Tue, 29 Dec 2015 11:41:15 +0800 Subject: [PATCH 1/4] power: reset: Disable SDI when dload mode is disabled Add function to auto disable the SDI when the ramdump is disabled. And make the device do hard reset at the same time. Change-Id: I14e2d13792ef535364a082cdaed0b79c262ecfe5 Signed-off-by: Lijuan Gao --- drivers/power/reset/msm-poweroff.c | 72 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 75a0de0c532b..d41ead1780dc 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -52,6 +52,13 @@ static bool scm_deassert_ps_hold_supported; /* Download mode master kill-switch */ static void __iomem *msm_ps_hold; static phys_addr_t tcsr_boot_misc_detect; +static void scm_disable_sdi(void); + +/* Runtime could be only changed value once. + * There is no API from TZ to re-enable the registers. + * So the SDI cannot be re-enabled when it already by-passed. +*/ +static int download_mode = 1; #ifdef CONFIG_QCOM_DLOAD_MODE #define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode" @@ -64,7 +71,6 @@ static void *emergency_dload_mode_addr; static bool scm_dload_supported; static int dload_set(const char *val, struct kernel_param *kp); -static int download_mode = 1; module_param_call(download_mode, dload_set, param_get_int, &download_mode, 0644); static int panic_prep_restart(struct notifier_block *this, @@ -116,6 +122,9 @@ static void set_dload_mode(int on) if (ret) pr_err("Failed to set secure DLOAD mode: %d\n", ret); + if (!on) + scm_disable_sdi(); + dload_mode_enabled = on; } @@ -170,7 +179,10 @@ static int dload_set(const char *val, struct kernel_param *kp) return 0; } #else -#define set_dload_mode(x) do {} while (0) +static void set_dload_mode(int on) +{ + scm_disable_sdi(); +} static void enable_emergency_dload_mode(void) { @@ -183,6 +195,26 @@ static bool get_dload_mode(void) } #endif +static void scm_disable_sdi(void) +{ + int ret; + struct scm_desc desc = { + .args[0] = 1, + .args[1] = 0, + .arginfo = SCM_ARGS(2), + }; + + /* Needed to bypass debug image on some chips */ + if (!is_scm_armv8()) + ret = scm_call_atomic2(SCM_SVC_BOOT, + SCM_WDOG_DEBUG_BOOT_PART, 1, 0); + else + ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, + SCM_WDOG_DEBUG_BOOT_PART), &desc); + if (ret) + pr_err("Failed to disable secure wdog debug: %d\n", ret); +} + void msm_set_restart_mode(int mode) { restart_mode = mode; @@ -320,13 +352,6 @@ static void deassert_ps_hold(void) static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) { - int ret; - struct scm_desc desc = { - .args[0] = 1, - .args[1] = 0, - .arginfo = SCM_ARGS(2), - }; - pr_notice("Going down for restart now\n"); msm_restart_prepare(cmd); @@ -341,16 +366,6 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) msm_trigger_wdog_bite(); #endif - /* Needed to bypass debug image on some chips */ - if (!is_scm_armv8()) - ret = scm_call_atomic2(SCM_SVC_BOOT, - SCM_WDOG_DEBUG_BOOT_PART, 1, 0); - else - ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, - SCM_WDOG_DEBUG_BOOT_PART), &desc); - if (ret) - pr_err("Failed to disable secure wdog debug: %d\n", ret); - halt_spmi_pmic_arbiter(); deassert_ps_hold(); @@ -359,27 +374,10 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) static void do_msm_poweroff(void) { - int ret; - struct scm_desc desc = { - .args[0] = 1, - .args[1] = 0, - .arginfo = SCM_ARGS(2), - }; - pr_notice("Powering off the SoC\n"); -#ifdef CONFIG_QCOM_DLOAD_MODE + set_dload_mode(0); -#endif qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN); - /* Needed to bypass debug image on some chips */ - if (!is_scm_armv8()) - ret = scm_call_atomic2(SCM_SVC_BOOT, - SCM_WDOG_DEBUG_BOOT_PART, 1, 0); - else - ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, - SCM_WDOG_DEBUG_BOOT_PART), &desc); - if (ret) - pr_err("Failed to disable wdog debug: %d\n", ret); halt_spmi_pmic_arbiter(); deassert_ps_hold(); From c6727963e159ca04a456661c15a7cbb22f6c2a6a Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Tue, 29 Dec 2015 19:29:59 +0530 Subject: [PATCH 2/4] power: reset: Add support for EMMC dload Add sysfs entry to support emmc dload mode. Adds /sys/kernel/reset/emmc_dload entry to enable or disable emmc dload mode support. Change-Id: If38135427304316b03d3193ad16d335605e9c143 Signed-off-by: Prasad Sodagudi --- .../devicetree/bindings/arm/msm/imem.txt | 6 + drivers/power/reset/msm-poweroff.c | 122 +++++++++++++++++- 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt index d1f8ce1e5ac8..a9d2a2456cfd 100644 --- a/Documentation/devicetree/bindings/arm/msm/imem.txt +++ b/Documentation/devicetree/bindings/arm/msm/imem.txt @@ -46,6 +46,12 @@ Required properties: -compatible: "qcom,msm-imem-restart_reason -reg: start address and size of restart_reason region in imem +Download Mode Type: +------------------- +Required properties: +-compatible: "qcom,msm-imem-dload-type" +-reg: start address and size of dload type region in imem + Download Mode: -------------- Required properties: diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index d41ead1780dc..8a045d3c5059 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -36,6 +36,7 @@ #define EMERGENCY_DLOAD_MAGIC1 0x322A4F99 #define EMERGENCY_DLOAD_MAGIC2 0xC67E4350 #define EMERGENCY_DLOAD_MAGIC3 0x77777777 +#define EMMC_DLOAD_TYPE 0x2 #define SCM_IO_DISABLE_PMIC_ARBITER 1 #define SCM_IO_DEASSERT_PS_HOLD 2 @@ -46,7 +47,7 @@ static int restart_mode; -void *restart_reason; +static void *restart_reason, *dload_type_addr; static bool scm_pmic_arbiter_disable_supported; static bool scm_deassert_ps_hold_supported; /* Download mode master kill-switch */ @@ -59,6 +60,7 @@ static void scm_disable_sdi(void); * So the SDI cannot be re-enabled when it already by-passed. */ static int download_mode = 1; +static struct kobject dload_kobj; #ifdef CONFIG_QCOM_DLOAD_MODE #define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode" @@ -71,8 +73,23 @@ static void *emergency_dload_mode_addr; static bool scm_dload_supported; static int dload_set(const char *val, struct kernel_param *kp); +/* interface for exporting attributes */ +struct reset_attribute { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, struct attribute *attr, + char *buf); + size_t (*store)(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count); +}; +#define to_reset_attr(_attr) \ + container_of(_attr, struct reset_attribute, attr) +#define RESET_ATTR(_name, _mode, _show, _store) \ + static struct reset_attribute reset_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + module_param_call(download_mode, dload_set, param_get_int, &download_mode, 0644); + static int panic_prep_restart(struct notifier_block *this, unsigned long event, void *ptr) { @@ -387,6 +404,84 @@ static void do_msm_poweroff(void) return; } +static ssize_t attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct reset_attribute *reset_attr = to_reset_attr(attr); + ssize_t ret = -EIO; + + if (reset_attr->show) + ret = reset_attr->show(kobj, attr, buf); + + return ret; +} + +static ssize_t attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct reset_attribute *reset_attr = to_reset_attr(attr); + ssize_t ret = -EIO; + + if (reset_attr->store) + ret = reset_attr->store(kobj, attr, buf, count); + + return ret; +} + +static const struct sysfs_ops reset_sysfs_ops = { + .show = attr_show, + .store = attr_store, +}; + +static struct kobj_type reset_ktype = { + .sysfs_ops = &reset_sysfs_ops, +}; + +static ssize_t show_emmc_dload(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + uint32_t read_val, show_val; + + read_val = __raw_readl(dload_type_addr); + if (read_val == EMMC_DLOAD_TYPE) + show_val = 1; + else + show_val = 0; + + return snprintf(buf, sizeof(show_val), "%u\n", show_val); +} + +static size_t store_emmc_dload(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + uint32_t enabled; + int ret; + + ret = kstrtouint(buf, 0, &enabled); + if (ret < 0) + return ret; + + if (!((enabled == 0) || (enabled == 1))) + return -EINVAL; + + if (enabled == 1) + __raw_writel(EMMC_DLOAD_TYPE, dload_type_addr); + else + __raw_writel(0, dload_type_addr); + + return count; +} +RESET_ATTR(emmc_dload, 0644, show_emmc_dload, store_emmc_dload); + +static struct attribute *reset_attrs[] = { + &reset_attr_emmc_dload.attr, + NULL +}; + +static struct attribute_group reset_attr_group = { + .attrs = reset_attrs, +}; + static int msm_restart_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -417,6 +512,31 @@ static int msm_restart_probe(struct platform_device *pdev) pr_err("unable to map imem EDLOAD mode offset\n"); } + np = of_find_compatible_node(NULL, NULL, + "qcom,msm-imem-dload-type"); + if (!np) { + pr_err("unable to find DT imem dload-type node\n"); + } else { + dload_type_addr = of_iomap(np, 0); + if (!dload_type_addr) { + pr_err("unable to map imem dload-type offset\n"); + goto skip_sysfs_create; + } + } + + ret = kobject_init_and_add(&dload_kobj, &reset_ktype, + kernel_kobj, "%s", "dload"); + if (ret) { + pr_err("%s:Error in creation kobject_add\n", __func__); + kobject_put(&dload_kobj); + } + + ret = sysfs_create_group(&dload_kobj, &reset_attr_group); + if (ret) { + pr_err("%s:Error in creation sysfs_create_group\n", __func__); + kobject_del(&dload_kobj); + } +skip_sysfs_create: #endif np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-restart_reason"); From 6c1af3c519bcf9f951c0ee020ef2b2b808a3f8aa Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Sun, 7 Feb 2016 10:07:50 +0530 Subject: [PATCH 3/4] power: reset: Disable SDI when dload mode is not supported Based on the kernel parameter download_mode, disable the SDI execution. Also disable SDI execution for kernel panic/crash scenarios. Currently SDI is getting executed for kernel crash/panic scenarios, but it does not required in these scenarios. Change-Id: I5a64107e2bf210f82d94ab03c4f86f27f9a330c8 Signed-off-by: Prasad Sodagudi --- drivers/power/reset/msm-poweroff.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 8a045d3c5059..2aee18291f9c 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -139,9 +139,6 @@ static void set_dload_mode(int on) if (ret) pr_err("Failed to set secure DLOAD mode: %d\n", ret); - if (!on) - scm_disable_sdi(); - dload_mode_enabled = on; } @@ -198,7 +195,7 @@ static int dload_set(const char *val, struct kernel_param *kp) #else static void set_dload_mode(int on) { - scm_disable_sdi(); + return; } static void enable_emergency_dload_mode(void) @@ -383,6 +380,7 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) msm_trigger_wdog_bite(); #endif + scm_disable_sdi(); halt_spmi_pmic_arbiter(); deassert_ps_hold(); @@ -394,6 +392,7 @@ static void do_msm_poweroff(void) pr_notice("Powering off the SoC\n"); set_dload_mode(0); + scm_disable_sdi(); qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN); halt_spmi_pmic_arbiter(); @@ -572,6 +571,8 @@ skip_sysfs_create: download_mode = scm_is_secure_device(); set_dload_mode(download_mode); + if (!download_mode) + scm_disable_sdi(); return 0; From 1498330abf682df68c94991c4f58eafe07a82e72 Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Thu, 3 Mar 2016 13:07:26 +0530 Subject: [PATCH 4/4] power: reset: Skip emmc_dload sysfs entry creation Do not create /sys/kernel/dload/emmc_dload sysfs entry when imem-dload-type is not defined and also fix error paths of sysfs entry creation. Change-Id: I354e1f7635c5163516e256ed71b8510d1665877d Signed-off-by: Prasad Sodagudi --- drivers/power/reset/msm-poweroff.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 2aee18291f9c..2f109013f723 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -515,6 +515,7 @@ static int msm_restart_probe(struct platform_device *pdev) "qcom,msm-imem-dload-type"); if (!np) { pr_err("unable to find DT imem dload-type node\n"); + goto skip_sysfs_create; } else { dload_type_addr = of_iomap(np, 0); if (!dload_type_addr) { @@ -528,6 +529,7 @@ static int msm_restart_probe(struct platform_device *pdev) if (ret) { pr_err("%s:Error in creation kobject_add\n", __func__); kobject_put(&dload_kobj); + goto skip_sysfs_create; } ret = sysfs_create_group(&dload_kobj, &reset_attr_group);