1 // SPDX-License-Identifier: GPL-2.0
3 * Freescale Management Complex (MC) bus driver MSI support
5 * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
6 * Author: German Rivera <German.Rivera@freescale.com>
10 #include <linux/of_device.h>
11 #include <linux/of_address.h>
12 #include <linux/irq.h>
13 #include <linux/msi.h>
15 #include <linux/of_irq.h>
16 #include <linux/fsl/mc.h>
18 static struct irq_chip its_msi_irq_chip
= {
20 .irq_mask
= irq_chip_mask_parent
,
21 .irq_unmask
= irq_chip_unmask_parent
,
22 .irq_eoi
= irq_chip_eoi_parent
,
23 .irq_set_affinity
= msi_domain_set_affinity
26 static int its_fsl_mc_msi_prepare(struct irq_domain
*msi_domain
,
28 int nvec
, msi_alloc_info_t
*info
)
30 struct fsl_mc_device
*mc_bus_dev
;
31 struct msi_domain_info
*msi_info
;
33 if (!dev_is_fsl_mc(dev
))
36 mc_bus_dev
= to_fsl_mc_device(dev
);
37 if (!(mc_bus_dev
->flags
& FSL_MC_IS_DPRC
))
41 * Set the device Id to be passed to the GIC-ITS:
43 * NOTE: This device id corresponds to the IOMMU stream ID
44 * associated with the DPRC object (ICID).
46 info
->scratchpad
[0].ul
= mc_bus_dev
->icid
;
47 msi_info
= msi_get_domain_info(msi_domain
->parent
);
49 /* Allocate at least 32 MSIs, and always as a power of 2 */
50 nvec
= max_t(int, 32, roundup_pow_of_two(nvec
));
51 return msi_info
->ops
->msi_prepare(msi_domain
->parent
, dev
, nvec
, info
);
54 static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init
= {
55 .msi_prepare
= its_fsl_mc_msi_prepare
,
58 static struct msi_domain_info its_fsl_mc_msi_domain_info
= {
59 .flags
= (MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
),
60 .ops
= &its_fsl_mc_msi_ops
,
61 .chip
= &its_msi_irq_chip
,
64 static const struct of_device_id its_device_id
[] = {
65 { .compatible
= "arm,gic-v3-its", },
69 static int __init
its_fsl_mc_msi_init(void)
71 struct device_node
*np
;
72 struct irq_domain
*parent
;
73 struct irq_domain
*mc_msi_domain
;
75 for (np
= of_find_matching_node(NULL
, its_device_id
); np
;
76 np
= of_find_matching_node(np
, its_device_id
)) {
77 if (!of_device_is_available(np
))
79 if (!of_property_read_bool(np
, "msi-controller"))
82 parent
= irq_find_matching_host(np
, DOMAIN_BUS_NEXUS
);
83 if (!parent
|| !msi_get_domain_info(parent
)) {
84 pr_err("%pOF: unable to locate ITS domain\n", np
);
88 mc_msi_domain
= fsl_mc_msi_create_irq_domain(
89 of_node_to_fwnode(np
),
90 &its_fsl_mc_msi_domain_info
,
93 pr_err("%pOF: unable to create fsl-mc domain\n", np
);
97 pr_info("fsl-mc MSI: %pOF domain created\n", np
);
103 early_initcall(its_fsl_mc_msi_init
);