diff --git a/sys/dev/firmware/arm/scmi.h b/sys/dev/firmware/arm/scmi.h
--- a/sys/dev/firmware/arm/scmi.h
+++ b/sys/dev/firmware/arm/scmi.h
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ruslan Bukin
+ * Copyright (c) 2023 Arm Ltd
*
* This work was supported by Innovate UK project 105694, "Digital Security
* by Design (DSbD) Technology Platform Prototype".
@@ -39,41 +40,25 @@
#define dprintf(fmt, ...)
+#define SCMI_MSG_HDR_SIZE (sizeof(uint32_t))
+
+enum scmi_chan {
+ SCMI_CHAN_A2P,
+ SCMI_CHAN_P2A,
+ SCMI_CHAN_MAX
+};
+
struct scmi_softc {
struct simplebus_softc simplebus_sc;
device_t dev;
- device_t tx_shmem;
+ device_t a2p_dev;
struct mtx mtx;
};
-/* 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;
+ uint32_t msg_header;
const void *in_buf;
uint32_t in_size;
void *out_buf;
@@ -85,9 +70,4 @@
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,
- bus_size_t len);
-
#endif /* !_ARM64_SCMI_SCMI_H_ */
diff --git a/sys/dev/firmware/arm/scmi.c b/sys/dev/firmware/arm/scmi.c
--- a/sys/dev/firmware/arm/scmi.c
+++ b/sys/dev/firmware/arm/scmi.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ruslan Bukin
+ * Copyright (c) 2023 Arm Ltd
*
* This work was supported by Innovate UK project 105694, "Digital Security
* by Design (DSbD) Technology Platform Prototype".
@@ -46,84 +47,62 @@
#include "scmi.h"
#include "scmi_protocols.h"
+#include "scmi_shmem.h"
-static device_t
-scmi_get_shmem(struct scmi_softc *sc, int index)
-{
- phandle_t *shmems;
- phandle_t node;
- device_t dev;
- size_t len;
-
- node = ofw_bus_get_node(sc->dev);
- if (node <= 0)
- 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);
- }
+#define SCMI_HDR_TOKEN_S 18
+#define SCMI_HDR_TOKEN_BF (0x3fff)
+#define SCMI_HDR_TOKEN_M (SCMI_HDR_TOKEN_BF << SCMI_HDR_TOKEN_S)
- if (index >= len) {
- OF_prop_free(shmems);
- return (NULL);
- }
+#define SCMI_HDR_PROTOCOL_ID_S 10
+#define SCMI_HDR_PROTOCOL_ID_BF (0xff)
+#define SCMI_HDR_PROTOCOL_ID_M \
+ (SCMI_HDR_PROTOCOL_ID_BF << SCMI_HDR_PROTOCOL_ID_S)
- dev = OF_device_from_xref(shmems[index]);
- if (dev == NULL)
- device_printf(sc->dev, "%s: Can't get shmem device.\n",
- __func__);
+#define SCMI_HDR_MESSAGE_TYPE_S 8
+#define SCMI_HDR_MESSAGE_TYPE_BF (0x3)
+#define SCMI_HDR_MESSAGE_TYPE_M \
+ (SCMI_HDR_MESSAGE_TYPE_BF << SCMI_HDR_MESSAGE_TYPE_S)
- OF_prop_free(shmems);
+#define SCMI_HDR_MESSAGE_ID_S 0
+#define SCMI_HDR_MESSAGE_ID_BF (0xff)
+#define SCMI_HDR_MESSAGE_ID_M \
+ (SCMI_HDR_MESSAGE_ID_BF << SCMI_HDR_MESSAGE_ID_S)
- return (dev);
-}
+#define SCMI_MSG_TYPE_CMD 0
+#define SCMI_MSG_TYPE_DRESP 2
+#define SCMI_MSG_TYPE_NOTIF 3
static int
scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req)
{
- struct scmi_smt_header hdr;
+ uint32_t reply_header;
int ret;
- bzero(&hdr, sizeof(struct scmi_smt_header));
-
SCMI_ASSERT_LOCKED(sc);
- /* Read header */
- scmi_shmem_read(sc->tx_shmem, 0, &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;
+ req->msg_header = req->message_id << SCMI_HDR_MESSAGE_ID_S;
/* TODO: Allocate a token */
- 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, &hdr, SMT_HEADER_SIZE);
+ req->msg_header |= SCMI_MSG_TYPE_CMD << SCMI_HDR_MESSAGE_TYPE_S;
+ req->msg_header |= req->protocol_id << SCMI_HDR_PROTOCOL_ID_S;
- /* Write request */
- scmi_shmem_write(sc->tx_shmem, SMT_HEADER_SIZE, req->in_buf,
- req->in_size);
+ ret = scmi_shmem_prepare_msg(sc->a2p_dev, req);
+ if (ret != 0)
+ return (ret);
ret = SCMI_XFER_MSG(sc->dev);
if (ret != 0)
return (ret);
/* Read header. */
- scmi_shmem_read(sc->tx_shmem, 0, &hdr, SMT_HEADER_SIZE);
+ ret = scmi_shmem_read_msg_header(sc->a2p_dev, &reply_header);
+ if (ret != 0)
+ return (ret);
- /* Read response */
- scmi_shmem_read(sc->tx_shmem, SMT_HEADER_SIZE, req->out_buf,
- req->out_size);
+ if (reply_header != req->msg_header)
+ return (EPROTO);
- return (0);
+ return (scmi_shmem_read_msg_payload(sc->a2p_dev, req->out_buf,
+ req->out_size));
}
int
@@ -155,9 +134,9 @@
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");
+ sc->a2p_dev = scmi_shmem_get(dev, node, SCMI_CHAN_A2P);
+ if (sc->a2p_dev == NULL) {
+ device_printf(dev, "A2P shmem dev not found.\n");
return (ENXIO);
}
diff --git a/sys/dev/firmware/arm/scmi.h b/sys/dev/firmware/arm/scmi_shmem.h
copy from sys/dev/firmware/arm/scmi.h
copy to sys/dev/firmware/arm/scmi_shmem.h
--- a/sys/dev/firmware/arm/scmi.h
+++ b/sys/dev/firmware/arm/scmi_shmem.h
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ruslan Bukin
+ * Copyright (c) 2023 Arm Ltd
*
* This work was supported by Innovate UK project 105694, "Digital Security
* by Design (DSbD) Technology Platform Prototype".
@@ -28,23 +29,8 @@
* SUCH DAMAGE.
*/
-#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;
-};
+#ifndef _ARM64_SCMI_SCMI_SHMEM_H_
+#define _ARM64_SCMI_SCMI_SHMEM_H_
/* Shared Memory Transfer. */
struct scmi_smt_header {
@@ -60,34 +46,25 @@
uint8_t msg_payload[0];
};
-#define SMT_HEADER_SIZE sizeof(struct scmi_smt_header)
+#define SMT_SIZE_HEADER 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)
+#define SMT_OFFSET_CHAN_STATUS \
+ __offsetof(struct scmi_smt_header, channel_status)
+#define SMT_SIZE_CHAN_STATUS sizeof(uint32_t)
-struct scmi_req {
- int protocol_id;
- int message_id;
- const void *in_buf;
- uint32_t in_size;
- void *out_buf;
- uint32_t out_size;
-};
+#define SMT_OFFSET_LENGTH \
+ __offsetof(struct scmi_smt_header, length)
+#define SMT_SIZE_LENGTH sizeof(uint32_t)
-DECLARE_CLASS(scmi_driver);
+#define SMT_OFFSET_MSG_HEADER \
+ __offsetof(struct scmi_smt_header, msg_header)
+#define SMT_SIZE_MSG_HEADER sizeof(uint32_t)
-int scmi_attach(device_t dev);
-int scmi_request(device_t dev, struct scmi_req *req);
+struct scmi_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,
- bus_size_t len);
+device_t scmi_shmem_get(device_t sdev, phandle_t node, int index);
+int scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req);
+int scmi_shmem_read_msg_header(device_t dev, uint32_t *msg_header);
+int scmi_shmem_read_msg_payload(device_t dev, uint8_t *buf, uint32_t buf_len);
-#endif /* !_ARM64_SCMI_SCMI_H_ */
+#endif /* !_ARM64_SCMI_SCMI_SHMEM_H_ */
diff --git a/sys/dev/firmware/arm/scmi_shmem.c b/sys/dev/firmware/arm/scmi_shmem.c
--- a/sys/dev/firmware/arm/scmi_shmem.c
+++ b/sys/dev/firmware/arm/scmi_shmem.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ruslan Bukin
+ * Copyright (c) 2023 Arm Ltd
*
* This work was supported by Innovate UK project 105694, "Digital Security
* by Design (DSbD) Technology Platform Prototype".
@@ -41,6 +42,7 @@
#include "mmio_sram_if.h"
+#include "scmi_shmem.h"
#include "scmi.h"
struct shmem_softc {
@@ -49,6 +51,14 @@
int reg;
};
+static void scmi_shmem_read(device_t, bus_size_t, void *, bus_size_t);
+static void scmi_shmem_write(device_t, bus_size_t, const void *,
+ bus_size_t);
+
+static int shmem_probe(device_t);
+static int shmem_attach(device_t);
+static int shmem_detach(device_t);
+
static int
shmem_probe(device_t dev)
{
@@ -97,7 +107,7 @@
return (0);
}
-void
+static void
scmi_shmem_read(device_t dev, bus_size_t offset, void *buf, bus_size_t len)
{
struct shmem_softc *sc;
@@ -112,7 +122,7 @@
addr[i] = MMIO_SRAM_READ_1(sc->parent, sc->reg + offset + i);
}
-void
+static void
scmi_shmem_write(device_t dev, bus_size_t offset, const void *buf,
bus_size_t len)
{
@@ -128,6 +138,107 @@
MMIO_SRAM_WRITE_1(sc->parent, sc->reg + offset + i, addr[i]);
}
+device_t
+scmi_shmem_get(device_t dev, phandle_t node, int index)
+{
+ phandle_t *shmems;
+ device_t shmem_dev;
+ size_t len;
+
+ len = OF_getencprop_alloc_multi(node, "shmem", sizeof(*shmems),
+ (void **)&shmems);
+ if (len <= 0) {
+ device_printf(dev, "%s: Can't get shmem node.\n", __func__);
+ return (NULL);
+ }
+
+ if (index >= len) {
+ OF_prop_free(shmems);
+ return (NULL);
+ }
+
+ shmem_dev = OF_device_from_xref(shmems[index]);
+ if (shmem_dev == NULL)
+ device_printf(dev, "%s: Can't get shmem device.\n",
+ __func__);
+
+ OF_prop_free(shmems);
+
+ return (shmem_dev);
+}
+
+int
+scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req)
+{
+ struct scmi_smt_header hdr = {};
+ uint32_t channel_status;
+
+ /* Read channel status */
+ scmi_shmem_read(dev, SMT_OFFSET_CHAN_STATUS, &channel_status,
+ SMT_SIZE_CHAN_STATUS);
+ if ((channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) == 0) {
+ device_printf(dev, "Shmem channel busy. Abort !.\n");
+ return (1);
+ }
+
+ /* Update header */
+ hdr.channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr.msg_header = htole32(req->msg_header);
+ hdr.length = htole32(sizeof(req->msg_header) + req->in_size);
+ hdr.flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
+
+ /* Write header */
+ scmi_shmem_write(dev, 0, &hdr, SMT_SIZE_HEADER);
+
+ /* Write request payload if any */
+ if (req->in_size)
+ scmi_shmem_write(dev, SMT_SIZE_HEADER, req->in_buf,
+ req->in_size);
+
+ return (0);
+}
+
+int
+scmi_shmem_read_msg_header(device_t dev, uint32_t *msg_header)
+{
+ uint32_t length, header;
+
+ /* Read and check length. */
+ scmi_shmem_read(dev, SMT_OFFSET_LENGTH, &length, SMT_SIZE_LENGTH);
+ if (le32toh(length) < sizeof(header))
+ return (EINVAL);
+
+ /* Read header. */
+ scmi_shmem_read(dev, SMT_OFFSET_MSG_HEADER, &header,
+ SMT_SIZE_MSG_HEADER);
+
+ *msg_header = le32toh(header);
+
+ return (0);
+}
+
+int
+scmi_shmem_read_msg_payload(device_t dev, uint8_t *buf, uint32_t buf_len)
+{
+ uint32_t length, payld_len;
+
+ /* Read length. */
+ scmi_shmem_read(dev, SMT_OFFSET_LENGTH, &length, SMT_SIZE_LENGTH);
+ payld_len = le32toh(length) - SCMI_MSG_HDR_SIZE;
+
+ if (payld_len > buf_len) {
+ device_printf(dev,
+ "RX payload %dbytes exceeds buflen %dbytes. Truncate.\n",
+ payld_len, buf_len);
+ payld_len = buf_len;
+ }
+
+ /* Read response payload */
+ scmi_shmem_read(dev, SMT_SIZE_HEADER, buf, payld_len);
+
+ return (0);
+}
+
static device_method_t shmem_methods[] = {
DEVMETHOD(device_probe, shmem_probe),
DEVMETHOD(device_attach, shmem_attach),