13
13
#include <linux/init.h>
14
14
#include <linux/module.h>
15
15
#include <linux/kernel.h>
16
+ #include <linux/regmap.h>
16
17
#include <linux/interrupt.h>
18
+ #include <linux/mfd/syscon.h>
17
19
#include <linux/mod_devicetable.h>
18
20
#include <linux/platform_device.h>
19
21
#include <linux/mailbox_controller.h>
20
22
#include <soc/microchip/mpfs.h>
21
23
24
+ #define MESSAGE_INT_OFFSET 0x18cu
22
25
#define SERVICES_CR_OFFSET 0x50u
23
26
#define SERVICES_SR_OFFSET 0x54u
24
27
#define MAILBOX_REG_OFFSET 0x800u
@@ -68,14 +71,18 @@ struct mpfs_mbox {
68
71
void __iomem * int_reg ;
69
72
struct mbox_chan chans [1 ];
70
73
struct mpfs_mss_response * response ;
74
+ struct regmap * sysreg_scb , * control_scb ;
71
75
u16 resp_offset ;
72
76
};
73
77
74
78
static bool mpfs_mbox_busy (struct mpfs_mbox * mbox )
75
79
{
76
80
u32 status ;
77
81
78
- status = readl_relaxed (mbox -> ctrl_base + SERVICES_SR_OFFSET );
82
+ if (mbox -> control_scb )
83
+ regmap_read (mbox -> control_scb , SERVICES_SR_OFFSET , & status );
84
+ else
85
+ status = readl_relaxed (mbox -> ctrl_base + SERVICES_SR_OFFSET );
79
86
80
87
return status & SCB_STATUS_BUSY_MASK ;
81
88
}
@@ -95,7 +102,11 @@ static bool mpfs_mbox_last_tx_done(struct mbox_chan *chan)
95
102
* Failed services are intended to generated interrupts, but in reality
96
103
* this does not happen, so the status must be checked here.
97
104
*/
98
- val = readl_relaxed (mbox -> ctrl_base + SERVICES_SR_OFFSET );
105
+ if (mbox -> control_scb )
106
+ regmap_read (mbox -> control_scb , SERVICES_SR_OFFSET , & val );
107
+ else
108
+ val = readl_relaxed (mbox -> ctrl_base + SERVICES_SR_OFFSET );
109
+
99
110
response -> resp_status = (val & SCB_STATUS_MASK ) >> SCB_STATUS_POS ;
100
111
101
112
return true;
@@ -143,7 +154,12 @@ static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
143
154
144
155
tx_trigger = (opt_sel << SCB_CTRL_POS ) & SCB_CTRL_MASK ;
145
156
tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK ;
146
- writel_relaxed (tx_trigger , mbox -> ctrl_base + SERVICES_CR_OFFSET );
157
+
158
+ if (mbox -> control_scb )
159
+ regmap_write (mbox -> control_scb , SERVICES_CR_OFFSET , tx_trigger );
160
+ else
161
+ writel_relaxed (tx_trigger , mbox -> ctrl_base + SERVICES_CR_OFFSET );
162
+
147
163
148
164
return 0 ;
149
165
}
@@ -185,7 +201,10 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
185
201
struct mbox_chan * chan = data ;
186
202
struct mpfs_mbox * mbox = (struct mpfs_mbox * )chan -> con_priv ;
187
203
188
- writel_relaxed (0 , mbox -> int_reg );
204
+ if (mbox -> control_scb )
205
+ regmap_write (mbox -> sysreg_scb , MESSAGE_INT_OFFSET , 0 );
206
+ else
207
+ writel_relaxed (0 , mbox -> int_reg );
189
208
190
209
mpfs_mbox_rx_data (chan );
191
210
@@ -221,28 +240,62 @@ static const struct mbox_chan_ops mpfs_mbox_ops = {
221
240
.last_tx_done = mpfs_mbox_last_tx_done ,
222
241
};
223
242
224
- static int mpfs_mbox_probe ( struct platform_device * pdev )
243
+ static inline int mpfs_mbox_syscon_probe ( struct mpfs_mbox * mbox , struct platform_device * pdev )
225
244
{
226
- struct mpfs_mbox * mbox ;
227
- struct resource * regs ;
228
- int ret ;
245
+ mbox -> control_scb = syscon_regmap_lookup_by_compatible ( "microchip,mpfs-control-scb" ) ;
246
+ if ( IS_ERR ( mbox -> control_scb ))
247
+ return PTR_ERR ( mbox -> control_scb ) ;
229
248
230
- mbox = devm_kzalloc (& pdev -> dev , sizeof (* mbox ), GFP_KERNEL );
231
- if (!mbox )
232
- return - ENOMEM ;
249
+ mbox -> sysreg_scb = syscon_regmap_lookup_by_compatible ("microchip,mpfs-sysreg-scb" );
250
+ if (IS_ERR (mbox -> sysreg_scb ))
251
+ return PTR_ERR (mbox -> sysreg_scb );
252
+
253
+ mbox -> mbox_base = devm_platform_ioremap_resource (pdev , 0 );
254
+ if (IS_ERR (mbox -> ctrl_base ))
255
+ return PTR_ERR (mbox -> mbox_base );
256
+
257
+ return 0 ;
258
+ }
259
+
260
+ static inline int mpfs_mbox_old_format_probe (struct mpfs_mbox * mbox , struct platform_device * pdev )
261
+ {
262
+ dev_warn (& pdev -> dev , "falling back to old devicetree format" );
233
263
234
- mbox -> ctrl_base = devm_platform_get_and_ioremap_resource (pdev , 0 , & regs );
264
+ mbox -> ctrl_base = devm_platform_ioremap_resource (pdev , 0 );
235
265
if (IS_ERR (mbox -> ctrl_base ))
236
266
return PTR_ERR (mbox -> ctrl_base );
237
267
238
- mbox -> int_reg = devm_platform_get_and_ioremap_resource (pdev , 1 , & regs );
268
+ mbox -> int_reg = devm_platform_ioremap_resource (pdev , 1 );
239
269
if (IS_ERR (mbox -> int_reg ))
240
270
return PTR_ERR (mbox -> int_reg );
241
271
242
- mbox -> mbox_base = devm_platform_get_and_ioremap_resource (pdev , 2 , & regs );
272
+ mbox -> mbox_base = devm_platform_ioremap_resource (pdev , 2 );
243
273
if (IS_ERR (mbox -> mbox_base )) // account for the old dt-binding w/ 2 regs
244
274
mbox -> mbox_base = mbox -> ctrl_base + MAILBOX_REG_OFFSET ;
245
275
276
+ return 0 ;
277
+ }
278
+
279
+ static int mpfs_mbox_probe (struct platform_device * pdev )
280
+ {
281
+ struct mpfs_mbox * mbox ;
282
+ int ret ;
283
+
284
+ mbox = devm_kzalloc (& pdev -> dev , sizeof (* mbox ), GFP_KERNEL );
285
+ if (!mbox )
286
+ return - ENOMEM ;
287
+
288
+ ret = mpfs_mbox_syscon_probe (mbox , pdev );
289
+ if (ret ) {
290
+ /*
291
+ * set this to null, so it can be used as the decision for to
292
+ * regmap or not to regmap
293
+ */
294
+ mbox -> control_scb = NULL ;
295
+ ret = mpfs_mbox_old_format_probe (mbox , pdev );
296
+ if (ret )
297
+ return ret ;
298
+ }
246
299
mbox -> irq = platform_get_irq (pdev , 0 );
247
300
if (mbox -> irq < 0 )
248
301
return mbox -> irq ;
0 commit comments