Add a platform driver for the RPMI TEE service group using an SBI MPXY mailbox channel. Select direct synchronous mailbox transfers so RPMI transactions complete in the calling context.
Query mailbox attributes to check the RPMI specification version, TEE service-group identifier and service-group version. Cache the maximum message data size for subsequent service requests.
This establishes the transport state used by later discovery, memory, and notification support.
Signed-off-by: Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com --- drivers/firmware/riscv_rpmi_tee/Makefile | 3 + drivers/firmware/riscv_rpmi_tee/driver.c | 133 +++++++++++++++++++++ drivers/firmware/riscv_rpmi_tee/rpmi_tee_private.h | 26 ++++ 3 files changed, 162 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..d9ae161d241b --- /dev/null +++ b/drivers/firmware/riscv_rpmi_tee/driver.c @@ -0,0 +1,133 @@ +// 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> + +#include "rpmi_tee_private.h" + +/** + * 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"); diff --git a/drivers/firmware/riscv_rpmi_tee/rpmi_tee_private.h b/drivers/firmware/riscv_rpmi_tee/rpmi_tee_private.h new file mode 100644 index 000000000000..b25192c5df00 --- /dev/null +++ b/drivers/firmware/riscv_rpmi_tee/rpmi_tee_private.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _RPMI_TEE_PRIVATE_H +#define _RPMI_TEE_PRIVATE_H + +#include <linux/mailbox_client.h> +#include <linux/types.h> + +/* TEE service group and the services used by this module. */ +#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; +}; + +#endif /* _RPMI_TEE_PRIVATE_H */