root/drivers/mailbox/imx-mailbox.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_imx_mu_priv
  2. imx_mu_write
  3. imx_mu_read
  4. imx_mu_xcr_rmw
  5. imx_mu_txdb_tasklet
  6. imx_mu_isr
  7. imx_mu_send_data
  8. imx_mu_startup
  9. imx_mu_shutdown
  10. imx_mu_xlate
  11. imx_mu_init_generic
  12. imx_mu_probe
  13. imx_mu_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
   4  */
   5 
   6 #include <linux/clk.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_device.h>
  13 #include <linux/slab.h>
  14 
  15 /* Transmit Register */
  16 #define IMX_MU_xTRn(x)          (0x00 + 4 * (x))
  17 /* Receive Register */
  18 #define IMX_MU_xRRn(x)          (0x10 + 4 * (x))
  19 /* Status Register */
  20 #define IMX_MU_xSR              0x20
  21 #define IMX_MU_xSR_GIPn(x)      BIT(28 + (3 - (x)))
  22 #define IMX_MU_xSR_RFn(x)       BIT(24 + (3 - (x)))
  23 #define IMX_MU_xSR_TEn(x)       BIT(20 + (3 - (x)))
  24 #define IMX_MU_xSR_BRDIP        BIT(9)
  25 
  26 /* Control Register */
  27 #define IMX_MU_xCR              0x24
  28 /* General Purpose Interrupt Enable */
  29 #define IMX_MU_xCR_GIEn(x)      BIT(28 + (3 - (x)))
  30 /* Receive Interrupt Enable */
  31 #define IMX_MU_xCR_RIEn(x)      BIT(24 + (3 - (x)))
  32 /* Transmit Interrupt Enable */
  33 #define IMX_MU_xCR_TIEn(x)      BIT(20 + (3 - (x)))
  34 /* General Purpose Interrupt Request */
  35 #define IMX_MU_xCR_GIRn(x)      BIT(16 + (3 - (x)))
  36 
  37 #define IMX_MU_CHANS            16
  38 #define IMX_MU_CHAN_NAME_SIZE   20
  39 
  40 enum imx_mu_chan_type {
  41         IMX_MU_TYPE_TX,         /* Tx */
  42         IMX_MU_TYPE_RX,         /* Rx */
  43         IMX_MU_TYPE_TXDB,       /* Tx doorbell */
  44         IMX_MU_TYPE_RXDB,       /* Rx doorbell */
  45 };
  46 
  47 struct imx_mu_con_priv {
  48         unsigned int            idx;
  49         char                    irq_desc[IMX_MU_CHAN_NAME_SIZE];
  50         enum imx_mu_chan_type   type;
  51         struct mbox_chan        *chan;
  52         struct tasklet_struct   txdb_tasklet;
  53 };
  54 
  55 struct imx_mu_priv {
  56         struct device           *dev;
  57         void __iomem            *base;
  58         spinlock_t              xcr_lock; /* control register lock */
  59 
  60         struct mbox_controller  mbox;
  61         struct mbox_chan        mbox_chans[IMX_MU_CHANS];
  62 
  63         struct imx_mu_con_priv  con_priv[IMX_MU_CHANS];
  64         struct clk              *clk;
  65         int                     irq;
  66 
  67         bool                    side_b;
  68 };
  69 
  70 static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
  71 {
  72         return container_of(mbox, struct imx_mu_priv, mbox);
  73 }
  74 
  75 static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs)
  76 {
  77         iowrite32(val, priv->base + offs);
  78 }
  79 
  80 static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs)
  81 {
  82         return ioread32(priv->base + offs);
  83 }
  84 
  85 static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, u32 set, u32 clr)
  86 {
  87         unsigned long flags;
  88         u32 val;
  89 
  90         spin_lock_irqsave(&priv->xcr_lock, flags);
  91         val = imx_mu_read(priv, IMX_MU_xCR);
  92         val &= ~clr;
  93         val |= set;
  94         imx_mu_write(priv, val, IMX_MU_xCR);
  95         spin_unlock_irqrestore(&priv->xcr_lock, flags);
  96 
  97         return val;
  98 }
  99 
 100 static void imx_mu_txdb_tasklet(unsigned long data)
 101 {
 102         struct imx_mu_con_priv *cp = (struct imx_mu_con_priv *)data;
 103 
 104         mbox_chan_txdone(cp->chan, 0);
 105 }
 106 
 107 static irqreturn_t imx_mu_isr(int irq, void *p)
 108 {
 109         struct mbox_chan *chan = p;
 110         struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 111         struct imx_mu_con_priv *cp = chan->con_priv;
 112         u32 val, ctrl, dat;
 113 
 114         ctrl = imx_mu_read(priv, IMX_MU_xCR);
 115         val = imx_mu_read(priv, IMX_MU_xSR);
 116 
 117         switch (cp->type) {
 118         case IMX_MU_TYPE_TX:
 119                 val &= IMX_MU_xSR_TEn(cp->idx) &
 120                         (ctrl & IMX_MU_xCR_TIEn(cp->idx));
 121                 break;
 122         case IMX_MU_TYPE_RX:
 123                 val &= IMX_MU_xSR_RFn(cp->idx) &
 124                         (ctrl & IMX_MU_xCR_RIEn(cp->idx));
 125                 break;
 126         case IMX_MU_TYPE_RXDB:
 127                 val &= IMX_MU_xSR_GIPn(cp->idx) &
 128                         (ctrl & IMX_MU_xCR_GIEn(cp->idx));
 129                 break;
 130         default:
 131                 break;
 132         }
 133 
 134         if (!val)
 135                 return IRQ_NONE;
 136 
 137         if (val == IMX_MU_xSR_TEn(cp->idx)) {
 138                 imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
 139                 mbox_chan_txdone(chan, 0);
 140         } else if (val == IMX_MU_xSR_RFn(cp->idx)) {
 141                 dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
 142                 mbox_chan_received_data(chan, (void *)&dat);
 143         } else if (val == IMX_MU_xSR_GIPn(cp->idx)) {
 144                 imx_mu_write(priv, IMX_MU_xSR_GIPn(cp->idx), IMX_MU_xSR);
 145                 mbox_chan_received_data(chan, NULL);
 146         } else {
 147                 dev_warn_ratelimited(priv->dev, "Not handled interrupt\n");
 148                 return IRQ_NONE;
 149         }
 150 
 151         return IRQ_HANDLED;
 152 }
 153 
 154 static int imx_mu_send_data(struct mbox_chan *chan, void *data)
 155 {
 156         struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 157         struct imx_mu_con_priv *cp = chan->con_priv;
 158         u32 *arg = data;
 159 
 160         switch (cp->type) {
 161         case IMX_MU_TYPE_TX:
 162                 imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
 163                 imx_mu_xcr_rmw(priv, IMX_MU_xCR_TIEn(cp->idx), 0);
 164                 break;
 165         case IMX_MU_TYPE_TXDB:
 166                 imx_mu_xcr_rmw(priv, IMX_MU_xCR_GIRn(cp->idx), 0);
 167                 tasklet_schedule(&cp->txdb_tasklet);
 168                 break;
 169         default:
 170                 dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type);
 171                 return -EINVAL;
 172         }
 173 
 174         return 0;
 175 }
 176 
 177 static int imx_mu_startup(struct mbox_chan *chan)
 178 {
 179         struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 180         struct imx_mu_con_priv *cp = chan->con_priv;
 181         int ret;
 182 
 183         if (cp->type == IMX_MU_TYPE_TXDB) {
 184                 /* Tx doorbell don't have ACK support */
 185                 tasklet_init(&cp->txdb_tasklet, imx_mu_txdb_tasklet,
 186                              (unsigned long)cp);
 187                 return 0;
 188         }
 189 
 190         ret = request_irq(priv->irq, imx_mu_isr, IRQF_SHARED |
 191                           IRQF_NO_SUSPEND, cp->irq_desc, chan);
 192         if (ret) {
 193                 dev_err(priv->dev,
 194                         "Unable to acquire IRQ %d\n", priv->irq);
 195                 return ret;
 196         }
 197 
 198         switch (cp->type) {
 199         case IMX_MU_TYPE_RX:
 200                 imx_mu_xcr_rmw(priv, IMX_MU_xCR_RIEn(cp->idx), 0);
 201                 break;
 202         case IMX_MU_TYPE_RXDB:
 203                 imx_mu_xcr_rmw(priv, IMX_MU_xCR_GIEn(cp->idx), 0);
 204                 break;
 205         default:
 206                 break;
 207         }
 208 
 209         return 0;
 210 }
 211 
 212 static void imx_mu_shutdown(struct mbox_chan *chan)
 213 {
 214         struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 215         struct imx_mu_con_priv *cp = chan->con_priv;
 216 
 217         if (cp->type == IMX_MU_TYPE_TXDB) {
 218                 tasklet_kill(&cp->txdb_tasklet);
 219                 return;
 220         }
 221 
 222         switch (cp->type) {
 223         case IMX_MU_TYPE_TX:
 224                 imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
 225                 break;
 226         case IMX_MU_TYPE_RX:
 227                 imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(cp->idx));
 228                 break;
 229         case IMX_MU_TYPE_RXDB:
 230                 imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_GIEn(cp->idx));
 231                 break;
 232         default:
 233                 break;
 234         }
 235 
 236         free_irq(priv->irq, chan);
 237 }
 238 
 239 static const struct mbox_chan_ops imx_mu_ops = {
 240         .send_data = imx_mu_send_data,
 241         .startup = imx_mu_startup,
 242         .shutdown = imx_mu_shutdown,
 243 };
 244 
 245 static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
 246                                        const struct of_phandle_args *sp)
 247 {
 248         u32 type, idx, chan;
 249 
 250         if (sp->args_count != 2) {
 251                 dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count);
 252                 return ERR_PTR(-EINVAL);
 253         }
 254 
 255         type = sp->args[0]; /* channel type */
 256         idx = sp->args[1]; /* index */
 257         chan = type * 4 + idx;
 258 
 259         if (chan >= mbox->num_chans) {
 260                 dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", chan, type, idx);
 261                 return ERR_PTR(-EINVAL);
 262         }
 263 
 264         return &mbox->chans[chan];
 265 }
 266 
 267 static void imx_mu_init_generic(struct imx_mu_priv *priv)
 268 {
 269         if (priv->side_b)
 270                 return;
 271 
 272         /* Set default MU configuration */
 273         imx_mu_write(priv, 0, IMX_MU_xCR);
 274 }
 275 
 276 static int imx_mu_probe(struct platform_device *pdev)
 277 {
 278         struct device *dev = &pdev->dev;
 279         struct device_node *np = dev->of_node;
 280         struct imx_mu_priv *priv;
 281         unsigned int i;
 282         int ret;
 283 
 284         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 285         if (!priv)
 286                 return -ENOMEM;
 287 
 288         priv->dev = dev;
 289 
 290         priv->base = devm_platform_ioremap_resource(pdev, 0);
 291         if (IS_ERR(priv->base))
 292                 return PTR_ERR(priv->base);
 293 
 294         priv->irq = platform_get_irq(pdev, 0);
 295         if (priv->irq < 0)
 296                 return priv->irq;
 297 
 298         priv->clk = devm_clk_get(dev, NULL);
 299         if (IS_ERR(priv->clk)) {
 300                 if (PTR_ERR(priv->clk) != -ENOENT)
 301                         return PTR_ERR(priv->clk);
 302 
 303                 priv->clk = NULL;
 304         }
 305 
 306         ret = clk_prepare_enable(priv->clk);
 307         if (ret) {
 308                 dev_err(dev, "Failed to enable clock\n");
 309                 return ret;
 310         }
 311 
 312         for (i = 0; i < IMX_MU_CHANS; i++) {
 313                 struct imx_mu_con_priv *cp = &priv->con_priv[i];
 314 
 315                 cp->idx = i % 4;
 316                 cp->type = i >> 2;
 317                 cp->chan = &priv->mbox_chans[i];
 318                 priv->mbox_chans[i].con_priv = cp;
 319                 snprintf(cp->irq_desc, sizeof(cp->irq_desc),
 320                          "imx_mu_chan[%i-%i]", cp->type, cp->idx);
 321         }
 322 
 323         priv->side_b = of_property_read_bool(np, "fsl,mu-side-b");
 324 
 325         spin_lock_init(&priv->xcr_lock);
 326 
 327         priv->mbox.dev = dev;
 328         priv->mbox.ops = &imx_mu_ops;
 329         priv->mbox.chans = priv->mbox_chans;
 330         priv->mbox.num_chans = IMX_MU_CHANS;
 331         priv->mbox.of_xlate = imx_mu_xlate;
 332         priv->mbox.txdone_irq = true;
 333 
 334         platform_set_drvdata(pdev, priv);
 335 
 336         imx_mu_init_generic(priv);
 337 
 338         return devm_mbox_controller_register(dev, &priv->mbox);
 339 }
 340 
 341 static int imx_mu_remove(struct platform_device *pdev)
 342 {
 343         struct imx_mu_priv *priv = platform_get_drvdata(pdev);
 344 
 345         clk_disable_unprepare(priv->clk);
 346 
 347         return 0;
 348 }
 349 
 350 static const struct of_device_id imx_mu_dt_ids[] = {
 351         { .compatible = "fsl,imx6sx-mu" },
 352         { },
 353 };
 354 MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
 355 
 356 static struct platform_driver imx_mu_driver = {
 357         .probe          = imx_mu_probe,
 358         .remove         = imx_mu_remove,
 359         .driver = {
 360                 .name   = "imx_mu",
 361                 .of_match_table = imx_mu_dt_ids,
 362         },
 363 };
 364 module_platform_driver(imx_mu_driver);
 365 
 366 MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
 367 MODULE_DESCRIPTION("Message Unit driver for i.MX");
 368 MODULE_LICENSE("GPL v2");

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