Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mailbox: ZynqMP IPI mailbox controller

This patch is to introduce ZynqMP IPI mailbox controller driver
to use the ZynqMP IPI block as mailboxes.

Signed-off-by: Wendy Liang <wendy.liang@xilinx.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>

authored by

Wendy Liang and committed by
Jassi Brar
4981b82b 419d67f3

+758
+11
drivers/mailbox/Kconfig
··· 205 205 mailbox driver. The CMDQ is used to help read/write registers with 206 206 critical time limitation, such as updating display configuration 207 207 during the vblank. 208 + 209 + config ZYNQMP_IPI_MBOX 210 + bool "Xilinx ZynqMP IPI Mailbox" 211 + depends on ARCH_ZYNQMP && OF 212 + help 213 + Say yes here to add support for Xilinx IPI mailbox driver. 214 + This mailbox driver is used to send notification or short message 215 + between processors with Xilinx ZynqMP IPI. It will place the 216 + message to the IPI buffer and will access the IPI control 217 + registers to kick the other processor or enquire status. 218 + 208 219 endif
+2
drivers/mailbox/Makefile
··· 44 44 obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o 45 45 46 46 obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o 47 + 48 + obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o
+725
drivers/mailbox/zynqmp-ipi-mailbox.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Xilinx Inter Processor Interrupt(IPI) Mailbox Driver 4 + * 5 + * Copyright (C) 2018 Xilinx, Inc. 6 + */ 7 + 8 + #include <linux/arm-smccc.h> 9 + #include <linux/delay.h> 10 + #include <linux/device.h> 11 + #include <linux/interrupt.h> 12 + #include <linux/io.h> 13 + #include <linux/kernel.h> 14 + #include <linux/mailbox_controller.h> 15 + #include <linux/mailbox/zynqmp-ipi-message.h> 16 + #include <linux/module.h> 17 + #include <linux/of.h> 18 + #include <linux/of_address.h> 19 + #include <linux/of_device.h> 20 + #include <linux/of_irq.h> 21 + #include <linux/platform_device.h> 22 + 23 + /* IPI agent ID any */ 24 + #define IPI_ID_ANY 0xFFUL 25 + 26 + /* indicate if ZynqMP IPI mailbox driver uses SMC calls or HVC calls */ 27 + #define USE_SMC 0 28 + #define USE_HVC 1 29 + 30 + /* Default IPI SMC function IDs */ 31 + #define SMC_IPI_MAILBOX_OPEN 0x82001000U 32 + #define SMC_IPI_MAILBOX_RELEASE 0x82001001U 33 + #define SMC_IPI_MAILBOX_STATUS_ENQUIRY 0x82001002U 34 + #define SMC_IPI_MAILBOX_NOTIFY 0x82001003U 35 + #define SMC_IPI_MAILBOX_ACK 0x82001004U 36 + #define SMC_IPI_MAILBOX_ENABLE_IRQ 0x82001005U 37 + #define SMC_IPI_MAILBOX_DISABLE_IRQ 0x82001006U 38 + 39 + /* IPI SMC Macros */ 40 + #define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001UL /* Flag to indicate if 41 + * notification interrupt 42 + * to be disabled. 43 + */ 44 + #define IPI_SMC_ACK_EIRQ_MASK 0x00000001UL /* Flag to indicate if 45 + * notification interrupt 46 + * to be enabled. 47 + */ 48 + 49 + /* IPI mailbox status */ 50 + #define IPI_MB_STATUS_IDLE 0 51 + #define IPI_MB_STATUS_SEND_PENDING 1 52 + #define IPI_MB_STATUS_RECV_PENDING 2 53 + 54 + #define IPI_MB_CHNL_TX 0 /* IPI mailbox TX channel */ 55 + #define IPI_MB_CHNL_RX 1 /* IPI mailbox RX channel */ 56 + 57 + /** 58 + * struct zynqmp_ipi_mchan - Description of a Xilinx ZynqMP IPI mailbox channel 59 + * @is_opened: indicate if the IPI channel is opened 60 + * @req_buf: local to remote request buffer start address 61 + * @resp_buf: local to remote response buffer start address 62 + * @req_buf_size: request buffer size 63 + * @resp_buf_size: response buffer size 64 + * @rx_buf: receive buffer to pass received message to client 65 + * @chan_type: channel type 66 + */ 67 + struct zynqmp_ipi_mchan { 68 + int is_opened; 69 + void __iomem *req_buf; 70 + void __iomem *resp_buf; 71 + void *rx_buf; 72 + size_t req_buf_size; 73 + size_t resp_buf_size; 74 + unsigned int chan_type; 75 + }; 76 + 77 + /** 78 + * struct zynqmp_ipi_mbox - Description of a ZynqMP IPI mailbox 79 + * platform data. 80 + * @pdata: pointer to the IPI private data 81 + * @dev: device pointer corresponding to the Xilinx ZynqMP 82 + * IPI mailbox 83 + * @remote_id: remote IPI agent ID 84 + * @mbox: mailbox Controller 85 + * @mchans: array for channels, tx channel and rx channel. 86 + * @irq: IPI agent interrupt ID 87 + */ 88 + struct zynqmp_ipi_mbox { 89 + struct zynqmp_ipi_pdata *pdata; 90 + struct device dev; 91 + u32 remote_id; 92 + struct mbox_controller mbox; 93 + struct zynqmp_ipi_mchan mchans[2]; 94 + }; 95 + 96 + /** 97 + * struct zynqmp_ipi_pdata - Description of z ZynqMP IPI agent platform data. 98 + * 99 + * @dev: device pointer corresponding to the Xilinx ZynqMP 100 + * IPI agent 101 + * @irq: IPI agent interrupt ID 102 + * @method: IPI SMC or HVC is going to be used 103 + * @local_id: local IPI agent ID 104 + * @num_mboxes: number of mailboxes of this IPI agent 105 + * @ipi_mboxes: IPI mailboxes of this IPI agent 106 + */ 107 + struct zynqmp_ipi_pdata { 108 + struct device *dev; 109 + int irq; 110 + unsigned int method; 111 + u32 local_id; 112 + int num_mboxes; 113 + struct zynqmp_ipi_mbox *ipi_mboxes; 114 + }; 115 + 116 + static struct device_driver zynqmp_ipi_mbox_driver = { 117 + .owner = THIS_MODULE, 118 + .name = "zynqmp-ipi-mbox", 119 + }; 120 + 121 + static void zynqmp_ipi_fw_call(struct zynqmp_ipi_mbox *ipi_mbox, 122 + unsigned long a0, unsigned long a3, 123 + struct arm_smccc_res *res) 124 + { 125 + struct zynqmp_ipi_pdata *pdata = ipi_mbox->pdata; 126 + unsigned long a1, a2; 127 + 128 + a1 = pdata->local_id; 129 + a2 = ipi_mbox->remote_id; 130 + if (pdata->method == USE_SMC) 131 + arm_smccc_smc(a0, a1, a2, a3, 0, 0, 0, 0, res); 132 + else 133 + arm_smccc_hvc(a0, a1, a2, a3, 0, 0, 0, 0, res); 134 + } 135 + 136 + /** 137 + * zynqmp_ipi_interrupt - Interrupt handler for IPI notification 138 + * 139 + * @irq: Interrupt number 140 + * @data: ZynqMP IPI mailbox platform data. 141 + * 142 + * Return: -EINVAL if there is no instance 143 + * IRQ_NONE if the interrupt is not ours. 144 + * IRQ_HANDLED if the rx interrupt was successfully handled. 145 + */ 146 + static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data) 147 + { 148 + struct zynqmp_ipi_pdata *pdata = data; 149 + struct mbox_chan *chan; 150 + struct zynqmp_ipi_mbox *ipi_mbox; 151 + struct zynqmp_ipi_mchan *mchan; 152 + struct zynqmp_ipi_message *msg; 153 + u64 arg0, arg3; 154 + struct arm_smccc_res res; 155 + int ret, i; 156 + 157 + (void)irq; 158 + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; 159 + arg3 = IPI_SMC_ENQUIRY_DIRQ_MASK; 160 + for (i = 0; i < pdata->num_mboxes; i++) { 161 + ipi_mbox = &pdata->ipi_mboxes[i]; 162 + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; 163 + chan = &ipi_mbox->mbox.chans[IPI_MB_CHNL_RX]; 164 + zynqmp_ipi_fw_call(ipi_mbox, arg0, arg3, &res); 165 + ret = (int)(res.a0 & 0xFFFFFFFF); 166 + if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) { 167 + if (mchan->is_opened) { 168 + msg = mchan->rx_buf; 169 + msg->len = mchan->req_buf_size; 170 + memcpy_fromio(msg->data, mchan->req_buf, 171 + msg->len); 172 + mbox_chan_received_data(chan, (void *)msg); 173 + return IRQ_HANDLED; 174 + } 175 + } 176 + } 177 + return IRQ_NONE; 178 + } 179 + 180 + /** 181 + * zynqmp_ipi_peek_data - Peek to see if there are any rx messages. 182 + * 183 + * @chan: Channel Pointer 184 + * 185 + * Return: 'true' if there is pending rx data, 'false' if there is none. 186 + */ 187 + static bool zynqmp_ipi_peek_data(struct mbox_chan *chan) 188 + { 189 + struct device *dev = chan->mbox->dev; 190 + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); 191 + struct zynqmp_ipi_mchan *mchan = chan->con_priv; 192 + int ret; 193 + u64 arg0; 194 + struct arm_smccc_res res; 195 + 196 + if (WARN_ON(!ipi_mbox)) { 197 + dev_err(dev, "no platform drv data??\n"); 198 + return false; 199 + } 200 + 201 + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; 202 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 203 + ret = (int)(res.a0 & 0xFFFFFFFF); 204 + 205 + if (mchan->chan_type == IPI_MB_CHNL_TX) { 206 + /* TX channel, check if the message has been acked 207 + * by the remote, if yes, response is available. 208 + */ 209 + if (ret < 0 || ret & IPI_MB_STATUS_SEND_PENDING) 210 + return false; 211 + else 212 + return true; 213 + } else if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) { 214 + /* RX channel, check if there is message arrived. */ 215 + return true; 216 + } 217 + return false; 218 + } 219 + 220 + /** 221 + * zynqmp_ipi_last_tx_done - See if the last tx message is sent 222 + * 223 + * @chan: Channel pointer 224 + * 225 + * Return: 'true' is no pending tx data, 'false' if there are any. 226 + */ 227 + static bool zynqmp_ipi_last_tx_done(struct mbox_chan *chan) 228 + { 229 + struct device *dev = chan->mbox->dev; 230 + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); 231 + struct zynqmp_ipi_mchan *mchan = chan->con_priv; 232 + int ret; 233 + u64 arg0; 234 + struct arm_smccc_res res; 235 + 236 + if (WARN_ON(!ipi_mbox)) { 237 + dev_err(dev, "no platform drv data??\n"); 238 + return false; 239 + } 240 + 241 + if (mchan->chan_type == IPI_MB_CHNL_TX) { 242 + /* We only need to check if the message been taken 243 + * by the remote in the TX channel 244 + */ 245 + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; 246 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 247 + /* Check the SMC call status, a0 of the result */ 248 + ret = (int)(res.a0 & 0xFFFFFFFF); 249 + if (ret < 0 || ret & IPI_MB_STATUS_SEND_PENDING) 250 + return false; 251 + return true; 252 + } 253 + /* Always true for the response message in RX channel */ 254 + return true; 255 + } 256 + 257 + /** 258 + * zynqmp_ipi_send_data - Send data 259 + * 260 + * @chan: Channel Pointer 261 + * @data: Message Pointer 262 + * 263 + * Return: 0 if all goes good, else appropriate error messages. 264 + */ 265 + static int zynqmp_ipi_send_data(struct mbox_chan *chan, void *data) 266 + { 267 + struct device *dev = chan->mbox->dev; 268 + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); 269 + struct zynqmp_ipi_mchan *mchan = chan->con_priv; 270 + struct zynqmp_ipi_message *msg = data; 271 + u64 arg0; 272 + struct arm_smccc_res res; 273 + 274 + if (WARN_ON(!ipi_mbox)) { 275 + dev_err(dev, "no platform drv data??\n"); 276 + return -EINVAL; 277 + } 278 + 279 + if (mchan->chan_type == IPI_MB_CHNL_TX) { 280 + /* Send request message */ 281 + if (msg && msg->len > mchan->req_buf_size) { 282 + dev_err(dev, "channel %d message length %u > max %lu\n", 283 + mchan->chan_type, (unsigned int)msg->len, 284 + mchan->req_buf_size); 285 + return -EINVAL; 286 + } 287 + if (msg && msg->len) 288 + memcpy_toio(mchan->req_buf, msg->data, msg->len); 289 + /* Kick IPI mailbox to send message */ 290 + arg0 = SMC_IPI_MAILBOX_NOTIFY; 291 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 292 + } else { 293 + /* Send response message */ 294 + if (msg && msg->len > mchan->resp_buf_size) { 295 + dev_err(dev, "channel %d message length %u > max %lu\n", 296 + mchan->chan_type, (unsigned int)msg->len, 297 + mchan->resp_buf_size); 298 + return -EINVAL; 299 + } 300 + if (msg && msg->len) 301 + memcpy_toio(mchan->resp_buf, msg->data, msg->len); 302 + arg0 = SMC_IPI_MAILBOX_ACK; 303 + zynqmp_ipi_fw_call(ipi_mbox, arg0, IPI_SMC_ACK_EIRQ_MASK, 304 + &res); 305 + } 306 + return 0; 307 + } 308 + 309 + /** 310 + * zynqmp_ipi_startup - Startup the IPI channel 311 + * 312 + * @chan: Channel pointer 313 + * 314 + * Return: 0 if all goes good, else return corresponding error message 315 + */ 316 + static int zynqmp_ipi_startup(struct mbox_chan *chan) 317 + { 318 + struct device *dev = chan->mbox->dev; 319 + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); 320 + struct zynqmp_ipi_mchan *mchan = chan->con_priv; 321 + u64 arg0; 322 + struct arm_smccc_res res; 323 + int ret = 0; 324 + unsigned int nchan_type; 325 + 326 + if (mchan->is_opened) 327 + return 0; 328 + 329 + /* If no channel has been opened, open the IPI mailbox */ 330 + nchan_type = (mchan->chan_type + 1) % 2; 331 + if (!ipi_mbox->mchans[nchan_type].is_opened) { 332 + arg0 = SMC_IPI_MAILBOX_OPEN; 333 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 334 + /* Check the SMC call status, a0 of the result */ 335 + ret = (int)(res.a0 & 0xFFFFFFFF); 336 + if (ret < 0) { 337 + dev_err(dev, "SMC to open the IPI channel failed.\n"); 338 + return ret; 339 + } 340 + ret = 0; 341 + } 342 + 343 + /* If it is RX channel, enable the IPI notification interrupt */ 344 + if (mchan->chan_type == IPI_MB_CHNL_RX) { 345 + arg0 = SMC_IPI_MAILBOX_ENABLE_IRQ; 346 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 347 + } 348 + mchan->is_opened = 1; 349 + 350 + return ret; 351 + } 352 + 353 + /** 354 + * zynqmp_ipi_shutdown - Shutdown the IPI channel 355 + * 356 + * @chan: Channel pointer 357 + */ 358 + static void zynqmp_ipi_shutdown(struct mbox_chan *chan) 359 + { 360 + struct device *dev = chan->mbox->dev; 361 + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); 362 + struct zynqmp_ipi_mchan *mchan = chan->con_priv; 363 + u64 arg0; 364 + struct arm_smccc_res res; 365 + unsigned int chan_type; 366 + 367 + if (!mchan->is_opened) 368 + return; 369 + 370 + /* If it is RX channel, disable notification interrupt */ 371 + chan_type = mchan->chan_type; 372 + if (chan_type == IPI_MB_CHNL_RX) { 373 + arg0 = SMC_IPI_MAILBOX_DISABLE_IRQ; 374 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 375 + } 376 + /* Release IPI mailbox if no other channel is opened */ 377 + chan_type = (chan_type + 1) % 2; 378 + if (!ipi_mbox->mchans[chan_type].is_opened) { 379 + arg0 = SMC_IPI_MAILBOX_RELEASE; 380 + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); 381 + } 382 + 383 + mchan->is_opened = 0; 384 + } 385 + 386 + /* ZynqMP IPI mailbox operations */ 387 + static const struct mbox_chan_ops zynqmp_ipi_chan_ops = { 388 + .startup = zynqmp_ipi_startup, 389 + .shutdown = zynqmp_ipi_shutdown, 390 + .peek_data = zynqmp_ipi_peek_data, 391 + .last_tx_done = zynqmp_ipi_last_tx_done, 392 + .send_data = zynqmp_ipi_send_data, 393 + }; 394 + 395 + /** 396 + * zynqmp_ipi_of_xlate - Translate of phandle to IPI mailbox channel 397 + * 398 + * @mbox: mailbox controller pointer 399 + * @p: phandle pointer 400 + * 401 + * Return: Mailbox channel, else return error pointer. 402 + */ 403 + static struct mbox_chan *zynqmp_ipi_of_xlate(struct mbox_controller *mbox, 404 + const struct of_phandle_args *p) 405 + { 406 + struct mbox_chan *chan; 407 + struct device *dev = mbox->dev; 408 + unsigned int chan_type; 409 + 410 + /* Only supports TX and RX channels */ 411 + chan_type = p->args[0]; 412 + if (chan_type != IPI_MB_CHNL_TX && chan_type != IPI_MB_CHNL_RX) { 413 + dev_err(dev, "req chnl failure: invalid chnl type %u.\n", 414 + chan_type); 415 + return ERR_PTR(-EINVAL); 416 + } 417 + chan = &mbox->chans[chan_type]; 418 + return chan; 419 + } 420 + 421 + static const struct of_device_id zynqmp_ipi_of_match[] = { 422 + { .compatible = "xlnx,zynqmp-ipi-mailbox" }, 423 + {}, 424 + }; 425 + MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); 426 + 427 + /** 428 + * zynqmp_ipi_mbox_get_buf_res - Get buffer resource from the IPI dev node 429 + * 430 + * @node: IPI mbox device child node 431 + * @name: name of the IPI buffer 432 + * @res: pointer to where the resource information will be stored. 433 + * 434 + * Return: 0 for success, negative value for failure 435 + */ 436 + static int zynqmp_ipi_mbox_get_buf_res(struct device_node *node, 437 + const char *name, 438 + struct resource *res) 439 + { 440 + int ret, index; 441 + 442 + index = of_property_match_string(node, "reg-names", name); 443 + if (index >= 0) { 444 + ret = of_address_to_resource(node, index, res); 445 + if (ret < 0) 446 + return -EINVAL; 447 + return 0; 448 + } 449 + return -ENODEV; 450 + } 451 + 452 + /** 453 + * zynqmp_ipi_mbox_dev_release() - release the existence of a ipi mbox dev 454 + * 455 + * @dev: the ipi mailbox device 456 + * 457 + * This is to avoid the no device release() function kernel warning. 458 + * 459 + */ 460 + static void zynqmp_ipi_mbox_dev_release(struct device *dev) 461 + { 462 + (void)dev; 463 + } 464 + 465 + /** 466 + * zynqmp_ipi_mbox_probe - probe IPI mailbox resource from device node 467 + * 468 + * @ipi_mbox: pointer to IPI mailbox private data structure 469 + * @node: IPI mailbox device node 470 + * 471 + * Return: 0 for success, negative value for failure 472 + */ 473 + static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, 474 + struct device_node *node) 475 + { 476 + struct zynqmp_ipi_mchan *mchan; 477 + struct mbox_chan *chans; 478 + struct mbox_controller *mbox; 479 + struct resource res; 480 + struct device *dev, *mdev; 481 + const char *name; 482 + int ret; 483 + 484 + dev = ipi_mbox->pdata->dev; 485 + /* Initialize dev for IPI mailbox */ 486 + ipi_mbox->dev.parent = dev; 487 + ipi_mbox->dev.release = NULL; 488 + ipi_mbox->dev.of_node = node; 489 + dev_set_name(&ipi_mbox->dev, "%s", of_node_full_name(node)); 490 + dev_set_drvdata(&ipi_mbox->dev, ipi_mbox); 491 + ipi_mbox->dev.release = zynqmp_ipi_mbox_dev_release; 492 + ipi_mbox->dev.driver = &zynqmp_ipi_mbox_driver; 493 + ret = device_register(&ipi_mbox->dev); 494 + if (ret) { 495 + dev_err(dev, "Failed to register ipi mbox dev.\n"); 496 + return ret; 497 + } 498 + mdev = &ipi_mbox->dev; 499 + 500 + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; 501 + name = "local_request_region"; 502 + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); 503 + if (!ret) { 504 + mchan->req_buf_size = resource_size(&res); 505 + mchan->req_buf = devm_ioremap(mdev, res.start, 506 + mchan->req_buf_size); 507 + if (IS_ERR(mchan->req_buf)) { 508 + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); 509 + ret = PTR_ERR(mchan->req_buf); 510 + return ret; 511 + } 512 + } else if (ret != -ENODEV) { 513 + dev_err(mdev, "Unmatched resource %s, %d.\n", name, ret); 514 + return ret; 515 + } 516 + 517 + name = "remote_response_region"; 518 + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); 519 + if (!ret) { 520 + mchan->resp_buf_size = resource_size(&res); 521 + mchan->resp_buf = devm_ioremap(mdev, res.start, 522 + mchan->resp_buf_size); 523 + if (IS_ERR(mchan->resp_buf)) { 524 + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); 525 + ret = PTR_ERR(mchan->resp_buf); 526 + return ret; 527 + } 528 + } else if (ret != -ENODEV) { 529 + dev_err(mdev, "Unmatched resource %s.\n", name); 530 + return ret; 531 + } 532 + mchan->rx_buf = devm_kzalloc(mdev, 533 + mchan->resp_buf_size + 534 + sizeof(struct zynqmp_ipi_message), 535 + GFP_KERNEL); 536 + if (!mchan->rx_buf) 537 + return -ENOMEM; 538 + 539 + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; 540 + name = "remote_request_region"; 541 + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); 542 + if (!ret) { 543 + mchan->req_buf_size = resource_size(&res); 544 + mchan->req_buf = devm_ioremap(mdev, res.start, 545 + mchan->req_buf_size); 546 + if (IS_ERR(mchan->req_buf)) { 547 + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); 548 + ret = PTR_ERR(mchan->req_buf); 549 + return ret; 550 + } 551 + } else if (ret != -ENODEV) { 552 + dev_err(mdev, "Unmatched resource %s.\n", name); 553 + return ret; 554 + } 555 + 556 + name = "local_response_region"; 557 + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); 558 + if (!ret) { 559 + mchan->resp_buf_size = resource_size(&res); 560 + mchan->resp_buf = devm_ioremap(mdev, res.start, 561 + mchan->resp_buf_size); 562 + if (IS_ERR(mchan->resp_buf)) { 563 + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); 564 + ret = PTR_ERR(mchan->resp_buf); 565 + return ret; 566 + } 567 + } else if (ret != -ENODEV) { 568 + dev_err(mdev, "Unmatched resource %s.\n", name); 569 + return ret; 570 + } 571 + mchan->rx_buf = devm_kzalloc(mdev, 572 + mchan->resp_buf_size + 573 + sizeof(struct zynqmp_ipi_message), 574 + GFP_KERNEL); 575 + if (!mchan->rx_buf) 576 + return -ENOMEM; 577 + 578 + /* Get the IPI remote agent ID */ 579 + ret = of_property_read_u32(node, "xlnx,ipi-id", &ipi_mbox->remote_id); 580 + if (ret < 0) { 581 + dev_err(dev, "No IPI remote ID is specified.\n"); 582 + return ret; 583 + } 584 + 585 + mbox = &ipi_mbox->mbox; 586 + mbox->dev = mdev; 587 + mbox->ops = &zynqmp_ipi_chan_ops; 588 + mbox->num_chans = 2; 589 + mbox->txdone_irq = false; 590 + mbox->txdone_poll = true; 591 + mbox->txpoll_period = 5; 592 + mbox->of_xlate = zynqmp_ipi_of_xlate; 593 + chans = devm_kzalloc(mdev, 2 * sizeof(*chans), GFP_KERNEL); 594 + if (!chans) 595 + return -ENOMEM; 596 + mbox->chans = chans; 597 + chans[IPI_MB_CHNL_TX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; 598 + chans[IPI_MB_CHNL_RX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; 599 + ipi_mbox->mchans[IPI_MB_CHNL_TX].chan_type = IPI_MB_CHNL_TX; 600 + ipi_mbox->mchans[IPI_MB_CHNL_RX].chan_type = IPI_MB_CHNL_RX; 601 + ret = devm_mbox_controller_register(mdev, mbox); 602 + if (ret) 603 + dev_err(mdev, 604 + "Failed to register mbox_controller(%d)\n", ret); 605 + else 606 + dev_info(mdev, 607 + "Registered ZynqMP IPI mbox with TX/RX channels.\n"); 608 + return ret; 609 + } 610 + 611 + /** 612 + * zynqmp_ipi_free_mboxes - Free IPI mailboxes devices 613 + * 614 + * @pdata: IPI private data 615 + */ 616 + static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata) 617 + { 618 + struct zynqmp_ipi_mbox *ipi_mbox; 619 + int i; 620 + 621 + i = pdata->num_mboxes; 622 + for (; i >= 0; i--) { 623 + ipi_mbox = &pdata->ipi_mboxes[i]; 624 + if (ipi_mbox->dev.parent) { 625 + mbox_controller_unregister(&ipi_mbox->mbox); 626 + device_unregister(&ipi_mbox->dev); 627 + } 628 + } 629 + } 630 + 631 + static int zynqmp_ipi_probe(struct platform_device *pdev) 632 + { 633 + struct device *dev = &pdev->dev; 634 + struct device_node *nc, *np = pdev->dev.of_node; 635 + struct zynqmp_ipi_pdata *pdata; 636 + struct zynqmp_ipi_mbox *mbox; 637 + int num_mboxes, ret = -EINVAL; 638 + 639 + num_mboxes = of_get_child_count(np); 640 + pdata = devm_kzalloc(dev, sizeof(*pdata) + (num_mboxes * sizeof(*mbox)), 641 + GFP_KERNEL); 642 + if (!pdata) 643 + return -ENOMEM; 644 + pdata->dev = dev; 645 + 646 + /* Get the IPI local agents ID */ 647 + ret = of_property_read_u32(np, "xlnx,ipi-id", &pdata->local_id); 648 + if (ret < 0) { 649 + dev_err(dev, "No IPI local ID is specified.\n"); 650 + return ret; 651 + } 652 + 653 + pdata->num_mboxes = num_mboxes; 654 + pdata->ipi_mboxes = (struct zynqmp_ipi_mbox *) 655 + ((char *)pdata + sizeof(*pdata)); 656 + 657 + mbox = pdata->ipi_mboxes; 658 + for_each_available_child_of_node(np, nc) { 659 + mbox->pdata = pdata; 660 + ret = zynqmp_ipi_mbox_probe(mbox, nc); 661 + if (ret) { 662 + dev_err(dev, "failed to probe subdev.\n"); 663 + ret = -EINVAL; 664 + goto free_mbox_dev; 665 + } 666 + mbox++; 667 + } 668 + 669 + /* IPI IRQ */ 670 + ret = platform_get_irq(pdev, 0); 671 + if (ret < 0) { 672 + dev_err(dev, "unable to find IPI IRQ.\n"); 673 + goto free_mbox_dev; 674 + } 675 + pdata->irq = ret; 676 + ret = devm_request_irq(dev, pdata->irq, zynqmp_ipi_interrupt, 677 + IRQF_SHARED, dev_name(dev), pdata); 678 + if (ret) { 679 + dev_err(dev, "IRQ %d is not requested successfully.\n", 680 + pdata->irq); 681 + goto free_mbox_dev; 682 + } 683 + 684 + platform_set_drvdata(pdev, pdata); 685 + return ret; 686 + 687 + free_mbox_dev: 688 + zynqmp_ipi_free_mboxes(pdata); 689 + return ret; 690 + } 691 + 692 + static int zynqmp_ipi_remove(struct platform_device *pdev) 693 + { 694 + struct zynqmp_ipi_pdata *pdata; 695 + 696 + pdata = platform_get_drvdata(pdev); 697 + zynqmp_ipi_free_mboxes(pdata); 698 + 699 + return 0; 700 + } 701 + 702 + static struct platform_driver zynqmp_ipi_driver = { 703 + .probe = zynqmp_ipi_probe, 704 + .remove = zynqmp_ipi_remove, 705 + .driver = { 706 + .name = "zynqmp-ipi", 707 + .of_match_table = of_match_ptr(zynqmp_ipi_of_match), 708 + }, 709 + }; 710 + 711 + static int __init zynqmp_ipi_init(void) 712 + { 713 + return platform_driver_register(&zynqmp_ipi_driver); 714 + } 715 + subsys_initcall(zynqmp_ipi_init); 716 + 717 + static void __exit zynqmp_ipi_exit(void) 718 + { 719 + platform_driver_unregister(&zynqmp_ipi_driver); 720 + } 721 + module_exit(zynqmp_ipi_exit); 722 + 723 + MODULE_LICENSE("GPL v2"); 724 + MODULE_DESCRIPTION("Xilinx ZynqMP IPI Mailbox driver"); 725 + MODULE_AUTHOR("Xilinx Inc.");
+20
include/linux/mailbox/zynqmp-ipi-message.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef _LINUX_ZYNQMP_IPI_MESSAGE_H_ 4 + #define _LINUX_ZYNQMP_IPI_MESSAGE_H_ 5 + 6 + /** 7 + * struct zynqmp_ipi_message - ZynqMP IPI message structure 8 + * @len: Length of message 9 + * @data: message payload 10 + * 11 + * This is the structure for data used in mbox_send_message 12 + * the maximum length of data buffer is fixed to 12 bytes. 13 + * Client is supposed to be aware of this. 14 + */ 15 + struct zynqmp_ipi_message { 16 + size_t len; 17 + u8 data[0]; 18 + }; 19 + 20 + #endif /* _LINUX_ZYNQMP_IPI_MESSAGE_H_ */