Skip to content

Commit 6457f4c

Browse files
Orson ZhaiJassiBrar
authored andcommitted
mailbox: sprd: Add supplementary inbox support
Some sensors connected to Unisoc mailbox will send data very frequently. This makes channel 0 very busy and the messages from other remote cores not able to be handled as soon as possible. It's a trick (un-documented) from Unisoc ASIC designers to resolve this special requirement that an inbox assigned to one of the remote cores before was modified to be exposed to host cpu core. Then from host side, a supplementary inbox is added for transferring mass but not emergency messages from the remote cores, such as step counting sensor, with an independent FIFO and interrupt which is as same as channel 0. Meanwihle, inbox part of this channel is still kept for original remote core to use. Signed-off-by: Orson Zhai <[email protected]> Reviewed-by: Baolin Wang <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent 6203b95 commit 6457f4c

File tree

1 file changed

+71
-17
lines changed

1 file changed

+71
-17
lines changed

drivers/mailbox/sprd-mailbox.c

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/io.h>
1212
#include <linux/mailbox_controller.h>
1313
#include <linux/module.h>
14+
#include <linux/of_device.h>
1415
#include <linux/platform_device.h>
1516
#include <linux/clk.h>
1617

@@ -50,13 +51,17 @@
5051
#define SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ BIT(0)
5152
#define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0)
5253

54+
#define SPRD_OUTBOX_BASE_SPAN 0x1000
5355
#define SPRD_MBOX_CHAN_MAX 8
56+
#define SPRD_SUPP_INBOX_ID_SC9863A 7
5457

5558
struct sprd_mbox_priv {
5659
struct mbox_controller mbox;
5760
struct device *dev;
5861
void __iomem *inbox_base;
5962
void __iomem *outbox_base;
63+
/* Base register address for supplementary outbox */
64+
void __iomem *supp_base;
6065
struct clk *clk;
6166
u32 outbox_fifo_depth;
6267

@@ -96,14 +101,13 @@ static u32 sprd_mbox_get_fifo_len(struct sprd_mbox_priv *priv, u32 fifo_sts)
96101
return fifo_len;
97102
}
98103

99-
static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data)
104+
static irqreturn_t do_outbox_isr(void __iomem *base, struct sprd_mbox_priv *priv)
100105
{
101-
struct sprd_mbox_priv *priv = data;
102106
struct mbox_chan *chan;
103107
u32 fifo_sts, fifo_len, msg[2];
104108
int i, id;
105109

106-
fifo_sts = readl(priv->outbox_base + SPRD_MBOX_FIFO_STS);
110+
fifo_sts = readl(base + SPRD_MBOX_FIFO_STS);
107111

108112
fifo_len = sprd_mbox_get_fifo_len(priv, fifo_sts);
109113
if (!fifo_len) {
@@ -112,9 +116,9 @@ static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data)
112116
}
113117

114118
for (i = 0; i < fifo_len; i++) {
115-
msg[0] = readl(priv->outbox_base + SPRD_MBOX_MSG_LOW);
116-
msg[1] = readl(priv->outbox_base + SPRD_MBOX_MSG_HIGH);
117-
id = readl(priv->outbox_base + SPRD_MBOX_ID);
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);
118122

119123
chan = &priv->chan[id];
120124
if (chan->cl)
@@ -124,15 +128,29 @@ static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data)
124128
"message's been dropped at ch[%d]\n", id);
125129

126130
/* Trigger to update outbox FIFO pointer */
127-
writel(0x1, priv->outbox_base + SPRD_MBOX_TRIGGER);
131+
writel(0x1, base + SPRD_MBOX_TRIGGER);
128132
}
129133

130134
/* Clear irq status after reading all message. */
131-
writel(SPRD_MBOX_IRQ_CLR, priv->outbox_base + SPRD_MBOX_IRQ_STS);
135+
writel(SPRD_MBOX_IRQ_CLR, base + SPRD_MBOX_IRQ_STS);
132136

133137
return IRQ_HANDLED;
134138
}
135139

140+
static 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+
147+
static 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+
136154
static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
137155
{
138156
struct sprd_mbox_priv *priv = data;
@@ -235,6 +253,14 @@ static int sprd_mbox_startup(struct mbox_chan *chan)
235253
val = readl(priv->outbox_base + SPRD_MBOX_IRQ_MSK);
236254
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
237255
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+
}
238264
}
239265
mutex_unlock(&priv->lock);
240266

@@ -250,6 +276,10 @@ static void sprd_mbox_shutdown(struct mbox_chan *chan)
250276
/* Disable inbox & outbox interrupt */
251277
writel(SPRD_INBOX_FIFO_IRQ_MASK, priv->inbox_base + SPRD_MBOX_IRQ_MSK);
252278
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);
253283
}
254284
mutex_unlock(&priv->lock);
255285
}
@@ -272,8 +302,8 @@ static int sprd_mbox_probe(struct platform_device *pdev)
272302
{
273303
struct device *dev = &pdev->dev;
274304
struct sprd_mbox_priv *priv;
275-
int ret, inbox_irq, outbox_irq;
276-
unsigned long id;
305+
int ret, inbox_irq, outbox_irq, supp_irq;
306+
unsigned long id, supp;
277307

278308
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
279309
if (!priv)
@@ -283,11 +313,15 @@ static int sprd_mbox_probe(struct platform_device *pdev)
283313
mutex_init(&priv->lock);
284314

285315
/*
286-
* The Spreadtrum mailbox uses an inbox to send messages to the target
287-
* core, and uses an outbox to receive messages from other cores.
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.
288322
*
289-
* Thus the mailbox controller supplies 2 different register addresses
290-
* 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.
291325
*/
292326
priv->inbox_base = devm_platform_ioremap_resource(pdev, 0);
293327
if (IS_ERR(priv->inbox_base))
@@ -313,7 +347,7 @@ static int sprd_mbox_probe(struct platform_device *pdev)
313347
return ret;
314348
}
315349

316-
inbox_irq = platform_get_irq(pdev, 0);
350+
inbox_irq = platform_get_irq_byname(pdev, "inbox");
317351
if (inbox_irq < 0)
318352
return inbox_irq;
319353

@@ -324,7 +358,7 @@ static int sprd_mbox_probe(struct platform_device *pdev)
324358
return ret;
325359
}
326360

327-
outbox_irq = platform_get_irq(pdev, 1);
361+
outbox_irq = platform_get_irq_byname(pdev, "outbox");
328362
if (outbox_irq < 0)
329363
return outbox_irq;
330364

@@ -335,6 +369,24 @@ static int sprd_mbox_probe(struct platform_device *pdev)
335369
return ret;
336370
}
337371

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+
338390
/* Get the default outbox FIFO depth */
339391
priv->outbox_fifo_depth =
340392
readl(priv->outbox_base + SPRD_MBOX_FIFO_DEPTH) + 1;
@@ -357,7 +409,9 @@ static int sprd_mbox_probe(struct platform_device *pdev)
357409
}
358410

359411
static const struct of_device_id sprd_mbox_of_match[] = {
360-
{ .compatible = "sprd,sc9860-mailbox", },
412+
{ .compatible = "sprd,sc9860-mailbox" },
413+
{ .compatible = "sprd,sc9863a-mailbox",
414+
.data = (void *)SPRD_SUPP_INBOX_ID_SC9863A },
361415
{ },
362416
};
363417
MODULE_DEVICE_TABLE(of, sprd_mbox_of_match);

0 commit comments

Comments
 (0)