From: Tanmay Shah Date: Mon, 4 Dec 2023 21:56:17 +0000 (-0800) Subject: mailbox: zynqmp: support smc calls to TF-A X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=cfb41b011dd675564d2ac2f6613e54c999fb8399;p=u-boot.git 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 Link: https://lore.kernel.org/r/20231204215620.63334-2-tanmay.shah@amd.com Signed-off-by: Michal Simek --- 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 #include #include +#include #include #include #include +#include +#include #include #include #include @@ -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;