1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Spreadtrum mailbox driver 4 * 5 * Copyright (c) 2020 Spreadtrum Communications Inc. 6 */ 7 8 #include <linux/delay.h> 9 #include <linux/err.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/clk.h> 17 18 #define SPRD_MBOX_ID 0x0 19 #define SPRD_MBOX_MSG_LOW 0x4 20 #define SPRD_MBOX_MSG_HIGH 0x8 21 #define SPRD_MBOX_TRIGGER 0xc 22 #define SPRD_MBOX_FIFO_RST 0x10 23 #define SPRD_MBOX_FIFO_STS 0x14 24 #define SPRD_MBOX_IRQ_STS 0x18 25 #define SPRD_MBOX_IRQ_MSK 0x1c 26 #define SPRD_MBOX_LOCK 0x20 27 #define SPRD_MBOX_FIFO_DEPTH 0x24 28 29 /* Bit and mask definition for inbox's SPRD_MBOX_FIFO_STS register */ 30 #define SPRD_INBOX_FIFO_DELIVER_MASK GENMASK(23, 16) 31 #define SPRD_INBOX_FIFO_OVERLOW_MASK GENMASK(15, 8) 32 #define SPRD_INBOX_FIFO_DELIVER_SHIFT 16 33 #define SPRD_INBOX_FIFO_BUSY_MASK GENMASK(7, 0) 34 35 /* Bit and mask definition for SPRD_MBOX_IRQ_STS register */ 36 #define SPRD_MBOX_IRQ_CLR BIT(0) 37 38 /* Bit and mask definition for outbox's SPRD_MBOX_FIFO_STS register */ 39 #define SPRD_OUTBOX_FIFO_FULL BIT(2) 40 #define SPRD_OUTBOX_FIFO_WR_SHIFT 16 41 #define SPRD_OUTBOX_FIFO_RD_SHIFT 24 42 #define SPRD_OUTBOX_FIFO_POS_MASK GENMASK(7, 0) 43 44 /* Bit and mask definition for inbox's SPRD_MBOX_IRQ_MSK register */ 45 #define SPRD_INBOX_FIFO_BLOCK_IRQ BIT(0) 46 #define SPRD_INBOX_FIFO_OVERFLOW_IRQ BIT(1) 47 #define SPRD_INBOX_FIFO_DELIVER_IRQ BIT(2) 48 #define SPRD_INBOX_FIFO_IRQ_MASK GENMASK(2, 0) 49 50 /* Bit and mask definition for outbox's SPRD_MBOX_IRQ_MSK register */ 51 #define SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ BIT(0) 52 #define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0) 53 54 #define SPRD_OUTBOX_BASE_SPAN 0x1000 55 #define SPRD_MBOX_CHAN_MAX 8 56 #define SPRD_SUPP_INBOX_ID_SC9863A 7 57 58 struct sprd_mbox_priv { 59 struct mbox_controller mbox; 60 struct device *dev; 61 void __iomem *inbox_base; 62 void __iomem *outbox_base; 63 /* Base register address for supplementary outbox */ 64 void __iomem *supp_base; 65 u32 outbox_fifo_depth; 66 67 struct mutex lock; 68 u32 refcnt; 69 struct mbox_chan chan[SPRD_MBOX_CHAN_MAX]; 70 }; 71 72 static struct sprd_mbox_priv *to_sprd_mbox_priv(struct mbox_controller *mbox) 73 { 74 return container_of(mbox, struct sprd_mbox_priv, mbox); 75 } 76 77 static u32 sprd_mbox_get_fifo_len(struct sprd_mbox_priv *priv, u32 fifo_sts) 78 { 79 u32 wr_pos = (fifo_sts >> SPRD_OUTBOX_FIFO_WR_SHIFT) & 80 SPRD_OUTBOX_FIFO_POS_MASK; 81 u32 rd_pos = (fifo_sts >> SPRD_OUTBOX_FIFO_RD_SHIFT) & 82 SPRD_OUTBOX_FIFO_POS_MASK; 83 u32 fifo_len; 84 85 /* 86 * If the read pointer is equal with write pointer, which means the fifo 87 * is full or empty. 88 */ 89 if (wr_pos == rd_pos) { 90 if (fifo_sts & SPRD_OUTBOX_FIFO_FULL) 91 fifo_len = priv->outbox_fifo_depth; 92 else 93 fifo_len = 0; 94 } else if (wr_pos > rd_pos) { 95 fifo_len = wr_pos - rd_pos; 96 } else { 97 fifo_len = priv->outbox_fifo_depth - rd_pos + wr_pos; 98 } 99 100 return fifo_len; 101 } 102 103 static irqreturn_t do_outbox_isr(void __iomem *base, struct sprd_mbox_priv *priv) 104 { 105 struct mbox_chan *chan; 106 u32 fifo_sts, fifo_len, msg[2]; 107 int i, id; 108 109 fifo_sts = readl(base + SPRD_MBOX_FIFO_STS); 110 111 fifo_len = sprd_mbox_get_fifo_len(priv, fifo_sts); 112 if (!fifo_len) { 113 dev_warn_ratelimited(priv->dev, "spurious outbox interrupt\n"); 114 return IRQ_NONE; 115 } 116 117 for (i = 0; i < fifo_len; i++) { 118 msg[0] = readl(base + SPRD_MBOX_MSG_LOW); 119 msg[1] = readl(base + SPRD_MBOX_MSG_HIGH); 120 id = readl(base + SPRD_MBOX_ID); 121 122 chan = &priv->chan[id]; 123 if (chan->cl) 124 mbox_chan_received_data(chan, (void *)msg); 125 else 126 dev_warn_ratelimited(priv->dev, 127 "message's been dropped at ch[%d]\n", id); 128 129 /* Trigger to update outbox FIFO pointer */ 130 writel(0x1, base + SPRD_MBOX_TRIGGER); 131 } 132 133 /* Clear irq status after reading all message. */ 134 writel(SPRD_MBOX_IRQ_CLR, base + SPRD_MBOX_IRQ_STS); 135 136 return IRQ_HANDLED; 137 } 138 139 static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data) 140 { 141 struct sprd_mbox_priv *priv = data; 142 143 return do_outbox_isr(priv->outbox_base, priv); 144 } 145 146 static irqreturn_t sprd_mbox_supp_isr(int irq, void *data) 147 { 148 struct sprd_mbox_priv *priv = data; 149 150 return do_outbox_isr(priv->supp_base, priv); 151 } 152 153 static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data) 154 { 155 struct sprd_mbox_priv *priv = data; 156 struct mbox_chan *chan; 157 u32 fifo_sts, send_sts, busy, id; 158 159 fifo_sts = readl(priv->inbox_base + SPRD_MBOX_FIFO_STS); 160 161 /* Get the inbox data delivery status */ 162 send_sts = (fifo_sts & SPRD_INBOX_FIFO_DELIVER_MASK) >> 163 SPRD_INBOX_FIFO_DELIVER_SHIFT; 164 if (!send_sts) { 165 dev_warn_ratelimited(priv->dev, "spurious inbox interrupt\n"); 166 return IRQ_NONE; 167 } 168 169 while (send_sts) { 170 id = __ffs(send_sts); 171 send_sts &= (send_sts - 1); 172 173 chan = &priv->chan[id]; 174 175 /* 176 * Check if the message was fetched by remote target, if yes, 177 * that means the transmission has been completed. 178 */ 179 busy = fifo_sts & SPRD_INBOX_FIFO_BUSY_MASK; 180 if (!(busy & BIT(id))) 181 mbox_chan_txdone(chan, 0); 182 } 183 184 /* Clear FIFO delivery and overflow status */ 185 writel(fifo_sts & 186 (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK), 187 priv->inbox_base + SPRD_MBOX_FIFO_RST); 188 189 /* Clear irq status */ 190 writel(SPRD_MBOX_IRQ_CLR, priv->inbox_base + SPRD_MBOX_IRQ_STS); 191 192 return IRQ_HANDLED; 193 } 194 195 static int sprd_mbox_send_data(struct mbox_chan *chan, void *msg) 196 { 197 struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); 198 unsigned long id = (unsigned long)chan->con_priv; 199 u32 *data = msg; 200 201 /* Write data into inbox FIFO, and only support 8 bytes every time */ 202 writel(data[0], priv->inbox_base + SPRD_MBOX_MSG_LOW); 203 writel(data[1], priv->inbox_base + SPRD_MBOX_MSG_HIGH); 204 205 /* Set target core id */ 206 writel(id, priv->inbox_base + SPRD_MBOX_ID); 207 208 /* Trigger remote request */ 209 writel(0x1, priv->inbox_base + SPRD_MBOX_TRIGGER); 210 211 return 0; 212 } 213 214 static int sprd_mbox_flush(struct mbox_chan *chan, unsigned long timeout) 215 { 216 struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); 217 unsigned long id = (unsigned long)chan->con_priv; 218 u32 busy; 219 220 timeout = jiffies + msecs_to_jiffies(timeout); 221 222 while (time_before(jiffies, timeout)) { 223 busy = readl(priv->inbox_base + SPRD_MBOX_FIFO_STS) & 224 SPRD_INBOX_FIFO_BUSY_MASK; 225 if (!(busy & BIT(id))) { 226 mbox_chan_txdone(chan, 0); 227 return 0; 228 } 229 230 udelay(1); 231 } 232 233 return -ETIME; 234 } 235 236 static int sprd_mbox_startup(struct mbox_chan *chan) 237 { 238 struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); 239 u32 val; 240 241 mutex_lock(&priv->lock); 242 if (priv->refcnt++ == 0) { 243 /* Select outbox FIFO mode and reset the outbox FIFO status */ 244 writel(0x0, priv->outbox_base + SPRD_MBOX_FIFO_RST); 245 246 /* Enable inbox FIFO overflow and delivery interrupt */ 247 val = readl(priv->inbox_base + SPRD_MBOX_IRQ_MSK); 248 val &= ~(SPRD_INBOX_FIFO_OVERFLOW_IRQ | SPRD_INBOX_FIFO_DELIVER_IRQ); 249 writel(val, priv->inbox_base + SPRD_MBOX_IRQ_MSK); 250 251 /* Enable outbox FIFO not empty interrupt */ 252 val = readl(priv->outbox_base + SPRD_MBOX_IRQ_MSK); 253 val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ; 254 writel(val, priv->outbox_base + SPRD_MBOX_IRQ_MSK); 255 256 /* Enable supplementary outbox as the fundamental one */ 257 if (priv->supp_base) { 258 writel(0x0, priv->supp_base + SPRD_MBOX_FIFO_RST); 259 val = readl(priv->supp_base + SPRD_MBOX_IRQ_MSK); 260 val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ; 261 writel(val, priv->supp_base + SPRD_MBOX_IRQ_MSK); 262 } 263 } 264 mutex_unlock(&priv->lock); 265 266 return 0; 267 } 268 269 static void sprd_mbox_shutdown(struct mbox_chan *chan) 270 { 271 struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); 272 273 mutex_lock(&priv->lock); 274 if (--priv->refcnt == 0) { 275 /* Disable inbox & outbox interrupt */ 276 writel(SPRD_INBOX_FIFO_IRQ_MASK, priv->inbox_base + SPRD_MBOX_IRQ_MSK); 277 writel(SPRD_OUTBOX_FIFO_IRQ_MASK, priv->outbox_base + SPRD_MBOX_IRQ_MSK); 278 279 if (priv->supp_base) 280 writel(SPRD_OUTBOX_FIFO_IRQ_MASK, 281 priv->supp_base + SPRD_MBOX_IRQ_MSK); 282 } 283 mutex_unlock(&priv->lock); 284 } 285 286 static const struct mbox_chan_ops sprd_mbox_ops = { 287 .send_data = sprd_mbox_send_data, 288 .flush = sprd_mbox_flush, 289 .startup = sprd_mbox_startup, 290 .shutdown = sprd_mbox_shutdown, 291 }; 292 293 static int sprd_mbox_probe(struct platform_device *pdev) 294 { 295 struct device *dev = &pdev->dev; 296 struct sprd_mbox_priv *priv; 297 int ret, inbox_irq, outbox_irq, supp_irq; 298 unsigned long id, supp; 299 struct clk *clk; 300 301 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 302 if (!priv) 303 return -ENOMEM; 304 305 priv->dev = dev; 306 mutex_init(&priv->lock); 307 308 /* 309 * Unisoc mailbox uses an inbox to send messages to the target 310 * core, and uses (an) outbox(es) to receive messages from other 311 * cores. 312 * 313 * Thus in general the mailbox controller supplies 2 different 314 * register addresses and IRQ numbers for inbox and outbox. 315 * 316 * If necessary, a supplementary inbox could be enabled optionally 317 * with an independent FIFO and an extra interrupt. 318 */ 319 priv->inbox_base = devm_platform_ioremap_resource(pdev, 0); 320 if (IS_ERR(priv->inbox_base)) 321 return PTR_ERR(priv->inbox_base); 322 323 priv->outbox_base = devm_platform_ioremap_resource(pdev, 1); 324 if (IS_ERR(priv->outbox_base)) 325 return PTR_ERR(priv->outbox_base); 326 327 clk = devm_clk_get_enabled(dev, "enable"); 328 if (IS_ERR(clk)) { 329 dev_err(dev, "failed to get mailbox clock\n"); 330 return PTR_ERR(clk); 331 } 332 333 inbox_irq = platform_get_irq_byname(pdev, "inbox"); 334 if (inbox_irq < 0) 335 return inbox_irq; 336 337 ret = devm_request_irq(dev, inbox_irq, sprd_mbox_inbox_isr, 338 IRQF_NO_SUSPEND, dev_name(dev), priv); 339 if (ret) { 340 dev_err(dev, "failed to request inbox IRQ: %d\n", ret); 341 return ret; 342 } 343 344 outbox_irq = platform_get_irq_byname(pdev, "outbox"); 345 if (outbox_irq < 0) 346 return outbox_irq; 347 348 ret = devm_request_irq(dev, outbox_irq, sprd_mbox_outbox_isr, 349 IRQF_NO_SUSPEND, dev_name(dev), priv); 350 if (ret) { 351 dev_err(dev, "failed to request outbox IRQ: %d\n", ret); 352 return ret; 353 } 354 355 /* Supplementary outbox IRQ is optional */ 356 supp_irq = platform_get_irq_byname(pdev, "supp-outbox"); 357 if (supp_irq > 0) { 358 ret = devm_request_irq(dev, supp_irq, sprd_mbox_supp_isr, 359 IRQF_NO_SUSPEND, dev_name(dev), priv); 360 if (ret) { 361 dev_err(dev, "failed to request outbox IRQ: %d\n", ret); 362 return ret; 363 } 364 365 supp = (unsigned long) of_device_get_match_data(dev); 366 if (!supp) { 367 dev_err(dev, "no supplementary outbox specified\n"); 368 return -ENODEV; 369 } 370 priv->supp_base = priv->outbox_base + (SPRD_OUTBOX_BASE_SPAN * supp); 371 } 372 373 /* Get the default outbox FIFO depth */ 374 priv->outbox_fifo_depth = 375 readl(priv->outbox_base + SPRD_MBOX_FIFO_DEPTH) + 1; 376 priv->mbox.dev = dev; 377 priv->mbox.chans = &priv->chan[0]; 378 priv->mbox.num_chans = SPRD_MBOX_CHAN_MAX; 379 priv->mbox.ops = &sprd_mbox_ops; 380 priv->mbox.txdone_irq = true; 381 382 for (id = 0; id < SPRD_MBOX_CHAN_MAX; id++) 383 priv->chan[id].con_priv = (void *)id; 384 385 ret = devm_mbox_controller_register(dev, &priv->mbox); 386 if (ret) { 387 dev_err(dev, "failed to register mailbox: %d\n", ret); 388 return ret; 389 } 390 391 return 0; 392 } 393 394 static const struct of_device_id sprd_mbox_of_match[] = { 395 { .compatible = "sprd,sc9860-mailbox" }, 396 { .compatible = "sprd,sc9863a-mailbox", 397 .data = (void *)SPRD_SUPP_INBOX_ID_SC9863A }, 398 { }, 399 }; 400 MODULE_DEVICE_TABLE(of, sprd_mbox_of_match); 401 402 static struct platform_driver sprd_mbox_driver = { 403 .driver = { 404 .name = "sprd-mailbox", 405 .of_match_table = sprd_mbox_of_match, 406 }, 407 .probe = sprd_mbox_probe, 408 }; 409 module_platform_driver(sprd_mbox_driver); 410 411 MODULE_AUTHOR("Baolin Wang <baolin.wang@unisoc.com>"); 412 MODULE_DESCRIPTION("Spreadtrum mailbox driver"); 413 MODULE_LICENSE("GPL v2"); 414