20
20
#include <linux/of_platform.h>
21
21
#include <linux/platform_device.h>
22
22
23
+ #include "irq-msi-lib.h"
24
+
23
25
#include <dt-bindings/interrupt-controller/mvebu-icu.h>
24
26
25
27
/* ICU registers */
@@ -60,14 +62,52 @@ struct mvebu_icu_msi_data {
60
62
const struct mvebu_icu_subset_data * subset_data ;
61
63
};
62
64
63
- struct mvebu_icu_irq_data {
64
- struct mvebu_icu * icu ;
65
- unsigned int icu_group ;
66
- unsigned int type ;
67
- };
68
-
69
65
static DEFINE_STATIC_KEY_FALSE (legacy_bindings );
70
66
67
+ static int mvebu_icu_translate (struct irq_domain * d , struct irq_fwspec * fwspec ,
68
+ unsigned long * hwirq , unsigned int * type )
69
+ {
70
+ unsigned int param_count = static_branch_unlikely (& legacy_bindings ) ? 3 : 2 ;
71
+ struct mvebu_icu_msi_data * msi_data = d -> host_data ;
72
+ struct mvebu_icu * icu = msi_data -> icu ;
73
+
74
+ /* Check the count of the parameters in dt */
75
+ if (WARN_ON (fwspec -> param_count != param_count )) {
76
+ dev_err (icu -> dev , "wrong ICU parameter count %d\n" ,
77
+ fwspec -> param_count );
78
+ return - EINVAL ;
79
+ }
80
+
81
+ if (static_branch_unlikely (& legacy_bindings )) {
82
+ * hwirq = fwspec -> param [1 ];
83
+ * type = fwspec -> param [2 ] & IRQ_TYPE_SENSE_MASK ;
84
+ if (fwspec -> param [0 ] != ICU_GRP_NSR ) {
85
+ dev_err (icu -> dev , "wrong ICU group type %x\n" ,
86
+ fwspec -> param [0 ]);
87
+ return - EINVAL ;
88
+ }
89
+ } else {
90
+ * hwirq = fwspec -> param [0 ];
91
+ * type = fwspec -> param [1 ] & IRQ_TYPE_SENSE_MASK ;
92
+
93
+ /*
94
+ * The ICU receives level interrupts. While the NSR are also
95
+ * level interrupts, SEI are edge interrupts. Force the type
96
+ * here in this case. Please note that this makes the interrupt
97
+ * handling unreliable.
98
+ */
99
+ if (msi_data -> subset_data -> icu_group == ICU_GRP_SEI )
100
+ * type = IRQ_TYPE_EDGE_RISING ;
101
+ }
102
+
103
+ if (* hwirq >= ICU_MAX_IRQS ) {
104
+ dev_err (icu -> dev , "invalid interrupt number %ld\n" , * hwirq );
105
+ return - EINVAL ;
106
+ }
107
+
108
+ return 0 ;
109
+ }
110
+
71
111
static void mvebu_icu_init (struct mvebu_icu * icu ,
72
112
struct mvebu_icu_msi_data * msi_data ,
73
113
struct msi_msg * msg )
@@ -89,6 +129,14 @@ static void mvebu_icu_init(struct mvebu_icu *icu,
89
129
writel_relaxed (msg [1 ].address_lo , icu -> base + subset -> offset_clr_al );
90
130
}
91
131
132
+ /* Start of area to be removed once all parent chips provide MSI parent */
133
+
134
+ struct mvebu_icu_irq_data {
135
+ struct mvebu_icu * icu ;
136
+ unsigned int icu_group ;
137
+ unsigned int type ;
138
+ };
139
+
92
140
static void mvebu_icu_write_msg (struct msi_desc * desc , struct msi_msg * msg )
93
141
{
94
142
struct irq_data * d = irq_get_irq_data (desc -> irq );
@@ -269,6 +317,109 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
269
317
.free = mvebu_icu_irq_domain_free ,
270
318
};
271
319
320
+ /* End of removal area */
321
+
322
+ static int mvebu_icu_msi_init (struct irq_domain * domain , struct msi_domain_info * info ,
323
+ unsigned int virq , irq_hw_number_t hwirq , msi_alloc_info_t * arg )
324
+ {
325
+ irq_domain_set_hwirq_and_chip (domain , virq , hwirq , info -> chip , info -> chip_data );
326
+ return irq_set_irqchip_state (virq , IRQCHIP_STATE_PENDING , false);
327
+ }
328
+
329
+ static void mvebu_icu_set_desc (msi_alloc_info_t * arg , struct msi_desc * desc )
330
+ {
331
+ arg -> desc = desc ;
332
+ arg -> hwirq = (u32 )desc -> data .icookie .value ;
333
+ }
334
+
335
+ static void mvebu_icu_write_msi_msg (struct irq_data * d , struct msi_msg * msg )
336
+ {
337
+ struct mvebu_icu_msi_data * msi_data = d -> chip_data ;
338
+ unsigned int icu_group = msi_data -> subset_data -> icu_group ;
339
+ struct msi_desc * desc = irq_data_get_msi_desc (d );
340
+ struct mvebu_icu * icu = msi_data -> icu ;
341
+ unsigned int type ;
342
+ u32 icu_int ;
343
+
344
+ if (msg -> address_lo || msg -> address_hi ) {
345
+ /* One off initialization per domain */
346
+ mvebu_icu_init (icu , msi_data , msg );
347
+ /* Configure the ICU with irq number & type */
348
+ icu_int = msg -> data | ICU_INT_ENABLE ;
349
+ type = (unsigned int )(desc -> data .icookie .value >> 32 );
350
+ if (type & IRQ_TYPE_EDGE_RISING )
351
+ icu_int |= ICU_IS_EDGE ;
352
+ icu_int |= icu_group << ICU_GROUP_SHIFT ;
353
+ } else {
354
+ /* De-configure the ICU */
355
+ icu_int = 0 ;
356
+ }
357
+
358
+ writel_relaxed (icu_int , icu -> base + ICU_INT_CFG (d -> hwirq ));
359
+
360
+ /*
361
+ * The SATA unit has 2 ports, and a dedicated ICU entry per
362
+ * port. The ahci sata driver supports only one irq interrupt
363
+ * per SATA unit. To solve this conflict, we configure the 2
364
+ * SATA wired interrupts in the south bridge into 1 GIC
365
+ * interrupt in the north bridge. Even if only a single port
366
+ * is enabled, if sata node is enabled, both interrupts are
367
+ * configured (regardless of which port is actually in use).
368
+ */
369
+ if (d -> hwirq == ICU_SATA0_ICU_ID || d -> hwirq == ICU_SATA1_ICU_ID ) {
370
+ writel_relaxed (icu_int , icu -> base + ICU_INT_CFG (ICU_SATA0_ICU_ID ));
371
+ writel_relaxed (icu_int , icu -> base + ICU_INT_CFG (ICU_SATA1_ICU_ID ));
372
+ }
373
+ }
374
+
375
+ static const struct msi_domain_template mvebu_icu_nsr_msi_template = {
376
+ .chip = {
377
+ .name = "ICU-NSR" ,
378
+ .irq_mask = irq_chip_mask_parent ,
379
+ .irq_unmask = irq_chip_unmask_parent ,
380
+ .irq_eoi = irq_chip_eoi_parent ,
381
+ .irq_set_type = irq_chip_set_type_parent ,
382
+ .irq_write_msi_msg = mvebu_icu_write_msi_msg ,
383
+ .flags = IRQCHIP_SUPPORTS_LEVEL_MSI ,
384
+ },
385
+
386
+ .ops = {
387
+ .msi_translate = mvebu_icu_translate ,
388
+ .msi_init = mvebu_icu_msi_init ,
389
+ .set_desc = mvebu_icu_set_desc ,
390
+ },
391
+
392
+ .info = {
393
+ .bus_token = DOMAIN_BUS_WIRED_TO_MSI ,
394
+ .flags = MSI_FLAG_LEVEL_CAPABLE |
395
+ MSI_FLAG_USE_DEV_FWNODE ,
396
+ },
397
+ };
398
+
399
+ static const struct msi_domain_template mvebu_icu_sei_msi_template = {
400
+ .chip = {
401
+ .name = "ICU-SEI" ,
402
+ .irq_mask = irq_chip_mask_parent ,
403
+ .irq_unmask = irq_chip_unmask_parent ,
404
+ .irq_ack = irq_chip_ack_parent ,
405
+ .irq_set_type = irq_chip_set_type_parent ,
406
+ .irq_write_msi_msg = mvebu_icu_write_msi_msg ,
407
+ .flags = IRQCHIP_SUPPORTS_LEVEL_MSI ,
408
+ },
409
+
410
+ .ops = {
411
+ .msi_translate = mvebu_icu_translate ,
412
+ .msi_init = mvebu_icu_msi_init ,
413
+ .set_desc = mvebu_icu_set_desc ,
414
+ },
415
+
416
+ .info = {
417
+ .bus_token = DOMAIN_BUS_WIRED_TO_MSI ,
418
+ .flags = MSI_FLAG_LEVEL_CAPABLE |
419
+ MSI_FLAG_USE_DEV_FWNODE ,
420
+ },
421
+ };
422
+
272
423
static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = {
273
424
.icu_group = ICU_GRP_NSR ,
274
425
.offset_set_ah = ICU_SETSPI_NSR_AH ,
@@ -298,7 +449,6 @@ static const struct of_device_id mvebu_icu_subset_of_match[] = {
298
449
static int mvebu_icu_subset_probe (struct platform_device * pdev )
299
450
{
300
451
struct mvebu_icu_msi_data * msi_data ;
301
- struct device_node * msi_parent_dn ;
302
452
struct device * dev = & pdev -> dev ;
303
453
struct irq_domain * irq_domain ;
304
454
@@ -314,15 +464,24 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev)
314
464
msi_data -> subset_data = of_device_get_match_data (dev );
315
465
}
316
466
317
- dev -> msi .domain = of_msi_get_domain (dev , dev -> of_node ,
318
- DOMAIN_BUS_PLATFORM_MSI );
467
+ dev -> msi .domain = of_msi_get_domain (dev , dev -> of_node , DOMAIN_BUS_PLATFORM_MSI );
319
468
if (!dev -> msi .domain )
320
469
return - EPROBE_DEFER ;
321
470
322
- msi_parent_dn = irq_domain_get_of_node (dev -> msi .domain );
323
- if (!msi_parent_dn )
471
+ if (!irq_domain_get_of_node (dev -> msi .domain ))
324
472
return - ENODEV ;
325
473
474
+ if (irq_domain_is_msi_parent (dev -> msi .domain )) {
475
+ bool sei = msi_data -> subset_data -> icu_group == ICU_GRP_SEI ;
476
+ const struct msi_domain_template * tmpl ;
477
+
478
+ tmpl = sei ? & mvebu_icu_sei_msi_template : & mvebu_icu_nsr_msi_template ;
479
+
480
+ if (!msi_create_device_irq_domain (dev , MSI_DEFAULT_DOMAIN , tmpl ,
481
+ ICU_MAX_IRQS , NULL , msi_data ))
482
+ return - ENOMEM ;
483
+ }
484
+
326
485
irq_domain = platform_msi_create_device_tree_domain (dev , ICU_MAX_IRQS ,
327
486
mvebu_icu_write_msg ,
328
487
& mvebu_icu_domain_ops ,
0 commit comments