Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions arch/arm/cpu/armv8/fwcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,18 @@ void __noreturn psci_system_off(void)
while (1)
;
}

int psci_features(u32 psci_func_id)
{
struct pt_regs regs;

regs.regs[0] = ARM_PSCI_1_0_FN_PSCI_FEATURES;
regs.regs[1] = psci_func_id;

if (use_smc_for_psci)
smc_call(&regs);
else
hvc_call(&regs);

return regs.regs[0];
}
1 change: 1 addition & 0 deletions arch/arm/include/asm/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ void smc_call(struct pt_regs *args);
void __noreturn psci_system_reset(void);
void __noreturn psci_system_reset2(u32 reset_level, u32 cookie);
void __noreturn psci_system_off(void);
int psci_features(u32 psci_func_id);

#ifdef CONFIG_ARMV8_PSCI
extern char __secure_start[];
Expand Down
3 changes: 3 additions & 0 deletions cmd/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ U_BOOT_CMD(
reset, 2, 0, do_reset,
"Perform RESET of the CPU",
"- cold boot without level specifier\n"
#ifdef CONFIG_SYSRESET_QCOM_PSCI
"reset -edl - Boot to Emergency DownLoad mode\n"
#endif
"reset -w - warm reset if implemented"
);

Expand Down
2 changes: 2 additions & 0 deletions configs/qcom_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ CONFIG_QCOM_RPMH=y
CONFIG_SPMI_MSM=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SMBIOS=y
CONFIG_SYSRESET_CMD_RESET_ARGS=y
CONFIG_SYSRESET_QCOM_PSHOLD=y
CONFIG_SYSRESET_QCOM_PSCI=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
Expand Down
2 changes: 2 additions & 0 deletions doc/usage/cmd/reset.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ DDR and peripherals, on some boards also resets external PMIC.
-w
Do warm WARM, reset CPU but keep peripheral/DDR/PMIC active.

-edl
Boot to Emergency DownLoad mode on supported Qualcomm platforms.

Return value
------------
Expand Down
4 changes: 4 additions & 0 deletions drivers/firmware/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
14 changes: 14 additions & 0 deletions drivers/sysreset/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ config SYSRESET_CMD_RESET
help
Enable sysreset implementation of the reset command.

config SYSRESET_CMD_RESET_ARGS
bool "Enable reset command to take arguments"
help
Pass on the arguments received by the 'reset' command to the
sysreset driver(s). The sysreset driver(s) may make use of the
additional arguments for implementing arch/board specific
functionality.

if CMD_POWEROFF

config SYSRESET_CMD_POWEROFF
Expand Down Expand Up @@ -293,6 +301,12 @@ config SYSRESET_RAA215300
help
Add support for the system reboot via the Renesas RAA215300 PMIC.

config SYSRESET_QCOM_PSCI
bool "Support reset to EDL for Qualcomm SoCs via PSCI"
help
Add support for the reset to EDL (Emergency Download) on Qualcomm
SoCs via PSCI.

config SYSRESET_QCOM_PSHOLD
bool "Support sysreset for Qualcomm SoCs via PSHOLD"
help
Expand Down
1 change: 1 addition & 0 deletions drivers/sysreset/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ 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
obj-$(CONFIG_SYSRESET_QEMU_VIRT_CTRL) += sysreset_qemu_virt_ctrl.o
37 changes: 37 additions & 0 deletions drivers/sysreset/sysreset-uclass.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type)
return ops->request(dev, type);
}

#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET_ARGS)
int sysreset_request_arg(struct udevice *dev, int argc, char * const argv[])
{
struct sysreset_ops *ops = sysreset_get_ops(dev);

if (!ops->request_arg)
return -ENOSYS;

return ops->request_arg(dev, argc, argv);
}
#endif /* CONFIG_SYSRESET_CMD_RESET_ARGS */

int sysreset_get_status(struct udevice *dev, char *buf, int size)
{
struct sysreset_ops *ops = sysreset_get_ops(dev);
Expand Down Expand Up @@ -71,6 +83,26 @@ int sysreset_walk(enum sysreset_t type)
return ret;
}

#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET_ARGS)
int sysreset_walk_arg(int argc, char * const argv[])
{
struct udevice *dev;
int ret = -ENOSYS;

while (ret != -EINPROGRESS && ret != -EPROTONOSUPPORT) {
for (uclass_first_device(UCLASS_SYSRESET, &dev);
dev;
uclass_next_device(&dev)) {
ret = sysreset_request_arg(dev, argc, argv);
if (ret == -EINPROGRESS || ret == -EPROTONOSUPPORT)
break;
}
}

return ret;
}
#endif /* CONFIG_SYSRESET_CMD_RESET_ARGS */

int sysreset_get_last_walk(void)
{
struct udevice *dev;
Expand Down Expand Up @@ -132,6 +164,11 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
printf("resetting ...\n");
mdelay(100);

#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET_ARGS)
if (argc > 1 && sysreset_walk_arg(argc, argv) == -EINPROGRESS)
return 0;
#endif

sysreset_walk_halt(reset_type);

return 0;
Expand Down
45 changes: 45 additions & 0 deletions drivers/sysreset/sysreset_qcom-psci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@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>
#include <asm/psci.h>

static int qcom_psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
{
return -EOPNOTSUPP;
}

static int qcom_psci_sysreset_request_arg(struct udevice *dev, int argc,
char * const argv[])
{
if (!strncasecmp(argv[1], "-edl", 4)) {
/* Supported in qcs9100, qcs8300, sc7280, qcs615 */
if (psci_features(ARM_PSCI_1_1_FN64_SYSTEM_RESET2) ==
ARM_PSCI_RET_SUCCESS) {
psci_system_reset2(0, 1);
return -EINPROGRESS;
}
printf("PSCI SYSTEM_RESET2 not supported\n");
}

return -EPROTONOSUPPORT;
}

static struct sysreset_ops qcom_psci_sysreset_ops = {
.request_arg = qcom_psci_sysreset_request_arg,
.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,
};
18 changes: 18 additions & 0 deletions include/sysreset.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ struct sysreset_ops {
* (in which case this method will not actually return)
*/
int (*request)(struct udevice *dev, enum sysreset_t type);

/**
* @request_arg: Reset handler implementations that might need to process
* arguments given to the 'reset' command.
*
* Note that this function may return before the reset takes effect.
*
* @dev: Device to be used for system reset
* @argc: No. of items in @argv
* @argv: Arguments given to 'reset' command
* Return:
* -EINPROGRESS if the reset has started and will complete soon
* -EPROTONOSUPPORT if not supported by this device
* 0 if the reset has already happened
* (in which case this method will not actually return)
*/
int (*request_arg)(struct udevice *dev, int argc, char * const argv[]);

/**
* @get_status: get printable reset status information
*
Expand Down