mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH v2 4/6] ARM: psci: implement PSCI client driver
Date: Wed,  6 Nov 2019 11:21:47 +0100	[thread overview]
Message-ID: <20191106102149.6858-5-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20191106102149.6858-1-a.fatoum@pengutronix.de>

System reset on the STM32MP may be done via PSCI when running TF-A
as first-stage boot loader. Provide a PSCI driver to simplify using it:

- A psci_invoke function is exported, so other code can use it
- A fixup for the PSCI device tree node is registered
- A reset and poweroff handler via PSCI is registered for PSCI >= v0.2

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/arm/Kconfig            |   9 ++
 arch/arm/cpu/Makefile       |   1 +
 arch/arm/cpu/psci-client.c  | 190 ++++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/psci.h |  23 ++++-
 4 files changed, 221 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/cpu/psci-client.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f82844a83a5e..1346f70f4f5f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -449,6 +449,15 @@ config ARM_PSCI
 	  PSCI is used for controlling secondary CPU cores on some systems. Say
 	  yes here if you want barebox to service PSCI calls on such systems.
 
+config ARM_PSCI_CLIENT
+	bool "Enable barebox PSCI client support"
+	select ARM_SMCCC
+	select ARM_PSCI_OF
+	help
+	  Say yes here if you want barebox to communicate with a secure monitor
+	  for resetting/powering off the system over PSCI. barebox' PSCI version
+	  information will also be shared with Linux via device tree fixups.
+
 config ARM_PSCI_DEBUG
 	bool "Enable PSCI debugging"
 	depends on ARM_PSCI
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index e0b16747ad66..09b3bc2eeab9 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -16,6 +16,7 @@ pbl-$(CONFIG_BOARD_ARM_GENERIC_DT_AARCH64) += board-dt-2nd-aarch64.o
 obj-pbl-y += setupc$(S64).o cache$(S64).o
 
 obj-$(CONFIG_BOOTM_OPTEE) += start-kernel-optee.o
+obj-$(CONFIG_ARM_PSCI_CLIENT) += psci-client.o
 
 #
 # Any variants can be called as start-armxyz.S
