// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2018-2024 Linaro Ltd. */ #include <linux/bug.h> #include <linux/firmware.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/types.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/soc/qcom/mdt_loader.h> #include "ipa.h" #include "ipa_cmd.h" #include "ipa_data.h" #include "ipa_endpoint.h" #include "ipa_interrupt.h" #include "ipa_mem.h" #include "ipa_modem.h" #include "ipa_power.h" #include "ipa_reg.h" #include "ipa_resource.h" #include "ipa_smp2p.h" #include "ipa_sysfs.h" #include "ipa_table.h" #include "ipa_uc.h" #include "ipa_version.h" /** * DOC: The IP Accelerator * * This driver supports the Qualcomm IP Accelerator (IPA), which is a * networking component found in many Qualcomm SoCs. The IPA is connected * to the application processor (AP), but is also connected (and partially * controlled by) other "execution environments" (EEs), such as a modem. * * The IPA is the conduit between the AP and the modem that carries network * traffic. This driver presents a network interface representing the * connection of the modem to external (e.g. LTE) networks. * * The IPA provides protocol checksum calculation, offloading this work * from the AP. The IPA offers additional functionality, including routing, * filtering, and NAT support, but that more advanced functionality is not * currently supported. Despite that, some resources--including routing * tables and filter tables--are defined in this driver because they must * be initialized even when the advanced hardware features are not used. * * There are two distinct layers that implement the IPA hardware, and this * is reflected in the organization of the driver. The generic software * interface (GSI) is an integral component of the IPA, providing a * well-defined communication layer between the AP subsystem and the IPA * core. The GSI implements a set of "channels" used for communication * between the AP and the IPA. * * The IPA layer uses GSI channels to implement its "endpoints". And while * a GSI channel carries data between the AP and the IPA, a pair of IPA * endpoints is used to carry traffic between two EEs. Specifically, the main * modem network interface is implemented by two pairs of endpoints: a TX * endpoint on the AP coupled with an RX endpoint on the modem; and another * RX endpoint on the AP receiving data from a TX endpoint on the modem. */ /* The name of the GSI firmware file relative to /lib/firmware */ #define IPA_FW_PATH_DEFAULT … #define IPA_PAS_ID … /* Shift of 19.2 MHz timestamp to achieve lower resolution timestamps */ /* IPA v5.5+ does not specify Qtime timestamp config for DPL */ #define DPL_TIMESTAMP_SHIFT … #define TAG_TIMESTAMP_SHIFT … #define NAT_TIMESTAMP_SHIFT … /* Divider for 19.2 MHz crystal oscillator clock to get common timer clock */ #define IPA_XO_CLOCK_DIVIDER … /** * enum ipa_firmware_loader: How GSI firmware gets loaded * * @IPA_LOADER_DEFER: System not ready; try again later * @IPA_LOADER_SELF: AP loads GSI firmware * @IPA_LOADER_MODEM: Modem loads GSI firmware, signals when done * @IPA_LOADER_SKIP: Neither AP nor modem need to load GSI firmware * @IPA_LOADER_INVALID: GSI firmware loader specification is invalid */ enum ipa_firmware_loader { … }; /** * ipa_setup() - Set up IPA hardware * @ipa: IPA pointer * * Perform initialization that requires issuing immediate commands on * the command TX endpoint. If the modem is doing GSI firmware load * and initialization, this function will be called when an SMP2P * interrupt has been signaled by the modem. Otherwise it will be * called from ipa_probe() after GSI firmware has been successfully * loaded, authenticated, and started by Trust Zone. */ int ipa_setup(struct ipa *ipa) { … } /** * ipa_teardown() - Inverse of ipa_setup() * @ipa: IPA pointer */ static void ipa_teardown(struct ipa *ipa) { … } static void ipa_hardware_config_bcr(struct ipa *ipa, const struct ipa_data *data) { … } static void ipa_hardware_config_tx(struct ipa *ipa) { … } static void ipa_hardware_config_clkon(struct ipa *ipa) { … } /* Configure bus access behavior for IPA components */ static void ipa_hardware_config_comp(struct ipa *ipa) { … } /* Configure DDR and (possibly) PCIe max read/write QSB values */ static void ipa_hardware_config_qsb(struct ipa *ipa, const struct ipa_data *data) { … } /* The internal inactivity timer clock is used for the aggregation timer */ #define TIMER_FREQUENCY … /* Compute the value to use in the COUNTER_CFG register AGGR_GRANULARITY * field to represent the given number of microseconds. The value is one * less than the number of timer ticks in the requested period. 0 is not * a valid granularity value (so for example @usec must be at least 16 for * a TIMER_FREQUENCY of 32000). */ static __always_inline u32 ipa_aggr_granularity_val(u32 usec) { … } /* IPA uses unified Qtime starting at IPA v4.5, implementing various * timestamps and timers independent of the IPA core clock rate. The * Qtimer is based on a 56-bit timestamp incremented at each tick of * a 19.2 MHz SoC crystal oscillator (XO clock). * * For IPA timestamps (tag, NAT, data path logging) a lower resolution * timestamp is achieved by shifting the Qtimer timestamp value right * some number of bits to produce the low-order bits of the coarser * granularity timestamp. * * For timers, a common timer clock is derived from the XO clock using * a divider (we use 192, to produce a 100kHz timer clock). From * this common clock, three "pulse generators" are used to produce * timer ticks at a configurable frequency. IPA timers (such as * those used for aggregation or head-of-line block handling) now * define their period based on one of these pulse generators. */ static void ipa_qtime_config(struct ipa *ipa) { … } /* Before IPA v4.5 timing is controlled by a counter register */ static void ipa_hardware_config_counter(struct ipa *ipa) { … } static void ipa_hardware_config_timing(struct ipa *ipa) { … } static void ipa_hardware_config_hashing(struct ipa *ipa) { … } static void ipa_idle_indication_cfg(struct ipa *ipa, u32 enter_idle_debounce_thresh, bool const_non_idle_enable) { … } /** * ipa_hardware_dcd_config() - Enable dynamic clock division on IPA * @ipa: IPA pointer * * Configures when the IPA signals it is idle to the global clock * controller, which can respond by scaling down the clock to save * power. */ static void ipa_hardware_dcd_config(struct ipa *ipa) { … } static void ipa_hardware_dcd_deconfig(struct ipa *ipa) { … } /** * ipa_hardware_config() - Primitive hardware initialization * @ipa: IPA pointer * @data: IPA configuration data */ static void ipa_hardware_config(struct ipa *ipa, const struct ipa_data *data) { … } /** * ipa_hardware_deconfig() - Inverse of ipa_hardware_config() * @ipa: IPA pointer * * This restores the power-on reset values (even if they aren't different) */ static void ipa_hardware_deconfig(struct ipa *ipa) { … } /** * ipa_config() - Configure IPA hardware * @ipa: IPA pointer * @data: IPA configuration data * * Perform initialization requiring IPA power to be enabled. */ static int ipa_config(struct ipa *ipa, const struct ipa_data *data) { … } /** * ipa_deconfig() - Inverse of ipa_config() * @ipa: IPA pointer */ static void ipa_deconfig(struct ipa *ipa) { … } static int ipa_firmware_load(struct device *dev) { … } static const struct of_device_id ipa_match[] = …; MODULE_DEVICE_TABLE(of, ipa_match); /* Check things that can be validated at build time. This just * groups these things BUILD_BUG_ON() calls don't clutter the rest * of the code. * */ static void ipa_validate_build(void) { … } static enum ipa_firmware_loader ipa_firmware_loader(struct device *dev) { … } /** * ipa_probe() - IPA platform driver probe function * @pdev: Platform device pointer * * Return: 0 if successful, or a negative error code (possibly * EPROBE_DEFER) * * This is the main entry point for the IPA driver. Initialization proceeds * in several stages: * - The "init" stage involves activities that can be initialized without * access to the IPA hardware. * - The "config" stage requires IPA power to be active so IPA registers * can be accessed, but does not require the use of IPA immediate commands. * - The "setup" stage uses IPA immediate commands, and so requires the GSI * layer to be initialized. * * A Boolean Device Tree "modem-init" property determines whether GSI * initialization will be performed by the AP (Trust Zone) or the modem. * If the AP does GSI initialization, the setup phase is entered after * this has completed successfully. Otherwise the modem initializes * the GSI layer and signals it has finished by sending an SMP2P interrupt * to the AP; this triggers the start if IPA setup. */ static int ipa_probe(struct platform_device *pdev) { … } static void ipa_remove(struct platform_device *pdev) { … } static const struct attribute_group *ipa_attribute_groups[] = …; static struct platform_driver ipa_driver = …; module_platform_driver(…) …; MODULE_LICENSE(…) …; MODULE_DESCRIPTION(…) …;