2 * Copyright (C) 2017 Marvell
4 * Hanna Hawa <hannah@marvell.com>
5 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
12 #include <linux/interrupt.h>
13 #include <linux/irq.h>
14 #include <linux/irqchip.h>
15 #include <linux/irqdomain.h>
16 #include <linux/kernel.h>
17 #include <linux/msi.h>
18 #include <linux/of_irq.h>
19 #include <linux/of_platform.h>
20 #include <linux/platform_device.h>
22 #include <dt-bindings/interrupt-controller/mvebu-icu.h>
25 #define ICU_SETSPI_NSR_AL 0x10
26 #define ICU_SETSPI_NSR_AH 0x14
27 #define ICU_CLRSPI_NSR_AL 0x18
28 #define ICU_CLRSPI_NSR_AH 0x1c
29 #define ICU_INT_CFG(x) (0x100 + 4 * (x))
30 #define ICU_INT_ENABLE BIT(24)
31 #define ICU_IS_EDGE BIT(28)
32 #define ICU_GROUP_SHIFT 29
35 #define ICU_MAX_IRQS 207
36 #define ICU_SATA0_ICU_ID 109
37 #define ICU_SATA1_ICU_ID 107
40 struct irq_chip irq_chip
;
42 struct irq_domain
*domain
;
47 struct mvebu_icu_irq_data
{
48 struct mvebu_icu
*icu
;
49 unsigned int icu_group
;
53 static void mvebu_icu_init(struct mvebu_icu
*icu
, struct msi_msg
*msg
)
55 if (atomic_cmpxchg(&icu
->initialized
, false, true))
58 /* Set Clear/Set ICU SPI message address in AP */
59 writel_relaxed(msg
[0].address_hi
, icu
->base
+ ICU_SETSPI_NSR_AH
);
60 writel_relaxed(msg
[0].address_lo
, icu
->base
+ ICU_SETSPI_NSR_AL
);
61 writel_relaxed(msg
[1].address_hi
, icu
->base
+ ICU_CLRSPI_NSR_AH
);
62 writel_relaxed(msg
[1].address_lo
, icu
->base
+ ICU_CLRSPI_NSR_AL
);
65 static void mvebu_icu_write_msg(struct msi_desc
*desc
, struct msi_msg
*msg
)
67 struct irq_data
*d
= irq_get_irq_data(desc
->irq
);
68 struct mvebu_icu_irq_data
*icu_irqd
= d
->chip_data
;
69 struct mvebu_icu
*icu
= icu_irqd
->icu
;
72 if (msg
->address_lo
|| msg
->address_hi
) {
73 /* One off initialization */
74 mvebu_icu_init(icu
, msg
);
75 /* Configure the ICU with irq number & type */
76 icu_int
= msg
->data
| ICU_INT_ENABLE
;
77 if (icu_irqd
->type
& IRQ_TYPE_EDGE_RISING
)
78 icu_int
|= ICU_IS_EDGE
;
79 icu_int
|= icu_irqd
->icu_group
<< ICU_GROUP_SHIFT
;
81 /* De-configure the ICU */
85 writel_relaxed(icu_int
, icu
->base
+ ICU_INT_CFG(d
->hwirq
));
88 * The SATA unit has 2 ports, and a dedicated ICU entry per
89 * port. The ahci sata driver supports only one irq interrupt
90 * per SATA unit. To solve this conflict, we configure the 2
91 * SATA wired interrupts in the south bridge into 1 GIC
92 * interrupt in the north bridge. Even if only a single port
93 * is enabled, if sata node is enabled, both interrupts are
94 * configured (regardless of which port is actually in use).
96 if (d
->hwirq
== ICU_SATA0_ICU_ID
|| d
->hwirq
== ICU_SATA1_ICU_ID
) {
97 writel_relaxed(icu_int
,
98 icu
->base
+ ICU_INT_CFG(ICU_SATA0_ICU_ID
));
99 writel_relaxed(icu_int
,
100 icu
->base
+ ICU_INT_CFG(ICU_SATA1_ICU_ID
));
105 mvebu_icu_irq_domain_translate(struct irq_domain
*d
, struct irq_fwspec
*fwspec
,
106 unsigned long *hwirq
, unsigned int *type
)
108 struct mvebu_icu
*icu
= platform_msi_get_host_data(d
);
109 unsigned int icu_group
;
111 /* Check the count of the parameters in dt */
112 if (WARN_ON(fwspec
->param_count
< 3)) {
113 dev_err(icu
->dev
, "wrong ICU parameter count %d\n",
114 fwspec
->param_count
);
118 /* Only ICU group type is handled */
119 icu_group
= fwspec
->param
[0];
120 if (icu_group
!= ICU_GRP_NSR
&& icu_group
!= ICU_GRP_SR
&&
121 icu_group
!= ICU_GRP_SEI
&& icu_group
!= ICU_GRP_REI
) {
122 dev_err(icu
->dev
, "wrong ICU group type %x\n", icu_group
);
126 *hwirq
= fwspec
->param
[1];
127 if (*hwirq
>= ICU_MAX_IRQS
) {
128 dev_err(icu
->dev
, "invalid interrupt number %ld\n", *hwirq
);
132 /* Mask the type to prevent wrong DT configuration */
133 *type
= fwspec
->param
[2] & IRQ_TYPE_SENSE_MASK
;
139 mvebu_icu_irq_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
140 unsigned int nr_irqs
, void *args
)
144 struct irq_fwspec
*fwspec
= args
;
145 struct mvebu_icu
*icu
= platform_msi_get_host_data(domain
);
146 struct mvebu_icu_irq_data
*icu_irqd
;
148 icu_irqd
= kmalloc(sizeof(*icu_irqd
), GFP_KERNEL
);
152 err
= mvebu_icu_irq_domain_translate(domain
, fwspec
, &hwirq
,
155 dev_err(icu
->dev
, "failed to translate ICU parameters\n");
159 icu_irqd
->icu_group
= fwspec
->param
[0];
162 err
= platform_msi_domain_alloc(domain
, virq
, nr_irqs
);
164 dev_err(icu
->dev
, "failed to allocate ICU interrupt in parent domain\n");
168 /* Make sure there is no interrupt left pending by the firmware */
169 err
= irq_set_irqchip_state(virq
, IRQCHIP_STATE_PENDING
, false);
173 err
= irq_domain_set_hwirq_and_chip(domain
, virq
, hwirq
,
174 &icu
->irq_chip
, icu_irqd
);
176 dev_err(icu
->dev
, "failed to set the data to IRQ domain\n");
183 platform_msi_domain_free(domain
, virq
, nr_irqs
);
190 mvebu_icu_irq_domain_free(struct irq_domain
*domain
, unsigned int virq
,
191 unsigned int nr_irqs
)
193 struct irq_data
*d
= irq_get_irq_data(virq
);
194 struct mvebu_icu_irq_data
*icu_irqd
= d
->chip_data
;
198 platform_msi_domain_free(domain
, virq
, nr_irqs
);
201 static const struct irq_domain_ops mvebu_icu_domain_ops
= {
202 .translate
= mvebu_icu_irq_domain_translate
,
203 .alloc
= mvebu_icu_irq_domain_alloc
,
204 .free
= mvebu_icu_irq_domain_free
,
207 static int mvebu_icu_probe(struct platform_device
*pdev
)
209 struct mvebu_icu
*icu
;
210 struct device_node
*node
= pdev
->dev
.of_node
;
211 struct device_node
*gicp_dn
;
212 struct resource
*res
;
215 icu
= devm_kzalloc(&pdev
->dev
, sizeof(struct mvebu_icu
),
220 icu
->dev
= &pdev
->dev
;
222 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
223 icu
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
224 if (IS_ERR(icu
->base
)) {
225 dev_err(&pdev
->dev
, "Failed to map icu base address.\n");
226 return PTR_ERR(icu
->base
);
229 icu
->irq_chip
.name
= devm_kasprintf(&pdev
->dev
, GFP_KERNEL
,
231 (unsigned int)res
->start
);
232 if (!icu
->irq_chip
.name
)
235 icu
->irq_chip
.irq_mask
= irq_chip_mask_parent
;
236 icu
->irq_chip
.irq_unmask
= irq_chip_unmask_parent
;
237 icu
->irq_chip
.irq_eoi
= irq_chip_eoi_parent
;
238 icu
->irq_chip
.irq_set_type
= irq_chip_set_type_parent
;
240 icu
->irq_chip
.irq_set_affinity
= irq_chip_set_affinity_parent
;
244 * We're probed after MSI domains have been resolved, so force
247 pdev
->dev
.msi_domain
= of_msi_get_domain(&pdev
->dev
, node
,
248 DOMAIN_BUS_PLATFORM_MSI
);
249 if (!pdev
->dev
.msi_domain
)
250 return -EPROBE_DEFER
;
252 gicp_dn
= irq_domain_get_of_node(pdev
->dev
.msi_domain
);
257 * Clean all ICU interrupts with type SPI_NSR, required to
258 * avoid unpredictable SPI assignments done by firmware.
260 for (i
= 0 ; i
< ICU_MAX_IRQS
; i
++) {
261 u32 icu_int
= readl_relaxed(icu
->base
+ ICU_INT_CFG(i
));
262 if ((icu_int
>> ICU_GROUP_SHIFT
) == ICU_GRP_NSR
)
263 writel_relaxed(0x0, icu
->base
+ ICU_INT_CFG(i
));
267 platform_msi_create_device_domain(&pdev
->dev
, ICU_MAX_IRQS
,
269 &mvebu_icu_domain_ops
, icu
);
271 dev_err(&pdev
->dev
, "Failed to create ICU domain\n");
278 static const struct of_device_id mvebu_icu_of_match
[] = {
279 { .compatible
= "marvell,cp110-icu", },
283 static struct platform_driver mvebu_icu_driver
= {
284 .probe
= mvebu_icu_probe
,
287 .of_match_table
= mvebu_icu_of_match
,
290 builtin_platform_driver(mvebu_icu_driver
);