1 // SPDX-License-Identifier: GPL-2.0
3 * Texas Instruments' K3 Interrupt Aggregator MSI bus
5 * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Lokesh Vutla <lokeshvutla@ti.com>
10 #include <linux/irqdomain.h>
11 #include <linux/msi.h>
12 #include <linux/of_address.h>
13 #include <linux/of_device.h>
14 #include <linux/of_irq.h>
15 #include <linux/soc/ti/ti_sci_inta_msi.h>
16 #include <linux/soc/ti/ti_sci_protocol.h>
18 static void ti_sci_inta_msi_write_msg(struct irq_data
*data
,
24 static void ti_sci_inta_msi_compose_msi_msg(struct irq_data
*data
,
30 static void ti_sci_inta_msi_update_chip_ops(struct msi_domain_info
*info
)
32 struct irq_chip
*chip
= info
->chip
;
37 chip
->irq_request_resources
= irq_chip_request_resources_parent
;
38 chip
->irq_release_resources
= irq_chip_release_resources_parent
;
39 chip
->irq_compose_msi_msg
= ti_sci_inta_msi_compose_msi_msg
;
40 chip
->irq_write_msi_msg
= ti_sci_inta_msi_write_msg
;
41 chip
->irq_set_type
= irq_chip_set_type_parent
;
42 chip
->irq_unmask
= irq_chip_unmask_parent
;
43 chip
->irq_mask
= irq_chip_mask_parent
;
44 chip
->irq_ack
= irq_chip_ack_parent
;
47 struct irq_domain
*ti_sci_inta_msi_create_irq_domain(struct fwnode_handle
*fwnode
,
48 struct msi_domain_info
*info
,
49 struct irq_domain
*parent
)
51 struct irq_domain
*domain
;
53 ti_sci_inta_msi_update_chip_ops(info
);
55 domain
= msi_create_irq_domain(fwnode
, info
, parent
);
57 irq_domain_update_bus_token(domain
, DOMAIN_BUS_TI_SCI_INTA_MSI
);
61 EXPORT_SYMBOL_GPL(ti_sci_inta_msi_create_irq_domain
);
63 static void ti_sci_inta_msi_free_descs(struct device
*dev
)
65 struct msi_desc
*desc
, *tmp
;
67 list_for_each_entry_safe(desc
, tmp
, dev_to_msi_list(dev
), list
) {
68 list_del(&desc
->list
);
73 static int ti_sci_inta_msi_alloc_descs(struct device
*dev
,
74 struct ti_sci_resource
*res
)
76 struct msi_desc
*msi_desc
;
77 int set
, i
, count
= 0;
79 for (set
= 0; set
< res
->sets
; set
++) {
80 for (i
= 0; i
< res
->desc
[set
].num
; i
++) {
81 msi_desc
= alloc_msi_entry(dev
, 1, NULL
);
83 ti_sci_inta_msi_free_descs(dev
);
87 msi_desc
->inta
.dev_index
= res
->desc
[set
].start
+ i
;
88 INIT_LIST_HEAD(&msi_desc
->list
);
89 list_add_tail(&msi_desc
->list
, dev_to_msi_list(dev
));
92 for (i
= 0; i
< res
->desc
[set
].num_sec
; i
++) {
93 msi_desc
= alloc_msi_entry(dev
, 1, NULL
);
95 ti_sci_inta_msi_free_descs(dev
);
99 msi_desc
->inta
.dev_index
= res
->desc
[set
].start_sec
+ i
;
100 INIT_LIST_HEAD(&msi_desc
->list
);
101 list_add_tail(&msi_desc
->list
, dev_to_msi_list(dev
));
109 int ti_sci_inta_msi_domain_alloc_irqs(struct device
*dev
,
110 struct ti_sci_resource
*res
)
112 struct platform_device
*pdev
= to_platform_device(dev
);
113 struct irq_domain
*msi_domain
;
116 msi_domain
= dev_get_msi_domain(dev
);
123 nvec
= ti_sci_inta_msi_alloc_descs(dev
, res
);
127 ret
= msi_domain_alloc_irqs(msi_domain
, dev
, nvec
);
129 dev_err(dev
, "Failed to allocate IRQs %d\n", ret
);
136 ti_sci_inta_msi_free_descs(&pdev
->dev
);
139 EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_alloc_irqs
);
141 void ti_sci_inta_msi_domain_free_irqs(struct device
*dev
)
143 msi_domain_free_irqs(dev
->msi_domain
, dev
);
144 ti_sci_inta_msi_free_descs(dev
);
146 EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_free_irqs
);
148 unsigned int ti_sci_inta_msi_get_virq(struct device
*dev
, u32 dev_index
)
150 struct msi_desc
*desc
;
152 for_each_msi_entry(desc
, dev
)
153 if (desc
->inta
.dev_index
== dev_index
)
158 EXPORT_SYMBOL_GPL(ti_sci_inta_msi_get_virq
);