2 * Copyright (C) 2017 Marvell
4 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
12 #include <linux/irq.h>
13 #include <linux/irqdomain.h>
14 #include <linux/msi.h>
16 #include <linux/of_irq.h>
17 #include <linux/of_platform.h>
18 #include <linux/platform_device.h>
20 #include <dt-bindings/interrupt-controller/arm-gic.h>
22 #define GICP_SETSPI_NSR_OFFSET 0x0
23 #define GICP_CLRSPI_NSR_OFFSET 0x8
25 struct mvebu_gicp_spi_range
{
31 struct mvebu_gicp_spi_range
*spi_ranges
;
32 unsigned int spi_ranges_cnt
;
34 unsigned long *spi_bitmap
;
40 static int gicp_idx_to_spi(struct mvebu_gicp
*gicp
, int idx
)
44 for (i
= 0; i
< gicp
->spi_ranges_cnt
; i
++) {
45 struct mvebu_gicp_spi_range
*r
= &gicp
->spi_ranges
[i
];
48 return r
->start
+ idx
;
56 static void gicp_compose_msi_msg(struct irq_data
*data
, struct msi_msg
*msg
)
58 struct mvebu_gicp
*gicp
= data
->chip_data
;
59 phys_addr_t setspi
= gicp
->res
->start
+ GICP_SETSPI_NSR_OFFSET
;
60 phys_addr_t clrspi
= gicp
->res
->start
+ GICP_CLRSPI_NSR_OFFSET
;
62 msg
[0].data
= data
->hwirq
;
63 msg
[0].address_lo
= lower_32_bits(setspi
);
64 msg
[0].address_hi
= upper_32_bits(setspi
);
65 msg
[1].data
= data
->hwirq
;
66 msg
[1].address_lo
= lower_32_bits(clrspi
);
67 msg
[1].address_hi
= upper_32_bits(clrspi
);
70 static struct irq_chip gicp_irq_chip
= {
72 .irq_mask
= irq_chip_mask_parent
,
73 .irq_unmask
= irq_chip_unmask_parent
,
74 .irq_eoi
= irq_chip_eoi_parent
,
75 .irq_set_affinity
= irq_chip_set_affinity_parent
,
76 .irq_set_type
= irq_chip_set_type_parent
,
77 .irq_compose_msi_msg
= gicp_compose_msi_msg
,
80 static int gicp_irq_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
81 unsigned int nr_irqs
, void *args
)
83 struct mvebu_gicp
*gicp
= domain
->host_data
;
84 struct irq_fwspec fwspec
;
88 spin_lock(&gicp
->spi_lock
);
89 hwirq
= find_first_zero_bit(gicp
->spi_bitmap
, gicp
->spi_cnt
);
90 if (hwirq
== gicp
->spi_cnt
) {
91 spin_unlock(&gicp
->spi_lock
);
94 __set_bit(hwirq
, gicp
->spi_bitmap
);
95 spin_unlock(&gicp
->spi_lock
);
97 fwspec
.fwnode
= domain
->parent
->fwnode
;
98 fwspec
.param_count
= 3;
99 fwspec
.param
[0] = GIC_SPI
;
100 fwspec
.param
[1] = gicp_idx_to_spi(gicp
, hwirq
) - 32;
102 * Assume edge rising for now, it will be properly set when
103 * ->set_type() is called
105 fwspec
.param
[2] = IRQ_TYPE_EDGE_RISING
;
107 ret
= irq_domain_alloc_irqs_parent(domain
, virq
, 1, &fwspec
);
109 dev_err(gicp
->dev
, "Cannot allocate parent IRQ\n");
113 ret
= irq_domain_set_hwirq_and_chip(domain
, virq
, hwirq
,
114 &gicp_irq_chip
, gicp
);
116 goto free_irqs_parent
;
121 irq_domain_free_irqs_parent(domain
, virq
, nr_irqs
);
123 spin_lock(&gicp
->spi_lock
);
124 __clear_bit(hwirq
, gicp
->spi_bitmap
);
125 spin_unlock(&gicp
->spi_lock
);
129 static void gicp_irq_domain_free(struct irq_domain
*domain
,
130 unsigned int virq
, unsigned int nr_irqs
)
132 struct mvebu_gicp
*gicp
= domain
->host_data
;
133 struct irq_data
*d
= irq_domain_get_irq_data(domain
, virq
);
135 if (d
->hwirq
>= gicp
->spi_cnt
) {
136 dev_err(gicp
->dev
, "Invalid hwirq %lu\n", d
->hwirq
);
140 irq_domain_free_irqs_parent(domain
, virq
, nr_irqs
);
142 spin_lock(&gicp
->spi_lock
);
143 __clear_bit(d
->hwirq
, gicp
->spi_bitmap
);
144 spin_unlock(&gicp
->spi_lock
);
147 static const struct irq_domain_ops gicp_domain_ops
= {
148 .alloc
= gicp_irq_domain_alloc
,
149 .free
= gicp_irq_domain_free
,
152 static struct irq_chip gicp_msi_irq_chip
= {
154 .irq_set_type
= irq_chip_set_type_parent
,
155 .flags
= IRQCHIP_SUPPORTS_LEVEL_MSI
,
158 static struct msi_domain_ops gicp_msi_ops
= {
161 static struct msi_domain_info gicp_msi_domain_info
= {
162 .flags
= (MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
|
163 MSI_FLAG_LEVEL_CAPABLE
),
164 .ops
= &gicp_msi_ops
,
165 .chip
= &gicp_msi_irq_chip
,
168 static int mvebu_gicp_probe(struct platform_device
*pdev
)
170 struct mvebu_gicp
*gicp
;
171 struct irq_domain
*inner_domain
, *plat_domain
, *parent_domain
;
172 struct device_node
*node
= pdev
->dev
.of_node
;
173 struct device_node
*irq_parent_dn
;
176 gicp
= devm_kzalloc(&pdev
->dev
, sizeof(*gicp
), GFP_KERNEL
);
180 gicp
->dev
= &pdev
->dev
;
181 spin_lock_init(&gicp
->spi_lock
);
183 gicp
->res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
187 ret
= of_property_count_u32_elems(node
, "marvell,spi-ranges");
191 gicp
->spi_ranges_cnt
= ret
/ 2;
194 devm_kcalloc(&pdev
->dev
,
195 gicp
->spi_ranges_cnt
,
196 sizeof(struct mvebu_gicp_spi_range
),
198 if (!gicp
->spi_ranges
)
201 for (i
= 0; i
< gicp
->spi_ranges_cnt
; i
++) {
202 of_property_read_u32_index(node
, "marvell,spi-ranges",
204 &gicp
->spi_ranges
[i
].start
);
206 of_property_read_u32_index(node
, "marvell,spi-ranges",
208 &gicp
->spi_ranges
[i
].count
);
210 gicp
->spi_cnt
+= gicp
->spi_ranges
[i
].count
;
213 gicp
->spi_bitmap
= devm_kcalloc(&pdev
->dev
,
214 BITS_TO_LONGS(gicp
->spi_cnt
), sizeof(long),
216 if (!gicp
->spi_bitmap
)
219 irq_parent_dn
= of_irq_find_parent(node
);
220 if (!irq_parent_dn
) {
221 dev_err(&pdev
->dev
, "failed to find parent IRQ node\n");
225 parent_domain
= irq_find_host(irq_parent_dn
);
226 if (!parent_domain
) {
227 dev_err(&pdev
->dev
, "failed to find parent IRQ domain\n");
231 inner_domain
= irq_domain_create_hierarchy(parent_domain
, 0,
233 of_node_to_fwnode(node
),
234 &gicp_domain_ops
, gicp
);
239 plat_domain
= platform_msi_create_irq_domain(of_node_to_fwnode(node
),
240 &gicp_msi_domain_info
,
243 irq_domain_remove(inner_domain
);
247 platform_set_drvdata(pdev
, gicp
);
252 static const struct of_device_id mvebu_gicp_of_match
[] = {
253 { .compatible
= "marvell,ap806-gicp", },
257 static struct platform_driver mvebu_gicp_driver
= {
258 .probe
= mvebu_gicp_probe
,
260 .name
= "mvebu-gicp",
261 .of_match_table
= mvebu_gicp_of_match
,
264 builtin_platform_driver(mvebu_gicp_driver
);