git: d46f01fd590e - main - scmi: Split out the SCMI mailbox to a new file

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Thu, 11 Apr 2024 09:59:21 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=d46f01fd590eab5b7c25c7b218d390704a5bcb81

commit d46f01fd590eab5b7c25c7b218d390704a5bcb81
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2023-10-04 09:32:29 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-04-11 09:58:56 +0000

    scmi: Split out the SCMI mailbox to a new file
    
    Add a new SCMI interface file to allow for multiple kind of transports
    and move the mailbox transport to its own file, using the new interface.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D43039
---
 sys/conf/files.arm64                |   2 +
 sys/dev/firmware/arm/scmi.c         |  82 ++---------------
 sys/dev/firmware/arm/scmi.h         |  13 +++
 sys/dev/firmware/arm/scmi_if.m      |  32 +++++++
 sys/dev/firmware/arm/scmi_mailbox.c | 178 ++++++++++++++++++++++++++++++++++++
 5 files changed, 232 insertions(+), 75 deletions(-)

diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 293a0ae1c0f9..5541a18af659 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -272,6 +272,8 @@ dev/etherswitch/felix/felix.c			optional enetc etherswitch fdt felix pci soc_nxp
 
 dev/firmware/arm/scmi.c				optional fdt scmi
 dev/firmware/arm/scmi_clk.c			optional fdt scmi
+dev/firmware/arm/scmi_if.m			optional fdt scmi
+dev/firmware/arm/scmi_mailbox.c			optional fdt scmi
 dev/firmware/arm/scmi_shmem.c			optional fdt scmi
 
 dev/gpio/pl061.c				optional pl061 gpio
diff --git a/sys/dev/firmware/arm/scmi.c b/sys/dev/firmware/arm/scmi.c
index 3101be245ee1..fae4ec676a17 100644
--- a/sys/dev/firmware/arm/scmi.c
+++ b/sys/dev/firmware/arm/scmi.c
@@ -47,15 +47,6 @@
 #include "scmi.h"
 #include "scmi_protocols.h"
 
-struct scmi_softc {
-	struct simplebus_softc	simplebus_sc;
-	device_t		dev;
-	device_t		tx_shmem;
-	struct arm_doorbell	*db;
-	struct mtx		mtx;
-	int			req_done;
-};
-
 static device_t
 scmi_get_shmem(struct scmi_softc *sc, int index)
 {
@@ -90,26 +81,11 @@ scmi_get_shmem(struct scmi_softc *sc, int index)
 	return (dev);
 }
 
-static void
-scmi_callback(void *arg)
-{
-	struct scmi_softc *sc;
-
-	sc = arg;
-
-	dprintf("%s sc %p\n", __func__, sc);
-
-	SCMI_LOCK(sc);
-	sc->req_done = 1;
-	wakeup(sc);
-	SCMI_UNLOCK(sc);
-}
-
 static int
 scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req)
 {
 	struct scmi_smt_header hdr;
-	int timeout;
+	int ret;
 
 	bzero(&hdr, sizeof(struct scmi_smt_header));
 
@@ -125,6 +101,7 @@ scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req)
 	hdr.channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
 	hdr.msg_header = req->protocol_id << SMT_HEADER_PROTOCOL_ID_S;
 	hdr.msg_header |= req->message_id << SMT_HEADER_MESSAGE_ID_S;
+	/* TODO: Allocate a token */
 	hdr.length = sizeof(hdr.msg_header) + req->in_size;
 	hdr.flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
 
@@ -135,31 +112,9 @@ scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req)
 	scmi_shmem_write(sc->tx_shmem, SMT_HEADER_SIZE, req->in_buf,
 	    req->in_size);
 
-	sc->req_done = 0;
-
-	/* Interrupt SCP firmware. */
-	arm_doorbell_set(sc->db);
-
-	timeout = 200;
-
-	dprintf("%s: request\n", __func__);
-
-	do {
-		if (cold) {
-			if (arm_doorbell_get(sc->db))
-				break;
-			DELAY(10000);
-		} else {
-			msleep(sc, &sc->mtx, 0, "scmi", hz / 10);
-			if (sc->req_done)
-				break;
-		}
-	} while (timeout--);
-
-	if (timeout <= 0)
-		return (-1);
-
-	dprintf("%s: got reply, timeout %d\n", __func__, timeout);
+	ret = SCMI_XFER_MSG(sc->dev);
+	if (ret != 0)
+		return (ret);
 
 	/* Read header. */
 	scmi_shmem_read(sc->tx_shmem, 0, &hdr, SMT_HEADER_SIZE);
@@ -186,22 +141,7 @@ scmi_request(device_t dev, struct scmi_req *req)
 	return (error);
 }
 
-static int
-scmi_probe(device_t dev)
-{
-
-	if (!ofw_bus_is_compatible(dev, "arm,scmi"))
-		return (ENXIO);
-
-	if (!ofw_bus_status_okay(dev))
-		return (ENXIO);
-
-	device_set_desc(dev, "ARM SCMI interface driver");
-
-	return (BUS_PROBE_DEFAULT);
-}
-
-static int
+int
 scmi_attach(device_t dev)
 {
 	struct scmi_softc *sc;
@@ -221,16 +161,8 @@ scmi_attach(device_t dev)
 		return (ENXIO);
 	}
 
-	sc->db = arm_doorbell_ofw_get(sc->dev, "tx");
-	if (sc->db == NULL) {
-		device_printf(dev, "Doorbell device not found.\n");
-		return (ENXIO);
-	}
-
 	mtx_init(&sc->mtx, device_get_nameunit(dev), "SCMI", MTX_DEF);
 
-	arm_doorbell_set_handler(sc->db, scmi_callback, sc);
-
 	simplebus_init(dev, node);
 
 	/*
@@ -257,9 +189,9 @@ scmi_detach(device_t dev)
 }
 
 static device_method_t scmi_methods[] = {
-	DEVMETHOD(device_probe,		scmi_probe),
 	DEVMETHOD(device_attach,	scmi_attach),
 	DEVMETHOD(device_detach,	scmi_detach),
+
 	DEVMETHOD_END
 };
 
diff --git a/sys/dev/firmware/arm/scmi.h b/sys/dev/firmware/arm/scmi.h
index 34faa3ff7e73..f1c81a609894 100644
--- a/sys/dev/firmware/arm/scmi.h
+++ b/sys/dev/firmware/arm/scmi.h
@@ -31,12 +31,21 @@
 #ifndef	_ARM64_SCMI_SCMI_H_
 #define	_ARM64_SCMI_SCMI_H_
 
+#include "scmi_if.h"
+
 #define	SCMI_LOCK(sc)		mtx_lock(&(sc)->mtx)
 #define	SCMI_UNLOCK(sc)		mtx_unlock(&(sc)->mtx)
 #define	SCMI_ASSERT_LOCKED(sc)	mtx_assert(&(sc)->mtx, MA_OWNED)
 
 #define dprintf(fmt, ...)
 
+struct scmi_softc {
+	struct simplebus_softc	simplebus_sc;
+	device_t		dev;
+	device_t		tx_shmem;
+	struct mtx		mtx;
+};
+
 /* Shared Memory Transfer. */
 struct scmi_smt_header {
 	uint32_t reserved;
@@ -71,7 +80,11 @@ struct scmi_req {
 	uint32_t out_size;
 };
 
+DECLARE_CLASS(scmi_driver);
+
+int scmi_attach(device_t dev);
 int scmi_request(device_t dev, struct scmi_req *req);
+
 void scmi_shmem_read(device_t dev, bus_size_t offset, void *buf,
     bus_size_t len);
 void scmi_shmem_write(device_t dev, bus_size_t offset, const void *buf,
diff --git a/sys/dev/firmware/arm/scmi_if.m b/sys/dev/firmware/arm/scmi_if.m
new file mode 100644
index 000000000000..524cf0fb0d66
--- /dev/null
+++ b/sys/dev/firmware/arm/scmi_if.m
@@ -0,0 +1,32 @@
+#-
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2023 Arm Ltd
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice unmodified, this list of conditions, and the following
+#    disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+INTERFACE scmi;
+
+METHOD int xfer_msg {
+	device_t dev;
+};
diff --git a/sys/dev/firmware/arm/scmi_mailbox.c b/sys/dev/firmware/arm/scmi_mailbox.c
new file mode 100644
index 000000000000..bebdc7348b98
--- /dev/null
+++ b/sys/dev/firmware/arm/scmi_mailbox.c
@@ -0,0 +1,178 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ * Copyright (c) 2023 Arm Ltd
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <dev/clk/clk.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "dev/mailbox/arm/arm_doorbell.h"
+
+#include "scmi.h"
+#include "scmi_protocols.h"
+
+struct scmi_mailbox_softc {
+	struct scmi_softc	base;
+	struct arm_doorbell	*db;
+	int			req_done;
+};
+
+static void
+scmi_mailbox_callback(void *arg)
+{
+	struct scmi_mailbox_softc *sc;
+
+	sc = arg;
+
+	dprintf("%s sc %p\n", __func__, sc);
+
+	SCMI_LOCK(&sc->base);
+	sc->req_done = 1;
+	wakeup(sc);
+	SCMI_UNLOCK(&sc->base);
+}
+
+static int
+scmi_mailbox_xfer_msg(device_t dev)
+{
+	struct scmi_mailbox_softc *sc;
+	int timeout;
+
+	sc = device_get_softc(dev);
+	SCMI_ASSERT_LOCKED(&sc->base);
+
+	sc->req_done = 0;
+
+	/* Interrupt SCP firmware. */
+	arm_doorbell_set(sc->db);
+
+	timeout = 200;
+
+	dprintf("%s: request\n", __func__);
+
+	do {
+		if (cold) {
+			if (arm_doorbell_get(sc->db))
+				break;
+			DELAY(10000);
+		} else {
+			msleep(sc, &sc->base.mtx, 0, "scmi", hz / 10);
+			if (sc->req_done)
+				break;
+		}
+	} while (timeout--);
+
+	if (timeout <= 0)
+		return (-1);
+
+	dprintf("%s: got reply, timeout %d\n", __func__, timeout);
+
+	return (0);
+}
+
+static int
+scmi_mailbox_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "arm,scmi"))
+		return (ENXIO);
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	device_set_desc(dev, "ARM SCMI interface driver");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+scmi_mailbox_attach(device_t dev)
+{
+	struct scmi_mailbox_softc *sc;
+	int ret;
+
+	sc = device_get_softc(dev);
+
+	/* TODO: Support other mailbox devices */
+	sc->db = arm_doorbell_ofw_get(dev, "tx");
+	if (sc->db == NULL) {
+		device_printf(dev, "Doorbell device not found.\n");
+		return (ENXIO);
+	}
+
+	arm_doorbell_set_handler(sc->db, scmi_mailbox_callback, sc);
+
+	ret = scmi_attach(dev);
+	if (ret != 0)
+		arm_doorbell_set_handler(sc->db, NULL, NULL);
+
+	return (ret);
+}
+
+static int
+scmi_mailbox_detach(device_t dev)
+{
+	struct scmi_mailbox_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	arm_doorbell_set_handler(sc->db, NULL, NULL);
+
+	return (0);
+}
+
+static device_method_t scmi_mailbox_methods[] = {
+	DEVMETHOD(device_probe,		scmi_mailbox_probe),
+	DEVMETHOD(device_attach,	scmi_mailbox_attach),
+	DEVMETHOD(device_detach,	scmi_mailbox_detach),
+
+	/* SCMI interface */
+	DEVMETHOD(scmi_xfer_msg,	scmi_mailbox_xfer_msg),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(scmi_mailbox, scmi_mailbox_driver, scmi_mailbox_methods,
+    sizeof(struct scmi_mailbox_softc), scmi_driver);
+
+DRIVER_MODULE(scmi_mailbox, simplebus, scmi_mailbox_driver, 0, 0);
+MODULE_VERSION(scmi_mailbox, 1);