The SYSRESET_PSCI interface presently available doesn't support booting into Emergency DownLoad (EDL) mode. The EDL mode is used to flash the board with different firmware.
Since EDL is Qcom specific, implement a Qcom specific SYSRESET_PSCI handler that handles resetting to EDL in addition to the usual cold/warm reset and poweroff. Signed-off-by: Varadarajan Narayanan <quic_var...@quicinc.com> --- v2: * Update commit message * Elaborate Kconfig help text * Use '-edl' instead of 'edl' for consistency with other arguments of reset command * Remove 'weak' for qcom_psci_sysreset_get_status() and make it static * Mention 'SYSRESET_EDL' is Qcom specific in the enum's comments --- drivers/firmware/psci.c | 4 +++ drivers/sysreset/Kconfig | 7 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset-uclass.c | 7 ++-- drivers/sysreset/sysreset_qcom-psci.c | 48 +++++++++++++++++++++++++++ include/sysreset.h | 7 ++++ 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 drivers/sysreset/sysreset_qcom-psci.c diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 2e3223e1c32..b6838a244d2 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -186,6 +186,10 @@ static int psci_bind(struct udevice *dev) NULL); if (ret) pr_debug("PSCI System Reset was not bound.\n"); + if (IS_ENABLED(CONFIG_SYSRESET_QCOM_PSCI) && + device_bind_driver(dev, "qcom_psci-sysreset", + "qcom_psci-sysreset", NULL)) + pr_debug("QCOM PSCI System Reset was not bound.\n"); } /* From PSCI v1.0 onward we can discover services through ARM_SMCCC_FEATURE */ diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 4972905482a..d407c322bdb 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -285,6 +285,13 @@ config SYSRESET_RAA215300 help Add support for the system reboot via the Renesas RAA215300 PMIC. +config SYSRESET_QCOM_PSCI + bool "Support sysreset for Qualcomm SoCs via PSCI" + help + Add support for the system reboot on Qualcomm SoCs via PSCI. + This allows warm/cold reset, poweroff and reset to EDL (Emergency + Download) + config SYSRESET_QCOM_PSHOLD bool "Support sysreset for Qualcomm SoCs via PSHOLD" help diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index ded91a4d325..58eb0e356e1 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o obj-$(CONFIG_$(PHASE_)SYSRESET_AT91) += sysreset_at91.o obj-$(CONFIG_$(PHASE_)SYSRESET_X86) += sysreset_x86.o obj-$(CONFIG_SYSRESET_RAA215300) += sysreset_raa215300.o +obj-$(CONFIG_SYSRESET_QCOM_PSCI) += sysreset_qcom-psci.o obj-$(CONFIG_SYSRESET_QCOM_PSHOLD) += sysreset_qcom-pshold.o obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index 536ac727142..ff9bc962ec0 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -125,8 +125,11 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (argc > 2) return CMD_RET_USAGE; - if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'w') { - reset_type = SYSRESET_WARM; + if (argc == 2) { + if (argv[1][0] == '-' && argv[1][1] == 'w') + reset_type = SYSRESET_WARM; + else if (!strncmp("-edl", argv[1], 4)) + reset_type = SYSRESET_EDL; } printf("resetting ...\n"); diff --git a/drivers/sysreset/sysreset_qcom-psci.c b/drivers/sysreset/sysreset_qcom-psci.c new file mode 100644 index 00000000000..9d0606c059b --- /dev/null +++ b/drivers/sysreset/sysreset_qcom-psci.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Masahiro Yamada <yamada.masah...@socionext.com> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <dm.h> +#include <sysreset.h> +#include <asm/system.h> +#include <linux/errno.h> +#include <linux/psci.h> + +static int qcom_psci_sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + return -EOPNOTSUPP; +} + +static int qcom_psci_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + switch (type) { + case SYSRESET_WARM: + case SYSRESET_COLD: + psci_sys_reset(type); + break; + case SYSRESET_POWER_OFF: + psci_sys_poweroff(); + break; + case SYSRESET_EDL: + psci_system_reset2(0, 1); + break; + default: + return -EPROTONOSUPPORT; + } + + return -EINPROGRESS; +} + +static struct sysreset_ops qcom_psci_sysreset_ops = { + .request = qcom_psci_sysreset_request, + .get_status = qcom_psci_sysreset_get_status, +}; + +U_BOOT_DRIVER(qcom_psci_sysreset) = { + .name = "qcom_psci-sysreset", + .id = UCLASS_SYSRESET, + .ops = &qcom_psci_sysreset_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/sysreset.h b/include/sysreset.h index ff20abdeed3..d0f60ed2456 100644 --- a/include/sysreset.h +++ b/include/sysreset.h @@ -21,6 +21,13 @@ enum sysreset_t { SYSRESET_POWER, /** @SYSRESET_POWER_OFF: turn off power */ SYSRESET_POWER_OFF, +#if IS_ENABLED(CONFIG_SYSRESET_QCOM_PSCI) + /** + * @SYSRESET_EDL: Reset and boot into Emergency DownLoader. + * This is supported only in recent Qcom SoCs. + */ + SYSRESET_EDL, +#endif /** @SYSRESET_COUNT: number of available reset types */ SYSRESET_COUNT, }; -- 2.34.1