From: Etienne Carriere <etienne.carri...@st.com> Basic mailbox inspired from https://patchwork.kernel.org/patch/11166071/.
When sending a message, the mailbox invokes the Cortex-A Arm Trustzone secure monitor with an SMC or HVC instruction providing a function identifier in register R0/X0 defined by the DTB. Signed-off-by: Etienne Carriere <etienne.carri...@st.com> Signed-off-by: Etienne Carriere <etienne.carri...@linaro.org> --- drivers/mailbox/Kconfig | 8 +++ drivers/mailbox/Makefile | 1 + drivers/mailbox/arm-smc-mbox.c | 123 +++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 drivers/mailbox/arm-smc-mbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index dd4b0ac0c3..599d1df1ae 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -47,4 +47,12 @@ config ZYNQMP_IPI help This enables support for the Xilinx ZynqMP Inter Processor Interrupt communication controller. + +config ARM_SMC_MAILBOX + bool "Enable Arm SMC mailbox support" + depends on DM_MAILBOX && ARM_SMCCC + default y + help + Mailbox notification through an Arm SMC or HVC calls. + endmenu diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index d2ace8cd21..7a56a454b8 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 2016, NVIDIA CORPORATION. # +obj-$(CONFIG_ARM_SMC_MAILBOX) += arm-smc-mbox.o obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o diff --git a/drivers/mailbox/arm-smc-mbox.c b/drivers/mailbox/arm-smc-mbox.c new file mode 100644 index 0000000000..d379da490a --- /dev/null +++ b/drivers/mailbox/arm-smc-mbox.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019, Linaro Limited + */ + +#define LOG_CATEGORY UCLASS_MAILBOX + +#include <common.h> +#include <dm.h> +#include <mailbox-uclass.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <linux/arm-smccc.h> +#include <linux/compat.h> + +#define ARM_SMC_METHOD 0 +#define ARM_HVC_METHOD 1 + +typedef void (invoke_fn_t)(unsigned long); + +struct smc_pdata { + unsigned long func_id; + invoke_fn_t *invoke_fn; +}; + +/* Simple wrapper functions to be able to use a function pointer */ +static void smccc_smc(unsigned long a0) +{ + struct arm_smccc_res res; + + arm_smccc_smc(a0, 0, 0, 0, 0, 0, 0, 0, &res); +} + +static void smccc_hvc(unsigned long a0) +{ + struct arm_smccc_res res; + + arm_smccc_hvc(a0, 0, 0, 0, 0, 0, 0, 0, &res); +} + +static int smc_mbox_send(struct mbox_chan *chan, const void *data) +{ + struct smc_pdata *pdata = dev_get_plat(chan->dev); + + /* + * This mailbox invokes secure world for a channel event. + * Message is already in the channel's shared memory. + */ + pdata->invoke_fn(pdata->func_id); + + return 0; +} + +static int smc_mbox_recv(struct mbox_chan *chan, void *data) +{ + /* Mbox owner already got the return message from shared memory */ + return 0; +} + +static int smc_mbox_request(struct mbox_chan *chan) +{ + return 0; +} + +static int smc_mbox_rfree(struct mbox_chan *chan) +{ + return 0; +} + +static int smc_mbox_of_xlate(struct mbox_chan *chan, + struct ofnode_phandle_args *args) +{ + if (args->args_count) + dev_warn(chan->dev, "Expect no argument to smc-mbox cells\n"); + + chan->id = 0; + + return 0; +} + +static int smc_mbox_ofdata_to_platdata(struct udevice *dev) +{ + ulong compat_data = dev_get_driver_data(dev); + struct smc_pdata *pdata = dev_get_plat(dev); + u32 func_id; + + if (dev_read_u32(dev, "arm,func-id", &func_id)) { + dev_err(dev, "Missing property arm,func-id\n"); + return -EINVAL; + } + + pdata->func_id = func_id; + + if (compat_data == ARM_SMC_METHOD) + pdata->invoke_fn = smccc_smc; + else + pdata->invoke_fn = smccc_hvc; + + return 0; +} + +static const struct udevice_id smc_mbox_ids[] = { + { .compatible = "arm,smc-mbox", .data = ARM_SMC_METHOD, }, + { .compatible = "arm,hvc-mbox", .data = ARM_HVC_METHOD, }, + { } +}; + +struct mbox_ops smc_mbox_ops = { + .of_xlate = smc_mbox_of_xlate, + .request = smc_mbox_request, + .rfree = smc_mbox_rfree, + .send = smc_mbox_send, + .recv = smc_mbox_recv, +}; + +U_BOOT_DRIVER(smc_mbox) = { + .name = "arm_smc_mbox", + .id = UCLASS_MAILBOX, + .of_match = smc_mbox_ids, + .of_to_plat = smc_mbox_ofdata_to_platdata, + .plat_auto = sizeof(struct smc_pdata), + .ops = &smc_mbox_ops, +}; -- 2.17.1