1717#include <linux/of_irq.h>
1818#include <linux/soc/ti/ti_sci_protocol.h>
1919
20- #define TI_SCI_DEV_ID_MASK 0xffff
21- #define TI_SCI_DEV_ID_SHIFT 16
22- #define TI_SCI_IRQ_ID_MASK 0xffff
23- #define TI_SCI_IRQ_ID_SHIFT 0
24- #define HWIRQ_TO_DEVID (hwirq ) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
25- (TI_SCI_DEV_ID_MASK))
26- #define HWIRQ_TO_IRQID (hwirq ) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
27- #define TO_HWIRQ (dev , index ) ((((dev) & TI_SCI_DEV_ID_MASK) << \
28- TI_SCI_DEV_ID_SHIFT) | \
29- ((index) & TI_SCI_IRQ_ID_MASK))
30-
3120/**
3221 * struct ti_sci_intr_irq_domain - Structure representing a TISCI based
3322 * Interrupt Router IRQ domain.
3423 * @sci: Pointer to TISCI handle
35- * @dst_irq: TISCI resource pointer representing GIC irq controller.
36- * @dst_id: TISCI device ID of the GIC irq controller.
24+ * @out_irqs: TISCI resource pointer representing INTR irqs.
25+ * @dev: Struct device pointer.
26+ * @ti_sci_id: TI-SCI device identifier
3727 * @type: Specifies the trigger type supported by this Interrupt Router
3828 */
3929struct ti_sci_intr_irq_domain {
4030 const struct ti_sci_handle * sci ;
41- struct ti_sci_resource * dst_irq ;
42- u32 dst_id ;
31+ struct ti_sci_resource * out_irqs ;
32+ struct device * dev ;
33+ u32 ti_sci_id ;
4334 u32 type ;
4435};
4536
@@ -70,15 +61,44 @@ static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
7061{
7162 struct ti_sci_intr_irq_domain * intr = domain -> host_data ;
7263
73- if (fwspec -> param_count != 2 )
64+ if (fwspec -> param_count != 1 )
7465 return - EINVAL ;
7566
76- * hwirq = TO_HWIRQ ( fwspec -> param [0 ], fwspec -> param [ 1 ]) ;
67+ * hwirq = fwspec -> param [0 ];
7768 * type = intr -> type ;
7869
7970 return 0 ;
8071}
8172
73+ /**
74+ * ti_sci_intr_xlate_irq() - Translate hwirq to parent's hwirq.
75+ * @intr: IRQ domain corresponding to Interrupt Router
76+ * @irq: Hardware irq corresponding to the above irq domain
77+ *
78+ * Return parent irq number if translation is available else -ENOENT.
79+ */
80+ static int ti_sci_intr_xlate_irq (struct ti_sci_intr_irq_domain * intr , u32 irq )
81+ {
82+ struct device_node * np = dev_of_node (intr -> dev );
83+ u32 base , pbase , size , len ;
84+ const __be32 * range ;
85+
86+ range = of_get_property (np , "ti,interrupt-ranges" , & len );
87+ if (!range )
88+ return irq ;
89+
90+ for (len /= sizeof (* range ); len >= 3 ; len -= 3 ) {
91+ base = be32_to_cpu (* range ++ );
92+ pbase = be32_to_cpu (* range ++ );
93+ size = be32_to_cpu (* range ++ );
94+
95+ if (base <= irq && irq < base + size )
96+ return irq - base + pbase ;
97+ }
98+
99+ return - ENOENT ;
100+ }
101+
82102/**
83103 * ti_sci_intr_irq_domain_free() - Free the specified IRQs from the domain.
84104 * @domain: Domain to which the irqs belong
@@ -89,66 +109,76 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
89109 unsigned int virq , unsigned int nr_irqs )
90110{
91111 struct ti_sci_intr_irq_domain * intr = domain -> host_data ;
92- struct irq_data * data , * parent_data ;
93- u16 dev_id , irq_index ;
112+ struct irq_data * data ;
113+ int out_irq ;
94114
95- parent_data = irq_domain_get_irq_data (domain -> parent , virq );
96115 data = irq_domain_get_irq_data (domain , virq );
97- irq_index = HWIRQ_TO_IRQID (data -> hwirq );
98- dev_id = HWIRQ_TO_DEVID (data -> hwirq );
116+ out_irq = (uintptr_t )data -> chip_data ;
99117
100- intr -> sci -> ops .rm_irq_ops .free_irq (intr -> sci , dev_id , irq_index ,
101- intr -> dst_id , parent_data -> hwirq );
102- ti_sci_release_resource (intr -> dst_irq , parent_data -> hwirq );
118+ intr -> sci -> ops .rm_irq_ops .free_irq (intr -> sci ,
119+ intr -> ti_sci_id , data -> hwirq ,
120+ intr -> ti_sci_id , out_irq );
121+ ti_sci_release_resource (intr -> out_irqs , out_irq );
103122 irq_domain_free_irqs_parent (domain , virq , 1 );
104123 irq_domain_reset_irq_data (data );
105124}
106125
107126/**
108- * ti_sci_intr_alloc_gic_irq () - Allocate GIC specific IRQ
127+ * ti_sci_intr_alloc_parent_irq () - Allocate parent IRQ
109128 * @domain: Pointer to the interrupt router IRQ domain
110129 * @virq: Corresponding Linux virtual IRQ number
111130 * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
112131 *
113- * Returns 0 if all went well else appropriate error pointer.
132+ * Returns parent irq if all went well else appropriate error pointer.
114133 */
115- static int ti_sci_intr_alloc_gic_irq (struct irq_domain * domain ,
116- unsigned int virq , u32 hwirq )
134+ static int ti_sci_intr_alloc_parent_irq (struct irq_domain * domain ,
135+ unsigned int virq , u32 hwirq )
117136{
118137 struct ti_sci_intr_irq_domain * intr = domain -> host_data ;
138+ struct device_node * parent_node ;
119139 struct irq_fwspec fwspec ;
120- u16 dev_id , irq_index ;
121- u16 dst_irq ;
122- int err ;
123-
124- dev_id = HWIRQ_TO_DEVID (hwirq );
125- irq_index = HWIRQ_TO_IRQID (hwirq );
140+ u16 out_irq , p_hwirq ;
141+ int err = 0 ;
126142
127- dst_irq = ti_sci_get_free_resource (intr -> dst_irq );
128- if (dst_irq == TI_SCI_RESOURCE_NULL )
143+ out_irq = ti_sci_get_free_resource (intr -> out_irqs );
144+ if (out_irq == TI_SCI_RESOURCE_NULL )
129145 return - EINVAL ;
130146
131- fwspec .fwnode = domain -> parent -> fwnode ;
132- fwspec .param_count = 3 ;
133- fwspec .param [0 ] = 0 ; /* SPI */
134- fwspec .param [1 ] = dst_irq - 32 ; /* SPI offset */
135- fwspec .param [2 ] = intr -> type ;
147+ p_hwirq = ti_sci_intr_xlate_irq (intr , out_irq );
148+ if (p_hwirq < 0 )
149+ goto err_irqs ;
150+
151+ parent_node = of_irq_find_parent (dev_of_node (intr -> dev ));
152+ fwspec .fwnode = of_node_to_fwnode (parent_node );
153+
154+ if (of_device_is_compatible (parent_node , "arm,gic-v3" )) {
155+ /* Parent is GIC */
156+ fwspec .param_count = 3 ;
157+ fwspec .param [0 ] = 0 ; /* SPI */
158+ fwspec .param [1 ] = p_hwirq - 32 ; /* SPI offset */
159+ fwspec .param [2 ] = intr -> type ;
160+ } else {
161+ /* Parent is Interrupt Router */
162+ fwspec .param_count = 1 ;
163+ fwspec .param [0 ] = p_hwirq ;
164+ }
136165
137166 err = irq_domain_alloc_irqs_parent (domain , virq , 1 , & fwspec );
138167 if (err )
139168 goto err_irqs ;
140169
141- err = intr -> sci -> ops .rm_irq_ops .set_irq (intr -> sci , dev_id , irq_index ,
142- intr -> dst_id , dst_irq );
170+ err = intr -> sci -> ops .rm_irq_ops .set_irq (intr -> sci ,
171+ intr -> ti_sci_id , hwirq ,
172+ intr -> ti_sci_id , out_irq );
143173 if (err )
144174 goto err_msg ;
145175
146- return 0 ;
176+ return p_hwirq ;
147177
148178err_msg :
149179 irq_domain_free_irqs_parent (domain , virq , 1 );
150180err_irqs :
151- ti_sci_release_resource (intr -> dst_irq , dst_irq );
181+ ti_sci_release_resource (intr -> out_irqs , out_irq );
152182 return err ;
153183}
154184
@@ -168,18 +198,19 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
168198 struct irq_fwspec * fwspec = data ;
169199 unsigned long hwirq ;
170200 unsigned int flags ;
171- int err ;
201+ int err , p_hwirq ;
172202
173203 err = ti_sci_intr_irq_domain_translate (domain , fwspec , & hwirq , & flags );
174204 if (err )
175205 return err ;
176206
177- err = ti_sci_intr_alloc_gic_irq (domain , virq , hwirq );
178- if (err )
179- return err ;
207+ p_hwirq = ti_sci_intr_alloc_parent_irq (domain , virq , hwirq );
208+ if (p_hwirq < 0 )
209+ return p_hwirq ;
180210
181211 irq_domain_set_hwirq_and_chip (domain , virq , hwirq ,
182- & ti_sci_intr_irq_chip , NULL );
212+ & ti_sci_intr_irq_chip ,
213+ (void * )(uintptr_t )p_hwirq );
183214
184215 return 0 ;
185216}
@@ -214,6 +245,7 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
214245 if (!intr )
215246 return - ENOMEM ;
216247
248+ intr -> dev = dev ;
217249 ret = of_property_read_u32 (dev_of_node (dev ), "ti,intr-trigger-type" ,
218250 & intr -> type );
219251 if (ret ) {
@@ -230,19 +262,19 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
230262 return ret ;
231263 }
232264
233- ret = of_property_read_u32 (dev_of_node (dev ), "ti,sci-dst -id" ,
234- & intr -> dst_id );
265+ ret = of_property_read_u32 (dev_of_node (dev ), "ti,sci-dev -id" ,
266+ & intr -> ti_sci_id );
235267 if (ret ) {
236- dev_err (dev , "missing 'ti,sci-dst -id' property\n" );
268+ dev_err (dev , "missing 'ti,sci-dev -id' property\n" );
237269 return - EINVAL ;
238270 }
239271
240- intr -> dst_irq = devm_ti_sci_get_of_resource (intr -> sci , dev ,
241- intr -> dst_id ,
242- "ti,sci-rm-range-girq" );
243- if (IS_ERR (intr -> dst_irq )) {
272+ intr -> out_irqs = devm_ti_sci_get_resource (intr -> sci , dev ,
273+ intr -> ti_sci_id ,
274+ TI_SCI_RESASG_SUBTYPE_IR_OUTPUT );
275+ if (IS_ERR (intr -> out_irqs )) {
244276 dev_err (dev , "Destination irq resource allocation failed\n" );
245- return PTR_ERR (intr -> dst_irq );
277+ return PTR_ERR (intr -> out_irqs );
246278 }
247279
248280 domain = irq_domain_add_hierarchy (parent_domain , 0 , 0 , dev_of_node (dev ),
@@ -252,6 +284,8 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
252284 return - ENOMEM ;
253285 }
254286
287+ dev_info (dev , "Interrupt Router %d domain created\n" , intr -> ti_sci_id );
288+
255289 return 0 ;
256290}
257291
0 commit comments