13
13
#include <linux/irq.h>
14
14
#include <linux/irqchip.h>
15
15
#include <linux/irqdomain.h>
16
+ #include <linux/jump_label.h>
16
17
#include <linux/kernel.h>
17
18
#include <linux/msi.h>
18
19
#include <linux/of_irq.h>
@@ -49,6 +50,8 @@ struct mvebu_icu_irq_data {
49
50
unsigned int type ;
50
51
};
51
52
53
+ DEFINE_STATIC_KEY_FALSE (legacy_bindings );
54
+
52
55
static void mvebu_icu_init (struct mvebu_icu * icu , struct msi_msg * msg )
53
56
{
54
57
if (atomic_cmpxchg (& icu -> initialized , false, true))
@@ -105,32 +108,33 @@ mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
105
108
unsigned long * hwirq , unsigned int * type )
106
109
{
107
110
struct mvebu_icu * icu = platform_msi_get_host_data (d );
108
- unsigned int icu_group ;
111
+ unsigned int param_count = static_branch_unlikely ( & legacy_bindings ) ? 3 : 2 ;
109
112
110
113
/* Check the count of the parameters in dt */
111
- if (WARN_ON (fwspec -> param_count < 3 )) {
114
+ if (WARN_ON (fwspec -> param_count != param_count )) {
112
115
dev_err (icu -> dev , "wrong ICU parameter count %d\n" ,
113
116
fwspec -> param_count );
114
117
return - EINVAL ;
115
118
}
116
119
117
- /* Only ICU group type is handled */
118
- icu_group = fwspec -> param [0 ];
119
- if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR &&
120
- icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI ) {
121
- dev_err (icu -> dev , "wrong ICU group type %x\n" , icu_group );
122
- return - EINVAL ;
120
+ if (static_branch_unlikely (& legacy_bindings )) {
121
+ * hwirq = fwspec -> param [1 ];
122
+ * type = fwspec -> param [2 ] & IRQ_TYPE_SENSE_MASK ;
123
+ if (fwspec -> param [0 ] != ICU_GRP_NSR ) {
124
+ dev_err (icu -> dev , "wrong ICU group type %x\n" ,
125
+ fwspec -> param [0 ]);
126
+ return - EINVAL ;
127
+ }
128
+ } else {
129
+ * hwirq = fwspec -> param [0 ];
130
+ * type = fwspec -> param [1 ] & IRQ_TYPE_SENSE_MASK ;
123
131
}
124
132
125
- * hwirq = fwspec -> param [1 ];
126
133
if (* hwirq >= ICU_MAX_IRQS ) {
127
134
dev_err (icu -> dev , "invalid interrupt number %ld\n" , * hwirq );
128
135
return - EINVAL ;
129
136
}
130
137
131
- /* Mask the type to prevent wrong DT configuration */
132
- * type = fwspec -> param [2 ] & IRQ_TYPE_SENSE_MASK ;
133
-
134
138
return 0 ;
135
139
}
136
140
@@ -155,7 +159,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
155
159
goto free_irqd ;
156
160
}
157
161
158
- icu_irqd -> icu_group = fwspec -> param [0 ];
162
+ if (static_branch_unlikely (& legacy_bindings ))
163
+ icu_irqd -> icu_group = fwspec -> param [0 ];
164
+ else
165
+ icu_irqd -> icu_group = ICU_GRP_NSR ;
159
166
icu_irqd -> icu = icu ;
160
167
161
168
err = platform_msi_domain_alloc (domain , virq , nr_irqs );
@@ -203,14 +210,24 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
203
210
.free = mvebu_icu_irq_domain_free ,
204
211
};
205
212
213
+ static const struct of_device_id mvebu_icu_subset_of_match [] = {
214
+ {
215
+ .compatible = "marvell,cp110-icu-nsr" ,
216
+ },
217
+ {},
218
+ };
219
+
206
220
static int mvebu_icu_subset_probe (struct platform_device * pdev )
207
221
{
208
222
struct device_node * msi_parent_dn ;
209
223
struct device * dev = & pdev -> dev ;
210
224
struct irq_domain * irq_domain ;
211
225
struct mvebu_icu * icu ;
212
226
213
- icu = dev_get_drvdata (dev );
227
+ if (static_branch_unlikely (& legacy_bindings ))
228
+ icu = dev_get_drvdata (dev );
229
+ else
230
+ icu = dev_get_drvdata (dev -> parent );
214
231
215
232
dev -> msi_domain = of_msi_get_domain (dev , dev -> of_node ,
216
233
DOMAIN_BUS_PLATFORM_MSI );
@@ -233,6 +250,15 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev)
233
250
return 0 ;
234
251
}
235
252
253
+ static struct platform_driver mvebu_icu_subset_driver = {
254
+ .probe = mvebu_icu_subset_probe ,
255
+ .driver = {
256
+ .name = "mvebu-icu-subset" ,
257
+ .of_match_table = mvebu_icu_subset_of_match ,
258
+ },
259
+ };
260
+ builtin_platform_driver (mvebu_icu_subset_driver );
261
+
236
262
static int mvebu_icu_probe (struct platform_device * pdev )
237
263
{
238
264
struct mvebu_icu * icu ;
@@ -259,6 +285,16 @@ static int mvebu_icu_probe(struct platform_device *pdev)
259
285
if (!icu -> irq_chip .name )
260
286
return - ENOMEM ;
261
287
288
+ /*
289
+ * Legacy bindings: ICU is one node with one MSI parent: force manually
290
+ * the probe of the NSR interrupts side.
291
+ * New bindings: ICU node has children, one per interrupt controller
292
+ * having its own MSI parent: call platform_populate().
293
+ * All ICU instances should use the same bindings.
294
+ */
295
+ if (!of_get_child_count (pdev -> dev .of_node ))
296
+ static_branch_enable (& legacy_bindings );
297
+
262
298
icu -> irq_chip .irq_mask = irq_chip_mask_parent ;
263
299
icu -> irq_chip .irq_unmask = irq_chip_unmask_parent ;
264
300
icu -> irq_chip .irq_eoi = irq_chip_eoi_parent ;
@@ -277,13 +313,18 @@ static int mvebu_icu_probe(struct platform_device *pdev)
277
313
icu_int = readl_relaxed (icu -> base + ICU_INT_CFG (i ));
278
314
icu_grp = icu_int >> ICU_GROUP_SHIFT ;
279
315
280
- if (icu_grp == ICU_GRP_NSR )
316
+ if (icu_grp == ICU_GRP_NSR ||
317
+ (icu_grp == ICU_GRP_SEI &&
318
+ !static_branch_unlikely (& legacy_bindings )))
281
319
writel_relaxed (0x0 , icu -> base + ICU_INT_CFG (i ));
282
320
}
283
321
284
322
platform_set_drvdata (pdev , icu );
285
323
286
- return mvebu_icu_subset_probe (pdev );
324
+ if (static_branch_unlikely (& legacy_bindings ))
325
+ return mvebu_icu_subset_probe (pdev );
326
+ else
327
+ return devm_of_platform_populate (& pdev -> dev );
287
328
}
288
329
289
330
static const struct of_device_id mvebu_icu_of_match [] = {
0 commit comments