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 #include "irq-mvebu-gicp.h"
24 #define GICP_SETSPI_NSR_OFFSET 0x0
25 #define GICP_CLRSPI_NSR_OFFSET 0x8
27 struct mvebu_gicp_spi_range
{
33 struct mvebu_gicp_spi_range
*spi_ranges
;
34 unsigned int spi_ranges_cnt
;
36 unsigned long *spi_bitmap
;
42 static int gicp_idx_to_spi(struct mvebu_gicp
*gicp
, int idx
)
46 for (i
= 0; i
< gicp
->spi_ranges_cnt
; i
++) {
47 struct mvebu_gicp_spi_range
*r
= &gicp
->spi_ranges
[i
];
50 return r
->start
+ idx
;
58 int mvebu_gicp_get_doorbells(struct device_node
*dn
, phys_addr_t
*setspi
,
61 struct platform_device
*pdev
;
62 struct mvebu_gicp
*gicp
;
64 pdev
= of_find_device_by_node(dn
);
68 gicp
= platform_get_drvdata(pdev
);
72 *setspi
= gicp
->res
->start
+ GICP_SETSPI_NSR_OFFSET
;
73 *clrspi
= gicp
->res
->start
+ GICP_CLRSPI_NSR_OFFSET
;
78 static void gicp_compose_msi_msg(struct irq_data
*data
, struct msi_msg
*msg
)
80 struct mvebu_gicp
*gicp
= data
->chip_data
;
81 phys_addr_t setspi
= gicp
->res
->start
+ GICP_SETSPI_NSR_OFFSET
;
83 msg
->data
= data
->hwirq
;
84 msg
->address_lo
= lower_32_bits(setspi
);
85 msg
->address_hi
= upper_32_bits(setspi
);
88 static struct irq_chip gicp_irq_chip
= {
90 .irq_mask
= irq_chip_mask_parent
,
91 .irq_unmask
= irq_chip_unmask_parent
,
92 .irq_eoi
= irq_chip_eoi_parent
,
93 .irq_set_affinity
= irq_chip_set_affinity_parent
,
94 .irq_set_type
= irq_chip_set_type_parent
,
95 .irq_compose_msi_msg
= gicp_compose_msi_msg
,
98 static int gicp_irq_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
99 unsigned int nr_irqs
, void *args
)
101 struct mvebu_gicp
*gicp
= domain
->host_data
;
102 struct irq_fwspec fwspec
;
106 spin_lock(&gicp
->spi_lock
);
107 hwirq
= find_first_zero_bit(gicp
->spi_bitmap
, gicp
->spi_cnt
);
108 if (hwirq
== gicp
->spi_cnt
) {
109 spin_unlock(&gicp
->spi_lock
);
112 __set_bit(hwirq
, gicp
->spi_bitmap
);
113 spin_unlock(&gicp
->spi_lock
);
115 fwspec
.fwnode
= domain
->parent
->fwnode
;
116 fwspec
.param_count
= 3;
117 fwspec
.param
[0] = GIC_SPI
;
118 fwspec
.param
[1] = gicp_idx_to_spi(gicp
, hwirq
) - 32;
120 * Assume edge rising for now, it will be properly set when
121 * ->set_type() is called
123 fwspec
.param
[2] = IRQ_TYPE_EDGE_RISING
;
125 ret
= irq_domain_alloc_irqs_parent(domain
, virq
, 1, &fwspec
);
127 dev_err(gicp
->dev
, "Cannot allocate parent IRQ\n");
131 ret
= irq_domain_set_hwirq_and_chip(domain
, virq
, hwirq
,
132 &gicp_irq_chip
, gicp
);
134 goto free_irqs_parent
;
139 irq_domain_free_irqs_parent(domain
, virq
, nr_irqs
);
141 spin_lock(&gicp
->spi_lock
);
142 __clear_bit(hwirq
, gicp
->spi_bitmap
);
143 spin_unlock(&gicp
->spi_lock
);
147 static void gicp_irq_domain_free(struct irq_domain
*domain
,
148 unsigned int virq
, unsigned int nr_irqs
)
150 struct mvebu_gicp
*gicp
= domain
->host_data
;
151 struct irq_data
*d
= irq_domain_get_irq_data(domain
, virq
);
153 if (d
->hwirq
>= gicp
->spi_cnt
) {
154 dev_err(gicp
->dev
, "Invalid hwirq %lu\n", d
->hwirq
);
158 irq_domain_free_irqs_parent(domain
, virq
, nr_irqs
);
160 spin_lock(&gicp
->spi_lock
);
161 __clear_bit(d
->hwirq
, gicp
->spi_bitmap
);
162 spin_unlock(&gicp
->spi_lock
);
165 static const struct irq_domain_ops gicp_domain_ops
= {
166 .alloc
= gicp_irq_domain_alloc
,
167 .free
= gicp_irq_domain_free
,
170 static struct irq_chip gicp_msi_irq_chip
= {
172 .irq_set_type
= irq_chip_set_type_parent
,
175 static struct msi_domain_ops gicp_msi_ops
= {
178 static struct msi_domain_info gicp_msi_domain_info
= {
179 .flags
= (MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
),
180 .ops
= &gicp_msi_ops
,
181 .chip
= &gicp_msi_irq_chip
,
184 static int mvebu_gicp_probe(struct platform_device
*pdev
)
186 struct mvebu_gicp
*gicp
;
187 struct irq_domain
*inner_domain
, *plat_domain
, *parent_domain
;
188 struct device_node
*node
= pdev
->dev
.of_node
;
189 struct device_node
*irq_parent_dn
;
192 gicp
= devm_kzalloc(&pdev
->dev
, sizeof(*gicp
), GFP_KERNEL
);
196 gicp
->dev
= &pdev
->dev
;
198 gicp
->res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
202 ret
= of_property_count_u32_elems(node
, "marvell,spi-ranges");
206 gicp
->spi_ranges_cnt
= ret
/ 2;
209 devm_kzalloc(&pdev
->dev
,
210 gicp
->spi_ranges_cnt
*
211 sizeof(struct mvebu_gicp_spi_range
),
213 if (!gicp
->spi_ranges
)
216 for (i
= 0; i
< gicp
->spi_ranges_cnt
; i
++) {
217 of_property_read_u32_index(node
, "marvell,spi-ranges",
219 &gicp
->spi_ranges
[i
].start
);
221 of_property_read_u32_index(node
, "marvell,spi-ranges",
223 &gicp
->spi_ranges
[i
].count
);
225 gicp
->spi_cnt
+= gicp
->spi_ranges
[i
].count
;
228 gicp
->spi_bitmap
= devm_kzalloc(&pdev
->dev
,
229 BITS_TO_LONGS(gicp
->spi_cnt
) * sizeof(long),
231 if (!gicp
->spi_bitmap
)
234 irq_parent_dn
= of_irq_find_parent(node
);
235 if (!irq_parent_dn
) {
236 dev_err(&pdev
->dev
, "failed to find parent IRQ node\n");
240 parent_domain
= irq_find_host(irq_parent_dn
);
241 if (!parent_domain
) {
242 dev_err(&pdev
->dev
, "failed to find parent IRQ domain\n");
246 inner_domain
= irq_domain_create_hierarchy(parent_domain
, 0,
248 of_node_to_fwnode(node
),
249 &gicp_domain_ops
, gicp
);
254 plat_domain
= platform_msi_create_irq_domain(of_node_to_fwnode(node
),
255 &gicp_msi_domain_info
,
258 irq_domain_remove(inner_domain
);
262 platform_set_drvdata(pdev
, gicp
);
267 static const struct of_device_id mvebu_gicp_of_match
[] = {
268 { .compatible
= "marvell,ap806-gicp", },
272 static struct platform_driver mvebu_gicp_driver
= {
273 .probe
= mvebu_gicp_probe
,
275 .name
= "mvebu-gicp",
276 .of_match_table
= mvebu_gicp_of_match
,
279 builtin_platform_driver(mvebu_gicp_driver
);