8
8
9
9
#include <linux/err.h>
10
10
#include <linux/io.h>
11
+ #include <linux/irq.h>
11
12
#include <linux/irqchip.h>
12
13
#include <linux/irqdomain.h>
13
14
#include <linux/interrupt.h>
@@ -130,6 +131,37 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
130
131
chained_irq_exit (irq_desc_get_chip (desc ), desc );
131
132
}
132
133
134
+ /**
135
+ * ti_sci_inta_xlate_irq() - Translate hwirq to parent's hwirq.
136
+ * @inta: IRQ domain corresponding to Interrupt Aggregator
137
+ * @irq: Hardware irq corresponding to the above irq domain
138
+ *
139
+ * Return parent irq number if translation is available else -ENOENT.
140
+ */
141
+ static int ti_sci_inta_xlate_irq (struct ti_sci_inta_irq_domain * inta ,
142
+ u16 vint_id )
143
+ {
144
+ struct device_node * np = dev_of_node (& inta -> pdev -> dev );
145
+ u32 base , parent_base , size ;
146
+ const __be32 * range ;
147
+ int len ;
148
+
149
+ range = of_get_property (np , "ti,interrupt-ranges" , & len );
150
+ if (!range )
151
+ return vint_id ;
152
+
153
+ for (len /= sizeof (* range ); len >= 3 ; len -= 3 ) {
154
+ base = be32_to_cpu (* range ++ );
155
+ parent_base = be32_to_cpu (* range ++ );
156
+ size = be32_to_cpu (* range ++ );
157
+
158
+ if (base <= vint_id && vint_id < base + size )
159
+ return vint_id - base + parent_base ;
160
+ }
161
+
162
+ return - ENOENT ;
163
+ }
164
+
133
165
/**
134
166
* ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
135
167
* @domain: IRQ domain corresponding to Interrupt Aggregator
@@ -141,30 +173,52 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
141
173
struct ti_sci_inta_irq_domain * inta = domain -> host_data ;
142
174
struct ti_sci_inta_vint_desc * vint_desc ;
143
175
struct irq_fwspec parent_fwspec ;
176
+ struct device_node * parent_node ;
144
177
unsigned int parent_virq ;
145
- u16 vint_id ;
178
+ u16 vint_id , p_hwirq ;
179
+ int ret ;
146
180
147
181
vint_id = ti_sci_get_free_resource (inta -> vint );
148
182
if (vint_id == TI_SCI_RESOURCE_NULL )
149
183
return ERR_PTR (- EINVAL );
150
184
185
+ p_hwirq = ti_sci_inta_xlate_irq (inta , vint_id );
186
+ if (p_hwirq < 0 ) {
187
+ ret = p_hwirq ;
188
+ goto free_vint ;
189
+ }
190
+
151
191
vint_desc = kzalloc (sizeof (* vint_desc ), GFP_KERNEL );
152
- if (!vint_desc )
153
- return ERR_PTR (- ENOMEM );
192
+ if (!vint_desc ) {
193
+ ret = - ENOMEM ;
194
+ goto free_vint ;
195
+ }
154
196
155
197
vint_desc -> domain = domain ;
156
198
vint_desc -> vint_id = vint_id ;
157
199
INIT_LIST_HEAD (& vint_desc -> list );
158
200
159
- parent_fwspec .fwnode = of_node_to_fwnode (of_irq_find_parent (dev_of_node (& inta -> pdev -> dev )));
160
- parent_fwspec .param_count = 2 ;
161
- parent_fwspec .param [0 ] = inta -> ti_sci_id ;
162
- parent_fwspec .param [1 ] = vint_desc -> vint_id ;
201
+ parent_node = of_irq_find_parent (dev_of_node (& inta -> pdev -> dev ));
202
+ parent_fwspec .fwnode = of_node_to_fwnode (parent_node );
203
+
204
+ if (of_device_is_compatible (parent_node , "arm,gic-v3" )) {
205
+ /* Parent is GIC */
206
+ parent_fwspec .param_count = 3 ;
207
+ parent_fwspec .param [0 ] = 0 ;
208
+ parent_fwspec .param [1 ] = p_hwirq - 32 ;
209
+ parent_fwspec .param [2 ] = IRQ_TYPE_LEVEL_HIGH ;
210
+ } else {
211
+ /* Parent is Interrupt Router */
212
+ parent_fwspec .param_count = 1 ;
213
+ parent_fwspec .param [0 ] = p_hwirq ;
214
+ }
163
215
164
216
parent_virq = irq_create_fwspec_mapping (& parent_fwspec );
165
217
if (parent_virq == 0 ) {
166
- kfree (vint_desc );
167
- return ERR_PTR (- EINVAL );
218
+ dev_err (& inta -> pdev -> dev , "Parent IRQ allocation failed\n" );
219
+ ret = - EINVAL ;
220
+ goto free_vint_desc ;
221
+
168
222
}
169
223
vint_desc -> parent_virq = parent_virq ;
170
224
@@ -173,6 +227,11 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
173
227
ti_sci_inta_irq_handler , vint_desc );
174
228
175
229
return vint_desc ;
230
+ free_vint_desc :
231
+ kfree (vint_desc );
232
+ free_vint :
233
+ ti_sci_release_resource (inta -> vint , vint_id );
234
+ return ERR_PTR (ret );
176
235
}
177
236
178
237
/**
@@ -555,15 +614,15 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
555
614
return - EINVAL ;
556
615
}
557
616
558
- inta -> vint = devm_ti_sci_get_of_resource (inta -> sci , dev , inta -> ti_sci_id ,
559
- "ti,sci-rm-range-vint" );
617
+ inta -> vint = devm_ti_sci_get_resource (inta -> sci , dev , inta -> ti_sci_id ,
618
+ TI_SCI_RESASG_SUBTYPE_IA_VINT );
560
619
if (IS_ERR (inta -> vint )) {
561
620
dev_err (dev , "VINT resource allocation failed\n" );
562
621
return PTR_ERR (inta -> vint );
563
622
}
564
623
565
- inta -> global_event = devm_ti_sci_get_of_resource (inta -> sci , dev , inta -> ti_sci_id ,
566
- "ti,sci-rm-range-global-event" );
624
+ inta -> global_event = devm_ti_sci_get_resource (inta -> sci , dev , inta -> ti_sci_id ,
625
+ TI_SCI_RESASG_SUBTYPE_GLOBAL_EVENT_SEVT );
567
626
if (IS_ERR (inta -> global_event )) {
568
627
dev_err (dev , "Global event resource allocation failed\n" );
569
628
return PTR_ERR (inta -> global_event );
@@ -594,6 +653,8 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
594
653
INIT_LIST_HEAD (& inta -> vint_list );
595
654
mutex_init (& inta -> vint_mutex );
596
655
656
+ dev_info (dev , "Interrupt Aggregator domain %d created\n" , pdev -> id );
657
+
597
658
return 0 ;
598
659
}
599
660
0 commit comments