root/drivers/mailbox/hi6220-mailbox.c

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

DEFINITIONS

This source file includes following definitions.
  1. mbox_set_state
  2. mbox_set_mode
  3. hi6220_mbox_last_tx_done
  4. hi6220_mbox_send_data
  5. hi6220_mbox_interrupt
  6. hi6220_mbox_startup
  7. hi6220_mbox_shutdown
  8. hi6220_mbox_xlate
  9. hi6220_mbox_probe
  10. hi6220_mbox_init
  11. hi6220_mbox_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Hisilicon's Hi6220 mailbox driver
   4  *
   5  * Copyright (c) 2015 Hisilicon Limited.
   6  * Copyright (c) 2015 Linaro Limited.
   7  *
   8  * Author: Leo Yan <leo.yan@linaro.org>
   9  */
  10 
  11 #include <linux/device.h>
  12 #include <linux/err.h>
  13 #include <linux/interrupt.h>
  14 #include <linux/io.h>
  15 #include <linux/kfifo.h>
  16 #include <linux/mailbox_controller.h>
  17 #include <linux/module.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/slab.h>
  20 
  21 #define MBOX_CHAN_MAX                   32
  22 
  23 #define MBOX_TX                         0x1
  24 
  25 /* Mailbox message length: 8 words */
  26 #define MBOX_MSG_LEN                    8
  27 
  28 /* Mailbox Registers */
  29 #define MBOX_OFF(m)                     (0x40 * (m))
  30 #define MBOX_MODE_REG(m)                (MBOX_OFF(m) + 0x0)
  31 #define MBOX_DATA_REG(m)                (MBOX_OFF(m) + 0x4)
  32 
  33 #define MBOX_STATE_MASK                 (0xF << 4)
  34 #define MBOX_STATE_IDLE                 (0x1 << 4)
  35 #define MBOX_STATE_TX                   (0x2 << 4)
  36 #define MBOX_STATE_RX                   (0x4 << 4)
  37 #define MBOX_STATE_ACK                  (0x8 << 4)
  38 #define MBOX_ACK_CONFIG_MASK            (0x1 << 0)
  39 #define MBOX_ACK_AUTOMATIC              (0x1 << 0)
  40 #define MBOX_ACK_IRQ                    (0x0 << 0)
  41 
  42 /* IPC registers */
  43 #define ACK_INT_RAW_REG(i)              ((i) + 0x400)
  44 #define ACK_INT_MSK_REG(i)              ((i) + 0x404)
  45 #define ACK_INT_STAT_REG(i)             ((i) + 0x408)
  46 #define ACK_INT_CLR_REG(i)              ((i) + 0x40c)
  47 #define ACK_INT_ENA_REG(i)              ((i) + 0x500)
  48 #define ACK_INT_DIS_REG(i)              ((i) + 0x504)
  49 #define DST_INT_RAW_REG(i)              ((i) + 0x420)
  50 
  51 
  52 struct hi6220_mbox_chan {
  53 
  54         /*
  55          * Description for channel's hardware info:
  56          *  - direction: tx or rx
  57          *  - dst irq: peer core's irq number
  58          *  - ack irq: local irq number
  59          *  - slot number
  60          */
  61         unsigned int dir, dst_irq, ack_irq;
  62         unsigned int slot;
  63 
  64         struct hi6220_mbox *parent;
  65 };
  66 
  67 struct hi6220_mbox {
  68         struct device *dev;
  69 
  70         int irq;
  71 
  72         /* flag of enabling tx's irq mode */
  73         bool tx_irq_mode;
  74 
  75         /* region for ipc event */
  76         void __iomem *ipc;
  77 
  78         /* region for mailbox */
  79         void __iomem *base;
  80 
  81         unsigned int chan_num;
  82         struct hi6220_mbox_chan *mchan;
  83 
  84         void *irq_map_chan[MBOX_CHAN_MAX];
  85         struct mbox_chan *chan;
  86         struct mbox_controller controller;
  87 };
  88 
  89 static void mbox_set_state(struct hi6220_mbox *mbox,
  90                            unsigned int slot, u32 val)
  91 {
  92         u32 status;
  93 
  94         status = readl(mbox->base + MBOX_MODE_REG(slot));
  95         status = (status & ~MBOX_STATE_MASK) | val;
  96         writel(status, mbox->base + MBOX_MODE_REG(slot));
  97 }
  98 
  99 static void mbox_set_mode(struct hi6220_mbox *mbox,
 100                           unsigned int slot, u32 val)
 101 {
 102         u32 mode;
 103 
 104         mode = readl(mbox->base + MBOX_MODE_REG(slot));
 105         mode = (mode & ~MBOX_ACK_CONFIG_MASK) | val;
 106         writel(mode, mbox->base + MBOX_MODE_REG(slot));
 107 }
 108 
 109 static bool hi6220_mbox_last_tx_done(struct mbox_chan *chan)
 110 {
 111         struct hi6220_mbox_chan *mchan = chan->con_priv;
 112         struct hi6220_mbox *mbox = mchan->parent;
 113         u32 state;
 114 
 115         /* Only set idle state for polling mode */
 116         BUG_ON(mbox->tx_irq_mode);
 117 
 118         state = readl(mbox->base + MBOX_MODE_REG(mchan->slot));
 119         return ((state & MBOX_STATE_MASK) == MBOX_STATE_IDLE);
 120 }
 121 
 122 static int hi6220_mbox_send_data(struct mbox_chan *chan, void *msg)
 123 {
 124         struct hi6220_mbox_chan *mchan = chan->con_priv;
 125         struct hi6220_mbox *mbox = mchan->parent;
 126         unsigned int slot = mchan->slot;
 127         u32 *buf = msg;
 128         int i;
 129 
 130         /* indicate as a TX channel */
 131         mchan->dir = MBOX_TX;
 132 
 133         mbox_set_state(mbox, slot, MBOX_STATE_TX);
 134 
 135         if (mbox->tx_irq_mode)
 136                 mbox_set_mode(mbox, slot, MBOX_ACK_IRQ);
 137         else
 138                 mbox_set_mode(mbox, slot, MBOX_ACK_AUTOMATIC);
 139 
 140         for (i = 0; i < MBOX_MSG_LEN; i++)
 141                 writel(buf[i], mbox->base + MBOX_DATA_REG(slot) + i * 4);
 142 
 143         /* trigger remote request */
 144         writel(BIT(mchan->dst_irq), DST_INT_RAW_REG(mbox->ipc));
 145         return 0;
 146 }
 147 
 148 static irqreturn_t hi6220_mbox_interrupt(int irq, void *p)
 149 {
 150         struct hi6220_mbox *mbox = p;
 151         struct hi6220_mbox_chan *mchan;
 152         struct mbox_chan *chan;
 153         unsigned int state, intr_bit, i;
 154         u32 msg[MBOX_MSG_LEN];
 155 
 156         state = readl(ACK_INT_STAT_REG(mbox->ipc));
 157         if (!state) {
 158                 dev_warn(mbox->dev, "%s: spurious interrupt\n",
 159                          __func__);
 160                 return IRQ_HANDLED;
 161         }
 162 
 163         while (state) {
 164                 intr_bit = __ffs(state);
 165                 state &= (state - 1);
 166 
 167                 chan = mbox->irq_map_chan[intr_bit];
 168                 if (!chan) {
 169                         dev_warn(mbox->dev, "%s: unexpected irq vector %d\n",
 170                                  __func__, intr_bit);
 171                         continue;
 172                 }
 173 
 174                 mchan = chan->con_priv;
 175                 if (mchan->dir == MBOX_TX)
 176                         mbox_chan_txdone(chan, 0);
 177                 else {
 178                         for (i = 0; i < MBOX_MSG_LEN; i++)
 179                                 msg[i] = readl(mbox->base +
 180                                         MBOX_DATA_REG(mchan->slot) + i * 4);
 181 
 182                         mbox_chan_received_data(chan, (void *)msg);
 183                 }
 184 
 185                 /* clear IRQ source */
 186                 writel(BIT(mchan->ack_irq), ACK_INT_CLR_REG(mbox->ipc));
 187                 mbox_set_state(mbox, mchan->slot, MBOX_STATE_IDLE);
 188         }
 189 
 190         return IRQ_HANDLED;
 191 }
 192 
 193 static int hi6220_mbox_startup(struct mbox_chan *chan)
 194 {
 195         struct hi6220_mbox_chan *mchan = chan->con_priv;
 196         struct hi6220_mbox *mbox = mchan->parent;
 197 
 198         mchan->dir = 0;
 199 
 200         /* enable interrupt */
 201         writel(BIT(mchan->ack_irq), ACK_INT_ENA_REG(mbox->ipc));
 202         return 0;
 203 }
 204 
 205 static void hi6220_mbox_shutdown(struct mbox_chan *chan)
 206 {
 207         struct hi6220_mbox_chan *mchan = chan->con_priv;
 208         struct hi6220_mbox *mbox = mchan->parent;
 209 
 210         /* disable interrupt */
 211         writel(BIT(mchan->ack_irq), ACK_INT_DIS_REG(mbox->ipc));
 212         mbox->irq_map_chan[mchan->ack_irq] = NULL;
 213 }
 214 
 215 static const struct mbox_chan_ops hi6220_mbox_ops = {
 216         .send_data    = hi6220_mbox_send_data,
 217         .startup      = hi6220_mbox_startup,
 218         .shutdown     = hi6220_mbox_shutdown,
 219         .last_tx_done = hi6220_mbox_last_tx_done,
 220 };
 221 
 222 static struct mbox_chan *hi6220_mbox_xlate(struct mbox_controller *controller,
 223                                            const struct of_phandle_args *spec)
 224 {
 225         struct hi6220_mbox *mbox = dev_get_drvdata(controller->dev);
 226         struct hi6220_mbox_chan *mchan;
 227         struct mbox_chan *chan;
 228         unsigned int i = spec->args[0];
 229         unsigned int dst_irq = spec->args[1];
 230         unsigned int ack_irq = spec->args[2];
 231 
 232         /* Bounds checking */
 233         if (i >= mbox->chan_num || dst_irq >= mbox->chan_num ||
 234             ack_irq >= mbox->chan_num) {
 235                 dev_err(mbox->dev,
 236                         "Invalid channel idx %d dst_irq %d ack_irq %d\n",
 237                         i, dst_irq, ack_irq);
 238                 return ERR_PTR(-EINVAL);
 239         }
 240 
 241         /* Is requested channel free? */
 242         chan = &mbox->chan[i];
 243         if (mbox->irq_map_chan[ack_irq] == (void *)chan) {
 244                 dev_err(mbox->dev, "Channel in use\n");
 245                 return ERR_PTR(-EBUSY);
 246         }
 247 
 248         mchan = chan->con_priv;
 249         mchan->dst_irq = dst_irq;
 250         mchan->ack_irq = ack_irq;
 251 
 252         mbox->irq_map_chan[ack_irq] = (void *)chan;
 253         return chan;
 254 }
 255 
 256 static const struct of_device_id hi6220_mbox_of_match[] = {
 257         { .compatible = "hisilicon,hi6220-mbox", },
 258         {},
 259 };
 260 MODULE_DEVICE_TABLE(of, hi6220_mbox_of_match);
 261 
 262 static int hi6220_mbox_probe(struct platform_device *pdev)
 263 {
 264         struct device_node *node = pdev->dev.of_node;
 265         struct device *dev = &pdev->dev;
 266         struct hi6220_mbox *mbox;
 267         struct resource *res;
 268         int i, err;
 269 
 270         mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
 271         if (!mbox)
 272                 return -ENOMEM;
 273 
 274         mbox->dev = dev;
 275         mbox->chan_num = MBOX_CHAN_MAX;
 276         mbox->mchan = devm_kcalloc(dev,
 277                 mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL);
 278         if (!mbox->mchan)
 279                 return -ENOMEM;
 280 
 281         mbox->chan = devm_kcalloc(dev,
 282                 mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL);
 283         if (!mbox->chan)
 284                 return -ENOMEM;
 285 
 286         mbox->irq = platform_get_irq(pdev, 0);
 287         if (mbox->irq < 0)
 288                 return mbox->irq;
 289 
 290         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 291         mbox->ipc = devm_ioremap_resource(dev, res);
 292         if (IS_ERR(mbox->ipc)) {
 293                 dev_err(dev, "ioremap ipc failed\n");
 294                 return PTR_ERR(mbox->ipc);
 295         }
 296 
 297         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 298         mbox->base = devm_ioremap_resource(dev, res);
 299         if (IS_ERR(mbox->base)) {
 300                 dev_err(dev, "ioremap buffer failed\n");
 301                 return PTR_ERR(mbox->base);
 302         }
 303 
 304         err = devm_request_irq(dev, mbox->irq, hi6220_mbox_interrupt, 0,
 305                         dev_name(dev), mbox);
 306         if (err) {
 307                 dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
 308                         err);
 309                 return -ENODEV;
 310         }
 311 
 312         mbox->controller.dev = dev;
 313         mbox->controller.chans = &mbox->chan[0];
 314         mbox->controller.num_chans = mbox->chan_num;
 315         mbox->controller.ops = &hi6220_mbox_ops;
 316         mbox->controller.of_xlate = hi6220_mbox_xlate;
 317 
 318         for (i = 0; i < mbox->chan_num; i++) {
 319                 mbox->chan[i].con_priv = &mbox->mchan[i];
 320                 mbox->irq_map_chan[i] = NULL;
 321 
 322                 mbox->mchan[i].parent = mbox;
 323                 mbox->mchan[i].slot   = i;
 324         }
 325 
 326         /* mask and clear all interrupt vectors */
 327         writel(0x0,  ACK_INT_MSK_REG(mbox->ipc));
 328         writel(~0x0, ACK_INT_CLR_REG(mbox->ipc));
 329 
 330         /* use interrupt for tx's ack */
 331         if (of_find_property(node, "hi6220,mbox-tx-noirq", NULL))
 332                 mbox->tx_irq_mode = false;
 333         else
 334                 mbox->tx_irq_mode = true;
 335 
 336         if (mbox->tx_irq_mode)
 337                 mbox->controller.txdone_irq = true;
 338         else {
 339                 mbox->controller.txdone_poll = true;
 340                 mbox->controller.txpoll_period = 5;
 341         }
 342 
 343         err = devm_mbox_controller_register(dev, &mbox->controller);
 344         if (err) {
 345                 dev_err(dev, "Failed to register mailbox %d\n", err);
 346                 return err;
 347         }
 348 
 349         platform_set_drvdata(pdev, mbox);
 350         dev_info(dev, "Mailbox enabled\n");
 351         return 0;
 352 }
 353 
 354 static struct platform_driver hi6220_mbox_driver = {
 355         .driver = {
 356                 .name = "hi6220-mbox",
 357                 .owner = THIS_MODULE,
 358                 .of_match_table = hi6220_mbox_of_match,
 359         },
 360         .probe  = hi6220_mbox_probe,
 361 };
 362 
 363 static int __init hi6220_mbox_init(void)
 364 {
 365         return platform_driver_register(&hi6220_mbox_driver);
 366 }
 367 core_initcall(hi6220_mbox_init);
 368 
 369 static void __exit hi6220_mbox_exit(void)
 370 {
 371         platform_driver_unregister(&hi6220_mbox_driver);
 372 }
 373 module_exit(hi6220_mbox_exit);
 374 
 375 MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
 376 MODULE_DESCRIPTION("Hi6220 mailbox driver");
 377 MODULE_LICENSE("GPL v2");

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