Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * APM X-Gene SLIMpro MailBox Driver
0004  *
0005  * Copyright (c) 2015, Applied Micro Circuits Corporation
0006  * Author: Feng Kan fkan@apm.com
0007  */
0008 #include <linux/acpi.h>
0009 #include <linux/delay.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/io.h>
0012 #include <linux/mailbox_controller.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/spinlock.h>
0017 
0018 #define MBOX_CON_NAME           "slimpro-mbox"
0019 #define MBOX_REG_SET_OFFSET     0x1000
0020 #define MBOX_CNT            8
0021 #define MBOX_STATUS_AVAIL_MASK      BIT(16)
0022 #define MBOX_STATUS_ACK_MASK        BIT(0)
0023 
0024 /* Configuration and Status Registers */
0025 #define REG_DB_IN       0x00
0026 #define REG_DB_DIN0     0x04
0027 #define REG_DB_DIN1     0x08
0028 #define REG_DB_OUT      0x10
0029 #define REG_DB_DOUT0        0x14
0030 #define REG_DB_DOUT1        0x18
0031 #define REG_DB_STAT     0x20
0032 #define REG_DB_STATMASK     0x24
0033 
0034 /**
0035  * X-Gene SlimPRO mailbox channel information
0036  *
0037  * @dev:    Device to which it is attached
0038  * @chan:   Pointer to mailbox communication channel
0039  * @reg:    Base address to access channel registers
0040  * @irq:    Interrupt number of the channel
0041  * @rx_msg: Received message storage
0042  */
0043 struct slimpro_mbox_chan {
0044     struct device       *dev;
0045     struct mbox_chan    *chan;
0046     void __iomem        *reg;
0047     int         irq;
0048     u32         rx_msg[3];
0049 };
0050 
0051 /**
0052  * X-Gene SlimPRO Mailbox controller data
0053  *
0054  * X-Gene SlimPRO Mailbox controller has 8 communication channels.
0055  * Each channel has a separate IRQ number assigned to it.
0056  *
0057  * @mb_ctrl:    Representation of the communication channel controller
0058  * @mc:     Array of SlimPRO mailbox channels of the controller
0059  * @chans:  Array of mailbox communication channels
0060  *
0061  */
0062 struct slimpro_mbox {
0063     struct mbox_controller      mb_ctrl;
0064     struct slimpro_mbox_chan    mc[MBOX_CNT];
0065     struct mbox_chan        chans[MBOX_CNT];
0066 };
0067 
0068 static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
0069 {
0070     writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
0071     writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
0072     writel(msg[0], mb_chan->reg + REG_DB_OUT);
0073 }
0074 
0075 static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
0076 {
0077     mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
0078     mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
0079     mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
0080 }
0081 
0082 static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
0083 {
0084     u32 val = readl(mb_chan->reg + REG_DB_STAT);
0085 
0086     if (val & MBOX_STATUS_ACK_MASK) {
0087         writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
0088         return 1;
0089     }
0090     return 0;
0091 }
0092 
0093 static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
0094 {
0095     u32 val = readl(mb_chan->reg + REG_DB_STAT);
0096 
0097     if (val & MBOX_STATUS_AVAIL_MASK) {
0098         mb_chan_recv_msg(mb_chan);
0099         writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
0100         return 1;
0101     }
0102     return 0;
0103 }
0104 
0105 static irqreturn_t slimpro_mbox_irq(int irq, void *id)
0106 {
0107     struct slimpro_mbox_chan *mb_chan = id;
0108 
0109     if (mb_chan_status_ack(mb_chan))
0110         mbox_chan_txdone(mb_chan->chan, 0);
0111 
0112     if (mb_chan_status_avail(mb_chan))
0113         mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
0114 
0115     return IRQ_HANDLED;
0116 }
0117 
0118 static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
0119 {
0120     struct slimpro_mbox_chan *mb_chan = chan->con_priv;
0121 
0122     mb_chan_send_msg(mb_chan, msg);
0123     return 0;
0124 }
0125 
0126 static int slimpro_mbox_startup(struct mbox_chan *chan)
0127 {
0128     struct slimpro_mbox_chan *mb_chan = chan->con_priv;
0129     int rc;
0130     u32 val;
0131 
0132     rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
0133                   MBOX_CON_NAME, mb_chan);
0134     if (unlikely(rc)) {
0135         dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
0136             mb_chan->irq);
0137         return rc;
0138     }
0139 
0140     /* Enable HW interrupt */
0141     writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
0142            mb_chan->reg + REG_DB_STAT);
0143     /* Unmask doorbell status interrupt */
0144     val = readl(mb_chan->reg + REG_DB_STATMASK);
0145     val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
0146     writel(val, mb_chan->reg + REG_DB_STATMASK);
0147 
0148     return 0;
0149 }
0150 
0151 static void slimpro_mbox_shutdown(struct mbox_chan *chan)
0152 {
0153     struct slimpro_mbox_chan *mb_chan = chan->con_priv;
0154     u32 val;
0155 
0156     /* Mask doorbell status interrupt */
0157     val = readl(mb_chan->reg + REG_DB_STATMASK);
0158     val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
0159     writel(val, mb_chan->reg + REG_DB_STATMASK);
0160 
0161     devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
0162 }
0163 
0164 static const struct mbox_chan_ops slimpro_mbox_ops = {
0165     .send_data = slimpro_mbox_send_data,
0166     .startup = slimpro_mbox_startup,
0167     .shutdown = slimpro_mbox_shutdown,
0168 };
0169 
0170 static int slimpro_mbox_probe(struct platform_device *pdev)
0171 {
0172     struct slimpro_mbox *ctx;
0173     void __iomem *mb_base;
0174     int rc;
0175     int i;
0176 
0177     ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
0178     if (!ctx)
0179         return -ENOMEM;
0180 
0181     platform_set_drvdata(pdev, ctx);
0182 
0183     mb_base = devm_platform_ioremap_resource(pdev, 0);
0184     if (IS_ERR(mb_base))
0185         return PTR_ERR(mb_base);
0186 
0187     /* Setup mailbox links */
0188     for (i = 0; i < MBOX_CNT; i++) {
0189         ctx->mc[i].irq = platform_get_irq(pdev, i);
0190         if (ctx->mc[i].irq < 0) {
0191             if (i == 0) {
0192                 dev_err(&pdev->dev, "no available IRQ\n");
0193                 return -EINVAL;
0194             }
0195             dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
0196             break;
0197         }
0198 
0199         ctx->mc[i].dev = &pdev->dev;
0200         ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
0201         ctx->mc[i].chan = &ctx->chans[i];
0202         ctx->chans[i].con_priv = &ctx->mc[i];
0203     }
0204 
0205     /* Setup mailbox controller */
0206     ctx->mb_ctrl.dev = &pdev->dev;
0207     ctx->mb_ctrl.chans = ctx->chans;
0208     ctx->mb_ctrl.txdone_irq = true;
0209     ctx->mb_ctrl.ops = &slimpro_mbox_ops;
0210     ctx->mb_ctrl.num_chans = i;
0211 
0212     rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl);
0213     if (rc) {
0214         dev_err(&pdev->dev,
0215             "APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
0216         return rc;
0217     }
0218 
0219     dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
0220     return 0;
0221 }
0222 
0223 static const struct of_device_id slimpro_of_match[] = {
0224     {.compatible = "apm,xgene-slimpro-mbox" },
0225     { },
0226 };
0227 MODULE_DEVICE_TABLE(of, slimpro_of_match);
0228 
0229 #ifdef CONFIG_ACPI
0230 static const struct acpi_device_id slimpro_acpi_ids[] = {
0231     {"APMC0D01", 0},
0232     {}
0233 };
0234 MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
0235 #endif
0236 
0237 static struct platform_driver slimpro_mbox_driver = {
0238     .probe  = slimpro_mbox_probe,
0239     .driver = {
0240         .name = "xgene-slimpro-mbox",
0241         .of_match_table = of_match_ptr(slimpro_of_match),
0242         .acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
0243     },
0244 };
0245 
0246 static int __init slimpro_mbox_init(void)
0247 {
0248     return platform_driver_register(&slimpro_mbox_driver);
0249 }
0250 
0251 static void __exit slimpro_mbox_exit(void)
0252 {
0253     platform_driver_unregister(&slimpro_mbox_driver);
0254 }
0255 
0256 subsys_initcall(slimpro_mbox_init);
0257 module_exit(slimpro_mbox_exit);
0258 
0259 MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
0260 MODULE_LICENSE("GPL");