Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102809722
D37316.id113857.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
47 KB
Referenced Files
None
Subscribers
None
D37316.id113857.diff
View Options
Index: sys/arm64/scmi/arm_doorbell.h
===================================================================
--- /dev/null
+++ sys/arm64/scmi/arm_doorbell.h
@@ -0,0 +1,53 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_SCMI_ARM_DOORBELL_H_
+#define _ARM64_SCMI_ARM_DOORBELL_H_
+
+static MALLOC_DEFINE(M_DOORBELL, "arm_doorbell", "ARM Doorbell");
+
+struct arm_doorbell {
+ device_t dev;
+ device_t db_dev;
+ int chan;
+ int db;
+ void (*func)(void *);
+ void *arg;
+};
+
+void arm_doorbell_set(struct arm_doorbell *db);
+int arm_doorbell_get(struct arm_doorbell *db);
+struct arm_doorbell * arm_doorbell_ofw_get(device_t dev, const char *name);
+void arm_doorbell_set_handler(struct arm_doorbell *db, void (*func)(void *),
+ void *arg);
+
+#endif /* !_ARM64_SCMI_ARM_DOORBELL_H_ */
Index: sys/arm64/scmi/arm_doorbell.c
===================================================================
--- /dev/null
+++ sys/arm64/scmi/arm_doorbell.c
@@ -0,0 +1,342 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "arm_doorbell.h"
+
+#define MHU_CHAN_RX_LP 0x000 /* Low priority channel */
+#define MHU_CHAN_RX_HP 0x020 /* High priority channel */
+#define MHU_CHAN_RX_SEC 0x200 /* Secure channel */
+#define MHU_INTR_STAT 0x00
+#define MHU_INTR_SET 0x08
+#define MHU_INTR_CLEAR 0x10
+
+#define MHU_TX_REG_OFFSET 0x100
+
+#define DOORBELL_N_CHANNELS 3
+#define DOORBELL_N_DOORBELLS (DOORBELL_N_CHANNELS * 32)
+
+struct arm_doorbell dbells[DOORBELL_N_DOORBELLS];
+
+static struct resource_spec arm_doorbell_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { -1, 0 }
+};
+
+struct arm_doorbell_softc {
+ struct resource *res[3];
+ void *lp_intr_cookie;
+ void *hp_intr_cookie;
+ device_t dev;
+};
+
+static void
+arm_doorbell_lp_intr(void *arg)
+{
+ struct arm_doorbell_softc *sc;
+ struct arm_doorbell *db;
+ uint32_t reg;
+ int i;
+
+ sc = arg;
+
+ reg = bus_read_4(sc->res[0], MHU_CHAN_RX_LP + MHU_INTR_STAT);
+ for (i = 0; i < 32; i++) {
+ if (reg & (1 << i)) {
+ db = &dbells[i];
+ bus_write_4(sc->res[0], MHU_CHAN_RX_LP + MHU_INTR_CLEAR,
+ (1 << i));
+ if (db->func != NULL)
+ db->func(db->arg);
+ }
+ }
+}
+
+static void
+arm_doorbell_hp_intr(void *arg)
+{
+ struct arm_doorbell_softc *sc;
+ struct arm_doorbell *db;
+ uint32_t reg;
+ int i;
+
+ sc = arg;
+
+ reg = bus_read_4(sc->res[0], MHU_CHAN_RX_HP + MHU_INTR_STAT);
+ for (i = 0; i < 32; i++) {
+ if (reg & (1 << i)) {
+ db = &dbells[i];
+ bus_write_4(sc->res[0], MHU_CHAN_RX_HP + MHU_INTR_CLEAR,
+ (1 << i));
+ if (db->func != NULL)
+ db->func(db->arg);
+ }
+ }
+}
+
+static int
+arm_doorbell_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "arm,mhu-doorbell"))
+ return (ENXIO);
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ device_set_desc(dev, "ARM MHU Doorbell");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+arm_doorbell_attach(device_t dev)
+{
+ struct arm_doorbell_softc *sc;
+ phandle_t node;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ node = ofw_bus_get_node(dev);
+ if (node == -1)
+ return (ENXIO);
+
+ if (bus_alloc_resources(dev, arm_doorbell_spec, sc->res) != 0) {
+ device_printf(dev, "Can't allocate resources for device.\n");
+ return (ENXIO);
+ }
+
+ /* Setup interrupt handlers. */
+ error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, arm_doorbell_lp_intr, sc, &sc->lp_intr_cookie);
+ if (error != 0) {
+ device_printf(dev, "Can't setup LP interrupt handler.\n");
+ bus_release_resources(dev, arm_doorbell_spec, sc->res);
+ return (ENXIO);
+ }
+
+ error = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, arm_doorbell_hp_intr, sc, &sc->hp_intr_cookie);
+ if (error != 0) {
+ device_printf(dev, "Can't setup HP interrupt handler.\n");
+ bus_release_resources(dev, arm_doorbell_spec, sc->res);
+ return (ENXIO);
+ }
+
+ OF_device_register_xref(OF_xref_from_node(node), dev);
+
+ return (0);
+}
+
+static int
+arm_doorbell_detach(device_t dev)
+{
+
+ return (0);
+}
+
+struct arm_doorbell *
+arm_doorbell_ofw_get(device_t dev, const char *name)
+{
+ phandle_t node, parent;
+ struct arm_doorbell *db;
+ device_t db_dev;
+ pcell_t *cells;
+ int nmboxes;
+ int ncells;
+ int idx;
+ int db_id;
+ int error;
+ int chan;
+
+ node = ofw_bus_get_node(dev);
+
+ error = ofw_bus_parse_xref_list_get_length(node, "mboxes",
+ "#mbox-cells", &nmboxes);
+ if (error) {
+ device_printf(dev, "%s can't get mboxes list.\n", __func__);
+ return (NULL);
+ }
+
+ if (nmboxes == 0) {
+ device_printf(dev, "%s mbox list is empty.\n", __func__);
+ return (NULL);
+ }
+
+ error = ofw_bus_find_string_index(node, "mbox-names", name, &idx);
+ if (error != 0) {
+ device_printf(dev, "%s can't find string index.\n",
+ __func__);
+ return (NULL);
+ }
+
+ error = ofw_bus_parse_xref_list_alloc(node, "mboxes", "#mbox-cells",
+ idx, &parent, &ncells, &cells);
+ if (error != 0) {
+ device_printf(dev, "%s can't get mbox device xref\n",
+ __func__);
+ return (NULL);
+ }
+
+ if (ncells != 2) {
+ device_printf(dev, "Unexpected data size.\n");
+ return (NULL);
+ }
+
+ db_dev = OF_device_from_xref(parent);
+ if (db_dev == NULL) {
+ device_printf(dev, "%s: Can't get arm_doorbell device\n", __func__);
+ return (NULL);
+ }
+
+ chan = cells[0];
+ if (chan >= DOORBELL_N_CHANNELS) {
+ device_printf(dev, "Unexpected channel number.\n");
+ return (NULL);
+ }
+
+ db_id = cells[1];
+ if (db_id >= 32) {
+ device_printf(dev, "Unexpected channel bit.\n");
+ return (NULL);
+ }
+
+ db = &dbells[chan * db_id];
+ db->dev = dev;
+ db->db_dev = db_dev;
+ db->chan = chan;
+ db->db = db_id;
+
+ free(cells, M_OFWPROP);
+
+ return (db);
+}
+
+void
+arm_doorbell_set(struct arm_doorbell *db)
+{
+ struct arm_doorbell_softc *sc;
+ uint32_t offset;
+
+ sc = device_get_softc(db->db_dev);
+
+ switch (db->chan) {
+ case 0:
+ offset = MHU_CHAN_RX_LP;
+ break;
+ case 1:
+ offset = MHU_CHAN_RX_HP;
+ break;
+ case 2:
+ offset = MHU_CHAN_RX_SEC;
+ break;
+ default:
+ panic("not reached");
+ };
+
+ offset |= MHU_TX_REG_OFFSET;
+
+ bus_write_4(sc->res[0], offset + MHU_INTR_SET, (1 << db->db));
+}
+
+int
+arm_doorbell_get(struct arm_doorbell *db)
+{
+ struct arm_doorbell_softc *sc;
+ uint32_t offset;
+ uint32_t reg;
+
+ sc = device_get_softc(db->db_dev);
+
+ switch (db->chan) {
+ case 0:
+ offset = MHU_CHAN_RX_LP;
+ break;
+ case 1:
+ offset = MHU_CHAN_RX_HP;
+ break;
+ case 2:
+ offset = MHU_CHAN_RX_SEC;
+ break;
+ default:
+ panic("not reached");
+ };
+
+ reg = bus_read_4(sc->res[0], offset + MHU_INTR_STAT);
+ if (reg & (1 << db->db)) {
+ bus_write_4(sc->res[0], offset + MHU_INTR_CLEAR,
+ (1 << db->db));
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+arm_doorbell_set_handler(struct arm_doorbell *db, void (*func)(void *),
+ void *arg)
+{
+
+ db->func = func;
+ db->arg = arg;
+}
+
+static device_method_t arm_doorbell_methods[] = {
+ DEVMETHOD(device_probe, arm_doorbell_probe),
+ DEVMETHOD(device_attach, arm_doorbell_attach),
+ DEVMETHOD(device_detach, arm_doorbell_detach),
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(arm_doorbell, arm_doorbell_driver, arm_doorbell_methods,
+ sizeof(struct arm_doorbell_softc), simplebus_driver);
+
+EARLY_DRIVER_MODULE(arm_doorbell, simplebus, arm_doorbell_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(arm_doorbell, 1);
Index: sys/arm64/scmi/mmio_sram.c
===================================================================
--- /dev/null
+++ sys/arm64/scmi/mmio_sram.c
@@ -0,0 +1,159 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "mmio_sram_if.h"
+
+#define dprintf(fmt, ...)
+
+static struct resource_spec mmio_sram_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+struct mmio_sram_softc {
+ struct simplebus_softc simplebus_sc;
+ struct resource *res[1];
+ device_t dev;
+};
+
+static int
+mmio_sram_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "mmio-sram"))
+ return (ENXIO);
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ device_set_desc(dev, "MMIO SRAM");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+mmio_sram_attach(device_t dev)
+{
+ struct mmio_sram_softc *sc;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ if (bus_alloc_resources(dev, mmio_sram_spec, sc->res) != 0) {
+ device_printf(dev, "Can't allocate resources for device.\n");
+ return (ENXIO);
+ }
+
+ node = ofw_bus_get_node(dev);
+ if (node == -1)
+ return (ENXIO);
+
+ simplebus_init(dev, node);
+
+ /*
+ * Allow devices to identify.
+ */
+ bus_generic_probe(dev);
+
+ /*
+ * Now walk the OFW tree and attach top-level devices.
+ */
+ for (node = OF_child(node); node > 0; node = OF_peer(node))
+ simplebus_add_device(dev, node, 0, NULL, -1, NULL);
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+mmio_sram_detach(device_t dev)
+{
+
+ return (0);
+}
+
+static uint8_t
+mmio_sram_read_1(device_t dev, bus_size_t offset)
+{
+ struct mmio_sram_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ dprintf("%s: reading from %lx\n", __func__, offset);
+
+ return (bus_read_1(sc->res[0], offset));
+}
+
+static void
+mmio_sram_write_1(device_t dev, bus_size_t offset, uint8_t val)
+{
+ struct mmio_sram_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ dprintf("%s: writing to %lx val %x\n", __func__, offset, val);
+
+ bus_write_1(sc->res[0], offset, val);
+}
+
+static device_method_t mmio_sram_methods[] = {
+ /* Device Interface */
+ DEVMETHOD(device_probe, mmio_sram_probe),
+ DEVMETHOD(device_attach, mmio_sram_attach),
+ DEVMETHOD(device_detach, mmio_sram_detach),
+
+ /* MMIO interface */
+ DEVMETHOD(mmio_sram_read_1, mmio_sram_read_1),
+ DEVMETHOD(mmio_sram_write_1, mmio_sram_write_1),
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(mmio_sram, mmio_sram_driver, mmio_sram_methods,
+ sizeof(struct mmio_sram_softc), simplebus_driver);
+
+EARLY_DRIVER_MODULE(mmio_sram, simplebus, mmio_sram_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(mmio_sram, 1);
Index: sys/arm64/scmi/mmio_sram_if.m
===================================================================
--- /dev/null
+++ sys/arm64/scmi/mmio_sram_if.m
@@ -0,0 +1,44 @@
+#-
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+#include <machine/bus.h>
+
+INTERFACE mmio_sram;
+
+METHOD uint8_t read_1 {
+ device_t dev;
+ bus_size_t offset;
+};
+
+METHOD void write_1 {
+ device_t dev;
+ bus_size_t offset;
+ uint8_t value;
+};
Index: sys/arm64/scmi/scmi.h
===================================================================
--- /dev/null
+++ sys/arm64/scmi/scmi.h
@@ -0,0 +1,82 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_SCMI_SCMI_H_
+#define _ARM64_SCMI_SCMI_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, ...)
+
+/* Shared Memory Transfer. */
+struct scmi_smt_header {
+ uint32_t reserved;
+ uint32_t channel_status;
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR (1 << 1)
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE (1 << 0)
+ uint32_t reserved1[2];
+ uint32_t flags;
+#define SCMI_SHMEM_FLAG_INTR_ENABLED (1 << 0)
+ uint32_t length;
+ uint32_t msg_header;
+ uint8_t msg_payload[0];
+};
+
+#define SMT_HEADER_SIZE sizeof(struct scmi_smt_header)
+
+#define SMT_HEADER_TOKEN_S 18
+#define SMT_HEADER_TOKEN_M (0x3fff << SMT_HEADER_TOKEN_S)
+#define SMT_HEADER_PROTOCOL_ID_S 10
+#define SMT_HEADER_PROTOCOL_ID_M (0xff << SMT_HEADER_PROTOCOL_ID_S)
+#define SMT_HEADER_MESSAGE_TYPE_S 8
+#define SMT_HEADER_MESSAGE_TYPE_M (0x3 << SMT_HEADER_MESSAGE_TYPE_S)
+#define SMT_HEADER_MESSAGE_ID_S 0
+#define SMT_HEADER_MESSAGE_ID_M (0xff << SMT_HEADER_MESSAGE_ID_S)
+
+struct scmi_req {
+ int protocol_id;
+ int message_id;
+ void *in_buf;
+ uint32_t in_size;
+ void *out_buf;
+ uint32_t out_size;
+};
+
+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, void *buf,
+ bus_size_t len);
+
+#endif /* !_ARM64_SCMI_SCMI_H_ */
Index: sys/arm64/scmi/scmi.c
===================================================================
--- /dev/null
+++ sys/arm64/scmi/scmi.c
@@ -0,0 +1,278 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#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/extres/clk/clk.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "arm_doorbell.h"
+
+#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)
+{
+ uint32_t *shmems;
+ phandle_t node;
+ device_t dev;
+ size_t len;
+ int count;
+
+ node = ofw_bus_get_node(sc->dev);
+ if (node <= 0)
+ return (NULL);
+
+ len = OF_getproplen(node, "shmem");
+ if (len <= 0)
+ return (NULL);
+
+ count = len / sizeof(pcell_t);
+ if (index >= count)
+ return (NULL);
+
+ len = OF_getencprop_alloc_multi(node, "shmem", sizeof(*shmems),
+ (void **)&shmems);
+ if (len <= 0) {
+ device_printf(sc->dev, "%s: Can't get shmem node.\n", __func__);
+ return (NULL);
+ }
+
+ dev = OF_device_from_xref(shmems[index]);
+ if (dev == NULL)
+ device_printf(sc->dev, "%s: Can't get shmem device.\n",
+ __func__);
+
+ OF_prop_free(shmems);
+
+ 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;
+
+ bzero(&hdr, sizeof(struct scmi_smt_header));
+
+ SCMI_ASSERT_LOCKED(sc);
+
+ /* Read header */
+ scmi_shmem_read(sc->tx_shmem, 0, (void *)&hdr, SMT_HEADER_SIZE);
+
+ if ((hdr.channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) == 0)
+ return (1);
+
+ /* Update header */
+ 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;
+ hdr.length = sizeof(hdr.msg_header) + req->in_size;
+ hdr.flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
+
+ /* Write header */
+ scmi_shmem_write(sc->tx_shmem, 0, (void *)&hdr, SMT_HEADER_SIZE);
+
+ /* Write request */
+ 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);
+
+ /* Read header. */
+ scmi_shmem_read(sc->tx_shmem, 0, (void *)&hdr, SMT_HEADER_SIZE);
+
+ /* Read response */
+ scmi_shmem_read(sc->tx_shmem, SMT_HEADER_SIZE, req->out_buf,
+ req->out_size);
+
+ return (0);
+}
+
+int
+scmi_request(device_t dev, struct scmi_req *req)
+{
+ struct scmi_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ SCMI_LOCK(sc);
+ error = scmi_request_locked(sc, req);
+ SCMI_UNLOCK(sc);
+
+ 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
+scmi_attach(device_t dev)
+{
+ struct scmi_softc *sc;
+ phandle_t node;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ node = ofw_bus_get_node(dev);
+ if (node == -1)
+ return (ENXIO);
+
+ sc->tx_shmem = scmi_get_shmem(sc, 0);
+ if (sc->tx_shmem == NULL) {
+ device_printf(dev, "TX shmem dev not found.\n");
+ 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);
+
+ /*
+ * Allow devices to identify.
+ */
+ bus_generic_probe(dev);
+
+ /*
+ * Now walk the OFW tree and attach top-level devices.
+ */
+ for (node = OF_child(node); node > 0; node = OF_peer(node))
+ simplebus_add_device(dev, node, 0, NULL, -1, NULL);
+
+ error = bus_generic_attach(dev);
+
+ return (error);
+}
+
+static int
+scmi_detach(device_t dev)
+{
+
+ return (0);
+}
+
+static device_method_t scmi_methods[] = {
+ DEVMETHOD(device_probe, scmi_probe),
+ DEVMETHOD(device_attach, scmi_attach),
+ DEVMETHOD(device_detach, scmi_detach),
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(scmi, scmi_driver, scmi_methods, sizeof(struct scmi_softc),
+ simplebus_driver);
+
+EARLY_DRIVER_MODULE(scmi, firmware, scmi_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(scmi, 1);
Index: sys/arm64/scmi/scmi_clk.h
===================================================================
--- /dev/null
+++ sys/arm64/scmi/scmi_clk.h
@@ -0,0 +1,116 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_SCMI_SCMI_CLK_H_
+#define _ARM64_SCMI_SCMI_CLK_H_
+
+/*
+ * SCMI Clock Protocol
+ */
+
+struct scmi_clk_protocol_attrs_out {
+ int32_t status;
+ uint32_t attributes;
+#define CLK_ATTRS_NCLOCKS_S 0
+#define CLK_ATTRS_NCLOCKS_M (0xffff << CLK_ATTRS_NCLOCKS_S)
+};
+
+struct scmi_clk_attrs_in {
+ uint32_t clock_id;
+};
+
+struct scmi_clk_attrs_out {
+ int32_t status;
+ uint32_t attributes;
+#define CLK_ATTRS_RATE_CHANGE_NOTIFY_SUPP (1 << 31)
+#define CLK_ATTRS_RATE_REQ_CHANGE_NOTIFY_SUPP (1 << 30)
+#define CLK_ATTRS_EXT_CLK_NAME (1 << 29)
+#define CLK_ATTRS_ENABLED (1 << 0)
+ uint8_t clock_name[16]; /* only if attrs bit 29 unset */
+ uint32_t clock_enable_delay; /* worst case */
+};
+
+struct scmi_clk_name_get_in {
+ uint32_t clock_id;
+};
+
+struct scmi_clk_name_get_out {
+ int32_t status;
+ uint32_t flags;
+ uint8_t name[64];
+};
+
+enum scmi_clock_message_id {
+ SCMI_CLOCK_ATTRIBUTES = 0x3,
+ SCMI_CLOCK_RATE_SET = 0x5,
+ SCMI_CLOCK_RATE_GET = 0x6,
+ SCMI_CLOCK_CONFIG_SET = 0x7,
+ SCMI_CLOCK_NAME_GET = 0x8,
+};
+
+#define SCMI_CLK_RATE_ASYNC_NOTIFY (1 << 0)
+#define SCMI_CLK_RATE_ASYNC_NORESP (1 << 0 | 1 << 1)
+#define SCMI_CLK_RATE_ROUND_DOWN 0
+#define SCMI_CLK_RATE_ROUND_UP (1 << 2)
+#define SCMI_CLK_RATE_ROUND_CLOSEST (1 << 3)
+
+struct scmi_clk_state_in {
+ uint32_t clock_id;
+ uint32_t attributes;
+};
+
+struct scmi_clk_state_out {
+ int32_t status;
+};
+
+struct scmi_clk_rate_get_in {
+ uint32_t clock_id;
+};
+
+struct scmi_clk_rate_get_out {
+ int32_t status;
+ uint32_t rate_lsb;
+ uint32_t rate_msb;
+};
+
+struct scmi_clk_rate_set_in {
+ uint32_t flags;
+ uint32_t clock_id;
+ uint32_t rate_lsb;
+ uint32_t rate_msb;
+};
+
+struct scmi_clk_rate_set_out {
+ int32_t status;
+};
+
+#endif /* !_ARM64_SCMI_SCMI_CLK_H_ */
Index: sys/arm64/scmi/scmi_clk.c
===================================================================
--- /dev/null
+++ sys/arm64/scmi/scmi_clk.c
@@ -0,0 +1,434 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "scmi.h"
+#include "scmi_protocols.h"
+#include "scmi_clk.h"
+
+struct scmi_clk_softc {
+ device_t dev;
+ device_t scmi;
+ struct clkdom *clkdom;
+};
+
+struct scmi_clknode_softc {
+ device_t dev;
+ int clock_id;
+};
+
+static int
+scmi_clk_get_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t *rate)
+{
+ struct scmi_clk_rate_get_out out;
+ struct scmi_clk_rate_get_in in;
+ struct scmi_req req;
+ int error;
+
+ req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
+ req.message_id = SCMI_CLOCK_RATE_GET;
+ req.in_buf = ∈
+ req.in_size = sizeof(struct scmi_clk_rate_get_in);
+ req.out_buf = &out;
+ req.out_size = sizeof(struct scmi_clk_rate_get_out);
+
+ in.clock_id = clk_id;
+
+ error = scmi_request(sc->scmi, &req);
+ if (error != 0)
+ return (error);
+
+ if (out.status != 0)
+ return (ENXIO);
+
+ *rate = out.rate_lsb | ((uint64_t)out.rate_msb << 32);
+
+ return (0);
+}
+
+static int
+scmi_clk_set_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t rate)
+{
+ struct scmi_clk_rate_set_out out;
+ struct scmi_clk_rate_set_in in;
+ struct scmi_req req;
+ int error;
+
+ req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
+ req.message_id = SCMI_CLOCK_RATE_SET;
+ req.in_buf = ∈
+ req.in_size = sizeof(struct scmi_clk_rate_set_in);
+ req.out_buf = &out;
+ req.out_size = sizeof(struct scmi_clk_rate_set_out);
+
+ in.clock_id = clk_id;
+ in.flags = SCMI_CLK_RATE_ROUND_CLOSEST;
+ in.rate_lsb = (uint32_t)rate;
+ in.rate_msb = (uint32_t)(rate >> 32);
+
+ error = scmi_request(sc->scmi, &req);
+ if (error != 0)
+ return (error);
+
+ if (out.status != 0)
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+scmi_clk_gate(struct scmi_clk_softc *sc, int clk_id, int enable)
+{
+ struct scmi_clk_state_out out;
+ struct scmi_clk_state_in in;
+ struct scmi_req req;
+ int error;
+
+ req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
+ req.message_id = SCMI_CLOCK_CONFIG_SET;
+ req.in_buf = ∈
+ req.in_size = sizeof(struct scmi_clk_state_in);
+ req.out_buf = &out;
+ req.out_size = sizeof(struct scmi_clk_state_out);
+
+ in.clock_id = clk_id;
+ in.attributes = enable;
+
+ error = scmi_request(sc->scmi, &req);
+ if (error != 0)
+ return (error);
+
+ if (out.status != 0)
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+scmi_clknode_init(struct clknode *clk, device_t dev)
+{
+
+ clknode_init_parent_idx(clk, 0);
+
+ return (0);
+}
+
+static int
+scmi_clknode_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+
+ return (0);
+}
+
+static int
+scmi_clknode_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct scmi_clknode_softc *clk_sc;
+ struct scmi_clk_softc *sc;
+
+ clk_sc = clknode_get_softc(clk);
+ sc = device_get_softc(clk_sc->dev);
+
+ dprintf("%s: %ld\n", __func__, *fout);
+
+ scmi_clk_set_rate(sc, clk_sc->clock_id, *fout);
+
+ *stop = 1;
+
+ return (0);
+}
+
+static clknode_method_t scmi_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, scmi_clknode_init),
+ CLKNODEMETHOD(clknode_recalc_freq, scmi_clknode_recalc_freq),
+ CLKNODEMETHOD(clknode_set_freq, scmi_clknode_set_freq),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(scmi_clknode, scmi_clknode_class, scmi_clknode_methods,
+ sizeof(struct scmi_clknode_softc), clknode_class);
+
+static int
+scmi_clk_add_node(struct scmi_clk_softc *sc, int index, char *clock_name)
+{
+ struct scmi_clknode_softc *clk_sc;
+ struct clknode_init_def def;
+ struct clknode *clk;
+
+ memset(&def, 0, sizeof(def));
+ def.id = index;
+ def.name = clock_name;
+ def.parent_names = NULL;
+ def.parent_cnt = 0;
+
+ clk = clknode_create(sc->clkdom, &scmi_clknode_class, &def);
+ if (clk == NULL) {
+ device_printf(sc->dev, "Cannot create clknode.\n");
+ return (ENXIO);
+ }
+
+ clk_sc = clknode_get_softc(clk);
+ clk_sc->dev = sc->dev;
+ clk_sc->clock_id = index;
+
+ if (clknode_register(sc->clkdom, clk) == NULL) {
+ device_printf(sc->dev, "Could not register clock '%s'.\n",
+ def.name);
+ return (ENXIO);
+ }
+
+ device_printf(sc->dev, "Clock '%s' registered.\n", def.name);
+
+ return (0);
+}
+
+static int
+scmi_clk_get_name(struct scmi_clk_softc *sc, int index, char **result)
+{
+ struct scmi_clk_name_get_out out;
+ struct scmi_clk_name_get_in in;
+ struct scmi_req req;
+ char *clock_name;
+ int error;
+
+ req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
+ req.message_id = SCMI_CLOCK_NAME_GET;
+ req.in_buf = ∈
+ req.in_size = sizeof(struct scmi_clk_name_get_in);
+ req.out_buf = &out;
+ req.out_size = sizeof(struct scmi_clk_name_get_out);
+
+ in.clock_id = index;
+
+ error = scmi_request(sc->scmi, &req);
+ if (error != 0)
+ return (error);
+
+ if (out.status != 0)
+ return (ENXIO);
+
+ clock_name = malloc(sizeof(out.name), M_DEVBUF, M_WAITOK);
+ strncpy(clock_name, out.name, sizeof(out.name));
+
+ *result = clock_name;
+
+ return (0);
+}
+
+static int
+scmi_clk_attrs(struct scmi_clk_softc *sc, int index)
+{
+ struct scmi_clk_attrs_out out;
+ struct scmi_clk_attrs_in in;
+ struct scmi_req req;
+ int error;
+ char *clock_name;
+
+ req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
+ req.message_id = SCMI_CLOCK_ATTRIBUTES;
+ req.in_buf = ∈
+ req.in_size = sizeof(struct scmi_clk_attrs_in);
+ req.out_buf = &out;
+ req.out_size = sizeof(struct scmi_clk_attrs_out);
+
+ in.clock_id = index;
+
+ error = scmi_request(sc->scmi, &req);
+ if (error != 0)
+ return (error);
+
+ if (out.status != 0)
+ return (ENXIO);
+
+ if (out.attributes & CLK_ATTRS_EXT_CLK_NAME) {
+ error = scmi_clk_get_name(sc, index, &clock_name);
+ if (error)
+ return (error);
+ } else {
+ clock_name = malloc(sizeof(out.clock_name), M_DEVBUF, M_WAITOK);
+ strncpy(clock_name, out.clock_name, sizeof(out.clock_name));
+ }
+
+ error = scmi_clk_add_node(sc, index, clock_name);
+
+ return (error);
+}
+
+static int
+scmi_clk_discover(struct scmi_clk_softc *sc)
+{
+ struct scmi_clk_protocol_attrs_out out;
+ struct scmi_req req;
+ int nclocks;
+ int failing;
+ int error;
+ int i;
+
+ req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
+ req.message_id = SCMI_PROTOCOL_ATTRIBUTES;
+ req.in_buf = NULL;
+ req.in_size = 0;
+ req.out_buf = &out;
+ req.out_size = sizeof(struct scmi_clk_protocol_attrs_out);
+
+ error = scmi_request(sc->scmi, &req);
+ if (error != 0)
+ return (error);
+
+ if (out.status != 0)
+ return (ENXIO);
+
+ nclocks = (out.attributes & CLK_ATTRS_NCLOCKS_M) >>
+ CLK_ATTRS_NCLOCKS_S;
+
+ device_printf(sc->dev, "Found %d clocks.\n", nclocks);
+
+ failing = 0;
+
+ for (i = 0; i < nclocks; i++) {
+ error = scmi_clk_attrs(sc, i);
+ if (error) {
+ device_printf(sc->dev,
+ "Could not process clock index %d.\n", i);
+ failing++;
+ }
+ }
+
+ if (failing == nclocks)
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+scmi_clk_init(struct scmi_clk_softc *sc)
+{
+ int error;
+
+ /* Create clock domain */
+ sc->clkdom = clkdom_create(sc->dev);
+ if (sc->clkdom == NULL)
+ return (ENXIO);
+
+ error = scmi_clk_discover(sc);
+ if (error) {
+ device_printf(sc->dev, "Could not discover clocks.\n");
+ return (ENXIO);
+ }
+
+ error = clkdom_finit(sc->clkdom);
+ if (error) {
+ device_printf(sc->dev, "Failed to init clock domain.\n");
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+scmi_clk_probe(device_t dev)
+{
+ phandle_t node;
+ uint32_t reg;
+ int error;
+
+ node = ofw_bus_get_node(dev);
+
+ error = OF_getencprop(node, "reg", ®, sizeof(uint32_t));
+ if (error < 0)
+ return (ENXIO);
+
+ if (reg != SCMI_PROTOCOL_ID_CLOCK)
+ return (ENXIO);
+
+ device_set_desc(dev, "SCMI Clock Management Unit");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+scmi_clk_attach(device_t dev)
+{
+ struct scmi_clk_softc *sc;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->scmi = device_get_parent(dev);
+
+ node = ofw_bus_get_node(sc->dev);
+
+ OF_device_register_xref(OF_xref_from_node(node), sc->dev);
+
+ scmi_clk_init(sc);
+
+ return (0);
+}
+
+static int
+scmi_clk_detach(device_t dev)
+{
+
+ return (0);
+}
+
+static device_method_t scmi_clk_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, scmi_clk_probe),
+ DEVMETHOD(device_attach, scmi_clk_attach),
+ DEVMETHOD(device_detach, scmi_clk_detach),
+ DEVMETHOD_END
+};
+
+static driver_t scmi_clk_driver = {
+ "scmi_clk",
+ scmi_clk_methods,
+ sizeof(struct scmi_clk_softc),
+};
+
+EARLY_DRIVER_MODULE(scmi_clk, scmi, scmi_clk_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(scmi_clk, 1);
Index: sys/arm64/scmi/scmi_protocols.h
===================================================================
--- /dev/null
+++ sys/arm64/scmi/scmi_protocols.h
@@ -0,0 +1,63 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_SCMI_SCMI_PROTOCOLS_H_
+#define _ARM64_SCMI_SCMI_PROTOCOLS_H_
+
+enum scmi_std_protocol {
+ SCMI_PROTOCOL_ID_BASE = 0x10,
+ SCMI_PROTOCOL_ID_POWER_DOMAIN = 0x11,
+ SCMI_PROTOCOL_ID_SYSTEM = 0x12,
+ SCMI_PROTOCOL_ID_PERF = 0x13,
+ SCMI_PROTOCOL_ID_CLOCK = 0x14,
+ SCMI_PROTOCOL_ID_SENSOR = 0x15,
+ SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16,
+ SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN = 0x17,
+};
+
+enum scmi_status_code {
+ SCMI_SUCCESS = 0,
+ SCMI_NOT_SUPPORTED = -1,
+ SCMI_INVALID_PARAMETERS = -2,
+ SCMI_DENIED = -3,
+ SCMI_NOT_FOUND = -4,
+ SCMI_OUT_OF_RANGE = -5,
+ SCMI_BUSY = -6,
+ SCMI_COMMS_ERROR = -7,
+ SCMI_GENERIC_ERROR = -8,
+ SCMI_HARDWARE_ERROR = -9,
+ SCMI_PROTOCOL_ERROR = -10,
+};
+
+#define SCMI_PROTOCOL_ATTRIBUTES 0x1
+
+#endif /* !_ARM64_SCMI_SCMI_PROTOCOLS_H_ */
Index: sys/arm64/scmi/scmi_shmem.c
===================================================================
--- /dev/null
+++ sys/arm64/scmi/scmi_shmem.c
@@ -0,0 +1,145 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "mmio_sram_if.h"
+
+#include "scmi.h"
+
+struct shmem_softc {
+ device_t dev;
+ device_t parent;
+ int reg;
+};
+
+static int
+shmem_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "arm,scmi-shmem"))
+ return (ENXIO);
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ device_set_desc(dev, "ARM SCMI Shared Memory driver");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+shmem_attach(device_t dev)
+{
+ struct shmem_softc *sc;
+ phandle_t node;
+ int reg;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->parent = device_get_parent(dev);
+
+ node = ofw_bus_get_node(dev);
+ if (node == -1)
+ return (ENXIO);
+
+ OF_getencprop(node, "reg", ®, sizeof(reg));
+
+ dprintf("%s: reg %x\n", __func__, reg);
+
+ sc->reg = reg;
+
+ OF_device_register_xref(OF_xref_from_node(node), dev);
+
+ return (0);
+}
+
+static int
+shmem_detach(device_t dev)
+{
+
+ return (0);
+}
+
+void
+scmi_shmem_read(device_t dev, bus_size_t offset, void *buf, bus_size_t len)
+{
+ struct shmem_softc *sc;
+ uint8_t *addr;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ addr = (uint8_t *)buf;
+
+ for (i = 0; i < len; i++)
+ addr[i] = MMIO_SRAM_READ_1(sc->parent, sc->reg + offset + i);
+}
+
+void
+scmi_shmem_write(device_t dev, bus_size_t offset, void *buf, bus_size_t len)
+{
+ struct shmem_softc *sc;
+ uint8_t *addr;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ addr = (uint8_t *)buf;
+
+ for (i = 0; i < len; i++)
+ MMIO_SRAM_WRITE_1(sc->parent, sc->reg + offset + i, addr[i]);
+}
+
+static device_method_t shmem_methods[] = {
+ DEVMETHOD(device_probe, shmem_probe),
+ DEVMETHOD(device_attach, shmem_attach),
+ DEVMETHOD(device_detach, shmem_detach),
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(shmem, shmem_driver, shmem_methods, sizeof(struct shmem_softc),
+ simplebus_driver);
+
+EARLY_DRIVER_MODULE(shmem, mmio_sram, shmem_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(scmi, 1);
Index: sys/conf/files.arm64
===================================================================
--- sys/conf/files.arm64
+++ sys/conf/files.arm64
@@ -113,6 +113,13 @@
dev/iommu/busdma_iommu.c optional iommu
dev/iommu/iommu_gas.c optional iommu
+arm64/scmi/arm_doorbell.c optional fdt
+arm64/scmi/mmio_sram.c optional fdt
+arm64/scmi/mmio_sram_if.m optional fdt
+arm64/scmi/scmi.c optional fdt
+arm64/scmi/scmi_clk.c optional fdt
+arm64/scmi/scmi_shmem.c optional fdt
+
crypto/armv8/armv8_crypto.c optional armv8crypto
armv8_crypto_wrap.o optional armv8crypto \
dependency "$S/crypto/armv8/armv8_crypto_wrap.c" \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 18, 11:44 AM (22 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14696877
Default Alt Text
D37316.id113857.diff (47 KB)
Attached To
Mode
D37316: SCMI support
Attached
Detach File
Event Timeline
Log In to Comment