// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2019-2024 Linaro Ltd. */ #include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/panic_notifier.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/types.h> #include <linux/soc/qcom/smem_state.h> #include "ipa.h" #include "ipa_smp2p.h" #include "ipa_uc.h" /** * DOC: IPA SMP2P communication with the modem * * SMP2P is a primitive communication mechanism available between the AP and * the modem. The IPA driver uses this for two purposes: to enable the modem * to state that the GSI hardware is ready to use; and to communicate the * state of IPA power in the event of a crash. * * GSI needs to have early initialization completed before it can be used. * This initialization is done either by Trust Zone or by the modem. In the * latter case, the modem uses an SMP2P interrupt to tell the AP IPA driver * when the GSI is ready to use. * * The modem is also able to inquire about the current state of IPA * power by trigging another SMP2P interrupt to the AP. We communicate * whether power is enabled using two SMP2P state bits--one to indicate * the power state (on or off), and a second to indicate the power state * bit is valid. The modem will poll the valid bit until it is set, and * at that time records whether the AP has IPA power enabled. * * Finally, if the AP kernel panics, we update the SMP2P state bits even if * we never receive an interrupt from the modem requesting this. */ /** * struct ipa_smp2p - IPA SMP2P information * @ipa: IPA pointer * @valid_state: SMEM state indicating enabled state is valid * @enabled_state: SMEM state to indicate power is enabled * @valid_bit: Valid bit in 32-bit SMEM state mask * @enabled_bit: Enabled bit in 32-bit SMEM state mask * @enabled_bit: Enabled bit in 32-bit SMEM state mask * @clock_query_irq: IPA interrupt triggered by modem for power query * @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready * @power_on: Whether IPA power is on * @notified: Whether modem has been notified of power state * @setup_disabled: Whether setup ready interrupt handler is disabled * @mutex: Mutex protecting ready-interrupt/shutdown interlock * @panic_notifier: Panic notifier structure */ struct ipa_smp2p { … }; /** * ipa_smp2p_notify() - use SMP2P to tell modem about IPA power state * @smp2p: SMP2P information * * This is called either when the modem has requested it (by triggering * the modem power query IPA interrupt) or whenever the AP is shutting down * (via a panic notifier). It sets the two SMP2P state bits--one saying * whether the IPA power is on, and the other indicating the first bit * is valid. */ static void ipa_smp2p_notify(struct ipa_smp2p *smp2p) { … } /* Threaded IRQ handler for modem "ipa-clock-query" SMP2P interrupt */ static irqreturn_t ipa_smp2p_modem_clk_query_isr(int irq, void *dev_id) { … } static int ipa_smp2p_panic_notifier(struct notifier_block *nb, unsigned long action, void *data) { … } static int ipa_smp2p_panic_notifier_register(struct ipa_smp2p *smp2p) { … } static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p) { … } /* Threaded IRQ handler for modem "ipa-setup-ready" SMP2P interrupt */ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id) { … } /* Initialize SMP2P interrupts */ static int ipa_smp2p_irq_init(struct ipa_smp2p *smp2p, struct platform_device *pdev, const char *name, irq_handler_t handler) { … } static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq) { … } /* Drop the power reference if it was taken in ipa_smp2p_notify() */ static void ipa_smp2p_power_release(struct ipa *ipa) { … } /* Initialize the IPA SMP2P subsystem */ int ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init) { … } void ipa_smp2p_exit(struct ipa *ipa) { … } void ipa_smp2p_irq_disable_setup(struct ipa *ipa) { … } /* Reset state tracking whether we have notified the modem */ void ipa_smp2p_notify_reset(struct ipa *ipa) { … }