msm: restart: remove native reboot and add msm_poweroff driver

Remove native reboot driver as reboot support moved
from MSM_NATIVE_RESTART to POWER_RESET_MSM driver.

Change-Id: I7b3f8d0b9320b85ea010e4c5a97e642355d318e2
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
This commit is contained in:
Prasad Sodagudi 2014-03-16 22:15:05 +05:30
parent a061aac605
commit 367d3a53d2
14 changed files with 289 additions and 427 deletions

View File

@ -15,7 +15,6 @@ config ARCH_MSM8974
select MSM_PIL select MSM_PIL
select MSM_SPM_V2 select MSM_SPM_V2
select MSM_L2_SPM select MSM_L2_SPM
select MSM_NATIVE_RESTART
select MSM_PM if PM select MSM_PM if PM
select MSM_RPM_SMD select MSM_RPM_SMD
select REGULATOR select REGULATOR
@ -47,7 +46,6 @@ config ARCH_APQ8084
select MSM_SCM select MSM_SCM
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select MSM_GPIOMUX select MSM_GPIOMUX
select MSM_NATIVE_RESTART
select MSM_PM if PM select MSM_PM if PM
select REGULATOR select REGULATOR
select MSM_QDSP6V2_CODECS select MSM_QDSP6V2_CODECS
@ -86,7 +84,6 @@ config ARCH_MPQ8092
select GPIO_MSM_V3 select GPIO_MSM_V3
select ARM_GIC select ARM_GIC
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select MSM_NATIVE_RESTART
select CPU_V7 select CPU_V7
select MSM_SCM select MSM_SCM
select MSM_GPIOMUX select MSM_GPIOMUX
@ -156,7 +153,6 @@ config ARCH_FSM9900
select PM_DEVFREQ select PM_DEVFREQ
select MSM_DEVFREQ_CPUBW select MSM_DEVFREQ_CPUBW
select MSM_PIL select MSM_PIL
select MSM_NATIVE_RESTART
select REGULATOR select REGULATOR
select ARM_HAS_SG_CHAIN select ARM_HAS_SG_CHAIN
select MSM_RUN_QUEUE_STATS select MSM_RUN_QUEUE_STATS
@ -176,7 +172,6 @@ config ARCH_MDM9630
select REGULATOR select REGULATOR
select REGULATOR_RPM_SMD select REGULATOR_RPM_SMD
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select MSM_NATIVE_RESTART
select MSM_SPM_V2 select MSM_SPM_V2
select MSM_PM if PM select MSM_PM if PM
select GPIO_MSM_V3 select GPIO_MSM_V3
@ -206,7 +201,6 @@ config ARCH_MSM8610
select GPIO_MSM_V3 select GPIO_MSM_V3
select MSM_GPIOMUX select MSM_GPIOMUX
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select MSM_NATIVE_RESTART
select MSM_QDSP6_APRV2 select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS select MSM_QDSP6V2_CODECS
select QMI_ENCDEC select QMI_ENCDEC
@ -247,7 +241,6 @@ config ARCH_MSM8226
select GPIO_MSM_V3 select GPIO_MSM_V3
select MSM_GPIOMUX select MSM_GPIOMUX
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select MSM_NATIVE_RESTART
select MSM_QDSP6_APRV2 select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS select MSM_QDSP6V2_CODECS
select QMI_ENCDEC select QMI_ENCDEC
@ -292,7 +285,6 @@ config ARCH_MSMSAMARIUM
select MSM_GPIOMUX select MSM_GPIOMUX
select MSM_SPM_V2 select MSM_SPM_V2
select MSM_L2_SPM select MSM_L2_SPM
select MSM_NATIVE_RESTART
select MSM_QDSP6_APRV2 select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS select MSM_QDSP6V2_CODECS
select MSM_PM if PM select MSM_PM if PM
@ -849,9 +841,6 @@ config IOMMU_API
config MSM_GPIOMUX config MSM_GPIOMUX
bool bool
config MSM_NATIVE_RESTART
bool
config MSM_BUS_RPM_MULTI_TIER_ENABLED config MSM_BUS_RPM_MULTI_TIER_ENABLED
bool "RPM Multi-tiering Configuration" bool "RPM Multi-tiering Configuration"
depends on MSM_BUS_SCALING depends on MSM_BUS_SCALING

View File

@ -65,8 +65,6 @@ obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_FSM9900) += gpiomux-v2.o gpiomux.o obj-$(CONFIG_ARCH_FSM9900) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_MSM_NATIVE_RESTART) += restart.o
obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o
@ -75,8 +73,6 @@ obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o
obj-$(CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL) += wdog_debug.o
obj-$(CONFIG_MEMORY_HOLE_CARVEOUT) += msm_mem_hole.o obj-$(CONFIG_MEMORY_HOLE_CARVEOUT) += msm_mem_hole.o
obj-$(CONFIG_MSM_SMCMOD) += smcmod.o obj-$(CONFIG_MSM_SMCMOD) += smcmod.o

View File

@ -119,6 +119,5 @@ DT_MACHINE_START(APQ8084_DT, "Qualcomm APQ 8084 (Flattened Device Tree)")
.dt_compat = apq8084_dt_match, .dt_compat = apq8084_dt_match,
.reserve = apq8084_reserve, .reserve = apq8084_reserve,
.init_very_early = apq8084_init_very_early, .init_very_early = apq8084_init_very_early,
.restart = msm_restart,
.smp = &msm8974_smp_ops, .smp = &msm8974_smp_ops,
MACHINE_END MACHINE_END

View File

@ -188,6 +188,5 @@ DT_MACHINE_START(MSM8092_DT, "Qualcomm MSM 8092 (Flattened Device Tree)")
.dt_compat = mpq8092_dt_match, .dt_compat = mpq8092_dt_match,
.reserve = mpq8092_dt_reserve, .reserve = mpq8092_dt_reserve,
.init_very_early = mpq8092_early_memory, .init_very_early = mpq8092_early_memory,
.restart = msm_restart,
.smp = &msm8974_smp_ops, .smp = &msm8974_smp_ops,
MACHINE_END MACHINE_END

View File

@ -141,6 +141,5 @@ DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8226 (Flattened Device Tree)")
.dt_compat = msm8226_dt_match, .dt_compat = msm8226_dt_match,
.reserve = msm8226_reserve, .reserve = msm8226_reserve,
.init_very_early = msm8226_early_memory, .init_very_early = msm8226_early_memory,
.restart = msm_restart,
.smp = &arm_smp_ops, .smp = &arm_smp_ops,
MACHINE_END MACHINE_END

View File

@ -108,7 +108,6 @@ DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8610 (Flattened Device Tree)")
.map_io = msm_map_msm8610_io, .map_io = msm_map_msm8610_io,
.init_machine = msm8610_init, .init_machine = msm8610_init,
.dt_compat = msm8610_dt_match, .dt_compat = msm8610_dt_match,
.restart = msm_restart,
.reserve = msm8610_reserve, .reserve = msm8610_reserve,
.init_very_early = msm8610_early_memory, .init_very_early = msm8610_early_memory,
.smp = &arm_smp_ops, .smp = &arm_smp_ops,

View File

@ -149,6 +149,5 @@ DT_MACHINE_START(MSM8974_DT, "Qualcomm MSM 8974 (Flattened Device Tree)")
.dt_compat = msm8974_dt_match, .dt_compat = msm8974_dt_match,
.reserve = msm_8974_reserve, .reserve = msm_8974_reserve,
.init_very_early = msm8974_init_very_early, .init_very_early = msm8974_init_very_early,
.restart = msm_restart,
.smp = &msm8974_smp_ops, .smp = &msm8974_smp_ops,
MACHINE_END MACHINE_END

View File

@ -96,5 +96,4 @@ DT_MACHINE_START(MDM9630_DT, "Qualcomm MDM 9630 (Flattened Device Tree)")
.dt_compat = mdm9630_dt_match, .dt_compat = mdm9630_dt_match,
.reserve = mdm9630_reserve, .reserve = mdm9630_reserve,
.init_very_early = mdm9630_early_memory, .init_very_early = mdm9630_early_memory,
.restart = msm_restart,
MACHINE_END MACHINE_END

