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