Lines Matching +full:ipa +full:- +full:reg
1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2018-2024 Linaro Ltd.
7 /* DOC: IPA Interrupts
9 * The IPA has an interrupt line distinct from the interrupt used by the GSI
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
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
28 #include "ipa.h"
36 * struct ipa_interrupt - IPA interrupt information
37 * @ipa: IPA pointer
38 * @irq: Linux IRQ number used for IPA interrupts
43 struct ipa *ipa; member
52 struct ipa *ipa = interrupt->ipa; in ipa_interrupt_suspend_clear_all() local
56 unit_count = DIV_ROUND_UP(ipa->endpoint_count, 32); in ipa_interrupt_suspend_clear_all()
58 const struct reg *reg; in ipa_interrupt_suspend_clear_all() local
61 reg = ipa_reg(ipa, IRQ_SUSPEND_INFO); in ipa_interrupt_suspend_clear_all()
62 val = ioread32(ipa->reg_virt + reg_n_offset(reg, unit)); in ipa_interrupt_suspend_clear_all()
64 /* SUSPEND interrupt status isn't cleared on IPA version 3.0 */ in ipa_interrupt_suspend_clear_all()
65 if (!val || ipa->version == IPA_VERSION_3_0) in ipa_interrupt_suspend_clear_all()
68 reg = ipa_reg(ipa, IRQ_SUSPEND_CLR); in ipa_interrupt_suspend_clear_all()
69 iowrite32(val, ipa->reg_virt + reg_n_offset(reg, unit)); in ipa_interrupt_suspend_clear_all()
76 struct ipa *ipa = interrupt->ipa; in ipa_interrupt_process() local
77 const struct reg *reg; in ipa_interrupt_process() local
81 reg = ipa_reg(ipa, IPA_IRQ_CLR); in ipa_interrupt_process()
82 offset = reg_offset(reg); in ipa_interrupt_process()
90 iowrite32(mask, ipa->reg_virt + offset); in ipa_interrupt_process()
91 ipa_uc_interrupt_handler(ipa, irq_id); in ipa_interrupt_process()
104 iowrite32(mask, ipa->reg_virt + offset); in ipa_interrupt_process()
109 /* IPA IRQ handler is threaded */
113 struct ipa *ipa = interrupt->ipa; in ipa_isr_thread() local
114 u32 enabled = interrupt->enabled; in ipa_isr_thread()
115 struct device *dev = ipa->dev; in ipa_isr_thread()
116 const struct reg *reg; in ipa_isr_thread() local
130 reg = ipa_reg(ipa, IPA_IRQ_STTS); in ipa_isr_thread()
131 offset = reg_offset(reg); in ipa_isr_thread()
132 pending = ioread32(ipa->reg_virt + offset); in ipa_isr_thread()
141 pending = ioread32(ipa->reg_virt + offset); in ipa_isr_thread()
146 dev_dbg(dev, "clearing disabled IPA interrupts 0x%08x\n", in ipa_isr_thread()
148 reg = ipa_reg(ipa, IPA_IRQ_CLR); in ipa_isr_thread()
149 iowrite32(pending, ipa->reg_virt + reg_offset(reg)); in ipa_isr_thread()
158 static void ipa_interrupt_enabled_update(struct ipa *ipa) in ipa_interrupt_enabled_update() argument
160 const struct reg *reg = ipa_reg(ipa, IPA_IRQ_EN); in ipa_interrupt_enabled_update() local
162 iowrite32(ipa->interrupt->enabled, ipa->reg_virt + reg_offset(reg)); in ipa_interrupt_enabled_update()
165 /* Enable an IPA interrupt type */
166 void ipa_interrupt_enable(struct ipa *ipa, enum ipa_irq_id ipa_irq) in ipa_interrupt_enable() argument
168 /* Update the IPA interrupt mask to enable it */ in ipa_interrupt_enable()
169 ipa->interrupt->enabled |= BIT(ipa_irq); in ipa_interrupt_enable()
170 ipa_interrupt_enabled_update(ipa); in ipa_interrupt_enable()
173 /* Disable an IPA interrupt type */
174 void ipa_interrupt_disable(struct ipa *ipa, enum ipa_irq_id ipa_irq) in ipa_interrupt_disable() argument
176 /* Update the IPA interrupt mask to disable it */ in ipa_interrupt_disable()
177 ipa->interrupt->enabled &= ~BIT(ipa_irq); in ipa_interrupt_disable()
178 ipa_interrupt_enabled_update(ipa); in ipa_interrupt_disable()
181 void ipa_interrupt_irq_disable(struct ipa *ipa) in ipa_interrupt_irq_disable() argument
183 disable_irq(ipa->interrupt->irq); in ipa_interrupt_irq_disable()
186 void ipa_interrupt_irq_enable(struct ipa *ipa) in ipa_interrupt_irq_enable() argument
188 enable_irq(ipa->interrupt->irq); in ipa_interrupt_irq_enable()
195 struct ipa *ipa = interrupt->ipa; in ipa_interrupt_suspend_control() local
198 const struct reg *reg; in ipa_interrupt_suspend_control() local
203 WARN_ON(!test_bit(endpoint_id, ipa->available)); in ipa_interrupt_suspend_control()
205 /* IPA version 3.0 does not support TX_SUSPEND interrupt control */ in ipa_interrupt_suspend_control()
206 if (ipa->version == IPA_VERSION_3_0) in ipa_interrupt_suspend_control()
209 weight = bitmap_weight(interrupt->suspend_enabled, ipa->endpoint_count); in ipa_interrupt_suspend_control()
211 ipa_interrupt_disable(ipa, IPA_IRQ_TX_SUSPEND); in ipa_interrupt_suspend_control()
213 reg = ipa_reg(ipa, IRQ_SUSPEND_EN); in ipa_interrupt_suspend_control()
214 offset = reg_n_offset(reg, unit); in ipa_interrupt_suspend_control()
215 val = ioread32(ipa->reg_virt + offset); in ipa_interrupt_suspend_control()
221 __change_bit(endpoint_id, interrupt->suspend_enabled); in ipa_interrupt_suspend_control()
223 iowrite32(val, ipa->reg_virt + offset); in ipa_interrupt_suspend_control()
226 ipa_interrupt_enable(ipa, IPA_IRQ_TX_SUSPEND); in ipa_interrupt_suspend_control()
243 /* Simulate arrival of an IPA TX_SUSPEND interrupt */
249 /* Configure the IPA interrupt framework */
250 int ipa_interrupt_config(struct ipa *ipa) in ipa_interrupt_config() argument
252 struct ipa_interrupt *interrupt = ipa->interrupt; in ipa_interrupt_config()
253 unsigned int irq = interrupt->irq; in ipa_interrupt_config()
254 struct device *dev = ipa->dev; in ipa_interrupt_config()
255 const struct reg *reg; in ipa_interrupt_config() local
258 interrupt->ipa = ipa; in ipa_interrupt_config()
260 /* Initially all IPA interrupt types are disabled */ in ipa_interrupt_config()
261 interrupt->enabled = 0; in ipa_interrupt_config()
262 interrupt->suspend_enabled = bitmap_zalloc(ipa->endpoint_count, in ipa_interrupt_config()
264 if (!interrupt->suspend_enabled) { in ipa_interrupt_config()
265 ret = -ENOMEM; in ipa_interrupt_config()
269 /* Disable IPA interrupt types */ in ipa_interrupt_config()
270 reg = ipa_reg(ipa, IPA_IRQ_EN); in ipa_interrupt_config()
271 iowrite32(0, ipa->reg_virt + reg_offset(reg)); in ipa_interrupt_config()
274 "ipa", interrupt); in ipa_interrupt_config()
276 dev_err(dev, "error %d requesting \"ipa\" IRQ\n", ret); in ipa_interrupt_config()
288 dev_err(dev, "error %d registering \"ipa\" IRQ as wakeirq\n", in ipa_interrupt_config()
293 ipa->interrupt = interrupt; in ipa_interrupt_config()
300 free_irq(interrupt->irq, interrupt); in ipa_interrupt_config()
302 bitmap_free(interrupt->suspend_enabled); in ipa_interrupt_config()
310 void ipa_interrupt_deconfig(struct ipa *ipa) in ipa_interrupt_deconfig() argument
312 struct ipa_interrupt *interrupt = ipa->interrupt; in ipa_interrupt_deconfig()
313 struct device *dev = ipa->dev; in ipa_interrupt_deconfig()
315 ipa->interrupt = NULL; in ipa_interrupt_deconfig()
319 free_irq(interrupt->irq, interrupt); in ipa_interrupt_deconfig()
320 bitmap_free(interrupt->suspend_enabled); in ipa_interrupt_deconfig()
323 /* Initialize the IPA interrupt structure */
329 irq = platform_get_irq_byname(pdev, "ipa"); in ipa_interrupt_init()
331 return ERR_PTR(irq ? : -EINVAL); in ipa_interrupt_init()
335 return ERR_PTR(-ENOMEM); in ipa_interrupt_init()
336 interrupt->irq = irq; in ipa_interrupt_init()