1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2018-2020 Linaro Ltd.
9 * The IPA has an interrupt line distinct from the interrupt used by the GSI
10 * code. Whereas GSI interrupts are generally related to channel events (like
11 * transfer completions), IPA interrupts are related to other events related
12 * to the IPA. Some of the IPA interrupts come from a microcontroller
13 * embedded in the IPA. Each IPA interrupt type can be both masked and
14 * acknowledged independent of the others.
16 * Two of the IPA interrupts are initiated by the microcontroller. A third
17 * can be generated to signal the need for a wakeup/resume when an IPA
18 * endpoint has been suspended. There are other IPA events, but at this
19 * time only these three are supported.
22 #include <linux/types.h>
23 #include <linux/interrupt.h>
26 #include "ipa_clock.h"
28 #include "ipa_endpoint.h"
29 #include "ipa_interrupt.h"
32 * struct ipa_interrupt - IPA interrupt information
34 * @irq: Linux IRQ number used for IPA interrupts
35 * @enabled: Mask indicating which interrupts are enabled
36 * @handler: Array of handlers indexed by IPA interrupt ID
38 struct ipa_interrupt
{
42 ipa_irq_handler_t handler
[IPA_IRQ_COUNT
];
45 /* Returns true if the interrupt type is associated with the microcontroller */
46 static bool ipa_interrupt_uc(struct ipa_interrupt
*interrupt
, u32 irq_id
)
48 return irq_id
== IPA_IRQ_UC_0
|| irq_id
== IPA_IRQ_UC_1
;
51 /* Process a particular interrupt type that has been received */
52 static void ipa_interrupt_process(struct ipa_interrupt
*interrupt
, u32 irq_id
)
54 bool uc_irq
= ipa_interrupt_uc(interrupt
, irq_id
);
55 struct ipa
*ipa
= interrupt
->ipa
;
56 u32 mask
= BIT(irq_id
);
58 /* For microcontroller interrupts, clear the interrupt right away,
59 * "to avoid clearing unhandled interrupts."
62 iowrite32(mask
, ipa
->reg_virt
+ IPA_REG_IRQ_CLR_OFFSET
);
64 if (irq_id
< IPA_IRQ_COUNT
&& interrupt
->handler
[irq_id
])
65 interrupt
->handler
[irq_id
](interrupt
->ipa
, irq_id
);
67 /* Clearing the SUSPEND_TX interrupt also clears the register
68 * that tells us which suspended endpoint(s) caused the interrupt,
69 * so defer clearing until after the handler has been called.
72 iowrite32(mask
, ipa
->reg_virt
+ IPA_REG_IRQ_CLR_OFFSET
);
75 /* Process all IPA interrupt types that have been signaled */
76 static void ipa_interrupt_process_all(struct ipa_interrupt
*interrupt
)
78 struct ipa
*ipa
= interrupt
->ipa
;
79 u32 enabled
= interrupt
->enabled
;
82 /* The status register indicates which conditions are present,
83 * including conditions whose interrupt is not enabled. Handle
84 * only the enabled ones.
86 mask
= ioread32(ipa
->reg_virt
+ IPA_REG_IRQ_STTS_OFFSET
);
87 while ((mask
&= enabled
)) {
89 u32 irq_id
= __ffs(mask
);
93 ipa_interrupt_process(interrupt
, irq_id
);
95 mask
= ioread32(ipa
->reg_virt
+ IPA_REG_IRQ_STTS_OFFSET
);
99 /* Threaded part of the IPA IRQ handler */
100 static irqreturn_t
ipa_isr_thread(int irq
, void *dev_id
)
102 struct ipa_interrupt
*interrupt
= dev_id
;
104 ipa_clock_get(interrupt
->ipa
);
106 ipa_interrupt_process_all(interrupt
);
108 ipa_clock_put(interrupt
->ipa
);
113 /* Hard part (i.e., "real" IRQ handler) of the IRQ handler */
114 static irqreturn_t
ipa_isr(int irq
, void *dev_id
)
116 struct ipa_interrupt
*interrupt
= dev_id
;
117 struct ipa
*ipa
= interrupt
->ipa
;
120 mask
= ioread32(ipa
->reg_virt
+ IPA_REG_IRQ_STTS_OFFSET
);
121 if (mask
& interrupt
->enabled
)
122 return IRQ_WAKE_THREAD
;
124 /* Nothing in the mask was supposed to cause an interrupt */
125 iowrite32(mask
, ipa
->reg_virt
+ IPA_REG_IRQ_CLR_OFFSET
);
127 dev_err(&ipa
->pdev
->dev
, "%s: unexpected interrupt, mask 0x%08x\n",
133 /* Common function used to enable/disable TX_SUSPEND for an endpoint */
134 static void ipa_interrupt_suspend_control(struct ipa_interrupt
*interrupt
,
135 u32 endpoint_id
, bool enable
)
137 struct ipa
*ipa
= interrupt
->ipa
;
138 u32 mask
= BIT(endpoint_id
);
141 /* assert(mask & ipa->available); */
142 val
= ioread32(ipa
->reg_virt
+ IPA_REG_SUSPEND_IRQ_EN_OFFSET
);
147 iowrite32(val
, ipa
->reg_virt
+ IPA_REG_SUSPEND_IRQ_EN_OFFSET
);
150 /* Enable TX_SUSPEND for an endpoint */
152 ipa_interrupt_suspend_enable(struct ipa_interrupt
*interrupt
, u32 endpoint_id
)
154 ipa_interrupt_suspend_control(interrupt
, endpoint_id
, true);
157 /* Disable TX_SUSPEND for an endpoint */
159 ipa_interrupt_suspend_disable(struct ipa_interrupt
*interrupt
, u32 endpoint_id
)
161 ipa_interrupt_suspend_control(interrupt
, endpoint_id
, false);
164 /* Clear the suspend interrupt for all endpoints that signaled it */
165 void ipa_interrupt_suspend_clear_all(struct ipa_interrupt
*interrupt
)
167 struct ipa
*ipa
= interrupt
->ipa
;
170 val
= ioread32(ipa
->reg_virt
+ IPA_REG_IRQ_SUSPEND_INFO_OFFSET
);
171 iowrite32(val
, ipa
->reg_virt
+ IPA_REG_SUSPEND_IRQ_CLR_OFFSET
);
174 /* Simulate arrival of an IPA TX_SUSPEND interrupt */
175 void ipa_interrupt_simulate_suspend(struct ipa_interrupt
*interrupt
)
177 ipa_interrupt_process(interrupt
, IPA_IRQ_TX_SUSPEND
);
180 /* Add a handler for an IPA interrupt */
181 void ipa_interrupt_add(struct ipa_interrupt
*interrupt
,
182 enum ipa_irq_id ipa_irq
, ipa_irq_handler_t handler
)
184 struct ipa
*ipa
= interrupt
->ipa
;
186 /* assert(ipa_irq < IPA_IRQ_COUNT); */
187 interrupt
->handler
[ipa_irq
] = handler
;
189 /* Update the IPA interrupt mask to enable it */
190 interrupt
->enabled
|= BIT(ipa_irq
);
191 iowrite32(interrupt
->enabled
, ipa
->reg_virt
+ IPA_REG_IRQ_EN_OFFSET
);
194 /* Remove the handler for an IPA interrupt type */
196 ipa_interrupt_remove(struct ipa_interrupt
*interrupt
, enum ipa_irq_id ipa_irq
)
198 struct ipa
*ipa
= interrupt
->ipa
;
200 /* assert(ipa_irq < IPA_IRQ_COUNT); */
201 /* Update the IPA interrupt mask to disable it */
202 interrupt
->enabled
&= ~BIT(ipa_irq
);
203 iowrite32(interrupt
->enabled
, ipa
->reg_virt
+ IPA_REG_IRQ_EN_OFFSET
);
205 interrupt
->handler
[ipa_irq
] = NULL
;
208 /* Set up the IPA interrupt framework */
209 struct ipa_interrupt
*ipa_interrupt_setup(struct ipa
*ipa
)
211 struct device
*dev
= &ipa
->pdev
->dev
;
212 struct ipa_interrupt
*interrupt
;
216 ret
= platform_get_irq_byname(ipa
->pdev
, "ipa");
218 dev_err(dev
, "DT error %d getting \"ipa\" IRQ property\n",
220 return ERR_PTR(ret
? : -EINVAL
);
224 interrupt
= kzalloc(sizeof(*interrupt
), GFP_KERNEL
);
226 return ERR_PTR(-ENOMEM
);
227 interrupt
->ipa
= ipa
;
228 interrupt
->irq
= irq
;
230 /* Start with all IPA interrupts disabled */
231 iowrite32(0, ipa
->reg_virt
+ IPA_REG_IRQ_EN_OFFSET
);
233 ret
= request_threaded_irq(irq
, ipa_isr
, ipa_isr_thread
, IRQF_ONESHOT
,
236 dev_err(dev
, "error %d requesting \"ipa\" IRQ\n", ret
);
248 /* Tear down the IPA interrupt framework */
249 void ipa_interrupt_teardown(struct ipa_interrupt
*interrupt
)
251 free_irq(interrupt
->irq
, interrupt
);