root/drivers/mailbox/mailbox-altera.c

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

DEFINITIONS

This source file includes following definitions.
  1. mbox_chan_to_altera_mbox
  2. altera_mbox_full
  3. altera_mbox_pending
  4. altera_mbox_rx_intmask
  5. altera_mbox_tx_intmask
  6. altera_mbox_is_sender
  7. altera_mbox_rx_data
  8. altera_mbox_poll_rx
  9. altera_mbox_tx_interrupt
  10. altera_mbox_rx_interrupt
  11. altera_mbox_startup_sender
  12. altera_mbox_startup_receiver
  13. altera_mbox_send_data
  14. altera_mbox_last_tx_done
  15. altera_mbox_peek_data
  16. altera_mbox_startup
  17. altera_mbox_shutdown
  18. altera_mbox_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright Altera Corporation (C) 2013-2014. All rights reserved
   4  */
   5 
   6 #include <linux/device.h>
   7 #include <linux/interrupt.h>
   8 #include <linux/io.h>
   9 #include <linux/kernel.h>
  10 #include <linux/mailbox_controller.h>
  11 #include <linux/module.h>
  12 #include <linux/of.h>
  13 #include <linux/platform_device.h>
  14 
  15 #define DRIVER_NAME     "altera-mailbox"
  16 
  17 #define MAILBOX_CMD_REG                 0x00
  18 #define MAILBOX_PTR_REG                 0x04
  19 #define MAILBOX_STS_REG                 0x08
  20 #define MAILBOX_INTMASK_REG             0x0C
  21 
  22 #define INT_PENDING_MSK                 0x1
  23 #define INT_SPACE_MSK                   0x2
  24 
  25 #define STS_PENDING_MSK                 0x1
  26 #define STS_FULL_MSK                    0x2
  27 #define STS_FULL_OFT                    0x1
  28 
  29 #define MBOX_PENDING(status)    (((status) & STS_PENDING_MSK))
  30 #define MBOX_FULL(status)       (((status) & STS_FULL_MSK) >> STS_FULL_OFT)
  31 
  32 enum altera_mbox_msg {
  33         MBOX_CMD = 0,
  34         MBOX_PTR,
  35 };
  36 
  37 #define MBOX_POLLING_MS         5       /* polling interval 5ms */
  38 
  39 struct altera_mbox {
  40         bool is_sender;         /* 1-sender, 0-receiver */
  41         bool intr_mode;
  42         int irq;
  43         void __iomem *mbox_base;
  44         struct device *dev;
  45         struct mbox_controller controller;
  46 
  47         /* If the controller supports only RX polling mode */
  48         struct timer_list rxpoll_timer;
  49         struct mbox_chan *chan;
  50 };
  51 
  52 static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan)
  53 {
  54         if (!chan || !chan->con_priv)
  55                 return NULL;
  56 
  57         return (struct altera_mbox *)chan->con_priv;
  58 }
  59 
  60 static inline int altera_mbox_full(struct altera_mbox *mbox)
  61 {
  62         u32 status;
  63 
  64         status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
  65         return MBOX_FULL(status);
  66 }
  67 
  68 static inline int altera_mbox_pending(struct altera_mbox *mbox)
  69 {
  70         u32 status;
  71 
  72         status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
  73         return MBOX_PENDING(status);
  74 }
  75 
  76 static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable)
  77 {
  78         u32 mask;
  79 
  80         mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
  81         if (enable)
  82                 mask |= INT_PENDING_MSK;
  83         else
  84                 mask &= ~INT_PENDING_MSK;
  85         writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
  86 }
  87 
  88 static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable)
  89 {
  90         u32 mask;
  91 
  92         mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
  93         if (enable)
  94                 mask |= INT_SPACE_MSK;
  95         else
  96                 mask &= ~INT_SPACE_MSK;
  97         writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
  98 }
  99 
 100 static bool altera_mbox_is_sender(struct altera_mbox *mbox)
 101 {
 102         u32 reg;
 103         /* Write a magic number to PTR register and read back this register.
 104          * This register is read-write if it is a sender.
 105          */
 106         #define MBOX_MAGIC      0xA5A5AA55
 107         writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG);
 108         reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
 109         if (reg == MBOX_MAGIC) {
 110                 /* Clear to 0 */
 111                 writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG);
 112                 return true;
 113         }
 114         return false;
 115 }
 116 
 117 static void altera_mbox_rx_data(struct mbox_chan *chan)
 118 {
 119         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 120         u32 data[2];
 121 
 122         if (altera_mbox_pending(mbox)) {
 123                 data[MBOX_PTR] =
 124                         readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
 125                 data[MBOX_CMD] =
 126                         readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG);
 127                 mbox_chan_received_data(chan, (void *)data);
 128         }
 129 }
 130 
 131 static void altera_mbox_poll_rx(struct timer_list *t)
 132 {
 133         struct altera_mbox *mbox = from_timer(mbox, t, rxpoll_timer);
 134 
 135         altera_mbox_rx_data(mbox->chan);
 136 
 137         mod_timer(&mbox->rxpoll_timer,
 138                   jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
 139 }
 140 
 141 static irqreturn_t altera_mbox_tx_interrupt(int irq, void *p)
 142 {
 143         struct mbox_chan *chan = (struct mbox_chan *)p;
 144         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 145 
 146         altera_mbox_tx_intmask(mbox, false);
 147         mbox_chan_txdone(chan, 0);
 148 
 149         return IRQ_HANDLED;
 150 }
 151 
 152 static irqreturn_t altera_mbox_rx_interrupt(int irq, void *p)
 153 {
 154         struct mbox_chan *chan = (struct mbox_chan *)p;
 155 
 156         altera_mbox_rx_data(chan);
 157         return IRQ_HANDLED;
 158 }
 159 
 160 static int altera_mbox_startup_sender(struct mbox_chan *chan)
 161 {
 162         int ret;
 163         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 164 
 165         if (mbox->intr_mode) {
 166                 ret = request_irq(mbox->irq, altera_mbox_tx_interrupt, 0,
 167                                   DRIVER_NAME, chan);
 168                 if (unlikely(ret)) {
 169                         dev_err(mbox->dev,
 170                                 "failed to register mailbox interrupt:%d\n",
 171                                 ret);
 172                         return ret;
 173                 }
 174         }
 175 
 176         return 0;
 177 }
 178 
 179 static int altera_mbox_startup_receiver(struct mbox_chan *chan)
 180 {
 181         int ret;
 182         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 183 
 184         if (mbox->intr_mode) {
 185                 ret = request_irq(mbox->irq, altera_mbox_rx_interrupt, 0,
 186                                   DRIVER_NAME, chan);
 187                 if (unlikely(ret)) {
 188                         mbox->intr_mode = false;
 189                         goto polling; /* use polling if failed */
 190                 }
 191 
 192                 altera_mbox_rx_intmask(mbox, true);
 193                 return 0;
 194         }
 195 
 196 polling:
 197         /* Setup polling timer */
 198         mbox->chan = chan;
 199         timer_setup(&mbox->rxpoll_timer, altera_mbox_poll_rx, 0);
 200         mod_timer(&mbox->rxpoll_timer,
 201                   jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
 202 
 203         return 0;
 204 }
 205 
 206 static int altera_mbox_send_data(struct mbox_chan *chan, void *data)
 207 {
 208         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 209         u32 *udata = (u32 *)data;
 210 
 211         if (!mbox || !data)
 212                 return -EINVAL;
 213         if (!mbox->is_sender) {
 214                 dev_warn(mbox->dev,
 215                          "failed to send. This is receiver mailbox.\n");
 216                 return -EINVAL;
 217         }
 218 
 219         if (altera_mbox_full(mbox))
 220                 return -EBUSY;
 221 
 222         /* Enable interrupt before send */
 223         if (mbox->intr_mode)
 224                 altera_mbox_tx_intmask(mbox, true);
 225 
 226         /* Pointer register must write before command register */
 227         writel_relaxed(udata[MBOX_PTR], mbox->mbox_base + MAILBOX_PTR_REG);
 228         writel_relaxed(udata[MBOX_CMD], mbox->mbox_base + MAILBOX_CMD_REG);
 229 
 230         return 0;
 231 }
 232 
 233 static bool altera_mbox_last_tx_done(struct mbox_chan *chan)
 234 {
 235         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 236 
 237         /* Return false if mailbox is full */
 238         return altera_mbox_full(mbox) ? false : true;
 239 }
 240 
 241 static bool altera_mbox_peek_data(struct mbox_chan *chan)
 242 {
 243         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 244 
 245         return altera_mbox_pending(mbox) ? true : false;
 246 }
 247 
 248 static int altera_mbox_startup(struct mbox_chan *chan)
 249 {
 250         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 251         int ret = 0;
 252 
 253         if (!mbox)
 254                 return -EINVAL;
 255 
 256         if (mbox->is_sender)
 257                 ret = altera_mbox_startup_sender(chan);
 258         else
 259                 ret = altera_mbox_startup_receiver(chan);
 260 
 261         return ret;
 262 }
 263 
 264 static void altera_mbox_shutdown(struct mbox_chan *chan)
 265 {
 266         struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
 267 
 268         if (mbox->intr_mode) {
 269                 /* Unmask all interrupt masks */
 270                 writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG);
 271                 free_irq(mbox->irq, chan);
 272         } else if (!mbox->is_sender) {
 273                 del_timer_sync(&mbox->rxpoll_timer);
 274         }
 275 }
 276 
 277 static const struct mbox_chan_ops altera_mbox_ops = {
 278         .send_data = altera_mbox_send_data,
 279         .startup = altera_mbox_startup,
 280         .shutdown = altera_mbox_shutdown,
 281         .last_tx_done = altera_mbox_last_tx_done,
 282         .peek_data = altera_mbox_peek_data,
 283 };
 284 
 285 static int altera_mbox_probe(struct platform_device *pdev)
 286 {
 287         struct altera_mbox *mbox;
 288         struct resource *regs;
 289         struct mbox_chan *chans;
 290         int ret;
 291 
 292         mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox),
 293                             GFP_KERNEL);
 294         if (!mbox)
 295                 return -ENOMEM;
 296 
 297         /* Allocated one channel */
 298         chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
 299         if (!chans)
 300                 return -ENOMEM;
 301 
 302         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 303 
 304         mbox->mbox_base = devm_ioremap_resource(&pdev->dev, regs);
 305         if (IS_ERR(mbox->mbox_base))
 306                 return PTR_ERR(mbox->mbox_base);
 307 
 308         /* Check is it a sender or receiver? */
 309         mbox->is_sender = altera_mbox_is_sender(mbox);
 310 
 311         mbox->irq = platform_get_irq(pdev, 0);
 312         if (mbox->irq >= 0)
 313                 mbox->intr_mode = true;
 314 
 315         mbox->dev = &pdev->dev;
 316 
 317         /* Hardware supports only one channel. */
 318         chans[0].con_priv = mbox;
 319         mbox->controller.dev = mbox->dev;
 320         mbox->controller.num_chans = 1;
 321         mbox->controller.chans = chans;
 322         mbox->controller.ops = &altera_mbox_ops;
 323 
 324         if (mbox->is_sender) {
 325                 if (mbox->intr_mode) {
 326                         mbox->controller.txdone_irq = true;
 327                 } else {
 328                         mbox->controller.txdone_poll = true;
 329                         mbox->controller.txpoll_period = MBOX_POLLING_MS;
 330                 }
 331         }
 332 
 333         ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
 334         if (ret) {
 335                 dev_err(&pdev->dev, "Register mailbox failed\n");
 336                 goto err;
 337         }
 338 
 339         platform_set_drvdata(pdev, mbox);
 340 err:
 341         return ret;
 342 }
 343 
 344 static const struct of_device_id altera_mbox_match[] = {
 345         { .compatible = "altr,mailbox-1.0" },
 346         { /* Sentinel */ }
 347 };
 348 
 349 MODULE_DEVICE_TABLE(of, altera_mbox_match);
 350 
 351 static struct platform_driver altera_mbox_driver = {
 352         .probe  = altera_mbox_probe,
 353         .driver = {
 354                 .name   = DRIVER_NAME,
 355                 .of_match_table = altera_mbox_match,
 356         },
 357 };
 358 
 359 module_platform_driver(altera_mbox_driver);
 360 
 361 MODULE_LICENSE("GPL v2");
 362 MODULE_DESCRIPTION("Altera mailbox specific functions");
 363 MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
 364 MODULE_ALIAS("platform:altera-mailbox");

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