diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c index 40d154811146..70bd93e30991 100644 --- a/drivers/firmware/qcom_scm-smc.c +++ b/drivers/firmware/qcom_scm-smc.c @@ -1919,6 +1919,19 @@ int __qcom_scm_tsens_reinit(struct device *dev, int *tsens_ret) return ret; } +int __qcom_scm_reboot(struct device *dev) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_OEM_POWER, + .cmd = QCOM_SCM_OEM_POWER_REBOOT, + .owner = ARM_SMCCC_OWNER_OEM, + }; + + desc.arginfo = QCOM_SCM_ARGS(0); + + return qcom_scm_call_atomic(dev, &desc); +} + int __qcom_scm_ice_restore_cfg(struct device *dev) { struct qcom_scm_desc desc = { diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d292859b9bd4..23e93331260b 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ struct qcom_scm { struct clk *iface_clk; struct clk *bus_clk; struct reset_controller_dev reset; + struct notifier_block restart_nb; u64 dload_mode_addr; }; @@ -992,6 +994,17 @@ bool qcom_scm_is_available(void) } EXPORT_SYMBOL(qcom_scm_is_available); +static int qcom_scm_do_restart(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct qcom_scm *scm = container_of(this, struct qcom_scm, restart_nb); + + if (reboot_mode == REBOOT_WARM) + __qcom_scm_reboot(scm->dev); + + return NOTIFY_OK; +} + static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) { struct device_node *tcsr; @@ -1085,6 +1098,10 @@ static int qcom_scm_probe(struct platform_device *pdev) if (ret) return ret; + scm->restart_nb.notifier_call = qcom_scm_do_restart; + scm->restart_nb.priority = 130; + register_restart_handler(&scm->restart_nb); + __scm = scm; __scm->dev = &pdev->dev; diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 04afabc82ca1..9a3ab3945dce 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -235,6 +235,11 @@ extern int __qcom_scm_qseecom_do(struct device *dev, u32 cmd_id, #define QCOM_SCM_TSENS_INIT_ID 0x5 extern int __qcom_scm_tsens_reinit(struct device *dev, int *tsens_ret); +// OEM Services and Function IDs +#define QCOM_SCM_SVC_OEM_POWER 0x09 +#define QCOM_SCM_OEM_POWER_REBOOT 0x22 +extern int __qcom_scm_reboot(struct device *dev); + // TOS Services and Function IDs #define QCOM_SCM_SVC_QSEELOG 0x01 #define QCOM_SCM_QSEELOG_REGISTER 0x06