2 * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3 * Author: Marc Zyngier <marc.zyngier@arm.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <linux/device.h>
19 #include <linux/msi.h>
21 #include <linux/of_irq.h>
23 static struct irq_chip its_pmsi_irq_chip
= {
27 static int of_pmsi_get_dev_id(struct irq_domain
*domain
, struct device
*dev
,
32 /* Suck the DeviceID out of the msi-parent property */
34 struct of_phandle_args args
;
36 ret
= of_parse_phandle_with_args(dev
->of_node
,
37 "msi-parent", "#msi-cells",
39 if (args
.np
== irq_domain_get_of_node(domain
)) {
40 if (WARN_ON(args
.args_count
!= 1))
42 *dev_id
= args
.args
[0];
50 static int its_pmsi_prepare(struct irq_domain
*domain
, struct device
*dev
,
51 int nvec
, msi_alloc_info_t
*info
)
53 struct msi_domain_info
*msi_info
;
57 msi_info
= msi_get_domain_info(domain
->parent
);
59 ret
= of_pmsi_get_dev_id(domain
, dev
, &dev_id
);
63 /* ITS specific DeviceID, as the core ITS ignores dev. */
64 info
->scratchpad
[0].ul
= dev_id
;
66 return msi_info
->ops
->msi_prepare(domain
->parent
,
70 static struct msi_domain_ops its_pmsi_ops
= {
71 .msi_prepare
= its_pmsi_prepare
,
74 static struct msi_domain_info its_pmsi_domain_info
= {
75 .flags
= (MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
),
77 .chip
= &its_pmsi_irq_chip
,
80 static struct of_device_id its_device_id
[] = {
81 { .compatible
= "arm,gic-v3-its", },
85 static int __init
its_pmsi_init_one(struct fwnode_handle
*fwnode
,
88 struct irq_domain
*parent
;
90 parent
= irq_find_matching_fwnode(fwnode
, DOMAIN_BUS_NEXUS
);
91 if (!parent
|| !msi_get_domain_info(parent
)) {
92 pr_err("%s: unable to locate ITS domain\n", name
);
96 if (!platform_msi_create_irq_domain(fwnode
, &its_pmsi_domain_info
,
98 pr_err("%s: unable to create platform domain\n", name
);
102 pr_info("Platform MSI: %s domain created\n", name
);
106 static void __init
its_pmsi_of_init(void)
108 struct device_node
*np
;
110 for (np
= of_find_matching_node(NULL
, its_device_id
); np
;
111 np
= of_find_matching_node(np
, its_device_id
)) {
112 if (!of_property_read_bool(np
, "msi-controller"))
115 its_pmsi_init_one(of_node_to_fwnode(np
), np
->full_name
);
119 static int __init
its_pmsi_init(void)
124 early_initcall(its_pmsi_init
);