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: Xogium <contact@xogium.me>, Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH 13/24] reset: add SCMI support
Date: Sun, 20 Feb 2022 13:47:25 +0100	[thread overview]
Message-ID: <20220220124736.3052502-14-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20220220124736.3052502-1-a.fatoum@pengutronix.de>

Import the Linux v5.13 state of the SCMI reset protocol driver.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/firmware/arm_scmi/Makefile |   2 +-
 drivers/firmware/arm_scmi/common.h |   1 +
 drivers/firmware/arm_scmi/driver.c |   2 +
 drivers/firmware/arm_scmi/reset.c  | 229 +++++++++++++++++++++++++++++
 drivers/reset/Kconfig              |  11 ++
 drivers/reset/Makefile             |   1 +
 drivers/reset/reset-scmi.c         | 130 ++++++++++++++++
 7 files changed, 375 insertions(+), 1 deletion(-)
 create mode 100644 drivers/firmware/arm_scmi/reset.c
 create mode 100644 drivers/reset/reset-scmi.c

diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile
index 8bb25484b9b2..510c0372a096 100644
--- a/drivers/firmware/arm_scmi/Makefile
+++ b/drivers/firmware/arm_scmi/Makefile
@@ -3,7 +3,7 @@ scmi-bus-y = bus.o
 scmi-driver-y = driver.o
 scmi-transport-y = shmem.o
 scmi-transport-$(CONFIG_ARM_SMCCC) += smc.o
-scmi-protocols-y = base.o
+scmi-protocols-y = base.o reset.o
 
 scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
 		    $(scmi-transport-y)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 9e48c0e7747d..f1f6cdae5af2 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -232,6 +232,7 @@ void __exit scmi_bus_exit(void);
 #define DECLARE_SCMI_REGISTER(func)		\
 	int __init scmi_##func##_register(void);
 DECLARE_SCMI_REGISTER(base);
+DECLARE_SCMI_REGISTER(reset);
 
 #define DEFINE_SCMI_PROTOCOL_REGISTER(name, proto)	\
 static const struct scmi_protocol *__this_proto = &(proto);	\
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index c9819e7c2aa3..d862e4de8afb 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1259,6 +1259,8 @@ static int __init scmi_bus_driver_init(void)
 
 	scmi_base_register();
 
