88
99#include <linux/err.h>
1010#include <linux/io.h>
11+ #include <linux/irq.h>
1112#include <linux/irqchip.h>
1213#include <linux/irqdomain.h>
1314#include <linux/interrupt.h>
@@ -130,6 +131,37 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
130131 chained_irq_exit (irq_desc_get_chip (desc ), desc );
131132}
132133
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+
133165/**
134166 * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
135167 * @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
141173 struct ti_sci_inta_irq_domain * inta = domain -> host_data ;
142174 struct ti_sci_inta_vint_desc * vint_desc ;
143175 struct irq_fwspec parent_fwspec ;
176+ struct device_node * parent_node ;
144177 unsigned int parent_virq ;
145- u16 vint_id ;
178+ u16 vint_id , p_hwirq ;
179+ int ret ;
146180
147181 vint_id = ti_sci_get_free_resource (inta -> vint );
148182 if (vint_id == TI_SCI_RESOURCE_NULL )
149183 return ERR_PTR (- EINVAL );
150184
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+
151191 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+ }
154196
155197 vint_desc -> domain = domain ;
156198 vint_desc -> vint_id = vint_id ;
157199 INIT_LIST_HEAD (& vint_desc -> list );
158200
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+ }
163215
164216 parent_virq = irq_create_fwspec_mapping (& parent_fwspec );
165217 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+
168222 }
169223 vint_desc -> parent_virq = parent_virq ;
170224
@@ -173,6 +227,11 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
173227 ti_sci_inta_irq_handler , vint_desc );
174228
175229 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 );
176235}
177236
178237/**
@@ -555,15 +614,15 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
555614 return - EINVAL ;
556615 }
557616
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 );
560619 if (IS_ERR (inta -> vint )) {
561620 dev_err (dev , "VINT resource allocation failed\n" );
562621 return PTR_ERR (inta -> vint );
563622 }
564623
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 );
567626 if (IS_ERR (inta -> global_event )) {
568627 dev_err (dev , "Global event resource allocation failed\n" );
569628 return PTR_ERR (inta -> global_event );
@@ -594,6 +653,8 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
594653 INIT_LIST_HEAD (& inta -> vint_list );
595654 mutex_init (& inta -> vint_mutex );
596655
656+ dev_info (dev , "Interrupt Aggregator domain %d created\n" , pdev -> id );
657+
597658 return 0 ;
598659}
599660
0 commit comments