0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/arm-smccc.h>
0009 #include <linux/delay.h>
0010 #include <linux/device.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mailbox_controller.h>
0015 #include <linux/mailbox/zynqmp-ipi-message.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 #include <linux/of_device.h>
0020 #include <linux/of_irq.h>
0021 #include <linux/platform_device.h>
0022
0023
0024 #define IPI_ID_ANY 0xFFUL
0025
0026
0027 #define USE_SMC 0
0028 #define USE_HVC 1
0029
0030
0031 #define SMC_IPI_MAILBOX_OPEN 0x82001000U
0032 #define SMC_IPI_MAILBOX_RELEASE 0x82001001U
0033 #define SMC_IPI_MAILBOX_STATUS_ENQUIRY 0x82001002U
0034 #define SMC_IPI_MAILBOX_NOTIFY 0x82001003U
0035 #define SMC_IPI_MAILBOX_ACK 0x82001004U
0036 #define SMC_IPI_MAILBOX_ENABLE_IRQ 0x82001005U
0037 #define SMC_IPI_MAILBOX_DISABLE_IRQ 0x82001006U
0038
0039
0040 #define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001UL
0041
0042
0043
0044 #define IPI_SMC_ACK_EIRQ_MASK 0x00000001UL
0045
0046
0047
0048
0049
0050 #define IPI_MB_STATUS_IDLE 0
0051 #define IPI_MB_STATUS_SEND_PENDING 1
0052 #define IPI_MB_STATUS_RECV_PENDING 2
0053
0054 #define IPI_MB_CHNL_TX 0
0055 #define IPI_MB_CHNL_RX 1
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 struct zynqmp_ipi_mchan {
0068 int is_opened;
0069 void __iomem *req_buf;
0070 void __iomem *resp_buf;
0071 void *rx_buf;
0072 size_t req_buf_size;
0073 size_t resp_buf_size;
0074 unsigned int chan_type;
0075 };
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 struct zynqmp_ipi_mbox {
0089 struct zynqmp_ipi_pdata *pdata;
0090 struct device dev;
0091 u32 remote_id;
0092 struct mbox_controller mbox;
0093 struct zynqmp_ipi_mchan mchans[2];
0094 };
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 struct zynqmp_ipi_pdata {
0108 struct device *dev;
0109 int irq;
0110 unsigned int method;
0111 u32 local_id;
0112 int num_mboxes;
0113 struct zynqmp_ipi_mbox *ipi_mboxes;
0114 };
0115
0116 static struct device_driver zynqmp_ipi_mbox_driver = {
0117 .owner = THIS_MODULE,
0118 .name = "zynqmp-ipi-mbox",
0119 };
0120
0121 static void zynqmp_ipi_fw_call(struct zynqmp_ipi_mbox *ipi_mbox,
0122 unsigned long a0, unsigned long a3,
0123 struct arm_smccc_res *res)
0124 {
0125 struct zynqmp_ipi_pdata *pdata = ipi_mbox->pdata;
0126 unsigned long a1, a2;
0127
0128 a1 = pdata->local_id;
0129 a2 = ipi_mbox->remote_id;
0130 if (pdata->method == USE_SMC)
0131 arm_smccc_smc(a0, a1, a2, a3, 0, 0, 0, 0, res);
0132 else
0133 arm_smccc_hvc(a0, a1, a2, a3, 0, 0, 0, 0, res);
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data)
0147 {
0148 struct zynqmp_ipi_pdata *pdata = data;
0149 struct mbox_chan *chan;
0150 struct zynqmp_ipi_mbox *ipi_mbox;
0151 struct zynqmp_ipi_mchan *mchan;
0152 struct zynqmp_ipi_message *msg;
0153 u64 arg0, arg3;
0154 struct arm_smccc_res res;
0155 int ret, i;
0156
0157 (void)irq;
0158 arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY;
0159 arg3 = IPI_SMC_ENQUIRY_DIRQ_MASK;
0160 for (i = 0; i < pdata->num_mboxes; i++) {
0161 ipi_mbox = &pdata->ipi_mboxes[i];
0162 mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX];
0163 chan = &ipi_mbox->mbox.chans[IPI_MB_CHNL_RX];
0164 zynqmp_ipi_fw_call(ipi_mbox, arg0, arg3, &res);
0165 ret = (int)(res.a0 & 0xFFFFFFFF);
0166 if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) {
0167 if (mchan->is_opened) {
0168 msg = mchan->rx_buf;
0169 msg->len = mchan->req_buf_size;
0170 memcpy_fromio(msg->data, mchan->req_buf,
0171 msg->len);
0172 mbox_chan_received_data(chan, (void *)msg);
0173 return IRQ_HANDLED;
0174 }
0175 }
0176 }
0177 return IRQ_NONE;
0178 }
0179
0180
0181
0182
0183
0184
0185
0186
0187 static bool zynqmp_ipi_peek_data(struct mbox_chan *chan)
0188 {
0189 struct device *dev = chan->mbox->dev;
0190 struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev);
0191 struct zynqmp_ipi_mchan *mchan = chan->con_priv;
0192 int ret;
0193 u64 arg0;
0194 struct arm_smccc_res res;
0195
0196 if (WARN_ON(!ipi_mbox)) {
0197 dev_err(dev, "no platform drv data??\n");
0198 return false;
0199 }
0200
0201 arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY;
0202 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0203 ret = (int)(res.a0 & 0xFFFFFFFF);
0204
0205 if (mchan->chan_type == IPI_MB_CHNL_TX) {
0206
0207
0208
0209 if (ret < 0 || ret & IPI_MB_STATUS_SEND_PENDING)
0210 return false;
0211 else
0212 return true;
0213 } else if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) {
0214
0215 return true;
0216 }
0217 return false;
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227 static bool zynqmp_ipi_last_tx_done(struct mbox_chan *chan)
0228 {
0229 struct device *dev = chan->mbox->dev;
0230 struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev);
0231 struct zynqmp_ipi_mchan *mchan = chan->con_priv;
0232 int ret;
0233 u64 arg0;
0234 struct arm_smccc_res res;
0235
0236 if (WARN_ON(!ipi_mbox)) {
0237 dev_err(dev, "no platform drv data??\n");
0238 return false;
0239 }
0240
0241 if (mchan->chan_type == IPI_MB_CHNL_TX) {
0242
0243
0244
0245 arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY;
0246 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0247
0248 ret = (int)(res.a0 & 0xFFFFFFFF);
0249 if (ret < 0 || ret & IPI_MB_STATUS_SEND_PENDING)
0250 return false;
0251 return true;
0252 }
0253
0254 return true;
0255 }
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 static int zynqmp_ipi_send_data(struct mbox_chan *chan, void *data)
0266 {
0267 struct device *dev = chan->mbox->dev;
0268 struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev);
0269 struct zynqmp_ipi_mchan *mchan = chan->con_priv;
0270 struct zynqmp_ipi_message *msg = data;
0271 u64 arg0;
0272 struct arm_smccc_res res;
0273
0274 if (WARN_ON(!ipi_mbox)) {
0275 dev_err(dev, "no platform drv data??\n");
0276 return -EINVAL;
0277 }
0278
0279 if (mchan->chan_type == IPI_MB_CHNL_TX) {
0280
0281 if (msg && msg->len > mchan->req_buf_size) {
0282 dev_err(dev, "channel %d message length %u > max %lu\n",
0283 mchan->chan_type, (unsigned int)msg->len,
0284 mchan->req_buf_size);
0285 return -EINVAL;
0286 }
0287 if (msg && msg->len)
0288 memcpy_toio(mchan->req_buf, msg->data, msg->len);
0289
0290 arg0 = SMC_IPI_MAILBOX_NOTIFY;
0291 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0292 } else {
0293
0294 if (msg && msg->len > mchan->resp_buf_size) {
0295 dev_err(dev, "channel %d message length %u > max %lu\n",
0296 mchan->chan_type, (unsigned int)msg->len,
0297 mchan->resp_buf_size);
0298 return -EINVAL;
0299 }
0300 if (msg && msg->len)
0301 memcpy_toio(mchan->resp_buf, msg->data, msg->len);
0302 arg0 = SMC_IPI_MAILBOX_ACK;
0303 zynqmp_ipi_fw_call(ipi_mbox, arg0, IPI_SMC_ACK_EIRQ_MASK,
0304 &res);
0305 }
0306 return 0;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316 static int zynqmp_ipi_startup(struct mbox_chan *chan)
0317 {
0318 struct device *dev = chan->mbox->dev;
0319 struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev);
0320 struct zynqmp_ipi_mchan *mchan = chan->con_priv;
0321 u64 arg0;
0322 struct arm_smccc_res res;
0323 int ret = 0;
0324 unsigned int nchan_type;
0325
0326 if (mchan->is_opened)
0327 return 0;
0328
0329
0330 nchan_type = (mchan->chan_type + 1) % 2;
0331 if (!ipi_mbox->mchans[nchan_type].is_opened) {
0332 arg0 = SMC_IPI_MAILBOX_OPEN;
0333 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0334
0335 ret = (int)(res.a0 & 0xFFFFFFFF);
0336 if (ret < 0) {
0337 dev_err(dev, "SMC to open the IPI channel failed.\n");
0338 return ret;
0339 }
0340 ret = 0;
0341 }
0342
0343
0344 if (mchan->chan_type == IPI_MB_CHNL_RX) {
0345 arg0 = SMC_IPI_MAILBOX_ENABLE_IRQ;
0346 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0347 }
0348 mchan->is_opened = 1;
0349
0350 return ret;
0351 }
0352
0353
0354
0355
0356
0357
0358 static void zynqmp_ipi_shutdown(struct mbox_chan *chan)
0359 {
0360 struct device *dev = chan->mbox->dev;
0361 struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev);
0362 struct zynqmp_ipi_mchan *mchan = chan->con_priv;
0363 u64 arg0;
0364 struct arm_smccc_res res;
0365 unsigned int chan_type;
0366
0367 if (!mchan->is_opened)
0368 return;
0369
0370
0371 chan_type = mchan->chan_type;
0372 if (chan_type == IPI_MB_CHNL_RX) {
0373 arg0 = SMC_IPI_MAILBOX_DISABLE_IRQ;
0374 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0375 }
0376
0377 chan_type = (chan_type + 1) % 2;
0378 if (!ipi_mbox->mchans[chan_type].is_opened) {
0379 arg0 = SMC_IPI_MAILBOX_RELEASE;
0380 zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res);
0381 }
0382
0383 mchan->is_opened = 0;
0384 }
0385
0386
0387 static const struct mbox_chan_ops zynqmp_ipi_chan_ops = {
0388 .startup = zynqmp_ipi_startup,
0389 .shutdown = zynqmp_ipi_shutdown,
0390 .peek_data = zynqmp_ipi_peek_data,
0391 .last_tx_done = zynqmp_ipi_last_tx_done,
0392 .send_data = zynqmp_ipi_send_data,
0393 };
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 static struct mbox_chan *zynqmp_ipi_of_xlate(struct mbox_controller *mbox,
0404 const struct of_phandle_args *p)
0405 {
0406 struct mbox_chan *chan;
0407 struct device *dev = mbox->dev;
0408 unsigned int chan_type;
0409
0410
0411 chan_type = p->args[0];
0412 if (chan_type != IPI_MB_CHNL_TX && chan_type != IPI_MB_CHNL_RX) {
0413 dev_err(dev, "req chnl failure: invalid chnl type %u.\n",
0414 chan_type);
0415 return ERR_PTR(-EINVAL);
0416 }
0417 chan = &mbox->chans[chan_type];
0418 return chan;
0419 }
0420
0421 static const struct of_device_id zynqmp_ipi_of_match[] = {
0422 { .compatible = "xlnx,zynqmp-ipi-mailbox" },
0423 {},
0424 };
0425 MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match);
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436 static int zynqmp_ipi_mbox_get_buf_res(struct device_node *node,
0437 const char *name,
0438 struct resource *res)
0439 {
0440 int ret, index;
0441
0442 index = of_property_match_string(node, "reg-names", name);
0443 if (index >= 0) {
0444 ret = of_address_to_resource(node, index, res);
0445 if (ret < 0)
0446 return -EINVAL;
0447 return 0;
0448 }
0449 return -ENODEV;
0450 }
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460 static void zynqmp_ipi_mbox_dev_release(struct device *dev)
0461 {
0462 (void)dev;
0463 }
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473 static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox,
0474 struct device_node *node)
0475 {
0476 struct zynqmp_ipi_mchan *mchan;
0477 struct mbox_chan *chans;
0478 struct mbox_controller *mbox;
0479 struct resource res;
0480 struct device *dev, *mdev;
0481 const char *name;
0482 int ret;
0483
0484 dev = ipi_mbox->pdata->dev;
0485
0486 ipi_mbox->dev.parent = dev;
0487 ipi_mbox->dev.release = NULL;
0488 ipi_mbox->dev.of_node = node;
0489 dev_set_name(&ipi_mbox->dev, "%s", of_node_full_name(node));
0490 dev_set_drvdata(&ipi_mbox->dev, ipi_mbox);
0491 ipi_mbox->dev.release = zynqmp_ipi_mbox_dev_release;
0492 ipi_mbox->dev.driver = &zynqmp_ipi_mbox_driver;
0493 ret = device_register(&ipi_mbox->dev);
0494 if (ret) {
0495 dev_err(dev, "Failed to register ipi mbox dev.\n");
0496 return ret;
0497 }
0498 mdev = &ipi_mbox->dev;
0499
0500 mchan = &ipi_mbox->mchans[IPI_MB_CHNL_TX];
0501 name = "local_request_region";
0502 ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res);
0503 if (!ret) {
0504 mchan->req_buf_size = resource_size(&res);
0505 mchan->req_buf = devm_ioremap(mdev, res.start,
0506 mchan->req_buf_size);
0507 if (!mchan->req_buf) {
0508 dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
0509 return -ENOMEM;
0510 }
0511 } else if (ret != -ENODEV) {
0512 dev_err(mdev, "Unmatched resource %s, %d.\n", name, ret);
0513 return ret;
0514 }
0515
0516 name = "remote_response_region";
0517 ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res);
0518 if (!ret) {
0519 mchan->resp_buf_size = resource_size(&res);
0520 mchan->resp_buf = devm_ioremap(mdev, res.start,
0521 mchan->resp_buf_size);
0522 if (!mchan->resp_buf) {
0523 dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
0524 return -ENOMEM;
0525 }
0526 } else if (ret != -ENODEV) {
0527 dev_err(mdev, "Unmatched resource %s.\n", name);
0528 return ret;
0529 }
0530 mchan->rx_buf = devm_kzalloc(mdev,
0531 mchan->resp_buf_size +
0532 sizeof(struct zynqmp_ipi_message),
0533 GFP_KERNEL);
0534 if (!mchan->rx_buf)
0535 return -ENOMEM;
0536
0537 mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX];
0538 name = "remote_request_region";
0539 ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res);
0540 if (!ret) {
0541 mchan->req_buf_size = resource_size(&res);
0542 mchan->req_buf = devm_ioremap(mdev, res.start,
0543 mchan->req_buf_size);
0544 if (!mchan->req_buf) {
0545 dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
0546 return -ENOMEM;
0547 }
0548 } else if (ret != -ENODEV) {
0549 dev_err(mdev, "Unmatched resource %s.\n", name);
0550 return ret;
0551 }
0552
0553 name = "local_response_region";
0554 ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res);
0555 if (!ret) {
0556 mchan->resp_buf_size = resource_size(&res);
0557 mchan->resp_buf = devm_ioremap(mdev, res.start,
0558 mchan->resp_buf_size);
0559 if (!mchan->resp_buf) {
0560 dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
0561 return -ENOMEM;
0562 }
0563 } else if (ret != -ENODEV) {
0564 dev_err(mdev, "Unmatched resource %s.\n", name);
0565 return ret;
0566 }
0567 mchan->rx_buf = devm_kzalloc(mdev,
0568 mchan->resp_buf_size +
0569 sizeof(struct zynqmp_ipi_message),
0570 GFP_KERNEL);
0571 if (!mchan->rx_buf)
0572 return -ENOMEM;
0573
0574
0575 ret = of_property_read_u32(node, "xlnx,ipi-id", &ipi_mbox->remote_id);
0576 if (ret < 0) {
0577 dev_err(dev, "No IPI remote ID is specified.\n");
0578 return ret;
0579 }
0580
0581 mbox = &ipi_mbox->mbox;
0582 mbox->dev = mdev;
0583 mbox->ops = &zynqmp_ipi_chan_ops;
0584 mbox->num_chans = 2;
0585 mbox->txdone_irq = false;
0586 mbox->txdone_poll = true;
0587 mbox->txpoll_period = 5;
0588 mbox->of_xlate = zynqmp_ipi_of_xlate;
0589 chans = devm_kzalloc(mdev, 2 * sizeof(*chans), GFP_KERNEL);
0590 if (!chans)
0591 return -ENOMEM;
0592 mbox->chans = chans;
0593 chans[IPI_MB_CHNL_TX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_TX];
0594 chans[IPI_MB_CHNL_RX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_RX];
0595 ipi_mbox->mchans[IPI_MB_CHNL_TX].chan_type = IPI_MB_CHNL_TX;
0596 ipi_mbox->mchans[IPI_MB_CHNL_RX].chan_type = IPI_MB_CHNL_RX;
0597 ret = devm_mbox_controller_register(mdev, mbox);
0598 if (ret)
0599 dev_err(mdev,
0600 "Failed to register mbox_controller(%d)\n", ret);
0601 else
0602 dev_info(mdev,
0603 "Registered ZynqMP IPI mbox with TX/RX channels.\n");
0604 return ret;
0605 }
0606
0607
0608
0609
0610
0611
0612 static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata)
0613 {
0614 struct zynqmp_ipi_mbox *ipi_mbox;
0615 int i;
0616
0617 i = pdata->num_mboxes;
0618 for (; i >= 0; i--) {
0619 ipi_mbox = &pdata->ipi_mboxes[i];
0620 if (ipi_mbox->dev.parent) {
0621 mbox_controller_unregister(&ipi_mbox->mbox);
0622 device_unregister(&ipi_mbox->dev);
0623 }
0624 }
0625 }
0626
0627 static int zynqmp_ipi_probe(struct platform_device *pdev)
0628 {
0629 struct device *dev = &pdev->dev;
0630 struct device_node *nc, *np = pdev->dev.of_node;
0631 struct zynqmp_ipi_pdata *pdata;
0632 struct zynqmp_ipi_mbox *mbox;
0633 int num_mboxes, ret = -EINVAL;
0634
0635 num_mboxes = of_get_child_count(np);
0636 pdata = devm_kzalloc(dev, sizeof(*pdata) + (num_mboxes * sizeof(*mbox)),
0637 GFP_KERNEL);
0638 if (!pdata)
0639 return -ENOMEM;
0640 pdata->dev = dev;
0641
0642
0643 ret = of_property_read_u32(np, "xlnx,ipi-id", &pdata->local_id);
0644 if (ret < 0) {
0645 dev_err(dev, "No IPI local ID is specified.\n");
0646 return ret;
0647 }
0648
0649 pdata->num_mboxes = num_mboxes;
0650 pdata->ipi_mboxes = (struct zynqmp_ipi_mbox *)
0651 ((char *)pdata + sizeof(*pdata));
0652
0653 mbox = pdata->ipi_mboxes;
0654 for_each_available_child_of_node(np, nc) {
0655 mbox->pdata = pdata;
0656 ret = zynqmp_ipi_mbox_probe(mbox, nc);
0657 if (ret) {
0658 of_node_put(nc);
0659 dev_err(dev, "failed to probe subdev.\n");
0660 ret = -EINVAL;
0661 goto free_mbox_dev;
0662 }
0663 mbox++;
0664 }
0665
0666
0667 ret = platform_get_irq(pdev, 0);
0668 if (ret < 0)
0669 goto free_mbox_dev;
0670
0671 pdata->irq = ret;
0672 ret = devm_request_irq(dev, pdata->irq, zynqmp_ipi_interrupt,
0673 IRQF_SHARED, dev_name(dev), pdata);
0674 if (ret) {
0675 dev_err(dev, "IRQ %d is not requested successfully.\n",
0676 pdata->irq);
0677 goto free_mbox_dev;
0678 }
0679
0680 platform_set_drvdata(pdev, pdata);
0681 return ret;
0682
0683 free_mbox_dev:
0684 zynqmp_ipi_free_mboxes(pdata);
0685 return ret;
0686 }
0687
0688 static int zynqmp_ipi_remove(struct platform_device *pdev)
0689 {
0690 struct zynqmp_ipi_pdata *pdata;
0691
0692 pdata = platform_get_drvdata(pdev);
0693 zynqmp_ipi_free_mboxes(pdata);
0694
0695 return 0;
0696 }
0697
0698 static struct platform_driver zynqmp_ipi_driver = {
0699 .probe = zynqmp_ipi_probe,
0700 .remove = zynqmp_ipi_remove,
0701 .driver = {
0702 .name = "zynqmp-ipi",
0703 .of_match_table = of_match_ptr(zynqmp_ipi_of_match),
0704 },
0705 };
0706
0707 static int __init zynqmp_ipi_init(void)
0708 {
0709 return platform_driver_register(&zynqmp_ipi_driver);
0710 }
0711 subsys_initcall(zynqmp_ipi_init);
0712
0713 static void __exit zynqmp_ipi_exit(void)
0714 {
0715 platform_driver_unregister(&zynqmp_ipi_driver);
0716 }
0717 module_exit(zynqmp_ipi_exit);
0718
0719 MODULE_LICENSE("GPL v2");
0720 MODULE_DESCRIPTION("Xilinx ZynqMP IPI Mailbox driver");
0721 MODULE_AUTHOR("Xilinx Inc.");