View File

@ -183,6 +183,5 @@ DT_MACHINE_START(FSM9900_DT, "Qualcomm FSM 9900 (Flattened Device Tree)")
.dt_compat = fsm9900_dt_match, .dt_compat = fsm9900_dt_match,
.reserve = fsm9900_reserve, .reserve = fsm9900_reserve,
.init_very_early = fsm9900_init_very_early, .init_very_early = fsm9900_init_very_early,
.restart = msm_restart,
.smp = &msm8974_smp_ops, .smp = &msm8974_smp_ops,
MACHINE_END MACHINE_END

View File

@ -1,331 +0,0 @@
/* Copyright (c) 2010-2014, 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/mfd/pmic8058.h>
#include <linux/mfd/pmic8901.h>
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/qpnp/power-on.h>
#include <linux/of_address.h>
#include <soc/qcom/scm.h>
#include <asm/cacheflush.h>
#include <mach/msm_iomap.h>
#include <soc/qcom/restart.h>
#include <soc/qcom/socinfo.h>
#include <mach/irqs.h>
#include "msm_watchdog.h"
#include "timer.h"
#include "wdog_debug.h"
#define WDT0_RST 0x38
#define WDT0_EN 0x40
#define WDT0_BARK_TIME 0x4C
#define WDT0_BITE_TIME 0x5C
#define PSHOLD_CTL_SU (MSM_TLMM_BASE + 0x820)
#define RESTART_REASON_ADDR 0x65C
#define DLOAD_MODE_ADDR 0x0
#define EMERGENCY_DLOAD_MODE_ADDR 0xFE0
#define EMERGENCY_DLOAD_MAGIC1 0x322A4F99
#define EMERGENCY_DLOAD_MAGIC2 0xC67E4350
#define EMERGENCY_DLOAD_MAGIC3 0x77777777
#define SCM_IO_DISABLE_PMIC_ARBITER 1
static int restart_mode;
void *restart_reason;
int pmic_reset_irq;
static void __iomem *msm_tmr0_base;
#ifdef CONFIG_MSM_DLOAD_MODE
#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
#define DL_MODE_PROP "qcom,msm-imem-download_mode"
static int in_panic;
static void *dload_mode_addr;
static bool dload_mode_enabled;
static void *emergency_dload_mode_addr;
/* Download mode master kill-switch */
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,
unsigned long event, void *ptr)
{
in_panic = 1;
return NOTIFY_DONE;
}
static struct notifier_block panic_blk = {
.notifier_call = panic_prep_restart,
};
static void set_dload_mode(int on)
{
if (dload_mode_addr) {
__raw_writel(on ? 0xE47B337D : 0, dload_mode_addr);
__raw_writel(on ? 0xCE14091A : 0,
dload_mode_addr + sizeof(unsigned int));
mb();
dload_mode_enabled = on;
}
}
static bool get_dload_mode(void)
{
return dload_mode_enabled;
}
static void enable_emergency_dload_mode(void)
{
if (emergency_dload_mode_addr) {
__raw_writel(EMERGENCY_DLOAD_MAGIC1,
emergency_dload_mode_addr);
__raw_writel(EMERGENCY_DLOAD_MAGIC2,
emergency_dload_mode_addr +
sizeof(unsigned int));
__raw_writel(EMERGENCY_DLOAD_MAGIC3,
emergency_dload_mode_addr +
(2 * sizeof(unsigned int)));
/* Need disable the pmic wdt, then the emergency dload mode
* will not auto reset. */
qpnp_pon_wd_config(0);
mb();
}
}
static int dload_set(const char *val, struct kernel_param *kp)
{
int ret;
int old_val = download_mode;
ret = param_set_int(val, kp);
if (ret)
return ret;
/* If download_mode is not zero or one, ignore. */
if (download_mode >> 1) {
download_mode = old_val;
return -EINVAL;
}
set_dload_mode(download_mode);
return 0;
}
#else
#define set_dload_mode(x) do {} while (0)
static void enable_emergency_dload_mode(void)
{
printk(KERN_ERR "dload mode is not enabled on target\n");
}
static bool get_dload_mode(void)
{
return false;
}
#endif
void msm_set_restart_mode(int mode)
{
restart_mode = mode;
}
EXPORT_SYMBOL(msm_set_restart_mode);
static bool scm_pmic_arbiter_disable_supported;
/*
* Force the SPMI PMIC arbiter to shutdown so that no more SPMI transactions
* are sent from the MSM to the PMIC. This is required in order to avoid an
* SPMI lockup on certain PMIC chips if PS_HOLD is lowered in the middle of
* an SPMI transaction.
*/
static void halt_spmi_pmic_arbiter(void)
{
if (scm_pmic_arbiter_disable_supported) {
pr_crit("Calling SCM to disable SPMI PMIC arbiter\n");
scm_call_atomic1(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER, 0);
}
}
static void __msm_power_off(int lower_pshold)
{
printk(KERN_CRIT "Powering off the SoC\n");
#ifdef CONFIG_MSM_DLOAD_MODE
set_dload_mode(0);
#endif
pm8xxx_reset_pwr_off(0);
qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
if (lower_pshold) {
halt_spmi_pmic_arbiter();
__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
mdelay(10000);
printk(KERN_ERR "Powering off has failed\n");
}
return;
}
static void msm_power_off(void)
{
/* MSM initiated power off, lower ps_hold */
__msm_power_off(1);
}
static void msm_restart_prepare(const char *cmd)
{
#ifdef CONFIG_MSM_DLOAD_MODE
/* This looks like a normal reboot at this point. */
set_dload_mode(0);
/* Write download mode flags if we're panic'ing */
set_dload_mode(in_panic);
/* Write download mode flags if restart_mode says so */
if (restart_mode == RESTART_DLOAD)
set_dload_mode(1);
/* Kill download mode if master-kill switch is set */
if (!download_mode)
set_dload_mode(0);
#endif
pm8xxx_reset_pwr_off(1);
/* Hard reset the PMIC unless memory contents must be maintained. */
if (get_dload_mode() || (cmd != NULL && cmd[0] != '\0'))
qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);
else
qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);
if (cmd != NULL) {
if (!strncmp(cmd, "bootloader", 10)) {
__raw_writel(0x77665500, restart_reason);
} else if (!strncmp(cmd, "recovery", 8)) {
__raw_writel(0x77665502, restart_reason);
} else if (!strcmp(cmd, "rtc")) {
__raw_writel(0x77665503, restart_reason);
} else if (!strncmp(cmd, "oem-", 4)) {
unsigned long code;
code = simple_strtoul(cmd + 4, NULL, 16) & 0xff;
__raw_writel(0x6f656d00 | code, restart_reason);
} else if (!strncmp(cmd, "edl", 3)) {
enable_emergency_dload_mode();
} else {
__raw_writel(0x77665501, restart_reason);
}
}
flush_cache_all();
outer_flush_all();
}
void msm_restart(enum reboot_mode mode, const char *cmd)
{
printk(KERN_NOTICE "Going down for restart now\n");
msm_restart_prepare(cmd);
/* Needed to bypass debug image on some chips */
msm_disable_wdog_debug();
halt_spmi_pmic_arbiter();
__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
mdelay(10000);
printk(KERN_ERR "Restarting has failed\n");
}
static int __init msm_restart_init(void)
{
struct device_node *np;
int ret = 0;
#ifdef CONFIG_MSM_DLOAD_MODE
atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
np = of_find_compatible_node(NULL, NULL, DL_MODE_PROP);
if (!np) {
pr_err("unable to find DT imem download mode node\n");
ret = -ENODEV;
goto err_dl_mode;
}
dload_mode_addr = of_iomap(np, 0);
if (!dload_mode_addr) {
pr_err("unable to map imem download model offset\n");
ret = -ENOMEM;
goto err_dl_mode;
}
np = of_find_compatible_node(NULL, NULL, EDL_MODE_PROP);
if (!np) {
pr_err("unable to find DT imem emergency download mode node\n");
ret = -ENODEV;
goto err_edl_mode;
}
emergency_dload_mode_addr = of_iomap(np, 0);
if (!emergency_dload_mode_addr) {
pr_err("unable to map imem emergency download model offset\n");
ret = -ENOMEM;
goto err_edl_mode;
}
set_dload_mode(download_mode);
#endif
msm_tmr0_base = msm_timer_get_timer0_base();
np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-restart_reason");
if (!np) {
pr_err("unable to find DT imem restart reason node\n");
ret = -ENODEV;
goto err_restart_reason;
}
restart_reason = of_iomap(np, 0);
if (!restart_reason) {
pr_err("unable to map imem restart reason offset\n");
ret = -ENOMEM;
goto err_restart_reason;
}
pm_power_off = msm_power_off;
if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)
scm_pmic_arbiter_disable_supported = true;
return 0;
err_restart_reason:
#ifdef CONFIG_MSM_DLOAD_MODE
iounmap(emergency_dload_mode_addr);
err_edl_mode:
iounmap(dload_mode_addr);
err_dl_mode:
#endif
return ret;
}
early_initcall(msm_restart_init);

