diff options
author | Tanmay Shah <tanmay.shah@amd.com> | 2023-12-04 13:56:17 -0800 |
---|---|---|
committer | Michal Simek <michal.simek@amd.com> | 2023-12-13 08:58:07 +0100 |
commit | cfb41b011dd675564d2ac2f6613e54c999fb8399 (patch) | |
tree | 7ec60d1d7923204890a6bde39a502904f8ccac8c /drivers/mailbox | |
parent | 0e54b473f2ea121972d8c97cc0fb3a608502edfa (diff) | |
download | u-boot-cfb41b011dd675564d2ac2f6613e54c999fb8399.tar.gz u-boot-cfb41b011dd675564d2ac2f6613e54c999fb8399.tar.bz2 u-boot-cfb41b011dd675564d2ac2f6613e54c999fb8399.zip |
mailbox: zynqmp: support smc calls to TF-A
Use SMC calls to TF-A to operate IPI for execution level below 3. For
EL3 use hardcode IPI registers as TF-A isn't available in EL3.
Hence, in EL3 remote and local IPI ids retrieved using xlnx,ipi-id
property are unused.
Signed-off-by: Tanmay Shah <tanmay.shah@amd.com>
Link: https://lore.kernel.org/r/20231204215620.63334-2-tanmay.shah@amd.com
Signed-off-by: Michal Simek <michal.simek@amd.com>
Diffstat (limited to 'drivers/mailbox')
-rw-r--r-- | drivers/mailbox/zynqmp-ipi.c | 88 |
1 files changed, 86 insertions, 2 deletions
diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c index 3e4ec47389..acd0b287db 100644 --- a/drivers/mailbox/zynqmp-ipi.c +++ b/drivers/mailbox/zynqmp-ipi.c @@ -8,9 +8,12 @@ #include <common.h> #include <log.h> #include <asm/io.h> +#include <asm/system.h> #include <dm.h> #include <mailbox-uclass.h> #include <dm/device_compat.h> +#include <dm/of_access.h> +#include <linux/arm-smccc.h> #include <linux/ioport.h> #include <linux/io.h> #include <wait_bit.h> @@ -21,6 +24,43 @@ #define IPI_BIT_MASK_PMU0 0x10000 #define IPI_INT_REG_BASE_APU 0xFF300000 +/* IPI agent ID any */ +#define IPI_ID_ANY 0xFFUL + +/* indicate if ZynqMP IPI mailbox driver uses SMC calls or HVC calls */ +#define USE_SMC 0 + +/* Default IPI SMC function IDs */ +#define SMC_IPI_MAILBOX_OPEN 0x82001000U +#define SMC_IPI_MAILBOX_RELEASE 0x82001001U +#define SMC_IPI_MAILBOX_STATUS_ENQUIRY 0x82001002U +#define SMC_IPI_MAILBOX_NOTIFY 0x82001003U +#define SMC_IPI_MAILBOX_ACK 0x82001004U +#define SMC_IPI_MAILBOX_ENABLE_IRQ 0x82001005U +#define SMC_IPI_MAILBOX_DISABLE_IRQ 0x82001006U + +/* IPI SMC Macros */ + +/* + * Flag to indicate if notification interrupt + * to be disabled. + */ +#define IPI_SMC_ENQUIRY_DIRQ_MASK BIT(0) + +/* + * Flag to indicate if notification interrupt + * to be enabled. + */ +#define IPI_SMC_ACK_EIRQ_MASK BIT(0) + +/* IPI mailbox status */ +#define IPI_MB_STATUS_IDLE 0 +#define IPI_MB_STATUS_SEND_PENDING 1 +#define IPI_MB_STATUS_RECV_PENDING 2 + +#define IPI_MB_CHNL_TX 0 /* IPI mailbox TX channel */ +#define IPI_MB_CHNL_RX 1 /* IPI mailbox RX channel */ + struct ipi_int_regs { u32 trig; /* 0x0 */ u32 obs; /* 0x4 */ @@ -39,8 +79,23 @@ struct zynqmp_ipi { void __iomem *local_res_regs; void __iomem *remote_req_regs; void __iomem *remote_res_regs; + u32 remote_id; + u32 local_id; }; +static int zynqmp_ipi_fw_call(struct zynqmp_ipi *ipi_mbox, + unsigned long a0, unsigned long a3) +{ + struct arm_smccc_res res = {0}; + unsigned long a1, a2; + + a1 = ipi_mbox->local_id; + a2 = ipi_mbox->remote_id; + arm_smccc_smc(a0, a1, a2, a3, 0, 0, 0, 0, &res); + + return (int)res.a0; +} + static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data) { const struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data; @@ -51,6 +106,15 @@ static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data) for (size_t i = 0; i < msg->len; i++) writel(msg->buf[i], &mbx[i]); + /* Use SMC calls for Exception Level less than 3 where TF-A is available */ + if (!IS_ENABLED(CONFIG_SPL_BUILD) && current_el() < 3) { + ret = zynqmp_ipi_fw_call(zynqmp, SMC_IPI_MAILBOX_NOTIFY, 0); + + debug("%s, send %ld bytes\n", __func__, msg->len); + + return ret; + } + /* Write trigger interrupt */ writel(IPI_BIT_MASK_PMU0, &ipi_int_apu->trig); @@ -67,16 +131,23 @@ static int zynqmp_ipi_recv(struct mbox_chan *chan, void *data) struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data; struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev); u32 *mbx = (u32 *)zynqmp->local_res_regs; + int ret = 0; /* * PMU Firmware does not trigger IPI interrupt for API call responses so - * there is no need to check ISR flags + * there is no need to check ISR flags for EL3. */ for (size_t i = 0; i < msg->len; i++) msg->buf[i] = readl(&mbx[i]); + /* Ack to remote if EL is not 3 */ + if (!IS_ENABLED(CONFIG_SPL_BUILD) && current_el() < 3) { + ret = zynqmp_ipi_fw_call(zynqmp, SMC_IPI_MAILBOX_ACK, + IPI_SMC_ACK_EIRQ_MASK); + } + debug("%s, recv %ld bytes\n", __func__, msg->len); - return 0; + return ret; }; static int zynqmp_ipi_probe(struct udevice *dev) @@ -84,6 +155,7 @@ static int zynqmp_ipi_probe(struct udevice *dev) struct zynqmp_ipi *zynqmp = dev_get_priv(dev); struct resource res; ofnode node; + int ret; debug("%s(dev=%p)\n", __func__, dev); @@ -91,6 +163,18 @@ static int zynqmp_ipi_probe(struct udevice *dev) /* Note IPI mailbox node needs to be the first one in DT */ node = ofnode_first_subnode(dev_ofnode(dev)); + ret = dev_read_u32(dev, "xlnx,ipi-id", &zynqmp->local_id); + if (ret) { + dev_err(dev, "can't get local ipi id\n"); + return ret; + } + + ret = ofnode_read_u32(node, "xlnx,ipi-id", &zynqmp->remote_id); + if (ret) { + dev_err(dev, "can't get remote ipi id\n"); + return ret; + } + if (ofnode_read_resource_byname(node, "local_request_region", &res)) { dev_err(dev, "No reg property for local_request_region\n"); return -EINVAL; |