diff --git a/arch/arm/cpu/psci-client.c b/arch/arm/cpu/psci-client.c
new file mode 100644
index 000000000000..b5d0d3749702
--- /dev/null
+++ b/arch/arm/cpu/psci-client.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2019 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <asm/psci.h>
+#include <asm/secure.h>
+#include <poweroff.h>
+#include <restart.h>
+#include <linux/arm-smccc.h>
+
+static struct restart_handler restart;
+
+static void __noreturn psci_invoke_noreturn(int function)
+{
+	int ret;
+
+	ret = psci_invoke(function, 0, 0, 0, NULL);
+
+	pr_err("psci command failed: %s\n", strerror(-ret));
+	hang();
+}
+
+static void __noreturn psci_poweroff(struct poweroff_handler *handler)
+{
+	psci_invoke_noreturn(ARM_PSCI_0_2_FN_SYSTEM_OFF);
+}
+
+static void __noreturn psci_restart(struct restart_handler *rst)
+{
+	psci_invoke_noreturn(ARM_PSCI_0_2_FN_SYSTEM_RESET);
+}
+
+static u32 version;
+int psci_get_version(void)
+{
+	if (!version)
+		return -EPROBE_DEFER;
+
+	return version;
+}
+
+static u32 (*psci_invoke_fn)(ulong, ulong, ulong, ulong);
+
+static int psci_xlate_error(s32 errnum)
+{
+       switch (errnum) {
+       case ARM_PSCI_RET_NOT_SUPPORTED:
+               return -ENOTSUPP; // Operation not supported
+       case ARM_PSCI_RET_INVAL:
+               return -EINVAL; // Invalid argument
+       case ARM_PSCI_RET_DENIED:
+               return -EPERM; // Operation not permitted
+       case ARM_PSCI_RET_ALREADY_ON:
+               return -EBUSY; // CPU already on
+       case ARM_PSCI_RET_ON_PENDING:
+               return -EALREADY; // CPU_ON in progress
+       case ARM_PSCI_RET_INTERNAL_FAILURE:
+               return -EIO; // Internal failure
+       case ARM_PSCI_RET_NOT_PRESENT:
+	       return -ESRCH; // Trusted OS not present on core
+       case ARM_PSCI_RET_DISABLED:
+               return -ENODEV; // CPU is disabled
+       case ARM_PSCI_RET_INVALID_ADDRESS:
+               return -EACCES; // Bad address
+       default:
+	       return errnum;
+       };
+}
+
+int psci_invoke(ulong function, ulong arg0, ulong arg1, ulong arg2,
+		ulong *result)
+{
+	ulong ret;
+	if (!psci_invoke_fn)
+		return -EPROBE_DEFER;
+
+	ret = psci_invoke_fn(function, arg0, arg1, arg2);
+	if (result)
+		*result = ret;
+
+	switch (function) {
+	case ARM_PSCI_0_2_FN_PSCI_VERSION:
+	case ARM_PSCI_1_0_FN64_STAT_RESIDENCY:
+	case ARM_PSCI_1_0_FN64_STAT_COUNT:
+		/* These don't return an error code */
+		return 0;
+	}
+
+	return psci_xlate_error(ret);
+}
+
+static u32 invoke_psci_fn_hvc(ulong function, ulong arg0, ulong arg1, ulong arg2)
+{
+	struct arm_smccc_res res;
+	arm_smccc_hvc(function, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static u32 invoke_psci_fn_smc(ulong function, ulong arg0, ulong arg1, ulong arg2)
+{
+	struct arm_smccc_res res;
+	arm_smccc_smc(function, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static int of_psci_do_fixup(struct device_node *root, void *context)
+{
+	return of_psci_fixup(root, *(u32 *)context);
+}
+
+static int __init psci_probe(struct device_d *dev)
+{
+	const char *method;
+	ulong of_version, actual_version;
+	int ret;
+
+	ret = dev_get_drvdata(dev, (const void **)&of_version);
+	if (ret)
+		return -ENODEV;
+
+	ret = of_property_read_string(dev->device_node, "method", &method);
+	if (ret) {
+		dev_warn(dev, "missing \"method\" property\n");
+		return -ENXIO;
+	}
+
+	if (!strcmp(method, "hvc")) {
+		psci_invoke_fn = invoke_psci_fn_hvc;
+	} else if (!strcmp(method, "smc")) {
+		psci_invoke_fn = invoke_psci_fn_smc;
+	} else {
+		pr_warn("invalid \"method\" property: %s\n", method);
+		return -EINVAL;
+	}
+
+
+	if (of_version < ARM_PSCI_VER(0,2)) {
+		version = of_version;
+
+		dev_info(dev, "assuming version %u.%u\n",
+			 version >> 16, version & 0xffff);
+		dev_dbg(dev, "Not registering reset handler due to PSCI version\n");
+
+		return 0;
+	}
+
+	psci_invoke(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, &actual_version);
+	version = actual_version;
+
+	dev_info(dev, "detected version %u.%u\n",
+		 version >> 16, version & 0xffff);
+
+	if (actual_version != of_version)
+		of_register_fixup(of_psci_do_fixup, &version);
+
+	ret = poweroff_handler_register_fn(psci_poweroff);
+	if (ret)
+		dev_warn(dev, "error registering poweroff handler: %s\n",
+			 strerror(-ret));
+
+	restart.name = "psci";
+	restart.restart = psci_restart;
+	restart.priority = 400;
+
+	ret = restart_handler_register(&restart);
+	if (ret)
+		dev_warn(dev, "error registering restart handler: %s\n",
+			 strerror(-ret));
+
+	return ret;
+}
+
+static __maybe_unused struct of_device_id psci_dt_ids[] = {
+	{ .compatible = "arm,psci",	.data = (void*)ARM_PSCI_VER(0,1) },
+	{ .compatible = "arm,psci-0.2",	.data = (void*)ARM_PSCI_VER(0,2) },
+	{ .compatible = "arm,psci-1.0",	.data = (void*)ARM_PSCI_VER(1,0) },
+	{ /* sentinel */ },
+};
+
+static struct driver_d psci_driver = {
+	.name = "psci",
+	.probe = psci_probe,
+	.of_compatible = DRV_OF_COMPAT(psci_dt_ids),
+};
+coredevice_platform_driver(psci_driver);
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
index f2db967f3a63..8f76ffcb2dbb 100644
--- a/arch/arm/include/asm/psci.h
+++ b/arch/arm/include/asm/psci.h
@@ -18,8 +18,9 @@
 #ifndef __ARM_PSCI_H__
 #define __ARM_PSCI_H__
 
-#define ARM_PSCI_VER_1_0		(0x00010000)
-#define ARM_PSCI_VER_0_2		(0x00000002)
+#define ARM_PSCI_VER(major, minor)	(((major) << 16) | (minor))
+#define ARM_PSCI_VER_1_0		ARM_PSCI_VER(1,0)
+#define ARM_PSCI_VER_0_2		ARM_PSCI_VER(0,2)
 
 /* PSCI 0.1 interface */
 #define ARM_PSCI_FN_BASE		0x95c1ba5e
@@ -106,6 +107,24 @@ static inline void psci_set_ops(struct psci_ops *ops)
 }
 #endif
 
+#ifdef CONFIG_ARM_PSCI_CLIENT
+int psci_invoke(ulong function, ulong arg0, ulong arg1, ulong arg2,
+		ulong *result);
+
+int psci_get_version(void);
+#else
+int psci_invoke(ulong function, ulong arg0, ulong arg1, ulong arg2,
+		ulong *result)
+{
+	return -ENOSYS;
+}
+
+int psci_get_version(void)
+{
+	return -ENOSYS;
+}
+#endif
+
 void psci_cpu_entry(void);
 
 #ifdef CONFIG_ARM_PSCI_DEBUG
-- 
2.24.0.rc1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2019-11-06 10:22 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-06 10:21 [PATCH v2 0/6] ARM: psci: add " Ahmad Fatoum
2019-11-06 10:21 ` [PATCH v2 1/6] ARM: psci: translate PSCI error codes in smc command Ahmad Fatoum
2019-11-06 10:21 ` [PATCH v2 2/6] ARM: psci: use CONFIG_ARM_PSCI_DEBUG for " Ahmad Fatoum
2019-11-06 10:21 ` [PATCH v2 3/6] ARM: psci: wire in smc command help Ahmad Fatoum
2019-11-06 10:21 ` Ahmad Fatoum [this message]
2019-11-07 11:33   ` [PATCH v2 4/6] ARM: psci: implement PSCI client driver Sascha Hauer
2019-11-06 10:21 ` [PATCH v2 5/6] ARM: stm32mp: select ARM_USE_COMPRESSED_DTB for the whole arch Ahmad Fatoum
2019-11-06 10:21 ` [PATCH v2 6/6] ARM: dts: stm32mp: report psci v0.2 at least Ahmad Fatoum
2019-11-06 10:26   ` [PATCH] fixup! " Ahmad Fatoum
2019-11-07  7:09 ` [PATCH v2 0/6] ARM: psci: add PSCI client driver Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191106102149.6858-5-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox