aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2023-10-04 09:32:29 +0000
committerAndrew Turner <andrew@FreeBSD.org>2024-04-11 09:58:56 +0000
commitd46f01fd590eab5b7c25c7b218d390704a5bcb81 (patch)
treeac30bab9cf4ae3ba0c42063bc1afd47f2ae65242
parentecd8cc84dcee7d08be8663f721f0502dc5b65808 (diff)
downloadsrc-d46f01fd590eab5b7c25c7b218d390704a5bcb81.tar.gz
src-d46f01fd590eab5b7c25c7b218d390704a5bcb81.zip
-rw-r--r--sys/conf/files.arm642
-rw-r--r--sys/dev/firmware/arm/scmi.c82
-rw-r--r--sys/dev/firmware/arm/scmi.h13
-rw-r--r--sys/dev/firmware/arm/scmi_if.m32
-rw-r--r--sys/dev/firmware/arm/scmi_mailbox.c178
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);