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>
14 #include <linux/of_device.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
;
66 u32 outbox_fifo_depth
;
70 struct mbox_chan chan
[SPRD_MBOX_CHAN_MAX
];
73 static struct sprd_mbox_priv
*to_sprd_mbox_priv(struct mbox_controller
*mbox
)
75 return container_of(mbox
, struct sprd_mbox_priv
, mbox
);
78 static u32
sprd_mbox_get_fifo_len(struct sprd_mbox_priv
*priv
, u32 fifo_sts
)
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
;
87 * If the read pointer is equal with write pointer, which means the fifo
90 if (wr_pos
== rd_pos
) {
91 if (fifo_sts
& SPRD_OUTBOX_FIFO_FULL
)
92 fifo_len
= priv
->outbox_fifo_depth
;
95 } else if (wr_pos
> rd_pos
) {
96 fifo_len
= wr_pos
- rd_pos
;
98 fifo_len
= priv
->outbox_fifo_depth
- rd_pos
+ wr_pos
;
104 static irqreturn_t
do_outbox_isr(void __iomem
*base
, struct sprd_mbox_priv
*priv
)
106 struct mbox_chan
*chan
;
107 u32 fifo_sts
, fifo_len
, msg
[2];
110 fifo_sts
= readl(base
+ SPRD_MBOX_FIFO_STS
);
112 fifo_len
= sprd_mbox_get_fifo_len(priv
, fifo_sts
);
114 dev_warn_ratelimited(priv
->dev
, "spurious outbox interrupt\n");
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
);
123 chan
= &priv
->chan
[id
];
125 mbox_chan_received_data(chan
, (void *)msg
);
127 dev_warn_ratelimited(priv
->dev
,
128 "message's been dropped at ch[%d]\n", id
);
130 /* Trigger to update outbox FIFO pointer */
131 writel(0x1, base
+ SPRD_MBOX_TRIGGER
);
134 /* Clear irq status after reading all message. */
135 writel(SPRD_MBOX_IRQ_CLR
, base
+ SPRD_MBOX_IRQ_STS
);
140 static irqreturn_t
sprd_mbox_outbox_isr(int irq
, void *data
)
142 struct sprd_mbox_priv
*priv
= data
;
144 return do_outbox_isr(priv
->outbox_base
, priv
);
147 static irqreturn_t
sprd_mbox_supp_isr(int irq
, void *data
)
149 struct sprd_mbox_priv
*priv
= data
;
151 return do_outbox_isr(priv
->supp_base
, priv
);
154 static irqreturn_t
sprd_mbox_inbox_isr(int irq
, void *data
)
156 struct sprd_mbox_priv
*priv
= data
;
157 struct mbox_chan
*chan
;
158 u32 fifo_sts
, send_sts
, busy
, id
;
160 fifo_sts
= readl(priv
->inbox_base
+ SPRD_MBOX_FIFO_STS
);
162 /* Get the inbox data delivery status */
163 send_sts
= (fifo_sts
& SPRD_INBOX_FIFO_DELIVER_MASK
) >>
164 SPRD_INBOX_FIFO_DELIVER_SHIFT
;
166 dev_warn_ratelimited(priv
->dev
, "spurious inbox interrupt\n");
171 id
= __ffs(send_sts
);
172 send_sts
&= (send_sts
- 1);
174 chan
= &priv
->chan
[id
];
177 * Check if the message was fetched by remote target, if yes,
178 * that means the transmission has been completed.
180 busy
= fifo_sts
& SPRD_INBOX_FIFO_BUSY_MASK
;
181 if (!(busy
& BIT(id
)))
182 mbox_chan_txdone(chan
, 0);
185 /* Clear FIFO delivery and overflow status */
187 (SPRD_INBOX_FIFO_DELIVER_MASK
| SPRD_INBOX_FIFO_OVERLOW_MASK
),
188 priv
->inbox_base
+ SPRD_MBOX_FIFO_RST
);
190 /* Clear irq status */
191 writel(SPRD_MBOX_IRQ_CLR
, priv
->inbox_base
+ SPRD_MBOX_IRQ_STS
);
196 static int sprd_mbox_send_data(struct mbox_chan
*chan
, void *msg
)
198 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
199 unsigned long id
= (unsigned long)chan
->con_priv
;
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
);
206 /* Set target core id */
207 writel(id
, priv
->inbox_base
+ SPRD_MBOX_ID
);
209 /* Trigger remote request */
210 writel(0x1, priv
->inbox_base
+ SPRD_MBOX_TRIGGER
);
215 static int sprd_mbox_flush(struct mbox_chan
*chan
, unsigned long timeout
)
217 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
218 unsigned long id
= (unsigned long)chan
->con_priv
;
221 timeout
= jiffies
+ msecs_to_jiffies(timeout
);
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);
237 static int sprd_mbox_startup(struct mbox_chan
*chan
)
239 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
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
);
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
);
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
);
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
);
265 mutex_unlock(&priv
->lock
);
270 static void sprd_mbox_shutdown(struct mbox_chan
*chan
)
272 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
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
);
281 writel(SPRD_OUTBOX_FIFO_IRQ_MASK
,
282 priv
->supp_base
+ SPRD_MBOX_IRQ_MSK
);
284 mutex_unlock(&priv
->lock
);
287 static 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
,
294 static void sprd_mbox_disable(void *data
)
296 struct sprd_mbox_priv
*priv
= data
;
298 clk_disable_unprepare(priv
->clk
);
301 static int sprd_mbox_probe(struct platform_device
*pdev
)
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
;
308 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
313 mutex_init(&priv
->lock
);
316 * Unisoc mailbox uses an inbox to send messages to the target
317 * core, and uses (an) outbox(es) to receive messages from other
320 * Thus in general the mailbox controller supplies 2 different
321 * register addresses and IRQ numbers for inbox and outbox.
323 * If necessary, a supplementary inbox could be enabled optionally
324 * with an independent FIFO and an extra interrupt.
326 priv
->inbox_base
= devm_platform_ioremap_resource(pdev
, 0);
327 if (IS_ERR(priv
->inbox_base
))
328 return PTR_ERR(priv
->inbox_base
);
330 priv
->outbox_base
= devm_platform_ioremap_resource(pdev
, 1);
331 if (IS_ERR(priv
->outbox_base
))
332 return PTR_ERR(priv
->outbox_base
);
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
);
340 ret
= clk_prepare_enable(priv
->clk
);
344 ret
= devm_add_action_or_reset(dev
, sprd_mbox_disable
, priv
);
346 dev_err(dev
, "failed to add mailbox disable action\n");
350 inbox_irq
= platform_get_irq_byname(pdev
, "inbox");
354 ret
= devm_request_irq(dev
, inbox_irq
, sprd_mbox_inbox_isr
,
355 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
357 dev_err(dev
, "failed to request inbox IRQ: %d\n", ret
);
361 outbox_irq
= platform_get_irq_byname(pdev
, "outbox");
365 ret
= devm_request_irq(dev
, outbox_irq
, sprd_mbox_outbox_isr
,
366 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
368 dev_err(dev
, "failed to request outbox IRQ: %d\n", ret
);
372 /* Supplementary outbox IRQ is optional */
373 supp_irq
= platform_get_irq_byname(pdev
, "supp-outbox");
375 ret
= devm_request_irq(dev
, supp_irq
, sprd_mbox_supp_isr
,
376 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
378 dev_err(dev
, "failed to request outbox IRQ: %d\n", ret
);
382 supp
= (unsigned long) of_device_get_match_data(dev
);
384 dev_err(dev
, "no supplementary outbox specified\n");
387 priv
->supp_base
= priv
->outbox_base
+ (SPRD_OUTBOX_BASE_SPAN
* supp
);
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;
399 for (id
= 0; id
< SPRD_MBOX_CHAN_MAX
; id
++)
400 priv
->chan
[id
].con_priv
= (void *)id
;
402 ret
= devm_mbox_controller_register(dev
, &priv
->mbox
);
404 dev_err(dev
, "failed to register mailbox: %d\n", ret
);
411 static 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
},
417 MODULE_DEVICE_TABLE(of
, sprd_mbox_of_match
);
419 static struct platform_driver sprd_mbox_driver
= {
421 .name
= "sprd-mailbox",
422 .of_match_table
= sprd_mbox_of_match
,
424 .probe
= sprd_mbox_probe
,
426 module_platform_driver(sprd_mbox_driver
);
428 MODULE_AUTHOR("Baolin Wang <baolin.wang@unisoc.com>");
429 MODULE_DESCRIPTION("Spreadtrum mailbox driver");
430 MODULE_LICENSE("GPL v2");