summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStepan Moskovchenko <stepanm@codeaurora.org>2015-01-22 14:08:08 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:02:17 -0700
commit6c3bc79a39ea9370ca7750a22705f93ef2f43e9d (patch)
treebe4973fa91dbfa6a0f66348aca9090eb40f47db3
parent4a5aa46b78b528c441eb96fa0071318a915b7fcf (diff)
power: reset: msm: Deassert PS_HOLD via SCM if possible
Support a new SCM call which disables the PMIC arbiter and deasserts PS_HOLD in a single operation. Fall back on the legacy behavior of disabling the PMIC abriter and directly deasserting PS_HOLD if this call is not available. This is necessary comply with atomicity requirements of the secure environment. Change-Id: Ia3b13d469932edf94d3249fa3e7234a1c12eee1b Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
-rw-r--r--drivers/power/reset/msm-poweroff.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index c1e80f813e69..1a4cc70ab5d3 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
#define EMERGENCY_DLOAD_MAGIC3 0x77777777
#define SCM_IO_DISABLE_PMIC_ARBITER 1
+#define SCM_IO_DEASSERT_PS_HOLD 2
#define SCM_WDOG_DEBUG_BOOT_PART 0x9
#define SCM_DLOAD_MODE 0X10
#define SCM_EDLOAD_MODE 0X01
@@ -47,6 +48,7 @@
static int restart_mode;
void *restart_reason;
static bool scm_pmic_arbiter_disable_supported;
+static bool scm_deassert_ps_hold_supported;
/* Download mode master kill-switch */
static void __iomem *msm_ps_hold;
@@ -255,6 +257,30 @@ static void msm_restart_prepare(const char *cmd)
}
+/*
+ * Deassert PS_HOLD to signal the PMIC that we are ready to power down or reset.
+ * Do this by calling into the secure environment, if available, or by directly
+ * writing to a hardware register.
+ *
+ * This function should never return.
+ */
+static void deassert_ps_hold(void)
+{
+ struct scm_desc desc = {
+ .args[0] = 0,
+ .arginfo = SCM_ARGS(1),
+ };
+
+ if (scm_deassert_ps_hold_supported) {
+ /* This call will be available on ARMv8 only */
+ scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_PWR,
+ SCM_IO_DEASSERT_PS_HOLD), &desc);
+ }
+
+ /* Fall-through to the direct write in case the scm_call "returns" */
+ __raw_writel(0, msm_ps_hold);
+}
+
static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
{
int ret;
@@ -289,7 +315,7 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
pr_err("Failed to disable secure wdog debug: %d\n", ret);
halt_spmi_pmic_arbiter();
- __raw_writel(0, msm_ps_hold);
+ deassert_ps_hold();
mdelay(10000);
}
@@ -319,8 +345,7 @@ static void do_msm_poweroff(void)
pr_err("Failed to disable wdog debug: %d\n", ret);
halt_spmi_pmic_arbiter();
- /* MSM initiated power off, lower ps_hold */
- __raw_writel(0, msm_ps_hold);
+ deassert_ps_hold();
mdelay(10000);
pr_err("Powering off has failed\n");
@@ -383,6 +408,9 @@ static int msm_restart_probe(struct platform_device *pdev)
if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)
scm_pmic_arbiter_disable_supported = true;
+ if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DEASSERT_PS_HOLD) > 0)
+ scm_deassert_ps_hold_supported = true;
+
return 0;
err_restart_reason: