root/drivers/mailbox/mailbox-xgene-slimpro.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mb_chan_send_msg
  2. mb_chan_recv_msg
  3. mb_chan_status_ack
  4. mb_chan_status_avail
  5. slimpro_mbox_irq
  6. slimpro_mbox_send_data
  7. slimpro_mbox_startup
  8. slimpro_mbox_shutdown
  9. slimpro_mbox_probe
  10. slimpro_mbox_init
  11. slimpro_mbox_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * APM X-Gene SLIMpro MailBox Driver
   4  *
   5  * Copyright (c) 2015, Applied Micro Circuits Corporation
   6  * Author: Feng Kan fkan@apm.com
   7  */
   8 #include <linux/acpi.h>
   9 #include <linux/delay.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/io.h>
  12 #include <linux/mailbox_controller.h>
  13 #include <linux/module.h>
  14 #include <linux/of.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/spinlock.h>
  17 
  18 #define MBOX_CON_NAME                   "slimpro-mbox"
  19 #define MBOX_REG_SET_OFFSET             0x1000
  20 #define MBOX_CNT                        8
  21 #define MBOX_STATUS_AVAIL_MASK          BIT(16)
  22 #define MBOX_STATUS_ACK_MASK            BIT(0)
  23 
  24 /* Configuration and Status Registers */
  25 #define REG_DB_IN               0x00
  26 #define REG_DB_DIN0             0x04
  27 #define REG_DB_DIN1             0x08
  28 #define REG_DB_OUT              0x10
  29 #define REG_DB_DOUT0            0x14
  30 #define REG_DB_DOUT1            0x18
  31 #define REG_DB_STAT             0x20
  32 #define REG_DB_STATMASK         0x24
  33 
  34 /**
  35  * X-Gene SlimPRO mailbox channel information
  36  *
  37  * @dev:        Device to which it is attached
  38  * @chan:       Pointer to mailbox communication channel
  39  * @reg:        Base address to access channel registers
  40  * @irq:        Interrupt number of the channel
  41  * @rx_msg:     Received message storage
  42  */
  43 struct slimpro_mbox_chan {
  44         struct device           *dev;
  45         struct mbox_chan        *chan;
  46         void __iomem            *reg;
  47         int                     irq;
  48         u32                     rx_msg[3];
  49 };
  50 
  51 /**
  52  * X-Gene SlimPRO Mailbox controller data
  53  *
  54  * X-Gene SlimPRO Mailbox controller has 8 commnunication channels.
  55  * Each channel has a separate IRQ number assgined to it.
  56  *
  57  * @mb_ctrl:    Representation of the commnunication channel controller
  58  * @mc:         Array of SlimPRO mailbox channels of the controller
  59  * @chans:      Array of mailbox communication channels
  60  *
  61  */
  62 struct slimpro_mbox {
  63         struct mbox_controller          mb_ctrl;
  64         struct slimpro_mbox_chan        mc[MBOX_CNT];
  65         struct mbox_chan                chans[MBOX_CNT];
  66 };
  67 
  68 static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
  69 {
  70         writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
  71         writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
  72         writel(msg[0], mb_chan->reg + REG_DB_OUT);
  73 }
  74 
  75 static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
  76 {
  77         mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
  78         mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
  79         mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
  80 }
  81 
  82 static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
  83 {
  84         u32 val = readl(mb_chan->reg + REG_DB_STAT);
  85 
  86         if (val & MBOX_STATUS_ACK_MASK) {
  87                 writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
  88                 return 1;
  89         }
  90         return 0;
  91 }
  92 
  93 static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
  94 {
  95         u32 val = readl(mb_chan->reg + REG_DB_STAT);
  96 
  97         if (val & MBOX_STATUS_AVAIL_MASK) {
  98                 mb_chan_recv_msg(mb_chan);
  99                 writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
 100                 return 1;
 101         }
 102         return 0;
 103 }
 104 
 105 static irqreturn_t slimpro_mbox_irq(int irq, void *id)
 106 {
 107         struct slimpro_mbox_chan *mb_chan = id;
 108 
 109         if (mb_chan_status_ack(mb_chan))
 110                 mbox_chan_txdone(mb_chan->chan, 0);
 111 
 112         if (mb_chan_status_avail(mb_chan))
 113                 mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
 114 
 115         return IRQ_HANDLED;
 116 }
 117 
 118 static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
 119 {
 120         struct slimpro_mbox_chan *mb_chan = chan->con_priv;
 121 
 122         mb_chan_send_msg(mb_chan, msg);
 123         return 0;
 124 }
 125 
 126 static int slimpro_mbox_startup(struct mbox_chan *chan)
 127 {
 128         struct slimpro_mbox_chan *mb_chan = chan->con_priv;
 129         int rc;
 130         u32 val;
 131 
 132         rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
 133                               MBOX_CON_NAME, mb_chan);
 134         if (unlikely(rc)) {
 135                 dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
 136                         mb_chan->irq);
 137                 return rc;
 138         }
 139 
 140         /* Enable HW interrupt */
 141         writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
 142                mb_chan->reg + REG_DB_STAT);
 143         /* Unmask doorbell status interrupt */
 144         val = readl(mb_chan->reg + REG_DB_STATMASK);
 145         val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
 146         writel(val, mb_chan->reg + REG_DB_STATMASK);
 147 
 148         return 0;
 149 }
 150 
 151 static void slimpro_mbox_shutdown(struct mbox_chan *chan)
 152 {
 153         struct slimpro_mbox_chan *mb_chan = chan->con_priv;
 154         u32 val;
 155 
 156         /* Mask doorbell status interrupt */
 157         val = readl(mb_chan->reg + REG_DB_STATMASK);
 158         val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
 159         writel(val, mb_chan->reg + REG_DB_STATMASK);
 160 
 161         devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
 162 }
 163 
 164 static const struct mbox_chan_ops slimpro_mbox_ops = {
 165         .send_data = slimpro_mbox_send_data,
 166         .startup = slimpro_mbox_startup,
 167         .shutdown = slimpro_mbox_shutdown,
 168 };
 169 
 170 static int slimpro_mbox_probe(struct platform_device *pdev)
 171 {
 172         struct slimpro_mbox *ctx;
 173         struct resource *regs;
 174         void __iomem *mb_base;
 175         int rc;
 176         int i;
 177 
 178         ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
 179         if (!ctx)
 180                 return -ENOMEM;
 181 
 182         platform_set_drvdata(pdev, ctx);
 183 
 184         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 185         mb_base = devm_ioremap_resource(&pdev->dev, regs);
 186         if (IS_ERR(mb_base))
 187                 return PTR_ERR(mb_base);
 188 
 189         /* Setup mailbox links */
 190         for (i = 0; i < MBOX_CNT; i++) {
 191                 ctx->mc[i].irq = platform_get_irq(pdev, i);
 192                 if (ctx->mc[i].irq < 0) {
 193                         if (i == 0) {
 194                                 dev_err(&pdev->dev, "no available IRQ\n");
 195                                 return -EINVAL;
 196                         }
 197                         dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
 198                         break;
 199                 }
 200 
 201                 ctx->mc[i].dev = &pdev->dev;
 202                 ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
 203                 ctx->mc[i].chan = &ctx->chans[i];
 204                 ctx->chans[i].con_priv = &ctx->mc[i];
 205         }
 206 
 207         /* Setup mailbox controller */
 208         ctx->mb_ctrl.dev = &pdev->dev;
 209         ctx->mb_ctrl.chans = ctx->chans;
 210         ctx->mb_ctrl.txdone_irq = true;
 211         ctx->mb_ctrl.ops = &slimpro_mbox_ops;
 212         ctx->mb_ctrl.num_chans = i;
 213 
 214         rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl);
 215         if (rc) {
 216                 dev_err(&pdev->dev,
 217                         "APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
 218                 return rc;
 219         }
 220 
 221         dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
 222         return 0;
 223 }
 224 
 225 static const struct of_device_id slimpro_of_match[] = {
 226         {.compatible = "apm,xgene-slimpro-mbox" },
 227         { },
 228 };
 229 MODULE_DEVICE_TABLE(of, slimpro_of_match);
 230 
 231 #ifdef CONFIG_ACPI
 232 static const struct acpi_device_id slimpro_acpi_ids[] = {
 233         {"APMC0D01", 0},
 234         {}
 235 };
 236 MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
 237 #endif
 238 
 239 static struct platform_driver slimpro_mbox_driver = {
 240         .probe  = slimpro_mbox_probe,
 241         .driver = {
 242                 .name = "xgene-slimpro-mbox",
 243                 .of_match_table = of_match_ptr(slimpro_of_match),
 244                 .acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
 245         },
 246 };
 247 
 248 static int __init slimpro_mbox_init(void)
 249 {
 250         return platform_driver_register(&slimpro_mbox_driver);
 251 }
 252 
 253 static void __exit slimpro_mbox_exit(void)
 254 {
 255         platform_driver_unregister(&slimpro_mbox_driver);
 256 }
 257 
 258 subsys_initcall(slimpro_mbox_init);
 259 module_exit(slimpro_mbox_exit);
 260 
 261 MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
 262 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */