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