Lines Matching +full:ipa +full:- +full:ap +full:- +full:to +full:- +full:modem

1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2018-2022 Linaro Ltd.
16 #include "ipa.h"
23 * DOC: IPA Power Management
25 * The IPA hardware is enabled when the IPA core clock and all the
27 * management is used to determine whether the core clock and
28 * interconnects are enabled, and if not in use to be suspended
38 * enum ipa_power_flag - IPA power flags
41 * @IPA_POWER_FLAG_STOPPED: Modem TX is disabled by ipa_start_xmit()
42 * @IPA_POWER_FLAG_STARTED: Modem TX was enabled by ipa_runtime_resume()
54 * struct ipa_power - IPA power management information
55 * @dev: IPA device pointer
56 * @core: IPA core clock
58 * @spinlock: Protects modem TX queue enable/disable
73 /* Initialize interconnects required for IPA operation */
82 interconnect = &power->interconnect[0]; in ipa_interconnect_init()
83 for (i = 0; i < power->interconnect_count; i++) { in ipa_interconnect_init()
84 /* interconnect->path is filled in by of_icc_bulk_get() */ in ipa_interconnect_init()
85 interconnect->name = data->name; in ipa_interconnect_init()
86 interconnect->avg_bw = data->average_bandwidth; in ipa_interconnect_init()
87 interconnect->peak_bw = data->peak_bandwidth; in ipa_interconnect_init()
92 ret = of_icc_bulk_get(power->dev, power->interconnect_count, in ipa_interconnect_init()
93 power->interconnect); in ipa_interconnect_init()
98 icc_bulk_disable(power->interconnect_count, power->interconnect); in ipa_interconnect_init()
100 /* Set the bandwidth values to be used when enabled */ in ipa_interconnect_init()
101 ret = icc_bulk_set_bw(power->interconnect_count, power->interconnect); in ipa_interconnect_init()
103 icc_bulk_put(power->interconnect_count, power->interconnect); in ipa_interconnect_init()
111 icc_bulk_put(power->interconnect_count, power->interconnect); in ipa_interconnect_exit()
114 /* Enable IPA power, enabling interconnects and the core clock */
115 static int ipa_power_enable(struct ipa *ipa) in ipa_power_enable() argument
117 struct ipa_power *power = ipa->power; in ipa_power_enable()
120 ret = icc_bulk_enable(power->interconnect_count, power->interconnect); in ipa_power_enable()
124 ret = clk_prepare_enable(power->core); in ipa_power_enable()
126 dev_err(power->dev, "error %d enabling core clock\n", ret); in ipa_power_enable()
127 icc_bulk_disable(power->interconnect_count, in ipa_power_enable()
128 power->interconnect); in ipa_power_enable()
135 static void ipa_power_disable(struct ipa *ipa) in ipa_power_disable() argument
137 struct ipa_power *power = ipa->power; in ipa_power_disable()
139 clk_disable_unprepare(power->core); in ipa_power_disable()
141 icc_bulk_disable(power->interconnect_count, power->interconnect); in ipa_power_disable()
146 struct ipa *ipa = dev_get_drvdata(dev); in ipa_runtime_suspend() local
149 if (ipa->setup_complete) { in ipa_runtime_suspend()
150 __clear_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags); in ipa_runtime_suspend()
151 ipa_endpoint_suspend(ipa); in ipa_runtime_suspend()
152 gsi_suspend(&ipa->gsi); in ipa_runtime_suspend()
155 ipa_power_disable(ipa); in ipa_runtime_suspend()
162 struct ipa *ipa = dev_get_drvdata(dev); in ipa_runtime_resume() local
165 ret = ipa_power_enable(ipa); in ipa_runtime_resume()
170 if (ipa->setup_complete) { in ipa_runtime_resume()
171 gsi_resume(&ipa->gsi); in ipa_runtime_resume()
172 ipa_endpoint_resume(ipa); in ipa_runtime_resume()
180 struct ipa *ipa = dev_get_drvdata(dev); in ipa_suspend() local
182 __set_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags); in ipa_suspend()
189 struct ipa *ipa = dev_get_drvdata(dev); in ipa_resume() local
194 __clear_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags); in ipa_resume()
199 /* Return the current IPA core clock rate */
200 u32 ipa_core_clock_rate(struct ipa *ipa) in ipa_core_clock_rate() argument
202 return ipa->power ? (u32)clk_get_rate(ipa->power->core) : 0; in ipa_core_clock_rate()
206 * ipa_suspend_handler() - Handle the suspend IPA interrupt
207 * @ipa: IPA pointer
208 * @irq_id: IPA interrupt type (unused)
210 * If an RX endpoint is suspended, and the IPA has a packet destined for
211 * that endpoint, the IPA generates a SUSPEND interrupt to inform the AP
215 static void ipa_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) in ipa_suspend_handler() argument
217 /* To handle an IPA interrupt we will have resumed the hardware in ipa_suspend_handler()
218 * just to handle the interrupt, so we're done. If we are in a in ipa_suspend_handler()
221 if (!__test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags)) in ipa_suspend_handler()
222 if (test_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags)) in ipa_suspend_handler()
223 pm_wakeup_dev_event(&ipa->pdev->dev, 0, true); in ipa_suspend_handler()
226 ipa_interrupt_suspend_clear_all(ipa->interrupt); in ipa_suspend_handler()
229 /* The next few functions coordinate stopping and starting the modem
235 * to avoid this: ipa_power_modem_queue_stop() is used by ipa_start_xmit()
236 * to conditionally stop the TX queue; and ipa_power_modem_queue_start()
237 * is used by ipa_runtime_resume() to conditionally restart it.
247 * The first function stops the modem netdev transmit queue, but only if
250 * from the power ->runtime_resume operation.
252 void ipa_power_modem_queue_stop(struct ipa *ipa) in ipa_power_modem_queue_stop() argument
254 struct ipa_power *power = ipa->power; in ipa_power_modem_queue_stop()
257 spin_lock_irqsave(&power->spinlock, flags); in ipa_power_modem_queue_stop()
259 if (!__test_and_clear_bit(IPA_POWER_FLAG_STARTED, power->flags)) { in ipa_power_modem_queue_stop()
260 netif_stop_queue(ipa->modem_netdev); in ipa_power_modem_queue_stop()
261 __set_bit(IPA_POWER_FLAG_STOPPED, power->flags); in ipa_power_modem_queue_stop()
264 spin_unlock_irqrestore(&power->spinlock, flags); in ipa_power_modem_queue_stop()
267 /* This function starts the modem netdev transmit queue, but only if the
270 * to skip stopping the queue in the event of a race.
272 void ipa_power_modem_queue_wake(struct ipa *ipa) in ipa_power_modem_queue_wake() argument
274 struct ipa_power *power = ipa->power; in ipa_power_modem_queue_wake()
277 spin_lock_irqsave(&power->spinlock, flags); in ipa_power_modem_queue_wake()
279 if (__test_and_clear_bit(IPA_POWER_FLAG_STOPPED, power->flags)) { in ipa_power_modem_queue_wake()
280 __set_bit(IPA_POWER_FLAG_STARTED, power->flags); in ipa_power_modem_queue_wake()
281 netif_wake_queue(ipa->modem_netdev); in ipa_power_modem_queue_wake()
284 spin_unlock_irqrestore(&power->spinlock, flags); in ipa_power_modem_queue_wake()
288 void ipa_power_modem_queue_active(struct ipa *ipa) in ipa_power_modem_queue_active() argument
290 clear_bit(IPA_POWER_FLAG_STARTED, ipa->power->flags); in ipa_power_modem_queue_active()
295 struct qmp *qmp = qmp_get(power->dev); in ipa_power_retention_init()
298 if (PTR_ERR(qmp) == -EPROBE_DEFER) in ipa_power_retention_init()
299 return -EPROBE_DEFER; in ipa_power_retention_init()
304 power->qmp = qmp; in ipa_power_retention_init()
311 qmp_put(power->qmp); in ipa_power_retention_exit()
312 power->qmp = NULL; in ipa_power_retention_exit()
316 void ipa_power_retention(struct ipa *ipa, bool enable) in ipa_power_retention() argument
319 struct ipa_power *power = ipa->power; in ipa_power_retention()
323 if (!power->qmp) in ipa_power_retention()
328 ret = qmp_send(power->qmp, buf, sizeof(buf)); in ipa_power_retention()
330 dev_err(power->dev, "error %d sending QMP %sable request\n", in ipa_power_retention()
334 int ipa_power_setup(struct ipa *ipa) in ipa_power_setup() argument
338 ipa_interrupt_add(ipa->interrupt, IPA_IRQ_TX_SUSPEND, in ipa_power_setup()
341 ret = device_init_wakeup(&ipa->pdev->dev, true); in ipa_power_setup()
343 ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND); in ipa_power_setup()
348 void ipa_power_teardown(struct ipa *ipa) in ipa_power_teardown() argument
350 (void)device_init_wakeup(&ipa->pdev->dev, false); in ipa_power_teardown()
351 ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND); in ipa_power_teardown()
354 /* Initialize IPA power management */
370 ret = clk_set_rate(clk, data->core_clock_rate); in ipa_power_init()
372 dev_err(dev, "error %d setting core clock rate to %u\n", in ipa_power_init()
373 ret, data->core_clock_rate); in ipa_power_init()
377 size = struct_size(power, interconnect, data->interconnect_count); in ipa_power_init()
380 ret = -ENOMEM; in ipa_power_init()
383 power->dev = dev; in ipa_power_init()
384 power->core = clk; in ipa_power_init()
385 spin_lock_init(&power->spinlock); in ipa_power_init()
386 power->interconnect_count = data->interconnect_count; in ipa_power_init()
388 ret = ipa_interconnect_init(power, data->interconnect_data); in ipa_power_init()
415 struct device *dev = power->dev; in ipa_power_exit()
416 struct clk *clk = power->core; in ipa_power_exit()