View File

@ -1,40 +0,0 @@
/* Copyright (c) 2012-2013, 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <soc/qcom/scm.h>
#define SCM_WDOG_DEBUG_BOOT_PART 0x9
#define BOOT_PART_EN_VAL 0x5D1
void msm_enable_wdog_debug(void)
{
int ret;
ret = scm_call_atomic2(SCM_SVC_BOOT,
SCM_WDOG_DEBUG_BOOT_PART, 0, BOOT_PART_EN_VAL);
if (ret)
pr_err("failed to enable wdog debug: %d\n", ret);
}
EXPORT_SYMBOL(msm_enable_wdog_debug);
void msm_disable_wdog_debug(void)
{
int ret;
ret = scm_call_atomic2(SCM_SVC_BOOT,
SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
if (ret)
pr_err("failed to disable wdog debug: %d\n", ret);
}
EXPORT_SYMBOL(msm_disable_wdog_debug);

View File

@ -1,24 +0,0 @@
/* Copyright (c) 2012, 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __WDOG_DEBUG_H
#define __WDOG_DEBUG_H
#ifdef CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL
void msm_enable_wdog_debug(void);
void msm_disable_wdog_debug(void);
#else
void msm_enable_wdog_debug(void) { }
void msm_disable_wdog_debug(void) { }
#endif
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 and
@ -20,27 +20,301 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/qpnp/power-on.h>
#include <linux/of_address.h>
#include <asm/cacheflush.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/restart.h>
#define EMERGENCY_DLOAD_MAGIC1 0x322A4F99
#define EMERGENCY_DLOAD_MAGIC2 0xC67E4350
#define EMERGENCY_DLOAD_MAGIC3 0x77777777
#define SCM_IO_DISABLE_PMIC_ARBITER 1
#define SCM_WDOG_DEBUG_BOOT_PART 0x9
#define SCM_DLOAD_MODE 0X10
#define SCM_EDLOAD_MODE 0X02
#define SCM_DLOAD_CMD 0x10
static int restart_mode;
void *restart_reason;
static bool scm_pmic_arbiter_disable_supported;
/* Download mode master kill-switch */
static void __iomem *msm_ps_hold; static void __iomem *msm_ps_hold;
#ifdef CONFIG_MSM_DLOAD_MODE
#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
#define DL_MODE_PROP "qcom,msm-imem-download_mode"
static int in_panic;
static void *dload_mode_addr;
static bool dload_mode_enabled;
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,
unsigned long event, void *ptr)
{
in_panic = 1;
return NOTIFY_DONE;
}
static struct notifier_block panic_blk = {
.notifier_call = panic_prep_restart,
};
static void set_dload_mode(int on)
{
int ret;
if (dload_mode_addr) {
__raw_writel(on ? 0xE47B337D : 0, dload_mode_addr);
__raw_writel(on ? 0xCE14091A : 0,
dload_mode_addr + sizeof(unsigned int));
mb();
}
if (scm_dload_supported) {
ret = scm_call_atomic2(SCM_SVC_BOOT,
SCM_DLOAD_CMD, on ? SCM_DLOAD_MODE : 0, 0);
if (ret)
pr_err("Failed to set DLOAD mode: %d\n", ret);
}
dload_mode_enabled = on;
}
static bool get_dload_mode(void)
{
return dload_mode_enabled;
}
static void enable_emergency_dload_mode(void)
{
int ret;
if (emergency_dload_mode_addr) {
__raw_writel(EMERGENCY_DLOAD_MAGIC1,
emergency_dload_mode_addr);
__raw_writel(EMERGENCY_DLOAD_MAGIC2,
emergency_dload_mode_addr +
sizeof(unsigned int));
__raw_writel(EMERGENCY_DLOAD_MAGIC3,
emergency_dload_mode_addr +
(2 * sizeof(unsigned int)));
/* Need disable the pmic wdt, then the emergency dload mode
* will not auto reset. */
qpnp_pon_wd_config(0);
mb();
}
if (scm_dload_supported) {
ret = scm_call_atomic2(SCM_SVC_BOOT,
SCM_DLOAD_CMD, SCM_EDLOAD_MODE, 0);
if (ret)
pr_err("Failed to set EDLOAD mode: %d\n", ret);
}
}
static int dload_set(const char *val, struct kernel_param *kp)
{
int ret;
int old_val = download_mode;
ret = param_set_int(val, kp);
if (ret)
return ret;
/* If download_mode is not zero or one, ignore. */
if (download_mode >> 1) {
download_mode = old_val;
return -EINVAL;
}
set_dload_mode(download_mode);
return 0;
}
#else
#define set_dload_mode(x) do {} while (0)
static void enable_emergency_dload_mode(void)
{
pr_err("dload mode is not enabled on target\n");
}
static bool get_dload_mode(void)
{
return false;
}
#endif
void msm_set_restart_mode(int mode)
{
restart_mode = mode;
}
EXPORT_SYMBOL(msm_set_restart_mode);
/*
* Force the SPMI PMIC arbiter to shutdown so that no more SPMI transactions
* are sent from the MSM to the PMIC. This is required in order to avoid an
* SPMI lockup on certain PMIC chips if PS_HOLD is lowered in the middle of
* an SPMI transaction.
*/
static void halt_spmi_pmic_arbiter(void)
{
if (scm_pmic_arbiter_disable_supported) {
pr_crit("Calling SCM to disable SPMI PMIC arbiter\n");
scm_call_atomic1(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER, 0);
}
}
static void msm_restart_prepare(const char *cmd)
{
#ifdef CONFIG_MSM_DLOAD_MODE
/* Write download mode flags if we're panic'ing
* Write download mode flags if restart_mode says so
* Kill download mode if master-kill switch is set
*/
set_dload_mode(download_mode &&
(in_panic || restart_mode == RESTART_DLOAD));
#endif
/* Hard reset the PMIC unless memory contents must be maintained. */
if (get_dload_mode() || (cmd != NULL && cmd[0] != '\0'))
qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);
else
qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);
if (cmd != NULL) {
if (!strncmp(cmd, "bootloader", 10)) {
__raw_writel(0x77665500, restart_reason);
} else if (!strncmp(cmd, "recovery", 8)) {
__raw_writel(0x77665502, restart_reason);
} else if (!strcmp(cmd, "rtc")) {
__raw_writel(0x77665503, restart_reason);
} else if (!strncmp(cmd, "oem-", 4)) {
unsigned long code;
code = kstrtoul(cmd + 4, 16, NULL) & 0xff;
__raw_writel(0x6f656d00 | code, restart_reason);
} else if (!strncmp(cmd, "edl", 3)) {
enable_emergency_dload_mode();
} else {
__raw_writel(0x77665501, restart_reason);
}
}
flush_cache_all();
/*outer_flush_all is not supported by 64bit kernel*/
#ifndef CONFIG_ARM64
outer_flush_all();
#endif
}
static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
{ {
writel(0, msm_ps_hold); int ret;
pr_notice("Going down for restart now\n");
msm_restart_prepare(cmd);
/* Needed to bypass debug image on some chips */
ret = scm_call_atomic2(SCM_SVC_BOOT,
SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
if (ret)
pr_err("Failed to disable wdog debug: %d\n", ret);
halt_spmi_pmic_arbiter();
__raw_writel(0, msm_ps_hold);
mdelay(10000); mdelay(10000);
} }
static void do_msm_poweroff(void) static void do_msm_poweroff(void)
{ {
/* TODO: Add poweroff capability */ int ret;
do_msm_restart(REBOOT_HARD, NULL);
pr_notice("Powering off the SoC\n");
#ifdef CONFIG_MSM_DLOAD_MODE
set_dload_mode(0);
#endif
qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
/* Needed to bypass debug image on some chips */
ret = scm_call_atomic2(SCM_SVC_BOOT,
SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
if (ret)
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);
mdelay(10000);
pr_err("Powering off has failed\n");
return;
} }
static int msm_restart_probe(struct platform_device *pdev) static int msm_restart_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *mem; struct resource *mem;
struct device_node *np;
int ret = 0;
#ifdef CONFIG_MSM_DLOAD_MODE
if (scm_is_call_available(SCM_SVC_BOOT, SCM_DLOAD_CMD) > 0)
scm_dload_supported = true;
atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
np = of_find_compatible_node(NULL, NULL, DL_MODE_PROP);
if (!np) {
pr_err("unable to find DT imem DLOAD mode node\n");
} else {
dload_mode_addr = of_iomap(np, 0);
if (!dload_mode_addr)
pr_err("unable to map imem DLOAD offset\n");
}
np = of_find_compatible_node(NULL, NULL, EDL_MODE_PROP);
if (!np) {
pr_err("unable to find DT imem EDLOAD mode node\n");
} else {
emergency_dload_mode_addr = of_iomap(np, 0);
if (!emergency_dload_mode_addr)
pr_err("unable to map imem EDLOAD mode offset\n");
}
set_dload_mode(download_mode);
#endif
np = of_find_compatible_node(NULL, NULL,
"qcom,msm-imem-restart_reason");
if (!np) {
pr_err("unable to find DT imem restart reason node\n");
} else {
restart_reason = of_iomap(np, 0);
if (!restart_reason) {
pr_err("unable to map imem restart reason offset\n");
ret = -ENOMEM;
goto err_restart_reason;
}
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
msm_ps_hold = devm_ioremap_resource(dev, mem); msm_ps_hold = devm_ioremap_resource(dev, mem);
@ -49,7 +323,18 @@ static int msm_restart_probe(struct platform_device *pdev)
pm_power_off = do_msm_poweroff; pm_power_off = do_msm_poweroff;
arm_pm_restart = do_msm_restart; arm_pm_restart = do_msm_restart;
if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)
scm_pmic_arbiter_disable_supported = true;
return 0; return 0;
err_restart_reason:
#ifdef CONFIG_MSM_DLOAD_MODE
iounmap(emergency_dload_mode_addr);
iounmap(dload_mode_addr);
#endif
return ret;
} }
static const struct of_device_id of_msm_restart_match[] = { static const struct of_device_id of_msm_restart_match[] = {

View File

@ -17,13 +17,7 @@
#define RESTART_NORMAL 0x0 #define RESTART_NORMAL 0x0
#define RESTART_DLOAD 0x1 #define RESTART_DLOAD 0x1
#if defined(CONFIG_MSM_NATIVE_RESTART)
void msm_set_restart_mode(int mode); void msm_set_restart_mode(int mode);
void msm_restart(enum reboot_mode mode, const char *cmd);
#else
#define msm_set_restart_mode(mode)
#endif
extern int pmic_reset_irq; extern int pmic_reset_irq;
#endif #endif