blob: eb86847bbe2354e0bfda3d4551e64066ec9c3f38 [file] [log] [blame]
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Xilinx Zynq MPSoC Mailbox driver
4 *
5 * Copyright (C) 2018-2019 Xilinx, Inc.
6 */
7
8#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010010#include <asm/io.h>
Tanmay Shahb7399062023-12-04 13:56:17 -080011#include <asm/system.h>
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010012#include <dm.h>
13#include <mailbox-uclass.h>
Simon Glass9bc15642020-02-03 07:36:16 -070014#include <dm/device_compat.h>
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -080015#include <dm/lists.h>
Tanmay Shahb7399062023-12-04 13:56:17 -080016#include <dm/of_access.h>
17#include <linux/arm-smccc.h>
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010018#include <linux/ioport.h>
19#include <linux/io.h>
20#include <wait_bit.h>
Ashok Reddy Soma73e3f992022-07-22 02:46:57 -060021#include <zynqmp_firmware.h>
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010022
23/* IPI bitmasks, register base */
24/* TODO: move reg base to DT */
25#define IPI_BIT_MASK_PMU0 0x10000
26#define IPI_INT_REG_BASE_APU 0xFF300000
27
Tanmay Shahb7399062023-12-04 13:56:17 -080028/* IPI agent ID any */
29#define IPI_ID_ANY 0xFFUL
30
31/* indicate if ZynqMP IPI mailbox driver uses SMC calls or HVC calls */
32#define USE_SMC 0
33
34/* Default IPI SMC function IDs */
35#define SMC_IPI_MAILBOX_OPEN 0x82001000U
36#define SMC_IPI_MAILBOX_RELEASE 0x82001001U
37#define SMC_IPI_MAILBOX_STATUS_ENQUIRY 0x82001002U
38#define SMC_IPI_MAILBOX_NOTIFY 0x82001003U
39#define SMC_IPI_MAILBOX_ACK 0x82001004U
40#define SMC_IPI_MAILBOX_ENABLE_IRQ 0x82001005U
41#define SMC_IPI_MAILBOX_DISABLE_IRQ 0x82001006U
42
43/* IPI SMC Macros */
44
45/*
46 * Flag to indicate if notification interrupt
47 * to be disabled.
48 */
49#define IPI_SMC_ENQUIRY_DIRQ_MASK BIT(0)
50
51/*
52 * Flag to indicate if notification interrupt
53 * to be enabled.
54 */
55#define IPI_SMC_ACK_EIRQ_MASK BIT(0)
56
57/* IPI mailbox status */
58#define IPI_MB_STATUS_IDLE 0
59#define IPI_MB_STATUS_SEND_PENDING 1
60#define IPI_MB_STATUS_RECV_PENDING 2
61
62#define IPI_MB_CHNL_TX 0 /* IPI mailbox TX channel */
63#define IPI_MB_CHNL_RX 1 /* IPI mailbox RX channel */
64
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010065struct ipi_int_regs {
66 u32 trig; /* 0x0 */
67 u32 obs; /* 0x4 */
Ibai Erkiagaab07ce52020-08-04 23:17:32 +010068 u32 dummy0;
69 u32 dummy1;
70 u32 isr; /* 0x10 */
71 u32 imr; /* 0x14 */
72 u32 ier; /* 0x18 */
73 u32 idr; /* 0x1C */
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010074};
75
76#define ipi_int_apu ((struct ipi_int_regs *)IPI_INT_REG_BASE_APU)
77
78struct zynqmp_ipi {
79 void __iomem *local_req_regs;
80 void __iomem *local_res_regs;
81 void __iomem *remote_req_regs;
82 void __iomem *remote_res_regs;
Tanmay Shahb7399062023-12-04 13:56:17 -080083 u32 remote_id;
84 u32 local_id;
Tanmay Shah26954072023-12-04 13:56:18 -080085 bool el3_supported;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +010086};
87
Tanmay Shahb7399062023-12-04 13:56:17 -080088static int zynqmp_ipi_fw_call(struct zynqmp_ipi *ipi_mbox,
89 unsigned long a0, unsigned long a3)
90{
91 struct arm_smccc_res res = {0};
92 unsigned long a1, a2;
93
94 a1 = ipi_mbox->local_id;
95 a2 = ipi_mbox->remote_id;
96 arm_smccc_smc(a0, a1, a2, a3, 0, 0, 0, 0, &res);
97
98 return (int)res.a0;
99}
100
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100101static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data)
102{
103 const struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data;
104 struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev);
105 u32 ret;
106 u32 *mbx = (u32 *)zynqmp->local_req_regs;
107
108 for (size_t i = 0; i < msg->len; i++)
109 writel(msg->buf[i], &mbx[i]);
110
Tanmay Shahb7399062023-12-04 13:56:17 -0800111 /* Use SMC calls for Exception Level less than 3 where TF-A is available */
112 if (!IS_ENABLED(CONFIG_SPL_BUILD) && current_el() < 3) {
113 ret = zynqmp_ipi_fw_call(zynqmp, SMC_IPI_MAILBOX_NOTIFY, 0);
114
115 debug("%s, send %ld bytes\n", __func__, msg->len);
116
117 return ret;
118 }
119
Tanmay Shah26954072023-12-04 13:56:18 -0800120 /* Return if EL3 is not supported */
121 if (!zynqmp->el3_supported) {
122 dev_err(chan->dev, "mailbox in EL3 only supported for zynqmp");
123 return -EOPNOTSUPP;
124 }
125
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100126 /* Write trigger interrupt */
127 writel(IPI_BIT_MASK_PMU0, &ipi_int_apu->trig);
128
129 /* Wait until observation bit is cleared */
130 ret = wait_for_bit_le32(&ipi_int_apu->obs, IPI_BIT_MASK_PMU0, false,
Michal Simekac1c7a32020-10-05 15:23:00 +0200131 1000, false);
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100132
133 debug("%s, send %ld bytes\n", __func__, msg->len);
134 return ret;
135};
136
137static int zynqmp_ipi_recv(struct mbox_chan *chan, void *data)
138{
139 struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data;
140 struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev);
141 u32 *mbx = (u32 *)zynqmp->local_res_regs;
Tanmay Shahb7399062023-12-04 13:56:17 -0800142 int ret = 0;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100143
Ibai Erkiagaab07ce52020-08-04 23:17:32 +0100144 /*
145 * PMU Firmware does not trigger IPI interrupt for API call responses so
Tanmay Shahb7399062023-12-04 13:56:17 -0800146 * there is no need to check ISR flags for EL3.
Ibai Erkiagaab07ce52020-08-04 23:17:32 +0100147 */
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100148 for (size_t i = 0; i < msg->len; i++)
149 msg->buf[i] = readl(&mbx[i]);
150
Tanmay Shahb7399062023-12-04 13:56:17 -0800151 /* Ack to remote if EL is not 3 */
152 if (!IS_ENABLED(CONFIG_SPL_BUILD) && current_el() < 3) {
153 ret = zynqmp_ipi_fw_call(zynqmp, SMC_IPI_MAILBOX_ACK,
154 IPI_SMC_ACK_EIRQ_MASK);
155 }
156
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100157 debug("%s, recv %ld bytes\n", __func__, msg->len);
Tanmay Shahb7399062023-12-04 13:56:17 -0800158 return ret;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100159};
160
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800161static int zynqmp_ipi_dest_probe(struct udevice *dev)
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100162{
163 struct zynqmp_ipi *zynqmp = dev_get_priv(dev);
164 struct resource res;
165 ofnode node;
Tanmay Shahb7399062023-12-04 13:56:17 -0800166 int ret;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100167
168 debug("%s(dev=%p)\n", __func__, dev);
169
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800170 node = dev_ofnode(dev);
171
Tanmay Shah26954072023-12-04 13:56:18 -0800172 if (IS_ENABLED(CONFIG_SPL_BUILD) || of_machine_is_compatible("xlnx,zynqmp"))
173 zynqmp->el3_supported = true;
174
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800175 ret = dev_read_u32(dev->parent, "xlnx,ipi-id", &zynqmp->local_id);
Tanmay Shahb7399062023-12-04 13:56:17 -0800176 if (ret) {
177 dev_err(dev, "can't get local ipi id\n");
178 return ret;
179 }
180
181 ret = ofnode_read_u32(node, "xlnx,ipi-id", &zynqmp->remote_id);
182 if (ret) {
183 dev_err(dev, "can't get remote ipi id\n");
184 return ret;
185 }
186
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100187 if (ofnode_read_resource_byname(node, "local_request_region", &res)) {
188 dev_err(dev, "No reg property for local_request_region\n");
189 return -EINVAL;
190 };
191 zynqmp->local_req_regs = devm_ioremap(dev, res.start,
192 (res.start - res.end));
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800193 if (!zynqmp->local_req_regs)
194 return -EINVAL;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100195
196 if (ofnode_read_resource_byname(node, "local_response_region", &res)) {
197 dev_err(dev, "No reg property for local_response_region\n");
198 return -EINVAL;
199 };
200 zynqmp->local_res_regs = devm_ioremap(dev, res.start,
201 (res.start - res.end));
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800202 if (!zynqmp->local_res_regs)
203 return -EINVAL;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100204
205 if (ofnode_read_resource_byname(node, "remote_request_region", &res)) {
206 dev_err(dev, "No reg property for remote_request_region\n");
207 return -EINVAL;
208 };
209 zynqmp->remote_req_regs = devm_ioremap(dev, res.start,
210 (res.start - res.end));
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800211 if (!zynqmp->remote_req_regs)
212 return -EINVAL;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100213
214 if (ofnode_read_resource_byname(node, "remote_response_region", &res)) {
215 dev_err(dev, "No reg property for remote_response_region\n");
216 return -EINVAL;
217 };
218 zynqmp->remote_res_regs = devm_ioremap(dev, res.start,
219 (res.start - res.end));
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800220 if (!zynqmp->remote_res_regs)
221 return -EINVAL;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100222
223 return 0;
224};
225
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800226static int zynqmp_ipi_probe(struct udevice *dev)
227{
228 struct udevice *cdev;
229 ofnode cnode;
230 int ret;
231
232 debug("%s(dev=%p)\n", __func__, dev);
233
234 dev_for_each_subnode(cnode, dev) {
235 ret = device_bind_driver_to_node(dev, "zynqmp_ipi_dest",
236 ofnode_get_name(cnode),
237 cnode, &cdev);
238 if (ret)
239 return ret;
240 }
241
242 return 0;
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100243};
244
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800245struct mbox_ops zynqmp_ipi_dest_mbox_ops = {
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100246 .send = zynqmp_ipi_send,
247 .recv = zynqmp_ipi_recv,
248};
249
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800250static const struct udevice_id zynqmp_ipi_dest_ids[] = {
251 { .compatible = "xlnx,zynqmp-ipi-dest-mailbox" },
252 { }
253};
254
255U_BOOT_DRIVER(zynqmp_ipi_dest) = {
256 .name = "zynqmp_ipi_dest",
257 .id = UCLASS_MAILBOX,
258 .of_match = zynqmp_ipi_dest_ids,
259 .probe = zynqmp_ipi_dest_probe,
260 .priv_auto = sizeof(struct zynqmp_ipi),
261 .ops = &zynqmp_ipi_dest_mbox_ops,
262};
263
264static const struct udevice_id zynqmp_ipi_ids[] = {
265 { .compatible = "xlnx,zynqmp-ipi-mailbox" },
266 { }
267};
268
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100269U_BOOT_DRIVER(zynqmp_ipi) = {
Michal Simek33093082020-01-07 08:50:34 +0100270 .name = "zynqmp_ipi",
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800271 .id = UCLASS_NOP,
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100272 .of_match = zynqmp_ipi_ids,
273 .probe = zynqmp_ipi_probe,
Tanmay Shaha7c0d3f2023-12-04 13:56:19 -0800274 .flags = DM_FLAG_PROBE_AFTER_BIND,
Ibai Erkiaga4b1264d2019-09-27 11:36:56 +0100275};