+	scmi_reset_register();
+
 	return 0;
 }
 pure_initcall(scmi_bus_driver_init);
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
new file mode 100644
index 000000000000..94baab99e1e4
--- /dev/null
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * System Control and Management Interface (SCMI) Reset Protocol
+ *
+ * Copyright (C) 2019-2021 ARM Ltd.
+ */
+
+#define pr_fmt(fmt) "SCMI RESET - " fmt
+
+#include <common.h>
+#include <linux/scmi_protocol.h>
+
+#include "common.h"
+
+enum scmi_reset_protocol_cmd {
+	RESET_DOMAIN_ATTRIBUTES = 0x3,
+	RESET = 0x4,
+	RESET_NOTIFY = 0x5,
+};
+
+#define NUM_RESET_DOMAIN_MASK	0xffff
+
+struct scmi_msg_resp_reset_domain_attributes {
+	__le32 attributes;
+#define SUPPORTS_ASYNC_RESET(x)		((x) & BIT(31))
+#define SUPPORTS_NOTIFY_RESET(x)	((x) & BIT(30))
+	__le32 latency;
+	    u8 name[SCMI_MAX_STR_SIZE];
+};
+
+struct scmi_msg_reset_domain_reset {
+	__le32 domain_id;
+	__le32 flags;
+#define AUTONOMOUS_RESET	BIT(0)
+#define EXPLICIT_RESET_ASSERT	BIT(1)
+#define ASYNCHRONOUS_RESET	BIT(2)
+	__le32 reset_state;
+#define ARCH_COLD_RESET		0
+};
+
+struct reset_dom_info {
+	bool async_reset;
+	u32 latency_us;
+	char name[SCMI_MAX_STR_SIZE];
+};
+
+struct scmi_reset_info {
+	u32 version;
+	int num_domains;
+	struct reset_dom_info *dom_info;
+};
+
+static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
+				     struct scmi_reset_info *pi)
+{
+	int ret;
+	struct scmi_xfer *t;
+	u32 attr;
+
+	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
+				      0, sizeof(attr), &t);
+	if (ret)
+		return ret;
+
+	ret = ph->xops->do_xfer(ph, t);
+	if (!ret) {
+		attr = get_unaligned_le32(t->rx.buf);
+		pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
+	}
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
+}
+
+static int
+scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
+				 u32 domain, struct reset_dom_info *dom_info)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_resp_reset_domain_attributes *attr;
+
+	ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
+				      sizeof(domain), sizeof(*attr), &t);
+	if (ret)
+		return ret;
+
+	put_unaligned_le32(domain, t->tx.buf);
+	attr = t->rx.buf;
+
+	ret = ph->xops->do_xfer(ph, t);
+	if (!ret) {
+		u32 attributes = le32_to_cpu(attr->attributes);
+
+		dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
+		dom_info->latency_us = le32_to_cpu(attr->latency);
+		if (dom_info->latency_us == U32_MAX)
+			dom_info->latency_us = 0;
+		strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+	}
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
+}
+
+static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
+{
+	struct scmi_reset_info *pi = ph->get_priv(ph);
+
+	return pi->num_domains;
+}
+
+static char *scmi_reset_name_get(const struct scmi_protocol_handle *ph,
+				 u32 domain)
+{
+	struct scmi_reset_info *pi = ph->get_priv(ph);
+
+	struct reset_dom_info *dom = pi->dom_info + domain;
+
+	return dom->name;
+}
+
+static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
+				  u32 domain)
+{
+	struct scmi_reset_info *pi = ph->get_priv(ph);
+	struct reset_dom_info *dom = pi->dom_info + domain;
+
+	return dom->latency_us;
+}
+
+static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
+			     u32 flags, u32 state)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_reset_domain_reset *dom;
+	struct scmi_reset_info *pi = ph->get_priv(ph);
+	struct reset_dom_info *rdom = pi->dom_info + domain;
+
+	if (rdom->async_reset)
+		flags |= ASYNCHRONOUS_RESET;
+
+	ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t);
+	if (ret)
+		return ret;
+
+	dom = t->tx.buf;
+	dom->domain_id = cpu_to_le32(domain);
+	dom->flags = cpu_to_le32(flags);
+	dom->reset_state = cpu_to_le32(state);
+
+	if (rdom->async_reset)
+		ret = ph->xops->do_xfer_with_response(ph, t);
+	else
+		ret = ph->xops->do_xfer(ph, t);
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
+}
+
+static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph,
+				   u32 domain)
+{
+	return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET,
+				 ARCH_COLD_RESET);
+}
+
+static int
+scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
+{
+	return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT,
+				 ARCH_COLD_RESET);
+}
+
+static int
+scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain)
+{
+	return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET);
+}
+
+static const struct scmi_reset_proto_ops reset_proto_ops = {
+	.num_domains_get = scmi_reset_num_domains_get,
+	.name_get = scmi_reset_name_get,
+	.latency_get = scmi_reset_latency_get,
+	.reset = scmi_reset_domain_reset,
+	.assert = scmi_reset_domain_assert,
+	.deassert = scmi_reset_domain_deassert,
+};
+
+static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
+{
+	int domain;
+	u32 version;
+	struct scmi_reset_info *pinfo;
+
+	ph->xops->version_get(ph, &version);
+
+	dev_dbg(ph->dev, "Reset Version %d.%d\n",
+		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+
+	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+	if (!pinfo)
+		return -ENOMEM;
+
+	scmi_reset_attributes_get(ph, pinfo);
+
+	pinfo->dom_info = kcalloc(pinfo->num_domains,
+				       sizeof(*pinfo->dom_info), GFP_KERNEL);
+	if (!pinfo->dom_info)
+		return -ENOMEM;
+
+	for (domain = 0; domain < pinfo->num_domains; domain++) {
+		struct reset_dom_info *dom = pinfo->dom_info + domain;
+
+		scmi_reset_domain_attributes_get(ph, domain, dom);
+	}
+
+	pinfo->version = version;
+	return ph->set_priv(ph, pinfo);
+}
+
+static const struct scmi_protocol scmi_reset = {
+	.id = SCMI_PROTOCOL_RESET,
+	.instance_init = &scmi_reset_protocol_init,
+	.ops = &reset_proto_ops,
+};
+
+DEFINE_SCMI_PROTOCOL_REGISTER(reset, scmi_reset)
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 21a6e1a50d8f..913b309eac3a 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -45,4 +45,15 @@ config RESET_STARFIVE
 	help
 	  This enables the reset controller driver for the StarFive JH7100.
 
+config RESET_SCMI
+	tristate "Reset driver controlled via ARM SCMI interface"
+	depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
+	default ARM_SCMI_PROTOCOL
+	help
+	  This driver provides support for reset signal/domains that are
+	  controlled by firmware that implements the SCMI interface.
+
+	  This driver uses SCMI Message Protocol to interact with the
+	  firmware controlling all the reset signals.
+
 endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 6d0cd51f86ce..b1668433d76a 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
 obj-$(CONFIG_RESET_STARFIVE) += reset-starfive-vic.o
+obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
new file mode 100644
index 000000000000..c33bbc5c8afe
--- /dev/null
+++ b/drivers/reset/reset-scmi.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM System Control and Management Interface (ARM SCMI) reset driver
+ *
+ * Copyright (C) 2019-2021 ARM Ltd.
+ */
+
+#include <common.h>
+#include <of.h>
+#include <driver.h>
+#include <linux/reset-controller.h>
+#include <linux/scmi_protocol.h>
+
+static const struct scmi_reset_proto_ops *reset_ops;
+
+/**
+ * struct scmi_reset_data - reset controller information structure
+ * @rcdev: reset controller entity
+ * @ph: ARM SCMI protocol handle used for communication with system controller
+ */
+struct scmi_reset_data {
+	struct reset_controller_dev rcdev;
+	const struct scmi_protocol_handle *ph;
+};
+
+#define to_scmi_reset_data(p)	container_of((p), struct scmi_reset_data, rcdev)
+#define to_scmi_handle(p)	(to_scmi_reset_data(p)->ph)
+
+/**
+ * scmi_reset_assert() - assert device reset
+ * @rcdev: reset controller entity
+ * @id: ID of the reset to be asserted
+ *
+ * This function implements the reset driver op to assert a device's reset
+ * using the ARM SCMI protocol.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int
+scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+	const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
+
+	return reset_ops->assert(ph, id);
+}
+
+/**
+ * scmi_reset_deassert() - deassert device reset
+ * @rcdev: reset controller entity
+ * @id: ID of the reset to be deasserted
+ *
+ * This function implements the reset driver op to deassert a device's reset
+ * using the ARM SCMI protocol.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int
+scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+	const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
+
+	return reset_ops->deassert(ph, id);
+}
+
+/**
+ * scmi_reset_reset() - reset the device
+ * @rcdev: reset controller entity
+ * @id: ID of the reset signal to be reset(assert + deassert)
+ *
+ * This function implements the reset driver op to trigger a device's
+ * reset signal using the ARM SCMI protocol.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int
+scmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+	const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
+
+	return reset_ops->reset(ph, id);
+}
+
+static const struct reset_control_ops scmi_reset_ops = {
+	.assert		= scmi_reset_assert,
+	.deassert	= scmi_reset_deassert,
+	.reset		= scmi_reset_reset,
+};
+
+static int scmi_reset_probe(struct scmi_device *sdev)
+{
+	struct scmi_reset_data *data;
+	struct device_d *dev = &sdev->dev;
+	struct device_node *np = dev->device_node;
+	const struct scmi_handle *handle = sdev->handle;
+	struct scmi_protocol_handle *ph;
+
+	if (!handle)
+		return -ENODEV;
+
+	reset_ops = handle->protocol_get(sdev, SCMI_PROTOCOL_RESET, &ph);
+	if (IS_ERR(reset_ops))
+		return PTR_ERR(reset_ops);
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->rcdev.ops = &scmi_reset_ops;
+	data->rcdev.of_node = np;
+	data->rcdev.nr_resets = reset_ops->num_domains_get(ph);
+	data->ph = ph;
+
+	return reset_controller_register(&data->rcdev);
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+	{ SCMI_PROTOCOL_RESET, "reset" },
+	{ },
+};
+
+static struct scmi_driver scmi_reset_driver = {
+	.name = "scmi-reset",
+	.probe = scmi_reset_probe,
+	.id_table = scmi_id_table,
+};
+core_scmi_driver(scmi_reset_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI reset controller driver");
+MODULE_LICENSE("GPL v2");
-- 
2.30.2


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


  parent reply	other threads:[~2022-02-20 12:49 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-20 12:47 [PATCH 00/24] ARM: stm32mp: add trusted bootchain (SCMI&FIP) support Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 01/24] PBL: fdt: factor reg property parsing into helper Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 02/24] pinctrl: stm32: use gpio-ranges instead of alias Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 03/24] ARM: stm32mp: simplify with build_stm32mp_image macro Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 04/24] ARM: stm32mp: change stm32image extension to .stm32 Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 05/24] filetype: detect TF-A Firmware Image Packages (FIP) Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 06/24] scripts: add tool to adjust bl33 load address in existing FIP Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 07/24] ARM: stm32mp: build extra barebox-stm32mp-generic-bl33.img Ahmad Fatoum
2022-02-21 10:35   ` [PATCH] fixup! " Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 08/24] ARM: stm32mp: ddrctrl: fix wrong register field widths Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 09/24] reset: stm32: drop stm32mp1_reset_ops indirection Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 10/24] reset: move stm32 reset code to drivers/power/reset Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 11/24] ARM: smccc: sync header with upstream Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 12/24] firmware: import Linux v5.13 SCMI support Ahmad Fatoum
2022-02-20 12:47 ` Ahmad Fatoum [this message]
2022-02-20 12:47 ` [PATCH 14/24] clk: add SCMI clock driver Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 15/24] regulator: add SCMI regulator driver Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 16/24] clk: accept const arguments in clk_to_clk_hw/clk_hw_to_clk Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 17/24] serial: stm32: bail if clock_get_rate returns zero Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 18/24] clk: implement of_clk_hw_{onecell,simple}_get Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 19/24] clk: implement clk_hw_reparent Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 20/24] reset: add support for reset_control_status Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 21/24] clk: stm32mp1: sync with Linux v5.17-rc1 Ahmad Fatoum
2022-02-21 10:35   ` [PATCH] fixup! " Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 22/24] regulator: core: fall back to node name if no regulator-name property Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 23/24] ARM: dts: stm32mp: remove regulator-name override in stm32mp151.dtsi Ahmad Fatoum
2022-02-20 12:47 ` [PATCH 24/24] ARM: stm32mp: enable more config options Ahmad Fatoum
2022-02-23 10:57 ` [PATCH 00/24] ARM: stm32mp: add trusted bootchain (SCMI&FIP) support 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=20220220124736.3052502-14-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    --cc=contact@xogium.me \
    /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