1 // SPDX-License-Identifier: GPL-2.0-only
3 * Spreadtrum mailbox driver
5 * Copyright (c) 2020 Spreadtrum Communications Inc.
8 #include <linux/delay.h>
10 #include <linux/interrupt.h>
12 #include <linux/mailbox_controller.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/clk.h>
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
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)
35 /* Bit and mask definition for SPRD_MBOX_IRQ_STS register */
36 #define SPRD_MBOX_IRQ_CLR BIT(0)
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)
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)
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)
54 #define SPRD_OUTBOX_BASE_SPAN 0x1000
55 #define SPRD_MBOX_CHAN_MAX 8
56 #define SPRD_SUPP_INBOX_ID_SC9863A 7
58 struct sprd_mbox_priv
{
59 struct mbox_controller mbox
;
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
;
69 struct mbox_chan chan
[SPRD_MBOX_CHAN_MAX
];
72 static struct sprd_mbox_priv
*to_sprd_mbox_priv(struct mbox_controller
*mbox
)
74 return container_of(mbox
, struct sprd_mbox_priv
, mbox
);
77 static u32
sprd_mbox_get_fifo_len(struct sprd_mbox_priv
*priv
, u32 fifo_sts
)
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
;
86 * If the read pointer is equal with write pointer, which means the fifo
89 if (wr_pos
== rd_pos
) {
90 if (fifo_sts
& SPRD_OUTBOX_FIFO_FULL
)
91 fifo_len
= priv
->outbox_fifo_depth
;
94 } else if (wr_pos
> rd_pos
) {
95 fifo_len
= wr_pos
- rd_pos
;
97 fifo_len
= priv
->outbox_fifo_depth
- rd_pos
+ wr_pos
;
103 static irqreturn_t
do_outbox_isr(void __iomem
*base
, struct sprd_mbox_priv
*priv
)
105 struct mbox_chan
*chan
;
106 u32 fifo_sts
, fifo_len
, msg
[2];
109 fifo_sts
= readl(base
+ SPRD_MBOX_FIFO_STS
);
111 fifo_len
= sprd_mbox_get_fifo_len(priv
, fifo_sts
);
113 dev_warn_ratelimited(priv
->dev
, "spurious outbox interrupt\n");
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
);
122 chan
= &priv
->chan
[id
];
124 mbox_chan_received_data(chan
, (void *)msg
);
126 dev_warn_ratelimited(priv
->dev
,
127 "message's been dropped at ch[%d]\n", id
);
129 /* Trigger to update outbox FIFO pointer */
130 writel(0x1, base
+ SPRD_MBOX_TRIGGER
);
133 /* Clear irq status after reading all message. */
134 writel(SPRD_MBOX_IRQ_CLR
, base
+ SPRD_MBOX_IRQ_STS
);
139 static irqreturn_t
sprd_mbox_outbox_isr(int irq
, void *data
)
141 struct sprd_mbox_priv
*priv
= data
;
143 return do_outbox_isr(priv
->outbox_base
, priv
);
146 static irqreturn_t
sprd_mbox_supp_isr(int irq
, void *data
)
148 struct sprd_mbox_priv
*priv
= data
;
150 return do_outbox_isr(priv
->supp_base
, priv
);
153 static irqreturn_t
sprd_mbox_inbox_isr(int irq
, void *data
)
155 struct sprd_mbox_priv
*priv
= data
;
156 struct mbox_chan
*chan
;
157 u32 fifo_sts
, send_sts
, busy
, id
;
159 fifo_sts
= readl(priv
->inbox_base
+ SPRD_MBOX_FIFO_STS
);
161 /* Get the inbox data delivery status */
162 send_sts
= (fifo_sts
& SPRD_INBOX_FIFO_DELIVER_MASK
) >>
163 SPRD_INBOX_FIFO_DELIVER_SHIFT
;
165 dev_warn_ratelimited(priv
->dev
, "spurious inbox interrupt\n");
170 id
= __ffs(send_sts
);
171 send_sts
&= (send_sts
- 1);
173 chan
= &priv
->chan
[id
];
176 * Check if the message was fetched by remote target, if yes,
177 * that means the transmission has been completed.
179 busy
= fifo_sts
& SPRD_INBOX_FIFO_BUSY_MASK
;
180 if (!(busy
& BIT(id
)))
181 mbox_chan_txdone(chan
, 0);
184 /* Clear FIFO delivery and overflow status */
186 (SPRD_INBOX_FIFO_DELIVER_MASK
| SPRD_INBOX_FIFO_OVERLOW_MASK
),
187 priv
->inbox_base
+ SPRD_MBOX_FIFO_RST
);
189 /* Clear irq status */
190 writel(SPRD_MBOX_IRQ_CLR
, priv
->inbox_base
+ SPRD_MBOX_IRQ_STS
);
195 static int sprd_mbox_send_data(struct mbox_chan
*chan
, void *msg
)
197 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
198 unsigned long id
= (unsigned long)chan
->con_priv
;
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
);
205 /* Set target core id */
206 writel(id
, priv
->inbox_base
+ SPRD_MBOX_ID
);
208 /* Trigger remote request */
209 writel(0x1, priv
->inbox_base
+ SPRD_MBOX_TRIGGER
);
214 static int sprd_mbox_flush(struct mbox_chan
*chan
, unsigned long timeout
)
216 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
217 unsigned long id
= (unsigned long)chan
->con_priv
;
220 timeout
= jiffies
+ msecs_to_jiffies(timeout
);
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);
236 static int sprd_mbox_startup(struct mbox_chan
*chan
)
238 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
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
);
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
);
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
);
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
);
264 mutex_unlock(&priv
->lock
);
269 static void sprd_mbox_shutdown(struct mbox_chan
*chan
)
271 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
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
);
280 writel(SPRD_OUTBOX_FIFO_IRQ_MASK
,
281 priv
->supp_base
+ SPRD_MBOX_IRQ_MSK
);
283 mutex_unlock(&priv
->lock
);
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
,
293 static int sprd_mbox_probe(struct platform_device
*pdev
)
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
;
301 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
306 mutex_init(&priv
->lock
);
309 * Unisoc mailbox uses an inbox to send messages to the target
310 * core, and uses (an) outbox(es) to receive messages from other
313 * Thus in general the mailbox controller supplies 2 different
314 * register addresses and IRQ numbers for inbox and outbox.
316 * If necessary, a supplementary inbox could be enabled optionally
317 * with an independent FIFO and an extra interrupt.
319 priv
->inbox_base
= devm_platform_ioremap_resource(pdev
, 0);
320 if (IS_ERR(priv
->inbox_base
))
321 return PTR_ERR(priv
->inbox_base
);
323 priv
->outbox_base
= devm_platform_ioremap_resource(pdev
, 1);
324 if (IS_ERR(priv
->outbox_base
))
325 return PTR_ERR(priv
->outbox_base
);
327 clk
= devm_clk_get_enabled(dev
, "enable");
329 dev_err(dev
, "failed to get mailbox clock\n");
333 inbox_irq
= platform_get_irq_byname(pdev
, "inbox");
337 ret
= devm_request_irq(dev
, inbox_irq
, sprd_mbox_inbox_isr
,
338 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
340 dev_err(dev
, "failed to request inbox IRQ: %d\n", ret
);
344 outbox_irq
= platform_get_irq_byname(pdev
, "outbox");
348 ret
= devm_request_irq(dev
, outbox_irq
, sprd_mbox_outbox_isr
,
349 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
351 dev_err(dev
, "failed to request outbox IRQ: %d\n", ret
);
355 /* Supplementary outbox IRQ is optional */
356 supp_irq
= platform_get_irq_byname(pdev
, "supp-outbox");
358 ret
= devm_request_irq(dev
, supp_irq
, sprd_mbox_supp_isr
,
359 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
361 dev_err(dev
, "failed to request outbox IRQ: %d\n", ret
);
365 supp
= (unsigned long) of_device_get_match_data(dev
);
367 dev_err(dev
, "no supplementary outbox specified\n");
370 priv
->supp_base
= priv
->outbox_base
+ (SPRD_OUTBOX_BASE_SPAN
* supp
);
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;
382 for (id
= 0; id
< SPRD_MBOX_CHAN_MAX
; id
++)
383 priv
->chan
[id
].con_priv
= (void *)id
;
385 ret
= devm_mbox_controller_register(dev
, &priv
->mbox
);
387 dev_err(dev
, "failed to register mailbox: %d\n", ret
);
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
},
400 MODULE_DEVICE_TABLE(of
, sprd_mbox_of_match
);
402 static struct platform_driver sprd_mbox_driver
= {
404 .name
= "sprd-mailbox",
405 .of_match_table
= sprd_mbox_of_match
,
407 .probe
= sprd_mbox_probe
,
409 module_platform_driver(sprd_mbox_driver
);
411 MODULE_AUTHOR("Baolin Wang <baolin.wang@unisoc.com>");
412 MODULE_DESCRIPTION("Spreadtrum mailbox driver");
413 MODULE_LICENSE("GPL v2");