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/platform_device.h>
15 #include <linux/clk.h>
17 #define SPRD_MBOX_ID 0x0
18 #define SPRD_MBOX_MSG_LOW 0x4
19 #define SPRD_MBOX_MSG_HIGH 0x8
20 #define SPRD_MBOX_TRIGGER 0xc
21 #define SPRD_MBOX_FIFO_RST 0x10
22 #define SPRD_MBOX_FIFO_STS 0x14
23 #define SPRD_MBOX_IRQ_STS 0x18
24 #define SPRD_MBOX_IRQ_MSK 0x1c
25 #define SPRD_MBOX_LOCK 0x20
26 #define SPRD_MBOX_FIFO_DEPTH 0x24
28 /* Bit and mask definiation for inbox's SPRD_MBOX_FIFO_STS register */
29 #define SPRD_INBOX_FIFO_DELIVER_MASK GENMASK(23, 16)
30 #define SPRD_INBOX_FIFO_OVERLOW_MASK GENMASK(15, 8)
31 #define SPRD_INBOX_FIFO_DELIVER_SHIFT 16
32 #define SPRD_INBOX_FIFO_BUSY_MASK GENMASK(7, 0)
34 /* Bit and mask definiation for SPRD_MBOX_IRQ_STS register */
35 #define SPRD_MBOX_IRQ_CLR BIT(0)
37 /* Bit and mask definiation for outbox's SPRD_MBOX_FIFO_STS register */
38 #define SPRD_OUTBOX_FIFO_FULL BIT(0)
39 #define SPRD_OUTBOX_FIFO_WR_SHIFT 16
40 #define SPRD_OUTBOX_FIFO_RD_SHIFT 24
41 #define SPRD_OUTBOX_FIFO_POS_MASK GENMASK(7, 0)
43 /* Bit and mask definiation for inbox's SPRD_MBOX_IRQ_MSK register */
44 #define SPRD_INBOX_FIFO_BLOCK_IRQ BIT(0)
45 #define SPRD_INBOX_FIFO_OVERFLOW_IRQ BIT(1)
46 #define SPRD_INBOX_FIFO_DELIVER_IRQ BIT(2)
47 #define SPRD_INBOX_FIFO_IRQ_MASK GENMASK(2, 0)
49 /* Bit and mask definiation for outbox's SPRD_MBOX_IRQ_MSK register */
50 #define SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ BIT(0)
51 #define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0)
53 #define SPRD_MBOX_CHAN_MAX 8
55 struct sprd_mbox_priv
{
56 struct mbox_controller mbox
;
58 void __iomem
*inbox_base
;
59 void __iomem
*outbox_base
;
61 u32 outbox_fifo_depth
;
63 struct mbox_chan chan
[SPRD_MBOX_CHAN_MAX
];
66 static struct sprd_mbox_priv
*to_sprd_mbox_priv(struct mbox_controller
*mbox
)
68 return container_of(mbox
, struct sprd_mbox_priv
, mbox
);
71 static u32
sprd_mbox_get_fifo_len(struct sprd_mbox_priv
*priv
, u32 fifo_sts
)
73 u32 wr_pos
= (fifo_sts
>> SPRD_OUTBOX_FIFO_WR_SHIFT
) &
74 SPRD_OUTBOX_FIFO_POS_MASK
;
75 u32 rd_pos
= (fifo_sts
>> SPRD_OUTBOX_FIFO_RD_SHIFT
) &
76 SPRD_OUTBOX_FIFO_POS_MASK
;
80 * If the read pointer is equal with write pointer, which means the fifo
83 if (wr_pos
== rd_pos
) {
84 if (fifo_sts
& SPRD_OUTBOX_FIFO_FULL
)
85 fifo_len
= priv
->outbox_fifo_depth
;
88 } else if (wr_pos
> rd_pos
) {
89 fifo_len
= wr_pos
- rd_pos
;
91 fifo_len
= priv
->outbox_fifo_depth
- rd_pos
+ wr_pos
;
97 static irqreturn_t
sprd_mbox_outbox_isr(int irq
, void *data
)
99 struct sprd_mbox_priv
*priv
= data
;
100 struct mbox_chan
*chan
;
101 u32 fifo_sts
, fifo_len
, msg
[2];
104 fifo_sts
= readl(priv
->outbox_base
+ SPRD_MBOX_FIFO_STS
);
106 fifo_len
= sprd_mbox_get_fifo_len(priv
, fifo_sts
);
108 dev_warn_ratelimited(priv
->dev
, "spurious outbox interrupt\n");
112 for (i
= 0; i
< fifo_len
; i
++) {
113 msg
[0] = readl(priv
->outbox_base
+ SPRD_MBOX_MSG_LOW
);
114 msg
[1] = readl(priv
->outbox_base
+ SPRD_MBOX_MSG_HIGH
);
115 id
= readl(priv
->outbox_base
+ SPRD_MBOX_ID
);
117 chan
= &priv
->chan
[id
];
118 mbox_chan_received_data(chan
, (void *)msg
);
120 /* Trigger to update outbox FIFO pointer */
121 writel(0x1, priv
->outbox_base
+ SPRD_MBOX_TRIGGER
);
124 /* Clear irq status after reading all message. */
125 writel(SPRD_MBOX_IRQ_CLR
, priv
->outbox_base
+ SPRD_MBOX_IRQ_STS
);
130 static irqreturn_t
sprd_mbox_inbox_isr(int irq
, void *data
)
132 struct sprd_mbox_priv
*priv
= data
;
133 struct mbox_chan
*chan
;
134 u32 fifo_sts
, send_sts
, busy
, id
;
136 fifo_sts
= readl(priv
->inbox_base
+ SPRD_MBOX_FIFO_STS
);
138 /* Get the inbox data delivery status */
139 send_sts
= (fifo_sts
& SPRD_INBOX_FIFO_DELIVER_MASK
) >>
140 SPRD_INBOX_FIFO_DELIVER_SHIFT
;
142 dev_warn_ratelimited(priv
->dev
, "spurious inbox interrupt\n");
147 id
= __ffs(send_sts
);
148 send_sts
&= (send_sts
- 1);
150 chan
= &priv
->chan
[id
];
153 * Check if the message was fetched by remote traget, if yes,
154 * that means the transmission has been completed.
156 busy
= fifo_sts
& SPRD_INBOX_FIFO_BUSY_MASK
;
157 if (!(busy
& BIT(id
)))
158 mbox_chan_txdone(chan
, 0);
161 /* Clear FIFO delivery and overflow status */
163 (SPRD_INBOX_FIFO_DELIVER_MASK
| SPRD_INBOX_FIFO_OVERLOW_MASK
),
164 priv
->inbox_base
+ SPRD_MBOX_FIFO_RST
);
166 /* Clear irq status */
167 writel(SPRD_MBOX_IRQ_CLR
, priv
->inbox_base
+ SPRD_MBOX_IRQ_STS
);
172 static int sprd_mbox_send_data(struct mbox_chan
*chan
, void *msg
)
174 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
175 unsigned long id
= (unsigned long)chan
->con_priv
;
178 /* Write data into inbox FIFO, and only support 8 bytes every time */
179 writel(data
[0], priv
->inbox_base
+ SPRD_MBOX_MSG_LOW
);
180 writel(data
[1], priv
->inbox_base
+ SPRD_MBOX_MSG_HIGH
);
182 /* Set target core id */
183 writel(id
, priv
->inbox_base
+ SPRD_MBOX_ID
);
185 /* Trigger remote request */
186 writel(0x1, priv
->inbox_base
+ SPRD_MBOX_TRIGGER
);
191 static int sprd_mbox_flush(struct mbox_chan
*chan
, unsigned long timeout
)
193 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
194 unsigned long id
= (unsigned long)chan
->con_priv
;
197 timeout
= jiffies
+ msecs_to_jiffies(timeout
);
199 while (time_before(jiffies
, timeout
)) {
200 busy
= readl(priv
->inbox_base
+ SPRD_MBOX_FIFO_STS
) &
201 SPRD_INBOX_FIFO_BUSY_MASK
;
202 if (!(busy
& BIT(id
))) {
203 mbox_chan_txdone(chan
, 0);
213 static int sprd_mbox_startup(struct mbox_chan
*chan
)
215 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
218 /* Select outbox FIFO mode and reset the outbox FIFO status */
219 writel(0x0, priv
->outbox_base
+ SPRD_MBOX_FIFO_RST
);
221 /* Enable inbox FIFO overflow and delivery interrupt */
222 val
= readl(priv
->inbox_base
+ SPRD_MBOX_IRQ_MSK
);
223 val
&= ~(SPRD_INBOX_FIFO_OVERFLOW_IRQ
| SPRD_INBOX_FIFO_DELIVER_IRQ
);
224 writel(val
, priv
->inbox_base
+ SPRD_MBOX_IRQ_MSK
);
226 /* Enable outbox FIFO not empty interrupt */
227 val
= readl(priv
->outbox_base
+ SPRD_MBOX_IRQ_MSK
);
228 val
&= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ
;
229 writel(val
, priv
->outbox_base
+ SPRD_MBOX_IRQ_MSK
);
234 static void sprd_mbox_shutdown(struct mbox_chan
*chan
)
236 struct sprd_mbox_priv
*priv
= to_sprd_mbox_priv(chan
->mbox
);
238 /* Disable inbox & outbox interrupt */
239 writel(SPRD_INBOX_FIFO_IRQ_MASK
, priv
->inbox_base
+ SPRD_MBOX_IRQ_MSK
);
240 writel(SPRD_OUTBOX_FIFO_IRQ_MASK
, priv
->outbox_base
+ SPRD_MBOX_IRQ_MSK
);
243 static const struct mbox_chan_ops sprd_mbox_ops
= {
244 .send_data
= sprd_mbox_send_data
,
245 .flush
= sprd_mbox_flush
,
246 .startup
= sprd_mbox_startup
,
247 .shutdown
= sprd_mbox_shutdown
,
250 static void sprd_mbox_disable(void *data
)
252 struct sprd_mbox_priv
*priv
= data
;
254 clk_disable_unprepare(priv
->clk
);
257 static int sprd_mbox_probe(struct platform_device
*pdev
)
259 struct device
*dev
= &pdev
->dev
;
260 struct sprd_mbox_priv
*priv
;
261 int ret
, inbox_irq
, outbox_irq
;
264 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
271 * The Spreadtrum mailbox uses an inbox to send messages to the target
272 * core, and uses an outbox to receive messages from other cores.
274 * Thus the mailbox controller supplies 2 different register addresses
275 * and IRQ numbers for inbox and outbox.
277 priv
->inbox_base
= devm_platform_ioremap_resource(pdev
, 0);
278 if (IS_ERR(priv
->inbox_base
))
279 return PTR_ERR(priv
->inbox_base
);
281 priv
->outbox_base
= devm_platform_ioremap_resource(pdev
, 1);
282 if (IS_ERR(priv
->outbox_base
))
283 return PTR_ERR(priv
->outbox_base
);
285 priv
->clk
= devm_clk_get(dev
, "enable");
286 if (IS_ERR(priv
->clk
)) {
287 dev_err(dev
, "failed to get mailbox clock\n");
288 return PTR_ERR(priv
->clk
);
291 ret
= clk_prepare_enable(priv
->clk
);
295 ret
= devm_add_action_or_reset(dev
, sprd_mbox_disable
, priv
);
297 dev_err(dev
, "failed to add mailbox disable action\n");
301 inbox_irq
= platform_get_irq(pdev
, 0);
305 ret
= devm_request_irq(dev
, inbox_irq
, sprd_mbox_inbox_isr
,
306 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
308 dev_err(dev
, "failed to request inbox IRQ: %d\n", ret
);
312 outbox_irq
= platform_get_irq(pdev
, 1);
316 ret
= devm_request_irq(dev
, outbox_irq
, sprd_mbox_outbox_isr
,
317 IRQF_NO_SUSPEND
, dev_name(dev
), priv
);
319 dev_err(dev
, "failed to request outbox IRQ: %d\n", ret
);
323 /* Get the default outbox FIFO depth */
324 priv
->outbox_fifo_depth
=
325 readl(priv
->outbox_base
+ SPRD_MBOX_FIFO_DEPTH
) + 1;
326 priv
->mbox
.dev
= dev
;
327 priv
->mbox
.chans
= &priv
->chan
[0];
328 priv
->mbox
.num_chans
= SPRD_MBOX_CHAN_MAX
;
329 priv
->mbox
.ops
= &sprd_mbox_ops
;
330 priv
->mbox
.txdone_irq
= true;
332 for (id
= 0; id
< SPRD_MBOX_CHAN_MAX
; id
++)
333 priv
->chan
[id
].con_priv
= (void *)id
;
335 ret
= devm_mbox_controller_register(dev
, &priv
->mbox
);
337 dev_err(dev
, "failed to register mailbox: %d\n", ret
);
344 static const struct of_device_id sprd_mbox_of_match
[] = {
345 { .compatible
= "sprd,sc9860-mailbox", },
348 MODULE_DEVICE_TABLE(of
, sprd_mbox_of_match
);
350 static struct platform_driver sprd_mbox_driver
= {
352 .name
= "sprd-mailbox",
353 .of_match_table
= sprd_mbox_of_match
,
355 .probe
= sprd_mbox_probe
,
357 module_platform_driver(sprd_mbox_driver
);
359 MODULE_AUTHOR("Baolin Wang <baolin.wang@unisoc.com>");
360 MODULE_DESCRIPTION("Spreadtrum mailbox driver");
361 MODULE_LICENSE("GPL v2");