11
11
#include <linux/io.h>
12
12
#include <linux/mailbox_controller.h>
13
13
#include <linux/module.h>
14
+ #include <linux/of_device.h>
14
15
#include <linux/platform_device.h>
15
16
#include <linux/clk.h>
16
17
50
51
#define SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ BIT(0)
51
52
#define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0)
52
53
54
+ #define SPRD_OUTBOX_BASE_SPAN 0x1000
53
55
#define SPRD_MBOX_CHAN_MAX 8
56
+ #define SPRD_SUPP_INBOX_ID_SC9863A 7
54
57
55
58
struct sprd_mbox_priv {
56
59
struct mbox_controller mbox ;
57
60
struct device * dev ;
58
61
void __iomem * inbox_base ;
59
62
void __iomem * outbox_base ;
63
+ /* Base register address for supplementary outbox */
64
+ void __iomem * supp_base ;
60
65
struct clk * clk ;
61
66
u32 outbox_fifo_depth ;
62
67
@@ -96,14 +101,13 @@ static u32 sprd_mbox_get_fifo_len(struct sprd_mbox_priv *priv, u32 fifo_sts)
96
101
return fifo_len ;
97
102
}
98
103
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 )
100
105
{
101
- struct sprd_mbox_priv * priv = data ;
102
106
struct mbox_chan * chan ;
103
107
u32 fifo_sts , fifo_len , msg [2 ];
104
108
int i , id ;
105
109
106
- fifo_sts = readl (priv -> outbox_base + SPRD_MBOX_FIFO_STS );
110
+ fifo_sts = readl (base + SPRD_MBOX_FIFO_STS );
107
111
108
112
fifo_len = sprd_mbox_get_fifo_len (priv , fifo_sts );
109
113
if (!fifo_len ) {
@@ -112,9 +116,9 @@ static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data)
112
116
}
113
117
114
118
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 );
118
122
119
123
chan = & priv -> chan [id ];
120
124
if (chan -> cl )
@@ -124,15 +128,29 @@ static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data)
124
128
"message's been dropped at ch[%d]\n" , id );
125
129
126
130
/* Trigger to update outbox FIFO pointer */
127
- writel (0x1 , priv -> outbox_base + SPRD_MBOX_TRIGGER );
131
+ writel (0x1 , base + SPRD_MBOX_TRIGGER );
128
132
}
129
133
130
134
/* 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 );
132
136
133
137
return IRQ_HANDLED ;
134
138
}
135
139
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
+
136
154
static irqreturn_t sprd_mbox_inbox_isr (int irq , void * data )
137
155
{
138
156
struct sprd_mbox_priv * priv = data ;
@@ -235,6 +253,14 @@ static int sprd_mbox_startup(struct mbox_chan *chan)
235
253
val = readl (priv -> outbox_base + SPRD_MBOX_IRQ_MSK );
236
254
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ ;
237
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
+ }
238
264
}
239
265
mutex_unlock (& priv -> lock );
240
266
@@ -250,6 +276,10 @@ static void sprd_mbox_shutdown(struct mbox_chan *chan)
250
276
/* Disable inbox & outbox interrupt */
251
277
writel (SPRD_INBOX_FIFO_IRQ_MASK , priv -> inbox_base + SPRD_MBOX_IRQ_MSK );
252
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 );
253
283
}
254
284
mutex_unlock (& priv -> lock );
255
285
}
@@ -272,8 +302,8 @@ static int sprd_mbox_probe(struct platform_device *pdev)
272
302
{
273
303
struct device * dev = & pdev -> dev ;
274
304
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 ;
277
307
278
308
priv = devm_kzalloc (dev , sizeof (* priv ), GFP_KERNEL );
279
309
if (!priv )
@@ -283,11 +313,15 @@ static int sprd_mbox_probe(struct platform_device *pdev)
283
313
mutex_init (& priv -> lock );
284
314
285
315
/*
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.
288
322
*
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 .
291
325
*/
292
326
priv -> inbox_base = devm_platform_ioremap_resource (pdev , 0 );
293
327
if (IS_ERR (priv -> inbox_base ))
@@ -313,7 +347,7 @@ static int sprd_mbox_probe(struct platform_device *pdev)
313
347
return ret ;
314
348
}
315
349
316
- inbox_irq = platform_get_irq (pdev , 0 );
350
+ inbox_irq = platform_get_irq_byname (pdev , "inbox" );
317
351
if (inbox_irq < 0 )
318
352
return inbox_irq ;
319
353
@@ -324,7 +358,7 @@ static int sprd_mbox_probe(struct platform_device *pdev)
324
358
return ret ;
325
359
}
326
360
327
- outbox_irq = platform_get_irq (pdev , 1 );
361
+ outbox_irq = platform_get_irq_byname (pdev , "outbox" );
328
362
if (outbox_irq < 0 )
329
363
return outbox_irq ;
330
364
@@ -335,6 +369,24 @@ static int sprd_mbox_probe(struct platform_device *pdev)
335
369
return ret ;
336
370
}
337
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
+
338
390
/* Get the default outbox FIFO depth */
339
391
priv -> outbox_fifo_depth =
340
392
readl (priv -> outbox_base + SPRD_MBOX_FIFO_DEPTH ) + 1 ;
@@ -357,7 +409,9 @@ static int sprd_mbox_probe(struct platform_device *pdev)
357
409
}
358
410
359
411
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 },
361
415
{ },
362
416
};
363
417
MODULE_DEVICE_TABLE (of , sprd_mbox_of_match );
0 commit comments