[PATCH RFC 05/10] firmware: add RPMI TEE transport core
Amirreza Zarrabi
amirreza.zarrabi at oss.qualcomm.com
Mon Sep 28 20:16:56 PDT 2026
Add the RISC-V RPMI TEE platform driver and bind it to a direct
synchronous mailbox channel via tx_sync.
Before retaining the channel, validate the RPMI spec version, the
TEE service-group identifier and version, and cache the negotiated
maximum message data size, so later discovery, memory, and
notification support can rely on a checked transport.
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi at oss.qualcomm.com>
---
drivers/firmware/riscv_rpmi_tee/Makefile | 3 +
drivers/firmware/riscv_rpmi_tee/driver.c | 144 +++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+)
diff --git a/drivers/firmware/riscv_rpmi_tee/Makefile b/drivers/firmware/riscv_rpmi_tee/Makefile
index d80ab5bc9dc4..8984127535ed 100644
--- a/drivers/firmware/riscv_rpmi_tee/Makefile
+++ b/drivers/firmware/riscv_rpmi_tee/Makefile
@@ -3,3 +3,6 @@
rpmi-tee-bus-y = bus.o
rpmi-tee-core-objs := $(rpmi-tee-bus-y)
obj-$(CONFIG_RISCV_RPMI_TEE_TRANSPORT) = rpmi-tee-core.o
+rpmi-tee-driver-y = driver.o
+rpmi-tee-module-objs := $(rpmi-tee-driver-y)
+obj-$(CONFIG_RISCV_RPMI_TEE_TRANSPORT) += rpmi-tee-module.o
diff --git a/drivers/firmware/riscv_rpmi_tee/driver.c b/drivers/firmware/riscv_rpmi_tee/driver.c
new file mode 100644
index 000000000000..633dba116584
--- /dev/null
+++ b/drivers/firmware/riscv_rpmi_tee/driver.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RISC-V RPMI TEE transport
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/mailbox_client.h>
+#include <linux/mailbox/riscv-rpmi-message.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rpmi_tee.h>
+
+#define RPMI_SRVGRP_TEE 0x10
+
+struct rpmi_tee_mbox {
+ struct mbox_client client;
+ struct mbox_chan *chan;
+ u32 max_msg_data_size;
+};
+
+struct rpmi_tee_transport {
+ struct device *dev;
+ struct rpmi_tee_mbox mbox;
+};
+
+/**
+ * rpmi_tee_get_attr() - Get an RPMI mailbox attribute
+ * @priv: RPMI TEE transport
+ * @id: Attribute identifier
+ * @value: Returned attribute value
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int rpmi_tee_get_attr(struct rpmi_tee_transport *priv,
+ enum rpmi_mbox_attribute_id id, u32 *value)
+{
+ struct rpmi_mbox_message msg;
+ int ret;
+
+ rpmi_mbox_init_get_attribute(&msg, id);
+ ret = rpmi_mbox_send_message_sync(priv->mbox.chan, &msg);
+ if (ret)
+ return ret;
+
+ *value = msg.attr.value;
+
+ return 0;
+}
+
+/* Validate the RPMI mailbox transport and cache its message size. */
+static int rpmi_tee_check_transport(struct rpmi_tee_transport *priv)
+{
+ u32 value;
+ int ret;
+
+ ret = rpmi_tee_get_attr(priv, RPMI_MBOX_ATTR_SPEC_VERSION, &value);
+ if (ret)
+ return ret;
+ if (value < RPMI_MKVER(1, 0))
+ return -EPROTONOSUPPORT;
+
+ ret = rpmi_tee_get_attr(priv, RPMI_MBOX_ATTR_SERVICEGROUP_ID, &value);
+ if (ret)
+ return ret;
+ if (value != RPMI_SRVGRP_TEE)
+ return -ENODEV;
+
+ ret = rpmi_tee_get_attr(priv, RPMI_MBOX_ATTR_SERVICEGROUP_VERSION,
+ &value);
+ if (ret)
+ return ret;
+ if (value < RPMI_MKVER(1, 0))
+ return -EPROTONOSUPPORT;
+
+ ret = rpmi_tee_get_attr(priv, RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE, &value);
+ if (ret)
+ return ret;
+
+ priv->mbox.max_msg_data_size = value;
+
+ return 0;
+}
+
+static int rpmi_tee_transport_probe(struct platform_device *pdev)
+{
+ struct rpmi_tee_transport *priv;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ platform_set_drvdata(pdev, priv);
+ priv->mbox.client.dev = &pdev->dev;
+ priv->mbox.client.tx_sync = true;
+ priv->mbox.chan = mbox_request_channel(&priv->mbox.client, 0);
+ if (IS_ERR(priv->mbox.chan))
+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->mbox.chan),
+ "failed to request mailbox channel\n");
+
+ ret = rpmi_tee_check_transport(priv);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret,
+ "invalid RPMI TEE mailbox channel\n");
+ goto out_failed;
+ }
+
+ return 0;
+
+out_failed:
+ mbox_free_channel(priv->mbox.chan);
+
+ return ret;
+}
+
+static void rpmi_tee_transport_remove(struct platform_device *pdev)
+{
+ struct rpmi_tee_transport *priv = platform_get_drvdata(pdev);
+
+ mbox_free_channel(priv->mbox.chan);
+}
+
+static const struct of_device_id rpmi_tee_transport_match[] = {
+ { .compatible = "riscv,rpmi-tee" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rpmi_tee_transport_match);
+
+static struct platform_driver rpmi_tee_transport_driver = {
+ .probe = rpmi_tee_transport_probe,
+ .remove = rpmi_tee_transport_remove,
+ .driver = {
+ .name = "riscv-rpmi-tee",
+ .of_match_table = rpmi_tee_transport_match,
+ },
+};
+
+module_platform_driver(rpmi_tee_transport_driver);
+
+MODULE_DESCRIPTION("RISC-V RPMI TEE service group transport");
+MODULE_LICENSE("GPL");
--
2.34.1
More information about the linux-riscv
mailing list