]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
qualcommax: drop 6.12 support
authorRobert Marko <robimarko@gmail.com>
Sun, 2 Aug 2026 17:39:22 +0000 (19:39 +0200)
committerRobert Marko <robimarko@gmail.com>
Sun, 2 Aug 2026 17:40:22 +0000 (19:40 +0200)
No point in keeping 6.12 on qualcommax anymore.

Signed-off-by: Robert Marko <robimarko@gmail.com>
119 files changed:
target/linux/qualcommax/config-6.12 [deleted file]
target/linux/qualcommax/patches-6.12/0036-v6.13-arm64-dts-qcom-ipq-change-labels-to-lower-case.patch [deleted file]
target/linux/qualcommax/patches-6.12/0037-v6.16-arm64-dts-qcom-ipq6018-add-1.2GHz-CPU-Frequency.patch [deleted file]
target/linux/qualcommax/patches-6.12/0038-v6.16-arm64-dts-qcom-ipq6018-add-1.5GHz-CPU-Frequency.patch [deleted file]
target/linux/qualcommax/patches-6.12/0039-v6.16-arm64-dts-qcom-ipq6018-move-mp5496-regulator-out-of-.patch [deleted file]
target/linux/qualcommax/patches-6.12/0040-v6.16-arm64-dts-qcom-ipq6018-rename-labels-of-mp5496-regul.patch [deleted file]
target/linux/qualcommax/patches-6.12/0041-v6.16-arm64-dts-qcom-ipq6018-add-LDOA2-regulator.patch [deleted file]
target/linux/qualcommax/patches-6.12/0045-v6.16-phy-qcom-Introduce-PCIe-UNIPHY-28LP-driver.patch [deleted file]
target/linux/qualcommax/patches-6.12/0046-v6.16-phy-qualcomm-qcom-uniphy-pcie-28LP-add-support-for-I.patch [deleted file]
target/linux/qualcommax/patches-6.12/0047-v6.16-PCI-qcom-Add-support-for-IPQ5018.patch [deleted file]
target/linux/qualcommax/patches-6.12/0048-v6.16-arm64-dts-qcom-ipq5018-Add-PCIe-related-nodes.patch [deleted file]
target/linux/qualcommax/patches-6.12/0049-v6.16-arm64-dts-qcom-ipq5018-enable-the-download-mode-supp.patch [deleted file]
target/linux/qualcommax/patches-6.12/0050-v6.15-thermal-drivers-tsens-Add-TSENS-enable-and-calibrati.patch [deleted file]
target/linux/qualcommax/patches-6.12/0051-v6.16-thermal-drivers-qcom-tsens-Update-conditions-to-stri.patch [deleted file]
target/linux/qualcommax/patches-6.12/0052-v6.16-thermal-drivers-qcom-tsens-Add-support-for-tsens-v1-.patch [deleted file]
target/linux/qualcommax/patches-6.12/0053-v6.16-thermal-drivers-qcom-tsens-Add-support-for-IPQ5018-t.patch [deleted file]
target/linux/qualcommax/patches-6.12/0054-v6.18-arm64-dts-qcom-ipq5018-Add-tsens-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0056-v6.17-clk-qcom-gcc-ipq5018-fix-GE-PHY-reset.patch [deleted file]
target/linux/qualcommax/patches-6.12/0057-v6.17-net-phy-qcom-at803x-Add-Qualcomm-IPQ5018-Internal-PHY-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0058-v6.18-arm64-dts-qcom-ipq5018-Add-MDIO-buses.patch [deleted file]
target/linux/qualcommax/patches-6.12/0059-v6.18-arm64-dts-qcom-ipq5018-Add-GE-PHY-to-internal-mdio-bus.patch [deleted file]
target/linux/qualcommax/patches-6.12/0060-v6.18-arm64-dts-qcom-ipq5018-Add-SPI-nand-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0061-v6.18-arm64-dts-qcom-ipq5018-add-PRNG-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0062-v6.18-arm64-dts-qcom-ipq5018-Add-crypto-nodes.patch [deleted file]
target/linux/qualcommax/patches-6.12/0063-v6.14-dt-bindings-clock-qcom-Add-CMN-PLL-clock-controller.patch [deleted file]
target/linux/qualcommax/patches-6.12/0064-v6.14-clk-qcom-Add-CMN-PLL-clock-controller-driver-for-IPQ-SoC.patch [deleted file]
target/linux/qualcommax/patches-6.12/0065-v6.17-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ5424-SoC.patch [deleted file]
target/linux/qualcommax/patches-6.12/0066-v6.17-clk-qcom-cmnpll-Add-IPQ5424-SoC-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0067-v6.17-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ5018-SoC.patch [deleted file]
target/linux/qualcommax/patches-6.12/0068-v6.17-clk-qcom-ipq-cmn-pll-Add-IPQ5018-SoC-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0069-v6.18-arm64-dts-ipq5018-Add-CMN-PLL-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0070-v6.18-arm64-dts-qcom-Update-IPQ5018-xo_board_clk-to-use-fixed-factor-clock.patch [deleted file]
target/linux/qualcommax/patches-6.12/0071-v6.18-arm64-dts-qcom-ipq5018-add-QUP3-I2C-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0072-v6.18-arm64-dts-qcom-ipq5018-add-QUP1-UART2-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0073-v7.0-arm64-dts-qcom-ipq5018-Remove-tsens-v1-fallback-compatible.patch [deleted file]
target/linux/qualcommax/patches-6.12/0075-v7.0-arm64-dts-qcom-ipq5018-Correct-USB-DWC3-wrapper-interrupts.patch [deleted file]
target/linux/qualcommax/patches-6.12/0076-v7.2-dt-bindings-pwm-add-IPQ6018-binding.patch [deleted file]
target/linux/qualcommax/patches-6.12/0077-v7.2-pwm-Driver-for-qualcomm-ipq6018-pwm-block.patch [deleted file]
target/linux/qualcommax/patches-6.12/0078-v7.3-arm64-dts-qcom-ipq6018-add-pwm-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0079-v7.3-arm64-dts-qcom-ipq5018-add-pwm-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0080-v7.1-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ6018.patch [deleted file]
target/linux/qualcommax/patches-6.12/0081-v7.1-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ8074.patch [deleted file]
target/linux/qualcommax/patches-6.12/0082-v7.1-clk-qcom-ipq-cmn-pll-Add-IPQ6018-SoC-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0083-v7.1-clk-qcom-ipq-cmn-pll-Add-IPQ8074-SoC-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0084-v7.2-clk-qcom-cmnpll-Account-for-reference-clock-divider.patch [deleted file]
target/linux/qualcommax/patches-6.12/0085-v7.3-arm64-dts-qcom-ipq5018-Correct-CMN-PLL-reference-clock-rate.patch [deleted file]
target/linux/qualcommax/patches-6.12/0086-v6.17-dt-bindings-net-qca-ar803x-Add-IPQ5018-Internal-GE-PHY-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0087-v7.2-dt-bindings-net-ethernet-phy-increase-max-clock-count-to-two.patch [deleted file]
target/linux/qualcommax/patches-6.12/0088-v7.2-dt-bindings-net-qca-ar803x-Add-clocks-for-IPQ5018-PHY.patch [deleted file]
target/linux/qualcommax/patches-6.12/0089-v7.2-net-phy-at803x-add-RX-and-TX-clock-management-for-IPQ5018-PHY.patch [deleted file]
target/linux/qualcommax/patches-6.12/0090-v7.3-arm64-qcom-ipq5018-Add-GEPHY-RX-and-TX-clocks.patch [deleted file]
target/linux/qualcommax/patches-6.12/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch [deleted file]
target/linux/qualcommax/patches-6.12/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch [deleted file]
target/linux/qualcommax/patches-6.12/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch [deleted file]
target/linux/qualcommax/patches-6.12/0113-remoteproc-qcom-Add-secure-PIL-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch [deleted file]
target/linux/qualcommax/patches-6.12/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch [deleted file]
target/linux/qualcommax/patches-6.12/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch [deleted file]
target/linux/qualcommax/patches-6.12/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch [deleted file]
target/linux/qualcommax/patches-6.12/0118-clk-qcom-Add-WCSSAON-reset.patch [deleted file]
target/linux/qualcommax/patches-6.12/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch [deleted file]
target/linux/qualcommax/patches-6.12/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch [deleted file]
target/linux/qualcommax/patches-6.12/0121-arm64-dts-ipq8074-Add-WLAN-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0122-arm64-dts-ipq8074-add-CPU-clock.patch [deleted file]
target/linux/qualcommax/patches-6.12/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch [deleted file]
target/linux/qualcommax/patches-6.12/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch [deleted file]
target/linux/qualcommax/patches-6.12/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch [deleted file]
target/linux/qualcommax/patches-6.12/0135-arm64-dts-qcom-ipq6018-add-NSS-reserved-memory.patch [deleted file]
target/linux/qualcommax/patches-6.12/0136-remoteproc-qcom-wcss-populate-driver-data-for-IPQ601.patch [deleted file]
target/linux/qualcommax/patches-6.12/0184-mailbox-tmelite-qmp-Introduce-TMEL-QMP-mailbox-driver.patch [deleted file]
target/linux/qualcommax/patches-6.12/0185-firmware-qcom_scm-ipq5332-add-support-to-pass-metadata-size.patch [deleted file]
target/linux/qualcommax/patches-6.12/0186-dt-bindings-remoteproc-qcom-document-hexagon-based-wcss-secure-pil.patch [deleted file]
target/linux/qualcommax/patches-6.12/0188-remoteproc-qcom-add-hexagon-based-wcss-secure-pil-driver.patch [deleted file]
target/linux/qualcommax/patches-6.12/0189-arm64-dts-qcom-ipq5018-add-nodes-to-bringup-q6.patch [deleted file]
target/linux/qualcommax/patches-6.12/0305-pinctrl-qcom-IPQ5018-update-pwm-groups.patch [deleted file]
target/linux/qualcommax/patches-6.12/0400-mtd-rawnand-add-support-for-TH58NYG3S0HBAI4.patch [deleted file]
target/linux/qualcommax/patches-6.12/0401-spi-spi-qpic-snand-default-to-4-bit-ECC.patch [deleted file]
target/linux/qualcommax/patches-6.12/0411-mtd-rawnand-qpic-only-support-max-4-bytes-ID.patch [deleted file]
target/linux/qualcommax/patches-6.12/0412-mtd-spinand-qpic-only-support-max-4-bytes-ID.patch [deleted file]
target/linux/qualcommax/patches-6.12/0715-arm64-dts-qcom-ipq5018-add-vendor-compatible-to-mdio-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0721-clk-gcc-ipq5018-remove-the-unsupported-clk-combinati.patch [deleted file]
target/linux/qualcommax/patches-6.12/0723-clk-qcom-gcc-ipq5018-fix-uniphy-soft-reset-issue.patch [deleted file]
target/linux/qualcommax/patches-6.12/0760-net-phy-aquantia-enable-USXGMII-MAC-autoneg.patch [deleted file]
target/linux/qualcommax/patches-6.12/0801-dt-bindings-remoteproc-qcom-Add-support-for-multipd-model.patch [deleted file]
target/linux/qualcommax/patches-6.12/0803-firmware-qcom_scm-ipq5332-add-msa-lock-unlock-suppor.patch [deleted file]
target/linux/qualcommax/patches-6.12/0804-remoteproc-qcom-q6v5-Add-multipd-interrupts-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0805-remoteproc-qcom-Add-Hexagon-based-multipd-rproc-driv.patch [deleted file]
target/linux/qualcommax/patches-6.12/0806-rproc-qcom_q6v5_mpd-split-q6_wcss-to-rootpd-and-user.patch [deleted file]
target/linux/qualcommax/patches-6.12/0807-remoteproc-qcom_q6v5_mpd-fix-incorrent-use-of-rproc-.patch [deleted file]
target/linux/qualcommax/patches-6.12/0808-remoteproc-qcom-wcss-sec-add-split-firmware-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0811-firmware-qcom_scm-support-MPD.patch [deleted file]
target/linux/qualcommax/patches-6.12/0812-soc-qcom-mdt_loader-support-MPD.patch [deleted file]
target/linux/qualcommax/patches-6.12/0813-remoteproc-qcom_q6v5_mpd-enable-clocks.patch [deleted file]
target/linux/qualcommax/patches-6.12/0814-remoteproc-qcom_q6v5_mpd-support-ipq5018.patch [deleted file]
target/linux/qualcommax/patches-6.12/0815-remoteproc-qcom_q6v5_mpd-add-support-for-passing-v1-bootargs.patch [deleted file]
target/linux/qualcommax/patches-6.12/0816-arm64-dts-qcom-ipq5018-add-wifi-support.patch [deleted file]
target/linux/qualcommax/patches-6.12/0817-arm64-dts-qcom-ipq5018-add-tz_apps-reserved-memory-region.patch [deleted file]
target/linux/qualcommax/patches-6.12/0820-dt-bindings-net-wireless-ath11k-add-bindings-for-QCN6122.patch [deleted file]
target/linux/qualcommax/patches-6.12/0842-arm64-dts-qcom-ipq5018-add-uniphy-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0843-net-stmmac-add-get_interfaces-platform-method.patch [deleted file]
target/linux/qualcommax/patches-6.12/0900-power-Add-Qualcomm-APM.patch [deleted file]
target/linux/qualcommax/patches-6.12/0901-regulator-add-Qualcomm-CPR-regulators.patch [deleted file]
target/linux/qualcommax/patches-6.12/0902-arm64-dts-ipq8074-add-label-to-clocks.patch [deleted file]
target/linux/qualcommax/patches-6.12/0903-psci-dont-advertise-OSI-support-for-IPQ6018.patch [deleted file]
target/linux/qualcommax/patches-6.12/0904-clk-qcom-ipq6018-workaround-networking-clock-parenti.patch [deleted file]
target/linux/qualcommax/patches-6.12/0905-remoteproc-q6v5_wcss-change-ssr-name-for-ipq6018-wif.patch [deleted file]
target/linux/qualcommax/patches-6.12/0906-arm64-dts-qcom-ipq6018-add-wifi-node.patch [deleted file]
target/linux/qualcommax/patches-6.12/0907-soc-qcom-fix-smp2p-ack-on-ipq6018.patch [deleted file]
target/linux/qualcommax/patches-6.12/0908-remoteproc-qcom_q6v5_wcss-add-optional-qdss_at-clock.patch [deleted file]
target/linux/qualcommax/patches-6.12/0909-arm64-dts-qcom-ipq6018-assign-QDSS_AT-clock-to-wifi-.patch [deleted file]
target/linux/qualcommax/patches-6.12/0911-arm64-cmdline-replacement.patch [deleted file]
target/linux/qualcommax/patches-6.12/0912-arm64-dts-qcom-ipq5018-remove-cpufreq-scaling.patch [deleted file]
target/linux/qualcommax/patches-6.12/0917-clk-qcom-gcc-ipq6018-mark-gcc_xo_clk_src-as-critical.patch [deleted file]
target/linux/qualcommax/patches-6.12/0920-clk-add-clk_hw_recalc_rate-to-trigger-HW-clk-rate-re.patch [deleted file]
target/linux/qualcommax/patches-6.12/0950-net-dsa-add-out-of-band-tagging-protocol.patch [deleted file]
target/linux/qualcommax/patches-6.12/0951-net-pcs-add-uniphy-pcs.patch [deleted file]
target/linux/qualcommax/patches-6.12/0952-net-ethernet-qca-add-ppe.patch [deleted file]
target/linux/qualcommax/patches-6.12/0953-net-ethernet-qca-add-EDMA.patch [deleted file]
target/linux/qualcommax/patches-6.12/0954-net-stmmac-Introduce-Qualcomm-IPQ5018-DWMAC-driver.patch [deleted file]

diff --git a/target/linux/qualcommax/config-6.12 b/target/linux/qualcommax/config-6.12
deleted file mode 100644 (file)
index 8daaff3..0000000
+++ /dev/null
@@ -1,626 +0,0 @@
-CONFIG_64BIT=y
-CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
-CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
-CONFIG_ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_ARCH_FORCE_MAX_ORDER=10
-CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-CONFIG_ARCH_KEEP_MEMBLOCK=y
-CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
-CONFIG_ARCH_MMAP_RND_BITS=18
-CONFIG_ARCH_MMAP_RND_BITS_MAX=24
-CONFIG_ARCH_MMAP_RND_BITS_MIN=18
-CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
-CONFIG_ARCH_PKEY_BITS=3
-CONFIG_ARCH_PROC_KCORE_TEXT=y
-CONFIG_ARCH_QCOM=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_STACKWALK=y
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-CONFIG_ARCH_WANTS_EXECMEM_LATE=y
-CONFIG_ARCH_WANTS_NO_INSTR=y
-CONFIG_ARCH_WANTS_THP_SWAP=y
-CONFIG_ARM64=y
-CONFIG_ARM64_4K_PAGES=y
-CONFIG_ARM64_ERRATUM_1165522=y
-CONFIG_ARM64_ERRATUM_1286807=y
-CONFIG_ARM64_ERRATUM_2051678=y
-CONFIG_ARM64_ERRATUM_2054223=y
-CONFIG_ARM64_ERRATUM_2067961=y
-CONFIG_ARM64_ERRATUM_2077057=y
-CONFIG_ARM64_ERRATUM_2658417=y
-CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y
-CONFIG_ARM64_PA_BITS=48
-CONFIG_ARM64_PA_BITS_48=y
-CONFIG_ARM64_PLATFORM_DEVICES=y
-CONFIG_ARM64_PTR_AUTH=y
-CONFIG_ARM64_PTR_AUTH_KERNEL=y
-CONFIG_ARM64_SVE=y
-CONFIG_ARM64_TAGGED_ADDR_ABI=y
-CONFIG_ARM64_VA_BITS=39
-CONFIG_ARM64_VA_BITS_39=y
-CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
-CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y
-CONFIG_ARM64_WORKAROUND_TSB_FLUSH_FAILURE=y
-CONFIG_ARM_AMBA=y
-CONFIG_ARM_ARCH_TIMER=y
-CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
-CONFIG_ARM_GIC=y
-CONFIG_ARM_GIC_V2M=y
-CONFIG_ARM_GIC_V3=y
-CONFIG_ARM_GIC_V3_ITS=y
-# CONFIG_ARM_MHU_V2 is not set
-# CONFIG_ARM_MHU_V3 is not set
-CONFIG_ARM_PSCI_CPUIDLE=y
-CONFIG_ARM_PSCI_FW=y
-# CONFIG_ARM_QCOM_CPUFREQ_HW is not set
-CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y
-CONFIG_AT803X_PHY=y
-CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
-CONFIG_AUXILIARY_BUS=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_BLK_MQ_PCI=y
-CONFIG_BLK_MQ_VIRTIO=y
-CONFIG_BLK_PM=y
-CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y
-CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
-CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
-# CONFIG_CLK_QCM2290_GPUCC is not set
-# CONFIG_CLK_X1E80100_CAMCC is not set
-# CONFIG_CLK_X1E80100_DISPCC is not set
-# CONFIG_CLK_X1E80100_GCC is not set
-# CONFIG_CLK_X1E80100_GPUCC is not set
-# CONFIG_CLK_X1E80100_TCSRCC is not set
-CONFIG_CLONE_BACKWARDS=y
-CONFIG_COMMON_CLK=y
-CONFIG_COMMON_CLK_QCOM=y
-CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
-# CONFIG_COMPAT_32BIT_TIME is not set
-CONFIG_CONTEXT_TRACKING=y
-CONFIG_CONTEXT_TRACKING_IDLE=y
-CONFIG_COREDUMP=y
-CONFIG_CPUFREQ_DT=y
-CONFIG_CPUFREQ_DT_PLATDEV=y
-CONFIG_CPU_FREQ=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
-CONFIG_CPU_FREQ_GOV_ATTR_SET=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-CONFIG_CPU_FREQ_STAT=y
-CONFIG_CPU_FREQ_THERMAL=y
-CONFIG_CPU_IDLE=y
-CONFIG_CPU_IDLE_GOV_MENU=y
-CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_CPU_MITIGATIONS=y
-CONFIG_CPU_PM=y
-CONFIG_CPU_RMAP=y
-CONFIG_CPU_THERMAL=y
-CONFIG_CRC16=y
-CONFIG_CRC8=y
-CONFIG_CRYPTO_AUTHENC=y
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_DEV_QCOM_RNG=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_HASH_INFO=y
-CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
-CONFIG_CRYPTO_LIB_DES=y
-CONFIG_CRYPTO_LIB_GF128MUL=y
-CONFIG_CRYPTO_LIB_SHA256=y
-CONFIG_CRYPTO_LIB_UTILS=y
-CONFIG_CRYPTO_LZO=y
-CONFIG_CRYPTO_RNG=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_XTS=y
-CONFIG_CRYPTO_ZSTD=y
-CONFIG_DCACHE_WORD_ACCESS=y
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEV_COREDUMP=y
-CONFIG_DMADEVICES=y
-CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y
-CONFIG_DMA_DIRECT_REMAP=y
-CONFIG_DMA_ENGINE=y
-CONFIG_DMA_NEED_SYNC=y
-CONFIG_DMA_OF=y
-CONFIG_DMA_VIRTUAL_CHANNELS=y
-CONFIG_DTC=y
-CONFIG_DT_IDLE_STATES=y
-CONFIG_EDAC_SUPPORT=y
-CONFIG_EXCLUSIVE_SYSTEM_RAM=y
-CONFIG_FIXED_PHY=y
-CONFIG_FIX_EARLYCON_MEM=y
-CONFIG_FRAME_POINTER=y
-CONFIG_FS_IOMAP=y
-CONFIG_FUNCTION_ALIGNMENT=4
-CONFIG_FUNCTION_ALIGNMENT_4B=y
-CONFIG_FWNODE_MDIO=y
-CONFIG_FWNODE_PCS=y
-CONFIG_FW_LOADER_PAGED_BUF=y
-CONFIG_FW_LOADER_SYSFS=y
-CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
-CONFIG_GENERIC_ALLOCATOR=y
-CONFIG_GENERIC_ARCH_TOPOLOGY=y
-CONFIG_GENERIC_BUG=y
-CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
-CONFIG_GENERIC_CPU_AUTOPROBE=y
-CONFIG_GENERIC_CPU_DEVICES=y
-CONFIG_GENERIC_CPU_VULNERABILITIES=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_GENERIC_EARLY_IOREMAP=y
-CONFIG_GENERIC_GETTIMEOFDAY=y
-CONFIG_GENERIC_IDLE_POLL_SETUP=y
-CONFIG_GENERIC_IOREMAP=y
-CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
-CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
-CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
-CONFIG_GENERIC_MSI_IRQ=y
-CONFIG_GENERIC_PCI_IOMAP=y
-CONFIG_GENERIC_PHY=y
-CONFIG_GENERIC_PINCONF=y
-CONFIG_GENERIC_PINCTRL_GROUPS=y
-CONFIG_GENERIC_PINMUX_FUNCTIONS=y
-CONFIG_GENERIC_SCHED_CLOCK=y
-CONFIG_GENERIC_SMP_IDLE_THREAD=y
-CONFIG_GENERIC_STRNCPY_FROM_USER=y
-CONFIG_GENERIC_STRNLEN_USER=y
-CONFIG_GENERIC_TIME_VSYSCALL=y
-CONFIG_GLOB=y
-CONFIG_GPIOLIB_IRQCHIP=y
-CONFIG_GPIO_CDEV=y
-CONFIG_GPIO_WATCHDOG=y
-# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
-CONFIG_GRO_CELLS=y
-CONFIG_HARDIRQS_SW_RESEND=y
-CONFIG_HAS_DMA=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_IOPORT_MAP=y
-CONFIG_HWMON=y
-CONFIG_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_QCOM=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_HELPER_AUTO=y
-# CONFIG_I2C_QCOM_CCI is not set
-CONFIG_I2C_QUP=y
-CONFIG_IIO=y
-CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_INTERCONNECT=y
-CONFIG_INTERCONNECT_CLK=y
-# CONFIG_INTERCONNECT_QCOM is not set
-CONFIG_IPQ_APSS_6018=y
-CONFIG_IPQ_APSS_PLL=y
-# CONFIG_IPQ_CMN_PLL is not set
-# CONFIG_IPQ_GCC_4019 is not set
-# CONFIG_IPQ_GCC_5018 is not set
-# CONFIG_IPQ_GCC_5332 is not set
-# CONFIG_IPQ_GCC_6018 is not set
-# CONFIG_IPQ_GCC_8074 is not set
-# CONFIG_IPQ_GCC_9574 is not set
-# CONFIG_IPQ_NSSCC_QCA8K is not set
-CONFIG_IRQCHIP=y
-CONFIG_IRQ_DOMAIN=y
-CONFIG_IRQ_DOMAIN_HIERARCHY=y
-CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y
-CONFIG_IRQ_FORCED_THREADING=y
-CONFIG_IRQ_MSI_LIB=y
-CONFIG_IRQ_WORK=y
-# CONFIG_KPSS_XCC is not set
-CONFIG_LEDS_TLC591XX=y
-CONFIG_LIBFDT=y
-CONFIG_LOCK_DEBUGGING_SUPPORT=y
-CONFIG_LOCK_SPIN_ON_OWNER=y
-CONFIG_LRU_GEN_WALKS_MMU=y
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-CONFIG_MAILBOX=y
-# CONFIG_MAILBOX_TEST is not set
-CONFIG_MDIO_BUS=y
-CONFIG_MDIO_DEVICE=y
-CONFIG_MDIO_DEVRES=y
-CONFIG_MDIO_IPQ4019=y
-# CONFIG_MFD_QCOM_RPM is not set
-CONFIG_MFD_SYSCON=y
-CONFIG_MIGRATION=y
-# CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY is not set
-CONFIG_MMC=y
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_BLOCK_MINORS=32
-CONFIG_MMC_CQHCI=y
-CONFIG_MMC_SDHCI=y
-CONFIG_MMC_SDHCI_IO_ACCESSORS=y
-CONFIG_MMC_SDHCI_MSM=y
-CONFIG_MMC_SDHCI_PLTFM=y
-CONFIG_MMU_LAZY_TLB_REFCOUNT=y
-CONFIG_MODULES_USE_ELF_RELA=y
-# CONFIG_MSM_GCC_8916 is not set
-# CONFIG_MSM_GCC_8917 is not set
-# CONFIG_MSM_GCC_8939 is not set
-# CONFIG_MSM_GCC_8976 is not set
-# CONFIG_MSM_GCC_8994 is not set
-# CONFIG_MSM_GCC_8996 is not set
-# CONFIG_MSM_GCC_8998 is not set
-# CONFIG_MSM_GPUCC_8998 is not set
-# CONFIG_MSM_MMCC_8996 is not set
-# CONFIG_MSM_MMCC_8998 is not set
-CONFIG_MTD_NAND_CORE=y
-CONFIG_MTD_NAND_ECC=y
-CONFIG_MTD_NAND_ECC_SW_HAMMING=y
-CONFIG_MTD_NAND_QCOM=y
-CONFIG_MTD_QCOMSMEM_PARTS=y
-CONFIG_MTD_RAW_NAND=y
-CONFIG_MTD_SPI_NOR=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_BEB_LIMIT=20
-CONFIG_MTD_UBI_BLOCK=y
-CONFIG_MTD_UBI_WL_THRESHOLD=4096
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_SG_DMA_LENGTH=y
-CONFIG_NET_DEVLINK=y
-CONFIG_NET_DSA=y
-CONFIG_NET_DSA_TAG_OOB=y
-CONFIG_NET_EGRESS=y
-CONFIG_NET_FLOW_LIMIT=y
-CONFIG_NET_INGRESS=y
-CONFIG_NET_SELFTESTS=y
-CONFIG_NET_XGRESS=y
-CONFIG_NLS=y
-CONFIG_NO_HZ_COMMON=y
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NR_CPUS=4
-# CONFIG_NSM is not set
-CONFIG_NVMEM=y
-CONFIG_NVMEM_LAYOUTS=y
-CONFIG_NVMEM_LAYOUT_ASCII_ENV=y
-CONFIG_NVMEM_LAYOUT_U_BOOT_ENV=y
-CONFIG_NVMEM_QCOM_QFPROM=y
-# CONFIG_NVMEM_QCOM_SEC_QFPROM is not set
-CONFIG_NVMEM_SYSFS=y
-CONFIG_OF=y
-CONFIG_OF_ADDRESS=y
-CONFIG_OF_EARLY_FLATTREE=y
-CONFIG_OF_FLATTREE=y
-CONFIG_OF_GPIO=y
-CONFIG_OF_IRQ=y
-CONFIG_OF_KOBJ=y
-CONFIG_OF_MDIO=y
-CONFIG_PADATA=y
-CONFIG_PAGE_POOL=y
-CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
-CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
-CONFIG_PARTITION_PERCPU=y
-CONFIG_PCI=y
-CONFIG_PCIEAER=y
-CONFIG_PCIEASPM=y
-CONFIG_PCIEASPM_DEFAULT=y
-# CONFIG_PCIEASPM_PERFORMANCE is not set
-# CONFIG_PCIEASPM_POWERSAVE is not set
-# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCIE_DW=y
-CONFIG_PCIE_DW_HOST=y
-CONFIG_PCIE_PME=y
-CONFIG_PCIE_QCOM=y
-CONFIG_PCIE_QCOM_COMMON=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_DOMAINS_GENERIC=y
-CONFIG_PCI_MSI=y
-CONFIG_PCS_QCA_UNIPHY=y
-CONFIG_PER_VMA_LOCK=y
-CONFIG_PGTABLE_LEVELS=3
-CONFIG_PHYLIB=y
-CONFIG_PHYLIB_LEDS=y
-CONFIG_PHYLINK=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-# CONFIG_PHY_QCOM_APQ8064_SATA is not set
-# CONFIG_PHY_QCOM_EDP is not set
-# CONFIG_PHY_QCOM_EUSB2_REPEATER is not set
-# CONFIG_PHY_QCOM_IPQ4019_USB is not set
-# CONFIG_PHY_QCOM_IPQ806X_SATA is not set
-# CONFIG_PHY_QCOM_IPQ806X_USB is not set
-# CONFIG_PHY_QCOM_M31_USB is not set
-# CONFIG_PHY_QCOM_PCIE2 is not set
-CONFIG_PHY_QCOM_QMP=y
-CONFIG_PHY_QCOM_QMP_COMBO=y
-CONFIG_PHY_QCOM_QMP_PCIE=y
-CONFIG_PHY_QCOM_QMP_PCIE_8996=y
-CONFIG_PHY_QCOM_QMP_UFS=y
-CONFIG_PHY_QCOM_QMP_USB=y
-# CONFIG_PHY_QCOM_QMP_USB_LEGACY is not set
-CONFIG_PHY_QCOM_QUSB2=y
-# CONFIG_PHY_QCOM_SGMII_ETH is not set
-# CONFIG_PHY_QCOM_SNPS_EUSB2 is not set
-# CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP is not set
-# CONFIG_PHY_QCOM_USB_HS_28NM is not set
-# CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2 is not set
-# CONFIG_PHY_QCOM_USB_SS is not set
-CONFIG_PINCTRL=y
-CONFIG_PINCTRL_AW9523=y
-# CONFIG_PINCTRL_IPQ5018 is not set
-# CONFIG_PINCTRL_IPQ5332 is not set
-# CONFIG_PINCTRL_IPQ6018 is not set
-# CONFIG_PINCTRL_IPQ8074 is not set
-# CONFIG_PINCTRL_IPQ9574 is not set
-CONFIG_PINCTRL_MSM=y
-# CONFIG_PINCTRL_MSM8916 is not set
-# CONFIG_PINCTRL_MSM8976 is not set
-# CONFIG_PINCTRL_MSM8994 is not set
-# CONFIG_PINCTRL_MSM8996 is not set
-# CONFIG_PINCTRL_MSM8998 is not set
-# CONFIG_PINCTRL_QCM2290 is not set
-# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
-# CONFIG_PINCTRL_QCS404 is not set
-# CONFIG_PINCTRL_QDU1000 is not set
-# CONFIG_PINCTRL_SA8775P is not set
-# CONFIG_PINCTRL_SC7180 is not set
-# CONFIG_PINCTRL_SC8280XP is not set
-# CONFIG_PINCTRL_SDM660 is not set
-# CONFIG_PINCTRL_SDM670 is not set
-# CONFIG_PINCTRL_SDM845 is not set
-# CONFIG_PINCTRL_SDX75 is not set
-# CONFIG_PINCTRL_SM4450 is not set
-# CONFIG_PINCTRL_SM6350 is not set
-# CONFIG_PINCTRL_SM6375 is not set
-# CONFIG_PINCTRL_SM7150 is not set
-# CONFIG_PINCTRL_SM8150 is not set
-# CONFIG_PINCTRL_SM8250 is not set
-# CONFIG_PINCTRL_SM8450 is not set
-# CONFIG_PINCTRL_SM8550 is not set
-# CONFIG_PINCTRL_SM8650 is not set
-# CONFIG_PINCTRL_X1E80100 is not set
-CONFIG_PM=y
-CONFIG_PM_CLK=y
-CONFIG_PM_OPP=y
-CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
-CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_GPIO=y
-# CONFIG_POWER_RESET_MSM is not set
-CONFIG_POWER_SUPPLY=y
-CONFIG_PRINTK_TIME=y
-CONFIG_PTP_1588_CLOCK_OPTIONAL=y
-CONFIG_QCA807X_PHY=y
-CONFIG_QCA808X_PHY=y
-# CONFIG_QCM_DISPCC_2290 is not set
-# CONFIG_QCM_GCC_2290 is not set
-# CONFIG_QCOM_80211AX_PPE is not set
-# CONFIG_QCOM_A53PLL is not set
-# CONFIG_QCOM_AOSS_QMP is not set
-CONFIG_QCOM_APCS_IPC=y
-# CONFIG_QCOM_APM is not set
-# CONFIG_QCOM_APR is not set
-CONFIG_QCOM_BAM_DMA=y
-# CONFIG_QCOM_CLK_APCC_MSM8996 is not set
-# CONFIG_QCOM_CLK_APCS_MSM8916 is not set
-# CONFIG_QCOM_COMMAND_DB is not set
-# CONFIG_QCOM_CPR is not set
-# CONFIG_QCOM_CPUCP_MBOX is not set
-# CONFIG_QCOM_EBI2 is not set
-# CONFIG_QCOM_EDMA is not set
-# CONFIG_QCOM_FASTRPC is not set
-# CONFIG_QCOM_GENI_SE is not set
-# CONFIG_QCOM_GSBI is not set
-# CONFIG_QCOM_HFPLL is not set
-# CONFIG_QCOM_ICC_BWMON is not set
-# CONFIG_QCOM_IPA is not set
-# CONFIG_QCOM_IPCC is not set
-# CONFIG_QCOM_LLCC is not set
-CONFIG_QCOM_MDT_LOADER=y
-# CONFIG_QCOM_MPM is not set
-CONFIG_QCOM_NET_PHYLIB=y
-# CONFIG_QCOM_OCMEM is not set
-# CONFIG_QCOM_PDC is not set
-CONFIG_QCOM_PIL_INFO=y
-# CONFIG_QCOM_Q6V5_ADSP is not set
-CONFIG_QCOM_Q6V5_COMMON=y
-# CONFIG_QCOM_Q6V5_MPD is not set
-# CONFIG_QCOM_Q6V5_MSS is not set
-# CONFIG_QCOM_Q6V5_PAS is not set
-CONFIG_QCOM_Q6V5_WCSS=y
-# CONFIG_QCOM_Q6V5_WCSS_SEC is not set
-# CONFIG_QCOM_QSEECOM is not set
-# CONFIG_QCOM_RAMP_CTRL is not set
-# CONFIG_QCOM_RMTFS_MEM is not set
-# CONFIG_QCOM_RPMH is not set
-# CONFIG_QCOM_RPM_MASTER_STATS is not set
-CONFIG_QCOM_RPROC_COMMON=y
-CONFIG_QCOM_SCM=y
-# CONFIG_QCOM_SMD_RPM is not set
-CONFIG_QCOM_SMEM=y
-CONFIG_QCOM_SMEM_STATE=y
-CONFIG_QCOM_SMP2P=y
-# CONFIG_QCOM_SMSM is not set
-CONFIG_QCOM_SOCINFO=y
-# CONFIG_QCOM_SPM is not set
-# CONFIG_QCOM_STATS is not set
-# CONFIG_QCOM_SYSMON is not set
-# CONFIG_QCOM_TMEL_QMP_MAILBOX is not set
-CONFIG_QCOM_TSENS=y
-CONFIG_QCOM_TZMEM=y
-CONFIG_QCOM_TZMEM_MODE_GENERIC=y
-# CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE is not set
-# CONFIG_QCOM_WCNSS_CTRL is not set
-# CONFIG_QCOM_WCNSS_PIL is not set
-CONFIG_QCOM_WDT=y
-# CONFIG_QCS_GCC_404 is not set
-# CONFIG_QCS_Q6SSTOP_404 is not set
-# CONFIG_QCS_TURING_404 is not set
-# CONFIG_QDU_ECPRICC_1000 is not set
-# CONFIG_QDU_GCC_1000 is not set
-CONFIG_QUEUED_RWLOCKS=y
-CONFIG_QUEUED_SPINLOCKS=y
-CONFIG_RANDSTRUCT_NONE=y
-CONFIG_RAS=y
-CONFIG_RATIONAL=y
-CONFIG_REGMAP=y
-CONFIG_REGMAP_I2C=y
-CONFIG_REGMAP_MMIO=y
-CONFIG_REGULATOR=y
-# CONFIG_REGULATOR_CPR3 is not set
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
-# CONFIG_REGULATOR_VQMMC_IPQ4019 is not set
-CONFIG_RELOCATABLE=y
-CONFIG_REMOTEPROC=y
-CONFIG_REMOTEPROC_CDEV=y
-CONFIG_RESET_CONTROLLER=y
-# CONFIG_RESET_QCOM_AOSS is not set
-# CONFIG_RESET_QCOM_PDC is not set
-CONFIG_RFS_ACCEL=y
-CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
-CONFIG_RPMSG=y
-CONFIG_RPMSG_CHAR=y
-# CONFIG_RPMSG_CTRL is not set
-# CONFIG_RPMSG_NS is not set
-CONFIG_RPMSG_QCOM_GLINK=y
-CONFIG_RPMSG_QCOM_GLINK_RPM=y
-CONFIG_RPMSG_QCOM_GLINK_SMEM=y
-CONFIG_RPMSG_QCOM_SMD=y
-# CONFIG_RPMSG_TTY is not set
-CONFIG_RPS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_I2C_AND_SPI=y
-CONFIG_RWSEM_SPIN_ON_OWNER=y
-# CONFIG_SA_GCC_8775P is not set
-# CONFIG_SA_GPUCC_8775P is not set
-# CONFIG_SCHED_CORE is not set
-CONFIG_SCHED_HW_PRESSURE=y
-CONFIG_SCHED_MC=y
-CONFIG_SCHED_SMT=y
-CONFIG_SCSI=y
-CONFIG_SCSI_COMMON=y
-# CONFIG_SCSI_LOWLEVEL is not set
-# CONFIG_SCSI_PROC_FS is not set
-# CONFIG_SC_CAMCC_7280 is not set
-# CONFIG_SC_CAMCC_8280XP is not set
-# CONFIG_SC_DISPCC_7180 is not set
-# CONFIG_SC_DISPCC_8280XP is not set
-# CONFIG_SC_GCC_7180 is not set
-# CONFIG_SC_GCC_8280XP is not set
-# CONFIG_SC_GPUCC_7180 is not set
-# CONFIG_SC_LPASSCC_7280 is not set
-# CONFIG_SC_LPASSCC_8280XP is not set
-# CONFIG_SC_LPASS_CORECC_7180 is not set
-# CONFIG_SC_LPASS_CORECC_7280 is not set
-# CONFIG_SC_VIDEOCC_7180 is not set
-# CONFIG_SDM_CAMCC_845 is not set
-# CONFIG_SDM_DISPCC_845 is not set
-# CONFIG_SDM_GCC_660 is not set
-# CONFIG_SDM_GCC_845 is not set
-# CONFIG_SDM_GPUCC_845 is not set
-# CONFIG_SDM_LPASSCC_845 is not set
-# CONFIG_SDM_VIDEOCC_845 is not set
-# CONFIG_SDX_GCC_75 is not set
-CONFIG_SERIAL_8250_FSL=y
-CONFIG_SERIAL_MCTRL_GPIO=y
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
-CONFIG_SGL_ALLOC=y
-CONFIG_SG_POOL=y
-CONFIG_SKB_EXTENSIONS=y
-CONFIG_SMP=y
-# CONFIG_SM_CAMCC_4450 is not set
-# CONFIG_SM_CAMCC_6350 is not set
-# CONFIG_SM_CAMCC_7150 is not set
-# CONFIG_SM_CAMCC_8150 is not set
-# CONFIG_SM_CAMCC_8450 is not set
-# CONFIG_SM_CAMCC_8550 is not set
-# CONFIG_SM_CAMCC_8650 is not set
-# CONFIG_SM_GCC_4450 is not set
-# CONFIG_SM_GCC_7150 is not set
-# CONFIG_SM_GCC_8150 is not set
-# CONFIG_SM_GCC_8250 is not set
-# CONFIG_SM_GCC_8450 is not set
-# CONFIG_SM_GCC_8550 is not set
-# CONFIG_SM_GCC_8650 is not set
-# CONFIG_SM_GPUCC_4450 is not set
-# CONFIG_SM_GPUCC_6115 is not set
-# CONFIG_SM_GPUCC_6125 is not set
-# CONFIG_SM_GPUCC_6350 is not set
-# CONFIG_SM_GPUCC_6375 is not set
-# CONFIG_SM_GPUCC_8150 is not set
-# CONFIG_SM_GPUCC_8250 is not set
-# CONFIG_SM_GPUCC_8350 is not set
-# CONFIG_SM_GPUCC_8450 is not set
-# CONFIG_SM_GPUCC_8550 is not set
-# CONFIG_SM_GPUCC_8650 is not set
-# CONFIG_SM_TCSRCC_8550 is not set
-# CONFIG_SM_TCSRCC_8650 is not set
-# CONFIG_SM_VIDEOCC_7150 is not set
-# CONFIG_SM_VIDEOCC_8150 is not set
-# CONFIG_SM_VIDEOCC_8250 is not set
-# CONFIG_SM_VIDEOCC_8350 is not set
-# CONFIG_SM_VIDEOCC_8450 is not set
-CONFIG_SOCK_RX_QUEUE_MAPPING=y
-CONFIG_SOC_BUS=y
-CONFIG_SOFTIRQ_ON_OWN_STACK=y
-CONFIG_SPARSEMEM=y
-CONFIG_SPARSEMEM_EXTREME=y
-CONFIG_SPARSEMEM_VMEMMAP=y
-CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
-CONFIG_SPARSE_IRQ=y
-CONFIG_SPI=y
-CONFIG_SPI_MASTER=y
-CONFIG_SPI_MEM=y
-# CONFIG_SPI_QPIC_SNAND is not set
-CONFIG_SPI_QUP=y
-CONFIG_SPLIT_PMD_PTLOCKS=y
-CONFIG_SPLIT_PTE_PTLOCKS=y
-CONFIG_SWIOTLB=y
-CONFIG_SWPHY=y
-CONFIG_SYSCTL_EXCEPTION_TRACE=y
-CONFIG_THERMAL=y
-CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
-CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
-CONFIG_THERMAL_GOV_STEP_WISE=y
-CONFIG_THERMAL_HWMON=y
-CONFIG_THERMAL_OF=y
-CONFIG_THREAD_INFO_IN_TASK=y
-CONFIG_TICK_CPU_ACCOUNTING=y
-CONFIG_TIMER_OF=y
-CONFIG_TIMER_PROBE=y
-CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
-CONFIG_TREE_RCU=y
-CONFIG_TREE_SRCU=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-# CONFIG_UCLAMP_TASK is not set
-CONFIG_UNMAP_KERNEL_AT_EL0=y
-CONFIG_USB=y
-CONFIG_USB_COMMON=y
-CONFIG_USB_SUPPORT=y
-CONFIG_USER_STACKTRACE_SUPPORT=y
-CONFIG_VDSO_GETRANDOM=y
-CONFIG_VIRTIO=y
-CONFIG_VIRTIO_ANCHOR=y
-# CONFIG_VIRTIO_BLK is not set
-# CONFIG_VIRTIO_DEBUG is not set
-# CONFIG_VIRTIO_NET is not set
-CONFIG_VMAP_STACK=y
-CONFIG_WANT_DEV_COREDUMP=y
-CONFIG_WATCHDOG_CORE=y
-CONFIG_WATCHDOG_SYSFS=y
-CONFIG_XPS=y
-CONFIG_XXHASH=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZONE_DMA32=y
-CONFIG_ZSTD_COMMON=y
-CONFIG_ZSTD_COMPRESS=y
-CONFIG_ZSTD_DECOMPRESS=y
diff --git a/target/linux/qualcommax/patches-6.12/0036-v6.13-arm64-dts-qcom-ipq-change-labels-to-lower-case.patch b/target/linux/qualcommax/patches-6.12/0036-v6.13-arm64-dts-qcom-ipq-change-labels-to-lower-case.patch
deleted file mode 100644 (file)
index 9dadee2..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-From 6f8c1ed25809181c187a59b1caaa1521756924bf Mon Sep 17 00:00:00 2001
-From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Date: Tue, 22 Oct 2024 17:47:26 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq: change labels to lower-case
-
-DTS coding style expects labels to be lowercase.  No functional impact.
-Verified with comparing decompiled DTB (dtx_diff and fdtdump+diff).
-
-Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Link: https://lore.kernel.org/r/20241022-dts-qcom-label-v3-1-0505bc7d2c56@linaro.org
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 10 +++---
- arch/arm64/boot/dts/qcom/ipq5332.dtsi | 18 +++++-----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 26 +++++++-------
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 18 +++++-----
- arch/arm64/boot/dts/qcom/ipq9574.dtsi | 50 +++++++++++++--------------
- 5 files changed, 61 insertions(+), 61 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -31,27 +31,27 @@
-               #address-cells = <1>;
-               #size-cells = <0>;
--              CPU0: cpu@0 {
-+              cpu0: cpu@0 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
--              CPU1: cpu@1 {
-+              cpu1: cpu@1 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x1>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
--              L2_0: l2-cache {
-+              l2_0: l2-cache {
-                       compatible = "cache";
-                       cache-level = <2>;
-                       cache-size = <0x80000>;
---- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi
-@@ -31,47 +31,47 @@
-               #address-cells = <1>;
-               #size-cells = <0>;
--              CPU0: cpu@0 {
-+              cpu0: cpu@0 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
--              CPU1: cpu@1 {
-+              cpu1: cpu@1 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x1>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
--              CPU2: cpu@2 {
-+              cpu2: cpu@2 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x2>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
--              CPU3: cpu@3 {
-+              cpu3: cpu@3 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x3>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
--              L2_0: l2-cache {
-+              l2_0: l2-cache {
-                       compatible = "cache";
-                       cache-level = <2>;
-                       cache-unified;
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -34,12 +34,12 @@
-               #address-cells = <1>;
-               #size-cells = <0>;
--              CPU0: cpu@0 {
-+              cpu0: cpu@0 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -47,12 +47,12 @@
-                       #cooling-cells = <2>;
-               };
--              CPU1: cpu@1 {
-+              cpu1: cpu@1 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       enable-method = "psci";
-                       reg = <0x1>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -60,12 +60,12 @@
-                       #cooling-cells = <2>;
-               };
--              CPU2: cpu@2 {
-+              cpu2: cpu@2 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       enable-method = "psci";
-                       reg = <0x2>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -73,12 +73,12 @@
-                       #cooling-cells = <2>;
-               };
--              CPU3: cpu@3 {
-+              cpu3: cpu@3 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       enable-method = "psci";
-                       reg = <0x3>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -86,7 +86,7 @@
-                       #cooling-cells = <2>;
-               };
--              L2_0: l2-cache {
-+              l2_0: l2-cache {
-                       compatible = "cache";
-                       cache-level = <2>;
-                       cache-unified;
-@@ -1015,10 +1015,10 @@
-                       cooling-maps {
-                               map0 {
-                                       trip = <&cpu_alert>;
--                                      cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-+                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               };
-                       };
-               };
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -32,39 +32,39 @@
-               #address-cells = <1>;
-               #size-cells = <0>;
--              CPU0: cpu@0 {
-+              cpu0: cpu@0 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       enable-method = "psci";
-               };
--              CPU1: cpu@1 {
-+              cpu1: cpu@1 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       enable-method = "psci";
-                       reg = <0x1>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-               };
--              CPU2: cpu@2 {
-+              cpu2: cpu@2 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       enable-method = "psci";
-                       reg = <0x2>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-               };
--              CPU3: cpu@3 {
-+              cpu3: cpu@3 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a53";
-                       enable-method = "psci";
-                       reg = <0x3>;
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-               };
--              L2_0: l2-cache {
-+              l2_0: l2-cache {
-                       compatible = "cache";
-                       cache-level = <2>;
-                       cache-unified;
---- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi
-@@ -34,12 +34,12 @@
-               #address-cells = <1>;
-               #size-cells = <0>;
--              CPU0: cpu@0 {
-+              cpu0: cpu@0 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a73";
-                       reg = <0x0>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -47,12 +47,12 @@
-                       #cooling-cells = <2>;
-               };
--              CPU1: cpu@1 {
-+              cpu1: cpu@1 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a73";
-                       reg = <0x1>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -60,12 +60,12 @@
-                       #cooling-cells = <2>;
-               };
--              CPU2: cpu@2 {
-+              cpu2: cpu@2 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a73";
-                       reg = <0x2>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -73,12 +73,12 @@
-                       #cooling-cells = <2>;
-               };
--              CPU3: cpu@3 {
-+              cpu3: cpu@3 {
-                       device_type = "cpu";
-                       compatible = "arm,cortex-a73";
-                       reg = <0x3>;
-                       enable-method = "psci";
--                      next-level-cache = <&L2_0>;
-+                      next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
-@@ -86,7 +86,7 @@
-                       #cooling-cells = <2>;
-               };
--              L2_0: l2-cache {
-+              l2_0: l2-cache {
-                       compatible = "cache";
-                       cache-level = <2>;
-                       cache-unified;
-@@ -865,10 +865,10 @@
-                       cooling-maps {
-                               map0 {
-                                       trip = <&cpu0_alert>;
--                                      cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-+                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               };
-                       };
-               };
-@@ -893,10 +893,10 @@
-                       cooling-maps {
-                               map0 {
-                                       trip = <&cpu1_alert>;
--                                      cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-+                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               };
-                       };
-               };
-@@ -921,10 +921,10 @@
-                       cooling-maps {
-                               map0 {
-                                       trip = <&cpu2_alert>;
--                                      cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-+                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               };
-                       };
-               };
-@@ -949,10 +949,10 @@
-                       cooling-maps {
-                               map0 {
-                                       trip = <&cpu3_alert>;
--                                      cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--                                                       <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-+                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               };
-                       };
-               };
diff --git a/target/linux/qualcommax/patches-6.12/0037-v6.16-arm64-dts-qcom-ipq6018-add-1.2GHz-CPU-Frequency.patch b/target/linux/qualcommax/patches-6.12/0037-v6.16-arm64-dts-qcom-ipq6018-add-1.2GHz-CPU-Frequency.patch
deleted file mode 100644 (file)
index 5a5a701..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From 144230e5840c09984ad743c3df9de5fb443159a9 Mon Sep 17 00:00:00 2001
-From: Chukun Pan <amadeus@jmu.edu.cn>
-Date: Mon, 10 Feb 2025 15:01:18 +0800
-Subject: [PATCH] arm64: dts: qcom: ipq6018: add 1.2GHz CPU Frequency
-
-The final version of IPQ6000 (SoC id: IPQ6000, SBL version:
-BOOT.XF.0.3-00086-IPQ60xxLZB-1) has a max design frequency
-of 1.2GHz, so add this CPU frequency.
-
-Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250210070122.208842-2-amadeus@jmu.edu.cn
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -119,6 +119,13 @@
-                       clock-latency-ns = <200000>;
-               };
-+              opp-1200000000 {
-+                      opp-hz = /bits/ 64 <1200000000>;
-+                      opp-microvolt = <850000>;
-+                      opp-supported-hw = <0x4>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-               opp-1320000000 {
-                       opp-hz = /bits/ 64 <1320000000>;
-                       opp-microvolt = <862500>;
diff --git a/target/linux/qualcommax/patches-6.12/0038-v6.16-arm64-dts-qcom-ipq6018-add-1.5GHz-CPU-Frequency.patch b/target/linux/qualcommax/patches-6.12/0038-v6.16-arm64-dts-qcom-ipq6018-add-1.5GHz-CPU-Frequency.patch
deleted file mode 100644 (file)
index f87356c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From a96e765a7b3f64429f7eec3471a2093355ab041e Mon Sep 17 00:00:00 2001
-From: Chukun Pan <amadeus@jmu.edu.cn>
-Date: Mon, 10 Feb 2025 15:01:19 +0800
-Subject: [PATCH] arm64: dts: qcom: ipq6018: add 1.5GHz CPU Frequency
-
-The early version of IPQ6000 (SoC id: IPQ6018, SBL version:
-BOOT.XF.0.3-00077-IPQ60xxLZB-2) and IPQ6005 SoCs can reach
-a max frequency of 1.5GHz, so add this CPU frequency.
-
-Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
-Link: https://lore.kernel.org/r/20250210070122.208842-3-amadeus@jmu.edu.cn
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -140,6 +140,13 @@
-                       clock-latency-ns = <200000>;
-               };
-+              opp-1512000000 {
-+                      opp-hz = /bits/ 64 <1512000000>;
-+                      opp-microvolt = <937500>;
-+                      opp-supported-hw = <0x2>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-               opp-1608000000 {
-                       opp-hz = /bits/ 64 <1608000000>;
-                       opp-microvolt = <987500>;
diff --git a/target/linux/qualcommax/patches-6.12/0039-v6.16-arm64-dts-qcom-ipq6018-move-mp5496-regulator-out-of-.patch b/target/linux/qualcommax/patches-6.12/0039-v6.16-arm64-dts-qcom-ipq6018-move-mp5496-regulator-out-of-.patch
deleted file mode 100644 (file)
index da39ae5..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-From 0c4c0f14b7d704bcb728d018a74788771dc9286b Mon Sep 17 00:00:00 2001
-From: Chukun Pan <amadeus@jmu.edu.cn>
-Date: Mon, 10 Feb 2025 15:01:20 +0800
-Subject: [PATCH] arm64: dts: qcom: ipq6018: move mp5496 regulator out of soc dtsi
-
-Some IPQ60xx SoCs don't come with the mp5496 pmic chip. The mp5496
-pmic was never part of the IPQ60xx SoC, it's optional, so we moved
-it out of the soc dtsi.
-
-Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Link: https://lore.kernel.org/r/20250210070122.208842-4-amadeus@jmu.edu.cn
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts |  2 +-
- arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi | 35 ++++++++++++++++++++++++++++
- arch/arm64/boot/dts/qcom/ipq6018.dtsi        | 14 -----------
- 3 files changed, 36 insertions(+), 15 deletions(-)
- create mode 100644 arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi
-
---- a/arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts
-+++ b/arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts
-@@ -7,7 +7,7 @@
- /dts-v1/;
--#include "ipq6018.dtsi"
-+#include "ipq6018-mp5496.dtsi"
- / {
-       model = "Qualcomm Technologies, Inc. IPQ6018/AP-CP01-C1";
---- /dev/null
-+++ b/arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi
-@@ -0,0 +1,35 @@
-+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-+/*
-+ * ipq6018-mp5496.dtsi describes common properties (e.g. regulators) that
-+ * apply to most devices that make use of the IPQ6018 SoC and MP5496 PMIC.
-+ */
-+
-+#include "ipq6018.dtsi"
-+
-+&cpu0 {
-+      cpu-supply = <&ipq6018_s2>;
-+};
-+
-+&cpu1 {
-+      cpu-supply = <&ipq6018_s2>;
-+};
-+
-+&cpu2 {
-+      cpu-supply = <&ipq6018_s2>;
-+};
-+
-+&cpu3 {
-+      cpu-supply = <&ipq6018_s2>;
-+};
-+
-+&rpm_requests {
-+      regulators {
-+              compatible = "qcom,rpm-mp5496-regulators";
-+
-+              ipq6018_s2: s2 {
-+                      regulator-min-microvolt = <725000>;
-+                      regulator-max-microvolt = <1062500>;
-+                      regulator-always-on;
-+              };
-+      };
-+};
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -43,7 +43,6 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
--                      cpu-supply = <&ipq6018_s2>;
-                       #cooling-cells = <2>;
-               };
-@@ -56,7 +55,6 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
--                      cpu-supply = <&ipq6018_s2>;
-                       #cooling-cells = <2>;
-               };
-@@ -69,7 +67,6 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
--                      cpu-supply = <&ipq6018_s2>;
-                       #cooling-cells = <2>;
-               };
-@@ -82,7 +79,6 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       operating-points-v2 = <&cpu_opp_table>;
--                      cpu-supply = <&ipq6018_s2>;
-                       #cooling-cells = <2>;
-               };
-@@ -184,16 +180,6 @@
-                       rpm_requests: rpm-requests {
-                               compatible = "qcom,rpm-ipq6018", "qcom,glink-smd-rpm";
-                               qcom,glink-channels = "rpm_requests";
--
--                              regulators {
--                                      compatible = "qcom,rpm-mp5496-regulators";
--
--                                      ipq6018_s2: s2 {
--                                              regulator-min-microvolt = <725000>;
--                                              regulator-max-microvolt = <1062500>;
--                                              regulator-always-on;
--                                      };
--                              };
-                       };
-               };
-       };
diff --git a/target/linux/qualcommax/patches-6.12/0040-v6.16-arm64-dts-qcom-ipq6018-rename-labels-of-mp5496-regul.patch b/target/linux/qualcommax/patches-6.12/0040-v6.16-arm64-dts-qcom-ipq6018-rename-labels-of-mp5496-regul.patch
deleted file mode 100644 (file)
index 120ce53..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-From e60f872c2dc4c1d9227977c8714373fe6328699c Mon Sep 17 00:00:00 2001
-From: Chukun Pan <amadeus@jmu.edu.cn>
-Date: Mon, 10 Feb 2025 15:01:21 +0800
-Subject: [PATCH] arm64: dts: qcom: ipq6018: rename labels of mp5496 regulator
-
-Change the labels of mp5496 regulator from ipq6018 to mp5496.
-
-Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
-Link: https://lore.kernel.org/r/20250210070122.208842-5-amadeus@jmu.edu.cn
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi
-@@ -7,26 +7,26 @@
- #include "ipq6018.dtsi"
- &cpu0 {
--      cpu-supply = <&ipq6018_s2>;
-+      cpu-supply = <&mp5496_s2>;
- };
- &cpu1 {
--      cpu-supply = <&ipq6018_s2>;
-+      cpu-supply = <&mp5496_s2>;
- };
- &cpu2 {
--      cpu-supply = <&ipq6018_s2>;
-+      cpu-supply = <&mp5496_s2>;
- };
- &cpu3 {
--      cpu-supply = <&ipq6018_s2>;
-+      cpu-supply = <&mp5496_s2>;
- };
- &rpm_requests {
-       regulators {
-               compatible = "qcom,rpm-mp5496-regulators";
--              ipq6018_s2: s2 {
-+              mp5496_s2: s2 {
-                       regulator-min-microvolt = <725000>;
-                       regulator-max-microvolt = <1062500>;
-                       regulator-always-on;
diff --git a/target/linux/qualcommax/patches-6.12/0041-v6.16-arm64-dts-qcom-ipq6018-add-LDOA2-regulator.patch b/target/linux/qualcommax/patches-6.12/0041-v6.16-arm64-dts-qcom-ipq6018-add-LDOA2-regulator.patch
deleted file mode 100644 (file)
index ce98c62..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From a566fb9ba8ffecb56c50729390a9ea076f5c9532 Mon Sep 17 00:00:00 2001
-From: Chukun Pan <amadeus@jmu.edu.cn>
-Date: Mon, 10 Feb 2025 15:01:22 +0800
-Subject: [PATCH] arm64: dts: qcom: ipq6018: add LDOA2 regulator
-
-Add LDOA2 regulator from MP5496 to support SDCC voltage scaling.
-
-Suggested-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250210070122.208842-6-amadeus@jmu.edu.cn
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018-mp5496.dtsi
-@@ -31,5 +31,14 @@
-                       regulator-max-microvolt = <1062500>;
-                       regulator-always-on;
-               };
-+
-+              mp5496_l2: l2 {
-+                      regulator-min-microvolt = <1800000>;
-+                      regulator-max-microvolt = <3300000>;
-+              };
-       };
- };
-+
-+&sdhc {
-+      vqmmc-supply = <&mp5496_l2>;
-+};
diff --git a/target/linux/qualcommax/patches-6.12/0045-v6.16-phy-qcom-Introduce-PCIe-UNIPHY-28LP-driver.patch b/target/linux/qualcommax/patches-6.12/0045-v6.16-phy-qcom-Introduce-PCIe-UNIPHY-28LP-driver.patch
deleted file mode 100644 (file)
index 622b388..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-From 74badb8b0b146668cc6c03eb58e2a814f9463d02 Mon Sep 17 00:00:00 2001
-From: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Date: Thu, 20 Feb 2025 15:12:46 +0530
-Subject: [PATCH] phy: qcom: Introduce PCIe UNIPHY 28LP driver
-
-Add Qualcomm PCIe UNIPHY 28LP driver support present in Qualcomm IPQ5332
-SoC and the phy init sequence.
-
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Signed-off-by: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
-Link: https://lore.kernel.org/r/20250220094251.230936-3-quic_varada@quicinc.com
-Signed-off-by: Vinod Koul <vkoul@kernel.org>
----
- drivers/phy/qualcomm/Kconfig                  |  12 +
- drivers/phy/qualcomm/Makefile                 |   1 +
- .../phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c  | 286 ++++++++++++++++++
- 3 files changed, 299 insertions(+)
- create mode 100644 drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-
---- a/drivers/phy/qualcomm/Kconfig
-+++ b/drivers/phy/qualcomm/Kconfig
-@@ -154,6 +154,18 @@ config PHY_QCOM_M31_USB
-         management. This driver is required even for peripheral only or
-         host only mode configurations.
-+config PHY_QCOM_UNIPHY_PCIE_28LP
-+      bool "PCIE UNIPHY 28LP PHY driver"
-+      depends on ARCH_QCOM
-+      depends on HAS_IOMEM
-+      depends on OF
-+      select GENERIC_PHY
-+      help
-+        Enable this to support the PCIe UNIPHY 28LP phy transceiver that
-+        is used with PCIe controllers on Qualcomm IPQ5332 chips. It
-+        handles PHY initialization, clock management required after
-+        resetting the hardware and power management.
-+
- config PHY_QCOM_USB_HS
-       tristate "Qualcomm USB HS PHY module"
-       depends on USB_ULPI_BUS
---- a/drivers/phy/qualcomm/Makefile
-+++ b/drivers/phy/qualcomm/Makefile
-@@ -17,6 +17,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY)        +=
- obj-$(CONFIG_PHY_QCOM_QUSB2)          += phy-qcom-qusb2.o
- obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2)     += phy-qcom-snps-eusb2.o
- obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
-+obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP)       += phy-qcom-uniphy-pcie-28lp.o
- obj-$(CONFIG_PHY_QCOM_USB_HS)                 += phy-qcom-usb-hs.o
- obj-$(CONFIG_PHY_QCOM_USB_HSIC)       += phy-qcom-usb-hsic.o
- obj-$(CONFIG_PHY_QCOM_USB_HS_28NM)    += phy-qcom-usb-hs-28nm.o
---- /dev/null
-+++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-@@ -0,0 +1,286 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (c) 2025, The Linux Foundation. All rights reserved.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/of.h>
-+#include <linux/phy/phy.h>
-+#include <linux/platform_device.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include <linux/units.h>
-+
-+#define RST_ASSERT_DELAY_MIN_US               100
-+#define RST_ASSERT_DELAY_MAX_US               150
-+#define PIPE_CLK_DELAY_MIN_US         5000
-+#define PIPE_CLK_DELAY_MAX_US         5100
-+#define CLK_EN_DELAY_MIN_US           30
-+#define CLK_EN_DELAY_MAX_US           50
-+#define CDR_CTRL_REG_1                0x80
-+#define CDR_CTRL_REG_2                0x84
-+#define CDR_CTRL_REG_3                0x88
-+#define CDR_CTRL_REG_4                0x8c
-+#define CDR_CTRL_REG_5                0x90
-+#define CDR_CTRL_REG_6                0x94
-+#define CDR_CTRL_REG_7                0x98
-+#define SSCG_CTRL_REG_1               0x9c
-+#define SSCG_CTRL_REG_2               0xa0
-+#define SSCG_CTRL_REG_3               0xa4
-+#define SSCG_CTRL_REG_4               0xa8
-+#define SSCG_CTRL_REG_5               0xac
-+#define SSCG_CTRL_REG_6               0xb0
-+#define PCS_INTERNAL_CONTROL_2        0x2d8
-+
-+#define PHY_CFG_PLLCFG                                0x220
-+#define PHY_CFG_EIOS_DTCT_REG                 0x3e4
-+#define PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME               0x3e8
-+
-+enum qcom_uniphy_pcie_type {
-+      PHY_TYPE_PCIE = 1,
-+      PHY_TYPE_PCIE_GEN2,
-+      PHY_TYPE_PCIE_GEN3,
-+};
-+
-+struct qcom_uniphy_pcie_regs {
-+      u32 offset;
-+      u32 val;
-+};
-+
-+struct qcom_uniphy_pcie_data {
-+      int lane_offset; /* offset between the lane register bases */
-+      u32 phy_type;
-+      const struct qcom_uniphy_pcie_regs *init_seq;
-+      u32 init_seq_num;
-+      u32 pipe_clk_rate;
-+};
-+
-+struct qcom_uniphy_pcie {
-+      struct phy phy;
-+      struct device *dev;
-+      const struct qcom_uniphy_pcie_data *data;
-+      struct clk_bulk_data *clks;
-+      int num_clks;
-+      struct reset_control *resets;
-+      void __iomem *base;
-+      int lanes;
-+};
-+
-+#define phy_to_dw_phy(x)      container_of((x), struct qca_uni_pcie_phy, phy)
-+
-+static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
-+      {
-+              .offset = PHY_CFG_PLLCFG,
-+              .val = 0x30,
-+      }, {
-+              .offset = PHY_CFG_EIOS_DTCT_REG,
-+              .val = 0x53ef,
-+      }, {
-+              .offset = PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME,
-+              .val = 0xcf,
-+      },
-+};
-+
-+static const struct qcom_uniphy_pcie_data ipq5332_data = {
-+      .lane_offset    = 0x800,
-+      .phy_type       = PHY_TYPE_PCIE_GEN3,
-+      .init_seq       = ipq5332_regs,
-+      .init_seq_num   = ARRAY_SIZE(ipq5332_regs),
-+      .pipe_clk_rate  = 250 * MEGA,
-+};
-+
-+static void qcom_uniphy_pcie_init(struct qcom_uniphy_pcie *phy)
-+{
-+      const struct qcom_uniphy_pcie_data *data = phy->data;
-+      const struct qcom_uniphy_pcie_regs *init_seq;
-+      void __iomem *base = phy->base;
-+      int lane, i;
-+
-+      for (lane = 0; lane < phy->lanes; lane++) {
-+              init_seq = data->init_seq;
-+
-+              for (i = 0; i < data->init_seq_num; i++)
-+                      writel(init_seq[i].val, base + init_seq[i].offset);
-+
-+              base += data->lane_offset;
-+      }
-+}
-+
-+static int qcom_uniphy_pcie_power_off(struct phy *x)
-+{
-+      struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
-+
-+      clk_bulk_disable_unprepare(phy->num_clks, phy->clks);
-+
-+      return reset_control_assert(phy->resets);
-+}
-+
-+static int qcom_uniphy_pcie_power_on(struct phy *x)
-+{
-+      struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
-+      int ret;
-+
-+      ret = reset_control_assert(phy->resets);
-+      if (ret) {
-+              dev_err(phy->dev, "reset assert failed (%d)\n", ret);
-+              return ret;
-+      }
-+
-+      usleep_range(RST_ASSERT_DELAY_MIN_US, RST_ASSERT_DELAY_MAX_US);
-+
-+      ret = reset_control_deassert(phy->resets);
-+      if (ret) {
-+              dev_err(phy->dev, "reset deassert failed (%d)\n", ret);
-+              return ret;
-+      }
-+
-+      usleep_range(PIPE_CLK_DELAY_MIN_US, PIPE_CLK_DELAY_MAX_US);
-+
-+      ret = clk_bulk_prepare_enable(phy->num_clks, phy->clks);
-+      if (ret) {
-+              dev_err(phy->dev, "clk prepare and enable failed %d\n", ret);
-+              return ret;
-+      }
-+
-+      usleep_range(CLK_EN_DELAY_MIN_US, CLK_EN_DELAY_MAX_US);
-+
-+      qcom_uniphy_pcie_init(phy);
-+
-+      return 0;
-+}
-+
-+static inline int qcom_uniphy_pcie_get_resources(struct platform_device *pdev,
-+                                               struct qcom_uniphy_pcie *phy)
-+{
-+      struct resource *res;
-+
-+      phy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-+      if (IS_ERR(phy->base))
-+              return PTR_ERR(phy->base);
-+
-+      phy->num_clks = devm_clk_bulk_get_all(phy->dev, &phy->clks);
-+      if (phy->num_clks < 0)
-+              return phy->num_clks;
-+
-+      phy->resets = devm_reset_control_array_get_exclusive(phy->dev);
-+      if (IS_ERR(phy->resets))
-+              return PTR_ERR(phy->resets);
-+
-+      return 0;
-+}
-+
-+/*
-+ * Register a fixed rate pipe clock.
-+ *
-+ * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
-+ * controls it. The <s>_pipe_clk coming out of the GCC is requested
-+ * by the PHY driver for its operations.
-+ * We register the <s>_pipe_clksrc here. The gcc driver takes care
-+ * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
-+ * Below picture shows this relationship.
-+ *
-+ *         +---------------+
-+ *         |   PHY block   |<<---------------------------------------+
-+ *         |               |                                         |
-+ *         |   +-------+   |                   +-----+               |
-+ *   I/P---^-->|  PLL  |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
-+ *    clk  |   +-------+   |                   +-----+
-+ *         +---------------+
-+ */
-+static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
-+{
-+      const struct qcom_uniphy_pcie_data *data = phy->data;
-+      struct clk_hw *hw;
-+      char name[64];
-+
-+      snprintf(name, sizeof(name), "phy%d_pipe_clk_src", id);
-+      hw = devm_clk_hw_register_fixed_rate(phy->dev, name, NULL, 0,
-+                                           data->pipe_clk_rate);
-+      if (IS_ERR(hw))
-+              return dev_err_probe(phy->dev, PTR_ERR(hw),
-+                                   "Unable to register %s\n", name);
-+
-+      return devm_of_clk_add_hw_provider(phy->dev, of_clk_hw_simple_get, hw);
-+}
-+
-+static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
-+      {
-+              .compatible = "qcom,ipq5332-uniphy-pcie-phy",
-+              .data = &ipq5332_data,
-+      }, {
-+              /* Sentinel */
-+      },
-+};
-+MODULE_DEVICE_TABLE(of, qcom_uniphy_pcie_id_table);
-+
-+static const struct phy_ops pcie_ops = {
-+      .power_on       = qcom_uniphy_pcie_power_on,
-+      .power_off      = qcom_uniphy_pcie_power_off,
-+      .owner          = THIS_MODULE,
-+};
-+
-+static int qcom_uniphy_pcie_probe(struct platform_device *pdev)
-+{
-+      struct phy_provider *phy_provider;
-+      struct device *dev = &pdev->dev;
-+      struct qcom_uniphy_pcie *phy;
-+      struct phy *generic_phy;
-+      int ret;
-+
-+      phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
-+      if (!phy)
-+              return -ENOMEM;
-+
-+      platform_set_drvdata(pdev, phy);
-+      phy->dev = &pdev->dev;
-+
-+      phy->data = of_device_get_match_data(dev);
-+      if (!phy->data)
-+              return -EINVAL;
-+
-+      ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &phy->lanes);
-+      if (ret)
-+              return dev_err_probe(dev, ret, "Couldn't read num-lanes\n");
-+
-+      ret = qcom_uniphy_pcie_get_resources(pdev, phy);
-+      if (ret < 0)
-+              return dev_err_probe(&pdev->dev, ret,
-+                                   "failed to get resources: %d\n", ret);
-+
-+      generic_phy = devm_phy_create(phy->dev, NULL, &pcie_ops);
-+      if (IS_ERR(generic_phy))
-+              return PTR_ERR(generic_phy);
-+
-+      phy_set_drvdata(generic_phy, phy);
-+
-+      ret = phy_pipe_clk_register(phy, generic_phy->id);
-+      if (ret)
-+              dev_err(&pdev->dev, "failed to register phy pipe clk\n");
-+
-+      phy_provider = devm_of_phy_provider_register(phy->dev,
-+                                                   of_phy_simple_xlate);
-+      if (IS_ERR(phy_provider))
-+              return PTR_ERR(phy_provider);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver qcom_uniphy_pcie_driver = {
-+      .probe          = qcom_uniphy_pcie_probe,
-+      .driver         = {
-+              .name   = "qcom-uniphy-pcie",
-+              .of_match_table = qcom_uniphy_pcie_id_table,
-+      },
-+};
-+
-+module_platform_driver(qcom_uniphy_pcie_driver);
-+
-+MODULE_DESCRIPTION("PCIE QCOM UNIPHY driver");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/qualcommax/patches-6.12/0046-v6.16-phy-qualcomm-qcom-uniphy-pcie-28LP-add-support-for-I.patch b/target/linux/qualcommax/patches-6.12/0046-v6.16-phy-qualcomm-qcom-uniphy-pcie-28LP-add-support-for-I.patch
deleted file mode 100644 (file)
index 4c727fc..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-From dfc820d2f8a8ea90bbc02269b5362e3678e58cac Mon Sep 17 00:00:00 2001
-From: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Date: Wed, 26 Mar 2025 12:10:56 +0400
-Subject: [PATCH] phy: qualcomm: qcom-uniphy-pcie 28LP add support for IPQ5018
-
-The Qualcomm UNIPHY PCIe PHY 28LP is found on both IPQ5332 and IPQ5018.
-Adding the PHY init sequence, pipe clock rate, and compatible for IPQ5018.
-
-Signed-off-by: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250326-ipq5018-pcie-v7-2-e1828fef06c9@outlook.com
-Signed-off-by: Vinod Koul <vkoul@kernel.org>
----
- .../phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c  | 45 +++++++++++++++++++
- 1 file changed, 45 insertions(+)
-
---- a/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-+++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-@@ -75,6 +75,40 @@ struct qcom_uniphy_pcie {
- #define phy_to_dw_phy(x)      container_of((x), struct qca_uni_pcie_phy, phy)
-+static const struct qcom_uniphy_pcie_regs ipq5018_regs[] = {
-+      {
-+              .offset = SSCG_CTRL_REG_4,
-+              .val = 0x1cb9,
-+      }, {
-+              .offset = SSCG_CTRL_REG_5,
-+              .val = 0x023a,
-+      }, {
-+              .offset = SSCG_CTRL_REG_3,
-+              .val = 0xd360,
-+      }, {
-+              .offset = SSCG_CTRL_REG_1,
-+              .val = 0x1,
-+      }, {
-+              .offset = SSCG_CTRL_REG_2,
-+              .val = 0xeb,
-+      }, {
-+              .offset = CDR_CTRL_REG_4,
-+              .val = 0x3f9,
-+      }, {
-+              .offset = CDR_CTRL_REG_5,
-+              .val = 0x1c9,
-+      }, {
-+              .offset = CDR_CTRL_REG_2,
-+              .val = 0x419,
-+      }, {
-+              .offset = CDR_CTRL_REG_1,
-+              .val = 0x200,
-+      }, {
-+              .offset = PCS_INTERNAL_CONTROL_2,
-+              .val = 0xf101,
-+      },
-+};
-+
- static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
-       {
-               .offset = PHY_CFG_PLLCFG,
-@@ -88,6 +122,14 @@ static const struct qcom_uniphy_pcie_reg
-       },
- };
-+static const struct qcom_uniphy_pcie_data ipq5018_data = {
-+      .lane_offset    = 0x800,
-+      .phy_type       = PHY_TYPE_PCIE_GEN2,
-+      .init_seq       = ipq5018_regs,
-+      .init_seq_num   = ARRAY_SIZE(ipq5018_regs),
-+      .pipe_clk_rate  = 125 * MEGA,
-+};
-+
- static const struct qcom_uniphy_pcie_data ipq5332_data = {
-       .lane_offset    = 0x800,
-       .phy_type       = PHY_TYPE_PCIE_GEN3,
-@@ -212,6 +254,9 @@ static inline int phy_pipe_clk_register(
- static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
-       {
-+              .compatible = "qcom,ipq5018-uniphy-pcie-phy",
-+              .data = &ipq5018_data,
-+      }, {
-               .compatible = "qcom,ipq5332-uniphy-pcie-phy",
-               .data = &ipq5332_data,
-       }, {
diff --git a/target/linux/qualcommax/patches-6.12/0047-v6.16-PCI-qcom-Add-support-for-IPQ5018.patch b/target/linux/qualcommax/patches-6.12/0047-v6.16-PCI-qcom-Add-support-for-IPQ5018.patch
deleted file mode 100644 (file)
index de1277a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From 3e5127469a8d41153fb30031a271788f52dd17ec Mon Sep 17 00:00:00 2001
-From: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Date: Wed, 26 Mar 2025 12:10:58 +0400
-Subject: [PATCH] PCI: qcom: Add support for IPQ5018
-
-Add IPQ5018 platform with is based on Qcom IP rev. 2.9.0 and Synopsys IP
-rev. 5.00a.
-
-The platform itself has two PCIe Gen2 controllers: one single-lane and
-one dual-lane. So add the IPQ5018 compatible and re-use 2_9_0 ops.
-
-Signed-off-by: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-Link: https://patch.msgid.link/20250326-ipq5018-pcie-v7-4-e1828fef06c9@outlook.com
----
- drivers/pci/controller/dwc/pcie-qcom.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/pci/controller/dwc/pcie-qcom.c
-+++ b/drivers/pci/controller/dwc/pcie-qcom.c
-@@ -1838,6 +1838,7 @@ static const struct of_device_id qcom_pc
-       { .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
-       { .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
-       { .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
-+      { .compatible = "qcom,pcie-ipq5018", .data = &cfg_2_9_0 },
-       { .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 },
-       { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
-       { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
diff --git a/target/linux/qualcommax/patches-6.12/0048-v6.16-arm64-dts-qcom-ipq5018-Add-PCIe-related-nodes.patch b/target/linux/qualcommax/patches-6.12/0048-v6.16-arm64-dts-qcom-ipq5018-Add-PCIe-related-nodes.patch
deleted file mode 100644 (file)
index a7fceeb..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-From 18a5bf00a02ca54d51266b861518f2844c4f08d7 Mon Sep 17 00:00:00 2001
-From: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Date: Wed, 14 May 2025 09:52:13 +0400
-Subject: [PATCH] arm64: dts: qcom: ipq5018: Add PCIe related nodes
-
-Add phy and controller nodes for a 2-lane Gen2 and
-a 1-lane Gen2 PCIe bus. IPQ5018 has 8 MSI SPI interrupts and
-one global interrupt.
-
-NOTE: the PCIe controller supports gen3, yet the phy is limited to gen2.
-
-Signed-off-by: Nitheesh Sekar <quic_nsekar@quicinc.com>
-Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
-Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250514-ipq5018-pcie-v10-1-5b42a8eff7ea@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 240 +++++++++++++++++++++++++-
- 1 file changed, 238 insertions(+), 2 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -147,6 +147,40 @@
-                       status = "disabled";
-               };
-+              pcie1_phy: phy@7e000 {
-+                      compatible = "qcom,ipq5018-uniphy-pcie-phy";
-+                      reg = <0x0007e000 0x800>;
-+
-+                      clocks = <&gcc GCC_PCIE1_PIPE_CLK>;
-+
-+                      resets = <&gcc GCC_PCIE1_PHY_BCR>,
-+                               <&gcc GCC_PCIE1PHY_PHY_BCR>;
-+
-+                      #clock-cells = <0>;
-+                      #phy-cells = <0>;
-+
-+                      num-lanes = <1>;
-+
-+                      status = "disabled";
-+              };
-+
-+              pcie0_phy: phy@86000 {
-+                      compatible = "qcom,ipq5018-uniphy-pcie-phy";
-+                      reg = <0x00086000 0x1000>;
-+
-+                      clocks = <&gcc GCC_PCIE0_PIPE_CLK>;
-+
-+                      resets = <&gcc GCC_PCIE0_PHY_BCR>,
-+                               <&gcc GCC_PCIE0PHY_PHY_BCR>;
-+
-+                      #clock-cells = <0>;
-+                      #phy-cells = <0>;
-+
-+                      num-lanes = <2>;
-+
-+                      status = "disabled";
-+              };
-+
-               tlmm: pinctrl@1000000 {
-                       compatible = "qcom,ipq5018-tlmm";
-                       reg = <0x01000000 0x300000>;
-@@ -170,8 +204,8 @@
-                       reg = <0x01800000 0x80000>;
-                       clocks = <&xo_board_clk>,
-                                <&sleep_clk>,
--                               <0>,
--                               <0>,
-+                               <&pcie0_phy>,
-+                               <&pcie1_phy>,
-                                <0>,
-                                <0>,
-                                <0>,
-@@ -387,6 +421,208 @@
-                               status = "disabled";
-                       };
-               };
-+
-+              pcie1: pcie@80000000 {
-+                      compatible = "qcom,pcie-ipq5018";
-+                      reg = <0x80000000 0xf1d>,
-+                            <0x80000f20 0xa8>,
-+                            <0x80001000 0x1000>,
-+                            <0x00078000 0x3000>,
-+                            <0x80100000 0x1000>,
-+                            <0x0007b000 0x1000>;
-+                      reg-names = "dbi",
-+                                  "elbi",
-+                                  "atu",
-+                                  "parf",
-+                                  "config",
-+                                  "mhi";
-+                      device_type = "pci";
-+                      linux,pci-domain = <1>;
-+                      bus-range = <0x00 0xff>;
-+                      num-lanes = <1>;
-+                      #address-cells = <3>;
-+                      #size-cells = <2>;
-+
-+                      /* The controller supports Gen3, but the connected PHY is Gen2-capable */
-+                      max-link-speed = <2>;
-+
-+                      phys = <&pcie1_phy>;
-+                      phy-names ="pciephy";
-+
-+                      ranges = <0x01000000 0 0x00000000 0x80200000 0 0x00100000>,
-+                               <0x02000000 0 0x80300000 0x80300000 0 0x10000000>;
-+
-+                      msi-map = <0x0 &v2m0 0x0 0xff8>;
-+
-+                      interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
-+                      interrupt-names = "msi0",
-+                                        "msi1",
-+                                        "msi2",
-+                                        "msi3",
-+                                        "msi4",
-+                                        "msi5",
-+                                        "msi6",
-+                                        "msi7",
-+                                        "global";
-+
-+                      #interrupt-cells = <1>;
-+                      interrupt-map-mask = <0 0 0 0x7>;
-+                      interrupt-map = <0 0 0 1 &intc 0 0 142 IRQ_TYPE_LEVEL_HIGH>,
-+                                      <0 0 0 2 &intc 0 0 143 IRQ_TYPE_LEVEL_HIGH>,
-+                                      <0 0 0 3 &intc 0 0 144 IRQ_TYPE_LEVEL_HIGH>,
-+                                      <0 0 0 4 &intc 0 0 145 IRQ_TYPE_LEVEL_HIGH>;
-+
-+                      clocks = <&gcc GCC_SYS_NOC_PCIE1_AXI_CLK>,
-+                               <&gcc GCC_PCIE1_AXI_M_CLK>,
-+                               <&gcc GCC_PCIE1_AXI_S_CLK>,
-+                               <&gcc GCC_PCIE1_AHB_CLK>,
-+                               <&gcc GCC_PCIE1_AUX_CLK>,
-+                               <&gcc GCC_PCIE1_AXI_S_BRIDGE_CLK>;
-+                      clock-names = "iface",
-+                                    "axi_m",
-+                                    "axi_s",
-+                                    "ahb",
-+                                    "aux",
-+                                    "axi_bridge";
-+
-+                      resets = <&gcc GCC_PCIE1_PIPE_ARES>,
-+                               <&gcc GCC_PCIE1_SLEEP_ARES>,
-+                               <&gcc GCC_PCIE1_CORE_STICKY_ARES>,
-+                               <&gcc GCC_PCIE1_AXI_MASTER_ARES>,
-+                               <&gcc GCC_PCIE1_AXI_SLAVE_ARES>,
-+                               <&gcc GCC_PCIE1_AHB_ARES>,
-+                               <&gcc GCC_PCIE1_AXI_MASTER_STICKY_ARES>,
-+                               <&gcc GCC_PCIE1_AXI_SLAVE_STICKY_ARES>;
-+                      reset-names = "pipe",
-+                                    "sleep",
-+                                    "sticky",
-+                                    "axi_m",
-+                                    "axi_s",
-+                                    "ahb",
-+                                    "axi_m_sticky",
-+                                    "axi_s_sticky";
-+
-+                      status = "disabled";
-+
-+                      pcie@0 {
-+                              device_type = "pci";
-+                              reg = <0x0 0x0 0x0 0x0 0x0>;
-+                              bus-range = <0x01 0xff>;
-+
-+                              #address-cells = <3>;
-+                              #size-cells = <2>;
-+                              ranges;
-+                      };
-+              };
-+
-+              pcie0: pcie@a0000000 {
-+                      compatible = "qcom,pcie-ipq5018";
-+                      reg = <0xa0000000 0xf1d>,
-+                            <0xa0000f20 0xa8>,
-+                            <0xa0001000 0x1000>,
-+                            <0x00080000 0x3000>,
-+                            <0xa0100000 0x1000>,
-+                            <0x00083000 0x1000>;
-+                      reg-names = "dbi",
-+                                  "elbi",
-+                                  "atu",
-+                                  "parf",
-+                                  "config",
-+                                  "mhi";
-+                      device_type = "pci";
-+                      linux,pci-domain = <0>;
-+                      bus-range = <0x00 0xff>;
-+                      num-lanes = <2>;
-+                      #address-cells = <3>;
-+                      #size-cells = <2>;
-+
-+                      /* The controller supports Gen3, but the connected PHY is Gen2-capable */
-+                      max-link-speed = <2>;
-+
-+                      phys = <&pcie0_phy>;
-+                      phy-names ="pciephy";
-+
-+                      ranges = <0x01000000 0 0x00000000 0xa0200000 0 0x00100000>,
-+                               <0x02000000 0 0xa0300000 0xa0300000 0 0x10000000>;
-+
-+                      msi-map = <0x0 &v2m0 0x0 0xff8>;
-+
-+                      interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
-+                      interrupt-names = "msi0",
-+                                        "msi1",
-+                                        "msi2",
-+                                        "msi3",
-+                                        "msi4",
-+                                        "msi5",
-+                                        "msi6",
-+                                        "msi7",
-+                                        "global";
-+
-+                      #interrupt-cells = <1>;
-+                      interrupt-map-mask = <0 0 0 0x7>;
-+                      interrupt-map = <0 0 0 1 &intc 0 0 75 IRQ_TYPE_LEVEL_HIGH>,
-+                                      <0 0 0 2 &intc 0 0 78 IRQ_TYPE_LEVEL_HIGH>,
-+                                      <0 0 0 3 &intc 0 0 79 IRQ_TYPE_LEVEL_HIGH>,
-+                                      <0 0 0 4 &intc 0 0 83 IRQ_TYPE_LEVEL_HIGH>;
-+
-+                      clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>,
-+                               <&gcc GCC_PCIE0_AXI_M_CLK>,
-+                               <&gcc GCC_PCIE0_AXI_S_CLK>,
-+                               <&gcc GCC_PCIE0_AHB_CLK>,
-+                               <&gcc GCC_PCIE0_AUX_CLK>,
-+                               <&gcc GCC_PCIE0_AXI_S_BRIDGE_CLK>;
-+                      clock-names = "iface",
-+                                    "axi_m",
-+                                    "axi_s",
-+                                    "ahb",
-+                                    "aux",
-+                                    "axi_bridge";
-+
-+                      resets = <&gcc GCC_PCIE0_PIPE_ARES>,
-+                               <&gcc GCC_PCIE0_SLEEP_ARES>,
-+                               <&gcc GCC_PCIE0_CORE_STICKY_ARES>,
-+                               <&gcc GCC_PCIE0_AXI_MASTER_ARES>,
-+                               <&gcc GCC_PCIE0_AXI_SLAVE_ARES>,
-+                               <&gcc GCC_PCIE0_AHB_ARES>,
-+                               <&gcc GCC_PCIE0_AXI_MASTER_STICKY_ARES>,
-+                               <&gcc GCC_PCIE0_AXI_SLAVE_STICKY_ARES>;
-+                      reset-names = "pipe",
-+                                    "sleep",
-+                                    "sticky",
-+                                    "axi_m",
-+                                    "axi_s",
-+                                    "ahb",
-+                                    "axi_m_sticky",
-+                                    "axi_s_sticky";
-+
-+                      status = "disabled";
-+
-+                      pcie@0 {
-+                              device_type = "pci";
-+                              reg = <0x0 0x0 0x0 0x0 0x0>;
-+                              bus-range = <0x01 0xff>;
-+
-+                              #address-cells = <3>;
-+                              #size-cells = <2>;
-+                              ranges;
-+                      };
-+              };
-       };
-       timer {
diff --git a/target/linux/qualcommax/patches-6.12/0049-v6.16-arm64-dts-qcom-ipq5018-enable-the-download-mode-supp.patch b/target/linux/qualcommax/patches-6.12/0049-v6.16-arm64-dts-qcom-ipq5018-enable-the-download-mode-supp.patch
deleted file mode 100644 (file)
index 0820051..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 43fefd6c71291b5793e7c4052b6e3e54d1d87715 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 12 May 2025 18:36:47 +0400
-Subject: [PATCH] arm64: dts: qcom: ipq5018: enable the download mode support
-
-Enable support for download mode to collect RAM dumps in case of a
-system crash, allowing post mortem analysis.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250512-ipq5018-syscon-v1-2-eb1ad2414c3c@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -79,6 +79,7 @@
-       firmware {
-               scm {
-                       compatible = "qcom,scm-ipq5018", "qcom,scm";
-+                      qcom,dload-mode = <&tcsr 0x6100>;
-                       qcom,sdi-enabled;
-               };
-       };
-@@ -221,6 +222,11 @@
-                       #hwlock-cells = <1>;
-               };
-+              tcsr: syscon@1937000 {
-+                      compatible = "qcom,tcsr-ipq5018", "syscon";
-+                      reg = <0x01937000 0x21000>;
-+              };
-+
-               sdhc_1: mmc@7804000 {
-                       compatible = "qcom,ipq5018-sdhci", "qcom,sdhci-msm-v5";
-                       reg = <0x7804000 0x1000>;
diff --git a/target/linux/qualcommax/patches-6.12/0050-v6.15-thermal-drivers-tsens-Add-TSENS-enable-and-calibrati.patch b/target/linux/qualcommax/patches-6.12/0050-v6.15-thermal-drivers-tsens-Add-TSENS-enable-and-calibrati.patch
deleted file mode 100644 (file)
index bf67555..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-From ff0cf0ab9073727a67f9902dba77a758654ae895 Mon Sep 17 00:00:00 2001
-From: Praveenkumar I <quic_ipkumar@quicinc.com>
-Date: Mon, 10 Feb 2025 17:34:32 +0530
-Subject: [PATCH] thermal/drivers/tsens: Add TSENS enable and calibration
- support for V2
-
-SoCs without RPM need to enable sensors and calibrate them from the kernel.
-The IPQ5332 and IPQ5424 use the tsens v2.3.3 IP and do not have RPM.
-Therefore, add a new calibration function for V2, as the tsens.c calib
-function only supports V1. Also add new feature_config, ops and data for
-IPQ5332, IPQ5424.
-
-Although the TSENS IP supports 16 sensors, not all are used. The hw_id
-is used to enable the relevant sensors.
-
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Signed-off-by: Praveenkumar I <quic_ipkumar@quicinc.com>
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Link: https://lore.kernel.org/r/20250210120436.821684-3-quic_mmanikan@quicinc.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens-v2.c | 178 ++++++++++++++++++++++++++++++++
- drivers/thermal/qcom/tsens.c    |   8 +-
- drivers/thermal/qcom/tsens.h    |   3 +
- 3 files changed, 188 insertions(+), 1 deletion(-)
-
---- a/drivers/thermal/qcom/tsens-v2.c
-+++ b/drivers/thermal/qcom/tsens-v2.c
-@@ -4,13 +4,32 @@
-  * Copyright (c) 2018, Linaro Limited
-  */
-+#include <linux/bitfield.h>
- #include <linux/bitops.h>
-+#include <linux/nvmem-consumer.h>
- #include <linux/regmap.h>
- #include "tsens.h"
- /* ----- SROT ------ */
- #define SROT_HW_VER_OFF       0x0000
- #define SROT_CTRL_OFF         0x0004
-+#define SROT_MEASURE_PERIOD   0x0008
-+#define SROT_Sn_CONVERSION    0x0060
-+#define V2_SHIFT_DEFAULT      0x0003
-+#define V2_SLOPE_DEFAULT      0x0cd0
-+#define V2_CZERO_DEFAULT      0x016a
-+#define ONE_PT_SLOPE          0x0cd0
-+#define TWO_PT_SHIFTED_GAIN   921600
-+#define ONE_PT_CZERO_CONST    94
-+#define SW_RST_DEASSERT               0x0
-+#define SW_RST_ASSERT         0x1
-+#define MEASURE_PERIOD_2mSEC  0x1
-+#define RESULT_FORMAT_TEMP    0x1
-+#define TSENS_ENABLE          0x1
-+#define SENSOR_CONVERSION(n)  (((n) * 4) + SROT_Sn_CONVERSION)
-+#define CONVERSION_SHIFT_MASK GENMASK(24, 23)
-+#define CONVERSION_SLOPE_MASK GENMASK(22, 10)
-+#define CONVERSION_CZERO_MASK GENMASK(9, 0)
- /* ----- TM ------ */
- #define TM_INT_EN_OFF                 0x0004
-@@ -50,6 +69,17 @@ static struct tsens_features ipq8074_fea
-       .trip_max_temp  = 204000,
- };
-+static struct tsens_features ipq5332_feat = {
-+      .ver_major      = VER_2_X_NO_RPM,
-+      .crit_int       = 1,
-+      .combo_int      = 1,
-+      .adc            = 0,
-+      .srot_split     = 1,
-+      .max_sensors    = 16,
-+      .trip_min_temp  = 0,
-+      .trip_max_temp  = 204000,
-+};
-+
- static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
-       /* ----- SROT ------ */
-       /* VERSION */
-@@ -59,6 +89,10 @@ static const struct reg_field tsens_v2_r
-       /* CTRL_OFF */
-       [TSENS_EN]     = REG_FIELD(SROT_CTRL_OFF,    0,  0),
-       [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF,    1,  1),
-+      [SENSOR_EN]    = REG_FIELD(SROT_CTRL_OFF,    3,  18),
-+      [CODE_OR_TEMP] = REG_FIELD(SROT_CTRL_OFF,    21, 21),
-+
-+      [MAIN_MEASURE_PERIOD] = REG_FIELD(SROT_MEASURE_PERIOD, 0, 7),
-       /* ----- TM ------ */
-       /* INTERRUPT ENABLE */
-@@ -104,6 +138,128 @@ static const struct reg_field tsens_v2_r
-       [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
- };
-+static int tsens_v2_calibrate_sensor(struct device *dev, struct tsens_sensor *sensor,
-+                                   struct regmap *map,  u32 mode, u32 base0, u32 base1)
-+{
-+      u32     shift = V2_SHIFT_DEFAULT;
-+      u32     slope = V2_SLOPE_DEFAULT;
-+      u32     czero = V2_CZERO_DEFAULT;
-+      char    name[20];
-+      u32     val;
-+      int     ret;
-+
-+      /* Read offset value */
-+      ret = snprintf(name, sizeof(name), "tsens_sens%d_off", sensor->hw_id);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = nvmem_cell_read_variable_le_u32(dev, name, &sensor->offset);
-+      if (ret)
-+              return ret;
-+
-+      /* Based on calib mode, program SHIFT, SLOPE and CZERO */
-+      switch (mode) {
-+      case TWO_PT_CALIB:
-+              slope = (TWO_PT_SHIFTED_GAIN / (base1 - base0));
-+
-+              czero = (base0 + sensor->offset - ((base1 - base0) / 3));
-+
-+              break;
-+      case ONE_PT_CALIB2:
-+              czero = base0 + sensor->offset - ONE_PT_CZERO_CONST;
-+
-+              slope = ONE_PT_SLOPE;
-+
-+              break;
-+      default:
-+              dev_dbg(dev, "calibrationless mode\n");
-+      }
-+
-+      val = FIELD_PREP(CONVERSION_SHIFT_MASK, shift) |
-+            FIELD_PREP(CONVERSION_SLOPE_MASK, slope) |
-+            FIELD_PREP(CONVERSION_CZERO_MASK, czero);
-+
-+      regmap_write(map, SENSOR_CONVERSION(sensor->hw_id), val);
-+
-+      return 0;
-+}
-+
-+static int tsens_v2_calibration(struct tsens_priv *priv)
-+{
-+      struct device *dev = priv->dev;
-+      u32 mode, base0, base1;
-+      int i, ret;
-+
-+      if (priv->num_sensors > MAX_SENSORS)
-+              return -EINVAL;
-+
-+      ret = nvmem_cell_read_variable_le_u32(priv->dev, "mode", &mode);
-+      if (ret == -ENOENT)
-+              dev_warn(priv->dev, "Calibration data not present in DT\n");
-+      if (ret < 0)
-+              return ret;
-+
-+      dev_dbg(priv->dev, "calibration mode is %d\n", mode);
-+
-+      ret = nvmem_cell_read_variable_le_u32(priv->dev, "base0", &base0);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = nvmem_cell_read_variable_le_u32(priv->dev, "base1", &base1);
-+      if (ret < 0)
-+              return ret;
-+
-+      /* Calibrate each sensor */
-+      for (i = 0; i < priv->num_sensors; i++) {
-+              ret = tsens_v2_calibrate_sensor(dev, &priv->sensor[i], priv->srot_map,
-+                                              mode, base0, base1);
-+              if (ret < 0)
-+                      return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int __init init_tsens_v2_no_rpm(struct tsens_priv *priv)
-+{
-+      struct device *dev = priv->dev;
-+      int i, ret;
-+      u32 val = 0;
-+
-+      ret = init_common(priv);
-+      if (ret < 0)
-+              return ret;
-+
-+      priv->rf[CODE_OR_TEMP] = devm_regmap_field_alloc(dev, priv->srot_map,
-+                                                       priv->fields[CODE_OR_TEMP]);
-+      if (IS_ERR(priv->rf[CODE_OR_TEMP]))
-+              return PTR_ERR(priv->rf[CODE_OR_TEMP]);
-+
-+      priv->rf[MAIN_MEASURE_PERIOD] = devm_regmap_field_alloc(dev, priv->srot_map,
-+                                                              priv->fields[MAIN_MEASURE_PERIOD]);
-+      if (IS_ERR(priv->rf[MAIN_MEASURE_PERIOD]))
-+              return PTR_ERR(priv->rf[MAIN_MEASURE_PERIOD]);
-+
-+      regmap_field_write(priv->rf[TSENS_SW_RST], SW_RST_ASSERT);
-+
-+      regmap_field_write(priv->rf[MAIN_MEASURE_PERIOD], MEASURE_PERIOD_2mSEC);
-+
-+      /* Enable available sensors */
-+      for (i = 0; i < priv->num_sensors; i++)
-+              val |= 1 << priv->sensor[i].hw_id;
-+
-+      regmap_field_write(priv->rf[SENSOR_EN], val);
-+
-+      /* Select temperature format, unit is deci-Celsius */
-+      regmap_field_write(priv->rf[CODE_OR_TEMP], RESULT_FORMAT_TEMP);
-+
-+      regmap_field_write(priv->rf[TSENS_SW_RST], SW_RST_DEASSERT);
-+
-+      regmap_field_write(priv->rf[TSENS_EN], TSENS_ENABLE);
-+
-+      return 0;
-+}
-+
- static const struct tsens_ops ops_generic_v2 = {
-       .init           = init_common,
-       .get_temp       = get_temp_tsens_valid,
-@@ -122,6 +278,28 @@ struct tsens_plat_data data_ipq8074 = {
-       .fields = tsens_v2_regfields,
- };
-+static const struct tsens_ops ops_ipq5332 = {
-+      .init           = init_tsens_v2_no_rpm,
-+      .get_temp       = get_temp_tsens_valid,
-+      .calibrate      = tsens_v2_calibration,
-+};
-+
-+const struct tsens_plat_data data_ipq5332 = {
-+      .num_sensors    = 5,
-+      .ops            = &ops_ipq5332,
-+      .hw_ids         = (unsigned int []){11, 12, 13, 14, 15},
-+      .feat           = &ipq5332_feat,
-+      .fields         = tsens_v2_regfields,
-+};
-+
-+const struct tsens_plat_data data_ipq5424 = {
-+      .num_sensors    = 7,
-+      .ops            = &ops_ipq5332,
-+      .hw_ids         = (unsigned int []){9, 10, 11, 12, 13, 14, 15},
-+      .feat           = &ipq5332_feat,
-+      .fields         = tsens_v2_regfields,
-+};
-+
- /* Kept around for backward compatibility with old msm8996.dtsi */
- struct tsens_plat_data data_8996 = {
-       .num_sensors    = 13,
---- a/drivers/thermal/qcom/tsens.c
-+++ b/drivers/thermal/qcom/tsens.c
-@@ -975,7 +975,7 @@ int __init init_common(struct tsens_priv
-       ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
-       if (ret)
-               goto err_put_device;
--      if (!enabled) {
-+      if (!enabled && (tsens_version(priv) != VER_2_X_NO_RPM)) {
-               dev_err(dev, "%s: device not enabled\n", __func__);
-               ret = -ENODEV;
-               goto err_put_device;
-@@ -1102,6 +1102,12 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t
- static const struct of_device_id tsens_table[] = {
-       {
-+              .compatible = "qcom,ipq5332-tsens",
-+              .data = &data_ipq5332,
-+      }, {
-+              .compatible = "qcom,ipq5424-tsens",
-+              .data = &data_ipq5424,
-+      }, {
-               .compatible = "qcom,ipq8064-tsens",
-               .data = &data_8960,
-       }, {
---- a/drivers/thermal/qcom/tsens.h
-+++ b/drivers/thermal/qcom/tsens.h
-@@ -35,6 +35,7 @@ enum tsens_ver {
-       VER_0_1,
-       VER_1_X,
-       VER_2_X,
-+      VER_2_X_NO_RPM,
- };
- enum tsens_irq_type {
-@@ -168,6 +169,7 @@ enum regfield_ids {
-       TSENS_SW_RST,
-       SENSOR_EN,
-       CODE_OR_TEMP,
-+      MAIN_MEASURE_PERIOD,
-       /* ----- TM ------ */
-       /* TRDY */
-@@ -651,5 +653,6 @@ extern struct tsens_plat_data data_tsens
- /* TSENS v2 targets */
- extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
-+extern const struct tsens_plat_data data_ipq5332, data_ipq5424;
- #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/qualcommax/patches-6.12/0051-v6.16-thermal-drivers-qcom-tsens-Update-conditions-to-stri.patch b/target/linux/qualcommax/patches-6.12/0051-v6.16-thermal-drivers-qcom-tsens-Update-conditions-to-stri.patch
deleted file mode 100644 (file)
index 7de3472..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-From e3f90f167a49902cda2408f7e91cca0dcfd5040a Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 28 Feb 2025 09:11:36 +0400
-Subject: [PATCH] thermal/drivers/qcom/tsens: Update conditions to strictly
- evaluate for IP v2+
-
-TSENS v2.0+ leverage features not available to prior versions such as
-updated interrupts init routine, masked interrupts, and watchdog.
-Currently, the checks in place evaluate whether the IP version is greater
-than v1 which invalidates when updates to v1 or v1 minor versions are
-implemented. As such, update the conditional statements to strictly
-evaluate whether the version is greater than or equal to v2 (inclusive).
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Reviewed-by: Amit Kucheria <amitk@kernel.org>
-Link: https://lore.kernel.org/r/DS7PR19MB8883434CAA053648E22AA8AC9DCC2@DS7PR19MB8883.namprd19.prod.outlook.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/thermal/qcom/tsens.c
-+++ b/drivers/thermal/qcom/tsens.c
-@@ -447,7 +447,7 @@ static void tsens_set_interrupt(struct t
-       dev_dbg(priv->dev, "[%u] %s: %s -> %s\n", hw_id, __func__,
-               irq_type ? ((irq_type == 1) ? "UP" : "CRITICAL") : "LOW",
-               enable ? "en" : "dis");
--      if (tsens_version(priv) > VER_1_X)
-+      if (tsens_version(priv) >= VER_2_X)
-               tsens_set_interrupt_v2(priv, hw_id, irq_type, enable);
-       else
-               tsens_set_interrupt_v1(priv, hw_id, irq_type, enable);
-@@ -499,7 +499,7 @@ static int tsens_read_irq_state(struct t
-       ret = regmap_field_read(priv->rf[LOW_INT_CLEAR_0 + hw_id], &d->low_irq_clear);
-       if (ret)
-               return ret;
--      if (tsens_version(priv) > VER_1_X) {
-+      if (tsens_version(priv) >= VER_2_X) {
-               ret = regmap_field_read(priv->rf[UP_INT_MASK_0 + hw_id], &d->up_irq_mask);
-               if (ret)
-                       return ret;
-@@ -543,7 +543,7 @@ static int tsens_read_irq_state(struct t
- static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
- {
--      if (ver > VER_1_X)
-+      if (ver >= VER_2_X)
-               return mask & (1 << hw_id);
-       /* v1, v0.1 don't have a irq mask register */
-@@ -733,7 +733,7 @@ static int tsens_set_trips(struct therma
- static int tsens_enable_irq(struct tsens_priv *priv)
- {
-       int ret;
--      int val = tsens_version(priv) > VER_1_X ? 7 : 1;
-+      int val = tsens_version(priv) >= VER_2_X ? 7 : 1;
-       ret = regmap_field_write(priv->rf[INT_EN], val);
-       if (ret < 0)
-@@ -1040,7 +1040,7 @@ int __init init_common(struct tsens_priv
-               }
-       }
--      if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
-+      if (tsens_version(priv) >= VER_2_X &&  ver_minor > 2) {
-               /* Watchdog is present only on v2.3+ */
-               priv->feat->has_watchdog = 1;
-               for (i = WDOG_BARK_STATUS; i <= CC_MON_MASK; i++) {
diff --git a/target/linux/qualcommax/patches-6.12/0052-v6.16-thermal-drivers-qcom-tsens-Add-support-for-tsens-v1-.patch b/target/linux/qualcommax/patches-6.12/0052-v6.16-thermal-drivers-qcom-tsens-Add-support-for-tsens-v1-.patch
deleted file mode 100644 (file)
index 0ed4f17..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-From 19f9b02ebc8fe3babefbe76a37c74c5f4c174de1 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 28 Feb 2025 09:11:37 +0400
-Subject: [PATCH] thermal/drivers/qcom/tsens: Add support for tsens v1 without
- RPM
-
-Adding generic support for SoCs with tsens v1.0 IP with no RPM.
-Due to lack of RPM, tsens has to be reset and enabled in the driver
-init. SoCs can have support for more sensors than those which will
-actually be enabled. As such, init will only enable those explicitly
-added to the hw_ids array.
-
-Co-developed-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Link: https://lore.kernel.org/r/DS7PR19MB8883C5D7974C7735E23923769DCC2@DS7PR19MB8883.namprd19.prod.outlook.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens-v1.c | 48 +++++++++++++++++++++++++++++++++
- drivers/thermal/qcom/tsens.c    | 14 +++++++---
- drivers/thermal/qcom/tsens.h    |  1 +
- 3 files changed, 59 insertions(+), 4 deletions(-)
-
---- a/drivers/thermal/qcom/tsens-v1.c
-+++ b/drivers/thermal/qcom/tsens-v1.c
-@@ -79,6 +79,17 @@ static struct tsens_features tsens_v1_fe
-       .trip_max_temp  = 120000,
- };
-+static struct tsens_features tsens_v1_no_rpm_feat = {
-+      .ver_major      = VER_1_X_NO_RPM,
-+      .crit_int       = 0,
-+      .combo_int      = 0,
-+      .adc            = 1,
-+      .srot_split     = 1,
-+      .max_sensors    = 11,
-+      .trip_min_temp  = -40000,
-+      .trip_max_temp  = 120000,
-+};
-+
- static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
-       /* ----- SROT ------ */
-       /* VERSION */
-@@ -150,6 +161,43 @@ static int __init init_8956(struct tsens
-       return init_common(priv);
- }
-+static int __init init_tsens_v1_no_rpm(struct tsens_priv *priv)
-+{
-+      int i, ret;
-+      u32 mask = 0;
-+
-+      ret = init_common(priv);
-+      if (ret < 0) {
-+              dev_err(priv->dev, "Init common failed %d\n", ret);
-+              return ret;
-+      }
-+
-+      ret = regmap_field_write(priv->rf[TSENS_SW_RST], 1);
-+      if (ret) {
-+              dev_err(priv->dev, "Reset failed\n");
-+              return ret;
-+      }
-+
-+      for (i = 0; i < priv->num_sensors; i++)
-+              mask |= BIT(priv->sensor[i].hw_id);
-+
-+      ret = regmap_field_update_bits(priv->rf[SENSOR_EN], mask, mask);
-+      if (ret) {
-+              dev_err(priv->dev, "Sensor Enable failed\n");
-+              return ret;
-+      }
-+
-+      ret = regmap_field_write(priv->rf[TSENS_EN], 1);
-+      if (ret) {
-+              dev_err(priv->dev, "Enable failed\n");
-+              return ret;
-+      }
-+
-+      ret = regmap_field_write(priv->rf[TSENS_SW_RST], 0);
-+
-+      return ret;
-+}
-+
- static const struct tsens_ops ops_generic_v1 = {
-       .init           = init_common,
-       .calibrate      = calibrate_v1,
---- a/drivers/thermal/qcom/tsens.c
-+++ b/drivers/thermal/qcom/tsens.c
-@@ -975,10 +975,16 @@ int __init init_common(struct tsens_priv
-       ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
-       if (ret)
-               goto err_put_device;
--      if (!enabled && (tsens_version(priv) != VER_2_X_NO_RPM)) {
--              dev_err(dev, "%s: device not enabled\n", __func__);
--              ret = -ENODEV;
--              goto err_put_device;
-+      if (!enabled) {
-+              switch (tsens_version(priv)) {
-+              case VER_1_X_NO_RPM:
-+              case VER_2_X_NO_RPM:
-+                      break;
-+              default:
-+                      dev_err(dev, "%s: device not enabled\n", __func__);
-+                      ret = -ENODEV;
-+                      goto err_put_device;
-+              }
-       }
-       priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
---- a/drivers/thermal/qcom/tsens.h
-+++ b/drivers/thermal/qcom/tsens.h
-@@ -34,6 +34,7 @@ enum tsens_ver {
-       VER_0 = 0,
-       VER_0_1,
-       VER_1_X,
-+      VER_1_X_NO_RPM,
-       VER_2_X,
-       VER_2_X_NO_RPM,
- };
diff --git a/target/linux/qualcommax/patches-6.12/0053-v6.16-thermal-drivers-qcom-tsens-Add-support-for-IPQ5018-t.patch b/target/linux/qualcommax/patches-6.12/0053-v6.16-thermal-drivers-qcom-tsens-Add-support-for-IPQ5018-t.patch
deleted file mode 100644 (file)
index 1c09ffc..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From 04b31cc53fe0df0e87a37d18a3c0363d7dee218f Mon Sep 17 00:00:00 2001
-From: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Date: Fri, 28 Feb 2025 09:11:38 +0400
-Subject: [PATCH] thermal/drivers/qcom/tsens: Add support for IPQ5018 tsens
-
-IPQ5018 has tsens IP V1.0, 5 sensors of which 4 are in use and 1
-interrupt. The IP does not have a RPM, hence use init routine for
-tsens v1.0 without RPM which does not early enable.
-
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/DS7PR19MB8883BD0E36C08DD1D03CE1CB9DCC2@DS7PR19MB8883.namprd19.prod.outlook.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens-v1.c | 14 ++++++++++++++
- drivers/thermal/qcom/tsens.c    |  3 +++
- drivers/thermal/qcom/tsens.h    |  3 +++
- 3 files changed, 20 insertions(+)
-
---- a/drivers/thermal/qcom/tsens-v1.c
-+++ b/drivers/thermal/qcom/tsens-v1.c
-@@ -242,3 +242,17 @@ struct tsens_plat_data data_8976 = {
-       .feat           = &tsens_v1_feat,
-       .fields         = tsens_v1_regfields,
- };
-+
-+const struct tsens_ops ops_ipq5018 = {
-+      .init           = init_tsens_v1_no_rpm,
-+      .calibrate      = tsens_calibrate_common,
-+      .get_temp       = get_temp_tsens_valid,
-+};
-+
-+const struct tsens_plat_data data_ipq5018 = {
-+      .num_sensors    = 5,
-+      .ops            = &ops_ipq5018,
-+      .hw_ids         = (unsigned int []){0, 1, 2, 3, 4},
-+      .feat           = &tsens_v1_no_rpm_feat,
-+      .fields         = tsens_v1_regfields,
-+};
---- a/drivers/thermal/qcom/tsens.c
-+++ b/drivers/thermal/qcom/tsens.c
-@@ -1108,6 +1108,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t
- static const struct of_device_id tsens_table[] = {
-       {
-+              .compatible = "qcom,ipq5018-tsens",
-+              .data = &data_ipq5018,
-+      }, {
-               .compatible = "qcom,ipq5332-tsens",
-               .data = &data_ipq5332,
-       }, {
---- a/drivers/thermal/qcom/tsens.h
-+++ b/drivers/thermal/qcom/tsens.h
-@@ -652,6 +652,9 @@ extern struct tsens_plat_data data_8226,
- /* TSENS v1 targets */
- extern struct tsens_plat_data data_tsens_v1, data_8937, data_8976, data_8956;
-+/* TSENS v1 with no RPM targets */
-+extern const struct tsens_plat_data data_ipq5018;
-+
- /* TSENS v2 targets */
- extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
- extern const struct tsens_plat_data data_ipq5332, data_ipq5424;
diff --git a/target/linux/qualcommax/patches-6.12/0054-v6.18-arm64-dts-qcom-ipq5018-Add-tsens-node.patch b/target/linux/qualcommax/patches-6.12/0054-v6.18-arm64-dts-qcom-ipq5018-Add-tsens-node.patch
deleted file mode 100644 (file)
index 81e9302..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-From 450a80623e3b8bb5dae59e0d56046fc3d0a88f3b Mon Sep 17 00:00:00 2001
-From: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Date: Thu, 12 Jun 2025 10:46:14 +0400
-Subject: arm64: dts: qcom: ipq5018: Add tsens node
-
-IPQ5018 has tsens V1.0 IP with 5 sensors, though 4 are in use.
-There is no RPM, so tsens has to be manually enabled. Adding the tsens
-and nvmem nodes and adding 4 thermal sensors (zones). The critical trip
-temperature is set to 120'C with an action to reboot.
-
-In addition, adding a cooling device to the CPU thermal zone which uses
-CPU frequency scaling.
-
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-[bjorn: Added tsens-v1 fallback compatible, per binding]
-Link: https://lore.kernel.org/r/20250612-ipq5018-tsens-v13-2-a210f3683240@outlook.com
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 178 ++++++++++++++++++++++++++++++++++
- 1 file changed, 178 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -9,6 +9,7 @@
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
- #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
-+#include <dt-bindings/thermal/thermal.h>
- / {
-       interrupt-parent = <&intc>;
-@@ -39,6 +40,7 @@
-                       next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-+                      #cooling-cells = <2>;
-               };
-               cpu1: cpu@1 {
-@@ -49,6 +51,7 @@
-                       next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       operating-points-v2 = <&cpu_opp_table>;
-+                      #cooling-cells = <2>;
-               };
-               l2_0: l2-cache {
-@@ -182,6 +185,117 @@
-                       status = "disabled";
-               };
-+              qfprom: qfprom@a0000 {
-+                      compatible = "qcom,ipq5018-qfprom", "qcom,qfprom";
-+                      reg = <0x000a0000 0x1000>;
-+                      #address-cells = <1>;
-+                      #size-cells = <1>;
-+
-+                      tsens_mode: mode@249 {
-+                              reg = <0x249 0x1>;
-+                              bits = <0 3>;
-+                      };
-+
-+                      tsens_base1: base1@249 {
-+                              reg = <0x249 0x2>;
-+                              bits = <3 8>;
-+                      };
-+
-+                      tsens_base2: base2@24a {
-+                              reg = <0x24a 0x2>;
-+                              bits = <3 8>;
-+                      };
-+
-+                      tsens_s0_p1: s0-p1@24b {
-+                              reg = <0x24b 0x2>;
-+                              bits = <2 6>;
-+                      };
-+
-+                      tsens_s0_p2: s0-p2@24c {
-+                              reg = <0x24c 0x1>;
-+                              bits = <1 6>;
-+                      };
-+
-+                      tsens_s1_p1: s1-p1@24c {
-+                              reg = <0x24c 0x2>;
-+                              bits = <7 6>;
-+                      };
-+
-+                      tsens_s1_p2: s1-p2@24d {
-+                              reg = <0x24d 0x2>;
-+                              bits = <5 6>;
-+                      };
-+
-+                      tsens_s2_p1: s2-p1@24e {
-+                              reg = <0x24e 0x2>;
-+                              bits = <3 6>;
-+                      };
-+
-+                      tsens_s2_p2: s2-p2@24f {
-+                              reg = <0x24f 0x1>;
-+                              bits = <1 6>;
-+                      };
-+
-+                      tsens_s3_p1: s3-p1@24f {
-+                              reg = <0x24f 0x2>;
-+                              bits = <7 6>;
-+                      };
-+
-+                      tsens_s3_p2: s3-p2@250 {
-+                              reg = <0x250 0x2>;
-+                              bits = <5 6>;
-+                      };
-+
-+                      tsens_s4_p1: s4-p1@251 {
-+                              reg = <0x251 0x2>;
-+                              bits = <3 6>;
-+                      };
-+
-+                      tsens_s4_p2: s4-p2@254 {
-+                              reg = <0x254 0x1>;
-+                              bits = <0 6>;
-+                      };
-+              };
-+
-+              tsens: thermal-sensor@4a9000 {
-+                      compatible = "qcom,ipq5018-tsens", "qcom,tsens-v1";
-+                      reg = <0x004a9000 0x1000>,
-+                            <0x004a8000 0x1000>;
-+
-+                      nvmem-cells = <&tsens_mode>,
-+                                    <&tsens_base1>,
-+                                    <&tsens_base2>,
-+                                    <&tsens_s0_p1>,
-+                                    <&tsens_s0_p2>,
-+                                    <&tsens_s1_p1>,
-+                                    <&tsens_s1_p2>,
-+                                    <&tsens_s2_p1>,
-+                                    <&tsens_s2_p2>,
-+                                    <&tsens_s3_p1>,
-+                                    <&tsens_s3_p2>,
-+                                    <&tsens_s4_p1>,
-+                                    <&tsens_s4_p2>;
-+
-+                      nvmem-cell-names = "mode",
-+                                         "base1",
-+                                         "base2",
-+                                         "s0_p1",
-+                                         "s0_p2",
-+                                         "s1_p1",
-+                                         "s1_p2",
-+                                         "s2_p1",
-+                                         "s2_p2",
-+                                         "s3_p1",
-+                                         "s3_p2",
-+                                         "s4_p1",
-+                                         "s4_p2";
-+
-+                      interrupts = <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>;
-+                      interrupt-names = "uplow";
-+                      #qcom,sensors = <5>;
-+                      #thermal-sensor-cells = <1>;
-+              };
-+
-               tlmm: pinctrl@1000000 {
-                       compatible = "qcom,ipq5018-tlmm";
-                       reg = <0x01000000 0x300000>;
-@@ -630,6 +744,70 @@
-                       };
-               };
-       };
-+
-+      thermal-zones {
-+              cpu-thermal {
-+                      thermal-sensors = <&tsens 2>;
-+
-+                      trips {
-+                              cpu-critical {
-+                                      temperature = <120000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+
-+                              cpu_alert: cpu-passive {
-+                                      temperature = <100000>;
-+                                      hysteresis = <1000>;
-+                                      type = "passive";
-+                              };
-+                      };
-+
-+                      cooling-maps {
-+                              map0 {
-+                                      trip = <&cpu_alert>;
-+                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-+                              };
-+                      };
-+              };
-+
-+              gephy-thermal {
-+                      thermal-sensors = <&tsens 4>;
-+
-+                      trips {
-+                              gephy-critical {
-+                                      temperature = <120000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-+              };
-+
-+              top-glue-thermal {
-+                      thermal-sensors = <&tsens 3>;
-+
-+                      trips {
-+                              top-glue-critical {
-+                                      temperature = <120000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-+              };
-+
-+              ubi32-thermal {
-+                      thermal-sensors = <&tsens 1>;
-+
-+                      trips {
-+                              ubi32-critical {
-+                                      temperature = <120000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-+              };
-+      };
-       timer {
-               compatible = "arm,armv8-timer";
diff --git a/target/linux/qualcommax/patches-6.12/0056-v6.17-clk-qcom-gcc-ipq5018-fix-GE-PHY-reset.patch b/target/linux/qualcommax/patches-6.12/0056-v6.17-clk-qcom-gcc-ipq5018-fix-GE-PHY-reset.patch
deleted file mode 100644 (file)
index 41399e4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From f6a4a55ae5d99f865e106916a9295548e381de47 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 30 Jun 2025 16:35:00 +0400
-Subject: clk: qcom: gcc-ipq5018: fix GE PHY reset
-
-The MISC reset is supposed to trigger a resets across the MDC, DSP, and
-RX & TX clocks of the IPQ5018 internal GE PHY. So let's set the bitmask
-of the reset definition accordingly in the GCC as per the downstream
-driver.
-
-Link: https://git.codelinaro.org/clo/qsdk/oss/kernel/linux-ipq-5.4/-/commit/00743c3e82fa87cba4460e7a2ba32f473a9ce932
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250630-ipq5018-ge-phy-v6-1-01be06378c15@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/gcc-ipq5018.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-(limited to 'drivers/clk/qcom/gcc-ipq5018.c')
-
---- a/drivers/clk/qcom/gcc-ipq5018.c
-+++ b/drivers/clk/qcom/gcc-ipq5018.c
-@@ -3661,7 +3661,7 @@ static const struct qcom_reset_map gcc_i
-       [GCC_WCSS_AXI_S_ARES] = { 0x59008, 6 },
-       [GCC_WCSS_Q6_BCR] = { 0x18004, 0 },
-       [GCC_WCSSAON_RESET] = { 0x59010, 0},
--      [GCC_GEPHY_MISC_ARES] = { 0x56004, 0 },
-+      [GCC_GEPHY_MISC_ARES] = { 0x56004, .bitmask = GENMASK(3, 0) },
- };
- static const struct of_device_id gcc_ipq5018_match_table[] = {
diff --git a/target/linux/qualcommax/patches-6.12/0057-v6.17-net-phy-qcom-at803x-Add-Qualcomm-IPQ5018-Internal-PHY-support.patch b/target/linux/qualcommax/patches-6.12/0057-v6.17-net-phy-qcom-at803x-Add-Qualcomm-IPQ5018-Internal-PHY-support.patch
deleted file mode 100644 (file)
index 006f0b3..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-From d46502279a11b48ede1d8bf65a229c8231bf0602 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 13 Jun 2025 05:55:08 +0400
-Subject: net: phy: qcom: at803x: Add Qualcomm IPQ5018 Internal PHY support
-
-The IPQ5018 SoC contains a single internal Gigabit Ethernet PHY which
-provides an MDI interface directly to an RJ45 connector or an external
-switch over a PHY to PHY link.
-
-The PHY supports 10BASE-T/100BASE-TX/1000BASE-T link modes in SGMII
-interface mode, CDT, auto-negotiation and 802.3az EEE.
-
-Let's add support for this PHY in the at803x driver as it falls within
-the Qualcomm Atheros OUI.
-
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://patch.msgid.link/20250613-ipq5018-ge-phy-v5-2-9af06e34ea6b@outlook.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- drivers/net/phy/qcom/at803x.c | 167 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 167 insertions(+)
-
-(limited to 'drivers/net/phy/qcom/at803x.c')
-
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -19,6 +19,7 @@
- #include <linux/regulator/consumer.h>
- #include <linux/of.h>
- #include <linux/phylink.h>
-+#include <linux/reset.h>
- #include <linux/sfp.h>
- #include <dt-bindings/net/qca-ar803x.h>
-@@ -93,6 +94,8 @@
- #define ATH8035_PHY_ID                                0x004dd072
- #define AT8030_PHY_ID_MASK                    0xffffffef
-+#define IPQ5018_PHY_ID                                0x004dd0c0
-+
- #define QCA9561_PHY_ID                                0x004dd042
- #define AT803X_PAGE_FIBER                     0
-@@ -105,6 +108,48 @@
- /* disable hibernation mode */
- #define AT803X_DISABLE_HIBERNATION_MODE               BIT(2)
-+#define IPQ5018_PHY_FIFO_CONTROL              0x19
-+#define IPQ5018_PHY_FIFO_RESET                        GENMASK(1, 0)
-+
-+#define IPQ5018_PHY_DEBUG_EDAC                        0x4380
-+#define IPQ5018_PHY_MMD1_MDAC                 0x8100
-+#define IPQ5018_PHY_DAC_MASK                  GENMASK(15, 8)
-+
-+/* MDAC and EDAC values for short cable length */
-+#define IPQ5018_PHY_DEBUG_EDAC_VAL            0x10
-+#define IPQ5018_PHY_MMD1_MDAC_VAL             0x10
-+
-+#define IPQ5018_PHY_MMD1_MSE_THRESH1          0x1000
-+#define IPQ5018_PHY_MMD1_MSE_THRESH2          0x1001
-+#define IPQ5018_PHY_PCS_EEE_TX_TIMER          0x8008
-+#define IPQ5018_PHY_PCS_EEE_RX_TIMER          0x8009
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL3      0x8074
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL4      0x8075
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL5      0x8076
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL6      0x8077
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL7      0x8078
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL9      0x807a
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL13     0x807e
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL14     0x807f
-+
-+#define IPQ5018_PHY_MMD1_MSE_THRESH1_VAL      0xf1
-+#define IPQ5018_PHY_MMD1_MSE_THRESH2_VAL      0x1f6
-+#define IPQ5018_PHY_PCS_EEE_TX_TIMER_VAL      0x7880
-+#define IPQ5018_PHY_PCS_EEE_RX_TIMER_VAL      0xc8
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL3_VAL  0xc040
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL4_VAL  0xa060
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL5_VAL  0xc040
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL6_VAL  0xa060
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL7_VAL  0xc24c
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL9_VAL  0xc060
-+#define IPQ5018_PHY_PCS_CDT_THRESH_CTRL13_VAL 0xb060
-+#define IPQ5018_PHY_PCS_NEAR_ECHO_THRESH_VAL  0x90b0
-+
-+#define IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE               0x1
-+#define IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_MASK  GENMASK(7, 4)
-+#define IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_DEFAULT       0x50
-+#define IPQ5018_PHY_DEBUG_ANA_DAC_FILTER      0xa080
-+
- MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
- MODULE_AUTHOR("Matus Ujhelyi");
- MODULE_LICENSE("GPL");
-@@ -130,6 +175,11 @@ struct at803x_context {
-       u16 led_control;
- };
-+struct ipq5018_priv {
-+      struct reset_control *rst;
-+      bool set_short_cable_dac;
-+};
-+
- static int at803x_write_page(struct phy_device *phydev, int page)
- {
-       int mask;
-@@ -960,6 +1010,109 @@ static int at8035_probe(struct phy_devic
-       return at8035_parse_dt(phydev);
- }
-+static int ipq5018_cable_test_start(struct phy_device *phydev)
-+{
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL3,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL3_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL4,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL4_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL5,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL5_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL6,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL6_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL7,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL7_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL9,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL9_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL13,
-+                    IPQ5018_PHY_PCS_CDT_THRESH_CTRL13_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_CDT_THRESH_CTRL3,
-+                    IPQ5018_PHY_PCS_NEAR_ECHO_THRESH_VAL);
-+
-+      /* we do all the (time consuming) work later */
-+      return 0;
-+}
-+
-+static int ipq5018_config_init(struct phy_device *phydev)
-+{
-+      struct ipq5018_priv *priv = phydev->priv;
-+      u16 val;
-+
-+      /*
-+       * set LDO efuse: first temporarily store ANA_DAC_FILTER value from
-+       * debug register as it will be reset once the ANA_LDO_EFUSE register
-+       * is written to
-+       */
-+      val = at803x_debug_reg_read(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER);
-+      at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE,
-+                            IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_MASK,
-+                            IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_DEFAULT);
-+      at803x_debug_reg_write(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER, val);
-+
-+      /* set 8023AZ EEE TX and RX timer values */
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_EEE_TX_TIMER,
-+                    IPQ5018_PHY_PCS_EEE_TX_TIMER_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_EEE_RX_TIMER,
-+                    IPQ5018_PHY_PCS_EEE_RX_TIMER_VAL);
-+
-+      /* set MSE threshold values */
-+      phy_write_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MSE_THRESH1,
-+                    IPQ5018_PHY_MMD1_MSE_THRESH1_VAL);
-+      phy_write_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MSE_THRESH2,
-+                    IPQ5018_PHY_MMD1_MSE_THRESH2_VAL);
-+
-+      /* PHY DAC values are optional and only set in a PHY to PHY link architecture */
-+      if (priv->set_short_cable_dac) {
-+              /* setting MDAC (Multi-level Digital-to-Analog Converter) in MMD1 */
-+              phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC,
-+                             IPQ5018_PHY_DAC_MASK, IPQ5018_PHY_MMD1_MDAC_VAL);
-+
-+              /* setting EDAC (Error-detection and Correction) in debug register */
-+              at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC,
-+                                    IPQ5018_PHY_DAC_MASK, IPQ5018_PHY_DEBUG_EDAC_VAL);
-+      }
-+
-+      return 0;
-+}
-+
-+static void ipq5018_link_change_notify(struct phy_device *phydev)
-+{
-+      /*
-+       * Reset the FIFO buffer upon link disconnects to clear any residual data
-+       * which may cause issues with the FIFO which it cannot recover from.
-+       */
-+      mdiobus_modify_changed(phydev->mdio.bus, phydev->mdio.addr,
-+                             IPQ5018_PHY_FIFO_CONTROL, IPQ5018_PHY_FIFO_RESET,
-+                             phydev->link ? IPQ5018_PHY_FIFO_RESET : 0);
-+}
-+
-+static int ipq5018_probe(struct phy_device *phydev)
-+{
-+      struct device *dev = &phydev->mdio.dev;
-+      struct ipq5018_priv *priv;
-+      int ret;
-+
-+      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+      if (!priv)
-+              return -ENOMEM;
-+
-+      priv->set_short_cable_dac = of_property_read_bool(dev->of_node,
-+                                                        "qcom,dac-preset-short-cable");
-+
-+      priv->rst = devm_reset_control_array_get_exclusive(dev);
-+      if (IS_ERR(priv->rst))
-+              return dev_err_probe(dev, PTR_ERR(priv->rst),
-+                                   "failed to acquire reset\n");
-+
-+      ret = reset_control_reset(priv->rst);
-+      if (ret)
-+              return dev_err_probe(dev, ret, "failed to reset\n");
-+
-+      phydev->priv = priv;
-+
-+      return 0;
-+}
-+
- static struct phy_driver at803x_driver[] = {
- {
-       /* Qualcomm Atheros AR8035 */
-@@ -1052,6 +1205,19 @@ static struct phy_driver at803x_driver[]
-       .soft_reset             = genphy_soft_reset,
-       .config_aneg            = at803x_config_aneg,
- }, {
-+      PHY_ID_MATCH_EXACT(IPQ5018_PHY_ID),
-+      .name                   = "Qualcomm Atheros IPQ5018 internal PHY",
-+      .flags                  = PHY_IS_INTERNAL | PHY_POLL_CABLE_TEST,
-+      .probe                  = ipq5018_probe,
-+      .config_init            = ipq5018_config_init,
-+      .link_change_notify     = ipq5018_link_change_notify,
-+      .read_status            = at803x_read_status,
-+      .config_intr            = at803x_config_intr,
-+      .handle_interrupt       = at803x_handle_interrupt,
-+      .cable_test_start       = ipq5018_cable_test_start,
-+      .cable_test_get_status  = qca808x_cable_test_get_status,
-+      .soft_reset             = genphy_soft_reset,
-+}, {
-       /* Qualcomm Atheros QCA9561 */
-       PHY_ID_MATCH_EXACT(QCA9561_PHY_ID),
-       .name                   = "Qualcomm Atheros QCA9561 built-in PHY",
-@@ -1077,6 +1243,7 @@ static const struct mdio_device_id __may
-       { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
-       { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
-       { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
-+      { PHY_ID_MATCH_EXACT(IPQ5018_PHY_ID) },
-       { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
-       { }
- };
diff --git a/target/linux/qualcommax/patches-6.12/0058-v6.18-arm64-dts-qcom-ipq5018-Add-MDIO-buses.patch b/target/linux/qualcommax/patches-6.12/0058-v6.18-arm64-dts-qcom-ipq5018-Add-MDIO-buses.patch
deleted file mode 100644 (file)
index 59f6bc2..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-From 1e2261a669a9596ba435c6fe524e026bac0f0e2f Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 30 Jun 2025 16:35:01 +0400
-Subject: arm64: dts: qcom: ipq5018: Add MDIO buses
-
-IPQ5018 contains two mdio buses of which one bus is used to control the
-SoC's internal GE PHY, while the other bus is connected to external PHYs
-or switches.
-
-There's already support for IPQ5018 in the mdio-ipq4019 driver, so let's
-simply add the mdio nodes for them.
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250630-ipq5018-ge-phy-v6-2-01be06378c15@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -185,6 +185,30 @@
-                       status = "disabled";
-               };
-+              mdio0: mdio@88000 {
-+                      compatible = "qcom,ipq5018-mdio";
-+                      reg = <0x00088000 0x64>;
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+
-+                      clocks = <&gcc GCC_MDIO0_AHB_CLK>;
-+                      clock-names = "gcc_mdio_ahb_clk";
-+
-+                      status = "disabled";
-+              };
-+
-+              mdio1: mdio@90000 {
-+                      compatible = "qcom,ipq5018-mdio";
-+                      reg = <0x00090000 0x64>;
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+
-+                      clocks = <&gcc GCC_MDIO1_AHB_CLK>;
-+                      clock-names = "gcc_mdio_ahb_clk";
-+
-+                      status = "disabled";
-+              };
-+
-               qfprom: qfprom@a0000 {
-                       compatible = "qcom,ipq5018-qfprom", "qcom,qfprom";
-                       reg = <0x000a0000 0x1000>;
diff --git a/target/linux/qualcommax/patches-6.12/0059-v6.18-arm64-dts-qcom-ipq5018-Add-GE-PHY-to-internal-mdio-bus.patch b/target/linux/qualcommax/patches-6.12/0059-v6.18-arm64-dts-qcom-ipq5018-Add-GE-PHY-to-internal-mdio-bus.patch
deleted file mode 100644 (file)
index e8d96b8..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-From f5f2b835e316df29b89e28ed7e467df473932e8d Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 30 Jun 2025 16:35:02 +0400
-Subject: arm64: dts: qcom: ipq5018: Add GE PHY to internal mdio bus
-
-The IPQ5018 SoC contains an internal GE PHY, always at phy address 7.
-As such, let's add the GE PHY node to the SoC dtsi.
-
-The LDO controller found in the SoC must be enabled to provide constant
-low voltages to the PHY. The mdio-ipq4019 driver already has support
-for this, so adding the appropriate TCSR register offset.
-
-In addition, the GE PHY outputs both the RX and TX clocks to the GCC
-which gate controls them and routes them back to the PHY itself.
-So let's create two DT fixed clocks and register them in the GCC node.
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250630-ipq5018-ge-phy-v6-3-01be06378c15@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 26 +++++++++++++++++++++++---
- 1 file changed, 23 insertions(+), 3 deletions(-)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -17,6 +17,18 @@
-       #size-cells = <2>;
-       clocks {
-+              gephy_rx_clk: gephy-rx-clk {
-+                      compatible = "fixed-clock";
-+                      clock-frequency = <125000000>;
-+                      #clock-cells = <0>;
-+              };
-+
-+              gephy_tx_clk: gephy-tx-clk {
-+                      compatible = "fixed-clock";
-+                      clock-frequency = <125000000>;
-+                      #clock-cells = <0>;
-+              };
-+
-               sleep_clk: sleep-clk {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-@@ -187,7 +199,8 @@
-               mdio0: mdio@88000 {
-                       compatible = "qcom,ipq5018-mdio";
--                      reg = <0x00088000 0x64>;
-+                      reg = <0x00088000 0x64>,
-+                            <0x019475c4 0x4>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-@@ -195,6 +208,13 @@
-                       clock-names = "gcc_mdio_ahb_clk";
-                       status = "disabled";
-+
-+                      ge_phy: ethernet-phy@7 {
-+                              compatible = "ethernet-phy-id004d.d0c0";
-+                              reg = <7>;
-+
-+                              resets = <&gcc GCC_GEPHY_MISC_ARES>;
-+                      };
-               };
-               mdio1: mdio@90000 {
-@@ -346,8 +366,8 @@
-                                <&pcie0_phy>,
-                                <&pcie1_phy>,
-                                <0>,
--                               <0>,
--                               <0>,
-+                               <&gephy_rx_clk>,
-+                               <&gephy_tx_clk>,
-                                <0>,
-                                <0>;
-                       #clock-cells = <1>;
diff --git a/target/linux/qualcommax/patches-6.12/0060-v6.18-arm64-dts-qcom-ipq5018-Add-SPI-nand-support.patch b/target/linux/qualcommax/patches-6.12/0060-v6.18-arm64-dts-qcom-ipq5018-Add-SPI-nand-support.patch
deleted file mode 100644 (file)
index f9b47cd..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From 8d2a8e8dc448f218b36b3b9f3790c9c0dfaa2b74 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Thu, 1 May 2025 13:20:52 +0400
-Subject: arm64: dts: qcom: ipq5018: Add SPI nand support
-
-Add QPIC SPI NAND support for IPQ5018 SoC.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250501-ipq5018-spi-qpic-snand-v1-2-31e01fbb606f@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 38 +++++++++++++++++++++++++++++++++++
- 1 file changed, 38 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -436,6 +436,44 @@
-                       status = "disabled";
-               };
-+              qpic_bam: dma-controller@7984000 {
-+                      compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0";
-+                      reg = <0x07984000 0x1c000>;
-+
-+                      interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
-+
-+                      clocks = <&gcc GCC_QPIC_AHB_CLK>;
-+                      clock-names = "bam_clk";
-+
-+                      #dma-cells = <1>;
-+                      qcom,ee = <0>;
-+
-+                      status = "disabled";
-+              };
-+
-+              qpic_nand: spi@79b0000 {
-+                      compatible = "qcom,ipq5018-snand", "qcom,ipq9574-snand";
-+                      reg = <0x079b0000 0x10000>;
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+
-+                      clocks = <&gcc GCC_QPIC_CLK>,
-+                               <&gcc GCC_QPIC_AHB_CLK>,
-+                               <&gcc GCC_QPIC_IO_MACRO_CLK>;
-+                      clock-names = "core",
-+                                    "aon",
-+                                    "iom";
-+
-+                      dmas = <&qpic_bam 0>,
-+                             <&qpic_bam 1>,
-+                             <&qpic_bam 2>;
-+                      dma-names = "tx",
-+                                  "rx",
-+                                  "cmd";
-+
-+                      status = "disabled";
-+              };
-+
-               usb: usb@8af8800 {
-                       compatible = "qcom,ipq5018-dwc3", "qcom,dwc3";
-                       reg = <0x08af8800 0x400>;
diff --git a/target/linux/qualcommax/patches-6.12/0061-v6.18-arm64-dts-qcom-ipq5018-add-PRNG-node.patch b/target/linux/qualcommax/patches-6.12/0061-v6.18-arm64-dts-qcom-ipq5018-add-PRNG-node.patch
deleted file mode 100644 (file)
index bdb15ff..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-From bf258fdaa2bcbafa04bf1ad646e8ed42e13033cb Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 21 Jul 2025 10:30:46 +0400
-Subject: arm64: dts: qcom: ipq5018: add PRNG node
-
-PRNG inside of IPQ5018 is already supported, so let's add the node for it.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250721-ipq5018-prng-v1-1-474310e0575d@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -301,6 +301,14 @@
-                       };
-               };
-+              prng: rng@e3000 {
-+                      compatible = "qcom,prng-ee";
-+                      reg = <0x000e3000 0x1000>;
-+                      clocks = <&gcc GCC_PRNG_AHB_CLK>;
-+                      clock-names = "core";
-+                      status = "disabled";
-+              };
-+
-               tsens: thermal-sensor@4a9000 {
-                       compatible = "qcom,ipq5018-tsens", "qcom,tsens-v1";
-                       reg = <0x004a9000 0x1000>,
diff --git a/target/linux/qualcommax/patches-6.12/0062-v6.18-arm64-dts-qcom-ipq5018-Add-crypto-nodes.patch b/target/linux/qualcommax/patches-6.12/0062-v6.18-arm64-dts-qcom-ipq5018-Add-crypto-nodes.patch
deleted file mode 100644 (file)
index 808f8ea..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-From ed5789ba7c2ce548f01ebbdbd7488dd9cccc4513 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 21 Jul 2025 10:23:15 +0400
-Subject: arm64: dts: qcom: ipq5018: Add crypto nodes
-
-IPQ5018 uses Qualcomm QCE crypto engine v5.1 which is already supported.
-So let's add the dts nodes for its DMA v1.7.4 and QCE itself.
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250721-ipq5018-crypto-v3-1-b9cd9b0ef147@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 30 ++++++++++++++++++++++++++++++
- 1 file changed, 30 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -348,6 +348,36 @@
-                       #thermal-sensor-cells = <1>;
-               };
-+              cryptobam: dma-controller@704000 {
-+                      compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0";
-+                      reg = <0x00704000 0x20000>;
-+                      interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>;
-+
-+                      clocks = <&gcc GCC_CRYPTO_AHB_CLK>;
-+                      clock-names = "bam_clk";
-+
-+                      #dma-cells = <1>;
-+                      qcom,ee = <1>;
-+                      qcom,controlled-remotely;
-+              };
-+
-+              crypto: crypto@73a000 {
-+                      compatible = "qcom,crypto-v5.1";
-+                      reg = <0x0073a000 0x6000>;
-+
-+                      clocks = <&gcc GCC_CRYPTO_AHB_CLK>,
-+                               <&gcc GCC_CRYPTO_AXI_CLK>,
-+                               <&gcc GCC_CRYPTO_CLK>;
-+                      clock-names = "iface",
-+                                    "bus",
-+                                    "core";
-+
-+                      dmas = <&cryptobam 2>,
-+                             <&cryptobam 3>;
-+                      dma-names = "rx",
-+                                  "tx";
-+              };
-+
-               tlmm: pinctrl@1000000 {
-                       compatible = "qcom,ipq5018-tlmm";
-                       reg = <0x01000000 0x300000>;
diff --git a/target/linux/qualcommax/patches-6.12/0063-v6.14-dt-bindings-clock-qcom-Add-CMN-PLL-clock-controller.patch b/target/linux/qualcommax/patches-6.12/0063-v6.14-dt-bindings-clock-qcom-Add-CMN-PLL-clock-controller.patch
deleted file mode 100644 (file)
index 01312eb..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-From c0f1cbf795095c21b92a46fa1dc47a7b787ce538 Mon Sep 17 00:00:00 2001
-From: Luo Jie <quic_luoj@quicinc.com>
-Date: Fri, 3 Jan 2025 15:31:34 +0800
-Subject: [PATCH] dt-bindings: clock: qcom: Add CMN PLL clock controller for
- IPQ SoC
-
-The CMN PLL controller provides clocks to networking hardware blocks
-and to GCC on Qualcomm IPQ9574 SoC. It receives input clock from the
-on-chip Wi-Fi, and produces output clocks at fixed rates. These output
-rates are predetermined, and are unrelated to the input clock rate.
-The primary purpose of CMN PLL is to supply clocks to the networking
-hardware such as PPE (packet process engine), PCS and the externally
-connected switch or PHY device. The CMN PLL block also outputs fixed
-rate clocks to GCC, such as 24 MHZ as XO clock and 32 KHZ as sleep
-clock supplied to GCC.
-
-Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Link: https://lore.kernel.org/r/20250103-qcom_ipq_cmnpll-v8-1-c89fb4d4849d@quicinc.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- .../bindings/clock/qcom,ipq9574-cmn-pll.yaml  | 77 +++++++++++++++++++
- include/dt-bindings/clock/qcom,ipq-cmn-pll.h  | 22 ++++++
- 2 files changed, 99 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
- create mode 100644 include/dt-bindings/clock/qcom,ipq-cmn-pll.h
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-@@ -0,0 +1,77 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/clock/qcom,ipq9574-cmn-pll.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Qualcomm CMN PLL Clock Controller on IPQ SoC
-+
-+maintainers:
-+  - Bjorn Andersson <andersson@kernel.org>
-+  - Luo Jie <quic_luoj@quicinc.com>
-+
-+description:
-+  The CMN (or common) PLL clock controller expects a reference
-+  input clock. This reference clock is from the on-board Wi-Fi.
-+  The CMN PLL supplies a number of fixed rate output clocks to
-+  the devices providing networking functions and to GCC. These
-+  networking hardware include PPE (packet process engine), PCS
-+  and the externally connected switch or PHY devices. The CMN
-+  PLL block also outputs fixed rate clocks to GCC. The PLL's
-+  primary function is to enable fixed rate output clocks for
-+  networking hardware functions used with the IPQ SoC.
-+
-+properties:
-+  compatible:
-+    enum:
-+      - qcom,ipq9574-cmn-pll
-+
-+  reg:
-+    maxItems: 1
-+
-+  clocks:
-+    items:
-+      - description: The reference clock. The supported clock rates include
-+          25000000, 31250000, 40000000, 48000000, 50000000 and 96000000 HZ.
-+      - description: The AHB clock
-+      - description: The SYS clock
-+    description:
-+      The reference clock is the source clock of CMN PLL, which is from the
-+      Wi-Fi. The AHB and SYS clocks must be enabled to access CMN PLL
-+      clock registers.
-+
-+  clock-names:
-+    items:
-+      - const: ref
-+      - const: ahb
-+      - const: sys
-+
-+  "#clock-cells":
-+    const: 1
-+
-+required:
-+  - compatible
-+  - reg
-+  - clocks
-+  - clock-names
-+  - "#clock-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+  - |
-+    #include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
-+    #include <dt-bindings/clock/qcom,ipq9574-gcc.h>
-+
-+    cmn_pll: clock-controller@9b000 {
-+        compatible = "qcom,ipq9574-cmn-pll";
-+        reg = <0x0009b000 0x800>;
-+        clocks = <&cmn_pll_ref_clk>,
-+                 <&gcc GCC_CMN_12GPLL_AHB_CLK>,
-+                 <&gcc GCC_CMN_12GPLL_SYS_CLK>;
-+        clock-names = "ref", "ahb", "sys";
-+        #clock-cells = <1>;
-+        assigned-clocks = <&cmn_pll CMN_PLL_CLK>;
-+        assigned-clock-rates-u64 = /bits/ 64 <12000000000>;
-+    };
-+...
---- /dev/null
-+++ b/include/dt-bindings/clock/qcom,ipq-cmn-pll.h
-@@ -0,0 +1,22 @@
-+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ_CMN_PLL_H
-+#define _DT_BINDINGS_CLK_QCOM_IPQ_CMN_PLL_H
-+
-+/* CMN PLL core clock. */
-+#define CMN_PLL_CLK                   0
-+
-+/* The output clocks from CMN PLL of IPQ9574. */
-+#define XO_24MHZ_CLK                  1
-+#define SLEEP_32KHZ_CLK                       2
-+#define PCS_31P25MHZ_CLK              3
-+#define NSS_1200MHZ_CLK                       4
-+#define PPE_353MHZ_CLK                        5
-+#define ETH0_50MHZ_CLK                        6
-+#define ETH1_50MHZ_CLK                        7
-+#define ETH2_50MHZ_CLK                        8
-+#define ETH_25MHZ_CLK                 9
-+#endif
diff --git a/target/linux/qualcommax/patches-6.12/0064-v6.14-clk-qcom-Add-CMN-PLL-clock-controller-driver-for-IPQ-SoC.patch b/target/linux/qualcommax/patches-6.12/0064-v6.14-clk-qcom-Add-CMN-PLL-clock-controller-driver-for-IPQ-SoC.patch
deleted file mode 100644 (file)
index 350e8ee..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-From f81715a4c87c3b75ca2640bb61b6c66506061a64 Mon Sep 17 00:00:00 2001
-From: Luo Jie <quic_luoj@quicinc.com>
-Date: Fri, 3 Jan 2025 15:31:35 +0800
-Subject: [PATCH] clk: qcom: Add CMN PLL clock controller driver for IPQ SoC
-
-The CMN PLL clock controller supplies clocks to the hardware
-blocks that together make up the Ethernet function on Qualcomm
-IPQ SoCs and to GCC. The driver is initially supported for
-IPQ9574 SoC.
-
-The CMN PLL clock controller expects a reference input clock
-from the on-board Wi-Fi block acting as clock source. The input
-reference clock needs to be configured to one of the supported
-clock rates.
-
-The controller supplies a number of fixed-rate output clocks.
-For the IPQ9574, there is one output clock of 353 MHZ to PPE
-(Packet Process Engine) hardware block, three 50 MHZ output
-clocks and an additional 25 MHZ output clock supplied to the
-connected Ethernet devices. The PLL also supplies a 24 MHZ
-clock as XO and a 32 KHZ sleep clock to GCC, and one 31.25
-MHZ clock to PCS.
-
-Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
-Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20250103-qcom_ipq_cmnpll-v8-2-c89fb4d4849d@quicinc.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/Kconfig       |   9 +
- drivers/clk/qcom/Makefile      |   1 +
- drivers/clk/qcom/ipq-cmn-pll.c | 435 +++++++++++++++++++++++++++++++++
- 3 files changed, 445 insertions(+)
- create mode 100644 drivers/clk/qcom/ipq-cmn-pll.c
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -190,6 +190,15 @@ config IPQ_APSS_6018
-         Say Y if you want to support CPU frequency scaling on
-         ipq based devices.
-+config IPQ_CMN_PLL
-+      tristate "IPQ CMN PLL Clock Controller"
-+      help
-+        Support for CMN PLL clock controller on IPQ platform. The
-+        CMN PLL consumes the AHB/SYS clocks from GCC and supplies
-+        the output clocks to the networking hardware and GCC blocks.
-+        Say Y or M if you want to support CMN PLL clock on the IPQ
-+        based devices.
-+
- config IPQ_GCC_4019
-       tristate "IPQ4019 Global Clock Controller"
-       help
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -29,6 +29,7 @@ obj-$(CONFIG_CLK_X1E80100_TCSRCC) += tcs
- obj-$(CONFIG_CLK_QCM2290_GPUCC) += gpucc-qcm2290.o
- obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
- obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o
-+obj-$(CONFIG_IPQ_CMN_PLL) += ipq-cmn-pll.o
- obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
- obj-$(CONFIG_IPQ_GCC_5018) += gcc-ipq5018.o
- obj-$(CONFIG_IPQ_GCC_5332) += gcc-ipq5332.o
---- /dev/null
-+++ b/drivers/clk/qcom/ipq-cmn-pll.c
-@@ -0,0 +1,435 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+/*
-+ * CMN PLL block expects the reference clock from on-board Wi-Fi block,
-+ * and supplies fixed rate clocks as output to the networking hardware
-+ * blocks and to GCC. The networking related blocks include PPE (packet
-+ * process engine), the externally connected PHY or switch devices, and
-+ * the PCS.
-+ *
-+ * On the IPQ9574 SoC, there are three clocks with 50 MHZ and one clock
-+ * with 25 MHZ which are output from the CMN PLL to Ethernet PHY (or switch),
-+ * and one clock with 353 MHZ to PPE. The other fixed rate output clocks
-+ * are supplied to GCC (24 MHZ as XO and 32 KHZ as sleep clock), and to PCS
-+ * with 31.25 MHZ.
-+ *
-+ *               +---------+
-+ *               |   GCC   |
-+ *               +--+---+--+
-+ *           AHB CLK|   |SYS CLK
-+ *                  V   V
-+ *          +-------+---+------+
-+ *          |                  +-------------> eth0-50mhz
-+ * REF CLK  |     IPQ9574      |
-+ * -------->+                  +-------------> eth1-50mhz
-+ *          |  CMN PLL block   |
-+ *          |                  +-------------> eth2-50mhz
-+ *          |                  |
-+ *          +----+----+----+---+-------------> eth-25mhz
-+ *               |    |    |
-+ *               V    V    V
-+ *              GCC  PCS  NSS/PPE
-+ */
-+
-+#include <linux/bitfield.h>
-+#include <linux/clk-provider.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/mod_devicetable.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_clock.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+
-+#include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
-+
-+#define CMN_PLL_REFCLK_SRC_SELECTION          0x28
-+#define CMN_PLL_REFCLK_SRC_DIV                        GENMASK(9, 8)
-+
-+#define CMN_PLL_LOCKED                                0x64
-+#define CMN_PLL_CLKS_LOCKED                   BIT(8)
-+
-+#define CMN_PLL_POWER_ON_AND_RESET            0x780
-+#define CMN_ANA_EN_SW_RSTN                    BIT(6)
-+
-+#define CMN_PLL_REFCLK_CONFIG                 0x784
-+#define CMN_PLL_REFCLK_EXTERNAL                       BIT(9)
-+#define CMN_PLL_REFCLK_DIV                    GENMASK(8, 4)
-+#define CMN_PLL_REFCLK_INDEX                  GENMASK(3, 0)
-+
-+#define CMN_PLL_CTRL                          0x78c
-+#define CMN_PLL_CTRL_LOCK_DETECT_EN           BIT(15)
-+
-+#define CMN_PLL_DIVIDER_CTRL                  0x794
-+#define CMN_PLL_DIVIDER_CTRL_FACTOR           GENMASK(9, 0)
-+
-+/**
-+ * struct cmn_pll_fixed_output_clk - CMN PLL output clocks information
-+ * @id:       Clock specifier to be supplied
-+ * @name: Clock name to be registered
-+ * @rate: Clock rate
-+ */
-+struct cmn_pll_fixed_output_clk {
-+      unsigned int id;
-+      const char *name;
-+      unsigned long rate;
-+};
-+
-+/**
-+ * struct clk_cmn_pll - CMN PLL hardware specific data
-+ * @regmap: hardware regmap.
-+ * @hw: handle between common and hardware-specific interfaces
-+ */
-+struct clk_cmn_pll {
-+      struct regmap *regmap;
-+      struct clk_hw hw;
-+};
-+
-+#define CLK_PLL_OUTPUT(_id, _name, _rate) {           \
-+      .id =           _id,                            \
-+      .name =         _name,                          \
-+      .rate =         _rate,                          \
-+}
-+
-+#define to_clk_cmn_pll(_hw) container_of(_hw, struct clk_cmn_pll, hw)
-+
-+static const struct regmap_config ipq_cmn_pll_regmap_config = {
-+      .reg_bits = 32,
-+      .reg_stride = 4,
-+      .val_bits = 32,
-+      .max_register = 0x7fc,
-+      .fast_io = true,
-+};
-+
-+static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
-+      CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
-+      CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
-+      CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
-+      CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
-+      CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
-+      CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
-+};
-+
-+/*
-+ * CMN PLL has the single parent clock, which supports the several
-+ * possible parent clock rates, each parent clock rate is reflected
-+ * by the specific reference index value in the hardware.
-+ */
-+static int ipq_cmn_pll_find_freq_index(unsigned long parent_rate)
-+{
-+      int index = -EINVAL;
-+
-+      switch (parent_rate) {
-+      case 25000000:
-+              index = 3;
-+              break;
-+      case 31250000:
-+              index = 4;
-+              break;
-+      case 40000000:
-+              index = 6;
-+              break;
-+      case 48000000:
-+      case 96000000:
-+              /*
-+               * Parent clock rate 48 MHZ and 96 MHZ take the same value
-+               * of reference clock index. 96 MHZ needs the source clock
-+               * divider to be programmed as 2.
-+               */
-+              index = 7;
-+              break;
-+      case 50000000:
-+              index = 8;
-+              break;
-+      default:
-+              break;
-+      }
-+
-+      return index;
-+}
-+
-+static unsigned long clk_cmn_pll_recalc_rate(struct clk_hw *hw,
-+                                           unsigned long parent_rate)
-+{
-+      struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
-+      u32 val, factor;
-+
-+      /*
-+       * The value of CMN_PLL_DIVIDER_CTRL_FACTOR is automatically adjusted
-+       * by HW according to the parent clock rate.
-+       */
-+      regmap_read(cmn_pll->regmap, CMN_PLL_DIVIDER_CTRL, &val);
-+      factor = FIELD_GET(CMN_PLL_DIVIDER_CTRL_FACTOR, val);
-+
-+      return parent_rate * 2 * factor;
-+}
-+
-+static int clk_cmn_pll_determine_rate(struct clk_hw *hw,
-+                                    struct clk_rate_request *req)
-+{
-+      int ret;
-+
-+      /* Validate the rate of the single parent clock. */
-+      ret = ipq_cmn_pll_find_freq_index(req->best_parent_rate);
-+
-+      return ret < 0 ? ret : 0;
-+}
-+
-+/*
-+ * This function is used to initialize the CMN PLL to enable the fixed
-+ * rate output clocks. It is expected to be configured once.
-+ */
-+static int clk_cmn_pll_set_rate(struct clk_hw *hw, unsigned long rate,
-+                              unsigned long parent_rate)
-+{
-+      struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
-+      int ret, index;
-+      u32 val;
-+
-+      /*
-+       * Configure the reference input clock selection as per the given
-+       * parent clock. The output clock rates are always of fixed value.
-+       */
-+      index = ipq_cmn_pll_find_freq_index(parent_rate);
-+      if (index < 0)
-+              return index;
-+
-+      ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG,
-+                               CMN_PLL_REFCLK_INDEX,
-+                               FIELD_PREP(CMN_PLL_REFCLK_INDEX, index));
-+      if (ret)
-+              return ret;
-+
-+      /*
-+       * Update the source clock rate selection and source clock
-+       * divider as 2 when the parent clock rate is 96 MHZ.
-+       */
-+      if (parent_rate == 96000000) {
-+              ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG,
-+                                       CMN_PLL_REFCLK_DIV,
-+                                       FIELD_PREP(CMN_PLL_REFCLK_DIV, 2));
-+              if (ret)
-+                      return ret;
-+
-+              ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_SRC_SELECTION,
-+                                       CMN_PLL_REFCLK_SRC_DIV,
-+                                       FIELD_PREP(CMN_PLL_REFCLK_SRC_DIV, 0));
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      /* Enable PLL locked detect. */
-+      ret = regmap_set_bits(cmn_pll->regmap, CMN_PLL_CTRL,
-+                            CMN_PLL_CTRL_LOCK_DETECT_EN);
-+      if (ret)
-+              return ret;
-+
-+      /*
-+       * Reset the CMN PLL block to ensure the updated configurations
-+       * take effect.
-+       */
-+      ret = regmap_clear_bits(cmn_pll->regmap, CMN_PLL_POWER_ON_AND_RESET,
-+                              CMN_ANA_EN_SW_RSTN);
-+      if (ret)
-+              return ret;
-+
-+      usleep_range(1000, 1200);
-+      ret = regmap_set_bits(cmn_pll->regmap, CMN_PLL_POWER_ON_AND_RESET,
-+                            CMN_ANA_EN_SW_RSTN);
-+      if (ret)
-+              return ret;
-+
-+      /* Stability check of CMN PLL output clocks. */
-+      return regmap_read_poll_timeout(cmn_pll->regmap, CMN_PLL_LOCKED, val,
-+                                      (val & CMN_PLL_CLKS_LOCKED),
-+                                      100, 100 * USEC_PER_MSEC);
-+}
-+
-+static const struct clk_ops clk_cmn_pll_ops = {
-+      .recalc_rate = clk_cmn_pll_recalc_rate,
-+      .determine_rate = clk_cmn_pll_determine_rate,
-+      .set_rate = clk_cmn_pll_set_rate,
-+};
-+
-+static struct clk_hw *ipq_cmn_pll_clk_hw_register(struct platform_device *pdev)
-+{
-+      struct clk_parent_data pdata = { .index = 0 };
-+      struct device *dev = &pdev->dev;
-+      struct clk_init_data init = {};
-+      struct clk_cmn_pll *cmn_pll;
-+      struct regmap *regmap;
-+      void __iomem *base;
-+      int ret;
-+
-+      base = devm_platform_ioremap_resource(pdev, 0);
-+      if (IS_ERR(base))
-+              return ERR_CAST(base);
-+
-+      regmap = devm_regmap_init_mmio(dev, base, &ipq_cmn_pll_regmap_config);
-+      if (IS_ERR(regmap))
-+              return ERR_CAST(regmap);
-+
-+      cmn_pll = devm_kzalloc(dev, sizeof(*cmn_pll), GFP_KERNEL);
-+      if (!cmn_pll)
-+              return ERR_PTR(-ENOMEM);
-+
-+      init.name = "cmn_pll";
-+      init.parent_data = &pdata;
-+      init.num_parents = 1;
-+      init.ops = &clk_cmn_pll_ops;
-+
-+      cmn_pll->hw.init = &init;
-+      cmn_pll->regmap = regmap;
-+
-+      ret = devm_clk_hw_register(dev, &cmn_pll->hw);
-+      if (ret)
-+              return ERR_PTR(ret);
-+
-+      return &cmn_pll->hw;
-+}
-+
-+static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
-+{
-+      const struct cmn_pll_fixed_output_clk *fixed_clk;
-+      struct clk_hw_onecell_data *hw_data;
-+      struct device *dev = &pdev->dev;
-+      struct clk_hw *cmn_pll_hw;
-+      unsigned int num_clks;
-+      struct clk_hw *hw;
-+      int ret, i;
-+
-+      fixed_clk = ipq9574_output_clks;
-+      num_clks = ARRAY_SIZE(ipq9574_output_clks);
-+
-+      hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks + 1),
-+                             GFP_KERNEL);
-+      if (!hw_data)
-+              return -ENOMEM;
-+
-+      /*
-+       * Register the CMN PLL clock, which is the parent clock of
-+       * the fixed rate output clocks.
-+       */
-+      cmn_pll_hw = ipq_cmn_pll_clk_hw_register(pdev);
-+      if (IS_ERR(cmn_pll_hw))
-+              return PTR_ERR(cmn_pll_hw);
-+
-+      /* Register the fixed rate output clocks. */
-+      for (i = 0; i < num_clks; i++) {
-+              hw = clk_hw_register_fixed_rate_parent_hw(dev, fixed_clk[i].name,
-+                                                        cmn_pll_hw, 0,
-+                                                        fixed_clk[i].rate);
-+              if (IS_ERR(hw)) {
-+                      ret = PTR_ERR(hw);
-+                      goto unregister_fixed_clk;
-+              }
-+
-+              hw_data->hws[fixed_clk[i].id] = hw;
-+      }
-+
-+      /*
-+       * Provide the CMN PLL clock. The clock rate of CMN PLL
-+       * is configured to 12 GHZ by DT property assigned-clock-rates-u64.
-+       */
-+      hw_data->hws[CMN_PLL_CLK] = cmn_pll_hw;
-+      hw_data->num = num_clks + 1;
-+
-+      ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
-+      if (ret)
-+              goto unregister_fixed_clk;
-+
-+      platform_set_drvdata(pdev, hw_data);
-+
-+      return 0;
-+
-+unregister_fixed_clk:
-+      while (i > 0)
-+              clk_hw_unregister(hw_data->hws[fixed_clk[--i].id]);
-+
-+      return ret;
-+}
-+
-+static int ipq_cmn_pll_clk_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      int ret;
-+
-+      ret = devm_pm_runtime_enable(dev);
-+      if (ret)
-+              return ret;
-+
-+      ret = devm_pm_clk_create(dev);
-+      if (ret)
-+              return ret;
-+
-+      /*
-+       * To access the CMN PLL registers, the GCC AHB & SYS clocks
-+       * of CMN PLL block need to be enabled.
-+       */
-+      ret = pm_clk_add(dev, "ahb");
-+      if (ret)
-+              return dev_err_probe(dev, ret, "Fail to add AHB clock\n");
-+
-+      ret = pm_clk_add(dev, "sys");
-+      if (ret)
-+              return dev_err_probe(dev, ret, "Fail to add SYS clock\n");
-+
-+      ret = pm_runtime_resume_and_get(dev);
-+      if (ret)
-+              return ret;
-+
-+      /* Register CMN PLL clock and fixed rate output clocks. */
-+      ret = ipq_cmn_pll_register_clks(pdev);
-+      pm_runtime_put(dev);
-+      if (ret)
-+              return dev_err_probe(dev, ret,
-+                                   "Fail to register CMN PLL clocks\n");
-+
-+      return 0;
-+}
-+
-+static void ipq_cmn_pll_clk_remove(struct platform_device *pdev)
-+{
-+      struct clk_hw_onecell_data *hw_data = platform_get_drvdata(pdev);
-+      int i;
-+
-+      /*
-+       * The clock with index CMN_PLL_CLK is unregistered by
-+       * device management.
-+       */
-+      for (i = 0; i < hw_data->num; i++) {
-+              if (i != CMN_PLL_CLK)
-+                      clk_hw_unregister(hw_data->hws[i]);
-+      }
-+}
-+
-+static const struct dev_pm_ops ipq_cmn_pll_pm_ops = {
-+      SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
-+};
-+
-+static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
-+      { .compatible = "qcom,ipq9574-cmn-pll", },
-+      { }
-+};
-+MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
-+
-+static struct platform_driver ipq_cmn_pll_clk_driver = {
-+      .probe = ipq_cmn_pll_clk_probe,
-+      .remove = ipq_cmn_pll_clk_remove,
-+      .driver = {
-+              .name = "ipq_cmn_pll",
-+              .of_match_table = ipq_cmn_pll_clk_ids,
-+              .pm = &ipq_cmn_pll_pm_ops,
-+      },
-+};
-+module_platform_driver(ipq_cmn_pll_clk_driver);
-+
-+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ CMN PLL Driver");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/qualcommax/patches-6.12/0065-v6.17-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ5424-SoC.patch b/target/linux/qualcommax/patches-6.12/0065-v6.17-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ5424-SoC.patch
deleted file mode 100644 (file)
index b320963..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-From 0c25ae62f5dc6a438b563536b5fe7fb6da3612b8 Mon Sep 17 00:00:00 2001
-From: Luo Jie <quic_luoj@quicinc.com>
-Date: Tue, 10 Jun 2025 18:35:18 +0800
-Subject: [PATCH] dt-bindings: clock: qcom: Add CMN PLL support for IPQ5424 SoC
-
-The CMN PLL block in the IPQ5424 SoC takes 48 MHZ as the reference
-input clock. The output clocks are the same as IPQ9574 SoC, except
-for the clock rate of output clocks to PPE and NSS.
-
-Also, add the new header file to export the CMN PLL output clock
-specifiers for IPQ5424 SoC.
-
-Acked-by: Rob Herring (Arm) <robh@kernel.org>
-Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
-Link: https://lore.kernel.org/r/20250610-qcom_ipq5424_cmnpll-v3-1-ceada8165645@quicinc.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- .../bindings/clock/qcom,ipq9574-cmn-pll.yaml  |  1 +
- .../dt-bindings/clock/qcom,ipq5424-cmn-pll.h  | 22 +++++++++++++++++++
- 2 files changed, 23 insertions(+)
- create mode 100644 include/dt-bindings/clock/qcom,ipq5424-cmn-pll.h
-
---- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-@@ -24,6 +24,7 @@ description:
- properties:
-   compatible:
-     enum:
-+      - qcom,ipq5424-cmn-pll
-       - qcom,ipq9574-cmn-pll
-   reg:
---- /dev/null
-+++ b/include/dt-bindings/clock/qcom,ipq5424-cmn-pll.h
-@@ -0,0 +1,22 @@
-+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-+/*
-+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ5424_CMN_PLL_H
-+#define _DT_BINDINGS_CLK_QCOM_IPQ5424_CMN_PLL_H
-+
-+/* CMN PLL core clock. */
-+#define IPQ5424_CMN_PLL_CLK                   0
-+
-+/* The output clocks from CMN PLL of IPQ5424. */
-+#define IPQ5424_XO_24MHZ_CLK                  1
-+#define IPQ5424_SLEEP_32KHZ_CLK                       2
-+#define IPQ5424_PCS_31P25MHZ_CLK              3
-+#define IPQ5424_NSS_300MHZ_CLK                        4
-+#define IPQ5424_PPE_375MHZ_CLK                        5
-+#define IPQ5424_ETH0_50MHZ_CLK                        6
-+#define IPQ5424_ETH1_50MHZ_CLK                        7
-+#define IPQ5424_ETH2_50MHZ_CLK                        8
-+#define IPQ5424_ETH_25MHZ_CLK                 9
-+#endif
diff --git a/target/linux/qualcommax/patches-6.12/0066-v6.17-clk-qcom-cmnpll-Add-IPQ5424-SoC-support.patch b/target/linux/qualcommax/patches-6.12/0066-v6.17-clk-qcom-cmnpll-Add-IPQ5424-SoC-support.patch
deleted file mode 100644 (file)
index d13e0b1..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-From a2afa4c33f0a7f7f70d54a1bc5110e326753f982 Mon Sep 17 00:00:00 2001
-From: Luo Jie <quic_luoj@quicinc.com>
-Date: Tue, 10 Jun 2025 18:35:19 +0800
-Subject: clk: qcom: cmnpll: Add IPQ5424 SoC support
-
-The CMN PLL in IPQ5424 SoC supplies the fixed clock to NSS at 300 MHZ
-and to PPE at 375 MHZ. Other output clocks from CMN PLL on this SoC,
-and their rates are same as IPQ9574.
-
-Acked-by: Stephen Boyd <sboyd@kernel.org>
-Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
-Link: https://lore.kernel.org/r/20250610-qcom_ipq5424_cmnpll-v3-2-ceada8165645@quicinc.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/ipq-cmn-pll.c | 35 ++++++++++++++++++++++++++++++-----
- 1 file changed, 30 insertions(+), 5 deletions(-)
-
-(limited to 'drivers/clk/qcom/ipq-cmn-pll.c')
-
---- a/drivers/clk/qcom/ipq-cmn-pll.c
-+++ b/drivers/clk/qcom/ipq-cmn-pll.c
-@@ -1,6 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0-only
- /*
-- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
-  */
- /*
-@@ -16,6 +16,10 @@
-  * are supplied to GCC (24 MHZ as XO and 32 KHZ as sleep clock), and to PCS
-  * with 31.25 MHZ.
-  *
-+ * On the IPQ5424 SoC, there is an output clock from CMN PLL to PPE at 375 MHZ,
-+ * and an output clock to NSS (network subsystem) at 300 MHZ. The other output
-+ * clocks from CMN PLL on IPQ5424 are the same as IPQ9574.
-+ *
-  *               +---------+
-  *               |   GCC   |
-  *               +--+---+--+
-@@ -46,6 +50,7 @@
- #include <linux/regmap.h>
- #include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
-+#include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
- #define CMN_PLL_REFCLK_SRC_SELECTION          0x28
- #define CMN_PLL_REFCLK_SRC_DIV                        GENMASK(9, 8)
-@@ -115,6 +120,20 @@ static const struct cmn_pll_fixed_output
-       CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
-       CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
-       CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
-+      { /* Sentinel */ }
-+};
-+
-+static const struct cmn_pll_fixed_output_clk ipq5424_output_clks[] = {
-+      CLK_PLL_OUTPUT(IPQ5424_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_NSS_300MHZ_CLK, "nss-300mhz", 300000000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_PPE_375MHZ_CLK, "ppe-375mhz", 375000000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(IPQ5424_ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
-+      { /* Sentinel */ }
- };
- /*
-@@ -297,7 +316,7 @@ static struct clk_hw *ipq_cmn_pll_clk_hw
- static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
- {
--      const struct cmn_pll_fixed_output_clk *fixed_clk;
-+      const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
-       struct clk_hw_onecell_data *hw_data;
-       struct device *dev = &pdev->dev;
-       struct clk_hw *cmn_pll_hw;
-@@ -305,8 +324,13 @@ static int ipq_cmn_pll_register_clks(str
-       struct clk_hw *hw;
-       int ret, i;
--      fixed_clk = ipq9574_output_clks;
--      num_clks = ARRAY_SIZE(ipq9574_output_clks);
-+      fixed_clk = device_get_match_data(dev);
-+      if (!fixed_clk)
-+              return -EINVAL;
-+
-+      num_clks = 0;
-+      for (p = fixed_clk; p->name; p++)
-+              num_clks++;
-       hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks + 1),
-                              GFP_KERNEL);
-@@ -415,7 +439,8 @@ static const struct dev_pm_ops ipq_cmn_p
- };
- static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
--      { .compatible = "qcom,ipq9574-cmn-pll", },
-+      { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
-+      { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
-       { }
- };
- MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
diff --git a/target/linux/qualcommax/patches-6.12/0067-v6.17-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ5018-SoC.patch b/target/linux/qualcommax/patches-6.12/0067-v6.17-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ5018-SoC.patch
deleted file mode 100644 (file)
index e2e3f74..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 314b903c30040632db7edd187cd33003b2aee512 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 16 May 2025 16:36:09 +0400
-Subject: [PATCH] dt-bindings: clock: qcom: Add CMN PLL support for IPQ5018 SoC
-
-The CMN PLL block in the IPQ5018 SoC takes 96 MHZ as the reference
-input clock. Its output clocks are the XO (24Mhz), sleep (32Khz), and
-ethernet (50Mhz) clocks.
-
-Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250516-ipq5018-cmn-pll-v4-2-389a6b30e504@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- .../bindings/clock/qcom,ipq9574-cmn-pll.yaml     |  1 +
- include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h | 16 ++++++++++++++++
- 2 files changed, 17 insertions(+)
- create mode 100644 include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h
-
---- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-@@ -24,6 +24,7 @@ description:
- properties:
-   compatible:
-     enum:
-+      - qcom,ipq5018-cmn-pll
-       - qcom,ipq5424-cmn-pll
-       - qcom,ipq9574-cmn-pll
---- /dev/null
-+++ b/include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ5018_CMN_PLL_H
-+#define _DT_BINDINGS_CLK_QCOM_IPQ5018_CMN_PLL_H
-+
-+/* CMN PLL core clock. */
-+#define IPQ5018_CMN_PLL_CLK                   0
-+
-+/* The output clocks from CMN PLL of IPQ5018. */
-+#define IPQ5018_XO_24MHZ_CLK                  1
-+#define IPQ5018_SLEEP_32KHZ_CLK                       2
-+#define IPQ5018_ETH_50MHZ_CLK                 3
-+#endif
diff --git a/target/linux/qualcommax/patches-6.12/0068-v6.17-clk-qcom-ipq-cmn-pll-Add-IPQ5018-SoC-support.patch b/target/linux/qualcommax/patches-6.12/0068-v6.17-clk-qcom-ipq-cmn-pll-Add-IPQ5018-SoC-support.patch
deleted file mode 100644 (file)
index d113c2d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-From 25d12630561d8d0906f1f5eceb055da3af67c8c9 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 16 May 2025 16:36:10 +0400
-Subject: clk: qcom: ipq-cmn-pll: Add IPQ5018 SoC support
-
-The CMN PLL in IPQ5018 SoC supplies fixed clocks to XO, sleep, and the
-ethernet block.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250516-ipq5018-cmn-pll-v4-3-389a6b30e504@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/ipq-cmn-pll.c | 37 +++++++++++++++++++++++--------------
- 1 file changed, 23 insertions(+), 14 deletions(-)
-
-(limited to 'drivers/clk/qcom/ipq-cmn-pll.c')
-
---- a/drivers/clk/qcom/ipq-cmn-pll.c
-+++ b/drivers/clk/qcom/ipq-cmn-pll.c
-@@ -50,6 +50,7 @@
- #include <linux/regmap.h>
- #include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
-+#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
- #include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
- #define CMN_PLL_REFCLK_SRC_SELECTION          0x28
-@@ -110,16 +111,10 @@ static const struct regmap_config ipq_cm
-       .fast_io = true,
- };
--static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
--      CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
--      CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
--      CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
--      CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
--      CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
--      CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
--      CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
--      CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
--      CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
-+static const struct cmn_pll_fixed_output_clk ipq5018_output_clks[] = {
-+      CLK_PLL_OUTPUT(IPQ5018_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
-+      CLK_PLL_OUTPUT(IPQ5018_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
-+      CLK_PLL_OUTPUT(IPQ5018_ETH_50MHZ_CLK, "eth-50mhz", 50000000UL),
-       { /* Sentinel */ }
- };
-@@ -136,6 +131,19 @@ static const struct cmn_pll_fixed_output
-       { /* Sentinel */ }
- };
-+static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
-+      CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
-+      CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
-+      CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
-+      CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
-+      CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
-+      CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
-+      CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
-+      { /* Sentinel */ }
-+};
-+
- /*
-  * CMN PLL has the single parent clock, which supports the several
-  * possible parent clock rates, each parent clock rate is reflected
-@@ -399,11 +407,11 @@ static int ipq_cmn_pll_clk_probe(struct
-        */
-       ret = pm_clk_add(dev, "ahb");
-       if (ret)
--              return dev_err_probe(dev, ret, "Fail to add AHB clock\n");
-+              return dev_err_probe(dev, ret, "Failed to add AHB clock\n");
-       ret = pm_clk_add(dev, "sys");
-       if (ret)
--              return dev_err_probe(dev, ret, "Fail to add SYS clock\n");
-+              return dev_err_probe(dev, ret, "Failed to add SYS clock\n");
-       ret = pm_runtime_resume_and_get(dev);
-       if (ret)
-@@ -414,7 +422,7 @@ static int ipq_cmn_pll_clk_probe(struct
-       pm_runtime_put(dev);
-       if (ret)
-               return dev_err_probe(dev, ret,
--                                   "Fail to register CMN PLL clocks\n");
-+                                   "Failed to register CMN PLL clocks\n");
-       return 0;
- }
-@@ -439,8 +447,9 @@ static const struct dev_pm_ops ipq_cmn_p
- };
- static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
--      { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
-+      { .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
-       { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
-+      { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
-       { }
- };
- MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
diff --git a/target/linux/qualcommax/patches-6.12/0069-v6.18-arm64-dts-ipq5018-Add-CMN-PLL-node.patch b/target/linux/qualcommax/patches-6.12/0069-v6.18-arm64-dts-ipq5018-Add-CMN-PLL-node.patch
deleted file mode 100644 (file)
index 83d6714..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-From c006b249c54441dd8a3a493c7c87158f441f8178 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 21 Jul 2025 10:04:35 +0400
-Subject: arm64: dts: ipq5018: Add CMN PLL node
-
-Add CMN PLL node for enabling output clocks to the networking
-hardware blocks on IPQ5018 devices.
-
-The reference clock of CMN PLL is routed from XO to the CMN PLL
-through the internal WiFi block.
-.XO (48 MHZ) --> WiFi (multiplier/divider)--> 96 MHZ to CMN PLL.
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250721-ipq5018-cmn-pll-v5-1-4cbf3479af65@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 33 +++++++++++++++++++++++++++++++--
- 1 file changed, 31 insertions(+), 2 deletions(-)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -2,12 +2,13 @@
- /*
-  * IPQ5018 SoC device tree source
-  *
-- * Copyright (c) 2023 The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2023-2025 The Linux Foundation. All rights reserved.
-  */
- #include <dt-bindings/clock/qcom,apss-ipq.h>
--#include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
-+#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
-+#include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
- #include <dt-bindings/thermal/thermal.h>
-@@ -29,6 +30,14 @@
-                       #clock-cells = <0>;
-               };
-+              ref_96mhz_clk: ref-96mhz-clk {
-+                      compatible = "fixed-factor-clock";
-+                      clocks = <&xo_clk>;
-+                      #clock-cells = <0>;
-+                      clock-div = <1>;
-+                      clock-mult = <2>;
-+              };
-+
-               sleep_clk: sleep-clk {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-@@ -38,6 +47,12 @@
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-               };
-+
-+              xo_clk: xo-clk {
-+                      compatible = "fixed-clock";
-+                      #clock-cells = <0>;
-+                      clock-frequency = <48000000>;
-+              };
-       };
-       cpus {
-@@ -229,6 +244,20 @@
-                       status = "disabled";
-               };
-+              cmn_pll: clock-controller@9b000 {
-+                      compatible = "qcom,ipq5018-cmn-pll";
-+                      reg = <0x0009b000 0x800>;
-+                      clocks = <&ref_96mhz_clk>,
-+                               <&gcc GCC_CMN_BLK_AHB_CLK>,
-+                               <&gcc GCC_CMN_BLK_SYS_CLK>;
-+                      clock-names = "ref",
-+                                    "ahb",
-+                                    "sys";
-+                      #clock-cells = <1>;
-+                      assigned-clocks = <&cmn_pll IPQ5018_CMN_PLL_CLK>;
-+                      assigned-clock-rates-u64 = /bits/ 64 <9600000000>;
-+              };
-+
-               qfprom: qfprom@a0000 {
-                       compatible = "qcom,ipq5018-qfprom", "qcom,qfprom";
-                       reg = <0x000a0000 0x1000>;
diff --git a/target/linux/qualcommax/patches-6.12/0070-v6.18-arm64-dts-qcom-Update-IPQ5018-xo_board_clk-to-use-fixed-factor-clock.patch b/target/linux/qualcommax/patches-6.12/0070-v6.18-arm64-dts-qcom-Update-IPQ5018-xo_board_clk-to-use-fixed-factor-clock.patch
deleted file mode 100644 (file)
index 20c184d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From 5ca3d42384a66bcb66f91d75da16ec9e9f053aab Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 21 Jul 2025 10:04:36 +0400
-Subject: arm64: dts: qcom: Update IPQ5018 xo_board_clk to use fixed factor
- clock
-
-The xo_board_clk is fixed to 24 MHZ, which is routed from WiFi output
-clock 96 MHZ (also being the reference clock of CMN PLL) divided by 4
-to the analog block routing channel. Update the xo_board_clk nodes in
-the board DTS files to use clock-div/clock-mult accordingly.
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250721-ipq5018-cmn-pll-v5-2-4cbf3479af65@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -44,7 +44,8 @@
-               };
-               xo_board_clk: xo-board-clk {
--                      compatible = "fixed-clock";
-+                      compatible = "fixed-factor-clock";
-+                      clocks = <&ref_96mhz_clk>;
-                       #clock-cells = <0>;
-               };
diff --git a/target/linux/qualcommax/patches-6.12/0071-v6.18-arm64-dts-qcom-ipq5018-add-QUP3-I2C-node.patch b/target/linux/qualcommax/patches-6.12/0071-v6.18-arm64-dts-qcom-ipq5018-add-QUP3-I2C-node.patch
deleted file mode 100644 (file)
index abf0cab..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-From patchwork Mon Sep 15 09:24:18 2025
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Submitter: George Moussalem <george.moussalem@outlook.com>
-X-Patchwork-Id: 14231524
-Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org
- [10.30.226.201])
-       (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
-       (No client certificate requested)
-       by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4305E2F49FD;
-       Mon, 15 Sep 2025 09:24:37 +0000 (UTC)
-Authentication-Results: smtp.subspace.kernel.org;
- arc=none smtp.client-ip=10.30.226.201
-ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
-       t=1757928277; cv=none;
- b=W4yjWHon01Sh2gBzP90ni3A/PWbNfjtSydk9zppsDHx/BPbANANjeMu4rhkRDwshIs4GuAEKBYZmGwGg0SnK/9N3ricPefdvF3PMI1VApzNpkksjRBlVeyccUbjx/+Y2/Oe/8cA1Oz4jQtocecxzE3CGh9+Kk9vqgpHa635Ky4M=
-ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
-       s=arc-20240116; t=1757928277; c=relaxed/simple;
-       bh=RgkgrwRypdT/518CgEj/V8LfEbAO8YRYx2xOm90hzPk=;
-       h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc;
- b=YM1Wxrnb67eDy0s8cezNXKJuM/Asp9L23eC7xAHqaosCV6mlayQFLEkibiqPvm1MRaNc/e2kOWU2I2cQMi88qUSuzlgK/veTaDHx5oePOCR/dZrkkC/bciWsT6CSiTbAbE9WOK2cuxGHzk2PQxCJaBBtFxN3Lg+Kar6d1TWv3Rw=
-ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
- dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org
- header.b=XbapCBXD; arc=none smtp.client-ip=10.30.226.201
-Authentication-Results: smtp.subspace.kernel.org;
-       dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org
- header.b="XbapCBXD"
-Received: by smtp.kernel.org (Postfix) with ESMTPS id D1D1EC4CEF1;
-       Mon, 15 Sep 2025 09:24:36 +0000 (UTC)
-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;
-       s=k20201202; t=1757928276;
-       bh=RgkgrwRypdT/518CgEj/V8LfEbAO8YRYx2xOm90hzPk=;
-       h=From:Date:Subject:To:Cc:Reply-To:From;
-       b=XbapCBXDF3N0JCGizjXEEnzD31MMXQC03i/+s2l2R0wZ8miOI4LMi5Gg4yH2GlKd+
-        Q6p/IdLWuIk3O4m0FpZ5lI2pKF+5siZCyzECvT+Y9LHHb6fMbXp/FNJbrOak3mz8xy
-        PVdw03eFO4Wj5bF3mCqyGd6HKakkfAR6ZDU9B05omFHE5FzakQMTWdHqjgi51gFOm9
-        EMzWFnvH1U1qqsNEicMESHpGGGhWu6VHZugCgkGnOZtnELneHxFgJLjJbYkjfZNBUZ
-        endu4HugvKFXwjcJFtv84yplTu3poxGqmKcC4DtURMjGwFa72IZgv6lJ1c/MXLajAx
-        7/Y8KfWSDjnpQ==
-Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org
- (localhost.localdomain [127.0.0.1])
-       by smtp.lore.kernel.org (Postfix) with ESMTP id C31A1CAC598;
-       Mon, 15 Sep 2025 09:24:36 +0000 (UTC)
-Date: Mon, 15 Sep 2025 13:24:18 +0400
-Subject: [PATCH] arm64: dts: qcom: ipq5018: add QUP3 I2C node
-Precedence: bulk
-X-Mailing-List: linux-arm-msm@vger.kernel.org
-List-Id: <linux-arm-msm.vger.kernel.org>
-List-Subscribe: <mailto:linux-arm-msm+subscribe@vger.kernel.org>
-List-Unsubscribe: <mailto:linux-arm-msm+unsubscribe@vger.kernel.org>
-MIME-Version: 1.0
-Message-Id: <20250915-ipq5018-i2c-v1-1-46bbf27396d6@outlook.com>
-X-B4-Tracking: v=1; b=H4sIAEHbx2gC/x3MQQqAIBBA0avIrBNmBMu6SrSQGms2ZQoRiHdPW
- r7F/wUyJ+EMkyqQ+JEs19lAnYL18OfOWrZmMGgsjkRa4m2RnBazavQYPA29ceSgFTFxkPe/zUu
- tH1sLzpNdAAAA
-X-Change-ID: 20250911-ipq5018-i2c-0a0fa1762818
-To: Bjorn Andersson <andersson@kernel.org>,
- Konrad Dybcio <konradybcio@kernel.org>, Rob Herring <robh@kernel.org>,
- Krzysztof Kozlowski <krzk+dt@kernel.org>,
- Conor Dooley <conor+dt@kernel.org>
-Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
- linux-kernel@vger.kernel.org,
- Vandhiadevan Karunamoorthy <vkarunam@codeaurora.org>,
- George Moussalem <george.moussalem@outlook.com>
-X-Mailer: b4 0.14.2
-X-Developer-Signature: v=1; a=ed25519-sha256; t=1757928274; l=1420;
- i=george.moussalem@outlook.com; s=20250321; h=from:subject:message-id;
- bh=5AMg7/oGtHNBWL+11z9Q/HGGQ9F6ll9nuoBPaZhI9aM=;
- b=YRzjCtxRPYCTIZbfjE7Ch/iQgVk2FPQ2D3Z9XheAftOihKy/1/tmjGVVJNjCCP6dXt51fm4rq
- wtSUjXqnECrAN3FPi6I7N+IBTc6A+E6Q/wpYazdNwaMdyxGBj0tyK4f
-X-Developer-Key: i=george.moussalem@outlook.com; a=ed25519;
- pk=/PuRTSI9iYiHwcc6Nrde8qF4ZDhJBlUgpHdhsIjnqIk=
-X-Endpoint-Received: by B4 Relay for george.moussalem@outlook.com/20250321
- with auth_id=364
-X-Original-From: George Moussalem <george.moussalem@outlook.com>
-Reply-To: george.moussalem@outlook.com
-From: George Moussalem <george.moussalem@outlook.com>
-
-From: Vandhiadevan Karunamoorthy <vkarunam@codeaurora.org>
-
-Add node to support I2C bus inside of IPQ5018.
-
-Signed-off-by: Vandhiadevan Karunamoorthy <vkarunam@codeaurora.org>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 15 +++++++++++++++
- 1 file changed, 15 insertions(+)
-
-
----
-base-commit: b0971d2008c644b9064d968d440fb9f44606d90c
-change-id: 20250911-ipq5018-i2c-0a0fa1762818
-
-Best regards,
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -504,6 +504,21 @@
-                       status = "disabled";
-               };
-+              blsp1_i2c3: i2c@78b7000 {
-+                      compatible = "qcom,i2c-qup-v2.2.1";
-+                      reg = <0x078b7000 0x600>;
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+                      interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
-+                      clocks = <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>,
-+                               <&gcc GCC_BLSP1_AHB_CLK>;
-+                      clock-names = "core", "iface";
-+                      clock-frequency = <400000>;
-+                      dmas = <&blsp_dma 9>, <&blsp_dma 8>;
-+                      dma-names = "tx", "rx";
-+                      status = "disabled";
-+              };
-+
-               qpic_bam: dma-controller@7984000 {
-                       compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0";
-                       reg = <0x07984000 0x1c000>;
diff --git a/target/linux/qualcommax/patches-6.12/0072-v6.18-arm64-dts-qcom-ipq5018-add-QUP1-UART2-node.patch b/target/linux/qualcommax/patches-6.12/0072-v6.18-arm64-dts-qcom-ipq5018-add-QUP1-UART2-node.patch
deleted file mode 100644 (file)
index e278075..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From b410d25fb349bc32132749bd2cb17aa17054287d Mon Sep 17 00:00:00 2001
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Wed, 17 Sep 2025 15:49:00 +0400
-Subject: arm64: dts: qcom: ipq5018: add QUP1 UART2 node
-
-Add node to support the second UART node controller in IPQ5018.
-
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250917-ipq5018-uart2-v1-1-f8680bbf947f@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -490,6 +490,16 @@
-                       status = "disabled";
-               };
-+              blsp1_uart2: serial@78b0000 {
-+                      compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
-+                      reg = <0x078b0000 0x200>;
-+                      interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-+                      clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>,
-+                               <&gcc GCC_BLSP1_AHB_CLK>;
-+                      clock-names = "core", "iface";
-+                      status = "disabled";
-+              };
-+
-               blsp1_spi1: spi@78b5000 {
-                       compatible = "qcom,spi-qup-v2.2.1";
-                       #address-cells = <1>;
diff --git a/target/linux/qualcommax/patches-6.12/0073-v7.0-arm64-dts-qcom-ipq5018-Remove-tsens-v1-fallback-compatible.patch b/target/linux/qualcommax/patches-6.12/0073-v7.0-arm64-dts-qcom-ipq5018-Remove-tsens-v1-fallback-compatible.patch
deleted file mode 100644 (file)
index 5b66e46..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From 60fb18fbc234efb2d59472a889282dba2df3402a Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 18 Aug 2025 15:33:47 +0400
-Subject: arm64: dts: qcom: ipq5018: Remove tsens v1 fallback compatible
-
-Remove qcom,tsens-v1 as fallback compatible since this IP has no RPM
-and, as such, must use its own init routine available in the driver.
-
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20250818-ipq5018-tsens-fix-v1-2-0f08cf09182d@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -340,7 +340,7 @@
-               };
-               tsens: thermal-sensor@4a9000 {
--                      compatible = "qcom,ipq5018-tsens", "qcom,tsens-v1";
-+                      compatible = "qcom,ipq5018-tsens";
-                       reg = <0x004a9000 0x1000>,
-                             <0x004a8000 0x1000>;
diff --git a/target/linux/qualcommax/patches-6.12/0075-v7.0-arm64-dts-qcom-ipq5018-Correct-USB-DWC3-wrapper-interrupts.patch b/target/linux/qualcommax/patches-6.12/0075-v7.0-arm64-dts-qcom-ipq5018-Correct-USB-DWC3-wrapper-interrupts.patch
deleted file mode 100644 (file)
index ed5faef..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From d106f9681d1952b7c19726b0713cee6ae11211f5 Mon Sep 17 00:00:00 2001
-From: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
-Date: Tue, 6 Jan 2026 19:51:24 +0100
-Subject: arm64: dts: qcom: ipq5018: Correct USB DWC3 wrapper interrupts
-
-Interrupts for DWC3 node were completely mixed up - SPI interrupt 62 is
-not listed in reference manual at all.  It was also causing dtbs_check
-warnings:
-
-  ipq5018-rdp432-c2.dtb: usb@8af8800 (qcom,ipq5018-dwc3): interrupt-names:0: 'pwr_event' was expected
-  ipq5018-rdp432-c2.dtb: usb@8af8800 (qcom,ipq5018-dwc3): interrupt-names: ['hs_phy_irq'] is too short
-
-Warning itself was introduced by commit 53c6d854be4e ("dt-bindings: usb:
-dwc3: Clean up hs_phy_irq in binding"), but this was trying to bring
-sanity to the interrupts overall, although did a mistake for IPQ5018.
-IPQ5018 does not have QUSB2 PHY and its interrupts should rather match
-ones used in IPQ5332.
-
-Correct it by using interrupts matching the bindings and reference
-manual.
-
-Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
-Tested-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20260106185123.19929-3-krzysztof.kozlowski@oss.qualcomm.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -571,8 +571,12 @@
-                       compatible = "qcom,ipq5018-dwc3", "qcom,dwc3";
-                       reg = <0x08af8800 0x400>;
--                      interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
--                      interrupt-names = "hs_phy_irq";
-+                      interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-+                                   <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-+                      interrupt-names = "pwr_event",
-+                                        "dp_hs_phy_irq",
-+                                        "dm_hs_phy_irq";
-                       clocks = <&gcc GCC_USB0_MASTER_CLK>,
-                                <&gcc GCC_SYS_NOC_USB0_AXI_CLK>,
diff --git a/target/linux/qualcommax/patches-6.12/0076-v7.2-dt-bindings-pwm-add-IPQ6018-binding.patch b/target/linux/qualcommax/patches-6.12/0076-v7.2-dt-bindings-pwm-add-IPQ6018-binding.patch
deleted file mode 100644 (file)
index cdf9772..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-From a8cd1a1baadbfed43ac214f0bf3e26c90e3b521e Mon Sep 17 00:00:00 2001
-From: Devi Priya <quic_devipriy@quicinc.com>
-Date: Mon, 6 Apr 2026 22:24:38 +0200
-Subject: [PATCH] dt-bindings: pwm: add IPQ6018 binding
-
-DT binding for the PWM block in Qualcomm IPQ6018 SoC.
-
-Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Co-developed-by: Baruch Siach <baruch.siach@siklu.com>
-Signed-off-by: Baruch Siach <baruch.siach@siklu.com>
-Signed-off-by: Devi Priya <quic_devipriy@quicinc.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://patch.msgid.link/20260406-ipq-pwm-v21-1-6ed1e868e4c2@outlook.com
-Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
----
- .../bindings/pwm/qcom,ipq6018-pwm.yaml        | 51 +++++++++++++++++++
- 1 file changed, 51 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pwm/qcom,ipq6018-pwm.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pwm/qcom,ipq6018-pwm.yaml
-@@ -0,0 +1,51 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/pwm/qcom,ipq6018-pwm.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Qualcomm IPQ6018 PWM controller
-+
-+maintainers:
-+  - George Moussalem <george.moussalem@outlook.com>
-+
-+properties:
-+  compatible:
-+    oneOf:
-+      - items:
-+          - enum:
-+              - qcom,ipq5018-pwm
-+              - qcom,ipq5332-pwm
-+              - qcom,ipq9574-pwm
-+          - const: qcom,ipq6018-pwm
-+      - const: qcom,ipq6018-pwm
-+
-+  reg:
-+    maxItems: 1
-+
-+  clocks:
-+    maxItems: 1
-+
-+  "#pwm-cells":
-+    const: 3
-+
-+required:
-+  - compatible
-+  - reg
-+  - clocks
-+  - "#pwm-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+  - |
-+    #include <dt-bindings/clock/qcom,gcc-ipq6018.h>
-+
-+    pwm: pwm@1941010 {
-+        compatible = "qcom,ipq6018-pwm";
-+        reg = <0x01941010 0x20>;
-+        clocks = <&gcc GCC_ADSS_PWM_CLK>;
-+        assigned-clocks = <&gcc GCC_ADSS_PWM_CLK>;
-+        assigned-clock-rates = <100000000>;
-+        #pwm-cells = <3>;
-+    };
diff --git a/target/linux/qualcommax/patches-6.12/0077-v7.2-pwm-Driver-for-qualcomm-ipq6018-pwm-block.patch b/target/linux/qualcommax/patches-6.12/0077-v7.2-pwm-Driver-for-qualcomm-ipq6018-pwm-block.patch
deleted file mode 100644 (file)
index ba0a65f..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-From c436e3e9c265a1f012008ef5da6fd28863f8025c Mon Sep 17 00:00:00 2001
-From: Devi Priya <quic_devipriy@quicinc.com>
-Date: Mon, 6 Apr 2026 22:24:39 +0200
-Subject: [PATCH] pwm: Driver for qualcomm ipq6018 pwm block
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Driver for the PWM block in Qualcomm IPQ6018 line of SoCs. Based on
-driver from downstream Codeaurora kernel tree. Removed support for older
-(V1) variants because I have no access to that hardware.
-
-Tested on IPQ5018 and IPQ6010 based hardware.
-
-Co-developed-by: Baruch Siach <baruch.siach@siklu.com>
-Signed-off-by: Baruch Siach <baruch.siach@siklu.com>
-Signed-off-by: Devi Priya <quic_devipriy@quicinc.com>
-Reviewed-by: Bjorn Andersson <andersson@kernel.org>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://patch.msgid.link/20260406-ipq-pwm-v21-2-6ed1e868e4c2@outlook.com
-[ukleinek: Fixed a few nitpicks as agreed on the mailing list]
-Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
----
- drivers/pwm/Kconfig   |  12 ++
- drivers/pwm/Makefile  |   1 +
- drivers/pwm/pwm-ipq.c | 263 ++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 276 insertions(+)
- create mode 100644 drivers/pwm/pwm-ipq.c
-
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -319,6 +319,18 @@ config PWM_INTEL_LGM
-         To compile this driver as a module, choose M here: the module
-         will be called pwm-intel-lgm.
-+config PWM_IPQ
-+      tristate "IPQ PWM support"
-+      depends on ARCH_QCOM || COMPILE_TEST
-+      depends on HAVE_CLK && HAS_IOMEM
-+      help
-+        Generic PWM framework driver for IPQ PWM block which supports
-+        4 pwm channels. Each of the these channels can be configured
-+        independent of each other.
-+
-+        To compile this driver as a module, choose M here: the module
-+        will be called pwm-ipq.
-+
- config PWM_IQS620A
-       tristate "Azoteq IQS620A PWM support"
-       depends on MFD_IQS62X || COMPILE_TEST
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
-@@ -27,6 +27,7 @@ obj-$(CONFIG_PWM_IMX1)               += pwm-imx1.o
- obj-$(CONFIG_PWM_IMX27)               += pwm-imx27.o
- obj-$(CONFIG_PWM_IMX_TPM)     += pwm-imx-tpm.o
- obj-$(CONFIG_PWM_INTEL_LGM)   += pwm-intel-lgm.o
-+obj-$(CONFIG_PWM_IPQ)         += pwm-ipq.o
- obj-$(CONFIG_PWM_IQS620A)     += pwm-iqs620a.o
- obj-$(CONFIG_PWM_JZ4740)      += pwm-jz4740.o
- obj-$(CONFIG_PWM_KEEMBAY)     += pwm-keembay.o
---- /dev/null
-+++ b/drivers/pwm/pwm-ipq.c
-@@ -0,0 +1,263 @@
-+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
-+/*
-+ * Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved.
-+ *
-+ * Limitations:
-+ * - The PWM controller has no publicly available datasheet.
-+ * - Each of the four channels is programmed via two 32-bit registers
-+ *   (REG0 and REG1 at 8-byte stride).
-+ * - Period and duty-cycle reconfiguration is fully atomic: new divider,
-+ *   pre-divider, and high-duration values are latched by setting the
-+ *   UPDATE bit (bit 30 in REG1). The hardware applies the new settings
-+ *   at the beginning of the next period without disabling the output,
-+ *   so the currently running period is always completed.
-+ * - On disable (clearing the ENABLE bit 31 in REG1), the hardware
-+ *   finishes the current period before stopping the output. The pin
-+ *   is then driven to the inactive (low) level.
-+ * - Upon disabling, the hardware resets the pre-divider (PRE_DIV) and divider
-+ *   fields (PWM_DIV) in REG0 and REG1 to 0x0000 and 0x0001 respectively.
-+ * - Only normal polarity is supported.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/math64.h>
-+#include <linux/of_device.h>
-+#include <linux/bitfield.h>
-+#include <linux/units.h>
-+
-+/* The frequency range supported is 1 Hz to 100 Mhz (clock rate) */
-+#define IPQ_PWM_MAX_PERIOD_NS ((u64)NSEC_PER_SEC)
-+#define IPQ_PWM_MIN_PERIOD_NS 10
-+
-+/*
-+ * Two 32-bit registers for each PWM: REG0, and REG1.
-+ * Base offset for PWM #i is at 8 * #i.
-+ */
-+#define IPQ_PWM_REG0                  0
-+#define IPQ_PWM_REG0_PWM_DIV          GENMASK(15, 0)
-+#define IPQ_PWM_REG0_HI_DURATION      GENMASK(31, 16)
-+
-+#define IPQ_PWM_REG1                  4
-+#define IPQ_PWM_REG1_PRE_DIV          GENMASK(15, 0)
-+/*
-+ * Enable bit is set to enable output toggling in pwm device.
-+ * Update bit is set to trigger the change and is unset automatically
-+ * to reflect the changed divider and high duration values in register.
-+ */
-+#define IPQ_PWM_REG1_UPDATE           BIT(30)
-+#define IPQ_PWM_REG1_ENABLE           BIT(31)
-+
-+/*
-+ * The max value specified for each field is based on the number of bits
-+ * in the pwm control register for that field (16-bit)
-+ */
-+#define IPQ_PWM_MAX_DIV                       FIELD_MAX(IPQ_PWM_REG0_PWM_DIV)
-+
-+struct ipq_pwm_chip {
-+      void __iomem *mem;
-+      unsigned long clk_rate;
-+};
-+
-+static struct ipq_pwm_chip *ipq_pwm_from_chip(struct pwm_chip *chip)
-+{
-+      return pwmchip_get_drvdata(chip);
-+}
-+
-+static unsigned int ipq_pwm_reg_read(struct pwm_device *pwm, unsigned int reg)
-+{
-+      struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(pwm->chip);
-+      unsigned int off = 8 * pwm->hwpwm + reg;
-+
-+      return readl(ipq_chip->mem + off);
-+}
-+
-+static void ipq_pwm_reg_write(struct pwm_device *pwm, unsigned int reg,
-+                            unsigned int val)
-+{
-+      struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(pwm->chip);
-+      unsigned int off = 8 * pwm->hwpwm + reg;
-+
-+      writel(val, ipq_chip->mem + off);
-+}
-+
-+static int ipq_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
-+                       const struct pwm_state *state)
-+{
-+      struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(chip);
-+      unsigned int pre_div, pwm_div;
-+      u64 period_ns, duty_ns;
-+      unsigned long val = 0;
-+      unsigned long hi_dur;
-+
-+      if (!state->enabled) {
-+              /* clear IPQ_PWM_REG1_ENABLE */
-+              ipq_pwm_reg_write(pwm, IPQ_PWM_REG1, IPQ_PWM_REG1_UPDATE);
-+              return 0;
-+      }
-+
-+      if (state->polarity != PWM_POLARITY_NORMAL)
-+              return -EINVAL;
-+
-+      /*
-+       * Check the upper and lower bounds for the period as per
-+       * hardware limits
-+       */
-+      if (state->period < IPQ_PWM_MIN_PERIOD_NS)
-+              return -ERANGE;
-+      period_ns = min(state->period, IPQ_PWM_MAX_PERIOD_NS);
-+      duty_ns = min(state->duty_cycle, period_ns);
-+
-+      /*
-+       * Pick the maximal value for PWM_DIV that still allows a
-+       * 100% relative duty cycle. This allows a fine grained
-+       * selection of duty cycles.
-+       */
-+      pwm_div = IPQ_PWM_MAX_DIV - 1;
-+
-+      /*
-+       * although mul_u64_u64_div_u64 returns a u64, in practice it
-+       * won't overflow due to above constraints. Take the max period
-+       * of 10^9 (NSEC_PER_SEC) and the pwm_div + 1 (IPQ_PWM_MAX_DIV)
-+       *  10^9 * 10^8
-+       * ------------- => which fits well into a 32-bit unsigned int.
-+       * 10^9 * 65,535
-+       */
-+      pre_div = mul_u64_u64_div_u64(period_ns, ipq_chip->clk_rate,
-+                                    (u64)NSEC_PER_SEC * (pwm_div + 1));
-+
-+      if (!pre_div)
-+              return -ERANGE;
-+
-+      pre_div -= 1;
-+
-+      if (pre_div > IPQ_PWM_MAX_DIV)
-+              pre_div = IPQ_PWM_MAX_DIV;
-+
-+      /* pwm duty = HI_DUR * (PRE_DIV + 1) / clk_rate */
-+      hi_dur = mul_u64_u64_div_u64(duty_ns, ipq_chip->clk_rate,
-+                                   (u64)NSEC_PER_SEC * (pre_div + 1));
-+
-+      val = FIELD_PREP(IPQ_PWM_REG0_HI_DURATION, hi_dur) |
-+              FIELD_PREP(IPQ_PWM_REG0_PWM_DIV, pwm_div);
-+      ipq_pwm_reg_write(pwm, IPQ_PWM_REG0, val);
-+
-+      val = FIELD_PREP(IPQ_PWM_REG1_PRE_DIV, pre_div);
-+      ipq_pwm_reg_write(pwm, IPQ_PWM_REG1, val);
-+
-+      /* PWM enable toggle needs a separate write to REG1 */
-+      val |= IPQ_PWM_REG1_UPDATE | IPQ_PWM_REG1_ENABLE;
-+      ipq_pwm_reg_write(pwm, IPQ_PWM_REG1, val);
-+
-+      return 0;
-+}
-+
-+static int ipq_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
-+                           struct pwm_state *state)
-+{
-+      struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(chip);
-+      unsigned int pre_div, pwm_div, hi_dur;
-+      u64 effective_div, hi_div;
-+      u32 reg0, reg1;
-+
-+      reg1 = ipq_pwm_reg_read(pwm, IPQ_PWM_REG1);
-+      state->enabled = reg1 & IPQ_PWM_REG1_ENABLE;
-+
-+      if (!state->enabled)
-+              return 0;
-+
-+      reg0 = ipq_pwm_reg_read(pwm, IPQ_PWM_REG0);
-+
-+      state->polarity = PWM_POLARITY_NORMAL;
-+
-+      pwm_div = FIELD_GET(IPQ_PWM_REG0_PWM_DIV, reg0);
-+      hi_dur = FIELD_GET(IPQ_PWM_REG0_HI_DURATION, reg0);
-+      pre_div = FIELD_GET(IPQ_PWM_REG1_PRE_DIV, reg1);
-+
-+      effective_div = (u64)(pwm_div + 1) * (pre_div + 1);
-+
-+      /*
-+       * effective_div <= 0x100000000, so the multiplication doesn't overflow.
-+       */
-+      state->period = DIV64_U64_ROUND_UP(effective_div * NSEC_PER_SEC,
-+                                         ipq_chip->clk_rate);
-+
-+      hi_div = hi_dur * (pre_div + 1);
-+      state->duty_cycle = DIV64_U64_ROUND_UP(hi_div * NSEC_PER_SEC,
-+                                             ipq_chip->clk_rate);
-+
-+      /*
-+       * ensure a valid config is passed back to PWM core in case duty_cycle
-+       * is > period (>100%)
-+       */
-+      state->duty_cycle = min(state->duty_cycle, state->period);
-+
-+      return 0;
-+}
-+
-+static const struct pwm_ops ipq_pwm_ops = {
-+      .apply = ipq_pwm_apply,
-+      .get_state = ipq_pwm_get_state,
-+};
-+
-+static int ipq_pwm_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct ipq_pwm_chip *pwm;
-+      struct pwm_chip *chip;
-+      struct clk *clk;
-+      int ret;
-+
-+      chip = devm_pwmchip_alloc(dev, 4, sizeof(*pwm));
-+      if (IS_ERR(chip))
-+              return PTR_ERR(chip);
-+      pwm = ipq_pwm_from_chip(chip);
-+
-+      pwm->mem = devm_platform_ioremap_resource(pdev, 0);
-+      if (IS_ERR(pwm->mem))
-+              return dev_err_probe(dev, PTR_ERR(pwm->mem),
-+                                   "Failed to acquire resource\n");
-+
-+      clk = devm_clk_get_enabled(dev, NULL);
-+      if (IS_ERR(clk))
-+              return dev_err_probe(dev, PTR_ERR(clk),
-+                                   "Failed to get clock\n");
-+
-+      ret = devm_clk_rate_exclusive_get(dev, clk);
-+      if (ret)
-+              return dev_err_probe(dev, ret, "Failed to lock clock rate\n");
-+
-+      pwm->clk_rate = clk_get_rate(clk);
-+      if (!pwm->clk_rate)
-+              return dev_err_probe(dev, -EINVAL, "Failed due to clock rate being zero\n");
-+
-+      chip->ops = &ipq_pwm_ops;
-+
-+      ret = devm_pwmchip_add(dev, chip);
-+      if (ret < 0)
-+              return dev_err_probe(dev, ret, "Failed to add pwm chip\n");
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id pwm_ipq_dt_match[] = {
-+      { .compatible = "qcom,ipq6018-pwm", },
-+      {}
-+};
-+MODULE_DEVICE_TABLE(of, pwm_ipq_dt_match);
-+
-+static struct platform_driver ipq_pwm_driver = {
-+      .driver = {
-+              .name = "ipq-pwm",
-+              .of_match_table = pwm_ipq_dt_match,
-+      },
-+      .probe = ipq_pwm_probe,
-+};
-+
-+module_platform_driver(ipq_pwm_driver);
-+
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/qualcommax/patches-6.12/0078-v7.3-arm64-dts-qcom-ipq6018-add-pwm-node.patch b/target/linux/qualcommax/patches-6.12/0078-v7.3-arm64-dts-qcom-ipq6018-add-pwm-node.patch
deleted file mode 100644 (file)
index 4ee9086..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From 6cc812b7435a64cd9d66af107c6dfefb2e77a7cb Mon Sep 17 00:00:00 2001
-From: Devi Priya <quic_devipriy@quicinc.com>
-Date: Mon, 6 Apr 2026 22:24:40 +0200
-Subject: arm64: dts: qcom: ipq6018: add pwm node
-
-Describe the PWM block on IPQ6018.
-
-Although PWM is in the TCSR area, make pwm its own node as simple-mfd
-has been removed from the bindings and as such hardware components
-should have its own node.
-
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Co-developed-by: Baruch Siach <baruch.siach@siklu.com>
-Signed-off-by: Baruch Siach <baruch.siach@siklu.com>
-Signed-off-by: Devi Priya <quic_devipriy@quicinc.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20260406-ipq-pwm-v21-3-6ed1e868e4c2@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq6018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -416,6 +416,16 @@
-                       reg = <0x0 0x01937000 0x0 0x21000>;
-               };
-+              pwm: pwm@1941010 {
-+                      compatible = "qcom,ipq6018-pwm";
-+                      reg = <0x0 0x01941010 0x0 0x20>;
-+                      clocks = <&gcc GCC_ADSS_PWM_CLK>;
-+                      assigned-clocks = <&gcc GCC_ADSS_PWM_CLK>;
-+                      assigned-clock-rates = <100000000>;
-+                      #pwm-cells = <3>;
-+                      status = "disabled";
-+              };
-+
-               usb2: usb@70f8800 {
-                       compatible = "qcom,ipq6018-dwc3", "qcom,dwc3";
-                       reg = <0x0 0x070f8800 0x0 0x400>;
diff --git a/target/linux/qualcommax/patches-6.12/0079-v7.3-arm64-dts-qcom-ipq5018-add-pwm-node.patch b/target/linux/qualcommax/patches-6.12/0079-v7.3-arm64-dts-qcom-ipq5018-add-pwm-node.patch
deleted file mode 100644 (file)
index 4be6601..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-From 4b00afd17a28f44dc63a8602143f84e5f3fa592c Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 6 Apr 2026 22:24:41 +0200
-Subject: arm64: dts: qcom: ipq5018: add pwm node
-
-Describe the PWM block on IPQ5018.
-
-Although PWM is in the TCSR area, make pwm its own node as simple-mfd
-has been removed from the bindings and as such hardware components
-should have its own node.
-
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20260406-ipq-pwm-v21-4-6ed1e868e4c2@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -453,6 +453,16 @@
-                       reg = <0x01937000 0x21000>;
-               };
-+              pwm: pwm@1941010 {
-+                      compatible = "qcom,ipq5018-pwm", "qcom,ipq6018-pwm";
-+                      reg = <0x01941010 0x20>;
-+                      clocks = <&gcc GCC_ADSS_PWM_CLK>;
-+                      assigned-clocks = <&gcc GCC_ADSS_PWM_CLK>;
-+                      assigned-clock-rates = <100000000>;
-+                      #pwm-cells = <3>;
-+                      status = "disabled";
-+              };
-+
-               sdhc_1: mmc@7804000 {
-                       compatible = "qcom,ipq5018-sdhci", "qcom,sdhci-msm-v5";
-                       reg = <0x7804000 0x1000>;
diff --git a/target/linux/qualcommax/patches-6.12/0080-v7.1-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ6018.patch b/target/linux/qualcommax/patches-6.12/0080-v7.1-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ6018.patch
deleted file mode 100644 (file)
index 0ab8bec..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From a57666004f49fa5031d6bf388834213e6f961922 Mon Sep 17 00:00:00 2001
-From: John Crispin <john@phrozen.org>
-Date: Wed, 11 Mar 2026 19:39:38 +0100
-Subject: [PATCH] dt-bindings: clock: qcom: Add CMN PLL support for IPQ6018
-
-The CMN PLL block in the IPQ6018 SoC takes 48 MHz as the reference
-input clock. Its output clocks are the bias_pll_cc_clk (300 MHz) and
-bias_pll_nss_noc_clk (416.5 MHz) clocks used by the networking
-subsystem.
-
-Add the related compatible for IPQ6018 to the ipq9574-cmn-pll
-generic schema.
-
-Signed-off-by: John Crispin <john@phrozen.org>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20260311183942.10134-2-ansuelsmth@gmail.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- .../bindings/clock/qcom,ipq9574-cmn-pll.yaml      |  1 +
- include/dt-bindings/clock/qcom,ipq6018-cmn-pll.h  | 15 +++++++++++++++
- 2 files changed, 16 insertions(+)
- create mode 100644 include/dt-bindings/clock/qcom,ipq6018-cmn-pll.h
-
---- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-@@ -26,6 +26,7 @@ properties:
-     enum:
-       - qcom,ipq5018-cmn-pll
-       - qcom,ipq5424-cmn-pll
-+      - qcom,ipq6018-cmn-pll
-       - qcom,ipq9574-cmn-pll
-   reg:
---- /dev/null
-+++ b/include/dt-bindings/clock/qcom,ipq6018-cmn-pll.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ6018_CMN_PLL_H
-+#define _DT_BINDINGS_CLK_QCOM_IPQ6018_CMN_PLL_H
-+
-+/* CMN PLL core clock. */
-+#define IPQ6018_CMN_PLL_CLK                   0
-+
-+/* The output clocks from CMN PLL of IPQ6018. */
-+#define IPQ6018_BIAS_PLL_CC_CLK                       1
-+#define IPQ6018_BIAS_PLL_NSS_NOC_CLK          2
-+#endif
diff --git a/target/linux/qualcommax/patches-6.12/0081-v7.1-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ8074.patch b/target/linux/qualcommax/patches-6.12/0081-v7.1-dt-bindings-clock-qcom-Add-CMN-PLL-support-for-IPQ8074.patch
deleted file mode 100644 (file)
index 8a10455..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From 7156c65030006e6930dd99c5b8c5e84e69ca5f0b Mon Sep 17 00:00:00 2001
-From: John Crispin <john@phrozen.org>
-Date: Wed, 11 Mar 2026 19:39:40 +0100
-Subject: [PATCH] dt-bindings: clock: qcom: Add CMN PLL support for IPQ8074
-
-The CMN PLL block in the IPQ8074 SoC takes 48 MHz as the reference
-input clock. Its output clocks are the bias_pll_cc_clk (300 MHz) and
-bias_pll_nss_noc_clk (416.5 MHz) clocks used by the networking
-subsystem.
-
-Add the related compatible for IPQ8074 to the ipq9574-cmn-pll
-generic schema.
-
-Signed-off-by: John Crispin <john@phrozen.org>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20260311183942.10134-4-ansuelsmth@gmail.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- .../bindings/clock/qcom,ipq9574-cmn-pll.yaml      |  1 +
- include/dt-bindings/clock/qcom,ipq8074-cmn-pll.h  | 15 +++++++++++++++
- 2 files changed, 16 insertions(+)
- create mode 100644 include/dt-bindings/clock/qcom,ipq8074-cmn-pll.h
-
---- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-@@ -27,6 +27,7 @@ properties:
-       - qcom,ipq5018-cmn-pll
-       - qcom,ipq5424-cmn-pll
-       - qcom,ipq6018-cmn-pll
-+      - qcom,ipq8074-cmn-pll
-       - qcom,ipq9574-cmn-pll
-   reg:
---- /dev/null
-+++ b/include/dt-bindings/clock/qcom,ipq8074-cmn-pll.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ8074_CMN_PLL_H
-+#define _DT_BINDINGS_CLK_QCOM_IPQ8074_CMN_PLL_H
-+
-+/* CMN PLL core clock. */
-+#define IPQ8074_CMN_PLL_CLK                   0
-+
-+/* The output clocks from CMN PLL of IPQ8074. */
-+#define IPQ8074_BIAS_PLL_CC_CLK                       1
-+#define IPQ8074_BIAS_PLL_NSS_NOC_CLK          2
-+#endif
diff --git a/target/linux/qualcommax/patches-6.12/0082-v7.1-clk-qcom-ipq-cmn-pll-Add-IPQ6018-SoC-support.patch b/target/linux/qualcommax/patches-6.12/0082-v7.1-clk-qcom-ipq-cmn-pll-Add-IPQ6018-SoC-support.patch
deleted file mode 100644 (file)
index cfdeea5..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 97eb2ac52726fbb702ced40d552a3f6f2683b664 Mon Sep 17 00:00:00 2001
-From: John Crispin <john@phrozen.org>
-Date: Wed, 11 Mar 2026 19:39:39 +0100
-Subject: [PATCH] clk: qcom: ipq-cmn-pll: Add IPQ6018 SoC support
-
-The CMN PLL in IPQ6018 SoC supplies fixed clocks to the networking
-subsystem: bias_pll_cc_clk at 300 MHz and bias_pll_nss_noc_clk at
-416.5 MHz.
-
-Signed-off-by: John Crispin <john@phrozen.org>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
-Link: https://lore.kernel.org/r/20260311183942.10134-3-ansuelsmth@gmail.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/ipq-cmn-pll.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/clk/qcom/ipq-cmn-pll.c
-+++ b/drivers/clk/qcom/ipq-cmn-pll.c
-@@ -52,6 +52,7 @@
- #include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
- #include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
- #include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
-+#include <dt-bindings/clock/qcom,ipq6018-cmn-pll.h>
- #define CMN_PLL_REFCLK_SRC_SELECTION          0x28
- #define CMN_PLL_REFCLK_SRC_DIV                        GENMASK(9, 8)
-@@ -118,6 +119,12 @@ static const struct cmn_pll_fixed_output
-       { /* Sentinel */ }
- };
-+static const struct cmn_pll_fixed_output_clk ipq6018_output_clks[] = {
-+      CLK_PLL_OUTPUT(IPQ6018_BIAS_PLL_CC_CLK, "bias_pll_cc_clk", 300000000UL),
-+      CLK_PLL_OUTPUT(IPQ6018_BIAS_PLL_NSS_NOC_CLK, "bias_pll_nss_noc_clk", 416500000UL),
-+      { /* Sentinel */ }
-+};
-+
- static const struct cmn_pll_fixed_output_clk ipq5424_output_clks[] = {
-       CLK_PLL_OUTPUT(IPQ5424_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
-       CLK_PLL_OUTPUT(IPQ5424_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
-@@ -449,6 +456,7 @@ static const struct dev_pm_ops ipq_cmn_p
- static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
-       { .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
-       { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
-+      { .compatible = "qcom,ipq6018-cmn-pll", .data = &ipq6018_output_clks },
-       { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
-       { }
- };
diff --git a/target/linux/qualcommax/patches-6.12/0083-v7.1-clk-qcom-ipq-cmn-pll-Add-IPQ8074-SoC-support.patch b/target/linux/qualcommax/patches-6.12/0083-v7.1-clk-qcom-ipq-cmn-pll-Add-IPQ8074-SoC-support.patch
deleted file mode 100644 (file)
index e972b50..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 4e36f8ab45c406420f2c2ce6ee3988e0d13ba1c9 Mon Sep 17 00:00:00 2001
-From: John Crispin <john@phrozen.org>
-Date: Wed, 11 Mar 2026 19:39:41 +0100
-Subject: [PATCH] clk: qcom: ipq-cmn-pll: Add IPQ8074 SoC support
-
-The CMN PLL in IPQ8074 SoC supplies fixed clocks to the networking
-subsystem: bias_pll_cc_clk at 300 MHz and bias_pll_nss_noc_clk at
-416.5 MHz.
-
-Signed-off-by: John Crispin <john@phrozen.org>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
-Link: https://lore.kernel.org/r/20260311183942.10134-5-ansuelsmth@gmail.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/ipq-cmn-pll.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/clk/qcom/ipq-cmn-pll.c
-+++ b/drivers/clk/qcom/ipq-cmn-pll.c
-@@ -53,6 +53,7 @@
- #include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
- #include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
- #include <dt-bindings/clock/qcom,ipq6018-cmn-pll.h>
-+#include <dt-bindings/clock/qcom,ipq8074-cmn-pll.h>
- #define CMN_PLL_REFCLK_SRC_SELECTION          0x28
- #define CMN_PLL_REFCLK_SRC_DIV                        GENMASK(9, 8)
-@@ -125,6 +126,12 @@ static const struct cmn_pll_fixed_output
-       { /* Sentinel */ }
- };
-+static const struct cmn_pll_fixed_output_clk ipq8074_output_clks[] = {
-+      CLK_PLL_OUTPUT(IPQ8074_BIAS_PLL_CC_CLK, "bias_pll_cc_clk", 300000000UL),
-+      CLK_PLL_OUTPUT(IPQ8074_BIAS_PLL_NSS_NOC_CLK, "bias_pll_nss_noc_clk", 416500000UL),
-+      { /* Sentinel */ }
-+};
-+
- static const struct cmn_pll_fixed_output_clk ipq5424_output_clks[] = {
-       CLK_PLL_OUTPUT(IPQ5424_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
-       CLK_PLL_OUTPUT(IPQ5424_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
-@@ -457,6 +464,7 @@ static const struct of_device_id ipq_cmn
-       { .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
-       { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
-       { .compatible = "qcom,ipq6018-cmn-pll", .data = &ipq6018_output_clks },
-+      { .compatible = "qcom,ipq8074-cmn-pll", .data = &ipq8074_output_clks },
-       { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
-       { }
- };
diff --git a/target/linux/qualcommax/patches-6.12/0084-v7.2-clk-qcom-cmnpll-Account-for-reference-clock-divider.patch b/target/linux/qualcommax/patches-6.12/0084-v7.2-clk-qcom-cmnpll-Account-for-reference-clock-divider.patch
deleted file mode 100644 (file)
index 2c78675..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From 88c543fff756450bcd04ec4560c4440be36c9e75 Mon Sep 17 00:00:00 2001
-From: Luo Jie <jie.luo@oss.qualcomm.com>
-Date: Tue, 6 Jan 2026 21:35:10 -0800
-Subject: [PATCH] clk: qcom: cmnpll: Account for reference clock divider
-
-The clk_cmn_pll_recalc_rate() function must account for the reference clock
-divider programmed in CMN_PLL_REFCLK_CONFIG. Without this fix, platforms
-with a reference divider other than 1 calculate incorrect CMN PLL rates.
-For example, on IPQ5332 where the reference divider is 2, the computed rate
-becomes twice the actual output.
-
-Read CMN_PLL_REFCLK_DIV and divide the parent rate by this value before
-applying the 2 * FACTOR scaling. This yields the correct rate calculation:
-rate = (parent_rate / ref_div) * 2 * factor.
-
-Maintain backward compatibility with earlier platforms (e.g. IPQ9574,
-IPQ5424, IPQ5018) that use ref_div = 1.
-
-Fixes: f81715a4c87c ("clk: qcom: Add CMN PLL clock controller driver for IPQ SoC")
-Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Tested-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20260106-qcom_ipq5332_cmnpll-v2-1-f9f7e4efbd79@oss.qualcomm.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- drivers/clk/qcom/ipq-cmn-pll.c | 11 +++++++++--
- 1 file changed, 9 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/qcom/ipq-cmn-pll.c
-+++ b/drivers/clk/qcom/ipq-cmn-pll.c
-@@ -200,7 +200,7 @@ static unsigned long clk_cmn_pll_recalc_
-                                            unsigned long parent_rate)
- {
-       struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
--      u32 val, factor;
-+      u32 val, factor, ref_div;
-       /*
-        * The value of CMN_PLL_DIVIDER_CTRL_FACTOR is automatically adjusted
-@@ -208,8 +208,15 @@ static unsigned long clk_cmn_pll_recalc_
-        */
-       regmap_read(cmn_pll->regmap, CMN_PLL_DIVIDER_CTRL, &val);
-       factor = FIELD_GET(CMN_PLL_DIVIDER_CTRL_FACTOR, val);
-+      if (WARN_ON(factor == 0))
-+              factor = 1;
--      return parent_rate * 2 * factor;
-+      regmap_read(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG, &val);
-+      ref_div = FIELD_GET(CMN_PLL_REFCLK_DIV, val);
-+      if (WARN_ON(ref_div == 0))
-+              ref_div = 1;
-+
-+      return div_u64((u64)parent_rate * 2 * factor, ref_div);
- }
- static int clk_cmn_pll_determine_rate(struct clk_hw *hw,
diff --git a/target/linux/qualcommax/patches-6.12/0085-v7.3-arm64-dts-qcom-ipq5018-Correct-CMN-PLL-reference-clock-rate.patch b/target/linux/qualcommax/patches-6.12/0085-v7.3-arm64-dts-qcom-ipq5018-Correct-CMN-PLL-reference-clock-rate.patch
deleted file mode 100644 (file)
index d3a2d8c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From 02320d694fa1124b8b77fcb52191141004ef7fbb Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Thu, 21 May 2026 11:55:58 +0400
-Subject: arm64: dts: qcom: ipq5018: Correct CMN PLL reference clock rate
-
-The correct CMN PLL reference clock rate for IPQ5018 is 4.8 GHz.
-
-The CMN PLL driver did not account for the ref clock divider which is 2
-for IPQ5018. Therefore, the computed rate was twice the actual output.
-
-With the driver now accounting for the CMN PLL reference clock
-divider (commit: 88c543fff756), set the correct reference clock rate.
-
-Fixes: c006b249c544 ("arm64: dts: ipq5018: Add CMN PLL node")
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Link: https://lore.kernel.org/r/20260521-ipq5018-cmn-pll-rate-fix-v2-1-04b28a92e0f2@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -256,7 +256,7 @@
-                                     "sys";
-                       #clock-cells = <1>;
-                       assigned-clocks = <&cmn_pll IPQ5018_CMN_PLL_CLK>;
--                      assigned-clock-rates-u64 = /bits/ 64 <9600000000>;
-+                      assigned-clock-rates-u64 = /bits/ 64 <4800000000>;
-               };
-               qfprom: qfprom@a0000 {
diff --git a/target/linux/qualcommax/patches-6.12/0086-v6.17-dt-bindings-net-qca-ar803x-Add-IPQ5018-Internal-GE-PHY-support.patch b/target/linux/qualcommax/patches-6.12/0086-v6.17-dt-bindings-net-qca-ar803x-Add-IPQ5018-Internal-GE-PHY-support.patch
deleted file mode 100644 (file)
index 52ff962..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-From 82eaf94d69fce20f8859a2b8dae8e7064d9343da Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 13 Jun 2025 05:55:07 +0400
-Subject: [PATCH] dt-bindings: net: qca,ar803x: Add IPQ5018 Internal GE PHY
- support
-
-Document the IPQ5018 Internal Gigabit Ethernet PHY found in the IPQ5018
-SoC. Its output pins provide an MDI interface to either an external
-switch in a PHY to PHY link scenario or is directly attached to an RJ45
-connector.
-
-The PHY supports 10/100/1000 mbps link modes, CDT, auto-negotiation and
-802.3az EEE.
-
-For operation, the LDO controller found in the IPQ5018 SoC for which
-there is provision in the mdio-4019 driver.
-
-Two common archictures across IPQ5018 boards are:
-1. IPQ5018 PHY --> MDI --> RJ45 connector
-2. IPQ5018 PHY --> MDI --> External PHY
-In a phy to phy architecture, the DAC needs to be configured to
-accommodate for the short cable length. As such, add an optional boolean
-property so the driver sets preset DAC register values accordingly.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Link: https://patch.msgid.link/20250613-ipq5018-ge-phy-v5-1-9af06e34ea6b@outlook.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- .../devicetree/bindings/net/qca,ar803x.yaml   | 43 +++++++++++++++++++
- 1 file changed, 43 insertions(+)
-
---- a/Documentation/devicetree/bindings/net/qca,ar803x.yaml
-+++ b/Documentation/devicetree/bindings/net/qca,ar803x.yaml
-@@ -16,8 +16,37 @@ description: |
- allOf:
-   - $ref: ethernet-phy.yaml#
-+  - if:
-+      properties:
-+        compatible:
-+          contains:
-+            enum:
-+              - ethernet-phy-id004d.d0c0
-+
-+    then:
-+      properties:
-+        reg:
-+          const: 7  # This PHY is always at MDIO address 7 in the IPQ5018 SoC
-+
-+        resets:
-+          items:
-+            - description:
-+                GE PHY MISC reset which triggers a reset across MDC, DSP, RX, and TX lines.
-+
-+        qcom,dac-preset-short-cable:
-+          description:
-+            Set if this phy is connected to another phy to adjust the values for
-+            MDAC and EDAC to adjust amplitude, bias current settings, and error
-+            detection and correction algorithm to accommodate for short cable length.
-+            If not set, DAC values are not modified and it is assumed the MDI output pins
-+            of this PHY are directly connected to an RJ45 connector.
-+          type: boolean
- properties:
-+  compatible:
-+    enum:
-+      - ethernet-phy-id004d.d0c0
-+
-   qca,clk-out-frequency:
-     description: Clock output frequency in Hertz.
-     $ref: /schemas/types.yaml#/definitions/uint32
-@@ -132,3 +161,17 @@ examples:
-             };
-         };
-     };
-+  - |
-+    #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
-+
-+    mdio {
-+        #address-cells = <1>;
-+        #size-cells = <0>;
-+
-+        ge_phy: ethernet-phy@7 {
-+            compatible = "ethernet-phy-id004d.d0c0";
-+            reg = <7>;
-+
-+            resets = <&gcc GCC_GEPHY_MISC_ARES>;
-+        };
-+    };
diff --git a/target/linux/qualcommax/patches-6.12/0087-v7.2-dt-bindings-net-ethernet-phy-increase-max-clock-count-to-two.patch b/target/linux/qualcommax/patches-6.12/0087-v7.2-dt-bindings-net-ethernet-phy-increase-max-clock-count-to-two.patch
deleted file mode 100644 (file)
index 73d6975..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 19e00bdfbb1b5f7a2d1f3c1c38b3da25e17ea486 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 8 Jun 2026 09:09:16 +0400
-Subject: [PATCH] dt-bindings: net: ethernet-phy: increase max clock count to
- two
-
-The clocks property has a restriction to maximum one.
-Yet, some PHYs may require more than 1 clock such as the IPQ5018 PHY
-which requires two clocks for RX and TX. As such, increase maxItems to
-two.
-
-Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://patch.msgid.link/20260608-ipq5018-gephy-clocks-v4-1-fb2ccd56894b@outlook.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- Documentation/devicetree/bindings/net/ethernet-phy.yaml | 9 ++++++---
- 1 file changed, 6 insertions(+), 3 deletions(-)
-
---- a/Documentation/devicetree/bindings/net/ethernet-phy.yaml
-+++ b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
-@@ -102,10 +102,13 @@ properties:
-       by software.
-   clocks:
--    maxItems: 1
-+    minItems: 1
-+    maxItems: 2
-     description:
--      External clock connected to the PHY. If not specified it is assumed
--      that the PHY uses a fixed crystal or an internal oscillator.
-+      External clock connected to the PHY or RX and TX clocks that the PHY
-+      requires to enable explicitly. If not specified it is assumed
-+      that the PHY uses a fixed crystal or an internal oscillator or that the
-+      RX/TX clocks are hardware enabled by default.
-   enet-phy-lane-swap:
-     $ref: /schemas/types.yaml#/definitions/flag
diff --git a/target/linux/qualcommax/patches-6.12/0088-v7.2-dt-bindings-net-qca-ar803x-Add-clocks-for-IPQ5018-PHY.patch b/target/linux/qualcommax/patches-6.12/0088-v7.2-dt-bindings-net-qca-ar803x-Add-clocks-for-IPQ5018-PHY.patch
deleted file mode 100644 (file)
index d410a24..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-From fea4ae4b5b5059612d1a4f5acb88c27a5f7e60dc Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 8 Jun 2026 09:09:17 +0400
-Subject: [PATCH] dt-bindings: net: qca,ar803x: Add clocks for IPQ5018 PHY
-
-Further testing revealed that the RX and TX clocks of the IPQ5018 PHY
-need to be explicitly enabled. As such, add the required clocks to the
-schema.
-
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://patch.msgid.link/20260608-ipq5018-gephy-clocks-v4-2-fb2ccd56894b@outlook.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- .../devicetree/bindings/net/qca,ar803x.yaml   | 19 +++++++++++++++++++
- 1 file changed, 19 insertions(+)
-
---- a/Documentation/devicetree/bindings/net/qca,ar803x.yaml
-+++ b/Documentation/devicetree/bindings/net/qca,ar803x.yaml
-@@ -28,6 +28,16 @@ allOf:
-         reg:
-           const: 7  # This PHY is always at MDIO address 7 in the IPQ5018 SoC
-+        clocks:
-+          items:
-+            - description: RX clock
-+            - description: TX clock
-+
-+        clock-names:
-+          items:
-+            - const: rx
-+            - const: tx
-+
-         resets:
-           items:
-             - description:
-@@ -42,6 +52,11 @@ allOf:
-             of this PHY are directly connected to an RJ45 connector.
-           type: boolean
-+      required:
-+        - clocks
-+        - clock-names
-+        - resets
-+
- properties:
-   compatible:
-     enum:
-@@ -162,6 +177,7 @@ examples:
-         };
-     };
-   - |
-+    #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
-     #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
-     mdio {
-@@ -172,6 +188,9 @@ examples:
-             compatible = "ethernet-phy-id004d.d0c0";
-             reg = <7>;
-+            clocks = <&gcc GCC_GEPHY_RX_CLK>,
-+                     <&gcc GCC_GEPHY_TX_CLK>;
-+            clock-names = "rx", "tx";
-             resets = <&gcc GCC_GEPHY_MISC_ARES>;
-         };
-     };
diff --git a/target/linux/qualcommax/patches-6.12/0089-v7.2-net-phy-at803x-add-RX-and-TX-clock-management-for-IPQ5018-PHY.patch b/target/linux/qualcommax/patches-6.12/0089-v7.2-net-phy-at803x-add-RX-and-TX-clock-management-for-IPQ5018-PHY.patch
deleted file mode 100644 (file)
index 4a43b52..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-From cf6077e4903ffed2291f5f3cb9d61b29abe456c4 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 8 Jun 2026 09:09:19 +0400
-Subject: [PATCH] net: phy: at803x: add RX and TX clock management for IPQ5018
- PHY
-
-Acquire and enable the RX and TX clocks for the IPQ5018 PHY.
-These clocks are required for the PHY's datapath to function correctly.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://patch.msgid.link/20260608-ipq5018-gephy-clocks-v4-4-fb2ccd56894b@outlook.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- drivers/net/phy/qcom/at803x.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -19,6 +19,7 @@
- #include <linux/regulator/consumer.h>
- #include <linux/of.h>
- #include <linux/phylink.h>
-+#include <linux/clk.h>
- #include <linux/reset.h>
- #include <linux/sfp.h>
- #include <dt-bindings/net/qca-ar803x.h>
-@@ -1089,6 +1090,7 @@ static void ipq5018_link_change_notify(s
- static int ipq5018_probe(struct phy_device *phydev)
- {
-       struct device *dev = &phydev->mdio.dev;
-+      struct clk *rx_clk, *tx_clk;
-       struct ipq5018_priv *priv;
-       int ret;
-@@ -1099,6 +1101,16 @@ static int ipq5018_probe(struct phy_devi
-       priv->set_short_cable_dac = of_property_read_bool(dev->of_node,
-                                                         "qcom,dac-preset-short-cable");
-+      rx_clk = devm_clk_get_enabled(dev, "rx");
-+      if (IS_ERR(rx_clk))
-+              return dev_err_probe(dev, PTR_ERR(rx_clk),
-+                                   "failed to get and enable RX clock\n");
-+
-+      tx_clk = devm_clk_get_enabled(dev, "tx");
-+      if (IS_ERR(tx_clk))
-+              return dev_err_probe(dev, PTR_ERR(tx_clk),
-+                                   "failed to get and enable TX clock\n");
-+
-       priv->rst = devm_reset_control_array_get_exclusive(dev);
-       if (IS_ERR(priv->rst))
-               return dev_err_probe(dev, PTR_ERR(priv->rst),
diff --git a/target/linux/qualcommax/patches-6.12/0090-v7.3-arm64-qcom-ipq5018-Add-GEPHY-RX-and-TX-clocks.patch b/target/linux/qualcommax/patches-6.12/0090-v7.3-arm64-qcom-ipq5018-Add-GEPHY-RX-and-TX-clocks.patch
deleted file mode 100644 (file)
index b77a834..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From 20959cefc27e7e2e506b4e789b728e5702c77f95 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 8 Jun 2026 09:09:18 +0400
-Subject: arm64: qcom: ipq5018: Add GEPHY RX and TX clocks
-
-Add RX and TX clocks for the IPQ5018 GEPHY to enable the datapath.
-
-Fixes: f5f2b835e316 ("arm64: dts: qcom: ipq5018: Add GE PHY to internal mdio bus")
-Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Link: https://lore.kernel.org/r/20260608-ipq5018-gephy-clocks-v4-3-fb2ccd56894b@outlook.com
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 3 +++
- 1 file changed, 3 insertions(+)
-
-(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -229,6 +229,9 @@
-                               compatible = "ethernet-phy-id004d.d0c0";
-                               reg = <7>;
-+                              clocks = <&gcc GCC_GEPHY_RX_CLK>,
-+                                       <&gcc GCC_GEPHY_TX_CLK>;
-+                              clock-names = "rx", "tx";
-                               resets = <&gcc GCC_GEPHY_MISC_ARES>;
-                       };
-               };
diff --git a/target/linux/qualcommax/patches-6.12/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch b/target/linux/qualcommax/patches-6.12/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch
deleted file mode 100644 (file)
index 6d97641..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-From ad2d07f71739351eeea1d8a120c0918e2c4b265f Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 22 Dec 2021 12:23:34 +0100
-Subject: [PATCH] arm64: dts: ipq8074: add reserved memory nodes
-
-IPQ8074 has multiple reserved memory ranges, if they are not defined
-then weird things tend to happen, board hangs and resets when PCI or
-WLAN is used etc.
-
-So, to avoid all of that add the reserved memory nodes from the downstream
-5.4 kernel from QCA.
-This is their default layout meant for devices with 1GB of RAM, but
-devices with lower ammounts can override the Q6 node.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 35 +++++++++++++++++++++++++++
- 1 file changed, 35 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -86,6 +86,16 @@
-               #size-cells = <2>;
-               ranges;
-+              nss@40000000 {
-+                      no-map;
-+                      reg = <0x0 0x40000000 0x0 0x01000000>;
-+              };
-+
-+              tzapp_region: tzapp@4a400000 {
-+                      no-map;
-+                      reg = <0x0 0x4a400000 0x0 0x00200000>;
-+              };
-+
-               bootloader@4a600000 {
-                       reg = <0x0 0x4a600000 0x0 0x400000>;
-                       no-map;
-@@ -108,6 +118,21 @@
-                       reg = <0x0 0x4ac00000 0x0 0x400000>;
-                       no-map;
-               };
-+
-+              q6_region: wcnss@4b000000 {
-+                      no-map;
-+                      reg = <0x0 0x4b000000 0x0 0x05f00000>;
-+              };
-+
-+              q6_etr_region: q6_etr_dump@50f00000 {
-+                      no-map;
-+                      reg = <0x0 0x50f00000 0x0 0x00100000>;
-+              };
-+
-+              m3_dump_region: m3_dump@51000000 {
-+                      no-map;
-+                      reg = <0x0 0x51000000 0x0 0x100000>;
-+              };
-       };
-       firmware {
diff --git a/target/linux/qualcommax/patches-6.12/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch b/target/linux/qualcommax/patches-6.12/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch
deleted file mode 100644 (file)
index a12dc44..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-From fb1f6850be00d8dd8a54017be4c1336e224069ac Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 16 Nov 2022 22:26:25 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: use msi-parent for PCIe
-
-Instead of hardcoding the IRQ, simply use msi-parent instead.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -759,7 +759,7 @@
-                       reg = <0x0b000000 0x1000>, <0x0b002000 0x1000>;
-                       ranges = <0 0xb00a000 0xffd>;
--                      v2m@0 {
-+                      gic_v2m0: v2m@0 {
-                               compatible = "arm,gic-v2m-frame";
-                               msi-controller;
-                               reg = <0x0 0xffd>;
-@@ -872,8 +872,7 @@
-                       ranges = <0x81000000 0x0 0x00000000 0x10200000 0x0 0x10000>,   /* I/O */
-                                <0x82000000 0x0 0x10220000 0x10220000 0x0 0xfde0000>; /* MEM */
--                      interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
--                      interrupt-names = "msi";
-+                      msi-parent = <&gic_v2m0>;
-                       #interrupt-cells = <1>;
-                       interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 0 142
-@@ -944,8 +943,7 @@
-                       ranges = <0x81000000 0x0 0x00000000 0x20200000 0x0 0x10000>,   /* I/O */
-                                <0x82000000 0x0 0x20220000 0x20220000 0x0 0xfde0000>; /* MEM */
--                      interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
--                      interrupt-names = "msi";
-+                      msi-parent = <&gic_v2m0>;
-                       #interrupt-cells = <1>;
-                       interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 0 75
diff --git a/target/linux/qualcommax/patches-6.12/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch b/target/linux/qualcommax/patches-6.12/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch
deleted file mode 100644 (file)
index ac46f9e..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-From 125681433c8e526356947acf572fe8ca8ad32291 Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:05 +0530
-Subject: [PATCH] remoteproc: qcom: Add PRNG proxy clock
-
-PRNG clock is needed by the secure PIL, support for the same
-is added in subsequent patches.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 65 +++++++++++++++++++++--------
- 1 file changed, 47 insertions(+), 18 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -91,19 +91,6 @@ enum {
-       WCSS_QCS404,
- };
--struct wcss_data {
--      const char *firmware_name;
--      unsigned int crash_reason_smem;
--      u32 version;
--      bool aon_reset_required;
--      bool wcss_q6_reset_required;
--      const char *ssr_name;
--      const char *sysmon_name;
--      int ssctl_id;
--      const struct rproc_ops *ops;
--      bool requires_force_stop;
--};
--
- struct q6v5_wcss {
-       struct device *dev;
-@@ -128,6 +115,7 @@ struct q6v5_wcss {
-       struct clk *qdsp6ss_xo_cbcr;
-       struct clk *qdsp6ss_core_gfmux;
-       struct clk *lcc_bcr_sleep;
-+      struct clk *prng_clk;
-       struct regulator *cx_supply;
-       struct qcom_sysmon *sysmon;
-@@ -152,6 +140,21 @@ struct q6v5_wcss {
-       struct qcom_rproc_ssr ssr_subdev;
- };
-+struct wcss_data {
-+      int (*init_clock)(struct q6v5_wcss *wcss);
-+      int (*init_regulator)(struct q6v5_wcss *wcss);
-+      const char *firmware_name;
-+      unsigned int crash_reason_smem;
-+      u32 version;
-+      bool aon_reset_required;
-+      bool wcss_q6_reset_required;
-+      const char *ssr_name;
-+      const char *sysmon_name;
-+      int ssctl_id;
-+      const struct rproc_ops *ops;
-+      bool requires_force_stop;
-+};
-+
- static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
- {
-       int ret;
-@@ -241,6 +244,12 @@ static int q6v5_wcss_start(struct rproc
-       struct q6v5_wcss *wcss = rproc->priv;
-       int ret;
-+      ret = clk_prepare_enable(wcss->prng_clk);
-+      if (ret) {
-+              dev_err(wcss->dev, "prng clock enable failed\n");
-+              return ret;
-+      }
-+
-       qcom_q6v5_prepare(&wcss->q6v5);
-       /* Release Q6 and WCSS reset */
-@@ -734,6 +743,7 @@ static int q6v5_wcss_stop(struct rproc *
-                       return ret;
-       }
-+      clk_disable_unprepare(wcss->prng_clk);
-       qcom_q6v5_unprepare(&wcss->q6v5);
-       return 0;
-@@ -900,7 +910,21 @@ static int q6v5_alloc_memory_region(stru
-       return 0;
- }
--static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss)
-+static int ipq8074_init_clock(struct q6v5_wcss *wcss)
-+{
-+      int ret;
-+
-+      wcss->prng_clk = devm_clk_get(wcss->dev, "prng");
-+      if (IS_ERR(wcss->prng_clk)) {
-+              ret = PTR_ERR(wcss->prng_clk);
-+              if (ret != -EPROBE_DEFER)
-+                      dev_err(wcss->dev, "Failed to get prng clock\n");
-+              return ret;
-+      }
-+      return 0;
-+}
-+
-+static int qcs404_init_clock(struct q6v5_wcss *wcss)
- {
-       int ret;
-@@ -990,7 +1014,7 @@ static int q6v5_wcss_init_clock(struct q
-       return 0;
- }
--static int q6v5_wcss_init_regulator(struct q6v5_wcss *wcss)
-+static int qcs404_init_regulator(struct q6v5_wcss *wcss)
- {
-       wcss->cx_supply = devm_regulator_get(wcss->dev, "cx");
-       if (IS_ERR(wcss->cx_supply))
-@@ -1034,12 +1058,14 @@ static int q6v5_wcss_probe(struct platfo
-       if (ret)
-               return ret;
--      if (wcss->version == WCSS_QCS404) {
--              ret = q6v5_wcss_init_clock(wcss);
-+      if (desc->init_clock) {
-+              ret = desc->init_clock(wcss);
-               if (ret)
-                       return ret;
-+      }
--              ret = q6v5_wcss_init_regulator(wcss);
-+      if (desc->init_regulator) {
-+              ret = desc->init_regulator(wcss);
-               if (ret)
-                       return ret;
-       }
-@@ -1081,6 +1107,7 @@ static void q6v5_wcss_remove(struct plat
- }
- static const struct wcss_data wcss_ipq8074_res_init = {
-+      .init_clock = ipq8074_init_clock,
-       .firmware_name = "IPQ8074/q6_fw.mdt",
-       .crash_reason_smem = WCSS_CRASH_REASON,
-       .aon_reset_required = true,
-@@ -1090,6 +1117,8 @@ static const struct wcss_data wcss_ipq80
- };
- static const struct wcss_data wcss_qcs404_res_init = {
-+      .init_clock = qcs404_init_clock,
-+      .init_regulator = qcs404_init_regulator,
-       .crash_reason_smem = WCSS_CRASH_REASON,
-       .firmware_name = "wcnss.mdt",
-       .version = WCSS_QCS404,
diff --git a/target/linux/qualcommax/patches-6.12/0113-remoteproc-qcom-Add-secure-PIL-support.patch b/target/linux/qualcommax/patches-6.12/0113-remoteproc-qcom-Add-secure-PIL-support.patch
deleted file mode 100644 (file)
index 6b11f04..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-From 7358d42dfbdfdb5d4f1d0d4c2e5c2bb4143a29b0 Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:06 +0530
-Subject: [PATCH] remoteproc: qcom: Add secure PIL support
-
-IPQ8074 uses secure PIL. Hence, adding the support for the same.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 43 +++++++++++++++++++++++++++--
- 1 file changed, 40 insertions(+), 3 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -18,6 +18,7 @@
- #include <linux/regulator/consumer.h>
- #include <linux/reset.h>
- #include <linux/soc/qcom/mdt_loader.h>
-+#include <linux/firmware/qcom/qcom_scm.h>
- #include "qcom_common.h"
- #include "qcom_pil_info.h"
- #include "qcom_q6v5.h"
-@@ -86,6 +87,9 @@
- #define TCSR_WCSS_CLK_ENABLE  0x14
- #define MAX_HALT_REG          4
-+
-+#define WCNSS_PAS_ID          6
-+
- enum {
-       WCSS_IPQ8074,
-       WCSS_QCS404,
-@@ -134,6 +138,7 @@ struct q6v5_wcss {
-       unsigned int crash_reason_smem;
-       u32 version;
-       bool requires_force_stop;
-+      bool need_mem_protection;
-       struct qcom_rproc_glink glink_subdev;
-       struct qcom_rproc_pdm pdm_subdev;
-@@ -153,6 +158,7 @@ struct wcss_data {
-       int ssctl_id;
-       const struct rproc_ops *ops;
-       bool requires_force_stop;
-+      bool need_mem_protection;
- };
- static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
-@@ -252,6 +258,15 @@ static int q6v5_wcss_start(struct rproc
-       qcom_q6v5_prepare(&wcss->q6v5);
-+      if (wcss->need_mem_protection) {
-+              ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
-+              if (ret) {
-+                      dev_err(wcss->dev, "wcss_reset failed\n");
-+                      return ret;
-+              }
-+              goto wait_for_reset;
-+      }
-+
-       /* Release Q6 and WCSS reset */
-       ret = reset_control_deassert(wcss->wcss_reset);
-       if (ret) {
-@@ -286,6 +301,7 @@ static int q6v5_wcss_start(struct rproc
-       if (ret)
-               goto wcss_q6_reset;
-+wait_for_reset:
-       ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
-       if (ret == -ETIMEDOUT)
-               dev_err(wcss->dev, "start timed out\n");
-@@ -719,6 +735,15 @@ static int q6v5_wcss_stop(struct rproc *
-       struct q6v5_wcss *wcss = rproc->priv;
-       int ret;
-+      if (wcss->need_mem_protection) {
-+              ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
-+              if (ret) {
-+                      dev_err(wcss->dev, "not able to shutdown\n");
-+                      return ret;
-+              }
-+              goto pas_done;
-+      }
-+
-       /* WCSS powerdown */
-       if (wcss->requires_force_stop) {
-               ret = qcom_q6v5_request_stop(&wcss->q6v5, NULL);
-@@ -743,6 +768,7 @@ static int q6v5_wcss_stop(struct rproc *
-                       return ret;
-       }
-+pas_done:
-       clk_disable_unprepare(wcss->prng_clk);
-       qcom_q6v5_unprepare(&wcss->q6v5);
-@@ -766,9 +792,15 @@ static int q6v5_wcss_load(struct rproc *
-       struct q6v5_wcss *wcss = rproc->priv;
-       int ret;
--      ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
--                                  0, wcss->mem_region, wcss->mem_phys,
--                                  wcss->mem_size, &wcss->mem_reloc);
-+      if (wcss->need_mem_protection)
-+              ret = qcom_mdt_load(wcss->dev, fw, rproc->firmware,
-+                                  WCNSS_PAS_ID, wcss->mem_region,
-+                                  wcss->mem_phys, wcss->mem_size,
-+                                  &wcss->mem_reloc);
-+      else
-+              ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
-+                                          0, wcss->mem_region, wcss->mem_phys,
-+                                          wcss->mem_size, &wcss->mem_reloc);
-       if (ret)
-               return ret;
-@@ -1036,6 +1068,9 @@ static int q6v5_wcss_probe(struct platfo
-       if (!desc)
-               return -EINVAL;
-+      if (desc->need_mem_protection && !qcom_scm_is_available())
-+              return -EPROBE_DEFER;
-+
-       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, desc->ops,
-                                desc->firmware_name, sizeof(*wcss));
-       if (!rproc) {
-@@ -1049,6 +1084,7 @@ static int q6v5_wcss_probe(struct platfo
-       wcss->version = desc->version;
-       wcss->requires_force_stop = desc->requires_force_stop;
-+      wcss->need_mem_protection = desc->need_mem_protection;
-       ret = q6v5_wcss_init_mmio(wcss, pdev);
-       if (ret)
-@@ -1114,6 +1150,7 @@ static const struct wcss_data wcss_ipq80
-       .wcss_q6_reset_required = true,
-       .ops = &q6v5_wcss_ipq8074_ops,
-       .requires_force_stop = true,
-+      .need_mem_protection = true,
- };
- static const struct wcss_data wcss_qcs404_res_init = {
diff --git a/target/linux/qualcommax/patches-6.12/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch b/target/linux/qualcommax/patches-6.12/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch
deleted file mode 100644 (file)
index be793d6..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-From b422c9d4f048b086ce83f44a7cfcddcce162897f Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:07 +0530
-Subject: [PATCH] remoteproc: qcom: Add support for split q6 + m3 wlan firmware
-
-IPQ8074 supports split firmware for q6 and m3 as well.
-So add support for loading the m3 firmware before q6.
-Now the drivers works fine for both split and unified
-firmwares.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 33 +++++++++++++++++++++++++----
- 1 file changed, 29 insertions(+), 4 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -139,6 +139,7 @@ struct q6v5_wcss {
-       u32 version;
-       bool requires_force_stop;
-       bool need_mem_protection;
-+      const char *m3_firmware_name;
-       struct qcom_rproc_glink glink_subdev;
-       struct qcom_rproc_pdm pdm_subdev;
-@@ -148,7 +149,8 @@ struct q6v5_wcss {
- struct wcss_data {
-       int (*init_clock)(struct q6v5_wcss *wcss);
-       int (*init_regulator)(struct q6v5_wcss *wcss);
--      const char *firmware_name;
-+      const char *q6_firmware_name;
-+      const char *m3_firmware_name;
-       unsigned int crash_reason_smem;
-       u32 version;
-       bool aon_reset_required;
-@@ -790,8 +792,29 @@ static void *q6v5_wcss_da_to_va(struct r
- static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
- {
-       struct q6v5_wcss *wcss = rproc->priv;
-+      const struct firmware *m3_fw;
-       int ret;
-+      if (wcss->m3_firmware_name) {
-+              ret = request_firmware(&m3_fw, wcss->m3_firmware_name,
-+                                     wcss->dev);
-+              if (ret)
-+                      goto skip_m3;
-+
-+              ret = qcom_mdt_load_no_init(wcss->dev, m3_fw,
-+                                          wcss->m3_firmware_name, 0,
-+                                          wcss->mem_region, wcss->mem_phys,
-+                                          wcss->mem_size, &wcss->mem_reloc);
-+
-+              release_firmware(m3_fw);
-+
-+              if (ret) {
-+                      dev_err(wcss->dev, "can't load m3_fw.bXX\n");
-+                      return ret;
-+              }
-+      }
-+
-+skip_m3:
-       if (wcss->need_mem_protection)
-               ret = qcom_mdt_load(wcss->dev, fw, rproc->firmware,
-                                   WCNSS_PAS_ID, wcss->mem_region,
-@@ -1072,7 +1095,7 @@ static int q6v5_wcss_probe(struct platfo
-               return -EPROBE_DEFER;
-       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, desc->ops,
--                               desc->firmware_name, sizeof(*wcss));
-+                               desc->q6_firmware_name, sizeof(*wcss));
-       if (!rproc) {
-               dev_err(&pdev->dev, "failed to allocate rproc\n");
-               return -ENOMEM;
-@@ -1085,6 +1108,7 @@ static int q6v5_wcss_probe(struct platfo
-       wcss->version = desc->version;
-       wcss->requires_force_stop = desc->requires_force_stop;
-       wcss->need_mem_protection = desc->need_mem_protection;
-+      wcss->m3_firmware_name = desc->m3_firmware_name;
-       ret = q6v5_wcss_init_mmio(wcss, pdev);
-       if (ret)
-@@ -1144,7 +1168,8 @@ static void q6v5_wcss_remove(struct plat
- static const struct wcss_data wcss_ipq8074_res_init = {
-       .init_clock = ipq8074_init_clock,
--      .firmware_name = "IPQ8074/q6_fw.mdt",
-+      .q6_firmware_name = "IPQ8074/q6_fw.mdt",
-+      .m3_firmware_name = "IPQ8074/m3_fw.mdt",
-       .crash_reason_smem = WCSS_CRASH_REASON,
-       .aon_reset_required = true,
-       .wcss_q6_reset_required = true,
-@@ -1157,7 +1182,7 @@ static const struct wcss_data wcss_qcs40
-       .init_clock = qcs404_init_clock,
-       .init_regulator = qcs404_init_regulator,
-       .crash_reason_smem = WCSS_CRASH_REASON,
--      .firmware_name = "wcnss.mdt",
-+      .q6_firmware_name = "wcnss.mdt",
-       .version = WCSS_QCS404,
-       .aon_reset_required = false,
-       .wcss_q6_reset_required = false,
diff --git a/target/linux/qualcommax/patches-6.12/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch b/target/linux/qualcommax/patches-6.12/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch
deleted file mode 100644 (file)
index 5d6a573..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From 3a8f67b4770c817b04794c9a02e3f88f85d86280 Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:08 +0530
-Subject: [PATCH] remoteproc: qcom: Add ssr subdevice identifier
-
-Add name for ssr subdevice on IPQ8074 SoC.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -1173,6 +1173,7 @@ static const struct wcss_data wcss_ipq80
-       .crash_reason_smem = WCSS_CRASH_REASON,
-       .aon_reset_required = true,
-       .wcss_q6_reset_required = true,
-+      .ssr_name = "q6wcss",
-       .ops = &q6v5_wcss_ipq8074_ops,
-       .requires_force_stop = true,
-       .need_mem_protection = true,
diff --git a/target/linux/qualcommax/patches-6.12/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch b/target/linux/qualcommax/patches-6.12/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch
deleted file mode 100644 (file)
index c9795b8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-From 8c73af6e8d78c66cfef0f551b00d375ec0b67ff3 Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:09 +0530
-Subject: [PATCH] remoteproc: qcom: Update regmap offsets for halt register
-
-Fixed issue in reading halt-regs parameter from device-tree.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 22 ++++++++++++++--------
- 1 file changed, 14 insertions(+), 8 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -155,6 +155,7 @@ struct wcss_data {
-       u32 version;
-       bool aon_reset_required;
-       bool wcss_q6_reset_required;
-+      bool bcr_reset_required;
-       const char *ssr_name;
-       const char *sysmon_name;
-       int ssctl_id;
-@@ -876,10 +877,13 @@ static int q6v5_wcss_init_reset(struct q
-               }
-       }
--      wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_bcr_reset");
--      if (IS_ERR(wcss->wcss_q6_bcr_reset)) {
--              dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
--              return PTR_ERR(wcss->wcss_q6_bcr_reset);
-+      if (desc->bcr_reset_required) {
-+              wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev,
-+                                                                         "wcss_q6_bcr_reset");
-+              if (IS_ERR(wcss->wcss_q6_bcr_reset)) {
-+                      dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
-+                      return PTR_ERR(wcss->wcss_q6_bcr_reset);
-+              }
-       }
-       return 0;
-@@ -1173,6 +1177,7 @@ static const struct wcss_data wcss_ipq80
-       .crash_reason_smem = WCSS_CRASH_REASON,
-       .aon_reset_required = true,
-       .wcss_q6_reset_required = true,
-+      .bcr_reset_required = false,
-       .ssr_name = "q6wcss",
-       .ops = &q6v5_wcss_ipq8074_ops,
-       .requires_force_stop = true,
-@@ -1187,6 +1192,7 @@ static const struct wcss_data wcss_qcs40
-       .version = WCSS_QCS404,
-       .aon_reset_required = false,
-       .wcss_q6_reset_required = false,
-+      .bcr_reset_required = true,
-       .ssr_name = "mpss",
-       .sysmon_name = "wcnss",
-       .ssctl_id = 0x12,
diff --git a/target/linux/qualcommax/patches-6.12/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch b/target/linux/qualcommax/patches-6.12/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch
deleted file mode 100644 (file)
index fe0e0f9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From ff7c6533ed8c4de58ed6c8aab03ea59c03eb4f31 Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:10 +0530
-Subject: [PATCH] dt-bindings: clock: qcom: Add reset for WCSSAON
-
-Add binding for WCSSAON reset required for Q6v5 reset on IPQ8074 SoC.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
-Acked-by: Rob Herring <robh@kernel.org>
-Acked-by: Stephen Boyd <sboyd@kernel.org>
----
- include/dt-bindings/clock/qcom,gcc-ipq8074.h | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h
-+++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h
-@@ -381,6 +381,7 @@
- #define GCC_NSSPORT4_RESET                    143
- #define GCC_NSSPORT5_RESET                    144
- #define GCC_NSSPORT6_RESET                    145
-+#define GCC_WCSSAON_RESET                     146
- #define USB0_GDSC                             0
- #define USB1_GDSC                             1
diff --git a/target/linux/qualcommax/patches-6.12/0118-clk-qcom-Add-WCSSAON-reset.patch b/target/linux/qualcommax/patches-6.12/0118-clk-qcom-Add-WCSSAON-reset.patch
deleted file mode 100644 (file)
index 7938b18..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 43d9788f546d24df22d8ba3fcc2497d7ccc198f3 Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:11 +0530
-Subject: [PATCH] clk: qcom: Add WCSSAON reset
-
-Add WCSSAON reset required for Q6v5 on IPQ8074 SoC.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
-Acked-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/gcc-ipq8074.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/clk/qcom/gcc-ipq8074.c
-+++ b/drivers/clk/qcom/gcc-ipq8074.c
-@@ -4712,6 +4712,7 @@ static const struct qcom_reset_map gcc_i
-       [GCC_NSSPORT4_RESET] = { .reg = 0x68014, .bitmask = BIT(27) | GENMASK(9, 8) },
-       [GCC_NSSPORT5_RESET] = { .reg = 0x68014, .bitmask = BIT(28) | GENMASK(11, 10) },
-       [GCC_NSSPORT6_RESET] = { .reg = 0x68014, .bitmask = BIT(29) | GENMASK(13, 12) },
-+      [GCC_WCSSAON_RESET] = { 0x59010, 0 },
- };
- static struct gdsc *gcc_ipq8074_gdscs[] = {
diff --git a/target/linux/qualcommax/patches-6.12/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch b/target/linux/qualcommax/patches-6.12/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch
deleted file mode 100644 (file)
index ccb78de..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 406a332fd1bcc4e18d73cce390f56272fe9111d7 Mon Sep 17 00:00:00 2001
-From: Sivaprakash Murugesan <sivaprak@codeaurora.org>
-Date: Fri, 17 Apr 2020 16:37:10 +0530
-Subject: [PATCH] remoteproc: wcss: disable auto boot for IPQ8074
-
-There is no need for remoteproc to boot automatically, ath11k will trigger
-booting when its probing.
-
-Signed-off-by: Sivaprakash Murugesan <sivaprak@codeaurora.org>
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -162,6 +162,7 @@ struct wcss_data {
-       const struct rproc_ops *ops;
-       bool requires_force_stop;
-       bool need_mem_protection;
-+      bool need_auto_boot;
- };
- static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
-@@ -1151,6 +1152,7 @@ static int q6v5_wcss_probe(struct platfo
-                                                     desc->sysmon_name,
-                                                     desc->ssctl_id);
-+      rproc->auto_boot = desc->need_auto_boot;
-       ret = rproc_add(rproc);
-       if (ret)
-               return ret;
-@@ -1182,6 +1184,7 @@ static const struct wcss_data wcss_ipq80
-       .ops = &q6v5_wcss_ipq8074_ops,
-       .requires_force_stop = true,
-       .need_mem_protection = true,
-+      .need_auto_boot = false,
- };
- static const struct wcss_data wcss_qcs404_res_init = {
-@@ -1198,6 +1201,7 @@ static const struct wcss_data wcss_qcs40
-       .ssctl_id = 0x12,
-       .ops = &q6v5_wcss_qcs404_ops,
-       .requires_force_stop = false,
-+      .need_auto_boot = true,
- };
- static const struct of_device_id q6v5_wcss_of_match[] = {
diff --git a/target/linux/qualcommax/patches-6.12/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch b/target/linux/qualcommax/patches-6.12/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch
deleted file mode 100644 (file)
index ea723f5..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-From 7388400b8bd42f71d040dbf2fdbdcb834fcc0ede Mon Sep 17 00:00:00 2001
-From: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date: Sat, 30 Jan 2021 10:50:13 +0530
-Subject: [PATCH] arm64: dts: qcom: Enable Q6v5 WCSS for ipq8074 SoC
-
-Enable remoteproc WCSS PIL driver with glink and ssr subdevices.
-Also enables smp2p and mailboxes required for IPC.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Signed-off-by: Nikhil Prakash V <nprakash@codeaurora.org>
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 81 +++++++++++++++++++++++++++
- 1 file changed, 81 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -142,6 +142,32 @@
-               };
-       };
-+      wcss: smp2p-wcss {
-+              compatible = "qcom,smp2p";
-+              qcom,smem = <435>, <428>;
-+
-+              interrupt-parent = <&intc>;
-+              interrupts = <0 322 1>;
-+
-+              mboxes = <&apcs_glb 9>;
-+
-+              qcom,local-pid = <0>;
-+              qcom,remote-pid = <1>;
-+
-+              wcss_smp2p_out: master-kernel {
-+                      qcom,entry-name = "master-kernel";
-+                      qcom,smp2p-feature-ssr-ack;
-+                      #qcom,smem-state-cells = <1>;
-+              };
-+
-+              wcss_smp2p_in: slave-kernel {
-+                      qcom,entry-name = "slave-kernel";
-+
-+                      interrupt-controller;
-+                      #interrupt-cells = <2>;
-+              };
-+      };
-+
-       soc: soc@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-@@ -415,6 +441,11 @@
-                       reg = <0x01937000 0x21000>;
-               };
-+              tcsr_q6: syscon@1945000 {
-+                      compatible = "syscon";
-+                      reg = <0x01945000 0xe000>;
-+              };
-+
-               spmi_bus: spmi@200f000 {
-                       compatible = "qcom,spmi-pmic-arb";
-                       reg = <0x0200f000 0x001000>,
-@@ -994,6 +1025,56 @@
-                               ranges;
-                       };
-               };
-+
-+              q6v5_wcss: q6v5_wcss@cd00000 {
-+                      compatible = "qcom,ipq8074-wcss-pil";
-+                      reg = <0x0cd00000 0x4040>,
-+                            <0x004ab000 0x20>;
-+                      reg-names = "qdsp6",
-+                                  "rmb";
-+                      qca,auto-restart;
-+                      qca,extended-intc;
-+                      interrupts-extended = <&intc 0 325 1>,
-+                                            <&wcss_smp2p_in 0 0>,
-+                                            <&wcss_smp2p_in 1 0>,
-+                                            <&wcss_smp2p_in 2 0>,
-+                                            <&wcss_smp2p_in 3 0>;
-+                      interrupt-names = "wdog",
-+                                        "fatal",
-+                                        "ready",
-+                                        "handover",
-+                                        "stop-ack";
-+
-+                      resets = <&gcc GCC_WCSSAON_RESET>,
-+                               <&gcc GCC_WCSS_BCR>,
-+                               <&gcc GCC_WCSS_Q6_BCR>;
-+
-+                      reset-names = "wcss_aon_reset",
-+                                    "wcss_reset",
-+                                    "wcss_q6_reset";
-+
-+                      clocks = <&gcc GCC_PRNG_AHB_CLK>;
-+                      clock-names = "prng";
-+
-+                      qcom,halt-regs = <&tcsr_q6 0xa000 0xd000 0x0>;
-+
-+                      qcom,smem-states = <&wcss_smp2p_out 0>,
-+                                         <&wcss_smp2p_out 1>;
-+                      qcom,smem-state-names = "shutdown",
-+                                              "stop";
-+
-+                      memory-region = <&q6_region>;
-+
-+                      glink-edge {
-+                              interrupts = <GIC_SPI 321 IRQ_TYPE_EDGE_RISING>;
-+                              qcom,remote-pid = <1>;
-+                              mboxes = <&apcs_glb 8>;
-+
-+                              rpm_requests {
-+                                      qcom,glink-channels = "IPCRTR";
-+                              };
-+                      };
-+              };
-       };
-       timer {
diff --git a/target/linux/qualcommax/patches-6.12/0121-arm64-dts-ipq8074-Add-WLAN-node.patch b/target/linux/qualcommax/patches-6.12/0121-arm64-dts-ipq8074-Add-WLAN-node.patch
deleted file mode 100644 (file)
index dcab329..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-From a67d1901741c162645eda0dbdc3a2c0c2aff5cf4 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Tue, 21 Dec 2021 14:49:36 +0100
-Subject: [PATCH] arm64: dts: ipq8074: Add WLAN node
-
-IPQ8074 has a AHB based Q6v5 802.11ax radios that are supported
-by the ath11k.
-
-Add the required DT node to enable the built-in radios.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 111 ++++++++++++++++++++++++++
- 1 file changed, 111 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -1075,6 +1075,117 @@
-                               };
-                       };
-               };
-+
-+              wifi: wifi@c0000000 {
-+                      compatible = "qcom,ipq8074-wifi";
-+                      reg = <0xc000000 0x2000000>;
-+
-+                      interrupts = <GIC_SPI 320 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 319 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 318 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 316 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 315 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 314 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 311 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 310 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 40 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 302 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 301 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 293 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 292 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 291 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 290 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 289 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 288 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 239 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 236 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 235 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 234 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 233 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 232 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 231 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 230 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 228 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 224 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 223 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 163 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 160 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 159 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 158 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 157 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
-+
-+                      interrupt-names = "misc-pulse1",
-+                                        "misc-latch",
-+                                        "sw-exception",
-+                                        "ce0",
-+                                        "ce1",
-+                                        "ce2",
-+                                        "ce3",
-+                                        "ce4",
-+                                        "ce5",
-+                                        "ce6",
-+                                        "ce7",
-+                                        "ce8",
-+                                        "ce9",
-+                                        "ce10",
-+                                        "ce11",
-+                                        "host2wbm-desc-feed",
-+                                        "host2reo-re-injection",
-+                                        "host2reo-command",
-+                                        "host2rxdma-monitor-ring3",
-+                                        "host2rxdma-monitor-ring2",
-+                                        "host2rxdma-monitor-ring1",
-+                                        "reo2ost-exception",
-+                                        "wbm2host-rx-release",
-+                                        "reo2host-status",
-+                                        "reo2host-destination-ring4",
-+                                        "reo2host-destination-ring3",
-+                                        "reo2host-destination-ring2",
-+                                        "reo2host-destination-ring1",
-+                                        "rxdma2host-monitor-destination-mac3",
-+                                        "rxdma2host-monitor-destination-mac2",
-+                                        "rxdma2host-monitor-destination-mac1",
-+                                        "ppdu-end-interrupts-mac3",
-+                                        "ppdu-end-interrupts-mac2",
-+                                        "ppdu-end-interrupts-mac1",
-+                                        "rxdma2host-monitor-status-ring-mac3",
-+                                        "rxdma2host-monitor-status-ring-mac2",
-+                                        "rxdma2host-monitor-status-ring-mac1",
-+                                        "host2rxdma-host-buf-ring-mac3",
-+                                        "host2rxdma-host-buf-ring-mac2",
-+                                        "host2rxdma-host-buf-ring-mac1",
-+                                        "rxdma2host-destination-ring-mac3",
-+                                        "rxdma2host-destination-ring-mac2",
-+                                        "rxdma2host-destination-ring-mac1",
-+                                        "host2tcl-input-ring4",
-+                                        "host2tcl-input-ring3",
-+                                        "host2tcl-input-ring2",
-+                                        "host2tcl-input-ring1",
-+                                        "wbm2host-tx-completions-ring3",
-+                                        "wbm2host-tx-completions-ring2",
-+                                        "wbm2host-tx-completions-ring1",
-+                                        "tcl2host-status-ring";
-+                      qcom,rproc = <&q6v5_wcss>;
-+                      status = "disabled";
-+              };
-       };
-       timer {
diff --git a/target/linux/qualcommax/patches-6.12/0122-arm64-dts-ipq8074-add-CPU-clock.patch b/target/linux/qualcommax/patches-6.12/0122-arm64-dts-ipq8074-add-CPU-clock.patch
deleted file mode 100644 (file)
index a6265ff..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-From cb3ef99c1553565e1dc0301ccd5c1c0fa2d15c15 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 31 Dec 2021 17:56:14 +0100
-Subject: [PATCH] arm64: dts: ipq8074: add CPU clock
-
-Now that CPU clock is exposed and can be controlled, add the necessary
-properties to the CPU nodes.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -5,6 +5,7 @@
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/clock/qcom,gcc-ipq8074.h>
-+#include <dt-bindings/clock/qcom,apss-ipq.h>
- / {
-       #address-cells = <2>;
-@@ -38,6 +39,8 @@
-                       reg = <0x0>;
-                       next-level-cache = <&l2_0>;
-                       enable-method = "psci";
-+                      clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-+                      clock-names = "cpu";
-               };
-               cpu1: cpu@1 {
-@@ -46,6 +49,8 @@
-                       enable-method = "psci";
-                       reg = <0x1>;
-                       next-level-cache = <&l2_0>;
-+                      clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-+                      clock-names = "cpu";
-               };
-               cpu2: cpu@2 {
-@@ -54,6 +59,8 @@
-                       enable-method = "psci";
-                       reg = <0x2>;
-                       next-level-cache = <&l2_0>;
-+                      clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-+                      clock-names = "cpu";
-               };
-               cpu3: cpu@3 {
-@@ -62,6 +69,8 @@
-                       enable-method = "psci";
-                       reg = <0x3>;
-                       next-level-cache = <&l2_0>;
-+                      clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-+                      clock-names = "cpu";
-               };
-               l2_0: l2-cache {
diff --git a/target/linux/qualcommax/patches-6.12/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch b/target/linux/qualcommax/patches-6.12/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch
deleted file mode 100644 (file)
index bea3580..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 347ca56e86c99021fad059b9a8ef101245b8507e Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 31 Dec 2021 20:38:06 +0100
-Subject: [PATCH] arm64: dts: ipq8074: add cooling cells to CPU nodes
-
-Since there is CPU Freq support as well as thermal sensor support
-now for the IPQ8074, add cooling cells to CPU nodes so that they can
-be used as cooling devices using CPU Freq.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -41,6 +41,7 @@
-                       enable-method = "psci";
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-+                      #cooling-cells = <2>;
-               };
-               cpu1: cpu@1 {
-@@ -51,6 +52,7 @@
-                       next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-+                      #cooling-cells = <2>;
-               };
-               cpu2: cpu@2 {
-@@ -61,6 +63,7 @@
-                       next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-+                      #cooling-cells = <2>;
-               };
-               cpu3: cpu@3 {
-@@ -71,6 +74,7 @@
-                       next-level-cache = <&l2_0>;
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-+                      #cooling-cells = <2>;
-               };
-               l2_0: l2-cache {
diff --git a/target/linux/qualcommax/patches-6.12/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch b/target/linux/qualcommax/patches-6.12/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch
deleted file mode 100644 (file)
index a9ac029..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-From 04d2fc6a551bbd972a6428059b45ce79cb9de9d7 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 6 May 2022 22:38:24 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add QFPROM fuses
-
-Add the QFPROM node and CPR fuses.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 107 ++++++++++++++++++++++++++
- 1 file changed, 107 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -326,6 +326,106 @@
-                       reg = <0x000a4000 0x2000>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-+
-+                      cpr_efuse_speedbin: speedbin@125 {
-+                              reg = <0x125 0x1>;
-+                              bits = <0 3>;
-+                      };
-+
-+                      cpr_efuse_boost_cfg: boost_cfg@125 {
-+                              reg = <0x125 0x1>;
-+                              bits = <3 3>;
-+                      };
-+
-+                      cpr_efuse_misc_volt_adj: misc_volt_adj@125 {
-+                              reg = <0x125 0x1>;
-+                              bits = <3 3>;
-+                      };
-+
-+                      cpr_efuse_boost_volt: boost_volt@126 {
-+                              reg = <0x126 0x1>;
-+                              bits = <6 1>;
-+                      };
-+
-+                      cpr_efuse_revision: revision@23e {
-+                              reg = <0x23e 0x1>;
-+                              bits = <5 3>;
-+                      };
-+
-+                      cpr_efuse_ro_sel0: rosel0@249 {
-+                              reg = <0x249 0x1>;
-+                              bits = <0 4>;
-+                      };
-+
-+                      cpr_efuse_ro_sel1: rosel1@248 {
-+                              reg = <0x248 0x1>;
-+                              bits = <4 4>;
-+                      };
-+
-+                      cpr_efuse_ro_sel2: rosel2@248 {
-+                              reg = <0x248 0x2>;
-+                              bits = <0 4>;
-+                      };
-+
-+                      cpr_efuse_ro_sel3: rosel3@249 {
-+                              reg = <0x249 0x1>;
-+                              bits = <4 4>;
-+                      };
-+
-+                      cpr_efuse_init_voltage0: ivoltage0@23a {
-+                              reg = <0x23a 0x1>;
-+                              bits = <2 6>;
-+                      };
-+
-+                      cpr_efuse_init_voltage1: ivoltage1@239 {
-+                              reg = <0x239 0x2>;
-+                              bits = <4 6>;
-+                      };
-+
-+                      cpr_efuse_init_voltage2: ivoltage2@238 {
-+                              reg = <0x238 0x2>;
-+                              bits = <6 6>;
-+                      };
-+
-+                      cpr_efuse_init_voltage3: ivoltage3@238 {
-+                              reg = <0x238 0x1>;
-+                              bits = <0 6>;
-+                      };
-+
-+                      cpr_efuse_quot0: quot0@244 {
-+                              reg = <0x244 0x2>;
-+                              bits = <0 12>;
-+                      };
-+
-+                      cpr_efuse_quot1: quot1@242 {
-+                              reg = <0x242 0x2>;
-+                              bits = <4 12>;
-+                      };
-+
-+                      cpr_efuse_quot2: quot2@241 {
-+                              reg = <0x241 0x2>;
-+                              bits = <0 12>;
-+                      };
-+
-+                      cpr_efuse_quot3: quot3@245 {
-+                              reg = <0x245 0x2>;
-+                              bits = <4 12>;
-+                      };
-+
-+                      cpr_efuse_quot0_offset: quot0_offset@23d {
-+                              reg = <0x23d 0x2>;
-+                              bits = <6 7>;
-+                      };
-+
-+                      cpr_efuse_quot1_offset: quot1_offset@23c {
-+                              reg = <0x23c 0x2>;
-+                              bits = <7 7>;
-+                      };
-+
-+                      cpr_efuse_quot2_offset: quot2_offset@23c {
-+                              reg = <0x23c 0x1>;
-+                              bits = <0 7>;
-+                      };
-               };
-               prng: rng@e3000 {
diff --git a/target/linux/qualcommax/patches-6.12/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch b/target/linux/qualcommax/patches-6.12/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch
deleted file mode 100644 (file)
index 9de502c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-From a20c4e8738a00087aa5d53fe5148ed484e23d229 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Sat, 31 Dec 2022 13:56:26 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add CPU OPP table
-
-Now that there is NVMEM CPUFreq support for IPQ8074, we can add the OPP
-table for SoC.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 52 +++++++++++++++++++++++++++
- 1 file changed, 52 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -42,6 +42,7 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       #cooling-cells = <2>;
-+                      operating-points-v2 = <&cpu_opp_table>;
-               };
-               cpu1: cpu@1 {
-@@ -53,6 +54,7 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       #cooling-cells = <2>;
-+                      operating-points-v2 = <&cpu_opp_table>;
-               };
-               cpu2: cpu@2 {
-@@ -64,6 +66,7 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       #cooling-cells = <2>;
-+                      operating-points-v2 = <&cpu_opp_table>;
-               };
-               cpu3: cpu@3 {
-@@ -75,6 +78,7 @@
-                       clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>;
-                       clock-names = "cpu";
-                       #cooling-cells = <2>;
-+                      operating-points-v2 = <&cpu_opp_table>;
-               };
-               l2_0: l2-cache {
-@@ -84,6 +88,54 @@
-               };
-       };
-+      cpu_opp_table: opp-table {
-+              compatible = "operating-points-v2-kryo-cpu";
-+              nvmem-cells = <&cpr_efuse_speedbin>;
-+              opp-shared;
-+
-+              opp-1017600000 {
-+                      opp-hz = /bits/ 64 <1017600000>;
-+                      opp-microvolt = <1>;
-+                      opp-supported-hw = <0xf>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-+              opp-1382400000 {
-+                      opp-hz = /bits/ 64 <1382400000>;
-+                      opp-microvolt = <2>;
-+                      opp-supported-hw = <0xf>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-+              opp-1651200000 {
-+                      opp-hz = /bits/ 64 <1651200000>;
-+                      opp-microvolt = <3>;
-+                      opp-supported-hw = <0x1>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-+              opp-1843200000 {
-+                      opp-hz = /bits/ 64 <1843200000>;
-+                      opp-microvolt = <4>;
-+                      opp-supported-hw = <0x1>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-+              opp-1920000000 {
-+                      opp-hz = /bits/ 64 <1920000000>;
-+                      opp-microvolt = <5>;
-+                      opp-supported-hw = <0x1>;
-+                      clock-latency-ns = <200000>;
-+              };
-+
-+              opp-2208000000 {
-+                      opp-hz = /bits/ 64 <2208000000>;
-+                      opp-microvolt = <6>;
-+                      opp-supported-hw = <0x1>;
-+                      clock-latency-ns = <200000>;
-+              };
-+      };
-+
-       pmu {
-               compatible = "arm,cortex-a53-pmu";
-               interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
diff --git a/target/linux/qualcommax/patches-6.12/0135-arm64-dts-qcom-ipq6018-add-NSS-reserved-memory.patch b/target/linux/qualcommax/patches-6.12/0135-arm64-dts-qcom-ipq6018-add-NSS-reserved-memory.patch
deleted file mode 100644 (file)
index 0d53531..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From 7e102b1eb2ca3eff7a6f33ebeab17825e6f70956 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 4 Nov 2024 22:01:24 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq6018: add NSS reserved memory
-
-It seems that despite NSS not being supported in OpenWrt the memory it
-usually uses needs to be reserved anyway for stability reasons.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -194,6 +194,11 @@
-                       no-map;
-               };
-+              nss_region: memory@40000000 {
-+                      reg = <0x0 0x40000000 0x0 0x01000000>;
-+                      no-map;
-+              };
-+
-               bootloader@4a100000 {
-                       reg = <0x0 0x4a100000 0x0 0x400000>;
-                       no-map;
diff --git a/target/linux/qualcommax/patches-6.12/0136-remoteproc-qcom-wcss-populate-driver-data-for-IPQ601.patch b/target/linux/qualcommax/patches-6.12/0136-remoteproc-qcom-wcss-populate-driver-data-for-IPQ601.patch
deleted file mode 100644 (file)
index b1175d4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-From 9dd19a9ae36bc60d58287d0c52e53024d484e64d Mon Sep 17 00:00:00 2001
-From:   Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
-Date:   Fri, 29 Jan 2021 22:41:59 +0530
-Subject: [PATCH 2/3] remoteproc: qcom: wcss: populate driver data for IPQ6018
-
-Populate hardcoded param using driver data for IPQ6018 SoCs.
-
-Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 19 +++++++++++++++++--
- 1 file changed, 17 insertions(+), 2 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -970,7 +970,7 @@ static int q6v5_alloc_memory_region(stru
-       return 0;
- }
--static int ipq8074_init_clock(struct q6v5_wcss *wcss)
-+static int ipq_init_clock(struct q6v5_wcss *wcss)
- {
-       int ret;
-@@ -1173,7 +1173,7 @@ static void q6v5_wcss_remove(struct plat
- }
- static const struct wcss_data wcss_ipq8074_res_init = {
--      .init_clock = ipq8074_init_clock,
-+      .init_clock = ipq_init_clock,
-       .q6_firmware_name = "IPQ8074/q6_fw.mdt",
-       .m3_firmware_name = "IPQ8074/m3_fw.mdt",
-       .crash_reason_smem = WCSS_CRASH_REASON,
-@@ -1187,6 +1187,20 @@ static const struct wcss_data wcss_ipq80
-       .need_auto_boot = false,
- };
-+static const struct wcss_data wcss_ipq6018_res_init = {
-+      .init_clock = ipq_init_clock,
-+      .q6_firmware_name = "IPQ6018/q6_fw.mdt",
-+      .m3_firmware_name = "IPQ6018/m3_fw.mdt",
-+      .crash_reason_smem = WCSS_CRASH_REASON,
-+      .aon_reset_required = true,
-+      .wcss_q6_reset_required = true,
-+      .bcr_reset_required = false,
-+      .ssr_name = "q6wcss",
-+      .ops = &q6v5_wcss_ipq8074_ops,
-+      .requires_force_stop = true,
-+      .need_mem_protection = true,
-+};
-+
- static const struct wcss_data wcss_qcs404_res_init = {
-       .init_clock = qcs404_init_clock,
-       .init_regulator = qcs404_init_regulator,
-@@ -1206,6 +1220,7 @@ static const struct wcss_data wcss_qcs40
- static const struct of_device_id q6v5_wcss_of_match[] = {
-       { .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init },
-+      { .compatible = "qcom,ipq6018-wcss-pil", .data = &wcss_ipq6018_res_init },
-       { .compatible = "qcom,qcs404-wcss-pil", .data = &wcss_qcs404_res_init },
-       { },
- };
diff --git a/target/linux/qualcommax/patches-6.12/0184-mailbox-tmelite-qmp-Introduce-TMEL-QMP-mailbox-driver.patch b/target/linux/qualcommax/patches-6.12/0184-mailbox-tmelite-qmp-Introduce-TMEL-QMP-mailbox-driver.patch
deleted file mode 100644 (file)
index 22016b4..0000000
+++ /dev/null
@@ -1,1245 +0,0 @@
-From patchwork Thu Mar 27 18:17:50 2025
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Submitter: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-X-Patchwork-Id: 14031335
-Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com
- [205.220.180.131])
-       (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
-       (No client certificate requested)
-       by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6FC4218EB3;
-       Thu, 27 Mar 2025 18:18:22 +0000 (UTC)
-Authentication-Results: smtp.subspace.kernel.org;
- arc=none smtp.client-ip=205.220.180.131
-ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
-       t=1743099505; cv=none;
- b=EIGqvUFVdX2yAV1X5BSy4Vd6avjUSpDkQyVdP3vFK5RB8T9Eoxto8HY1cWSbjWATbbmUQdxpIqDsTwpW93ZxX2u+xR66TEfrq53Mz7WXezAMNj+c7sxKOvD1LuN/SwZlpLeymS3aYCTXQF9tlaX4Kchd/XG9PHCNNlj4J/HMLEU=
-ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
-       s=arc-20240116; t=1743099505; c=relaxed/simple;
-       bh=1bC94iLOVn4uSZE28DCVE/Z1lxJpVgGYizWuGyj1fB4=;
-       h=From:To:Subject:Date:Message-ID:In-Reply-To:References:
-        MIME-Version:Content-Type;
- b=Vd0k6dRvTlGuhPjBJy4f26hetu50FFAxHBHHvpt01PASSbUWn5QdLpfIBDf4hhOejN+OP/t5Y4zRcQ8ls9btkI0XMU7nqZw/h8kFFPlXO+VWPWCIVQo6DeM4rgWKPIskkdmi3YCmekJQ8mOvrnj0Z1B7840MW6GkQowDA1ijXyQ=
-ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
- dmarc=pass (p=none dis=none) header.from=quicinc.com;
- spf=pass smtp.mailfrom=quicinc.com;
- dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com
- header.b=nWsnWiiP; arc=none smtp.client-ip=205.220.180.131
-Authentication-Results: smtp.subspace.kernel.org;
- dmarc=pass (p=none dis=none) header.from=quicinc.com
-Authentication-Results: smtp.subspace.kernel.org;
- spf=pass smtp.mailfrom=quicinc.com
-Authentication-Results: smtp.subspace.kernel.org;
-       dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com
- header.b="nWsnWiiP"
-Received: from pps.filterd (m0279870.ppops.net [127.0.0.1])
-       by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id
- 52RElAqC023840;
-       Thu, 27 Mar 2025 18:18:16 GMT
-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=
-       content-transfer-encoding:content-type:date:from:in-reply-to
-       :message-id:mime-version:references:subject:to; s=qcppdkim1; bh=
-       QkU6cfXx/Dr1uYdS2bfC4yKOb27hRI4xX4Mjt2GlxX0=; b=nWsnWiiPd2BhTQo2
-       8bvwRq7Eyr3yMh8LCCDfuk/SXkQbpNukzvr4A4R66oU3PmGnp5Y+Yeo0w09T3vue
-       4JYS0hV8suACJbj1eqqWEu+sLl1Uns0BXlWaWmOCnRVIwh/bpA3XIfCi9Fy+rANI
-       aXzrjtC81dBCEuqIj+0J97gY2Tt/kGays9pGkqXp64pNSHDoVQ7ijZgQlosIAg4b
-       qnNh7nFqwkbdlodmMjTuAQk0RBEAf1C5Wbyu2SP+jmUdu1Ign7AZHlK8OQtHCeR5
-       W1EPvlsTzXeaqCfYpgYZWI/kcO/WfBgjLFlrn4EG660ta9NShqlsNyHbuG0R5u8P
-       GiugpQ==
-Received: from nasanppmta03.qualcomm.com (i-global254.qualcomm.com
- [199.106.103.254])
-       by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 45kyr9qahq-1
-       (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);
-       Thu, 27 Mar 2025 18:18:16 +0000 (GMT)
-Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com
- [10.46.141.250])
-       by NASANPPMTA03.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id
- 52RIIFs2028891
-       (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);
-       Thu, 27 Mar 2025 18:18:15 GMT
-Received: from hu-srichara-blr.qualcomm.com (10.80.80.8) by
- nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server
- (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
- 15.2.1544.9; Thu, 27 Mar 2025 11:18:11 -0700
-From: Sricharan R <quic_srichara@quicinc.com>
-To: <jassisinghbrar@gmail.com>, <robh@kernel.org>, <krzk+dt@kernel.org>,
-        <conor+dt@kernel.org>, <linux-arm-msm@vger.kernel.org>,
-        <linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
-        <andersson@kernel.org>, <konradybcio@kernel.org>,
-        <manivannan.sadhasivam@linaro.org>, <dmitry.baryshkov@linaro.org>,
-        <quic_srichara@quicinc.com>
-Subject: [PATCH V4 2/2] mailbox: tmelite-qmp: Introduce TMEL QMP mailbox
- driver
-Date: Thu, 27 Mar 2025 23:47:50 +0530
-Message-ID: <20250327181750.3733881-3-quic_srichara@quicinc.com>
-X-Mailer: git-send-email 2.34.1
-In-Reply-To: <20250327181750.3733881-1-quic_srichara@quicinc.com>
-References: <20250327181750.3733881-1-quic_srichara@quicinc.com>
-Precedence: bulk
-X-Mailing-List: linux-arm-msm@vger.kernel.org
-List-Id: <linux-arm-msm.vger.kernel.org>
-List-Subscribe: <mailto:linux-arm-msm+subscribe@vger.kernel.org>
-List-Unsubscribe: <mailto:linux-arm-msm+unsubscribe@vger.kernel.org>
-MIME-Version: 1.0
-X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To
- nasanex01b.na.qualcomm.com (10.46.141.250)
-X-QCInternal: smtphost
-X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800
- signatures=585085
-X-Proofpoint-GUID: 0rO4P6gnHKFRp6byxTJdsYHwAuRh45Fp
-X-Authority-Analysis: v=2.4 cv=UblRSLSN c=1 sm=1 tr=0 ts=67e59668 cx=c_pps
- a=JYp8KDb2vCoCEuGobkYCKw==:117 a=JYp8KDb2vCoCEuGobkYCKw==:17
- a=GEpy-HfZoHoA:10 a=Vs1iUdzkB0EA:10 a=COk6AnOGAAAA:8 a=hOkhvlhF9aMxycy05ToA:9
- a=RVmHIydaz68A:10
- a=TjNXssC_j7lpFel5tvFf:22
-X-Proofpoint-ORIG-GUID: 0rO4P6gnHKFRp6byxTJdsYHwAuRh45Fp
-X-Proofpoint-Virus-Version: vendor=baseguard
- engine=ICAP:2.0.293,Aquarius:18.0.1095,Hydra:6.0.680,FMLib:17.12.68.34
- definitions=2025-03-27_03,2025-03-26_02,2024-11-22_01
-X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0
- lowpriorityscore=0
- suspectscore=0 priorityscore=1501 phishscore=0 mlxscore=0 impostorscore=0
- adultscore=0 clxscore=1015 mlxlogscore=999 bulkscore=0 malwarescore=0
- spamscore=0 classifier=spam authscore=0 authtc=n/a authcc= route=outbound
- adjust=0 reason=mlx scancount=1 engine=8.19.0-2502280000
- definitions=main-2503270125
-
-From: Sricharan Ramabadhran <quic_srichara@quicinc.com>
-
-This mailbox facilitates the communication between the TMEL server
-subsystem (Trust Management Engine Lite) and the TMEL client
-(APPSS/BTSS/AUDIOSS), used for secure services like secure image
-authentication, enable/disable efuses, crypto services etc. Each client in
-the SoC has its own block of message RAM and IRQ for communication with the
-TMEL SS. The protocol used to communicate in the message RAM is known as
-Qualcomm Messaging Protocol (QMP).
-
-Remote proc driver subscribes to this mailbox and uses the
-mbox_send_message to use TMEL to securely authenticate/teardown the images.
-
-Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
----
-[V4]
-        Fixed TME-L naming in all places and expanded it.
-        Folded tmel_work in tmel.
-        Added more kernel doc as relevant.
-        Removed __packed in all places, as not required.
-        Renamed all functions to have tmel_ prefixes.
-        Used readl/writel in all places.
-       Added Inline for all required functions.
-        Removed redundant type conversions.
-        Removed redundant 'goto's
-        Added __free macro
-        Fixed Linux std errno in tmel_sec_boot_auth/teardown
-        Added spinlock in qmp_startup
-        Used of_mbox_index_xlate and dropped the tmel_qmp_mbox_xlate
-        Updated header file to have only mbox consumer required and moved rest to .c file
-        Fixed the TMEL_MSG macros to use standard GENMASK
-        Moved the irq registration to end of probe
-
-    Following tests were done and no issues.
-
-       *)  Checkpatch
-       *)  Codespell
-       *)  Sparse
-       *)  kerneldoc check
-       *)  Kernel lock debugging
-       *)  dt_binding_check and dtbs_check
-
-[V3]
-
-        Fixed wrong code/comments wrappings.
-        Fixed Kconfig and Makefile entries to right place.
-        Removed unused headers inclusion.
-        Fixed locking, removed the mutexes and having only tx spinlock.
-        Removed the use of global ptr for tmel, made it as device specific.
-        Replaced pr_err/pr_debug with dev_err/dev_dbg in all places.
-        Fixed usage of dev_err_probe.
-        Fixed xlate callback as per comments.
-        Used devm equivalents and kcalloc version as per comments.
-        Removed all un-nessecary wrapper macros for register access, inlined it
-        as per comments.
-        Re-organised the function layout as per comments and make it more readable.
-        Removed the pictures in headers files as per comments.
-        Used Field_prep/get as per comments.
-        Fixed Kernel test reported issues.
-        Fixed all other comments as well.
-
-    Following tests were done and no issues.
-
-       *)  Checkpatch
-       *)  Codespell
-       *)  Sparse
-       *)  kerneldoc check
-       *)  Kernel lock debugging
-       *)  dt_binding_check and dtbs_check
-
-[v2]
-     Added HW description in the bindings patch.
-     Fixed review comments for bindings from Krzysztof and Dmitry
-     Changed patch#2 driver to add work for mailbox tx processing
-     Cleaned up patch#2 for some checkpatch warnings.
-     There are some checkpatch [CHECK] like below, which looks like false positive.
-
-       CHECK: Macro argument 'm' may be better as '(m)' to avoid precedence issues
-       #1072: FILE: include/linux/mailbox/tmelcom-qmp.h:40:
-       +#define TMEL_MSG_UID_CREATE(m, a)      ((u32)(((m & 0xff) << 8) | (a & 0xff)))
-
-[v1]
-      RFC Post
-
- drivers/mailbox/Kconfig             |  10 +
- drivers/mailbox/Makefile            |   2 +
- drivers/mailbox/qcom-tmel-qmp.c     | 947 ++++++++++++++++++++++++++++
- include/linux/mailbox/tmelcom-qmp.h |  65 ++
- 4 files changed, 1024 insertions(+)
- create mode 100644 drivers/mailbox/qcom-tmel-qmp.c
- create mode 100644 include/linux/mailbox/tmelcom-qmp.h
-
---- a/drivers/mailbox/Kconfig
-+++ b/drivers/mailbox/Kconfig
-@@ -295,4 +295,14 @@ config QCOM_IPCC
-         acts as an interrupt controller for receiving interrupts from clients.
-         Say Y here if you want to build this driver.
-+config QCOM_TMEL_QMP_MAILBOX
-+      tristate "QCOM Mailbox Protocol(QMP) for TMEL SS"
-+      depends on ARCH_QCOM || COMPILE_TEST
-+      help
-+        Say yes to add support for the QMP Mailbox Protocol driver for
-+        Trust Management Engine Lite Sub System (TMEL SS).
-+        QMP is a lightweight communication protocol for sending messages to
-+        TMEL. This protocol fits into the Generic Mailbox Framework.
-+        QMP uses a mailbox registers.
-+
- endif
---- a/drivers/mailbox/Makefile
-+++ b/drivers/mailbox/Makefile
-@@ -47,6 +47,8 @@ obj-$(CONFIG_POLARFIRE_SOC_MAILBOX)  += m
- obj-$(CONFIG_QCOM_APCS_IPC)   += qcom-apcs-ipc-mailbox.o
-+obj-$(CONFIG_QCOM_TMEL_QMP_MAILBOX) += qcom-tmel-qmp.o
-+
- obj-$(CONFIG_TEGRA_HSP_MBOX)  += tegra-hsp.o
- obj-$(CONFIG_STM32_IPCC)      += stm32-ipcc.o
---- /dev/null
-+++ b/drivers/mailbox/qcom-tmel-qmp.c
-@@ -0,0 +1,947 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#include <linux/cleanup.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/interrupt.h>
-+#include <linux/mailbox_client.h>
-+#include <linux/mailbox_controller.h>
-+#include <linux/mailbox/tmelcom-qmp.h>
-+#include <linux/platform_device.h>
-+#include <linux/uio.h>
-+
-+#define QMP_NUM_CHANS         0x1
-+#define QMP_TOUT_MS           1000
-+#define QMP_CTRL_DATA_SIZE    4
-+#define QMP_MAX_PKT_SIZE      0x18
-+#define QMP_UCORE_DESC_OFFSET 0x1000
-+#define QMP_SEND_TIMEOUT      30000
-+
-+#define QMP_HW_MBOX_SIZE              32
-+#define QMP_MBOX_RSV_SIZE             4
-+#define QMP_MBOX_IPC_PACKET_SIZE      (QMP_HW_MBOX_SIZE - QMP_CTRL_DATA_SIZE - QMP_MBOX_RSV_SIZE)
-+#define QMP_MBOX_IPC_MAX_PARAMS               5
-+
-+#define QMP_MAX_PARAM_IN_PARAM_ID     14
-+#define QMP_PARAM_CNT_FOR_OUTBUF      3
-+#define QMP_SRAM_IPC_MAX_PARAMS               (QMP_MAX_PARAM_IN_PARAM_ID * QMP_PARAM_CNT_FOR_OUTBUF)
-+#define QMP_SRAM_IPC_MAX_BUF_SIZE     (QMP_SRAM_IPC_MAX_PARAMS * sizeof(u32))
-+
-+#define TMEL_ERROR_GENERIC            (0x1u)
-+#define TMEL_ERROR_NOT_SUPPORTED      (0x2u)
-+#define TMEL_ERROR_BAD_PARAMETER      (0x3u)
-+#define TMEL_ERROR_BAD_MESSAGE                (0x4u)
-+#define TMEL_ERROR_BAD_ADDRESS                (0x5u)
-+#define TMEL_ERROR_TMELCOM_FAILURE    (0x6u)
-+#define TMEL_ERROR_TMEL_BUSY          (0x7u)
-+
-+/*
-+ * mbox data can be shared over mem or sram
-+ */
-+enum ipc_type {
-+      IPC_MBOX_MEM,
-+      IPC_MBOX_SRAM,
-+};
-+
-+/*
-+ * mbox header indicates the type of payload and action required.
-+ */
-+struct ipc_header {
-+      u8 ipc_type:1;
-+      u8 msg_len:7;
-+      u8 msg_type;
-+      u8 action_id;
-+      s8 response;
-+};
-+
-+struct mbox_payload {
-+      u32 param[QMP_MBOX_IPC_MAX_PARAMS];
-+};
-+
-+struct sram_payload {
-+      u32 payload_ptr;
-+      u32 payload_len;
-+};
-+
-+union ipc_payload {
-+      struct mbox_payload mbox_payload;
-+      struct sram_payload sram_payload;
-+};
-+
-+struct tmel_ipc_pkt {
-+      struct ipc_header msg_hdr;
-+      union ipc_payload payload;
-+};
-+
-+/**
-+ * enum qmp_local_state - definition of the local state machine
-+ * @LINK_DISCONNECTED: Init state, waiting for ucore to start
-+ * @LINK_NEGOTIATION: Set local link state to up, wait for ucore ack
-+ * @LINK_CONNECTED: Link state up, channel not connected
-+ * @LOCAL_CONNECTING: Channel opening locally, wait for ucore ack
-+ * @CHANNEL_CONNECTED: Channel fully opened
-+ * @LOCAL_DISCONNECTING: Channel disconnected locally, wait for ucore ack
-+ */
-+enum qmp_local_state {
-+      LINK_DISCONNECTED,
-+      LINK_NEGOTIATION,
-+      LINK_CONNECTED,
-+      LOCAL_CONNECTING,
-+      CHANNEL_CONNECTED,
-+      LOCAL_DISCONNECTING,
-+};
-+
-+/**
-+ * struct qmp_channel_desc - IPC bits
-+ * @bits: Var to access each member
-+ * @val: u32 representation of above
-+ */
-+union qmp_channel_desc {
-+      struct {
-+              u32 link_state:1;
-+              u32 link_state_ack:1;
-+              u32 ch_state:1;
-+              u32 ch_state_ack:1;
-+              u32 tx:1;
-+              u32 tx_ack:1;
-+              u32 rx_done:1;
-+              u32 rx_done_ack:1;
-+              u32 reserved:8;
-+              u32 frag_size:8;
-+              u32 rem_frag_count:8;
-+      } bits;
-+      unsigned int val;
-+};
-+
-+/**
-+ * struct qmp_device - local information for managing a single mailbox
-+ * @dev: The device that corresponds to this mailbox
-+ * @mcore_desc: Local core (APSS) mailbox descriptor
-+ * @ucore_desc: Remote core (TME-L) mailbox descriptor
-+ * @mcore: Local core (APSS) channel descriptor
-+ * @ucore: Remote core (TME-L) channel descriptor
-+ * @rx_pkt: Buffer to pass to client, holds received data from mailbox
-+ * @mbox_client: Mailbox client for the IPC interrupt
-+ * @mbox_chan: Mailbox client chan for the IPC interrupt
-+ * @local_state: Current state of mailbox protocol
-+ * @tx_lock: Serialize access for writes to mailbox
-+ * @link_complete: Use to block until link negotiation with remote proc
-+ * @ch_complete: Use to block until the channel is fully opened
-+ * @tx_sent: True if tx is sent and remote proc has not sent ack
-+ */
-+struct qmp_device {
-+      struct device *dev;
-+
-+      void __iomem *mcore_desc;
-+      void __iomem *ucore_desc;
-+      union qmp_channel_desc mcore;
-+      union qmp_channel_desc ucore;
-+
-+      struct kvec rx_pkt;
-+
-+      struct mbox_client mbox_client;
-+      struct mbox_chan *mbox_chan;
-+
-+      enum qmp_local_state local_state;
-+
-+      /*
-+       * Serialize access to mcore IPC descriptors.
-+       * mcore refers to the IPC request descriptors sent to TMEL,
-+       * protecting it from various SM transitions using this.
-+       */
-+      spinlock_t tx_lock;
-+
-+      struct completion link_complete;
-+      struct completion ch_complete;
-+
-+      atomic_t tx_sent;
-+};
-+
-+/**
-+ * struct tmel - tmel controller instance
-+ * @dev: The device that corresponds to this mailbox
-+ * @ctrl: Mailbox controller for use by tmel clients
-+ * @mdev: qmp_device associated with this tmel instance
-+ * @pkt: Buffer from client, to be sent over mailbox
-+ * @ipc_pkt: wrapper used for prepare/un_prepare
-+ * @sram_dma_addr: mailbox sram address to copy the data
-+ * @waitq: Use to wait for posted messages completion
-+ * @rx_done: Use to indicate receive completion from remote
-+ * @twork: worker for posting the client req to tmel ctrl
-+ * @data: client data to be sent for the current request
-+ */
-+struct tmel {
-+      struct device *dev;
-+      struct mbox_controller ctrl;
-+      struct qmp_device *mdev;
-+      struct kvec pkt;
-+      struct tmel_ipc_pkt *ipc_pkt;
-+      dma_addr_t sram_dma_addr;
-+      wait_queue_head_t waitq;
-+      bool rx_done;
-+      struct work_struct twork;
-+      void *data;
-+};
-+
-+struct tmel_msg_param_type_buf_in {
-+      u32 buf;
-+      u32 buf_len;
-+};
-+
-+struct tmel_secboot_sec_auth_req {
-+      u32 sw_id;
-+      struct tmel_msg_param_type_buf_in elf_buf;
-+      struct tmel_msg_param_type_buf_in region_list;
-+      u32 relocate;
-+};
-+
-+struct tmel_secboot_sec_auth_resp {
-+      u32 first_seg_addr;
-+      u32 first_seg_len;
-+      u32 entry_addr;
-+      u32 extended_error;
-+      u32 status;
-+};
-+
-+struct tmel_secboot_sec_auth {
-+      struct tmel_secboot_sec_auth_req req;
-+      struct tmel_secboot_sec_auth_resp resp;
-+};
-+
-+struct tmel_secboot_sec {
-+      struct device *dev;
-+      void *elf_buf;
-+      struct tmel_secboot_sec_auth msg;
-+};
-+
-+struct tmel_secboot_teardown_req {
-+      u32 sw_id;
-+      u32 secondary_sw_id;
-+};
-+
-+struct tmel_secboot_teardown_resp {
-+      u32 status;
-+};
-+
-+struct tmel_secboot_teardown {
-+      struct tmel_secboot_teardown_req req;
-+      struct tmel_secboot_teardown_resp resp;
-+};
-+
-+/**
-+ * tmel_qmp_send_irq() - send an irq to a remote entity as an event signal.
-+ * @mdev: Which remote entity that should receive the irq.
-+ */
-+static inline void tmel_qmp_send_irq(struct qmp_device *mdev)
-+{
-+      writel(mdev->mcore.val, mdev->mcore_desc);
-+      /* Ensure desc update is visible before IPC */
-+      wmb();
-+
-+      dev_dbg(mdev->dev, "%s: mcore 0x%x ucore 0x%x", __func__,
-+              mdev->mcore.val, mdev->ucore.val);
-+
-+      mbox_send_message(mdev->mbox_chan, NULL);
-+      mbox_client_txdone(mdev->mbox_chan, 0);
-+}
-+
-+/**
-+ * tmel_qmp_send_data() - Send the data to remote and notify.
-+ * @mdev: qmp_device to send the data to.
-+ * @data: Data to be sent to remote processor, should be in the format of
-+ *      a kvec.
-+ *
-+ * Copy the data to the channel's mailbox and notify remote subsystem of new
-+ * data. This function will return an error if the previous message sent has
-+ * not been read.
-+ */
-+static inline int tmel_qmp_send_data(struct qmp_device *mdev, void *data)
-+{
-+      struct kvec *pkt = (struct kvec *)data;
-+      void __iomem *addr;
-+      unsigned long flags;
-+
-+      if (pkt->iov_len > QMP_MAX_PKT_SIZE) {
-+              dev_err(mdev->dev, "Unsupported packet size");
-+              return -EINVAL;
-+      }
-+
-+      if (atomic_read(&mdev->tx_sent))
-+              return -EAGAIN;
-+
-+      dev_dbg(mdev->dev, "%s: mcore 0x%x ucore 0x%x", __func__,
-+              mdev->mcore.val, mdev->ucore.val);
-+
-+      addr = mdev->mcore_desc + QMP_CTRL_DATA_SIZE;
-+      memcpy_toio(addr, pkt->iov_base, pkt->iov_len);
-+
-+      mdev->mcore.bits.frag_size = pkt->iov_len;
-+      mdev->mcore.bits.rem_frag_count = 0;
-+
-+      dev_dbg(mdev->dev, "Copied buffer to mbox, sz: %d",
-+              mdev->mcore.bits.frag_size);
-+
-+      atomic_set(&mdev->tx_sent, 1);
-+
-+      spin_lock_irqsave(&mdev->tx_lock, flags);
-+      mdev->mcore.bits.tx = !(mdev->mcore.bits.tx);
-+      tmel_qmp_send_irq(mdev);
-+      spin_unlock_irqrestore(&mdev->tx_lock, flags);
-+
-+      return 0;
-+}
-+
-+/**
-+ * tmel_qmp_notify_client() - Notify the tmel client about remote data.
-+ * @tdev: tmel device to notify.
-+ * @message: response pkt from remote processor, should be in format of kvec.
-+ *
-+ * Wakeup the clients after receiving data from the remote.
-+ */
-+static inline void tmel_qmp_notify_client(struct tmel *tdev, void *message)
-+{
-+      struct kvec *pkt = NULL;
-+
-+      if (!message) {
-+              dev_err(tdev->dev, "spurious message received\n");
-+              goto notify_fail;
-+      }
-+
-+      if (tdev->rx_done) {
-+              dev_err(tdev->dev, "tmel response pending\n");
-+              goto notify_fail;
-+      }
-+
-+      pkt = (struct kvec *)message;
-+      tdev->pkt.iov_len = pkt->iov_len;
-+      tdev->pkt.iov_base = pkt->iov_base;
-+      tdev->rx_done = true;
-+
-+notify_fail:
-+      wake_up_interruptible(&tdev->waitq);
-+}
-+
-+/**
-+ * tmel_qmp_recv_data() - Receive data and send ack.
-+ * @tdev: tmel device that received the notification.
-+ * @mbox_of: offset of mailbox after QMP Control data.
-+ *
-+ * Copies data from mailbox and passes to the client upon receiving data
-+ * available notification. Also acknowledges the read completion.
-+ */
-+static inline void tmel_qmp_recv_data(struct tmel *tdev, u32 mbox_of)
-+{
-+      struct qmp_device *mdev = tdev->mdev;
-+      void __iomem *addr;
-+      struct kvec *pkt;
-+
-+      addr = mdev->ucore_desc + mbox_of;
-+      pkt = &mdev->rx_pkt;
-+      pkt->iov_len = mdev->ucore.bits.frag_size;
-+
-+      memcpy_fromio(pkt->iov_base, addr, pkt->iov_len);
-+      mdev->mcore.bits.tx_ack = mdev->ucore.bits.tx;
-+      dev_dbg(mdev->dev, "%s: Send RX data to TMEL Client", __func__);
-+      tmel_qmp_notify_client(tdev, pkt);
-+
-+      mdev->mcore.bits.rx_done = !(mdev->mcore.bits.rx_done);
-+      tmel_qmp_send_irq(mdev);
-+}
-+
-+/**
-+ * tmel_qmp_clr_mcore_ch_state() - Clear the mcore state of a mailbox.
-+ * @mdev: mailbox device to be initialized.
-+ */
-+static inline void tmel_qmp_clr_mcore_ch_state(struct qmp_device *mdev)
-+{
-+      /* Clear all fields except link_state */
-+      mdev->mcore.bits.ch_state = 0;
-+      mdev->mcore.bits.ch_state_ack = 0;
-+      mdev->mcore.bits.tx =  0;
-+      mdev->mcore.bits.tx_ack =  0;
-+      mdev->mcore.bits.rx_done = 0;
-+      mdev->mcore.bits.rx_done_ack = 0;
-+      mdev->mcore.bits.frag_size = 0;
-+      mdev->mcore.bits.rem_frag_count = 0;
-+}
-+
-+/**
-+ * tmel_qmp_rx() - Handle incoming messages from remote processor.
-+ * @tdev: tmel device to send the event to.
-+ */
-+static inline void tmel_qmp_rx(struct tmel *tdev)
-+{
-+      struct qmp_device *mdev = tdev->mdev;
-+      unsigned long flags;
-+
-+      /* read remote_desc from mailbox register */
-+      mdev->ucore.val = readl(mdev->ucore_desc);
-+
-+      dev_dbg(mdev->dev, "%s: mcore 0x%x ucore 0x%x", __func__,
-+              mdev->mcore.val, mdev->ucore.val);
-+
-+      spin_lock_irqsave(&mdev->tx_lock, flags);
-+
-+      /* Check if remote link down */
-+      if (mdev->local_state >= LINK_CONNECTED &&
-+          !(mdev->ucore.bits.link_state)) {
-+              mdev->local_state = LINK_NEGOTIATION;
-+              mdev->mcore.bits.link_state_ack = mdev->ucore.bits.link_state;
-+              tmel_qmp_send_irq(mdev);
-+              spin_unlock_irqrestore(&mdev->tx_lock, flags);
-+              return;
-+      }
-+
-+      switch (mdev->local_state) {
-+      case LINK_NEGOTIATION:
-+              if (!(mdev->mcore.bits.link_state) ||
-+                  !(mdev->ucore.bits.link_state)) {
-+                      dev_err(mdev->dev, "rx irq:link down state\n");
-+                      break;
-+              }
-+              tmel_qmp_clr_mcore_ch_state(mdev);
-+              mdev->mcore.bits.link_state_ack = mdev->ucore.bits.link_state;
-+              mdev->local_state = LINK_CONNECTED;
-+              complete_all(&mdev->link_complete);
-+              dev_dbg(mdev->dev, "Set to link connected");
-+              break;
-+      case LINK_CONNECTED:
-+              /* No need to handle until local opens */
-+              break;
-+      case LOCAL_CONNECTING:
-+              /* Ack to remote ch_state change */
-+              mdev->mcore.bits.ch_state_ack = mdev->ucore.bits.ch_state;
-+              mdev->local_state = CHANNEL_CONNECTED;
-+              complete_all(&mdev->ch_complete);
-+              dev_dbg(mdev->dev, "Set to channel connected");
-+              tmel_qmp_send_irq(mdev);
-+              break;
-+      case CHANNEL_CONNECTED:
-+              /* Check for remote channel down */
-+              if (!(mdev->ucore.bits.ch_state)) {
-+                      mdev->local_state = LOCAL_CONNECTING;
-+                      mdev->mcore.bits.ch_state_ack = mdev->ucore.bits.ch_state;
-+                      dev_dbg(mdev->dev, "Remote Disconnect");
-+                      tmel_qmp_send_irq(mdev);
-+              }
-+
-+              /* Check TX done */
-+              if (atomic_read(&mdev->tx_sent) &&
-+                  mdev->ucore.bits.rx_done != mdev->mcore.bits.rx_done_ack) {
-+                      /* Ack to remote */
-+                      mdev->mcore.bits.rx_done_ack = mdev->ucore.bits.rx_done;
-+                      atomic_set(&mdev->tx_sent, 0);
-+                      dev_dbg(mdev->dev, "TX flag cleared");
-+              }
-+
-+              /* Check if remote is Transmitting */
-+              if (!(mdev->ucore.bits.tx != mdev->mcore.bits.tx_ack))
-+                      break;
-+              if (mdev->ucore.bits.frag_size == 0 ||
-+                  mdev->ucore.bits.frag_size > QMP_MAX_PKT_SIZE) {
-+                      dev_err(mdev->dev, "Rx frag size error %d\n",
-+                              mdev->ucore.bits.frag_size);
-+                      break;
-+              }
-+              tmel_qmp_recv_data(tdev, QMP_CTRL_DATA_SIZE);
-+              break;
-+      case LOCAL_DISCONNECTING:
-+              if (!(mdev->mcore.bits.ch_state)) {
-+                      tmel_qmp_clr_mcore_ch_state(mdev);
-+                      mdev->local_state = LINK_CONNECTED;
-+                      dev_dbg(mdev->dev, "Channel closed");
-+                      reinit_completion(&mdev->ch_complete);
-+              }
-+
-+              break;
-+      default:
-+              dev_err(mdev->dev, "Local Channel State corrupted\n");
-+      }
-+      spin_unlock_irqrestore(&mdev->tx_lock, flags);
-+}
-+
-+/**
-+ * tmel_qmp_irq_handler() - Handle incoming messages from remote processor.
-+ * @irq: ipc interrupt from remote
-+ * @priv: ptr to the corresponding tmel device.
-+ */
-+static inline irqreturn_t tmel_qmp_irq_handler(int irq, void *priv)
-+{
-+      struct tmel *tdev = (struct tmel *)priv;
-+
-+      tmel_qmp_rx(tdev);
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/**
-+ * tmel_prepare_msg() - copies the payload to the mbox destination
-+ * @tdev: the tmel device
-+ * @msg_uid: msg_type/action_id combo
-+ * @msg_buf: payload to be sent
-+ * @msg_size: size of the payload
-+ */
-+static inline int tmel_prepare_msg(struct tmel *tdev, u32 msg_uid,
-+                                 void *msg_buf, size_t msg_size)
-+{
-+      struct tmel_ipc_pkt *ipc_pkt = tdev->ipc_pkt;
-+      struct ipc_header *msg_hdr = &ipc_pkt->msg_hdr;
-+      struct mbox_payload *mbox_payload = &ipc_pkt->payload.mbox_payload;
-+      struct sram_payload *sram_payload = &ipc_pkt->payload.sram_payload;
-+      int ret;
-+
-+      memset(ipc_pkt, 0, sizeof(struct tmel_ipc_pkt));
-+
-+      msg_hdr->msg_type = TMEL_MSG_UID_MSG_TYPE(msg_uid);
-+      msg_hdr->action_id = TMEL_MSG_UID_ACTION_ID(msg_uid);
-+
-+      dev_dbg(tdev->dev, "uid: %d, msg_size: %zu msg_type:%d, action_id:%d\n",
-+              msg_uid, msg_size, msg_hdr->msg_type, msg_hdr->action_id);
-+
-+      if (sizeof(struct ipc_header) + msg_size <= QMP_MBOX_IPC_PACKET_SIZE) {
-+              /* Mbox only */
-+              msg_hdr->ipc_type = IPC_MBOX_MEM;
-+              msg_hdr->msg_len = msg_size;
-+              memcpy((void *)mbox_payload, msg_buf, msg_size);
-+      } else if (msg_size <= QMP_SRAM_IPC_MAX_BUF_SIZE) {
-+              /* SRAM */
-+              msg_hdr->ipc_type = IPC_MBOX_SRAM;
-+              msg_hdr->msg_len = 8;
-+
-+              tdev->sram_dma_addr = dma_map_single(tdev->dev, msg_buf,
-+                                                   msg_size,
-+                                                   DMA_BIDIRECTIONAL);
-+              ret = dma_mapping_error(tdev->dev, tdev->sram_dma_addr);
-+              if (ret) {
-+                      dev_err(tdev->dev, "SRAM DMA mapping error: %d\n", ret);
-+                      return ret;
-+              }
-+
-+              sram_payload->payload_ptr = tdev->sram_dma_addr;
-+              sram_payload->payload_len = msg_size;
-+      } else {
-+              dev_err(tdev->dev, "Invalid payload length: %zu\n", msg_size);
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * tmel_unprepare_message() - Get the response data back for client
-+ * @tdev: the tmel device
-+ * @msg_buf: payload to be sent
-+ * @msg_size: size of the payload
-+ */
-+static inline void tmel_unprepare_message(struct tmel *tdev, void *msg_buf, size_t msg_size)
-+{
-+      struct tmel_ipc_pkt *ipc_pkt = (struct tmel_ipc_pkt *)tdev->pkt.iov_base;
-+      struct mbox_payload *mbox_payload = &ipc_pkt->payload.mbox_payload;
-+
-+      if (ipc_pkt->msg_hdr.ipc_type == IPC_MBOX_MEM) {
-+              memcpy(msg_buf, mbox_payload, msg_size);
-+      } else if (ipc_pkt->msg_hdr.ipc_type == IPC_MBOX_SRAM) {
-+              dma_unmap_single(tdev->dev, tdev->sram_dma_addr, msg_size, DMA_BIDIRECTIONAL);
-+              tdev->sram_dma_addr = 0;
-+      }
-+}
-+
-+static inline bool tmel_rx_done(struct tmel *tdev)
-+{
-+      return tdev->rx_done;
-+}
-+
-+/**
-+ * tmel_process_request() - process client msg and wait for response
-+ * @tdev: the tmel device
-+ * @msg_uid: msg_type/action_id combo
-+ * @msg_buf: payload to be sent
-+ * @msg_size: size of the payload
-+ */
-+static inline int tmel_process_request(struct tmel *tdev, u32 msg_uid,
-+                                     void *msg_buf, size_t msg_size)
-+{
-+      struct qmp_device *mdev = tdev->mdev;
-+      struct tmel_ipc_pkt *resp_ipc_pkt;
-+      struct mbox_chan *chan;
-+      unsigned long jiffies;
-+      long time_left = 0;
-+      int ret = 0;
-+
-+      chan = &tdev->ctrl.chans[0];
-+
-+      if (!msg_buf || !msg_size) {
-+              dev_err(tdev->dev, "Invalid msg_buf or msg_size\n");
-+              return -EINVAL;
-+      }
-+
-+      tdev->rx_done = false;
-+
-+      ret = tmel_prepare_msg(tdev, msg_uid, msg_buf, msg_size);
-+      if (ret)
-+              return ret;
-+
-+      tdev->pkt.iov_len = sizeof(struct tmel_ipc_pkt);
-+      tdev->pkt.iov_base = (void *)tdev->ipc_pkt;
-+
-+      tmel_qmp_send_data(mdev, &tdev->pkt);
-+      jiffies = msecs_to_jiffies(QMP_SEND_TIMEOUT);
-+
-+      time_left = wait_event_interruptible_timeout(tdev->waitq,
-+                                                   tmel_rx_done(tdev),
-+                                                   jiffies);
-+
-+      if (!time_left) {
-+              dev_err(tdev->dev, "Request timed out\n");
-+              atomic_set(&mdev->tx_sent, 0);
-+              mbox_chan_txdone(chan, ret);
-+              return -ETIMEDOUT;
-+      }
-+
-+      if (tdev->pkt.iov_len != sizeof(struct tmel_ipc_pkt))
-+              return -EPROTO;
-+
-+      resp_ipc_pkt = (struct tmel_ipc_pkt *)tdev->pkt.iov_base;
-+      tmel_unprepare_message(tdev, msg_buf, msg_size);
-+      tdev->rx_done = false;
-+
-+      return resp_ipc_pkt->msg_hdr.response;
-+}
-+
-+/**
-+ * tmel_secboot_sec_free() - Release the dma alloc and kmalloc'ed memory
-+ * @ptr: Address of the tmel_secboot_sec wrapper for dma and kmalloc region.
-+ */
-+void tmel_secboot_sec_free(void *ptr)
-+{
-+      struct tmel_secboot_sec *smsg = ptr;
-+      void *elf_buf = smsg->elf_buf;
-+      dma_addr_t elf_buf_phys;
-+      u32 size;
-+
-+      elf_buf_phys = smsg->msg.req.elf_buf.buf;
-+      size = smsg->msg.req.elf_buf.buf_len;
-+      dma_free_coherent(smsg->dev, size, elf_buf, elf_buf_phys);
-+      kfree(smsg);
-+}
-+
-+/**
-+ * tmel_secboot_sec_auth() - authenticate the remote subsys image
-+ * @tdev: the tmel device
-+ * @sw_id: pas_id of the remote
-+ * @metadata: payload to be sent
-+ * @size: size of the payload
-+ */
-+static inline int tmel_secboot_sec_auth(struct tmel *tdev, u32 sw_id,
-+                                      void *metadata, size_t size)
-+{
-+      struct tmel_secboot_sec *smsg __free(tmel_secboot_sec_f) = NULL;
-+      struct device *dev = tdev->dev;
-+      dma_addr_t elf_buf_phys;
-+      void *elf_buf;
-+      int ret;
-+
-+      if (!dev || !metadata)
-+              return -EINVAL;
-+
-+      smsg = kzalloc(sizeof(*smsg), GFP_KERNEL);
-+
-+      elf_buf = dma_alloc_coherent(dev, size, &elf_buf_phys, GFP_KERNEL);
-+      if (!elf_buf)
-+              return -ENOMEM;
-+
-+      memcpy(elf_buf, metadata, size);
-+
-+      smsg->dev = dev;
-+      smsg->elf_buf = elf_buf;
-+
-+      smsg->msg.req.sw_id = sw_id;
-+      smsg->msg.req.elf_buf.buf = (u32)elf_buf_phys;
-+      smsg->msg.req.elf_buf.buf_len = (u32)size;
-+
-+      ret = tmel_process_request(tdev, TMEL_MSG_UID_SECBOOT_SEC_AUTH,
-+                                 &smsg->msg,
-+                                 sizeof(struct tmel_secboot_sec_auth));
-+      if (ret) {
-+              dev_err(dev, "Failed to send IPC: %d\n", ret);
-+      } else if (smsg->msg.resp.status) {
-+              dev_err(dev, "Failed with status: %d", smsg->msg.resp.status);
-+              ret = smsg->msg.resp.status ? -EINVAL : 0;
-+      } else if (smsg->msg.resp.extended_error) {
-+              dev_err(dev, "Failed with error: %d", smsg->msg.resp.extended_error);
-+              ret = smsg->msg.resp.extended_error ? -EINVAL : 0;
-+      }
-+
-+      return ret;
-+}
-+
-+/**
-+ * tmel_secboot_teardown() - teardown the remote subsys
-+ * @tdev: tmel device
-+ * @sw_id: pas_id of the remote
-+ * @secondary_sw_id: extra argument for the pas_id
-+ */
-+static inline int tmel_secboot_teardown(struct tmel *tdev, u32 sw_id,
-+                                      u32 secondary_sw_id)
-+{
-+      struct tmel_secboot_teardown msg = {0};
-+      struct device *dev = tdev->dev;
-+      int ret;
-+
-+      if (!dev)
-+              return -EINVAL;
-+
-+      msg.req.sw_id = sw_id;
-+      msg.req.secondary_sw_id = secondary_sw_id;
-+      msg.resp.status = TMEL_ERROR_GENERIC;
-+
-+      ret = tmel_process_request(tdev, TMEL_MSG_UID_SECBOOT_SS_TEAR_DOWN,
-+                                 &msg, sizeof(msg));
-+      if (ret) {
-+              dev_err(dev, "Failed to send IPC: %d\n", ret);
-+      } else if (msg.resp.status) {
-+              dev_err(dev, "Failed with status: %d\n", msg.resp.status);
-+              ret = msg.resp.status ? -EINVAL : 0;
-+      }
-+
-+      return ret;
-+}
-+
-+static inline void tmel_qmp_send_work(struct work_struct *work)
-+{
-+      struct tmel *tdev = container_of(work, struct tmel, twork);
-+      struct tmel_qmp_msg *tmsg = tdev->data;
-+      struct tmel_sec_auth *smsg = tmsg->msg;
-+      struct mbox_chan *chan;
-+      int ret;
-+
-+      chan = &tdev->ctrl.chans[0];
-+
-+      switch (tmsg->msg_id) {
-+      case TMEL_MSG_UID_SECBOOT_SEC_AUTH:
-+              ret = tmel_secboot_sec_auth(tdev, smsg->pas_id, smsg->data, smsg->size);
-+              break;
-+      case TMEL_MSG_UID_SECBOOT_SS_TEAR_DOWN:
-+              ret = tmel_secboot_teardown(tdev, smsg->pas_id, 0);
-+              break;
-+      }
-+
-+      mbox_chan_txdone(chan, ret);
-+}
-+
-+/**
-+ * tmel_qmp_startup() - Start qmp mailbox channel for communication.
-+ * @chan: mailbox channel that is being opened.
-+ * Waits for remote subsystem to open channel if link is not
-+ * initiated or until timeout.
-+ */
-+static inline int tmel_qmp_startup(struct mbox_chan *chan)
-+{
-+      struct tmel *tdev = chan->con_priv;
-+      struct qmp_device *mdev = tdev->mdev;
-+      unsigned long flags;
-+      int ret;
-+
-+      /*
-+       * Kick start the SM from the negotiation phase
-+       * Rest of the link changes would follow when remote responds.
-+       */
-+      spin_lock_irqsave(&mdev->tx_lock, flags);
-+      mdev->mcore.bits.link_state = 1;
-+      mdev->local_state = LINK_NEGOTIATION;
-+      spin_unlock_irqrestore(&mdev->tx_lock, flags);
-+
-+      mdev->rx_pkt.iov_base = devm_kcalloc(mdev->dev, 1, QMP_MAX_PKT_SIZE,
-+                                           GFP_KERNEL);
-+      if (!mdev->rx_pkt.iov_base)
-+              return -ENOMEM;
-+
-+      tmel_qmp_send_irq(mdev);
-+
-+      ret = wait_for_completion_timeout(&mdev->link_complete,
-+                                        msecs_to_jiffies(QMP_TOUT_MS));
-+      if (!ret)
-+              return -EAGAIN;
-+
-+      spin_lock_irqsave(&mdev->tx_lock, flags);
-+      if (mdev->local_state == LINK_CONNECTED) {
-+              mdev->mcore.bits.ch_state = 1;
-+              mdev->local_state = LOCAL_CONNECTING;
-+              dev_dbg(mdev->dev, "link complete, local connecting");
-+              tmel_qmp_send_irq(mdev);
-+      }
-+      spin_unlock_irqrestore(&mdev->tx_lock, flags);
-+
-+      ret = wait_for_completion_timeout(&mdev->ch_complete,
-+                                        msecs_to_jiffies(QMP_TOUT_MS));
-+      if (!ret)
-+              return -ETIMEDOUT;
-+
-+      return 0;
-+}
-+
-+/**
-+ * tmel_qmp_shutdown() - Shutdown this mailbox channel.
-+ * @chan: mailbox channel to be shutdown.
-+ * Disconnect this mailbox channel so the client does not receive anymore
-+ * data and can reliquish control of the channel.
-+ */
-+static inline void tmel_qmp_shutdown(struct mbox_chan *chan)
-+{
-+      struct qmp_device *mdev = chan->con_priv;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&mdev->tx_lock, flags);
-+      if (mdev->local_state != LINK_DISCONNECTED) {
-+              mdev->local_state = LOCAL_DISCONNECTING;
-+              mdev->mcore.bits.ch_state = 0;
-+              tmel_qmp_send_irq(mdev);
-+      }
-+      spin_unlock_irqrestore(&mdev->tx_lock, flags);
-+}
-+
-+static inline int tmel_qmp_send(struct mbox_chan *chan, void *data)
-+{
-+      struct tmel *tdev = chan->con_priv;
-+
-+      tdev->data = data;
-+      queue_work(system_wq, &tdev->twork);
-+
-+      return 0;
-+}
-+
-+static struct mbox_chan_ops tmel_qmp_ops = {
-+      .startup = tmel_qmp_startup,
-+      .shutdown = tmel_qmp_shutdown,
-+      .send_data = tmel_qmp_send,
-+};
-+
-+static inline struct tmel *tmel_init(struct platform_device *pdev)
-+{
-+      struct tmel *tdev;
-+      struct mbox_chan *chans;
-+
-+      tdev = devm_kcalloc(&pdev->dev, 1, sizeof(*tdev), GFP_KERNEL);
-+      if (!tdev)
-+              return ERR_PTR(-ENOMEM);
-+
-+      tdev->ipc_pkt = devm_kcalloc(&pdev->dev, 1, sizeof(struct tmel_ipc_pkt), GFP_KERNEL);
-+      if (!tdev->ipc_pkt)
-+              return ERR_PTR(-ENOMEM);
-+
-+      init_waitqueue_head(&tdev->waitq);
-+
-+      tdev->rx_done = false;
-+      tdev->dev = &pdev->dev;
-+      platform_set_drvdata(pdev, tdev);
-+
-+      chans = devm_kcalloc(&pdev->dev, QMP_NUM_CHANS, sizeof(*chans), GFP_KERNEL);
-+      if (!chans)
-+              return ERR_PTR(-ENOMEM);
-+
-+      tdev->ctrl.chans = chans;
-+      INIT_WORK(&tdev->twork, tmel_qmp_send_work);
-+
-+      return tdev;
-+}
-+
-+static inline struct qmp_device *qmp_init(struct platform_device *pdev)
-+{
-+      struct qmp_device *mdev;
-+
-+      mdev = devm_kcalloc(&pdev->dev, 1, sizeof(*mdev), GFP_KERNEL);
-+      if (!mdev)
-+              return ERR_PTR(-ENOMEM);
-+
-+      mdev->dev = &pdev->dev;
-+      mdev->mcore_desc = devm_platform_ioremap_resource(pdev, 0);
-+      if (IS_ERR(mdev->mcore_desc))
-+              return ERR_PTR(-EIO);
-+
-+      mdev->ucore_desc = mdev->mcore_desc + QMP_UCORE_DESC_OFFSET;
-+
-+      spin_lock_init(&mdev->tx_lock);
-+      mdev->local_state = LINK_DISCONNECTED;
-+      init_completion(&mdev->link_complete);
-+      init_completion(&mdev->ch_complete);
-+
-+      return mdev;
-+}
-+
-+static inline int qmp_mbox_client_init(struct qmp_device *mdev)
-+{
-+      int ret = 0;
-+
-+      mdev->mbox_client.dev = mdev->dev;
-+      mdev->mbox_client.knows_txdone = false;
-+      mdev->mbox_chan = mbox_request_channel(&mdev->mbox_client, 0);
-+      if (IS_ERR(mdev->mbox_chan))
-+              ret = PTR_ERR(mdev->mbox_chan);
-+
-+      return ret;
-+}
-+
-+static inline int tmel_mbox_ctrl_init(struct tmel *tdev)
-+{
-+      tdev->ctrl.dev = tdev->dev;
-+      tdev->ctrl.ops = &tmel_qmp_ops;
-+      tdev->ctrl.chans[0].con_priv = tdev;
-+      tdev->ctrl.num_chans = QMP_NUM_CHANS;
-+      tdev->ctrl.txdone_irq = true;
-+
-+      return devm_mbox_controller_register(tdev->dev, &tdev->ctrl);
-+}
-+
-+static inline int tmel_qmp_probe(struct platform_device *pdev)
-+{
-+      struct device_node *node = pdev->dev.of_node;
-+      struct qmp_device *mdev;
-+      struct tmel *tdev;
-+      int ret = 0;
-+
-+      tdev = tmel_init(pdev);
-+      if (IS_ERR(tdev))
-+              return dev_err_probe(tdev->dev, ret, "tmel device init failed\n");
-+
-+      mdev = qmp_init(pdev);
-+      if (IS_ERR(mdev))
-+              return dev_err_probe(tdev->dev, ret, "qmp device init failed\n");
-+
-+      tdev->mdev = mdev;
-+
-+      ret = qmp_mbox_client_init(mdev);
-+      if (ret)
-+              return dev_err_probe(mdev->dev, ret, "IPC chan missing, client init failed");
-+
-+      ret = tmel_mbox_ctrl_init(tdev);
-+      if (ret)
-+              return dev_err_probe(tdev->dev, ret, "failed to register mbox controller");
-+
-+      ret = platform_get_irq(pdev, 0);
-+      ret = devm_request_threaded_irq(tdev->dev, ret, NULL, tmel_qmp_irq_handler,
-+                                      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-+                                      node->name, (void *)tdev);
-+      if (ret < 0)
-+              return dev_err_probe(tdev->dev, ret, "request threaded irq failed\n");
-+
-+      return ret;
-+}
-+
-+static const struct of_device_id tmel_qmp_dt_match[] = {
-+      { .compatible = "qcom,ipq5424-tmel" },
-+      {},
-+};
-+
-+static struct platform_driver tmel_qmp_driver = {
-+      .driver = {
-+              .name = "tmel_qmp_mbox",
-+              .of_match_table = tmel_qmp_dt_match,
-+      },
-+      .probe = tmel_qmp_probe,
-+};
-+module_platform_driver(tmel_qmp_driver);
-+
-+MODULE_DESCRIPTION("QCOM TMEL QMP driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/include/linux/mailbox/tmelcom-qmp.h
-@@ -0,0 +1,65 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+/*
-+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+#ifndef _TMELCOM_H_
-+#define _TMELCOM_H_
-+
-+#include <linux/bitfield.h>
-+
-+/*
-+ * Macro used to define unique TMEL Message Identifier based on
-+ * message type and action identifier.
-+ */
-+#define MSGTYPE_MASK GENMASK(15, 8)
-+#define ACTIONID_MASK GENMASK(7, 0)
-+
-+#define TMEL_MSG_UID_CREATE(msg_type, action_id) \
-+      (FIELD_PREP_CONST(MSGTYPE_MASK, msg_type) | \
-+      FIELD_PREP_CONST(ACTIONID_MASK, action_id))
-+
-+/*
-+ * Helper macro to extract the messageType from TMEL_MSG_UID
-+ */
-+#define TMEL_MSG_UID_MSG_TYPE(v)      FIELD_GET(MSGTYPE_MASK, v)
-+
-+/*
-+ * Helper macro to extract the actionID from TMEL_MSG_UID
-+ */
-+#define TMEL_MSG_UID_ACTION_ID(v)     FIELD_GET(ACTIONID_MASK, v)
-+
-+/*
-+ * All definitions of supported messageTypes.
-+ */
-+#define TMEL_MSG_SECBOOT      0x00
-+
-+/*
-+ * Action IDs for TMEL_MSG_SECBOOT
-+ */
-+#define TMEL_ACTION_SECBOOT_SEC_AUTH          0x04
-+#define TMEL_ACTION_SECBOOT_SS_TEAR_DOWN      0x0a
-+
-+/*
-+ * UIDs for TMEL_MSG_SECBOOT
-+ */
-+#define TMEL_MSG_UID_SECBOOT_SEC_AUTH     TMEL_MSG_UID_CREATE(TMEL_MSG_SECBOOT,\
-+                                          TMEL_ACTION_SECBOOT_SEC_AUTH)
-+
-+#define TMEL_MSG_UID_SECBOOT_SS_TEAR_DOWN     TMEL_MSG_UID_CREATE(TMEL_MSG_SECBOOT,\
-+                                              TMEL_ACTION_SECBOOT_SS_TEAR_DOWN)
-+
-+struct tmel_qmp_msg {
-+      void *msg;
-+      u32 msg_id;
-+};
-+
-+struct tmel_sec_auth {
-+      void *data;
-+      u32 size;
-+      u32 pas_id;
-+};
-+
-+void tmel_secboot_sec_free(void *ptr);
-+
-+DEFINE_FREE(tmel_secboot_sec_f, void *, if (_T) tmel_secboot_sec_free(_T))
-+#endif  /* _TMELCOM_H_ */
diff --git a/target/linux/qualcommax/patches-6.12/0185-firmware-qcom_scm-ipq5332-add-support-to-pass-metadata-size.patch b/target/linux/qualcommax/patches-6.12/0185-firmware-qcom_scm-ipq5332-add-support-to-pass-metadata-size.patch
deleted file mode 100644 (file)
index 103c443..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From 9d67219c941458fd26eb474d25f9a6b2525876ca Mon Sep 17 00:00:00 2001
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Tue, 21 Oct 2025 15:38:28 +0400
-Subject: [PATCH v6 1/8] firmware: qcom_scm: ipq5332: add support to pass metadata size
-MIME-Version: 1.0
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 7bit
-Message-Id: <20251021-ipq5018-wifi-v6-1-c55c547df6fc@outlook.com>
-
-IPQ5332 security software running under trustzone requires metadata size.
-With new command support added in TrustZone that includes a size parameter,
-pass metadata size as well.
-
-Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Signed-off-by: Gokul Sriram Palanisamy <gokul.sriram.p@oss.qualcomm.com>
----
- drivers/firmware/qcom/qcom_scm.c | 17 +++++++++++++----
- drivers/firmware/qcom/qcom_scm.h |  1 +
- 2 files changed, 14 insertions(+), 4 deletions(-)
-
---- a/drivers/firmware/qcom/qcom_scm.c
-+++ b/drivers/firmware/qcom/qcom_scm.c
-@@ -583,9 +583,6 @@ int qcom_scm_pas_init_image(u32 peripher
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_PIL,
--              .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
--              .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW),
--              .args[0] = peripheral,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-@@ -617,7 +614,19 @@ int qcom_scm_pas_init_image(u32 peripher
-       if (ret)
-               goto disable_clk;
--      desc.args[1] = mdata_phys;
-+      if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
-+                                       QCOM_SCM_PIL_PAS_INIT_IMAGE_V2)) {
-+              desc.cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE_V2;
-+              desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL);
-+              desc.args[0] = peripheral;
-+              desc.args[1] = mdata_phys;
-+              desc.args[2] = size;
-+      } else {
-+              desc.cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE;
-+              desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
-+              desc.args[0] = peripheral;
-+              desc.args[1] = mdata_phys;
-+      }
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-       qcom_scm_bw_disable();
---- a/drivers/firmware/qcom/qcom_scm.h
-+++ b/drivers/firmware/qcom/qcom_scm.h
-@@ -101,6 +101,7 @@ struct qcom_tzmem_pool *qcom_scm_get_tzm
- #define QCOM_SCM_PIL_PAS_SHUTDOWN     0x06
- #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
- #define QCOM_SCM_PIL_PAS_MSS_RESET    0x0a
-+#define QCOM_SCM_PIL_PAS_INIT_IMAGE_V2        0x1a
- #define QCOM_SCM_SVC_IO                       0x05
- #define QCOM_SCM_IO_READ              0x01
diff --git a/target/linux/qualcommax/patches-6.12/0186-dt-bindings-remoteproc-qcom-document-hexagon-based-wcss-secure-pil.patch b/target/linux/qualcommax/patches-6.12/0186-dt-bindings-remoteproc-qcom-document-hexagon-based-wcss-secure-pil.patch
deleted file mode 100644 (file)
index ff74f44..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-From db128ef0282b8cc41816caf39a03fa17d10fa865 Mon Sep 17 00:00:00 2001
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Tue, 21 Oct 2025 15:38:29 +0400
-Subject: [PATCH v6 2/8] dt-bindings: remoteproc: qcom: document hexagon based WCSS secure PIL
-MIME-Version: 1.0
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 7bit
-Message-Id: <20251021-ipq5018-wifi-v6-2-c55c547df6fc@outlook.com>
-
-Add new binding document for hexagon based WCSS secure PIL remoteproc.
-IPQ5018, IPQ5332, IPQ5424 and IPQ9574 follow secure PIL remoteproc.
-
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Signed-off-by: Gokul Sriram Palanisamy <quic_gokulsri@quicinc.com>
----
- .../bindings/remoteproc/qcom,wcss-sec-pil.yaml     | 133 +++++++++++++++++++++
- 1 file changed, 133 insertions(+)
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/remoteproc/qcom,wcss-sec-pil.yaml
-@@ -0,0 +1,135 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/remoteproc/qcom,wcss-sec-pil.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Qualcomm WCSS Secure Peripheral Image Loader
-+
-+maintainers:
-+  - Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-+
-+description:
-+  Wireless Connectivity Subsystem (WCSS) Secure Peripheral Image Loader loads
-+  firmware and power up QDSP6 remoteproc on the Qualcomm IPQ series SoC.
-+
-+properties:
-+  compatible:
-+    enum:
-+      - qcom,ipq5018-wcss-sec-pil
-+      - qcom,ipq5332-wcss-sec-pil
-+      - qcom,ipq5424-wcss-sec-pil
-+      - qcom,ipq9574-wcss-sec-pil
-+
-+  reg:
-+    maxItems: 1
-+
-+  firmware-name:
-+    maxItems: 1
-+    description: Firmware name for the Hexagon core
-+
-+  interrupts:
-+    items:
-+      - description: Watchdog interrupt
-+      - description: Fatal interrupt
-+      - description: Ready interrupt
-+      - description: Handover interrupt
-+      - description: Stop acknowledge interrupt
-+
-+  interrupt-names:
-+    items:
-+      - const: wdog
-+      - const: fatal
-+      - const: ready
-+      - const: handover
-+      - const: stop-ack
-+
-+  clocks:
-+    items:
-+      - description: sleep clock
-+      - description: AHB interconnect between system NOC and WCSS block
-+
-+  clock-names:
-+    items:
-+      - const: sleep
-+      - const: interconnect
-+
-+  mboxes:
-+    maxItems: 1
-+    items:
-+      - description: A phandle to the TMECom mailbox device node
-+
-+  qcom,smem-states:
-+    $ref: /schemas/types.yaml#/definitions/phandle-array
-+    description: States used by the AP to signal the remote processor
-+    items:
-+      - description: Stop Q6
-+      - description: Shutdown Q6
-+
-+  qcom,smem-state-names:
-+    description:
-+      Names of the states used by the AP to signal the remote processor
-+    items:
-+      - const: stop
-+      - const: shutdown
-+
-+  memory-region:
-+    items:
-+      - description: Q6 reserved region
-+
-+  glink-edge:
-+    $ref: /schemas/remoteproc/qcom,glink-edge.yaml#
-+    description:
-+      Qualcomm G-Link subnode which represents communication edge, channels
-+      and devices related to the Modem.
-+    unevaluatedProperties: false
-+
-+required:
-+  - compatible
-+  - reg
-+  - firmware-name
-+  - interrupts
-+  - interrupt-names
-+  - qcom,smem-states
-+  - qcom,smem-state-names
-+  - memory-region
-+
-+additionalProperties: false
-+
-+examples:
-+  - |
-+    #include <dt-bindings/interrupt-controller/arm-gic.h>
-+    #include <dt-bindings/clock/qcom,ipq5424-gcc.h>
-+    remoteproc@d100000 {
-+      compatible = "qcom,ipq5424-wcss-sec-pil";
-+      reg = <0x0d100000 0x4040>;
-+      firmware-name = "ath12k/IPQ5424/hw1.0/q6_fw0.mbn";
-+      interrupts-extended = <&intc GIC_SPI 508 IRQ_TYPE_EDGE_RISING>,
-+                            <&wcss_smp2p_in 0 IRQ_TYPE_NONE>,
-+                            <&wcss_smp2p_in 1 IRQ_TYPE_NONE>,
-+                            <&wcss_smp2p_in 2 IRQ_TYPE_NONE>,
-+                            <&wcss_smp2p_in 3 IRQ_TYPE_NONE>;
-+      interrupt-names = "wdog",
-+                        "fatal",
-+                        "ready",
-+                        "handover",
-+                        "stop-ack";
-+
-+      clocks = <&gcc GCC_IM_SLEEP_CLK>;
-+      clock-names = "sleep";
-+
-+      mboxes = <&tmel_qmp 0>;
-+      qcom,smem-states = <&wcss_smp2p_out 1>,
-+                         <&wcss_smp2p_out 0>;
-+      qcom,smem-state-names = "stop",
-+                              "shutdown";
-+
-+      memory-region = <&q6_region>;
-+
-+      glink-edge {
-+        interrupts = <GIC_SPI 500 IRQ_TYPE_EDGE_RISING>;
-+        label = "rtr";
-+        qcom,remote-pid = <1>;
-+        mboxes = <&apcs_glb 8>;
-+      };
-+    };
diff --git a/target/linux/qualcommax/patches-6.12/0188-remoteproc-qcom-add-hexagon-based-wcss-secure-pil-driver.patch b/target/linux/qualcommax/patches-6.12/0188-remoteproc-qcom-add-hexagon-based-wcss-secure-pil-driver.patch
deleted file mode 100644 (file)
index d999e55..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-From 47d46157200bb5f67e540a87c67aab9cde62f8a4 Mon Sep 17 00:00:00 2001
-From: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com>
-Date: Tue, 21 Oct 2025 15:38:30 +0400
-Subject: [PATCH v6 3/8] remoteproc: qcom: add hexagon based WCSS secure PIL driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 7bit
-Message-Id: <20251021-ipq5018-wifi-v6-3-c55c547df6fc@outlook.com>
-
-Add support to bring up hexagon based WCSS using secure PIL. All IPQxxxx
-SoCs support secure Peripheral Image Loading (PIL).
-
-Secure PIL image is signed firmware image which only trusted software such
-as TrustZone (TZ) can authenticate and load. Linux kernel will send a
-Peripheral Authentication Service (PAS) request to TZ to authenticate and
-load the PIL images. This change also introduces secure firmware
-authentication using Trusted Management Engine-Lite (TME-L) which is
-supported on IPQ5424 SoC. This driver uses mailbox based PAS request to
-TME-L for image authentication if supported, else it will fallback to use
-SCM call based PAS request to TZ.
-
-In order to avoid overloading the existing WCSS driver or PAS driver, we
-came up with this new PAS based IPQ WCSS driver.
-
-Signed-off-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com>
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Signed-off-by: Gokul Sriram Palanisamy <gokul.sriram.p@oss.qualcomm.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- drivers/remoteproc/Kconfig              |  19 ++
- drivers/remoteproc/Makefile             |   1 +
- drivers/remoteproc/qcom_q6v5_wcss_sec.c | 390 ++++++++++++++++++++++++++++++++
- include/linux/remoteproc.h              |   2 +
- 4 files changed, 412 insertions(+)
-
---- a/drivers/remoteproc/Kconfig
-+++ b/drivers/remoteproc/Kconfig
-@@ -255,6 +255,25 @@ config QCOM_Q6V5_WCSS
-         Hexagon V5 based WCSS remote processors on e.g. IPQ8074.  This is
-         a non-TrustZone wireless subsystem.
-+config QCOM_Q6V5_WCSS_SEC
-+      tristate "Qualcomm Hexagon based WCSS Secure Peripheral Image Loader"
-+      depends on OF && ARCH_QCOM
-+      depends on QCOM_SMEM
-+      depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
-+      depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
-+      select QCOM_MDT_LOADER
-+      select QCOM_PIL_INFO
-+      select QCOM_Q6V5_COMMON
-+      select QCOM_RPROC_COMMON
-+      select QCOM_SCM
-+      help
-+        Say y here to support the Qualcomm Secure Peripheral Image Loader
-+        for the Hexagon based remote processors on e.g. IPQ5332.
-+
-+        This is TrustZone wireless subsystem. The firmware is
-+        verified and booted with the help of the Peripheral Authentication
-+        System (PAS) in TrustZone.
-+
- config QCOM_SYSMON
-       tristate "Qualcomm sysmon driver"
-       depends on RPMSG
---- a/drivers/remoteproc/Makefile
-+++ b/drivers/remoteproc/Makefile
-@@ -28,6 +28,7 @@ obj-$(CONFIG_QCOM_Q6V5_ADSP)         += qcom_q6
- obj-$(CONFIG_QCOM_Q6V5_MSS)           += qcom_q6v5_mss.o
- obj-$(CONFIG_QCOM_Q6V5_PAS)           += qcom_q6v5_pas.o
- obj-$(CONFIG_QCOM_Q6V5_WCSS)          += qcom_q6v5_wcss.o
-+obj-$(CONFIG_QCOM_Q6V5_WCSS_SEC)      += qcom_q6v5_wcss_sec.o
- obj-$(CONFIG_QCOM_SYSMON)             += qcom_sysmon.o
- obj-$(CONFIG_QCOM_WCNSS_PIL)          += qcom_wcnss_pil.o
- qcom_wcnss_pil-y                      += qcom_wcnss.o
---- /dev/null
-+++ b/drivers/remoteproc/qcom_q6v5_wcss_sec.c
-@@ -0,0 +1,406 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2016-2018 Linaro Ltd.
-+ * Copyright (C) 2014 Sony Mobile Communications AB
-+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+#include <linux/clk.h>
-+#include <linux/firmware/qcom/qcom_scm.h>
-+#include <linux/io.h>
-+#include <linux/mailbox_client.h>
-+#include <linux/mailbox/tmelcom-qmp.h>
-+#include <linux/of_reserved_mem.h>
-+#include <linux/platform_device.h>
-+#include <linux/soc/qcom/mdt_loader.h>
-+
-+#include "qcom_common.h"
-+#include "qcom_q6v5.h"
-+#include "qcom_pil_info.h"
-+
-+#define WCSS_CRASH_REASON             421
-+
-+#define WCSS_PAS_ID                   0x6
-+#define MPD_WCSS_PAS_ID                       0xd
-+
-+#define Q6_WAIT_TIMEOUT                       (5 * HZ)
-+
-+struct wcss_sec {
-+      struct device *dev;
-+      struct qcom_rproc_glink glink_subdev;
-+      struct qcom_rproc_ssr ssr_subdev;
-+      struct qcom_q6v5 q6;
-+      phys_addr_t mem_phys;
-+      phys_addr_t mem_reloc;
-+      void *mem_region;
-+      size_t mem_size;
-+      const struct wcss_data *desc;
-+
-+      struct mbox_client mbox_client;
-+      struct mbox_chan *mbox_chan;
-+      void *metadata;
-+      size_t metadata_len;
-+};
-+
-+struct wcss_data {
-+      u32 pasid;
-+      const char *ss_name;
-+      bool auto_boot;
-+      bool use_tmelcom;
-+};
-+
-+static int wcss_sec_start(struct rproc *rproc)
-+{
-+      struct wcss_sec *wcss = rproc->priv;
-+      struct device *dev = wcss->dev;
-+      int ret;
-+
-+      ret = qcom_q6v5_prepare(&wcss->q6);
-+      if (ret)
-+              return ret;
-+
-+      if (wcss->desc->use_tmelcom) {
-+              struct tmel_sec_auth tsa;
-+              struct tmel_qmp_msg tqm;
-+
-+              tsa.data = wcss->metadata;
-+              tsa.size = wcss->metadata_len;
-+              tsa.pas_id = wcss->desc->pasid;
-+              tqm.msg = &tsa;
-+              tqm.msg_id = TMEL_MSG_UID_SECBOOT_SEC_AUTH;
-+
-+              ret = mbox_send_message(wcss->mbox_chan, (void *)&tqm);
-+              if (ret < 0) {
-+                      dev_err(dev, "Failed to send message via mailbox\n");
-+                      goto unprepare;
-+              }
-+      } else {
-+              ret = qcom_scm_pas_auth_and_reset(wcss->desc->pasid);
-+              if (ret) {
-+                      dev_err(dev, "wcss_reset failed\n");
-+                      goto unprepare;
-+              }
-+      }
-+
-+      ret = qcom_q6v5_wait_for_start(&wcss->q6, Q6_WAIT_TIMEOUT);
-+      if (ret == -ETIMEDOUT)
-+              dev_err(dev, "start timed out\n");
-+
-+unprepare:
-+      qcom_q6v5_unprepare(&wcss->q6);
-+
-+      return ret;
-+}
-+
-+static int wcss_sec_stop(struct rproc *rproc)
-+{
-+      struct wcss_sec *wcss = rproc->priv;
-+      struct device *dev = wcss->dev;
-+      int ret;
-+
-+      if (wcss->desc->use_tmelcom) {
-+              struct tmel_sec_auth tsa = {0};
-+              struct tmel_qmp_msg tqm;
-+
-+              tsa.pas_id = wcss->desc->pasid;
-+              tqm.msg = &tsa;
-+              tqm.msg_id = TMEL_MSG_UID_SECBOOT_SS_TEAR_DOWN;
-+
-+              mbox_send_message(wcss->mbox_chan, (void *)&tqm);
-+      } else {
-+              ret = qcom_scm_pas_shutdown(wcss->desc->pasid);
-+              if (ret) {
-+                      dev_err(dev, "not able to shutdown\n");
-+                      return ret;
-+              }
-+      }
-+
-+      qcom_q6v5_unprepare(&wcss->q6);
-+
-+      return 0;
-+}
-+
-+static void *wcss_sec_da_to_va(struct rproc *rproc, u64 da, size_t len,
-+                             bool *is_iomem)
-+{
-+      struct wcss_sec *wcss = rproc->priv;
-+      int offset;
-+
-+      offset = da - wcss->mem_reloc;
-+      if (offset < 0 || offset + len > wcss->mem_size)
-+              return NULL;
-+
-+      return wcss->mem_region + offset;
-+}
-+
-+static int wcss_sec_load(struct rproc *rproc, const struct firmware *fw)
-+{
-+      struct wcss_sec *wcss = rproc->priv;
-+      struct device *dev = wcss->dev;
-+      int ret;
-+
-+      if (wcss->desc->use_tmelcom) {
-+              wcss->metadata = qcom_mdt_read_metadata(fw, &wcss->metadata_len,
-+                                                      rproc->firmware, wcss->dev);
-+              if (IS_ERR(wcss->metadata)) {
-+                      ret = PTR_ERR(wcss->metadata);
-+                      dev_err(wcss->dev, "error %d reading firmware %s metadata\n",
-+                              ret, rproc->firmware);
-+                      return ret;
-+              }
-+
-+              ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, wcss->desc->pasid,
-+                                          wcss->mem_region, wcss->mem_phys, wcss->mem_size,
-+                                          &wcss->mem_reloc);
-+              if (ret) {
-+                      kfree(wcss->metadata);
-+                      return ret;
-+              }
-+      } else {
-+              ret = qcom_mdt_load(dev, fw, rproc->firmware, wcss->desc->pasid, wcss->mem_region,
-+                                  wcss->mem_phys, wcss->mem_size, &wcss->mem_reloc);
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      qcom_pil_info_store("wcss", wcss->mem_phys, wcss->mem_size);
-+
-+      return 0;
-+}
-+
-+static unsigned long wcss_sec_panic(struct rproc *rproc)
-+{
-+      struct wcss_sec *wcss = rproc->priv;
-+
-+      return qcom_q6v5_panic(&wcss->q6);
-+}
-+
-+static void wcss_sec_copy_segment(struct rproc *rproc,
-+                                struct rproc_dump_segment *segment,
-+                                void *dest, size_t offset, size_t size)
-+{
-+      struct wcss_sec *wcss = rproc->priv;
-+      struct device *dev = wcss->dev;
-+
-+      if (!segment->io_ptr)
-+              segment->io_ptr = ioremap_wc(segment->da, segment->size);
-+
-+      if (!segment->io_ptr) {
-+              dev_err(dev, "Failed to ioremap segment %pad size 0x%zx\n",
-+                      &segment->da, segment->size);
-+              return;
-+      }
-+
-+      if (offset + size < segment->size) {
-+              memcpy(dest, segment->io_ptr + offset, size);
-+      } else {
-+              iounmap(segment->io_ptr);
-+              segment->io_ptr = NULL;
-+      }
-+}
-+
-+static int wcss_sec_dump_segments(struct rproc *rproc,
-+                                const struct firmware *fw)
-+{
-+      struct device *dev = rproc->dev.parent;
-+      struct reserved_mem *rmem = NULL;
-+      struct device_node *node;
-+      int num_segs, index;
-+      int ret;
-+
-+      /*
-+       * Parse through additional reserved memory regions for the rproc
-+       * and add them to the coredump segments
-+       */
-+      num_segs = of_count_phandle_with_args(dev->of_node,
-+                                            "memory-region", NULL);
-+      for (index = 0; index < num_segs; index++) {
-+              node = of_parse_phandle(dev->of_node,
-+                                      "memory-region", index);
-+              if (!node)
-+                      return -EINVAL;
-+
-+              rmem = of_reserved_mem_lookup(node);
-+              of_node_put(node);
-+              if (!rmem) {
-+                      dev_err(dev, "unable to acquire memory-region index %d num_segs %d\n",
-+                              index, num_segs);
-+                      return -EINVAL;
-+              }
-+
-+              dev_dbg(dev, "Adding segment 0x%pa size 0x%pa",
-+                      &rmem->base, &rmem->size);
-+              ret = rproc_coredump_add_custom_segment(rproc,
-+                                                      rmem->base,
-+                                                      rmem->size,
-+                                                      wcss_sec_copy_segment,
-+                                                      NULL);
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static const struct rproc_ops wcss_sec_ops = {
-+      .start = wcss_sec_start,
-+      .stop = wcss_sec_stop,
-+      .da_to_va = wcss_sec_da_to_va,
-+      .load = wcss_sec_load,
-+      .get_boot_addr = rproc_elf_get_boot_addr,
-+      .panic = wcss_sec_panic,
-+      .parse_fw = wcss_sec_dump_segments,
-+};
-+
-+static int wcss_sec_alloc_memory_region(struct wcss_sec *wcss)
-+{
-+      struct reserved_mem *rmem = NULL;
-+      struct device_node *node;
-+      struct device *dev = wcss->dev;
-+
-+      node = of_parse_phandle(dev->of_node, "memory-region", 0);
-+      if (!node) {
-+              dev_err(dev, "can't find phandle memory-region\n");
-+              return -EINVAL;
-+      }
-+
-+      rmem = of_reserved_mem_lookup(node);
-+      of_node_put(node);
-+
-+      if (!rmem) {
-+              dev_err(dev, "unable to acquire memory-region\n");
-+              return -EINVAL;
-+      }
-+
-+      wcss->mem_phys = rmem->base;
-+      wcss->mem_reloc = rmem->base;
-+      wcss->mem_size = rmem->size;
-+      wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
-+      if (!wcss->mem_region) {
-+              dev_err(dev, "unable to map memory region: %pa+%pa\n",
-+                      &rmem->base, &rmem->size);
-+              return -ENOMEM;
-+      }
-+
-+      return 0;
-+}
-+
-+static int wcss_sec_probe(struct platform_device *pdev)
-+{
-+      struct rproc *rproc;
-+      struct wcss_sec *wcss;
-+      struct clk *sleep_clk;
-+      struct clk *int_clk;
-+      const char *fw_name = NULL;
-+      const struct wcss_data *desc = of_device_get_match_data(&pdev->dev);
-+      int ret;
-+
-+      ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
-+                                    &fw_name);
-+      if (ret < 0)
-+              return ret;
-+
-+      rproc = devm_rproc_alloc(&pdev->dev, desc->ss_name, &wcss_sec_ops,
-+                               fw_name, sizeof(*wcss));
-+      if (!rproc) {
-+              dev_err(&pdev->dev, "failed to allocate rproc\n");
-+              return -ENOMEM;
-+      }
-+
-+      wcss = rproc->priv;
-+      wcss->dev = &pdev->dev;
-+      wcss->desc = desc;
-+
-+      ret = wcss_sec_alloc_memory_region(wcss);
-+      if (ret)
-+              return ret;
-+
-+      sleep_clk = devm_clk_get_optional_enabled(&pdev->dev, "sleep");
-+      if (IS_ERR(sleep_clk))
-+              return dev_err_probe(&pdev->dev, PTR_ERR(sleep_clk),
-+                                   "Failed to get sleep clock\n");
-+
-+      int_clk = devm_clk_get_optional_enabled(&pdev->dev, "interconnect");
-+      if (IS_ERR(int_clk))
-+              return dev_err_probe(&pdev->dev, PTR_ERR(int_clk),
-+                                   "Failed to get interconnect clock\n");
-+
-+      ret = qcom_q6v5_init(&wcss->q6, pdev, rproc,
-+                           WCSS_CRASH_REASON, NULL, NULL);
-+      if (ret)
-+              return ret;
-+
-+      qcom_add_glink_subdev(rproc, &wcss->glink_subdev, desc->ss_name);
-+      qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, desc->ss_name);
-+
-+      rproc->auto_boot = false;
-+      rproc->dump_conf = RPROC_COREDUMP_INLINE;
-+      rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
-+
-+      if (desc->use_tmelcom) {
-+              wcss->mbox_client.dev = wcss->dev;
-+              wcss->mbox_client.knows_txdone = true;
-+              wcss->mbox_client.tx_block = true;
-+              wcss->mbox_chan = mbox_request_channel(&wcss->mbox_client, 0);
-+              if (IS_ERR_OR_NULL(wcss->mbox_chan))
-+                      return dev_err_probe(wcss->dev, PTR_ERR(wcss->mbox_chan),
-+                                           "mbox chan for IPC is missing\n");
-+      }
-+
-+      ret = devm_rproc_add(&pdev->dev, rproc);
-+      if (ret)
-+              return ret;
-+
-+      platform_set_drvdata(pdev, rproc);
-+
-+      return 0;
-+}
-+
-+static void wcss_sec_remove(struct platform_device *pdev)
-+{
-+      struct rproc *rproc = platform_get_drvdata(pdev);
-+      struct wcss_sec *wcss = rproc->priv;
-+
-+      mbox_free_channel(wcss->mbox_chan);
-+      qcom_remove_glink_subdev(rproc, &wcss->glink_subdev);
-+      qcom_remove_ssr_subdev(rproc, &wcss->ssr_subdev);
-+      qcom_q6v5_deinit(&wcss->q6);
-+}
-+
-+static const struct wcss_data wcss_sec_ipq5332_res_init = {
-+      .pasid = MPD_WCSS_PAS_ID,
-+      .ss_name = "q6wcss",
-+};
-+
-+static const struct wcss_data wcss_sec_ipq5424_res_init = {
-+      .pasid = MPD_WCSS_PAS_ID,
-+      .ss_name = "q6wcss",
-+      .use_tmelcom = true,
-+};
-+
-+static const struct wcss_data wcss_sec_ipq9574_res_init = {
-+      .pasid = WCSS_PAS_ID,
-+      .ss_name = "q6wcss",
-+};
-+
-+static const struct of_device_id wcss_sec_of_match[] = {
-+      { .compatible = "qcom,ipq5018-wcss-sec-pil", .data = &wcss_sec_ipq5332_res_init },
-+      { .compatible = "qcom,ipq5332-wcss-sec-pil", .data = &wcss_sec_ipq5332_res_init },
-+      { .compatible = "qcom,ipq5424-wcss-sec-pil", .data = &wcss_sec_ipq5424_res_init },
-+      { .compatible = "qcom,ipq9574-wcss-sec-pil", .data = &wcss_sec_ipq9574_res_init },
-+      { },
-+};
-+MODULE_DEVICE_TABLE(of, wcss_sec_of_match);
-+
-+static struct platform_driver wcss_sec_driver = {
-+      .probe = wcss_sec_probe,
-+      .remove = wcss_sec_remove,
-+      .driver = {
-+              .name = "qcom-wcss-secure-pil",
-+              .of_match_table = wcss_sec_of_match,
-+      },
-+};
-+module_platform_driver(wcss_sec_driver);
-+
-+MODULE_DESCRIPTION("Hexagon WCSS Secure Peripheral Image Loader");
-+MODULE_LICENSE("GPL");
---- a/include/linux/remoteproc.h
-+++ b/include/linux/remoteproc.h
-@@ -472,6 +472,7 @@ enum rproc_dump_mechanism {
-  * @node:     list node related to the rproc segment list
-  * @da:               device address of the segment
-  * @size:     size of the segment
-+ * @io_ptr:   ptr to store the ioremapped dump segment
-  * @priv:     private data associated with the dump_segment
-  * @dump:     custom dump function to fill device memory segment associated
-  *            with coredump
-@@ -483,6 +484,7 @@ struct rproc_dump_segment {
-       dma_addr_t da;
-       size_t size;
-+      void *io_ptr;
-       void *priv;
-       void (*dump)(struct rproc *rproc, struct rproc_dump_segment *segment,
-                    void *dest, size_t offset, size_t size);
diff --git a/target/linux/qualcommax/patches-6.12/0189-arm64-dts-qcom-ipq5018-add-nodes-to-bringup-q6.patch b/target/linux/qualcommax/patches-6.12/0189-arm64-dts-qcom-ipq5018-add-nodes-to-bringup-q6.patch
deleted file mode 100644 (file)
index ee1c573..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-From 553461c1f1ae9b2ac50bce5ed5de15092cc04d29 Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Tue, 21 Oct 2025 15:38:32 +0400
-Subject: [PATCH v6 5/8] arm64: dts: qcom: ipq5018: add nodes to bringup q6
-MIME-Version: 1.0
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 7bit
-Message-Id: <20251021-ipq5018-wifi-v6-5-c55c547df6fc@outlook.com>
-
-Enable nodes required for q6 remoteproc bring up.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 62 +++++++++++++++++++++++++++++++++++
- 1 file changed, 62 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -158,6 +158,11 @@
-                       reg = <0x0 0x4ac00000 0x0 0x200000>;
-                       no-map;
-               };
-+
-+              q6_region: wcss@4b000000 {
-+                      reg = <0x0 0x4b000000 0x0 0x1b00000>;
-+                      no-map;
-+              };
-       };
-       soc: soc@0 {
-@@ -734,6 +739,41 @@
-                       };
-               };
-+              q6v5_wcss: remoteproc@cd00000 {
-+                      compatible = "qcom,ipq5018-wcss-sec-pil";
-+                      reg = <0x0cd00000 0x10000>;
-+                      firmware-name = "ath11k/IPQ5018/hw1.0/q6_fw.mbn";
-+                      interrupts-extended = <&intc GIC_SPI 291 IRQ_TYPE_EDGE_RISING>,
-+                                            <&wcss_smp2p_in 0 IRQ_TYPE_NONE>,
-+                                            <&wcss_smp2p_in 1 IRQ_TYPE_NONE>,
-+                                            <&wcss_smp2p_in 2 IRQ_TYPE_NONE>,
-+                                            <&wcss_smp2p_in 3 IRQ_TYPE_NONE>;
-+                      interrupt-names = "wdog",
-+                                        "fatal",
-+                                        "ready",
-+                                        "handover",
-+                                        "stop-ack";
-+
-+                      clocks = <&gcc GCC_SLEEP_CLK_SRC>,
-+                               <&gcc GCC_SYS_NOC_WCSS_AHB_CLK>;
-+                      clock-names = "sleep",
-+                                    "interconnect";
-+
-+                      qcom,smem-states = <&wcss_smp2p_out 0>,
-+                                         <&wcss_smp2p_out 1>;
-+                      qcom,smem-state-names = "shutdown",
-+                                              "stop";
-+
-+                      memory-region = <&q6_region>;
-+
-+                      glink-edge {
-+                              interrupts = <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>;
-+                              label = "rtr";
-+                              qcom,remote-pid = <1>;
-+                              mboxes = <&apcs_glb 8>;
-+                      };
-+              };
-+
-               pcie1: pcie@80000000 {
-                       compatible = "qcom,pcie-ipq5018";
-                       reg = <0x80000000 0xf1d>,
-@@ -1008,4 +1048,28 @@
-                            <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                            <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
-       };
-+
-+      wcss: smp2p-wcss {
-+              compatible = "qcom,smp2p";
-+              qcom,smem = <435>, <428>;
-+
-+              interrupt-parent = <&intc>;
-+              interrupts = <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>;
-+
-+              mboxes = <&apcs_glb 9>;
-+
-+              qcom,local-pid = <0>;
-+              qcom,remote-pid = <1>;
-+
-+              wcss_smp2p_out: master-kernel {
-+                      qcom,entry-name = "master-kernel";
-+                      #qcom,smem-state-cells = <1>;
-+              };
-+
-+              wcss_smp2p_in: slave-kernel {
-+                      qcom,entry-name = "slave-kernel";
-+                      interrupt-controller;
-+                      #interrupt-cells = <2>;
-+              };
-+      };
- };
diff --git a/target/linux/qualcommax/patches-6.12/0305-pinctrl-qcom-IPQ5018-update-pwm-groups.patch b/target/linux/qualcommax/patches-6.12/0305-pinctrl-qcom-IPQ5018-update-pwm-groups.patch
deleted file mode 100644 (file)
index 476e5f6..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Subject: [PATCH] pinctrl: qcom: IPQ5018: update pwm groups
-Date: Wed, 27 Nov 2024 09:14:11 +0400
-
-GPIO 1, 30, and 46 are used to control PWM1, PWM3, and PWM0 respectively which
-in turn drive the PWM led, so let's update the pwm# and pingroups accordingly.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
---- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c
-+++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c
-@@ -541,7 +541,7 @@ static const char * const qdss_tracectl_
- };
- static const char * const pwm0_groups[] = {
--      "gpio42",
-+      "gpio42", "gpio46",
- };
- static const char * const qdss_cti_trig_out_b0_groups[] = {
-@@ -549,7 +549,7 @@ static const char * const qdss_cti_trig_
- };
- static const char * const pwm1_groups[] = {
--      "gpio43",
-+      "gpio43", "gpio1",
- };
- static const char * const qdss_cti_trig_in_b0_groups[] = {
-@@ -565,7 +565,7 @@ static const char * const qdss_cti_trig_
- };
- static const char * const pwm3_groups[] = {
--      "gpio45",
-+      "gpio45", "gpio30",
- };
- static const char * const qdss_cti_trig_in_b1_groups[] = {
-@@ -679,7 +679,7 @@ static const struct pinfunction ipq5018_
- static const struct msm_pingroup ipq5018_groups[] = {
-       PINGROUP(0, atest_char, _, qdss_cti_trig_out_a0, wci_txd, wci_rxd, xfem, _, _, _),
--      PINGROUP(1, atest_char, _, qdss_cti_trig_in_a0, wci_txd, wci_rxd, xfem, _, _, _),
-+      PINGROUP(1, atest_char, pwm1, qdss_cti_trig_in_a0, wci_txd, wci_rxd, xfem, _, _, _),
-       PINGROUP(2, atest_char, _, qdss_cti_trig_out_a1, wci_txd, wci_rxd, xfem, _, _, _),
-       PINGROUP(3, atest_char, _, qdss_cti_trig_in_a1, wci_txd, wci_rxd, xfem, _, _, _),
-       PINGROUP(4, sdc1_data, qspi_data, blsp1_spi1, btss, dbg_out, qdss_traceclk_a, _, burn0, _),
-@@ -708,7 +708,7 @@ static const struct msm_pingroup ipq5018
-       PINGROUP(27, audio_txmclk, wsa_swrm, audio_txmclk, blsp2_spi, btss, _, qdss_tracedata_b, _, _),
-       PINGROUP(28, audio_txbclk, wsa_swrm, blsp0_uart1, btss, qdss_tracedata_b, _, _, _, _),
-       PINGROUP(29, audio_txfsync, _, blsp0_uart1, _, qdss_tracedata_b, _, _, _, _),
--      PINGROUP(30, audio_txd, led2, led0, _, _, _, _, _, _),
-+      PINGROUP(30, audio_txd, led2, led0, pwm3, _, _, _, _, _),
-       PINGROUP(31, blsp2_spi0, blsp1_uart1, _, qdss_tracedata_b, eud_gpio, _, _, _, _),
-       PINGROUP(32, blsp2_spi0, blsp1_uart1, _, qdss_tracedata_b, eud_gpio, _, _, _, _),
-       PINGROUP(33, blsp2_i2c0, blsp2_spi0, blsp1_uart1, _, qdss_tracedata_b, eud_gpio, _, _, _),
-@@ -724,7 +724,7 @@ static const struct msm_pingroup ipq5018
-       PINGROUP(43, pwm1, qdss_cti_trig_in_b0, wci_txd, wci_rxd, xfem, _, _, _, _),
-       PINGROUP(44, pwm2, qdss_cti_trig_out_b1, wci_txd, wci_rxd, xfem, _, _, _, _),
-       PINGROUP(45, pwm3, qdss_cti_trig_in_b1, wci_txd, wci_rxd, xfem, _, _, _, _),
--      PINGROUP(46, led0, _, _, _, _, _, _, _, _),
-+      PINGROUP(46, led0, pwm0, _, _, _, _, _, _, _),
- };
- static const struct msm_pinctrl_soc_data ipq5018_pinctrl = {
diff --git a/target/linux/qualcommax/patches-6.12/0400-mtd-rawnand-add-support-for-TH58NYG3S0HBAI4.patch b/target/linux/qualcommax/patches-6.12/0400-mtd-rawnand-add-support-for-TH58NYG3S0HBAI4.patch
deleted file mode 100644 (file)
index b393a47..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-From 8d8b37d3af2bdccf0a37d2017d876bfc6ce42552 Mon Sep 17 00:00:00 2001
-From: Chukun Pan <amadeus@jmu.edu.cn>
-Date: Fri, 20 Oct 2023 23:18:21 +0800
-Subject: [PATCH 1/1] mtd: rawnand: add support for TH58NYG3S0HBAI4 NAND flash
-
-The Toshiba TH58NYG3S0HBAI4 is detected with 128 byte OOB while the flash
-has 256 bytes OOB. Since it is not an ONFI compliant NAND, the model name
-cannot be read from anywhere, add a static NAND ID entry to correct this.
-
-However, the NAND ID of this flash is inconsistent with the datasheet.
-The actual NAND ID is only 4 ID bytes, the last ID byte is missing.
-
-Datasheet available at (the ID table is on page 50):
-https://europe.kioxia.com/content/dam/kioxia/newidr/productinfo/datasheet/201910/DST_TH58NYG3S0HBAI4-TDE_EN_31565.pdf
-
-Datasheet NAND ID: {0x98, 0xa3, 0x91, 0x26, 0x76}
-Actual NAND ID: {0x98, 0xa3, 0x91, 0x26}
-
-It seems that this flash may be counterfeit, but another Toshiba flash
-also has the same problem. Maybe the driver has a bug, or some Toshiba
-nand flash is like this. Anyway, add a static NAND ID entry with only
-4 ID bytes as a hack to make sure it works.
-
-Tested on Arcadyan AW1000 flashed with OpenWrt.
-
-Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
-
-With 0411-mtd-rawnand-qpic-only-support-max-4-bytes-ID.patch, we can
-define 5 bytes ID here.
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- drivers/mtd/nand/raw/nand_ids.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/mtd/nand/raw/nand_ids.c
-+++ b/drivers/mtd/nand/raw/nand_ids.c
-@@ -58,6 +58,9 @@ struct nand_flash_dev nand_flash_ids[] =
-               { .id = {0xad, 0xde, 0x14, 0xa7, 0x42, 0x4a} },
-                 SZ_16K, SZ_8K, SZ_4M, NAND_NEED_SCRAMBLING, 6, 1664,
-                 NAND_ECC_INFO(40, SZ_1K) },
-+      {"TH58NYG3S0HBAI4 8G 1.8V 8-bit", /* Last ID bytes missing */
-+              { .id = {0x98, 0xa3, 0x91, 0x26, 0x76} },
-+                SZ_4K, SZ_1K, SZ_256K, 0, 5, 256, NAND_ECC_INFO(8, SZ_512) },
-       {"TH58NVG2S3HBAI4 4G 3.3V 8-bit",
-               { .id = {0x98, 0xdc, 0x91, 0x15, 0x76} },
-                 SZ_2K, SZ_512, SZ_128K, 0, 5, 128, NAND_ECC_INFO(8, SZ_512) },
diff --git a/target/linux/qualcommax/patches-6.12/0401-spi-spi-qpic-snand-default-to-4-bit-ECC.patch b/target/linux/qualcommax/patches-6.12/0401-spi-spi-qpic-snand-default-to-4-bit-ECC.patch
deleted file mode 100644 (file)
index 156d411..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-From 2e1ab53e8fcf708db51f560f7846802d406ee57d Mon Sep 17 00:00:00 2001
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Thu, 15 May 2025 22:47:43 +0200
-Subject: [PATCH] spi: spi-qpic-snand: default to 4-bit ECC
-
-There are NAND IC-s that define 1-bit ECC as the minimal strength,
-however that is unsupported by QPIC-SNAND as it only supports 4 or 8 bit
-ECC.
-
-Since most of these chips also support 4-bit ECC just fine, instead of
-erroring out if 1-bit ECC is requested lets instead default to 4-bit ECC.
-
-Fixes: 01b72ce61e8f ("qualcommax: ipq50xx: remove ECC user config from board files")
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/spi/spi-qpic-snand.c | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -304,6 +304,24 @@ static int qcom_spi_ecc_init_ctx_pipelin
-               ecc_cfg->spare_bytes = 2;
-               break;
-+      case 1:
-+      case 2:
-+              /*
-+               * Many chips have set a minimum ECC strength requirement
-+               * lower than 4-bits but also support higher strength, so
-+               * check if ecc_cfg was set by chip reqs and try 4-bits.
-+               */
-+              if (reqs->strength) {
-+                      dev_warn(snandc->dev,
-+                               "ECC strength requirement of %u-bit(s) is unsupported, trying 4-bits\n",
-+                               reqs->strength);
-+                      ecc_cfg->ecc_mode = ECC_MODE_4BIT;
-+                      ecc_cfg->ecc_bytes_hw = 7;
-+                      ecc_cfg->spare_bytes = 4;
-+                      break;
-+              } else
-+                      fallthrough;
-+
-       default:
-               dev_err(snandc->dev,
-                       "only 4 or 8 bits ECC strength is supported\n");
diff --git a/target/linux/qualcommax/patches-6.12/0411-mtd-rawnand-qpic-only-support-max-4-bytes-ID.patch b/target/linux/qualcommax/patches-6.12/0411-mtd-rawnand-qpic-only-support-max-4-bytes-ID.patch
deleted file mode 100644 (file)
index 6bb1123..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From ce4d8b3c5e866a8c515608cf623990e1471a69c7 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Tue, 2 Dec 2025 22:02:30 +0800
-Subject: [PATCH 1/2] mtd: rawnand: qpic only support max 4 bytes ID
-
-QPIC use a reg (NAND_READ_ID) to transport the ID, so the max bytes of ID is a word (4Bytes).
-
-https://github.com/torvalds/linux/blob/3a8660878839faadb4f1a6dd72c3179c1df56787/drivers/mtd/nand/raw/qcom_nandc.c#L1783
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- drivers/mtd/nand/raw/nand_base.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/mtd/nand/raw/nand_base.c
-+++ b/drivers/mtd/nand/raw/nand_base.c
-@@ -4965,7 +4965,7 @@ static bool find_full_id_nand(struct nan
-       memorg = nanddev_get_memorg(&chip->base);
--      if (!strncmp(type->id, id_data, type->id_len)) {
-+      if (!strncmp(type->id, id_data, min(4, type->id_len))) {
-               memorg->pagesize = type->pagesize;
-               mtd->writesize = memorg->pagesize;
-               memorg->pages_per_eraseblock = type->erasesize /
diff --git a/target/linux/qualcommax/patches-6.12/0412-mtd-spinand-qpic-only-support-max-4-bytes-ID.patch b/target/linux/qualcommax/patches-6.12/0412-mtd-spinand-qpic-only-support-max-4-bytes-ID.patch
deleted file mode 100644 (file)
index 35943a6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From cf5225a6e279995a574a5ed97cb227b5e076ed8e Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:11 +0800
-Subject: [PATCH 2/2] mtd: spinand: qpic only support max 4 bytes ID
-
-QPIC use a reg (NAND_READ_ID) to transport the ID, so the max bytes of ID is a word (4Bytes).
-
-https://github.com/torvalds/linux/blob/4a26e7032d7d57c998598c08a034872d6f0d3945/drivers/spi/spi-qpic-snand.c#L1392-L1393
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- drivers/mtd/nand/spi/core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -1337,7 +1337,7 @@ int spinand_match_and_init(struct spinan
-               if (rdid_method != info->devid.method)
-                       continue;
--              if (memcmp(id + 1, info->devid.id, info->devid.len))
-+              if (memcmp(id + 1, info->devid.id, min(3, info->devid.len)))
-                       continue;
-               nand->memorg = table[i].memorg;
diff --git a/target/linux/qualcommax/patches-6.12/0715-arm64-dts-qcom-ipq5018-add-vendor-compatible-to-mdio-node.patch b/target/linux/qualcommax/patches-6.12/0715-arm64-dts-qcom-ipq5018-add-vendor-compatible-to-mdio-node.patch
deleted file mode 100644 (file)
index 7250f93..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Wed, 28 May 2025 08:37:28 +0400
-Subject: [PATCH] arm64: dts: qcom: ipq5018: Add vendor compatible to mdio bus
-
-QCA SSDK needs to register the MDIO bus in its driver. Without a proper reference,
-it will crash. Since it tries to look up the MDIO bus using compatible strings that
-aren't upstreamed, add the vendor compatible.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -219,7 +219,7 @@
-               };
-               mdio0: mdio@88000 {
--                      compatible = "qcom,ipq5018-mdio";
-+                      compatible = "qcom,ipq5018-mdio", "qcom,ipq40xx-mdio";
-                       reg = <0x00088000 0x64>,
-                             <0x019475c4 0x4>;
-                       #address-cells = <1>;
diff --git a/target/linux/qualcommax/patches-6.12/0721-clk-gcc-ipq5018-remove-the-unsupported-clk-combinati.patch b/target/linux/qualcommax/patches-6.12/0721-clk-gcc-ipq5018-remove-the-unsupported-clk-combinati.patch
deleted file mode 100644 (file)
index c6225f6..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From f71366e0530db2c5cecbbbb6edfbf7344bd6f83b Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH 1/2] clk: gcc-ipq5018: remove the unsupported clk
- combination for gmac
-
-Comment out the unsupported clock combination in the frequency table 
-for GMAC1.
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- drivers/clk/qcom/gcc-ipq5018.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/qcom/gcc-ipq5018.c
-+++ b/drivers/clk/qcom/gcc-ipq5018.c
-@@ -678,7 +678,7 @@ static const struct freq_tbl ftbl_gmac1_
-       F(2500000, P_UNIPHY_RX, 12.5, 0, 0),
-       F(24000000, P_XO, 1, 0, 0),
-       F(25000000, P_UNIPHY_RX, 2.5, 0, 0),
--      F(125000000, P_UNIPHY_RX, 2.5, 0, 0),
-+      /* F(125000000, P_UNIPHY_RX, 2.5, 0, 0), */
-       F(125000000, P_UNIPHY_RX, 1, 0, 0),
-       F(312500000, P_UNIPHY_RX, 1, 0, 0),
-       { }
-@@ -718,7 +718,7 @@ static const struct freq_tbl ftbl_gmac1_
-       F(2500000, P_UNIPHY_TX, 12.5, 0, 0),
-       F(24000000, P_XO, 1, 0, 0),
-       F(25000000, P_UNIPHY_TX, 2.5, 0, 0),
--      F(125000000, P_UNIPHY_TX, 2.5, 0, 0),
-+      /* F(125000000, P_UNIPHY_TX, 2.5, 0, 0), */
-       F(125000000, P_UNIPHY_TX, 1, 0, 0),
-       F(312500000, P_UNIPHY_TX, 1, 0, 0),
-       { }
diff --git a/target/linux/qualcommax/patches-6.12/0723-clk-qcom-gcc-ipq5018-fix-uniphy-soft-reset-issue.patch b/target/linux/qualcommax/patches-6.12/0723-clk-qcom-gcc-ipq5018-fix-uniphy-soft-reset-issue.patch
deleted file mode 100644 (file)
index f670ef4..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Fri, 30 May 2025 09:12:23 +0400
-Subject: [PATCH] clk: qcom: gcc-ipq5018: fix UNIPHY soft reset issue
-
-The SOFT reset is supposed to trigger a resets across the SYS, RX, and
-TX lines of the IPQ5018 UNIPHY. So let's set the bitmask of the reset
-definition accordingly in the GCC as per the downstream driver.
-
-Link: https://git.codelinaro.org/clo/qsdk/oss/kernel/linux-ipq-5.4/-/commit/036bdc62aca561e8ff94a29c447fc400de2b7304
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---- a/drivers/clk/qcom/gcc-ipq5018.c
-+++ b/drivers/clk/qcom/gcc-ipq5018.c
-@@ -3648,7 +3648,7 @@ static const struct qcom_reset_map gcc_i
-       [GCC_UNIPHY_SYS_ARES] = { 0x56104, 1 },
-       [GCC_UNIPHY_RX_ARES] = { 0x56104, 4 },
-       [GCC_UNIPHY_TX_ARES] = { 0x56104, 5 },
--      [GCC_UNIPHY_SOFT_RESET] = {0x56104, 0 },
-+      [GCC_UNIPHY_SOFT_RESET] = {0x56104, .bitmask = 0x32 },
-       [GCC_USB0_BCR] = { 0x3e070, 0 },
-       [GCC_USB0_PHY_BCR] = { 0x3e034, 0 },
-       [GCC_WCSS_BCR] = { 0x18000, 0 },
diff --git a/target/linux/qualcommax/patches-6.12/0760-net-phy-aquantia-enable-USXGMII-MAC-autoneg.patch b/target/linux/qualcommax/patches-6.12/0760-net-phy-aquantia-enable-USXGMII-MAC-autoneg.patch
deleted file mode 100644 (file)
index 6ff9b32..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 54280bff5b17407e8b23cdeafdc63f4d43ad1ee5 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Thu, 27 Nov 2025 13:49:06 +0100
-Subject: [PATCH] net: phy: aquantia: enable USXGMII MAC autoneg
-
-USXGMII MAC autoneg control bit is always set disabled by default, in order
-for USXGMII to work properly we must enable it.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/net/phy/aquantia/aquantia_main.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -46,6 +46,9 @@
- #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI  7
- #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII        10
-+#define MDIO_PHYXS_VEND_PROV2                 0xc441
-+#define MDIO_PHYXS_VEND_PROV2_USX_AUTONEG_MAC BIT(3)
-+
- #define MDIO_AN_VEND_PROV                     0xc400
- #define MDIO_AN_VEND_PROV_1000BASET_FULL      BIT(15)
- #define MDIO_AN_VEND_PROV_1000BASET_HALF      BIT(14)
-@@ -440,6 +443,10 @@ static int aqr107_read_status(struct phy
-               break;
-       case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII:
-               phydev->interface = PHY_INTERFACE_MODE_USXGMII;
-+              phy_modify_mmd(phydev, MDIO_MMD_PHYXS,
-+                             MDIO_PHYXS_VEND_PROV2,
-+                             MDIO_PHYXS_VEND_PROV2_USX_AUTONEG_MAC,
-+                             MDIO_PHYXS_VEND_PROV2_USX_AUTONEG_MAC);
-               break;
-       case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI:
-               phydev->interface = PHY_INTERFACE_MODE_XAUI;
diff --git a/target/linux/qualcommax/patches-6.12/0801-dt-bindings-remoteproc-qcom-Add-support-for-multipd-model.patch b/target/linux/qualcommax/patches-6.12/0801-dt-bindings-remoteproc-qcom-Add-support-for-multipd-model.patch
deleted file mode 100644 (file)
index 81248e5..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Fri, 10 Nov 2023 14:49:29 +0530
-Subject: [PATCH] dt-bindings: remoteproc: qcom: Add support for multipd model
-
-Add new binding document for multipd model remoteproc.
-IPQ5332, IPQ9574 follows multipd model.
-
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
----
---- /dev/null
-+++ b/Documentation/devicetree/bindings/remoteproc/qcom,multipd-pil.yaml
-@@ -0,0 +1,189 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/remoteproc/qcom,multipd-pil.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Qualcomm Multipd Secure Peripheral Image Loader
-+
-+maintainers:
-+  - Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-+
-+description:
-+  Multipd Peripheral Image Loader loads firmware and boots Q6 protection domain,
-+  WCSS protection domain remoteproc's on the Qualcomm IPQ9574, IPQ5332 SoC.
-+  Protection domain is similar to process in Linux. Here QDSP6 processor runs
-+  each wifi radio functionality on a separate process. One process can't access
-+  other process resources, so this is termed as PD i.e protection domain.
-+
-+properties:
-+  compatible:
-+    enum:
-+      - qcom,ipq5332-q6-mpd
-+      - qcom,ipq9574-q6-mpd
-+
-+  reg:
-+    maxItems: 1
-+
-+  firmware-name:
-+    maxItems: 2
-+
-+  interrupts:
-+    items:
-+      - description: Watchdog interrupt
-+      - description: Fatal interrupt
-+      - description: Ready interrupt
-+      - description: Handover interrupt
-+      - description: Stop acknowledge interrupt
-+
-+  interrupt-names:
-+    items:
-+      - const: wdog
-+      - const: fatal
-+      - const: ready
-+      - const: handover
-+      - const: stop-ack
-+
-+  qcom,smem-states:
-+    $ref: /schemas/types.yaml#/definitions/phandle-array
-+    description: States used by the AP to signal the remote processor
-+    items:
-+      - description: Shutdown Q6
-+      - description: Stop Q6
-+
-+  qcom,smem-state-names:
-+    description:
-+      Names of the states used by the AP to signal the remote processor
-+    items:
-+      - const: shutdown
-+      - const: stop
-+
-+  memory-region:
-+    items:
-+      - description: Q6 reserved region
-+
-+  glink-edge:
-+    $ref: /schemas/remoteproc/qcom,glink-edge.yaml#
-+    description:
-+      Qualcomm G-Link subnode which represents communication edge, channels
-+      and devices related to the Modem.
-+    unevaluatedProperties: false
-+
-+patternProperties:
-+  "^pd-1|pd-2|pd-3":
-+    type: object
-+    description:
-+      WCSS means 'wireless connectivity sub system', in simple words it's a
-+      wifi radio block. In multipd model, Q6 root protection domain will
-+      provide services to WCSS user protection domain. In other words WCSS
-+      protection domains depends on Q6 protection domain i.e  Q6 should be up
-+      before WCSS, similarly Q6 should shut down after all WCSS domains are
-+      down. It can be achieved by building parent-child topology between Q6
-+      and WCSS domain's i.e keeping wcss node as sub node of Q6 device node.
-+
-+    properties:
-+      firmware-name:
-+        maxItems: 1
-+
-+      interrupts:
-+        items:
-+          - description: Fatal interrupt
-+          - description: Ready interrupt
-+          - description: Spawn acknowledge interrupt
-+          - description: Stop acknowledge interrupt
-+
-+      interrupt-names:
-+        items:
-+          - const: fatal
-+          - const: ready
-+          - const: spawn-ack
-+          - const: stop-ack
-+
-+      qcom,smem-states:
-+        $ref: /schemas/types.yaml#/definitions/phandle-array
-+        description: States used by the AP to signal the remote processor
-+        items:
-+          - description: Shutdown WCSS pd
-+          - description: Stop WCSS pd
-+          - description: Spawn WCSS pd
-+
-+      qcom,smem-state-names:
-+        description:
-+          Names of the states used by the AP to signal the remote processor
-+        items:
-+          - const: shutdown
-+          - const: stop
-+          - const: spawn
-+
-+    required:
-+      - firmware-name
-+      - interrupts
-+      - interrupt-names
-+      - qcom,smem-states
-+      - qcom,smem-state-names
-+
-+    additionalProperties: false
-+
-+required:
-+  - compatible
-+  - firmware-name
-+  - reg
-+  - interrupts
-+  - interrupt-names
-+  - qcom,smem-states
-+  - qcom,smem-state-names
-+  - memory-region
-+
-+additionalProperties: false
-+
-+examples:
-+  - |
-+    #include <dt-bindings/interrupt-controller/arm-gic.h>
-+    q6v5_wcss: remoteproc@d100000 {
-+      compatible = "qcom,ipq5332-q6-mpd";
-+      reg = <0xd100000 0x4040>;
-+      firmware-name = "ath11k/IPQ5332/hw1.0/q6_fw0.mdt",
-+                      "ath11k/IPQ5332/hw1.0/iu_fw.mdt";
-+      interrupts-extended = <&intc GIC_SPI 291 IRQ_TYPE_EDGE_RISING>,
-+                            <&wcss_smp2p_in 0 IRQ_TYPE_NONE>,
-+                            <&wcss_smp2p_in 1 IRQ_TYPE_NONE>,
-+                            <&wcss_smp2p_in 2 IRQ_TYPE_NONE>,
-+                            <&wcss_smp2p_in 3 IRQ_TYPE_NONE>;
-+      interrupt-names = "wdog",
-+                        "fatal",
-+                        "ready",
-+                        "handover",
-+                        "stop-ack";
-+
-+      qcom,smem-states = <&wcss_smp2p_out 0>,
-+                         <&wcss_smp2p_out 1>;
-+      qcom,smem-state-names = "shutdown",
-+                              "stop";
-+
-+      memory-region = <&q6_region>;
-+
-+      glink-edge {
-+        interrupts = <GIC_SPI 417 IRQ_TYPE_EDGE_RISING>;
-+        label = "rtr";
-+        qcom,remote-pid = <1>;
-+        mboxes = <&apcs_glb 8>;
-+      };
-+
-+      pd-1 {
-+        firmware-name = "ath11k/IPQ5332/hw1.0/q6_fw1.mdt";
-+        interrupts-extended = <&wcss_smp2p_in 8 IRQ_TYPE_NONE>,
-+                              <&wcss_smp2p_in 9 IRQ_TYPE_NONE>,
-+                              <&wcss_smp2p_in 12 IRQ_TYPE_NONE>,
-+                              <&wcss_smp2p_in 11 IRQ_TYPE_NONE>;
-+        interrupt-names = "fatal",
-+                          "ready",
-+                          "spawn-ack",
-+                          "stop-ack";
-+        qcom,smem-states = <&wcss_smp2p_out 8>,
-+                           <&wcss_smp2p_out 9>,
-+                           <&wcss_smp2p_out 10>;
-+        qcom,smem-state-names = "shutdown",
-+                                "stop",
-+                                "spawn";
-+      };
-+    };
diff --git a/target/linux/qualcommax/patches-6.12/0803-firmware-qcom_scm-ipq5332-add-msa-lock-unlock-suppor.patch b/target/linux/qualcommax/patches-6.12/0803-firmware-qcom_scm-ipq5332-add-msa-lock-unlock-suppor.patch
deleted file mode 100644 (file)
index 438e553..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-From 217fbbc122663c5a3dac752cebef44fb3e0cc179 Mon Sep 17 00:00:00 2001
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Fri, 10 Nov 2023 14:49:35 +0530
-Subject: [PATCH] firmware: qcom_scm: ipq5332: add msa lock/unlock
- support
-
-IPQ5332 user pd remoteproc firmwares need to be locked
-with MSA(modem secure access) features. This patch add
-support to lock/unlock MSA features.
-
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
----
- drivers/firmware/qcom//qcom_scm.c            | 78 ++++++++++++++++++++++++++
- drivers/firmware/qcom//qcom_scm.h            |  2 +
- include/linux/firmware/qcom/qcom_scm.h |  2 +
- 3 files changed, 82 insertions(+)
-
---- a/include/linux/firmware/qcom/qcom_scm.h
-+++ b/include/linux/firmware/qcom/qcom_scm.h
-@@ -79,6 +79,8 @@ int qcom_scm_pas_mem_setup(u32 periphera
- int qcom_scm_pas_auth_and_reset(u32 peripheral);
- int qcom_scm_pas_shutdown(u32 peripheral);
- bool qcom_scm_pas_supported(u32 peripheral);
-+int qcom_scm_msa_lock(u32 peripheral);
-+int qcom_scm_msa_unlock(u32 peripheral);
- int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
- int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
---- a/drivers/firmware/qcom/qcom_scm.c
-+++ b/drivers/firmware/qcom/qcom_scm.c
-@@ -807,6 +807,84 @@ bool qcom_scm_pas_supported(u32 peripher
- }
- EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
-+/**
-+ * qcom_scm_msa_lock() - Lock given peripheral firmware region as MSA
-+ *
-+ * @peripheral:       peripheral id
-+ *
-+ * Return 0 on success.
-+ */
-+int qcom_scm_msa_lock(u32 peripheral)
-+{
-+      int ret;
-+      struct qcom_scm_desc desc = {
-+              .svc = QCOM_SCM_SVC_PIL,
-+              .cmd = QCOM_SCM_MSA_LOCK,
-+              .arginfo = QCOM_SCM_ARGS(1),
-+              .args[0] = peripheral,
-+              .owner = ARM_SMCCC_OWNER_SIP,
-+      };
-+      struct qcom_scm_res res;
-+
-+      if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
-+                                        QCOM_SCM_MSA_LOCK))
-+              return 0;
-+
-+      ret = qcom_scm_clk_enable();
-+      if (ret)
-+              return ret;
-+
-+      ret = qcom_scm_bw_enable();
-+      if (ret)
-+              return ret;
-+
-+      ret = qcom_scm_call(__scm->dev, &desc, &res);
-+      qcom_scm_bw_disable();
-+      qcom_scm_clk_disable();
-+
-+      return ret ? : res.result[0];
-+}
-+EXPORT_SYMBOL_GPL(qcom_scm_msa_lock);
-+
-+/**
-+ * qcom_scm_msa_unlock() - Unlock given peripheral MSA firmware region
-+ *
-+ * @peripheral:       peripheral id
-+ *
-+ * Return 0 on success.
-+ */
-+int qcom_scm_msa_unlock(u32 peripheral)
-+{
-+      int ret;
-+      struct qcom_scm_desc desc = {
-+              .svc = QCOM_SCM_SVC_PIL,
-+              .cmd = QCOM_SCM_MSA_UNLOCK,
-+              .arginfo = QCOM_SCM_ARGS(1),
-+              .args[0] = peripheral,
-+              .owner = ARM_SMCCC_OWNER_SIP,
-+      };
-+      struct qcom_scm_res res;
-+
-+      if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
-+                                        QCOM_SCM_MSA_UNLOCK))
-+              return 0;
-+
-+      ret = qcom_scm_clk_enable();
-+      if (ret)
-+              return ret;
-+
-+      ret = qcom_scm_bw_enable();
-+      if (ret)
-+              return ret;
-+
-+      ret = qcom_scm_call(__scm->dev, &desc, &res);
-+      qcom_scm_bw_disable();
-+      qcom_scm_clk_disable();
-+
-+      return ret ? : res.result[0];
-+}
-+EXPORT_SYMBOL_GPL(qcom_scm_msa_unlock);
-+
- static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
- {
-       struct qcom_scm_desc desc = {
---- a/drivers/firmware/qcom/qcom_scm.h
-+++ b/drivers/firmware/qcom/qcom_scm.h
-@@ -102,6 +102,8 @@ struct qcom_tzmem_pool *qcom_scm_get_tzm
- #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
- #define QCOM_SCM_PIL_PAS_MSS_RESET    0x0a
- #define QCOM_SCM_PIL_PAS_INIT_IMAGE_V2        0x1a
-+#define QCOM_SCM_MSA_LOCK             0x24
-+#define QCOM_SCM_MSA_UNLOCK           0x25
- #define QCOM_SCM_SVC_IO                       0x05
- #define QCOM_SCM_IO_READ              0x01
diff --git a/target/linux/qualcommax/patches-6.12/0804-remoteproc-qcom-q6v5-Add-multipd-interrupts-support.patch b/target/linux/qualcommax/patches-6.12/0804-remoteproc-qcom-q6v5-Add-multipd-interrupts-support.patch
deleted file mode 100644 (file)
index 1dae38a..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-From cae691d32306966065df869fa7424728d1b16b14 Mon Sep 17 00:00:00 2001
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Fri, 10 Nov 2023 14:49:36 +0530
-Subject: [PATCH] remoteproc: qcom: q6v5: Add multipd interrupts support
-
-In multipd model, root & user pd remoteproc's interrupts are
-different. User pd needs additional interrupts like spawn.
-Instead of going with qcom_q6v5_init(), we defined a new
-function to register userpd rproc interrupts in mpd driver.
-Since userpd rproc uses some of common interrupts like fatal,
-ready, static is removed from ISR handler and used in userpd
-interrupt registration.
-
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
----
- drivers/remoteproc/qcom_q6v5.c | 41 +++++++++++++++++++++++++++++++---
- drivers/remoteproc/qcom_q6v5.h | 11 +++++++++
- 2 files changed, 49 insertions(+), 3 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5.c
-+++ b/drivers/remoteproc/qcom_q6v5.c
-@@ -112,7 +112,7 @@ static irqreturn_t q6v5_wdog_interrupt(i
-       return IRQ_HANDLED;
- }
--static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
-+irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
- {
-       struct qcom_q6v5 *q6v5 = data;
-       size_t len;
-@@ -132,8 +132,9 @@ static irqreturn_t q6v5_fatal_interrupt(
-       return IRQ_HANDLED;
- }
-+EXPORT_SYMBOL_GPL(q6v5_fatal_interrupt);
--static irqreturn_t q6v5_ready_interrupt(int irq, void *data)
-+irqreturn_t q6v5_ready_interrupt(int irq, void *data)
- {
-       struct qcom_q6v5 *q6v5 = data;
-@@ -141,6 +142,7 @@ static irqreturn_t q6v5_ready_interrupt(
-       return IRQ_HANDLED;
- }
-+EXPORT_SYMBOL_GPL(q6v5_ready_interrupt);
- /**
-  * qcom_q6v5_wait_for_start() - wait for remote processor start signal
-@@ -179,7 +181,17 @@ static irqreturn_t q6v5_handover_interru
-       return IRQ_HANDLED;
- }
--static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
-+irqreturn_t q6v5_spawn_interrupt(int irq, void *data)
-+{
-+      struct qcom_q6v5 *q6v5 = data;
-+
-+      complete(&q6v5->spawn_done);
-+
-+      return IRQ_HANDLED;
-+}
-+EXPORT_SYMBOL_GPL(q6v5_spawn_interrupt);
-+
-+irqreturn_t q6v5_stop_interrupt(int irq, void *data)
- {
-       struct qcom_q6v5 *q6v5 = data;
-@@ -187,6 +199,7 @@ static irqreturn_t q6v5_stop_interrupt(i
-       return IRQ_HANDLED;
- }
-+EXPORT_SYMBOL_GPL(q6v5_stop_interrupt);
- /**
-  * qcom_q6v5_request_stop() - request the remote processor to stop
-@@ -217,6 +230,28 @@ int qcom_q6v5_request_stop(struct qcom_q
- EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
- /**
-+ * qcom_q6v5_request_spawn() - request the remote processor to spawn
-+ * @q6v5:      reference to qcom_q6v5 context
-+ *
-+ * Return: 0 on success, negative errno on failure
-+ */
-+int qcom_q6v5_request_spawn(struct qcom_q6v5 *q6v5)
-+{
-+      int ret;
-+
-+      ret = qcom_smem_state_update_bits(q6v5->spawn_state,
-+                                        BIT(q6v5->spawn_bit), BIT(q6v5->spawn_bit));
-+
-+      ret = wait_for_completion_timeout(&q6v5->spawn_done, 5 * HZ);
-+
-+      qcom_smem_state_update_bits(q6v5->spawn_state,
-+                                  BIT(q6v5->spawn_bit), 0);
-+
-+      return ret == 0 ? -ETIMEDOUT : 0;
-+}
-+EXPORT_SYMBOL_GPL(qcom_q6v5_request_spawn);
-+
-+/**
-  * qcom_q6v5_panic() - panic handler to invoke a stop on the remote
-  * @q6v5:     reference to qcom_q6v5 context
-  *
---- a/drivers/remoteproc/qcom_q6v5.h
-+++ b/drivers/remoteproc/qcom_q6v5.h
-@@ -18,21 +18,27 @@ struct qcom_q6v5 {
-       struct qcom_smem_state *state;
-       struct qmp *qmp;
-+      struct qcom_smem_state *shutdown_state;
-+      struct qcom_smem_state *spawn_state;
-       struct icc_path *path;
-       unsigned stop_bit;
-+      unsigned shutdown_bit;
-+      unsigned spawn_bit;
-       int wdog_irq;
-       int fatal_irq;
-       int ready_irq;
-       int handover_irq;
-       int stop_irq;
-+      int spawn_irq;
-       bool handover_issued;
-       struct completion start_done;
-       struct completion stop_done;
-+      struct completion spawn_done;
-       int crash_reason;
-@@ -50,7 +56,12 @@ void qcom_q6v5_deinit(struct qcom_q6v5 *
- int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5);
- int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5);
- int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon);
-+int qcom_q6v5_request_spawn(struct qcom_q6v5 *q6v5);
- int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout);
- unsigned long qcom_q6v5_panic(struct qcom_q6v5 *q6v5);
-+irqreturn_t q6v5_fatal_interrupt(int irq, void *data);
-+irqreturn_t q6v5_ready_interrupt(int irq, void *data);
-+irqreturn_t q6v5_spawn_interrupt(int irq, void *data);
-+irqreturn_t q6v5_stop_interrupt(int irq, void *data);
- #endif
diff --git a/target/linux/qualcommax/patches-6.12/0805-remoteproc-qcom-Add-Hexagon-based-multipd-rproc-driv.patch b/target/linux/qualcommax/patches-6.12/0805-remoteproc-qcom-Add-Hexagon-based-multipd-rproc-driv.patch
deleted file mode 100644 (file)
index 98b4981..0000000
+++ /dev/null
@@ -1,895 +0,0 @@
-From 3f61ff1fb5c90f8b6c28a3a2b4a29203000ee585 Mon Sep 17 00:00:00 2001
-From: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
-Date: Fri, 10 Nov 2023 14:49:37 +0530
-Subject: [PATCH] remoteproc: qcom: Add Hexagon based multipd rproc
- driver
-
-It adds support to bring up remoteproc's on multipd model.
-Pd means protection domain. It's similar to process in Linux.
-Here QDSP6 processor runs each wifi radio functionality on a
-separate process. One process can't access other process
-resources, so this is termed as PD i.e protection domain.
-
-Here we have two pd's called root and user pd. We can correlate
-Root pd as root and user pd as user in linux. Root pd has more
-privileges than user pd. Root will provide services to user pd.
-
->From remoteproc driver perspective, root pd corresponds to QDSP6
-processor bring up and user pd corresponds to Wifi radio (WCSS)
-bring up.
-
-Here WCSS(user) PD is dependent on Q6(root) PD, so first
-q6 pd should be up before wcss pd. After wcss pd goes down,
-q6 pd should be turned off.
-
- APPS                          QDSP6
--------                      -------------
-|     |         Crash notification  |          |       ------
-|     |<---------------------|----------|-------|User|
-|     |                             |          |    |->|PD1 |
-|     |                             |  ------- |    |  ------
-|     |                             |  |     | |    |
-|Root |         Start/stop  Q6      |  |  R  | |    |
-|PD   |<---------------------|->|     | |    |
-|rproc|  Crash notification  | |  O  | |    |
-|     |                             |  |     | |    |
-|User |Start/stop UserPD1    |  |  O  | |    |
-|PD1  |----------------------|->|     |-|----|
-|rproc|                             |  |  T  | |    |
-|     |                             |  |     | |    |
-|User |Start/stop UserPD2    | |  P  | |    |
-|PD2  |----------------------|->|     |-|----|
-|rproc|                             |  |  D  | |    |
-|     |                             |  ------- |    |  ------
-|     |        Crash notification   |          |    |->|User|
-|     |<---------------------|----------|-------|PD2 |
--------                             |          |       ------
-                             ------------
-
-IPQ5332, IPQ9574 supports multipd remoteproc driver.
-
-Signed-off-by: Manikanta Mylavarapu <quic_mmanikan@quicinc.com>
----
- drivers/remoteproc/Kconfig         |  19 +
- drivers/remoteproc/Makefile        |   1 +
- drivers/remoteproc/qcom_q6v5_mpd.c | 802 +++++++++++++++++++++++++++++
- 3 files changed, 822 insertions(+)
- create mode 100644 drivers/remoteproc/qcom_q6v5_mpd.c
-
---- a/drivers/remoteproc/Kconfig
-+++ b/drivers/remoteproc/Kconfig
-@@ -235,6 +235,25 @@ config QCOM_Q6V5_PAS
-         CDSP (Compute DSP), MPSS (Modem Peripheral SubSystem), and
-         SLPI (Sensor Low Power Island).
-+config QCOM_Q6V5_MPD
-+      tristate "Qualcomm Hexagon based MPD model Peripheral Image Loader"
-+      depends on OF && ARCH_QCOM
-+      depends on QCOM_SMEM
-+      depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n
-+      depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
-+      depends on QCOM_SYSMON || QCOM_SYSMON=n
-+      depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
-+      depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
-+      select QCOM_MDT_LOADER
-+      select QCOM_PIL_INFO
-+      select QCOM_Q6V5_COMMON
-+      select QCOM_RPROC_COMMON
-+      select QCOM_SCM
-+      help
-+        Say y here to support the Qualcomm Secure Peripheral Image Loader
-+        for the Hexagon based MultiPD model remote processors on e.g. IPQ5018.
-+        This is trustZone wireless subsystem.
-+
- config QCOM_Q6V5_WCSS
-       tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader"
-       depends on OF && ARCH_QCOM
---- a/drivers/remoteproc/Makefile
-+++ b/drivers/remoteproc/Makefile
-@@ -25,6 +25,7 @@ obj-$(CONFIG_QCOM_PIL_INFO)          += qcom_pil
- obj-$(CONFIG_QCOM_RPROC_COMMON)               += qcom_common.o
- obj-$(CONFIG_QCOM_Q6V5_COMMON)                += qcom_q6v5.o
- obj-$(CONFIG_QCOM_Q6V5_ADSP)          += qcom_q6v5_adsp.o
-+obj-$(CONFIG_QCOM_Q6V5_MPD)           += qcom_q6v5_mpd.o
- obj-$(CONFIG_QCOM_Q6V5_MSS)           += qcom_q6v5_mss.o
- obj-$(CONFIG_QCOM_Q6V5_PAS)           += qcom_q6v5_pas.o
- obj-$(CONFIG_QCOM_Q6V5_WCSS)          += qcom_q6v5_wcss.o
---- /dev/null
-+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
-@@ -0,0 +1,796 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2016-2018 Linaro Ltd.
-+ * Copyright (C) 2014 Sony Mobile Communications AB
-+ * Copyright (c) 2012-2018, 2021 The Linux Foundation. All rights reserved.
-+ */
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/firmware/qcom/qcom_scm.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/iopoll.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
-+#include <linux/of_device.h>
-+#include <linux/of_platform.h>
-+#include <linux/of_reserved_mem.h>
-+#include <linux/platform_device.h>
-+#include <linux/reset.h>
-+#include <linux/soc/qcom/mdt_loader.h>
-+#include <linux/soc/qcom/smem.h>
-+#include <linux/soc/qcom/smem_state.h>
-+#include "qcom_common.h"
-+#include "qcom_q6v5.h"
-+
-+#include "remoteproc_internal.h"
-+
-+#define WCSS_CRASH_REASON             421
-+#define WCSS_SMEM_HOST                        1
-+
-+#define WCNSS_PAS_ID                  6
-+#define MPD_WCNSS_PAS_ID        0xD
-+
-+#define BUF_SIZE                      35
-+
-+#define MAX_FIRMWARE                  3
-+
-+#define RPD_SWID              MPD_WCNSS_PAS_ID
-+#define UPD_SWID              0x12
-+#define REMOTE_PID                    1
-+#define UPD_BOOT_INFO_SMEM_SIZE               4096
-+#define UPD_BOOT_INFO_HEADER_TYPE     0x2
-+#define UPD_BOOT_INFO_SMEM_ID         507
-+#define VERSION2                      2
-+
-+static LIST_HEAD(upd_rproc_list);
-+enum {
-+      Q6_IPQ,
-+      WCSS_IPQ,
-+};
-+
-+/**
-+ * struct userpd_boot_info_header - header of user pd bootinfo
-+ * @type:             type of bootinfo passing over smem
-+ * @length:           length of header in bytes
-+ */
-+struct userpd_boot_info_header {
-+      u8 type;
-+      u8 length;
-+};
-+
-+/**
-+ * struct userpd_boot_info - holds info required to boot user pd
-+ * @header:           pointer to header
-+ * @pid:              unique id represents each user pd process
-+ * @bootaddr:         load address of user pd firmware
-+ * @data_size:                user pd firmware memory size
-+ */
-+struct userpd_boot_info {
-+      struct userpd_boot_info_header header;
-+      u8 pid;
-+      u32 bootaddr;
-+      u32 data_size;
-+} __packed;
-+
-+struct q6_wcss {
-+      struct device *dev;
-+      struct qcom_rproc_glink glink_subdev;
-+      struct qcom_rproc_ssr ssr_subdev;
-+      struct qcom_q6v5 q6;
-+      phys_addr_t mem_phys;
-+      phys_addr_t mem_reloc;
-+      void *mem_region;
-+      size_t mem_size;
-+      u8 pd_asid;
-+      const struct wcss_data *desc;
-+      const char **firmware;
-+      u32 version;
-+};
-+
-+struct wcss_data {
-+      u32 pasid;
-+      bool share_upd_info_to_q6;
-+};
-+
-+/**
-+ * qcom_get_pd_asid() - get the pd asid number from PD spawn bit
-+ * @rproc:    rproc handle
-+ *
-+ * Returns asid on success
-+ */
-+static u8 qcom_get_pd_asid(struct rproc *rproc)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      u8 bit = wcss->q6.spawn_bit;
-+
-+      return bit / 8;
-+}
-+
-+static int q6_wcss_start(struct rproc *rproc)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      int ret;
-+      const struct wcss_data *desc = wcss->desc;
-+
-+      qcom_q6v5_prepare(&wcss->q6);
-+
-+      ret = qcom_scm_pas_auth_and_reset(desc->pasid);
-+      if (ret) {
-+              dev_err(wcss->dev, "wcss_reset failed\n");
-+              return ret;
-+      }
-+
-+      ret = qcom_q6v5_wait_for_start(&wcss->q6, 5 * HZ);
-+      if (ret == -ETIMEDOUT)
-+              dev_err(wcss->dev, "start timed out\n");
-+
-+      return ret;
-+}
-+
-+static int q6_wcss_spawn_pd(struct rproc *rproc)
-+{
-+      int ret;
-+      struct q6_wcss *wcss = rproc->priv;
-+
-+      ret = qcom_q6v5_request_spawn(&wcss->q6);
-+      if (ret == -ETIMEDOUT) {
-+              dev_err(wcss->dev, "%s spawn timedout\n", rproc->name);
-+              return ret;
-+      }
-+
-+      ret = qcom_q6v5_wait_for_start(&wcss->q6, msecs_to_jiffies(10000));
-+      if (ret == -ETIMEDOUT) {
-+              dev_err(wcss->dev, "%s start timedout\n", rproc->name);
-+              wcss->q6.running = false;
-+              return ret;
-+      }
-+      wcss->q6.running = true;
-+      return ret;
-+}
-+
-+static int wcss_pd_start(struct rproc *rproc)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      u32 pasid = (wcss->pd_asid << 8) | UPD_SWID;
-+      int ret;
-+
-+      ret = qcom_scm_msa_lock(pasid);
-+      if (ret) {
-+              dev_err(wcss->dev, "failed to power up pd\n");
-+              return ret;
-+      }
-+
-+      if (wcss->q6.spawn_bit) {
-+              ret = q6_wcss_spawn_pd(rproc);
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      return ret;
-+}
-+
-+static int q6_wcss_stop(struct rproc *rproc)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      const struct wcss_data *desc = wcss->desc;
-+      int ret;
-+
-+      ret = qcom_scm_pas_shutdown(desc->pasid);
-+      if (ret) {
-+              dev_err(wcss->dev, "not able to shutdown\n");
-+              return ret;
-+      }
-+      qcom_q6v5_unprepare(&wcss->q6);
-+
-+      return 0;
-+}
-+
-+/**
-+ * wcss_pd_stop() - Stop WCSS user pd
-+ * @rproc:    rproc handle
-+ *
-+ * Stop root pd after user pd down. Root pd
-+ * is used to provide services to user pd, so
-+ * keeping root pd alive when user pd is down
-+ * is invalid.
-+ * ---------------------------------------------
-+ *
-+ *                            -----------
-+ *                 |-------->| User PD1 |
-+ *                 |          -----------
-+ *                 |
-+ *                 |
-+ *    -----        |          -----------
-+ *    | Q6 |---------------->| User Pd2 |
-+ *    -----        |          -----------
-+ *                 |
-+ *                 |
-+ *                 |          -----------
-+ *                 |--------->| User Pd3 |
-+ *                            -----------
-+ * ----------------------------------------------
-+ */
-+static int wcss_pd_stop(struct rproc *rproc)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      struct rproc *rpd_rproc = dev_get_drvdata(wcss->dev->parent);
-+      u32 pasid = (wcss->pd_asid << 8) | UPD_SWID;
-+      int ret;
-+
-+      if (rproc->state != RPROC_CRASHED && wcss->q6.stop_bit) {
-+              ret = qcom_q6v5_request_stop(&wcss->q6, NULL);
-+              if (ret) {
-+                      dev_err(&rproc->dev, "pd not stopped\n");
-+                      return ret;
-+              }
-+      }
-+
-+      ret = qcom_scm_msa_unlock(pasid);
-+      if (ret) {
-+              dev_err(wcss->dev, "failed to power down pd\n");
-+              return ret;
-+      }
-+
-+      rproc_shutdown(rpd_rproc);
-+
-+      return 0;
-+}
-+
-+static void *q6_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len,
-+                            bool *is_iomem)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      int offset;
-+
-+      offset = da - wcss->mem_reloc;
-+      if (offset < 0 || offset + len > wcss->mem_size)
-+              return NULL;
-+
-+      return wcss->mem_region + offset;
-+}
-+
-+/**
-+ * share_upd_bootinfo_to_q6() - Share userpd boot info to Q6 root pd
-+ * @rproc:    rproc handle
-+ *
-+ * Q6 needs user pd parameters like loadaddress and
-+ * PIL size to authenticate user pd with underlying
-+ * security software. If authenticatoin success then
-+ * only Q6 spawns user pd and sends spawn ack to rproc
-+ * driver. This API is passing userpd boot info to Q6
-+ * over SMEM.
-+ *
-+ * User pd boot-info format mentioned below
-+ * <Version> <No of elements passing over smem> <Header type> <Header Length>
-+ * <Process Id> <Load address> <firmware mem Size>
-+ *
-+ * Returns 0 on success else negative value on failure.
-+ */
-+static int share_upd_bootinfo_to_q6(struct rproc *rproc)
-+{
-+      int ret;
-+      size_t size;
-+      u16 cnt = 0, version;
-+      void *ptr;
-+      struct q6_wcss *wcss = rproc->priv, *upd_wcss;
-+      struct rproc *upd_rproc;
-+      struct userpd_boot_info upd_bootinfo = {0};
-+      const struct firmware *fw;
-+
-+      ret = qcom_smem_alloc(REMOTE_PID, UPD_BOOT_INFO_SMEM_ID,
-+                            UPD_BOOT_INFO_SMEM_SIZE);
-+      if (ret && ret != -EEXIST) {
-+              dev_err(wcss->dev,
-+                      "failed to allocate q6 bootinfo smem segment\n");
-+              return ret;
-+      }
-+
-+      ptr = qcom_smem_get(REMOTE_PID, UPD_BOOT_INFO_SMEM_ID, &size);
-+      if (IS_ERR(ptr) || size != UPD_BOOT_INFO_SMEM_SIZE) {
-+              dev_err(wcss->dev,
-+                      "Unable to acquire smp2p item(%d) ret:%ld\n",
-+                      UPD_BOOT_INFO_SMEM_ID, PTR_ERR(ptr));
-+              return PTR_ERR(ptr);
-+      }
-+
-+      /*Version*/
-+      version = VERSION2;
-+      memcpy_toio(ptr, &version, sizeof(version));
-+      ptr += sizeof(version);
-+
-+      list_for_each_entry(upd_rproc, &upd_rproc_list, node)
-+              cnt++;
-+
-+      /* No of elements */
-+      cnt = (sizeof(upd_bootinfo) * cnt);
-+      memcpy_toio(ptr, &cnt, sizeof(u16));
-+      ptr += sizeof(u16);
-+
-+      list_for_each_entry(upd_rproc, &upd_rproc_list, node) {
-+              upd_wcss = upd_rproc->priv;
-+
-+              /* TYPE */
-+              upd_bootinfo.header.type = UPD_BOOT_INFO_HEADER_TYPE;
-+
-+              /* LENGTH */
-+              upd_bootinfo.header.length =
-+                      sizeof(upd_bootinfo) - sizeof(upd_bootinfo.header);
-+
-+              /* Process ID */
-+              upd_bootinfo.pid = upd_wcss->pd_asid + 1;
-+
-+              ret = request_firmware(&fw, upd_rproc->firmware, upd_wcss->dev);
-+              if (ret < 0) {
-+                      dev_err(upd_wcss->dev, "request_firmware failed: %d\n", ret);
-+                      return ret;
-+              }
-+
-+              /* Load address */
-+              upd_bootinfo.bootaddr = rproc_get_boot_addr(upd_rproc, fw);
-+
-+              /* Firmware mem size */
-+              upd_bootinfo.data_size = qcom_mdt_get_size(fw);
-+
-+              release_firmware(fw);
-+
-+              /* copy into smem */
-+              memcpy_toio(ptr, &upd_bootinfo, sizeof(upd_bootinfo));
-+              ptr += sizeof(upd_bootinfo);
-+      }
-+      return 0;
-+}
-+
-+static int q6_wcss_load(struct rproc *rproc, const struct firmware *fw)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      const struct firmware *fw_hdl;
-+      int ret;
-+      const struct wcss_data *desc = wcss->desc;
-+      int loop;
-+
-+      /* Share user pd boot info to Q6 remote processor */
-+      if (desc->share_upd_info_to_q6) {
-+              ret = share_upd_bootinfo_to_q6(rproc);
-+              if (ret) {
-+                      dev_err(wcss->dev,
-+                              "user pd boot info sharing with q6 failed %d\n",
-+                              ret);
-+                      return ret;
-+              }
-+      }
-+
-+      ret = qcom_mdt_load(wcss->dev, fw, rproc->firmware,
-+                          desc->pasid, wcss->mem_region,
-+                          wcss->mem_phys, wcss->mem_size,
-+                          &wcss->mem_reloc);
-+      if (ret)
-+              return ret;
-+
-+      for (loop = 1; loop < MAX_FIRMWARE; loop++) {
-+              if (!wcss->firmware[loop])
-+                      continue;
-+
-+              ret = request_firmware(&fw_hdl, wcss->firmware[loop],
-+                                     wcss->dev);
-+              if (ret)
-+                      continue;
-+
-+              ret = qcom_mdt_load_no_init(wcss->dev, fw_hdl,
-+                                          wcss->firmware[loop], 0,
-+                                          wcss->mem_region,
-+                                          wcss->mem_phys,
-+                                          wcss->mem_size,
-+                                          &wcss->mem_reloc);
-+
-+              release_firmware(fw_hdl);
-+
-+              if (ret) {
-+                      dev_err(wcss->dev,
-+                              "can't load %s ret:%d\n", wcss->firmware[loop], ret);
-+                      return ret;
-+              }
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * wcss_pd_load() - Load WCSS user pd firmware
-+ * @rproc:    rproc handle
-+ * @fw:               firmware handle
-+ *
-+ * User pd get services from root pd. So first
-+ * bring up root pd and then load userpd firmware.
-+ * ---------------------------------------------
-+ *
-+ *                            -----------
-+ *                 |-------->| User PD1 |
-+ *                 |          -----------
-+ *                 |
-+ *                 |
-+ *    -----        |          -----------
-+ *    | Q6 |---------------->| User Pd2 |
-+ *    -----        |          -----------
-+ *                 |
-+ *                 |
-+ *                 |          -----------
-+ *                 |--------->| User Pd3 |
-+ *                            -----------
-+ * ----------------------------------------------
-+ *
-+ */
-+static int wcss_pd_load(struct rproc *rproc, const struct firmware *fw)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+      struct rproc *rpd_rproc = dev_get_drvdata(wcss->dev->parent);
-+      u32 pasid = (wcss->pd_asid << 8) | UPD_SWID;
-+      int ret;
-+
-+      ret = rproc_boot(rpd_rproc);
-+      if (ret)
-+              return ret;
-+
-+      return qcom_mdt_load(wcss->dev, fw, rproc->firmware,
-+                           pasid, wcss->mem_region,
-+                           wcss->mem_phys, wcss->mem_size,
-+                           &wcss->mem_reloc);
-+}
-+
-+static unsigned long q6_wcss_panic(struct rproc *rproc)
-+{
-+      struct q6_wcss *wcss = rproc->priv;
-+
-+      return qcom_q6v5_panic(&wcss->q6);
-+}
-+
-+static const struct rproc_ops wcss_ops = {
-+      .start = wcss_pd_start,
-+      .stop = wcss_pd_stop,
-+      .load = wcss_pd_load,
-+      .get_boot_addr = rproc_elf_get_boot_addr,
-+};
-+
-+static const struct rproc_ops q6_wcss_ops = {
-+      .start = q6_wcss_start,
-+      .stop = q6_wcss_stop,
-+      .da_to_va = q6_wcss_da_to_va,
-+      .load = q6_wcss_load,
-+      .get_boot_addr = rproc_elf_get_boot_addr,
-+      .panic = q6_wcss_panic,
-+};
-+
-+static int q6_alloc_memory_region(struct q6_wcss *wcss)
-+{
-+      struct reserved_mem *rmem = NULL;
-+      struct device_node *node;
-+      struct device *dev = wcss->dev;
-+
-+      if (wcss->version == Q6_IPQ) {
-+              node = of_parse_phandle(dev->of_node, "memory-region", 0);
-+              if (node)
-+                      rmem = of_reserved_mem_lookup(node);
-+
-+              of_node_put(node);
-+
-+              if (!rmem) {
-+                      dev_err(dev, "unable to acquire memory-region\n");
-+                      return -EINVAL;
-+              }
-+      } else {
-+              struct rproc *rpd_rproc = dev_get_drvdata(dev->parent);
-+              struct q6_wcss *rpd_wcss = rpd_rproc->priv;
-+
-+              wcss->mem_phys = rpd_wcss->mem_phys;
-+              wcss->mem_reloc = rpd_wcss->mem_reloc;
-+              wcss->mem_size = rpd_wcss->mem_size;
-+              wcss->mem_region = rpd_wcss->mem_region;
-+              return 0;
-+      }
-+
-+      wcss->mem_phys = rmem->base;
-+      wcss->mem_reloc = rmem->base;
-+      wcss->mem_size = rmem->size;
-+      wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
-+      if (!wcss->mem_region) {
-+              dev_err(dev, "unable to map memory region: %pa+%pa\n",
-+                      &rmem->base, &rmem->size);
-+              return -EBUSY;
-+      }
-+
-+      return 0;
-+}
-+
-+static int q6_get_inbound_irq(struct qcom_q6v5 *q6,
-+                            struct platform_device *pdev,
-+                            const char *int_name,
-+                            int index, int *pirq,
-+                            irqreturn_t (*handler)(int irq, void *data))
-+{
-+      int ret, irq;
-+      char *interrupt, *tmp = (char *)int_name;
-+      struct q6_wcss *wcss = q6->rproc->priv;
-+
-+      irq = platform_get_irq(pdev, index);
-+      if (irq < 0)
-+              return irq;
-+
-+      *pirq = irq;
-+
-+      interrupt = devm_kzalloc(&pdev->dev, BUF_SIZE, GFP_KERNEL);
-+      if (!interrupt)
-+              return -ENOMEM;
-+
-+      snprintf(interrupt, BUF_SIZE, "q6v5_wcss_userpd%d_%s", wcss->pd_asid, tmp);
-+
-+      ret = devm_request_threaded_irq(&pdev->dev, *pirq,
-+                                      NULL, handler,
-+                                      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-+                                      interrupt, q6);
-+      if (ret)
-+              return dev_err_probe(&pdev->dev, ret,
-+                                   "failed to acquire %s irq\n", interrupt);
-+      return 0;
-+}
-+
-+static int q6_get_outbound_irq(struct qcom_q6v5 *q6,
-+                             struct platform_device *pdev,
-+                             const char *int_name)
-+{
-+      struct qcom_smem_state *tmp_state;
-+      unsigned  bit;
-+
-+      tmp_state = qcom_smem_state_get(&pdev->dev, int_name, &bit);
-+      if (IS_ERR(tmp_state))
-+              return dev_err_probe(&pdev->dev, PTR_ERR(tmp_state),
-+                                   "failed to acquire %s state\n", int_name);
-+
-+      if (!strcmp(int_name, "stop")) {
-+              q6->state = tmp_state;
-+              q6->stop_bit = bit;
-+      } else if (!strcmp(int_name, "spawn")) {
-+              q6->spawn_state = tmp_state;
-+              q6->spawn_bit = bit;
-+      }
-+
-+      return 0;
-+}
-+
-+static int init_irq(struct qcom_q6v5 *q6,
-+                  struct platform_device *pdev, struct rproc *rproc,
-+                  int crash_reason, const char *load_state,
-+                  void (*handover)(struct qcom_q6v5 *q6))
-+{
-+      int ret;
-+      struct q6_wcss *wcss = rproc->priv;
-+
-+      q6->rproc = rproc;
-+      q6->dev = &pdev->dev;
-+      q6->crash_reason = crash_reason;
-+      q6->handover = handover;
-+
-+      init_completion(&q6->start_done);
-+      init_completion(&q6->stop_done);
-+      init_completion(&q6->spawn_done);
-+
-+      ret = q6_get_outbound_irq(q6, pdev, "stop");
-+      if (ret)
-+              return ret;
-+
-+      ret = q6_get_outbound_irq(q6, pdev, "spawn");
-+      if (ret)
-+              return ret;
-+
-+      /* Get pd_asid to prepare interrupt names */
-+      wcss->pd_asid = qcom_get_pd_asid(rproc);
-+
-+      ret = q6_get_inbound_irq(q6, pdev, "fatal", 0, &q6->fatal_irq,
-+                               q6v5_fatal_interrupt);
-+      if (ret)
-+              return ret;
-+
-+      ret = q6_get_inbound_irq(q6, pdev, "ready", 1, &q6->ready_irq,
-+                               q6v5_ready_interrupt);
-+      if (ret)
-+              return ret;
-+
-+      ret = q6_get_inbound_irq(q6, pdev, "stop-ack", 3, &q6->stop_irq,
-+                               q6v5_stop_interrupt);
-+      if (ret)
-+              return ret;
-+
-+      ret = q6_get_inbound_irq(q6, pdev, "spawn-ack", 2, &q6->spawn_irq,
-+                               q6v5_spawn_interrupt);
-+      if (ret)
-+              return ret;
-+      return 0;
-+}
-+
-+static void q6_release_resources(void)
-+{
-+      struct rproc *upd_rproc;
-+
-+      /* Release userpd resources */
-+      list_for_each_entry(upd_rproc, &upd_rproc_list, node) {
-+              rproc_del(upd_rproc);
-+              rproc_free(upd_rproc);
-+      }
-+}
-+
-+static int q6_register_userpd(struct platform_device *pdev,
-+                            struct device_node *userpd_np)
-+{
-+      struct q6_wcss *wcss;
-+      struct rproc *rproc = NULL;
-+      int ret;
-+      struct platform_device *userpd_pdev;
-+      const char *firmware_name = NULL;
-+      const char *label = NULL;
-+
-+      ret = of_property_read_string(userpd_np, "firmware-name",
-+                                    &firmware_name);
-+      if (ret < 0) {
-+              /* All userpd's who want to register as rproc must have firmware.
-+               * Other than userpd like glink they don't need any firmware.
-+               * So for glink child simply return success.
-+               */
-+              if (ret == -EINVAL) {
-+                      /* Confirming userpd_np is glink node or not */
-+                      if (!of_property_read_string(userpd_np, "label", &label))
-+                              return 0;
-+              }
-+              return ret;
-+      }
-+
-+      dev_info(&pdev->dev, "%s node found\n", userpd_np->name);
-+
-+      userpd_pdev = of_platform_device_create(userpd_np, userpd_np->name,
-+                                              &pdev->dev);
-+      if (!userpd_pdev)
-+              return dev_err_probe(&pdev->dev, -ENODEV,
-+                                   "failed to create %s platform device\n",
-+                                   userpd_np->name);
-+
-+      userpd_pdev->dev.driver = pdev->dev.driver;
-+      rproc = rproc_alloc(&userpd_pdev->dev, userpd_pdev->name, &wcss_ops,
-+                          firmware_name, sizeof(*wcss));
-+      if (!rproc) {
-+              ret = -ENOMEM;
-+              goto free_rproc;
-+      }
-+
-+      wcss = rproc->priv;
-+      wcss->dev = &userpd_pdev->dev;
-+      wcss->version = WCSS_IPQ;
-+
-+      ret = q6_alloc_memory_region(wcss);
-+      if (ret)
-+              goto free_rproc;
-+
-+      ret = init_irq(&wcss->q6, userpd_pdev, rproc,
-+                     WCSS_CRASH_REASON, NULL, NULL);
-+      if (ret)
-+              goto free_rproc;
-+
-+      rproc->auto_boot = false;
-+      ret = rproc_add(rproc);
-+      if (ret)
-+              goto free_rproc;
-+
-+      list_add(&rproc->node, &upd_rproc_list);
-+      platform_set_drvdata(userpd_pdev, rproc);
-+      qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, userpd_pdev->name);
-+      return 0;
-+
-+free_rproc:
-+      kfree(rproc);
-+      return ret;
-+}
-+
-+static int q6_wcss_probe(struct platform_device *pdev)
-+{
-+      struct q6_wcss *wcss;
-+      struct rproc *rproc;
-+      int ret;
-+      const char **firmware;
-+      struct device_node *userpd_np;
-+      const struct rproc_ops *ops = &q6_wcss_ops;
-+
-+      firmware = devm_kcalloc(&pdev->dev, MAX_FIRMWARE,
-+                              sizeof(*firmware), GFP_KERNEL);
-+      if (!firmware)
-+              return -ENOMEM;
-+
-+      ret = of_property_read_string_array(pdev->dev.of_node, "firmware-name",
-+                                          firmware, MAX_FIRMWARE);
-+      if (ret < 0)
-+              return ret;
-+
-+      rproc = rproc_alloc(&pdev->dev, pdev->name, ops,
-+                          firmware[0], sizeof(*wcss));
-+      if (!rproc)
-+              return -ENOMEM;
-+
-+      wcss = rproc->priv;
-+      wcss->dev = &pdev->dev;
-+      wcss->desc = of_device_get_match_data(&pdev->dev);
-+      wcss->firmware = firmware;
-+      wcss->version = Q6_IPQ;
-+
-+      ret = q6_alloc_memory_region(wcss);
-+      if (ret)
-+              goto free_rproc;
-+
-+      ret = qcom_q6v5_init(&wcss->q6, pdev, rproc,
-+                           WCSS_CRASH_REASON, NULL, NULL);
-+      if (ret)
-+              goto free_rproc;
-+
-+      qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
-+      qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
-+
-+      rproc->auto_boot = false;
-+      ret = rproc_add(rproc);
-+      if (ret)
-+              goto free_rproc;
-+
-+      platform_set_drvdata(pdev, rproc);
-+
-+      /* Iterate over userpd child's and register with rproc */
-+      for_each_available_child_of_node(pdev->dev.of_node, userpd_np) {
-+              ret = q6_register_userpd(pdev, userpd_np);
-+              if (ret) {
-+                      /* release resources of successfully allocated userpd rproc's */
-+                      q6_release_resources();
-+                      return dev_err_probe(&pdev->dev, ret,
-+                                           "Failed to register userpd(%s)\n",
-+                                           userpd_np->name);
-+              }
-+      }
-+      return 0;
-+
-+free_rproc:
-+      rproc_free(rproc);
-+
-+      return ret;
-+}
-+
-+static void q6_wcss_remove(struct platform_device *pdev)
-+{
-+      struct rproc *rproc = platform_get_drvdata(pdev);
-+      struct q6_wcss *wcss = rproc->priv;
-+
-+      qcom_q6v5_deinit(&wcss->q6);
-+
-+      rproc_del(rproc);
-+      rproc_free(rproc);
-+}
-+
-+static const struct wcss_data q6_ipq5332_res_init = {
-+      .pasid = MPD_WCNSS_PAS_ID,
-+      .share_upd_info_to_q6 = true,
-+};
-+
-+static const struct wcss_data q6_ipq9574_res_init = {
-+      .pasid = WCNSS_PAS_ID,
-+};
-+
-+static const struct of_device_id q6_wcss_of_match[] = {
-+      { .compatible = "qcom,ipq5332-q6-mpd", .data = &q6_ipq5332_res_init },
-+      { .compatible = "qcom,ipq9574-q6-mpd", .data = &q6_ipq9574_res_init },
-+      { },
-+};
-+MODULE_DEVICE_TABLE(of, q6_wcss_of_match);
-+
-+static struct platform_driver q6_wcss_driver = {
-+      .probe = q6_wcss_probe,
-+      .remove_new = q6_wcss_remove,
-+      .driver = {
-+              .name = "qcom-q6-mpd",
-+              .of_match_table = q6_wcss_of_match,
-+      },
-+};
-+module_platform_driver(q6_wcss_driver);
-+
-+MODULE_DESCRIPTION("Hexagon WCSS Multipd Peripheral Image Loader");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/qualcommax/patches-6.12/0806-rproc-qcom_q6v5_mpd-split-q6_wcss-to-rootpd-and-user.patch b/target/linux/qualcommax/patches-6.12/0806-rproc-qcom_q6v5_mpd-split-q6_wcss-to-rootpd-and-user.patch
deleted file mode 100644 (file)
index 5f40358..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-From 6c66dff196cbba8515380110dd3599cde31dd896 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH 1/2] rproc: qcom_q6v5_mpd: split q6_wcss to rootpd and
- userpd
-
-Split the q6_wcss structure and create a separate userpd struct to clearly
-differentiate between the process to bring up the QDSP6 processor vs 
-process(es) to bring up the Wifi radio(s) (WCSS) for better readability.
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- drivers/remoteproc/qcom_q6v5_mpd.c | 126 +++++++++++++----------------
- 1 file changed, 56 insertions(+), 70 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_mpd.c
-+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
-@@ -45,10 +45,6 @@
- #define VERSION2                      2
- static LIST_HEAD(upd_rproc_list);
--enum {
--      Q6_IPQ,
--      WCSS_IPQ,
--};
- /**
-  * struct userpd_boot_info_header - header of user pd bootinfo
-@@ -83,10 +79,15 @@ struct q6_wcss {
-       phys_addr_t mem_reloc;
-       void *mem_region;
-       size_t mem_size;
--      u8 pd_asid;
-       const struct wcss_data *desc;
-       const char **firmware;
--      u32 version;
-+};
-+
-+struct userpd {
-+      u8 pd_asid;
-+      struct device *dev;
-+      struct qcom_rproc_ssr ssr_subdev;
-+      struct qcom_q6v5 q6;
- };
- struct wcss_data {
-@@ -102,8 +103,8 @@ struct wcss_data {
-  */
- static u8 qcom_get_pd_asid(struct rproc *rproc)
- {
--      struct q6_wcss *wcss = rproc->priv;
--      u8 bit = wcss->q6.spawn_bit;
-+      struct userpd *upd = rproc->priv;
-+      u8 bit = upd->q6.spawn_bit;
-       return bit / 8;
- }
-@@ -132,37 +133,37 @@ static int q6_wcss_start(struct rproc *r
- static int q6_wcss_spawn_pd(struct rproc *rproc)
- {
-       int ret;
--      struct q6_wcss *wcss = rproc->priv;
-+      struct userpd *upd = rproc->priv;
--      ret = qcom_q6v5_request_spawn(&wcss->q6);
-+      ret = qcom_q6v5_request_spawn(&upd->q6);
-       if (ret == -ETIMEDOUT) {
--              dev_err(wcss->dev, "%s spawn timedout\n", rproc->name);
-+              dev_err(upd->dev, "%s spawn timedout\n", rproc->name);
-               return ret;
-       }
--      ret = qcom_q6v5_wait_for_start(&wcss->q6, msecs_to_jiffies(10000));
-+      ret = qcom_q6v5_wait_for_start(&upd->q6, msecs_to_jiffies(10000));
-       if (ret == -ETIMEDOUT) {
--              dev_err(wcss->dev, "%s start timedout\n", rproc->name);
--              wcss->q6.running = false;
-+              dev_err(upd->dev, "%s start timedout\n", rproc->name);
-+              upd->q6.running = false;
-               return ret;
-       }
--      wcss->q6.running = true;
-+      upd->q6.running = true;
-       return ret;
- }
- static int wcss_pd_start(struct rproc *rproc)
- {
--      struct q6_wcss *wcss = rproc->priv;
--      u32 pasid = (wcss->pd_asid << 8) | UPD_SWID;
-+      struct userpd *upd = rproc->priv;
-+      u32 pasid = (upd->pd_asid << 8) | UPD_SWID;
-       int ret;
-       ret = qcom_scm_msa_lock(pasid);
-       if (ret) {
--              dev_err(wcss->dev, "failed to power up pd\n");
-+              dev_err(upd->dev, "failed to power up pd\n");
-               return ret;
-       }
--      if (wcss->q6.spawn_bit) {
-+      if (upd->q6.spawn_bit) {
-               ret = q6_wcss_spawn_pd(rproc);
-               if (ret)
-                       return ret;
-@@ -214,22 +215,22 @@ static int q6_wcss_stop(struct rproc *rp
-  */
- static int wcss_pd_stop(struct rproc *rproc)
- {
--      struct q6_wcss *wcss = rproc->priv;
--      struct rproc *rpd_rproc = dev_get_drvdata(wcss->dev->parent);
--      u32 pasid = (wcss->pd_asid << 8) | UPD_SWID;
-+      struct userpd *upd = rproc->priv;
-+      struct rproc *rpd_rproc = dev_get_drvdata(upd->dev->parent);
-+      u32 pasid = (upd->pd_asid << 8) | UPD_SWID;
-       int ret;
--      if (rproc->state != RPROC_CRASHED && wcss->q6.stop_bit) {
--              ret = qcom_q6v5_request_stop(&wcss->q6, NULL);
-+      if (rproc->state != RPROC_CRASHED && upd->q6.stop_bit) {
-+              ret = qcom_q6v5_request_stop(&upd->q6, NULL);
-               if (ret) {
--                      dev_err(&rproc->dev, "pd not stopped\n");
-+                      dev_err(upd->dev, "pd not stopped\n");
-                       return ret;
-               }
-       }
-       ret = qcom_scm_msa_unlock(pasid);
-       if (ret) {
--              dev_err(wcss->dev, "failed to power down pd\n");
-+              dev_err(upd->dev, "failed to power down pd\n");
-               return ret;
-       }
-@@ -274,7 +275,8 @@ static int share_upd_bootinfo_to_q6(stru
-       size_t size;
-       u16 cnt = 0, version;
-       void *ptr;
--      struct q6_wcss *wcss = rproc->priv, *upd_wcss;
-+      struct q6_wcss *wcss = rproc->priv;
-+      struct userpd *upd;
-       struct rproc *upd_rproc;
-       struct userpd_boot_info upd_bootinfo = {0};
-       const struct firmware *fw;
-@@ -309,7 +311,7 @@ static int share_upd_bootinfo_to_q6(stru
-       ptr += sizeof(u16);
-       list_for_each_entry(upd_rproc, &upd_rproc_list, node) {
--              upd_wcss = upd_rproc->priv;
-+              upd = upd_rproc->priv;
-               /* TYPE */
-               upd_bootinfo.header.type = UPD_BOOT_INFO_HEADER_TYPE;
-@@ -319,11 +321,11 @@ static int share_upd_bootinfo_to_q6(stru
-                       sizeof(upd_bootinfo) - sizeof(upd_bootinfo.header);
-               /* Process ID */
--              upd_bootinfo.pid = upd_wcss->pd_asid + 1;
-+              upd_bootinfo.pid = upd->pd_asid + 1;
--              ret = request_firmware(&fw, upd_rproc->firmware, upd_wcss->dev);
-+              ret = request_firmware(&fw, upd_rproc->firmware, upd->dev);
-               if (ret < 0) {
--                      dev_err(upd_wcss->dev, "request_firmware failed: %d\n", ret);
-+                      dev_err(upd->dev, "request_firmware failed: %d\n",      ret);
-                       return ret;
-               }
-@@ -422,19 +424,20 @@ static int q6_wcss_load(struct rproc *rp
-  */
- static int wcss_pd_load(struct rproc *rproc, const struct firmware *fw)
- {
--      struct q6_wcss *wcss = rproc->priv;
--      struct rproc *rpd_rproc = dev_get_drvdata(wcss->dev->parent);
--      u32 pasid = (wcss->pd_asid << 8) | UPD_SWID;
-+      struct userpd *upd = rproc->priv;
-+      struct rproc *rpd_rproc = dev_get_drvdata(upd->dev->parent);
-+      struct q6_wcss *wcss = rpd_rproc->priv;
-+      u32 pasid = (upd->pd_asid << 8) | UPD_SWID;
-       int ret;
-       ret = rproc_boot(rpd_rproc);
-       if (ret)
-               return ret;
--      return qcom_mdt_load(wcss->dev, fw, rproc->firmware,
-+      return qcom_mdt_load(upd->dev, fw, rproc->firmware,
-                            pasid, wcss->mem_region,
-                            wcss->mem_phys, wcss->mem_size,
--                           &wcss->mem_reloc);
-+                           NULL);
- }
- static unsigned long q6_wcss_panic(struct rproc *rproc)
-@@ -466,26 +469,15 @@ static int q6_alloc_memory_region(struct
-       struct device_node *node;
-       struct device *dev = wcss->dev;
--      if (wcss->version == Q6_IPQ) {
--              node = of_parse_phandle(dev->of_node, "memory-region", 0);
--              if (node)
--                      rmem = of_reserved_mem_lookup(node);
--
--              of_node_put(node);
--
--              if (!rmem) {
--                      dev_err(dev, "unable to acquire memory-region\n");
--                      return -EINVAL;
--              }
--      } else {
--              struct rproc *rpd_rproc = dev_get_drvdata(dev->parent);
--              struct q6_wcss *rpd_wcss = rpd_rproc->priv;
--
--              wcss->mem_phys = rpd_wcss->mem_phys;
--              wcss->mem_reloc = rpd_wcss->mem_reloc;
--              wcss->mem_size = rpd_wcss->mem_size;
--              wcss->mem_region = rpd_wcss->mem_region;
--              return 0;
-+      node = of_parse_phandle(dev->of_node, "memory-region", 0);
-+      if (node)
-+              rmem = of_reserved_mem_lookup(node);
-+
-+      of_node_put(node);
-+
-+      if (!rmem) {
-+              dev_err(dev, "unable to acquire memory-region\n");
-+              return -EINVAL;
-       }
-       wcss->mem_phys = rmem->base;
-@@ -509,7 +501,7 @@ static int q6_get_inbound_irq(struct qco
- {
-       int ret, irq;
-       char *interrupt, *tmp = (char *)int_name;
--      struct q6_wcss *wcss = q6->rproc->priv;
-+      struct userpd *upd = q6->rproc->priv;
-       irq = platform_get_irq(pdev, index);
-       if (irq < 0)
-@@ -521,7 +513,7 @@ static int q6_get_inbound_irq(struct qco
-       if (!interrupt)
-               return -ENOMEM;
--      snprintf(interrupt, BUF_SIZE, "q6v5_wcss_userpd%d_%s", wcss->pd_asid, tmp);
-+      snprintf(interrupt, BUF_SIZE, "q6v5_wcss_userpd%d_%s", upd->pd_asid, tmp);
-       ret = devm_request_threaded_irq(&pdev->dev, *pirq,
-                                       NULL, handler,
-@@ -562,7 +554,7 @@ static int init_irq(struct qcom_q6v5 *q6
-                   void (*handover)(struct qcom_q6v5 *q6))
- {
-       int ret;
--      struct q6_wcss *wcss = rproc->priv;
-+      struct userpd *upd = rproc->priv;
-       q6->rproc = rproc;
-       q6->dev = &pdev->dev;
-@@ -582,7 +574,7 @@ static int init_irq(struct qcom_q6v5 *q6
-               return ret;
-       /* Get pd_asid to prepare interrupt names */
--      wcss->pd_asid = qcom_get_pd_asid(rproc);
-+      upd->pd_asid = qcom_get_pd_asid(rproc);
-       ret = q6_get_inbound_irq(q6, pdev, "fatal", 0, &q6->fatal_irq,
-                                q6v5_fatal_interrupt);
-@@ -620,7 +612,7 @@ static void q6_release_resources(void)
- static int q6_register_userpd(struct platform_device *pdev,
-                             struct device_node *userpd_np)
- {
--      struct q6_wcss *wcss;
-+      struct userpd *upd;
-       struct rproc *rproc = NULL;
-       int ret;
-       struct platform_device *userpd_pdev;
-@@ -653,21 +645,16 @@ static int q6_register_userpd(struct pla
-       userpd_pdev->dev.driver = pdev->dev.driver;
-       rproc = rproc_alloc(&userpd_pdev->dev, userpd_pdev->name, &wcss_ops,
--                          firmware_name, sizeof(*wcss));
-+                          firmware_name, sizeof(*upd));
-       if (!rproc) {
-               ret = -ENOMEM;
-               goto free_rproc;
-       }
--      wcss = rproc->priv;
--      wcss->dev = &userpd_pdev->dev;
--      wcss->version = WCSS_IPQ;
--
--      ret = q6_alloc_memory_region(wcss);
--      if (ret)
--              goto free_rproc;
-+      upd = rproc->priv;
-+      upd->dev = &userpd_pdev->dev;
--      ret = init_irq(&wcss->q6, userpd_pdev, rproc,
-+      ret = init_irq(&upd->q6, userpd_pdev, rproc,
-                      WCSS_CRASH_REASON, NULL, NULL);
-       if (ret)
-               goto free_rproc;
-@@ -679,7 +666,7 @@ static int q6_register_userpd(struct pla
-       list_add(&rproc->node, &upd_rproc_list);
-       platform_set_drvdata(userpd_pdev, rproc);
--      qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, userpd_pdev->name);
-+      qcom_add_ssr_subdev(rproc, &upd->ssr_subdev, userpd_pdev->name);
-       return 0;
- free_rproc:
-@@ -715,7 +702,6 @@ static int q6_wcss_probe(struct platform
-       wcss->dev = &pdev->dev;
-       wcss->desc = of_device_get_match_data(&pdev->dev);
-       wcss->firmware = firmware;
--      wcss->version = Q6_IPQ;
-       ret = q6_alloc_memory_region(wcss);
-       if (ret)
diff --git a/target/linux/qualcommax/patches-6.12/0807-remoteproc-qcom_q6v5_mpd-fix-incorrent-use-of-rproc-.patch b/target/linux/qualcommax/patches-6.12/0807-remoteproc-qcom_q6v5_mpd-fix-incorrent-use-of-rproc-.patch
deleted file mode 100644 (file)
index cd73dd0..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-From 0fa7bdb855247b738d1d227d6f4b3417ebdf21a8 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH 2/2] remoteproc: qcom_q6v5_mpd: fix incorrent use of
- rproc->node
-
-    1.817524] list_add corruption. next->prev should be prev (ffffffc0814bbfc8), but was ffffffc0814bc358. (next=ffffff8003b56800).
-[    1.822435] WARNING: CPU: 1 PID: 24 at lib/list_debug.c:29 __list_add_valid_or_report+0x8c/0xdc
-[    1.833923] Modules linked in:
-[    1.842425] CPU: 1 PID: 24 Comm: kworker/u4:1 Not tainted 6.6.47 #0
-[    1.845552] Hardware name: Qualcomm MP03 (DT)
-[    1.851716] Workqueue: events_unbound deferred_probe_work_func
-[    1.856229] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
-[    1.861959] pc : __list_add_valid_or_report+0x8c/0xdc
-[    1.868816] lr : __list_add_valid_or_report+0x8c/0xdc
-[    1.874022] sp : ffffffc081603a50
-[    1.879055] x29: ffffffc081603a50 x28: ffffff8000fa2810 x27: ffffff8003cba800
-[    1.882358] x26: ffffff8000fa2800 x25: ffffff8003cbac80 x24: 0000000000000000
-[    1.889476] x23: ffffffc08088b968 x22: ffffffc0814bb000 x21: ffffffc0814bbfc8
-[    1.896593] x20: ffffffc08088b8e8 x19: ffffff8003cba800 x18: 00000000000000b1
-[    1.903713] x17: 3863666262343138 x16: 3063666666666666 x15: ffffffc081416e20
-[    1.910830] x14: 0000000000000213 x13: 00000000000000b1 x12: 00000000ffffffea
-[    1.917948] x11: 00000000ffffefff x10: ffffffc08146ee20 x9 : ffffffc081416dc8
-[    1.925066] x8 : 0000000000017fe8 x7 : c0000000ffffefff x6 : 0000000000057fa8
-[    1.932184] x5 : 0000000000000fff x4 : 0000000000000000 x3 : ffffffc081603850
-[    1.939302] x2 : ffffffc081416d60 x1 : ffffffc081416d60 x0 : 0000000000000075
-[    1.946422] Call trace:
-[    1.953535]  __list_add_valid_or_report+0x8c/0xdc
-[    1.955793]  rproc_add+0x1f4/0x25c
-[    1.960653]  q6_wcss_probe+0x510/0x634
-[    1.963950]  platform_probe+0x68/0xc4
-[    1.967684]  really_probe+0x148/0x2b0
-[    1.971417]  __driver_probe_device+0x78/0x128
-[    1.975063]  driver_probe_device+0x40/0xdc
-[    1.979402]  __device_attach_driver+0xb8/0xf8
-[    1.983397]  bus_for_each_drv+0x70/0xb8
-[    1.987823]  __device_attach+0xa0/0x184
-[    1.991468]  device_initial_probe+0x14/0x20
-[    1.995289]  bus_probe_device+0xac/0xb0
-[    1.999455]  deferred_probe_work_func+0xa4/0xec
-[    2.003275]  process_one_work+0x178/0x2d4
-[    2.007788]  worker_thread+0x2ec/0x4d8
-[    2.011954]  kthread+0xdc/0xe0
-[    2.015600]  ret_from_fork+0x10/0x20
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- drivers/remoteproc/qcom_q6v5_mpd.c | 53 +++++++++++++++++-------------
- 1 file changed, 30 insertions(+), 23 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_mpd.c
-+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
-@@ -34,6 +34,7 @@
- #define BUF_SIZE                      35
-+#define MAX_UPD                               3
- #define MAX_FIRMWARE                  3
- #define RPD_SWID              MPD_WCNSS_PAS_ID
-@@ -44,8 +45,6 @@
- #define UPD_BOOT_INFO_SMEM_ID         507
- #define VERSION2                      2
--static LIST_HEAD(upd_rproc_list);
--
- /**
-  * struct userpd_boot_info_header - header of user pd bootinfo
-  * @type:             type of bootinfo passing over smem
-@@ -81,6 +80,7 @@ struct q6_wcss {
-       size_t mem_size;
-       const struct wcss_data *desc;
-       const char **firmware;
-+      struct userpd *upd[MAX_UPD];
- };
- struct userpd {
-@@ -271,13 +271,12 @@ static void *q6_wcss_da_to_va(struct rpr
-  */
- static int share_upd_bootinfo_to_q6(struct rproc *rproc)
- {
--      int ret;
-+      int i, ret;
-       size_t size;
-       u16 cnt = 0, version;
-       void *ptr;
-       struct q6_wcss *wcss = rproc->priv;
-       struct userpd *upd;
--      struct rproc *upd_rproc;
-       struct userpd_boot_info upd_bootinfo = {0};
-       const struct firmware *fw;
-@@ -302,16 +301,19 @@ static int share_upd_bootinfo_to_q6(stru
-       memcpy_toio(ptr, &version, sizeof(version));
-       ptr += sizeof(version);
--      list_for_each_entry(upd_rproc, &upd_rproc_list, node)
--              cnt++;
-+      for (i = 0; i < ARRAY_SIZE(wcss->upd); i++)
-+              if (wcss->upd[i])
-+                      cnt++;
-       /* No of elements */
-       cnt = (sizeof(upd_bootinfo) * cnt);
-       memcpy_toio(ptr, &cnt, sizeof(u16));
-       ptr += sizeof(u16);
--      list_for_each_entry(upd_rproc, &upd_rproc_list, node) {
--              upd = upd_rproc->priv;
-+      for (i = 0; i < ARRAY_SIZE(wcss->upd); i++) {
-+              upd = wcss->upd[i];
-+              if (!upd)
-+                      continue;
-               /* TYPE */
-               upd_bootinfo.header.type = UPD_BOOT_INFO_HEADER_TYPE;
-@@ -323,14 +325,14 @@ static int share_upd_bootinfo_to_q6(stru
-               /* Process ID */
-               upd_bootinfo.pid = upd->pd_asid + 1;
--              ret = request_firmware(&fw, upd_rproc->firmware, upd->dev);
-+              ret = request_firmware(&fw, upd->q6.rproc->firmware, upd->dev);
-               if (ret < 0) {
-                       dev_err(upd->dev, "request_firmware failed: %d\n",      ret);
-                       return ret;
-               }
-               /* Load address */
--              upd_bootinfo.bootaddr = rproc_get_boot_addr(upd_rproc, fw);
-+              upd_bootinfo.bootaddr = rproc_get_boot_addr(upd->q6.rproc, fw);
-               /* Firmware mem size */
-               upd_bootinfo.data_size = qcom_mdt_get_size(fw);
-@@ -598,18 +600,23 @@ static int init_irq(struct qcom_q6v5 *q6
-       return 0;
- }
--static void q6_release_resources(void)
-+static void q6_release_resources(struct q6_wcss *wcss)
- {
--      struct rproc *upd_rproc;
-+      struct userpd *upd;
-+      int i;
-       /* Release userpd resources */
--      list_for_each_entry(upd_rproc, &upd_rproc_list, node) {
--              rproc_del(upd_rproc);
--              rproc_free(upd_rproc);
-+      for (i = 0; i < ARRAY_SIZE(wcss->upd); i++) {
-+              upd = wcss->upd[i];
-+              if (!upd)
-+                      continue;
-+
-+              rproc_del(upd->q6.rproc);
-+              rproc_free(upd->q6.rproc);
-       }
- }
--static int q6_register_userpd(struct platform_device *pdev,
-+static int q6_register_userpd(struct q6_wcss *wcss,
-                             struct device_node *userpd_np)
- {
-       struct userpd *upd;
-@@ -634,16 +641,16 @@ static int q6_register_userpd(struct pla
-               return ret;
-       }
--      dev_info(&pdev->dev, "%s node found\n", userpd_np->name);
-+      dev_info(wcss->dev, "%s node found\n", userpd_np->name);
-       userpd_pdev = of_platform_device_create(userpd_np, userpd_np->name,
--                                              &pdev->dev);
-+                                              wcss->dev);
-       if (!userpd_pdev)
--              return dev_err_probe(&pdev->dev, -ENODEV,
-+              return dev_err_probe(wcss->dev, -ENODEV,
-                                    "failed to create %s platform device\n",
-                                    userpd_np->name);
--      userpd_pdev->dev.driver = pdev->dev.driver;
-+      userpd_pdev->dev.driver = wcss->dev->driver;
-       rproc = rproc_alloc(&userpd_pdev->dev, userpd_pdev->name, &wcss_ops,
-                           firmware_name, sizeof(*upd));
-       if (!rproc) {
-@@ -664,7 +671,7 @@ static int q6_register_userpd(struct pla
-       if (ret)
-               goto free_rproc;
--      list_add(&rproc->node, &upd_rproc_list);
-+      wcss->upd[upd->pd_asid] = upd;
-       platform_set_drvdata(userpd_pdev, rproc);
-       qcom_add_ssr_subdev(rproc, &upd->ssr_subdev, userpd_pdev->name);
-       return 0;
-@@ -724,10 +731,10 @@ static int q6_wcss_probe(struct platform
-       /* Iterate over userpd child's and register with rproc */
-       for_each_available_child_of_node(pdev->dev.of_node, userpd_np) {
--              ret = q6_register_userpd(pdev, userpd_np);
-+              ret = q6_register_userpd(wcss, userpd_np);
-               if (ret) {
-                       /* release resources of successfully allocated userpd rproc's */
--                      q6_release_resources();
-+                      q6_release_resources(wcss);
-                       return dev_err_probe(&pdev->dev, ret,
-                                            "Failed to register userpd(%s)\n",
-                                            userpd_np->name);
diff --git a/target/linux/qualcommax/patches-6.12/0808-remoteproc-qcom-wcss-sec-add-split-firmware-support.patch b/target/linux/qualcommax/patches-6.12/0808-remoteproc-qcom-wcss-sec-add-split-firmware-support.patch
deleted file mode 100644 (file)
index 29644e3..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Tue, 21 Oct 2025 15:26:31 +0400
-Subject: [PATCH] remoteproc: qcom: wcss-sec: add split firmware support
-
-The driver currently expects only one firmware file to be loaded as part
-of bringing up WCSS. For IPQ5018 and QCN6122, multiple firmware files are
-required, both the q6 and m3 firmware files. As such, add support for
-loading up to 3 firmware files.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
---- a/drivers/remoteproc/qcom_q6v5_wcss_sec.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss_sec.c
-@@ -25,6 +25,8 @@
- #define Q6_WAIT_TIMEOUT                       (5 * HZ)
-+#define MAX_FIRMWARE                  3
-+
- struct wcss_sec {
-       struct device *dev;
-       struct qcom_rproc_glink glink_subdev;
-@@ -35,6 +37,7 @@ struct wcss_sec {
-       void *mem_region;
-       size_t mem_size;
-       const struct wcss_data *desc;
-+      const char **firmware;
-       struct mbox_client mbox_client;
-       struct mbox_chan *mbox_chan;
-@@ -137,7 +140,8 @@ static int wcss_sec_load(struct rproc *r
- {
-       struct wcss_sec *wcss = rproc->priv;
-       struct device *dev = wcss->dev;
--      int ret;
-+      const struct firmware *fw_hdl;
-+      int i, ret;
-       if (wcss->desc->use_tmelcom) {
-               wcss->metadata = qcom_mdt_read_metadata(fw, &wcss->metadata_len,
-@@ -161,6 +165,28 @@ static int wcss_sec_load(struct rproc *r
-                                   wcss->mem_phys, wcss->mem_size, &wcss->mem_reloc);
-               if (ret)
-                       return ret;
-+
-+              for (i = 1; i < MAX_FIRMWARE; i++) {
-+                      if (!wcss->firmware[i])
-+                              continue;
-+
-+                      ret = request_firmware(&fw_hdl, wcss->firmware[i], dev);
-+
-+                      if (ret)
-+                              continue;
-+
-+                      ret = qcom_mdt_load_no_init(dev, fw_hdl, wcss->firmware[i], 0,
-+                                                  wcss->mem_region, wcss->mem_phys,
-+                                                  wcss->mem_size, &wcss->mem_reloc);
-+
-+                      release_firmware(fw_hdl);
-+
-+                      if (ret) {
-+                              dev_err(dev, "error %d loading firmware %s\n",
-+                                      ret, wcss->firmware[i]);
-+                              return ret;
-+                      }
-+              }
-       }
-       qcom_pil_info_store("wcss", wcss->mem_phys, wcss->mem_size);
-@@ -291,17 +317,20 @@ static int wcss_sec_probe(struct platfor
-       struct wcss_sec *wcss;
-       struct clk *sleep_clk;
-       struct clk *int_clk;
--      const char *fw_name = NULL;
-+      const char **firmware = NULL;
-       const struct wcss_data *desc = of_device_get_match_data(&pdev->dev);
-       int ret;
--      ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
--                                    &fw_name);
-+      firmware = devm_kcalloc(&pdev->dev, MAX_FIRMWARE,
-+                              sizeof(*firmware), GFP_KERNEL);
-+
-+      ret = of_property_read_string_array(pdev->dev.of_node, "firmware-name",
-+                                          firmware, MAX_FIRMWARE);
-       if (ret < 0)
-               return ret;
-       rproc = devm_rproc_alloc(&pdev->dev, desc->ss_name, &wcss_sec_ops,
--                               fw_name, sizeof(*wcss));
-+                               firmware[0], sizeof(*wcss));
-       if (!rproc) {
-               dev_err(&pdev->dev, "failed to allocate rproc\n");
-               return -ENOMEM;
-@@ -310,6 +339,7 @@ static int wcss_sec_probe(struct platfor
-       wcss = rproc->priv;
-       wcss->dev = &pdev->dev;
-       wcss->desc = desc;
-+      wcss->firmware = firmware;
-       ret = wcss_sec_alloc_memory_region(wcss);
-       if (ret)
diff --git a/target/linux/qualcommax/patches-6.12/0811-firmware-qcom_scm-support-MPD.patch b/target/linux/qualcommax/patches-6.12/0811-firmware-qcom_scm-support-MPD.patch
deleted file mode 100644 (file)
index 760f76c..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-From 6553d598cdb507f7ede020f25da646ba084a23c6 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH] firmware: qcom_scm: support MPD
-
-Add SCM calls to power up / down the SoC's internal WiFi radio and to 
-load PIL segments to support the MPD architecture.
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- drivers/firmware/qcom//qcom_scm.c            | 79 ++++++++++++++++++++++++++
- drivers/firmware/qcom//qcom_scm.h            |  3 +
- include/linux/firmware/qcom/qcom_scm.h |  3 +
- 3 files changed, 85 insertions(+)
-
---- a/include/linux/firmware/qcom/qcom_scm.h
-+++ b/include/linux/firmware/qcom/qcom_scm.h
-@@ -79,6 +79,9 @@ int qcom_scm_pas_mem_setup(u32 periphera
- int qcom_scm_pas_auth_and_reset(u32 peripheral);
- int qcom_scm_pas_shutdown(u32 peripheral);
- bool qcom_scm_pas_supported(u32 peripheral);
-+int qcom_scm_internal_wifi_powerup(u32 peripheral);
-+int qcom_scm_internal_wifi_shutdown(u32 peripheral);
-+int qcom_scm_pas_load_segment(u32 peripheral, int segment, dma_addr_t dma, int seg_cnt);
- int qcom_scm_msa_lock(u32 peripheral);
- int qcom_scm_msa_unlock(u32 peripheral);
---- a/drivers/firmware/qcom/qcom_scm.c
-+++ b/drivers/firmware/qcom/qcom_scm.c
-@@ -808,6 +808,85 @@ bool qcom_scm_pas_supported(u32 peripher
- EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
- /**
-+ * qcom_scm_internal_wifi_powerup() - Bring up internal wifi
-+ * @peripheral:       peripheral id
-+ *
-+ * Return 0 on success.
-+ */
-+int qcom_scm_internal_wifi_powerup(u32 peripheral)
-+{
-+      struct qcom_scm_desc desc = {
-+              .svc = QCOM_SCM_SVC_PIL,
-+              .cmd = QCOM_SCM_INTERNAL_WIFI_POWERUP,
-+              .arginfo = QCOM_SCM_ARGS(1),
-+              .args[0] = peripheral,
-+              .owner = ARM_SMCCC_OWNER_SIP,
-+      };
-+      struct qcom_scm_res res;
-+      int ret;
-+
-+      ret = qcom_scm_call(__scm->dev, &desc, &res);
-+
-+      return ret ? : res.result[0];
-+}
-+EXPORT_SYMBOL(qcom_scm_internal_wifi_powerup);
-+
-+/**
-+ * qcom_scm_internal_wifi_shutdown() - Shut down internal wifi
-+ * @peripheral: peripheral id
-+ *
-+ * Returns 0 on success.
-+ */
-+int qcom_scm_internal_wifi_shutdown(u32 peripheral)
-+{
-+      struct qcom_scm_desc desc = {
-+              .svc = QCOM_SCM_SVC_PIL,
-+              .cmd = QCOM_SCM_INTERNAL_WIFI_SHUTDOWN,
-+              .arginfo = QCOM_SCM_ARGS(1),
-+              .args[0] = peripheral,
-+              .owner = ARM_SMCCC_OWNER_SIP,
-+      };
-+      struct qcom_scm_res res;
-+      int ret;
-+
-+      ret = qcom_scm_call(__scm->dev, &desc, &res);
-+
-+      return ret ? : res.result[0];
-+}
-+EXPORT_SYMBOL(qcom_scm_internal_wifi_shutdown);
-+
-+/**
-+ * qcom_scm_pas_load_segment() - copy userpd PIL segments data to dma blocks
-+ * @peripheral:               peripheral id
-+ * @segment:          segment id
-+ * @dma:              handle of dma region
-+ * @seg_cnt:          no of dma blocks
-+ *
-+ * Returns 0 if trustzone successfully loads userpd PIL segments from dma
-+ * blocks to DDR
-+ */
-+int qcom_scm_pas_load_segment(u32 peripheral, int segment, dma_addr_t dma, int seg_cnt)
-+{
-+      struct qcom_scm_desc desc = {
-+              .svc = QCOM_SCM_SVC_PIL,
-+              .cmd = QCOM_SCM_PIL_PAS_LOAD_SEG,
-+              .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_VAL, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL),
-+              .args[0] = peripheral,
-+              .args[1] = segment,
-+              .args[2] = dma,
-+              .args[3] = seg_cnt,
-+              .owner = ARM_SMCCC_OWNER_SIP,
-+      };
-+      struct qcom_scm_res res;
-+      int ret;
-+
-+      ret = qcom_scm_call(__scm->dev, &desc, &res);
-+
-+      return ret ? : res.result[0];
-+}
-+EXPORT_SYMBOL(qcom_scm_pas_load_segment);
-+
-+/**
-  * qcom_scm_msa_lock() - Lock given peripheral firmware region as MSA
-  *
-  * @peripheral:       peripheral id
---- a/drivers/firmware/qcom/qcom_scm.h
-+++ b/drivers/firmware/qcom/qcom_scm.h
-@@ -102,6 +102,9 @@ struct qcom_tzmem_pool *qcom_scm_get_tzm
- #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
- #define QCOM_SCM_PIL_PAS_MSS_RESET    0x0a
- #define QCOM_SCM_PIL_PAS_INIT_IMAGE_V2        0x1a
-+#define QCOM_SCM_INTERNAL_WIFI_POWERUP        0x17
-+#define QCOM_SCM_INTERNAL_WIFI_SHUTDOWN       0x18
-+#define QCOM_SCM_PIL_PAS_LOAD_SEG     0x19
- #define QCOM_SCM_MSA_LOCK             0x24
- #define QCOM_SCM_MSA_UNLOCK           0x25
diff --git a/target/linux/qualcommax/patches-6.12/0812-soc-qcom-mdt_loader-support-MPD.patch b/target/linux/qualcommax/patches-6.12/0812-soc-qcom-mdt_loader-support-MPD.patch
deleted file mode 100644 (file)
index c8d5019..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-From bf42d84868bc82a9cb334a33930f2d1da24f7070 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH] soc: qcom: mdt_loader: support MPD
-
-Add support for loading user PD specific PIL segments as required by the 
-MPD architecture.
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- drivers/soc/qcom/mdt_loader.c       | 110 ++++++++++++++++++++++++++--
- include/linux/soc/qcom/mdt_loader.h |   5 ++
- 2 files changed, 110 insertions(+), 5 deletions(-)
-
---- a/drivers/soc/qcom/mdt_loader.c
-+++ b/drivers/soc/qcom/mdt_loader.c
-@@ -17,6 +17,16 @@
- #include <linux/sizes.h>
- #include <linux/slab.h>
- #include <linux/soc/qcom/mdt_loader.h>
-+#include <linux/dma-mapping.h>
-+
-+#include "../../remoteproc/qcom_common.h"
-+
-+#define QCOM_MDT_PF_ASID_MASK GENMASK(19, 16)
-+
-+struct segment_load_args {
-+      __le64 addr;
-+      __le64 blk_size;
-+};
- static bool mdt_header_valid(const struct firmware *fw)
- {
-@@ -100,6 +110,56 @@ static ssize_t mdt_load_split_segment(vo
-       return ret;
- }
-+static int mdt_load_split_segment_dma(int pas_id, unsigned int segment,
-+                                    const struct elf32_phdr *phdrs,
-+                                    const char *fw_name,
-+                                    struct device *dev)
-+{
-+      const struct elf32_phdr *phdr = &phdrs[segment];
-+      struct segment_load_args *args;
-+      dma_addr_t *addrs;
-+      void *ptr;
-+      dma_addr_t dma_args, dma_addrs, dma_ptr;
-+      int ret;
-+
-+      args = dma_alloc_coherent(dev, sizeof(*args) + sizeof(*addrs), &dma_args, GFP_DMA);
-+      if (!args) {
-+              dev_err(dev, "Error in dma alloc regin: %ld\n", sizeof(*args));
-+              return -ENOMEM;
-+      }
-+
-+      addrs = (void *) args + sizeof(*args);
-+      dma_addrs = dma_args + sizeof(*args);
-+
-+      ptr = dma_alloc_coherent(dev, phdr->p_filesz, &dma_ptr, GFP_DMA);
-+      if (!ptr) {
-+              dev_err(dev, "Error in dma alloc ptr: %d\n", phdr->p_filesz);
-+              return -ENOMEM;
-+      }
-+
-+      args->addr = dma_addrs;
-+      args->blk_size = phdr->p_filesz;
-+
-+      addrs[0] = dma_ptr;
-+
-+      ret = mdt_load_split_segment(ptr, phdrs, segment, fw_name, dev);
-+      if (ret < 0) {
-+              dev_err(dev, "Error in mdt_load_split_segment: %d\n", ret);
-+              return ret;
-+      }
-+
-+      ret = qcom_scm_pas_load_segment(pas_id, segment, dma_args, 1);
-+      if (ret < 0) {
-+              dev_err(dev, "Error in qcom_scm_pas_load_segment: %d\n", ret);
-+              return ret;
-+      }
-+
-+      dma_free_coherent(dev, phdr->p_filesz, ptr, dma_ptr);
-+      dma_free_coherent(dev, sizeof(*args) + sizeof(*addrs), args, dma_args);
-+
-+      return 0;
-+}
-+
- /**
-  * qcom_mdt_get_size() - acquire size of the memory region needed to load mdt
-  * @fw:               firmware object for the mdt file
-@@ -335,7 +395,8 @@ static bool qcom_mdt_bins_are_split(cons
- static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
-                          const char *fw_name, int pas_id, void *mem_region,
-                          phys_addr_t mem_phys, size_t mem_size,
--                         phys_addr_t *reloc_base, bool pas_init)
-+                         phys_addr_t *reloc_base, bool pas_init,
-+                         bool dma_require, int pd_asid)
- {
-       const struct elf32_phdr *phdrs;
-       const struct elf32_phdr *phdr;
-@@ -392,6 +453,14 @@ static int __qcom_mdt_load(struct device
-               if (!mdt_phdr_valid(phdr))
-                       continue;
-+              /*
-+               * While doing PD specific reloading, load only that PD
-+               * specific writeable entries. Skip others
-+               */
-+              if (pd_asid && (FIELD_GET(QCOM_MDT_PF_ASID_MASK, phdr->p_flags) != pd_asid ||
-+                              (phdr->p_flags & PF_W) == 0))
-+                      continue;
-+
-               offset = phdr->p_paddr - mem_reloc;
-               if (offset < 0 || offset + phdr->p_memsz > mem_size) {
-                       dev_err(dev, "segment outside memory range\n");
-@@ -409,7 +478,11 @@ static int __qcom_mdt_load(struct device
-               ptr = mem_region + offset;
--              if (phdr->p_filesz && !is_split) {
-+              if (dma_require && phdr->p_filesz) {
-+                      ret = mdt_load_split_segment_dma(pas_id, i, phdrs, fw_name, dev);
-+                      if (ret)
-+                              break;
-+              } else if (phdr->p_filesz && !is_split) {
-                       /* Firmware is large enough to be non-split */
-                       if (phdr->p_offset + phdr->p_filesz > fw->size) {
-                               dev_err(dev, "file %s segment %d would be truncated\n",
-@@ -426,7 +499,7 @@ static int __qcom_mdt_load(struct device
-                               break;
-               }
--              if (phdr->p_memsz > phdr->p_filesz)
-+              if (!dma_require && phdr->p_memsz > phdr->p_filesz)
-                       memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
-       }
-@@ -461,7 +534,7 @@ int qcom_mdt_load(struct device *dev, co
-               return ret;
-       return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
--                             mem_size, reloc_base, true);
-+                             mem_size, reloc_base, true, false, 0);
- }
- EXPORT_SYMBOL_GPL(qcom_mdt_load);
-@@ -484,9 +557,36 @@ int qcom_mdt_load_no_init(struct device
-                         size_t mem_size, phys_addr_t *reloc_base)
- {
-       return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
--                             mem_size, reloc_base, false);
-+                             mem_size, reloc_base, false, false, 0);
- }
- EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init);
-+/**
-+ * qcom_mdt_load_pd_seg() - load userpd specific PIL segements
-+ * @dev:      device handle to associate resources with
-+ * @fw:               firmware object for the mdt file
-+ * @firmware: name of the firmware, for construction of segment file names
-+ * @pas_id:   PAS identifier
-+ * @mem_region:       allocated memory region to load firmware into
-+ * @mem_phys: physical address of allocated memory region
-+ * @mem_size: size of the allocated memory region
-+ * @reloc_base:       adjusted physical address after relocation
-+ *
-+ * Here userpd PIL segements are stitched with rootpd firmware.
-+ * This function reloads userpd specific PIL segments during SSR
-+ * of userpd.
-+ *
-+ * Returns 0 on success, negative errno otherwise.
-+ */
-+int qcom_mdt_load_pd_seg(struct device *dev, const struct firmware *fw,
-+                       const char *firmware, int pas_id, int pd_asid, void *mem_region,
-+                       phys_addr_t mem_phys, size_t mem_size,
-+                       phys_addr_t *reloc_base)
-+{
-+      return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
-+                             mem_size, reloc_base, false, true, pd_asid);
-+}
-+EXPORT_SYMBOL_GPL(qcom_mdt_load_pd_seg);
-+
- MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
- MODULE_LICENSE("GPL v2");
---- a/include/linux/soc/qcom/mdt_loader.h
-+++ b/include/linux/soc/qcom/mdt_loader.h
-@@ -30,6 +30,11 @@ int qcom_mdt_load_no_init(struct device
- void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
-                            const char *fw_name, struct device *dev);
-+int qcom_mdt_load_pd_seg(struct device *dev, const struct firmware *fw,
-+                       const char *firmware, int pas_id, int pd_asid, void *mem_region,
-+                       phys_addr_t mem_phys, size_t mem_size,
-+                       phys_addr_t *reloc_base);
-+
- #else /* !IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */
- static inline ssize_t qcom_mdt_get_size(const struct firmware *fw)
diff --git a/target/linux/qualcommax/patches-6.12/0813-remoteproc-qcom_q6v5_mpd-enable-clocks.patch b/target/linux/qualcommax/patches-6.12/0813-remoteproc-qcom_q6v5_mpd-enable-clocks.patch
deleted file mode 100644 (file)
index efa4855..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From e83215d5d22946885fa388d375b12f1b991a43c1 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH 3/5] remoteproc: qcom_q6v5_mpd: enable clocks
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- drivers/remoteproc/qcom_q6v5_mpd.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/remoteproc/qcom_q6v5_mpd.c
-+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
-@@ -78,6 +78,8 @@ struct q6_wcss {
-       phys_addr_t mem_reloc;
-       void *mem_region;
-       size_t mem_size;
-+      struct clk_bulk_data *clks;
-+      int num_clks;
-       const struct wcss_data *desc;
-       const char **firmware;
-       struct userpd *upd[MAX_UPD];
-@@ -714,6 +716,16 @@ static int q6_wcss_probe(struct platform
-       if (ret)
-               goto free_rproc;
-+      wcss->num_clks = devm_clk_bulk_get_all(wcss->dev, &wcss->clks);
-+      if (wcss->num_clks < 0)
-+              return dev_err_probe(wcss->dev, wcss->num_clks,
-+                                   "failed to acquire clocks\n");
-+
-+      ret = clk_bulk_prepare_enable(wcss->num_clks, wcss->clks);
-+      if (ret)
-+              return dev_err_probe(wcss->dev, ret,
-+                                   "failed to enable clocks\n");
-+
-       ret = qcom_q6v5_init(&wcss->q6, pdev, rproc,
-                            WCSS_CRASH_REASON, NULL, NULL);
-       if (ret)
diff --git a/target/linux/qualcommax/patches-6.12/0814-remoteproc-qcom_q6v5_mpd-support-ipq5018.patch b/target/linux/qualcommax/patches-6.12/0814-remoteproc-qcom_q6v5_mpd-support-ipq5018.patch
deleted file mode 100644 (file)
index e50417f..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-From 4ae334127f073aa5f7c9209c9f0a17fd9e331db1 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:12 +0800
-Subject: [PATCH] remoteproc: qcom_q6v5_mpd: support ipq5018
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- drivers/remoteproc/qcom_q6v5_mpd.c | 37 +++++++++++++++++++++++++++---
- 1 file changed, 34 insertions(+), 3 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_mpd.c
-+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
-@@ -156,6 +156,8 @@ static int q6_wcss_spawn_pd(struct rproc
- static int wcss_pd_start(struct rproc *rproc)
- {
-       struct userpd *upd = rproc->priv;
-+      struct rproc *rpd_rproc = dev_get_drvdata(upd->dev->parent);
-+      struct q6_wcss *wcss = rpd_rproc->priv;
-       u32 pasid = (upd->pd_asid << 8) | UPD_SWID;
-       int ret;
-@@ -171,6 +173,14 @@ static int wcss_pd_start(struct rproc *r
-                       return ret;
-       }
-+      if (upd->pd_asid == 1) {
-+              ret = qcom_scm_internal_wifi_powerup(wcss->desc->pasid);
-+              if (ret) {
-+                      dev_err(upd->dev, "failed to power up internal radio\n");
-+                      return ret;
-+              }
-+      }
-+
-       return ret;
- }
-@@ -180,6 +190,12 @@ static int q6_wcss_stop(struct rproc *rp
-       const struct wcss_data *desc = wcss->desc;
-       int ret;
-+      ret = qcom_q6v5_request_stop(&wcss->q6, NULL);
-+      if (ret) {
-+              dev_err(wcss->dev, "pd not stopped\n");
-+              return ret;
-+      }
-+
-       ret = qcom_scm_pas_shutdown(desc->pasid);
-       if (ret) {
-               dev_err(wcss->dev, "not able to shutdown\n");
-@@ -219,6 +235,7 @@ static int wcss_pd_stop(struct rproc *rp
- {
-       struct userpd *upd = rproc->priv;
-       struct rproc *rpd_rproc = dev_get_drvdata(upd->dev->parent);
-+      struct q6_wcss *wcss = rpd_rproc->priv;
-       u32 pasid = (upd->pd_asid << 8) | UPD_SWID;
-       int ret;
-@@ -230,6 +247,14 @@ static int wcss_pd_stop(struct rproc *rp
-               }
-       }
-+      if (upd->pd_asid == 1) {
-+              ret = qcom_scm_internal_wifi_shutdown(wcss->desc->pasid);
-+              if (ret) {
-+                      dev_err(upd->dev, "failed to power down internal radio\n");
-+                      return ret;
-+              }
-+      }
-+
-       ret = qcom_scm_msa_unlock(pasid);
-       if (ret) {
-               dev_err(upd->dev, "failed to power down pd\n");
-@@ -431,15 +456,14 @@ static int wcss_pd_load(struct rproc *rp
-       struct userpd *upd = rproc->priv;
-       struct rproc *rpd_rproc = dev_get_drvdata(upd->dev->parent);
-       struct q6_wcss *wcss = rpd_rproc->priv;
--      u32 pasid = (upd->pd_asid << 8) | UPD_SWID;
-       int ret;
-       ret = rproc_boot(rpd_rproc);
-       if (ret)
-               return ret;
--      return qcom_mdt_load(upd->dev, fw, rproc->firmware,
--                           pasid, wcss->mem_region,
-+      return qcom_mdt_load_pd_seg(upd->dev, fw, rproc->firmware,
-+                           wcss->desc->pasid, upd->pd_asid, wcss->mem_region,
-                            wcss->mem_phys, wcss->mem_size,
-                            NULL);
- }
-@@ -771,6 +795,12 @@ static void q6_wcss_remove(struct platfo
-       rproc_free(rproc);
- }
-+static const struct wcss_data q6_ipq5018_res_init = {
-+      .pasid = MPD_WCNSS_PAS_ID,
-+      // .share_upd_info_to_q6 = true, /* Version 1 */
-+      // .mdt_load_sec = qcom_mdt_load_pd_seg,
-+};
-+
- static const struct wcss_data q6_ipq5332_res_init = {
-       .pasid = MPD_WCNSS_PAS_ID,
-       .share_upd_info_to_q6 = true,
-@@ -781,6 +811,7 @@ static const struct wcss_data q6_ipq9574
- };
- static const struct of_device_id q6_wcss_of_match[] = {
-+      { .compatible = "qcom,ipq5018-q6-mpd", .data = &q6_ipq5018_res_init },
-       { .compatible = "qcom,ipq5332-q6-mpd", .data = &q6_ipq5332_res_init },
-       { .compatible = "qcom,ipq9574-q6-mpd", .data = &q6_ipq9574_res_init },
-       { },
diff --git a/target/linux/qualcommax/patches-6.12/0815-remoteproc-qcom_q6v5_mpd-add-support-for-passing-v1-bootargs.patch b/target/linux/qualcommax/patches-6.12/0815-remoteproc-qcom_q6v5_mpd-add-support-for-passing-v1-bootargs.patch
deleted file mode 100644 (file)
index 2c4a7b1..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Mon, 09 Dec 2024 09:59:38 +0400
-Subject: [PATCH] remoteproc: qcom_q6v5_mpd: add support for passing v1 bootargs
-
-On multi-PD platforms such as IPQ5018, boot args are passed to the root PD
-run on the Q6 processor which in turn boots the user PDs for internal 
-(IPQ5018) and external wifi radios (such as QCN6122). These boot args 
-let the user PD process know details like what PCIE index, user PD ID, and
-reset GPIO is used. These are otherwise hardcoded in the firmware.
-
-Below is the structure expected of the version 1 boot args including the 
-default values hardcoded in the firmware for IPQ5018:
-
-+------------+------+--------------+--------------+
-| Argument   | type | def val UPD2 | def val UPD3 |
-+------------+------+--------------+--------------+
-| PCIE Index | u32  | 0x02 (PCIE1) | 0x01 (PCIE0) |
-| Length     | u32  | 0x04         | 0x04         |
-| User PD ID | u32  | 0x02         | 0x03         |
-| Reset GPIO | u32  | 0x12         | 0x0f         |
-| Reserved 1 | u32  | 0x00         | 0x00         |
-| Reserved 2 | u32  | 0x00         | 0x00         |
-+------------+------+--------------+--------------+
-
-On IPQ5018/QCN6122 boards, the default mapping is as follows:
-
-          +-> UPD1 ----> IPQ5018 Internal 2.4G Radio
-         / 
-        /
-Root PD +---> UPD2 ----> QCN6122 6G Radio on PCIE1 (if available)
-        \
-         \
-          +-> UPD3 ----> QCN6102 5G Radio on PCIE0
-
-To support (future) boards with other mappings or control what UPD ID is 
-used, let's add support for passing boot args for more flexibility.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
---- a/drivers/remoteproc/qcom_q6v5_mpd.c
-+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
-@@ -43,7 +43,11 @@
- #define UPD_BOOT_INFO_SMEM_SIZE               4096
- #define UPD_BOOT_INFO_HEADER_TYPE     0x2
- #define UPD_BOOT_INFO_SMEM_ID         507
--#define VERSION2                      2
-+
-+enum q6_bootargs_version {
-+      VERSION1 = 1,
-+      VERSION2,
-+};
- /**
-  * struct userpd_boot_info_header - header of user pd bootinfo
-@@ -95,6 +99,7 @@ struct userpd {
- struct wcss_data {
-       u32 pasid;
-       bool share_upd_info_to_q6;
-+      u8 bootargs_version;
- };
- /**
-@@ -299,10 +304,13 @@ static void *q6_wcss_da_to_va(struct rpr
- static int share_upd_bootinfo_to_q6(struct rproc *rproc)
- {
-       int i, ret;
-+      u32 rd_val;
-       size_t size;
-       u16 cnt = 0, version;
-       void *ptr;
-+      u8 *bootargs_arr;
-       struct q6_wcss *wcss = rproc->priv;
-+      struct device_node *np = wcss->dev->of_node;
-       struct userpd *upd;
-       struct userpd_boot_info upd_bootinfo = {0};
-       const struct firmware *fw;
-@@ -324,10 +332,47 @@ static int share_upd_bootinfo_to_q6(stru
-       }
-       /*Version*/
--      version = VERSION2;
-+      version = (wcss->desc->bootargs_version) ? wcss->desc->bootargs_version : VERSION2;
-       memcpy_toio(ptr, &version, sizeof(version));
-       ptr += sizeof(version);
-+      cnt = ret = of_property_count_u32_elems(np, "boot-args");
-+      if (ret < 0) {
-+              if (ret == -ENODATA) {
-+                      dev_err(wcss->dev, "failed to read boot args ret:%d\n", ret);
-+                      return ret;
-+              }
-+              cnt = 0;
-+      }
-+
-+      /* No of elements */
-+      memcpy_toio(ptr, &cnt, sizeof(u16));
-+      ptr += sizeof(u16);
-+
-+      bootargs_arr = kzalloc(cnt, GFP_KERNEL);
-+      if (!bootargs_arr) {
-+              dev_err(wcss->dev, "failed to allocate memory\n");
-+              return PTR_ERR(bootargs_arr);
-+      }
-+
-+      for (i = 0; i < cnt; i++) {
-+              ret = of_property_read_u32_index(np, "boot-args", i, &rd_val);
-+              if (ret) {
-+                      dev_err(wcss->dev, "failed to read boot args\n");
-+                      kfree(bootargs_arr);
-+                      return ret;
-+              }
-+              bootargs_arr[i] = (u8)rd_val;
-+      }
-+
-+      /* Copy bootargs */
-+      memcpy_toio(ptr, bootargs_arr, cnt);
-+      ptr += (cnt);
-+
-+      of_node_put(np);
-+      kfree(bootargs_arr);
-+      cnt = 0;
-+
-       for (i = 0; i < ARRAY_SIZE(wcss->upd); i++)
-               if (wcss->upd[i])
-                       cnt++;
-@@ -383,12 +428,14 @@ static int q6_wcss_load(struct rproc *rp
-       /* Share user pd boot info to Q6 remote processor */
-       if (desc->share_upd_info_to_q6) {
--              ret = share_upd_bootinfo_to_q6(rproc);
--              if (ret) {
--                      dev_err(wcss->dev,
--                              "user pd boot info sharing with q6 failed %d\n",
--                              ret);
--                      return ret;
-+              if (of_property_present(wcss->dev->of_node, "boot-args")) {
-+                      ret = share_upd_bootinfo_to_q6(rproc);
-+                      if (ret) {
-+                              dev_err(wcss->dev,
-+                                      "user pd boot info sharing with q6 failed %d\n",
-+                                      ret);
-+                              return ret;
-+                      }
-               }
-       }
-@@ -797,13 +844,15 @@ static void q6_wcss_remove(struct platfo
- static const struct wcss_data q6_ipq5018_res_init = {
-       .pasid = MPD_WCNSS_PAS_ID,
--      // .share_upd_info_to_q6 = true, /* Version 1 */
-+      .share_upd_info_to_q6 = true,
-+      .bootargs_version = VERSION1,
-       // .mdt_load_sec = qcom_mdt_load_pd_seg,
- };
- static const struct wcss_data q6_ipq5332_res_init = {
-       .pasid = MPD_WCNSS_PAS_ID,
-       .share_upd_info_to_q6 = true,
-+      .bootargs_version = VERSION2,
- };
- static const struct wcss_data q6_ipq9574_res_init = {
diff --git a/target/linux/qualcommax/patches-6.12/0816-arm64-dts-qcom-ipq5018-add-wifi-support.patch b/target/linux/qualcommax/patches-6.12/0816-arm64-dts-qcom-ipq5018-add-wifi-support.patch
deleted file mode 100644 (file)
index 8c6b2f9..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Wed, 27 Oct 2024 16:34:11 +0400
-Subject: [PATCH] arm64: dts: qcom: ipq5018: add wifi support
-
-The IPQ5018 SoC comes with an internal 2x2 2.4Ghz wifi radio.
-QCN6122 is a PCIe based wifi solution specific to the IPQ5018 platform which 
-comes optinally packed with 1 or 2 QCN6122 chips or with an external 
-PCIe based wifi solution (such as QCN9074) for 5/6 Ghz support.
-
-As such, add wifi nodes for both IPQ5018 and QCN6122.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -739,6 +739,118 @@
-                       };
-               };
-+              wifi: wifi@c000000 {
-+                      compatible = "qcom,ipq5018-wifi";
-+                      reg = <0x0c000000 0x1000000>;
-+
-+                      interrupts = <GIC_SPI 288 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 289 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 290 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 291 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 292 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 293 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 300 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 301 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 302 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 303 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 304 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 305 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 306 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 307 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 308 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 309 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 310 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 311 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 334 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 313 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 314 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 315 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 316 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 317 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 318 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 319 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 320 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 321 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 322 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 324 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 325 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 326 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 328 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 329 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 331 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 332 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 333 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 312 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 335 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 336 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 337 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 338 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 339 IRQ_TYPE_EDGE_RISING>;
-+                      interrupt-names = "misc-pulse1",
-+                                        "misc-latch",
-+                                        "sw-exception",
-+                                        "watchdog",
-+                                        "ce0",
-+                                        "ce1",
-+                                        "ce2",
-+                                        "ce3",
-+                                        "ce4",
-+                                        "ce5",
-+                                        "ce6",
-+                                        "ce7",
-+                                        "ce8",
-+                                        "ce9",
-+                                        "ce10",
-+                                        "ce11",
-+                                        "host2wbm-desc-feed",
-+                                        "host2reo-re-injection",
-+                                        "host2reo-command",
-+                                        "host2rxdma-monitor-ring3",
-+                                        "host2rxdma-monitor-ring2",
-+                                        "host2rxdma-monitor-ring1",
-+                                        "reo2ost-exception",
-+                                        "wbm2host-rx-release",
-+                                        "reo2host-status",
-+                                        "reo2host-destination-ring4",
-+                                        "reo2host-destination-ring3",
-+                                        "reo2host-destination-ring2",
-+                                        "reo2host-destination-ring1",
-+                                        "rxdma2host-monitor-destination-mac3",
-+                                        "rxdma2host-monitor-destination-mac2",
-+                                        "rxdma2host-monitor-destination-mac1",
-+                                        "ppdu-end-interrupts-mac3",
-+                                        "ppdu-end-interrupts-mac2",
-+                                        "ppdu-end-interrupts-mac1",
-+                                        "rxdma2host-monitor-status-ring-mac3",
-+                                        "rxdma2host-monitor-status-ring-mac2",
-+                                        "rxdma2host-monitor-status-ring-mac1",
-+                                        "host2rxdma-host-buf-ring-mac3",
-+                                        "host2rxdma-host-buf-ring-mac2",
-+                                        "host2rxdma-host-buf-ring-mac1",
-+                                        "rxdma2host-destination-ring-mac3",
-+                                        "rxdma2host-destination-ring-mac2",
-+                                        "rxdma2host-destination-ring-mac1",
-+                                        "host2tcl-input-ring4",
-+                                        "host2tcl-input-ring3",
-+                                        "host2tcl-input-ring2",
-+                                        "host2tcl-input-ring1",
-+                                        "wbm2host-tx-completions-ring3",
-+                                        "wbm2host-tx-completions-ring2",
-+                                        "wbm2host-tx-completions-ring1",
-+                                        "tcl2host-status-ring";
-+
-+                      status = "disabled";
-+              };
-+
-               q6v5_wcss: remoteproc@cd00000 {
-                       compatible = "qcom,ipq5018-wcss-sec-pil";
-                       reg = <0x0cd00000 0x10000>;
diff --git a/target/linux/qualcommax/patches-6.12/0817-arm64-dts-qcom-ipq5018-add-tz_apps-reserved-memory-region.patch b/target/linux/qualcommax/patches-6.12/0817-arm64-dts-qcom-ipq5018-add-tz_apps-reserved-memory-region.patch
deleted file mode 100644 (file)
index ce44b03..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Wed, 05 Feb 2025 12:12:47 +0400
-Subject: [PATCH] arm64: dts: qcom: ipq5018: add tz_apps reserved memory region
-
-Add tz_apps memory region needed for wifi to work.
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -136,6 +136,11 @@
-               #size-cells = <2>;
-               ranges;
-+              tz_apps@4a400000 {
-+                      reg = <0x0 0x4a400000 0x0 0x400000>;
-+                      no-map;
-+              };
-+
-               bootloader@4a800000 {
-                       reg = <0x0 0x4a800000 0x0 0x200000>;
-                       no-map;
diff --git a/target/linux/qualcommax/patches-6.12/0820-dt-bindings-net-wireless-ath11k-add-bindings-for-QCN6122.patch b/target/linux/qualcommax/patches-6.12/0820-dt-bindings-net-wireless-ath11k-add-bindings-for-QCN6122.patch
deleted file mode 100644 (file)
index 2980acb..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-From: George Moussalem <george.moussalem@outlook.com>
-Date: Wed, 27 Oct 2024 16:34:11 +0400
-Subject: [PATCH] dt: bindings: net: add bindings for QCN6122
-
-QCN6122 is a PCIe based solution that is attached to and enumerated
-by the WPSS (Wireless Processor SubSystem) Q6 processor.
-
-Though it is a PCIe device, since it is not attached to APSS processor
-(Application Processor SubSystem), APSS will be unaware of such a decice
-and hence it is registered to the APSS processor as a platform device(AHB).
-Because of this hybrid nature, it is called as a hybrid bus device.
-
-As such, QCN6122 is a hybrid bus type device and follows the same codepath
-as for WCN6750.
-
-This is a reversed engineered and heavily simplified version of below
-downstream patch:
-https://git.codelinaro.org/clo/qsdk/oss/system/feeds/wlan-open/-/ \
-blob/NHSS.QSDK.12.4.5.r2/mac80211/patches/232-ath11k-qcn6122-support.patch
-
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
---- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
-+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
-@@ -22,6 +22,7 @@ properties:
-       - qcom,ipq6018-wifi
-       - qcom,wcn6750-wifi
-       - qcom,ipq5018-wifi
-+      - qcom,qcn6122-wifi
-   reg:
-     maxItems: 1
-@@ -262,6 +263,29 @@ allOf:
-             - description: interrupt event for ring DP20
-             - description: interrupt event for ring DP21
-             - description: interrupt event for ring DP22
-+  - if:
-+      properties:
-+        compatible:
-+          contains:
-+            enum:
-+              - qcom,qcn6122-wifi
-+    then:
-+      properties:
-+        interrupts:
-+          items:
-+            - description: interrupt event for ring CE1
-+            - description: interrupt event for ring CE2
-+            - description: interrupt event for ring CE3
-+            - description: interrupt event for ring CE4
-+            - description: interrupt event for ring CE5
-+            - description: interrupt event for ring DP1
-+            - description: interrupt event for ring DP2
-+            - description: interrupt event for ring DP3
-+            - description: interrupt event for ring DP4
-+            - description: interrupt event for ring DP5
-+            - description: interrupt event for ring DP6
-+            - description: interrupt event for ring DP7
-+            - description: interrupt event for ring DP8
- examples:
-   - |
diff --git a/target/linux/qualcommax/patches-6.12/0842-arm64-dts-qcom-ipq5018-add-uniphy-node.patch b/target/linux/qualcommax/patches-6.12/0842-arm64-dts-qcom-ipq5018-add-uniphy-node.patch
deleted file mode 100644 (file)
index a443217..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -9,6 +9,7 @@
- #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
- #include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
-+#include <dt-bindings/net/qca-uniphy.h>
- #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
- #include <dt-bindings/thermal/thermal.h>
-@@ -258,6 +259,29 @@
-                       status = "disabled";
-               };
-+              uniphy0: ethernet-pcs@98000 {
-+                      compatible = "qualcomm,ipq5018-uniphy";
-+                      reg = <0x00098000 0x800>;
-+                      #clock-cells = <1>;
-+                      clocks = <&gcc GCC_UNIPHY_AHB_CLK>,
-+                               <&gcc GCC_UNIPHY_SYS_CLK>,
-+                               <&gcc GCC_UNIPHY_RX_CLK>,
-+                               <&gcc GCC_UNIPHY_TX_CLK>,
-+                               <&cmn_pll IPQ5018_ETH_50MHZ_CLK>;
-+                      clock-names = "ahb",
-+                                    "sys",
-+                                    "port5_rx",
-+                                    "port5_tx",
-+                                    "ref";
-+                      clock-output-names = "uniphy0_gcc_rx_clk",
-+                                           "uniphy0_gcc_tx_clk",
-+                                           "uniphy0_ref_clk";
-+                      resets = <&gcc GCC_UNIPHY_SOFT_RESET>;
-+                      reset-names = "soft";
-+                      #pcs-cells = <0>;
-+                      status = "disabled";
-+              };
-+
-               cmn_pll: clock-controller@9b000 {
-                       compatible = "qcom,ipq5018-cmn-pll";
-                       reg = <0x0009b000 0x800>;
-@@ -449,8 +473,8 @@
-                                <0>,
-                                <&gephy_rx_clk>,
-                                <&gephy_tx_clk>,
--                               <0>,
--                               <0>;
-+                               <&uniphy0 UNIPHY_CLK_RX>,
-+                               <&uniphy0 UNIPHY_CLK_TX>;
-                       #clock-cells = <1>;
-                       #reset-cells = <1>;
-               };
diff --git a/target/linux/qualcommax/patches-6.12/0843-net-stmmac-add-get_interfaces-platform-method.patch b/target/linux/qualcommax/patches-6.12/0843-net-stmmac-add-get_interfaces-platform-method.patch
deleted file mode 100644 (file)
index 3e415d2..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From ca732e990fc8222a2d6782ae750304719e212fe8 Mon Sep 17 00:00:00 2001
-From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
-Date: Thu, 1 May 2025 12:45:11 +0100
-Subject: [PATCH] net: stmmac: add get_interfaces() platform method
-
-Add a get_interfaces() platform method to allow platforms to indicate
-to phylink which interface modes they support - which then allows
-phylink to validate on initialisation that the configured PHY interface
-mode is actually supported.
-
-Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-Link: https://patch.msgid.link/E1uASLn-0021Qd-Mi@rmk-PC.armlinux.org.uk
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- .../net/ethernet/stmicro/stmmac/stmmac_main.c    | 16 +++++++++++++---
- include/linux/stmmac.h                           |  2 ++
- 2 files changed, 15 insertions(+), 3 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -1250,10 +1250,21 @@ static int stmmac_phy_setup(struct stmma
-               priv->phylink_config.default_an_inband =
-                       mdio_bus_data->default_an_inband;
--      /* Set the platform/firmware specified interface mode. Note, phylink
--       * deals with the PHY interface mode, not the MAC interface mode.
-+      /* Get the PHY interface modes (at the PHY end of the link) that
-+       * are supported by the platform.
-        */
--      __set_bit(mode, priv->phylink_config.supported_interfaces);
-+      if (priv->plat->get_interfaces)
-+              priv->plat->get_interfaces(priv, priv->plat->bsp_priv,
-+                                         priv->phylink_config.supported_interfaces);
-+
-+      /* Set the platform/firmware specified interface mode if the
-+       * supported interfaces have not already been provided using
-+       * phy_interface as a last resort.
-+       */
-+      if (phy_interface_empty(priv->phylink_config.supported_interfaces))
-+              __set_bit(priv->plat->phy_interface,
-+                        priv->phylink_config.supported_interfaces);
-+
-       /* If we have an xpcs, it defines which PHY interfaces are supported. */
-       if (priv->hw->xpcs)
---- a/include/linux/stmmac.h
-+++ b/include/linux/stmmac.h
-@@ -229,6 +229,8 @@ struct plat_stmmacenet_data {
-       u8 tx_sched_algorithm;
-       struct stmmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES];
-       struct stmmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES];
-+      void (*get_interfaces)(struct stmmac_priv *priv, void *bsp_priv,
-+                             unsigned long *interfaces);
-       void (*fix_mac_speed)(void *priv, unsigned int speed, unsigned int mode);
-       int (*fix_soc_reset)(void *priv, void __iomem *ioaddr);
-       int (*serdes_powerup)(struct net_device *ndev, void *priv);
diff --git a/target/linux/qualcommax/patches-6.12/0900-power-Add-Qualcomm-APM.patch b/target/linux/qualcommax/patches-6.12/0900-power-Add-Qualcomm-APM.patch
deleted file mode 100644 (file)
index c0744d7..0000000
+++ /dev/null
@@ -1,1039 +0,0 @@
-From 6c98adf98236b8644b8f5e1aa7af9f1a88ea2766 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 11 Apr 2022 14:38:08 +0200
-Subject: [PATCH] power: Add Qualcomm APM
-
-Add Qualcomm APM driver, which allows scaling cache and memory fabrics.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/power/Kconfig          |   1 +
- drivers/power/Makefile         |   1 +
- drivers/power/qcom/Kconfig     |   7 +
- drivers/power/qcom/Makefile    |   1 +
- drivers/power/qcom/apm.c       | 944 +++++++++++++++++++++++++++++++++
- include/linux/power/qcom/apm.h |  48 ++
- 6 files changed, 1002 insertions(+)
- create mode 100644 drivers/power/qcom/Kconfig
- create mode 100644 drivers/power/qcom/Makefile
- create mode 100644 drivers/power/qcom/apm.c
- create mode 100644 include/linux/power/qcom/apm.h
-
---- a/drivers/power/Kconfig
-+++ b/drivers/power/Kconfig
-@@ -2,3 +2,4 @@
- source "drivers/power/reset/Kconfig"
- source "drivers/power/sequencing/Kconfig"
- source "drivers/power/supply/Kconfig"
-+source "drivers/power/qcom/Kconfig"
---- a/drivers/power/Makefile
-+++ b/drivers/power/Makefile
-@@ -2,3 +2,4 @@
- obj-$(CONFIG_POWER_RESET)     += reset/
- obj-$(CONFIG_POWER_SEQUENCING)        += sequencing/
- obj-$(CONFIG_POWER_SUPPLY)    += supply/
-+obj-$(CONFIG_QCOM_APM)                += qcom/
---- /dev/null
-+++ b/drivers/power/qcom/Kconfig
-@@ -0,0 +1,7 @@
-+config QCOM_APM
-+       bool "Qualcomm Technologies Inc platform specific APM driver"
-+       help
-+      Platform specific driver to manage the power source of
-+      memory arrays. Interfaces with regulator drivers to ensure
-+      SRAM Vmin requirements are met across different performance
-+      levels.
---- /dev/null
-+++ b/drivers/power/qcom/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_QCOM_APM)                += apm.o
---- /dev/null
-+++ b/drivers/power/qcom/apm.c
-@@ -0,0 +1,936 @@
-+/*
-+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#define pr_fmt(fmt) "%s: " fmt, __func__
-+
-+#include <linux/debugfs.h>
-+#include <linux/delay.h>
-+#include <linux/of_device.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/power/qcom/apm.h>
-+
-+/*
-+ *        VDD_APCC
-+ * =============================================================
-+ *       |      VDD_MX                  |                    |
-+ *       |    ==========================|=============       |
-+ *    ___|___   ___|___    ___|___   ___|___    ___|___   ___|___
-+ *   |       | |       |  |       | |       |  |       | |       |
-+ *   | APCC  | | MX HS |  | MX HS | | APCC  |  | MX HS | | APCC  |
-+ *   |  HS   | |       |  |       | |  HS   |  |       | |  HS   |
-+ *   |_______| |_______|  |_______| |_______|  |_______| |_______|
-+ *       |_________|          |_________|         |__________|
-+ *            |                    |                    |
-+ *      ______|_____         ______|_____        _______|_____
-+ *     |            |       |            |      |             |
-+ *     |            |       |            |      |             |
-+ *     |  CPU MEM   |       |   L2 MEM   |      |    L3 MEM   |
-+ *     |   Arrays   |       |   Arrays   |      |    Arrays   |
-+ *     |            |       |            |      |             |
-+ *     |____________|       |____________|      |_____________|
-+ *
-+ */
-+
-+/* Register value definitions */
-+#define APCS_GFMUXA_SEL_VAL            0x13
-+#define APCS_GFMUXA_DESEL_VAL          0x03
-+#define MSM_APM_MX_MODE_VAL            0x00
-+#define MSM_APM_APCC_MODE_VAL          0x10
-+#define MSM_APM_MX_DONE_VAL            0x00
-+#define MSM_APM_APCC_DONE_VAL          0x03
-+#define MSM_APM_OVERRIDE_SEL_VAL       0xb0
-+#define MSM_APM_SEC_CLK_SEL_VAL        0x30
-+#define SPM_EVENT_SET_VAL              0x01
-+#define SPM_EVENT_CLEAR_VAL            0x00
-+
-+/* Register bit mask definitions */
-+#define MSM_APM_CTL_STS_MASK            0x0f
-+
-+/* Register offset definitions */
-+#define APCC_APM_MODE              0x00000098
-+#define APCC_APM_CTL_STS           0x000000a8
-+#define APCS_SPARE                 0x00000068
-+#define APCS_VERSION               0x00000fd0
-+
-+#define HMSS_VERSION_1P2           0x10020000
-+
-+#define MSM_APM_SWITCH_TIMEOUT_US  10
-+#define SPM_WAKEUP_DELAY_US        2
-+#define SPM_EVENT_NUM              6
-+
-+#define MSM_APM_DRIVER_NAME        "qcom,msm-apm"
-+
-+enum {
-+      MSM8996_ID,
-+      MSM8953_ID,
-+      IPQ807x_ID,
-+};
-+
-+struct msm_apm_ctrl_dev {
-+      struct list_head        list;
-+      struct device           *dev;
-+      enum msm_apm_supply     supply;
-+      spinlock_t              lock;
-+      void __iomem            *reg_base;
-+      void __iomem            *apcs_csr_base;
-+      void __iomem            **apcs_spm_events_addr;
-+      void __iomem            *apc0_pll_ctl_addr;
-+      void __iomem            *apc1_pll_ctl_addr;
-+      u32                     version;
-+      struct dentry           *debugfs;
-+      u32                     msm_id;
-+};
-+
-+#if defined(CONFIG_DEBUG_FS)
-+static struct dentry *apm_debugfs_base;
-+#endif
-+
-+static DEFINE_MUTEX(apm_ctrl_list_mutex);
-+static LIST_HEAD(apm_ctrl_list);
-+
-+/*
-+ * Get the resources associated with the APM controller from device tree
-+ * and remap all I/O addresses that are relevant to this HW revision.
-+ */
-+static int msm_apm_ctrl_devm_ioremap(struct platform_device *pdev,
-+                                   struct msm_apm_ctrl_dev *ctrl)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct resource *res;
-+      static const char *res_name[SPM_EVENT_NUM] = {
-+              "apc0-l2-spm",
-+              "apc1-l2-spm",
-+              "apc0-cpu0-spm",
-+              "apc0-cpu1-spm",
-+              "apc1-cpu0-spm",
-+              "apc1-cpu1-spm"
-+      };
-+      int i, ret = 0;
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pm-apcc-glb");
-+      if (!res) {
-+              dev_err(dev, "Missing PM APCC Global register physical address");
-+              return -EINVAL;
-+      }
-+      ctrl->reg_base = devm_ioremap(dev, res->start, resource_size(res));
-+      if (!ctrl->reg_base) {
-+              dev_err(dev, "Failed to map PM APCC Global registers\n");
-+              return -ENOMEM;
-+      }
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs-csr");
-+      if (!res) {
-+              dev_err(dev, "Missing APCS CSR physical base address");
-+              return -EINVAL;
-+      }
-+      ctrl->apcs_csr_base = devm_ioremap(dev, res->start, resource_size(res));
-+      if (!ctrl->apcs_csr_base) {
-+              dev_err(dev, "Failed to map APCS CSR registers\n");
-+              return -ENOMEM;
-+      }
-+
-+      ctrl->version = readl_relaxed(ctrl->apcs_csr_base + APCS_VERSION);
-+
-+      if (ctrl->version >= HMSS_VERSION_1P2)
-+              return ret;
-+
-+      ctrl->apcs_spm_events_addr = devm_kzalloc(&pdev->dev,
-+                                                SPM_EVENT_NUM
-+                                                * sizeof(void __iomem *),
-+                                                GFP_KERNEL);
-+      if (!ctrl->apcs_spm_events_addr) {
-+              dev_err(dev, "Failed to allocate memory for APCS SPM event registers\n");
-+              return -ENOMEM;
-+      }
-+
-+      for (i = 0; i < SPM_EVENT_NUM; i++) {
-+              res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+                                                 res_name[i]);
-+              if (!res) {
-+                      dev_err(dev, "Missing address for %s\n", res_name[i]);
-+                      ret = -EINVAL;
-+                      goto free_events;
-+              }
-+
-+              ctrl->apcs_spm_events_addr[i] = devm_ioremap(dev, res->start,
-+                                              resource_size(res));
-+              if (!ctrl->apcs_spm_events_addr[i]) {
-+                      dev_err(dev, "Failed to map %s\n", res_name[i]);
-+                      ret = -ENOMEM;
-+                      goto free_events;
-+              }
-+
-+              dev_dbg(dev, "%s event phys: %pa virt:0x%p\n", res_name[i],
-+                      &res->start, ctrl->apcs_spm_events_addr[i]);
-+      }
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+                                         "apc0-pll-ctl");
-+      if (!res) {
-+              dev_err(dev, "Missing APC0 PLL CTL physical address\n");
-+              ret = -EINVAL;
-+              goto free_events;
-+      }
-+
-+      ctrl->apc0_pll_ctl_addr = devm_ioremap(dev,
-+                                         res->start,
-+                                         resource_size(res));
-+      if (!ctrl->apc0_pll_ctl_addr) {
-+              dev_err(dev, "Failed to map APC0 PLL CTL register\n");
-+              ret = -ENOMEM;
-+              goto free_events;
-+      }
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+                                         "apc1-pll-ctl");
-+      if (!res) {
-+              dev_err(dev, "Missing APC1 PLL CTL physical address\n");
-+              ret = -EINVAL;
-+              goto free_events;
-+      }
-+
-+      ctrl->apc1_pll_ctl_addr = devm_ioremap(dev,
-+                                         res->start,
-+                                         resource_size(res));
-+      if (!ctrl->apc1_pll_ctl_addr) {
-+              dev_err(dev, "Failed to map APC1 PLL CTL register\n");
-+              ret = -ENOMEM;
-+              goto free_events;
-+      }
-+
-+      return ret;
-+
-+free_events:
-+      devm_kfree(dev, ctrl->apcs_spm_events_addr);
-+      return ret;
-+}
-+
-+/* 8953 register offset definition */
-+#define MSM8953_APM_DLY_CNTR  0x2ac
-+
-+/* Register field shift definitions */
-+#define APM_CTL_SEL_SWITCH_DLY_SHIFT  0
-+#define APM_CTL_RESUME_CLK_DLY_SHIFT  8
-+#define APM_CTL_HALT_CLK_DLY_SHIFT    16
-+#define APM_CTL_POST_HALT_DLY_SHIFT   24
-+
-+/* Register field mask definitions */
-+#define APM_CTL_SEL_SWITCH_DLY_MASK   GENMASK(7, 0)
-+#define APM_CTL_RESUME_CLK_DLY_MASK   GENMASK(15, 8)
-+#define APM_CTL_HALT_CLK_DLY_MASK     GENMASK(23, 16)
-+#define APM_CTL_POST_HALT_DLY_MASK    GENMASK(31, 24)
-+
-+/*
-+ * Get the resources associated with the msm8953 APM controller from
-+ * device tree, remap all I/O addresses, and program the initial
-+ * register configuration required for the 8953 APM controller device.
-+ */
-+static int msm8953_apm_ctrl_init(struct platform_device *pdev,
-+                                   struct msm_apm_ctrl_dev *ctrl)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct resource *res;
-+      u32 delay_counter, val = 0, regval = 0;
-+      int rc = 0;
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pm-apcc-glb");
-+      if (!res) {
-+              dev_err(dev, "Missing PM APCC Global register physical address\n");
-+              return -ENODEV;
-+      }
-+      ctrl->reg_base = devm_ioremap(dev, res->start, resource_size(res));
-+      if (!ctrl->reg_base) {
-+              dev_err(dev, "Failed to map PM APCC Global registers\n");
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Initial APM register configuration required before starting
-+       * APM HW controller.
-+       */
-+      regval = readl_relaxed(ctrl->reg_base + MSM8953_APM_DLY_CNTR);
-+      val = regval;
-+
-+      if (of_property_present(dev->of_node, "qcom,apm-post-halt-delay")) {
-+              rc = of_property_read_u32(dev->of_node,
-+                              "qcom,apm-post-halt-delay", &delay_counter);
-+              if (rc < 0) {
-+                      dev_err(dev, "apm-post-halt-delay read failed, rc = %d",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              val &= ~APM_CTL_POST_HALT_DLY_MASK;
-+              val |= (delay_counter << APM_CTL_POST_HALT_DLY_SHIFT)
-+                      & APM_CTL_POST_HALT_DLY_MASK;
-+      }
-+
-+      if (of_property_present(dev->of_node, "qcom,apm-halt-clk-delay")) {
-+              rc = of_property_read_u32(dev->of_node,
-+                              "qcom,apm-halt-clk-delay", &delay_counter);
-+              if (rc < 0) {
-+                      dev_err(dev, "apm-halt-clk-delay read failed, rc = %d",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              val &= ~APM_CTL_HALT_CLK_DLY_MASK;
-+              val |= (delay_counter << APM_CTL_HALT_CLK_DLY_SHIFT)
-+                      & APM_CTL_HALT_CLK_DLY_MASK;
-+      }
-+
-+      if (of_property_present(dev->of_node, "qcom,apm-resume-clk-delay")) {
-+              rc = of_property_read_u32(dev->of_node,
-+                              "qcom,apm-resume-clk-delay", &delay_counter);
-+              if (rc < 0) {
-+                      dev_err(dev, "apm-resume-clk-delay read failed, rc = %d",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              val &= ~APM_CTL_RESUME_CLK_DLY_MASK;
-+              val |= (delay_counter << APM_CTL_RESUME_CLK_DLY_SHIFT)
-+                      & APM_CTL_RESUME_CLK_DLY_MASK;
-+      }
-+
-+      if (of_property_present(dev->of_node, "qcom,apm-sel-switch-delay")) {
-+              rc = of_property_read_u32(dev->of_node,
-+                              "qcom,apm-sel-switch-delay", &delay_counter);
-+              if (rc < 0) {
-+                      dev_err(dev, "apm-sel-switch-delay read failed, rc = %d",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              val &= ~APM_CTL_SEL_SWITCH_DLY_MASK;
-+              val |= (delay_counter << APM_CTL_SEL_SWITCH_DLY_SHIFT)
-+                      & APM_CTL_SEL_SWITCH_DLY_MASK;
-+      }
-+
-+      if (val != regval) {
-+              writel_relaxed(val, ctrl->reg_base + MSM8953_APM_DLY_CNTR);
-+              /* make sure write completes before return */
-+              mb();
-+      }
-+
-+      return rc;
-+}
-+
-+static int msm8996_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      int i, timeout = MSM_APM_SWITCH_TIMEOUT_US;
-+      u32 regval;
-+      int ret = 0;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&ctrl_dev->lock, flags);
-+
-+      /* Perform revision-specific programming steps */
-+      if (ctrl_dev->version < HMSS_VERSION_1P2) {
-+              /* Clear SPM events */
-+              for (i = 0; i < SPM_EVENT_NUM; i++)
-+                      writel_relaxed(SPM_EVENT_CLEAR_VAL,
-+                                     ctrl_dev->apcs_spm_events_addr[i]);
-+
-+              udelay(SPM_WAKEUP_DELAY_US);
-+
-+              /* Switch APC/CBF to GPLL0 clock */
-+              writel_relaxed(APCS_GFMUXA_SEL_VAL,
-+                             ctrl_dev->apcs_csr_base + APCS_SPARE);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
-+                             ctrl_dev->apc0_pll_ctl_addr);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
-+                             ctrl_dev->apc1_pll_ctl_addr);
-+
-+              /* Ensure writes complete before proceeding */
-+              mb();
-+      }
-+
-+      /* Switch arrays to MX supply and wait for its completion */
-+      writel_relaxed(MSM_APM_MX_MODE_VAL, ctrl_dev->reg_base +
-+                     APCC_APM_MODE);
-+
-+      /* Ensure write above completes before delaying */
-+      mb();
-+
-+      while (timeout > 0) {
-+              regval = readl_relaxed(ctrl_dev->reg_base + APCC_APM_CTL_STS);
-+              if ((regval & MSM_APM_CTL_STS_MASK) ==
-+                  MSM_APM_MX_DONE_VAL)
-+                      break;
-+
-+              udelay(1);
-+              timeout--;
-+      }
-+
-+      if (timeout == 0) {
-+              ret = -ETIMEDOUT;
-+              dev_err(ctrl_dev->dev, "APCC to MX APM switch timed out. APCC_APM_CTL_STS=0x%x\n",
-+                      regval);
-+      }
-+
-+      /* Perform revision-specific programming steps */
-+      if (ctrl_dev->version < HMSS_VERSION_1P2) {
-+              /* Switch APC/CBF clocks to original source */
-+              writel_relaxed(APCS_GFMUXA_DESEL_VAL,
-+                             ctrl_dev->apcs_csr_base + APCS_SPARE);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
-+                             ctrl_dev->apc0_pll_ctl_addr);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
-+                             ctrl_dev->apc1_pll_ctl_addr);
-+
-+              /* Complete clock source switch before SPM event sequence */
-+              mb();
-+
-+              /* Set SPM events */
-+              for (i = 0; i < SPM_EVENT_NUM; i++)
-+                      writel_relaxed(SPM_EVENT_SET_VAL,
-+                                     ctrl_dev->apcs_spm_events_addr[i]);
-+      }
-+
-+      if (!ret) {
-+              ctrl_dev->supply = MSM_APM_SUPPLY_MX;
-+              dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n");
-+      }
-+
-+      spin_unlock_irqrestore(&ctrl_dev->lock, flags);
-+
-+      return ret;
-+}
-+
-+static int msm8996_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      int i, timeout = MSM_APM_SWITCH_TIMEOUT_US;
-+      u32 regval;
-+      int ret = 0;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&ctrl_dev->lock, flags);
-+
-+      /* Perform revision-specific programming steps */
-+      if (ctrl_dev->version < HMSS_VERSION_1P2) {
-+              /* Clear SPM events */
-+              for (i = 0; i < SPM_EVENT_NUM; i++)
-+                      writel_relaxed(SPM_EVENT_CLEAR_VAL,
-+                                     ctrl_dev->apcs_spm_events_addr[i]);
-+
-+              udelay(SPM_WAKEUP_DELAY_US);
-+
-+              /* Switch APC/CBF to GPLL0 clock */
-+              writel_relaxed(APCS_GFMUXA_SEL_VAL,
-+                             ctrl_dev->apcs_csr_base + APCS_SPARE);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
-+                             ctrl_dev->apc0_pll_ctl_addr);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
-+                             ctrl_dev->apc1_pll_ctl_addr);
-+
-+              /* Ensure previous writes complete before proceeding */
-+              mb();
-+      }
-+
-+      /* Switch arrays to APCC supply and wait for its completion */
-+      writel_relaxed(MSM_APM_APCC_MODE_VAL, ctrl_dev->reg_base +
-+                     APCC_APM_MODE);
-+
-+      /* Ensure write above completes before delaying */
-+      mb();
-+
-+      while (timeout > 0) {
-+              regval = readl_relaxed(ctrl_dev->reg_base + APCC_APM_CTL_STS);
-+              if ((regval & MSM_APM_CTL_STS_MASK) ==
-+                  MSM_APM_APCC_DONE_VAL)
-+                      break;
-+
-+              udelay(1);
-+              timeout--;
-+      }
-+
-+      if (timeout == 0) {
-+              ret = -ETIMEDOUT;
-+              dev_err(ctrl_dev->dev, "MX to APCC APM switch timed out. APCC_APM_CTL_STS=0x%x\n",
-+                      regval);
-+      }
-+
-+      /* Perform revision-specific programming steps */
-+      if (ctrl_dev->version < HMSS_VERSION_1P2) {
-+              /* Set SPM events */
-+              for (i = 0; i < SPM_EVENT_NUM; i++)
-+                      writel_relaxed(SPM_EVENT_SET_VAL,
-+                                     ctrl_dev->apcs_spm_events_addr[i]);
-+
-+              /* Complete SPM event sequence before clock source switch */
-+              mb();
-+
-+              /* Switch APC/CBF clocks to original source */
-+              writel_relaxed(APCS_GFMUXA_DESEL_VAL,
-+                             ctrl_dev->apcs_csr_base + APCS_SPARE);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
-+                             ctrl_dev->apc0_pll_ctl_addr);
-+              ndelay(200);
-+              writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
-+                             ctrl_dev->apc1_pll_ctl_addr);
-+      }
-+
-+      if (!ret) {
-+              ctrl_dev->supply = MSM_APM_SUPPLY_APCC;
-+              dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n");
-+      }
-+
-+      spin_unlock_irqrestore(&ctrl_dev->lock, flags);
-+
-+      return ret;
-+}
-+
-+/* 8953 register value definitions */
-+#define MSM8953_APM_MX_MODE_VAL            0x00
-+#define MSM8953_APM_APCC_MODE_VAL          0x02
-+#define MSM8953_APM_MX_DONE_VAL            0x00
-+#define MSM8953_APM_APCC_DONE_VAL          0x03
-+
-+/* 8953 register offset definitions */
-+#define MSM8953_APCC_APM_MODE              0x000002a8
-+#define MSM8953_APCC_APM_CTL_STS           0x000002b0
-+
-+/* 8953 constants */
-+#define MSM8953_APM_SWITCH_TIMEOUT_US      500
-+
-+/* Register bit mask definitions */
-+#define MSM8953_APM_CTL_STS_MASK           0x1f
-+
-+static int msm8953_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
-+      u32 regval;
-+      int ret = 0;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&ctrl_dev->lock, flags);
-+
-+      /* Switch arrays to MX supply and wait for its completion */
-+      writel_relaxed(MSM8953_APM_MX_MODE_VAL, ctrl_dev->reg_base +
-+                     MSM8953_APCC_APM_MODE);
-+
-+      /* Ensure write above completes before delaying */
-+      mb();
-+
-+      while (timeout > 0) {
-+              regval = readl_relaxed(ctrl_dev->reg_base +
-+                                      MSM8953_APCC_APM_CTL_STS);
-+              if ((regval & MSM8953_APM_CTL_STS_MASK) ==
-+                              MSM8953_APM_MX_DONE_VAL)
-+                      break;
-+
-+              udelay(1);
-+              timeout--;
-+      }
-+
-+      if (timeout == 0) {
-+              ret = -ETIMEDOUT;
-+              dev_err(ctrl_dev->dev, "APCC to MX APM switch timed out. APCC_APM_CTL_STS=0x%x\n",
-+                      regval);
-+      } else {
-+              ctrl_dev->supply = MSM_APM_SUPPLY_MX;
-+              dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n");
-+      }
-+
-+      spin_unlock_irqrestore(&ctrl_dev->lock, flags);
-+
-+      return ret;
-+}
-+
-+static int msm8953_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
-+      u32 regval;
-+      int ret = 0;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&ctrl_dev->lock, flags);
-+
-+      /* Switch arrays to APCC supply and wait for its completion */
-+      writel_relaxed(MSM8953_APM_APCC_MODE_VAL, ctrl_dev->reg_base +
-+                     MSM8953_APCC_APM_MODE);
-+
-+      /* Ensure write above completes before delaying */
-+      mb();
-+
-+      while (timeout > 0) {
-+              regval = readl_relaxed(ctrl_dev->reg_base +
-+                                      MSM8953_APCC_APM_CTL_STS);
-+              if ((regval & MSM8953_APM_CTL_STS_MASK) ==
-+                              MSM8953_APM_APCC_DONE_VAL)
-+                      break;
-+
-+              udelay(1);
-+              timeout--;
-+      }
-+
-+      if (timeout == 0) {
-+              ret = -ETIMEDOUT;
-+              dev_err(ctrl_dev->dev, "MX to APCC APM switch timed out. APCC_APM_CTL_STS=0x%x\n",
-+                      regval);
-+      } else {
-+              ctrl_dev->supply = MSM_APM_SUPPLY_APCC;
-+              dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n");
-+      }
-+
-+      spin_unlock_irqrestore(&ctrl_dev->lock, flags);
-+
-+      return ret;
-+}
-+
-+static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      int ret = 0;
-+
-+      switch (ctrl_dev->msm_id) {
-+      case MSM8996_ID:
-+              ret = msm8996_apm_switch_to_mx(ctrl_dev);
-+              break;
-+      case MSM8953_ID:
-+      case IPQ807x_ID:
-+              ret = msm8953_apm_switch_to_mx(ctrl_dev);
-+              break;
-+      }
-+
-+      return ret;
-+}
-+
-+static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      int ret = 0;
-+
-+      switch (ctrl_dev->msm_id) {
-+      case MSM8996_ID:
-+              ret = msm8996_apm_switch_to_apcc(ctrl_dev);
-+              break;
-+      case MSM8953_ID:
-+      case IPQ807x_ID:
-+              ret = msm8953_apm_switch_to_apcc(ctrl_dev);
-+              break;
-+      }
-+
-+      return ret;
-+}
-+
-+/**
-+ * msm_apm_get_supply() - Returns the supply that is currently
-+ *                    powering the memory arrays
-+ * @ctrl_dev:                   Pointer to an MSM APM controller device
-+ *
-+ * Returns the supply currently selected by the APM.
-+ */
-+int msm_apm_get_supply(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      return ctrl_dev->supply;
-+}
-+EXPORT_SYMBOL(msm_apm_get_supply);
-+
-+/**
-+ * msm_apm_set_supply() - Perform the necessary steps to switch the voltage
-+ *                        source of the memory arrays to a given supply
-+ * @ctrl_dev:                   Pointer to an MSM APM controller device
-+ * @supply:                     Power rail to use as supply for the memory
-+ *                              arrays
-+ *
-+ * Returns 0 on success, -ETIMEDOUT on APM switch timeout, or -EPERM if
-+ * the supply is not supported.
-+ */
-+int msm_apm_set_supply(struct msm_apm_ctrl_dev *ctrl_dev,
-+                     enum msm_apm_supply supply)
-+{
-+      int ret;
-+
-+      switch (supply) {
-+      case MSM_APM_SUPPLY_APCC:
-+              ret = msm_apm_switch_to_apcc(ctrl_dev);
-+              break;
-+      case MSM_APM_SUPPLY_MX:
-+              ret = msm_apm_switch_to_mx(ctrl_dev);
-+              break;
-+      default:
-+              ret = -EPERM;
-+              break;
-+      }
-+
-+      return ret;
-+}
-+EXPORT_SYMBOL(msm_apm_set_supply);
-+
-+/**
-+ * msm_apm_ctrl_dev_get() - get a handle to the MSM APM controller linked to
-+ *                          the device in device tree
-+ * @dev:                    Pointer to the device
-+ *
-+ * The device must specify "qcom,apm-ctrl" property in its device tree
-+ * node which points to an MSM APM controller device node.
-+ *
-+ * Returns an MSM APM controller handle if successful or ERR_PTR on any error.
-+ * If the APM controller device hasn't probed yet, ERR_PTR(-EPROBE_DEFER) is
-+ * returned.
-+ */
-+struct msm_apm_ctrl_dev *msm_apm_ctrl_dev_get(struct device *dev)
-+{
-+      struct msm_apm_ctrl_dev *ctrl_dev = NULL;
-+      struct msm_apm_ctrl_dev *dev_found = ERR_PTR(-EPROBE_DEFER);
-+      struct device_node *ctrl_node;
-+
-+      if (!dev || !dev->of_node) {
-+              pr_err("Invalid device node\n");
-+              return ERR_PTR(-EINVAL);
-+      }
-+
-+      ctrl_node = of_parse_phandle(dev->of_node, "qcom,apm-ctrl", 0);
-+      if (!ctrl_node) {
-+              pr_err("Could not find qcom,apm-ctrl property in %s\n",
-+                     dev->of_node->full_name);
-+              return ERR_PTR(-ENXIO);
-+      }
-+
-+      mutex_lock(&apm_ctrl_list_mutex);
-+      list_for_each_entry(ctrl_dev, &apm_ctrl_list, list) {
-+              if (ctrl_dev->dev && ctrl_dev->dev->of_node == ctrl_node) {
-+                      dev_found = ctrl_dev;
-+                      break;
-+              }
-+      }
-+      mutex_unlock(&apm_ctrl_list_mutex);
-+
-+      of_node_put(ctrl_node);
-+      return dev_found;
-+}
-+EXPORT_SYMBOL(msm_apm_ctrl_dev_get);
-+
-+#if defined(CONFIG_DEBUG_FS)
-+
-+static int apm_supply_dbg_open(struct inode *inode, struct file *filep)
-+{
-+      filep->private_data = inode->i_private;
-+
-+      return 0;
-+}
-+
-+static ssize_t apm_supply_dbg_read(struct file *filep, char __user *ubuf,
-+                                 size_t count, loff_t *ppos)
-+{
-+      struct msm_apm_ctrl_dev *ctrl_dev = filep->private_data;
-+      char buf[10];
-+      int len;
-+
-+      if (!ctrl_dev) {
-+              pr_err("invalid apm ctrl handle\n");
-+              return -ENODEV;
-+      }
-+
-+      if (ctrl_dev->supply == MSM_APM_SUPPLY_APCC)
-+              len = snprintf(buf, sizeof(buf), "APCC\n");
-+      else if (ctrl_dev->supply == MSM_APM_SUPPLY_MX)
-+              len = snprintf(buf, sizeof(buf), "MX\n");
-+      else
-+              len = snprintf(buf, sizeof(buf), "ERR\n");
-+
-+      return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-+}
-+
-+static const struct file_operations apm_supply_fops = {
-+      .open = apm_supply_dbg_open,
-+      .read = apm_supply_dbg_read,
-+};
-+
-+static void apm_debugfs_base_init(void)
-+{
-+      apm_debugfs_base = debugfs_create_dir("msm-apm", NULL);
-+
-+      if (IS_ERR_OR_NULL(apm_debugfs_base))
-+              pr_err("msm-apm debugfs base directory creation failed\n");
-+}
-+
-+static void apm_debugfs_init(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      struct dentry *temp;
-+
-+      if (IS_ERR_OR_NULL(apm_debugfs_base)) {
-+              pr_err("Base directory missing, cannot create apm debugfs nodes\n");
-+              return;
-+      }
-+
-+      ctrl_dev->debugfs = debugfs_create_dir(dev_name(ctrl_dev->dev),
-+                                             apm_debugfs_base);
-+      if (IS_ERR_OR_NULL(ctrl_dev->debugfs)) {
-+              pr_err("%s debugfs directory creation failed\n",
-+                     dev_name(ctrl_dev->dev));
-+              return;
-+      }
-+
-+      temp = debugfs_create_file("supply", S_IRUGO, ctrl_dev->debugfs,
-+                                 ctrl_dev, &apm_supply_fops);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              pr_err("supply mode creation failed\n");
-+              return;
-+      }
-+}
-+
-+static void apm_debugfs_deinit(struct msm_apm_ctrl_dev *ctrl_dev)
-+{
-+      if (!IS_ERR_OR_NULL(ctrl_dev->debugfs))
-+              debugfs_remove_recursive(ctrl_dev->debugfs);
-+}
-+
-+static void apm_debugfs_base_remove(void)
-+{
-+      debugfs_remove_recursive(apm_debugfs_base);
-+}
-+#else
-+
-+static void apm_debugfs_base_init(void)
-+{}
-+
-+static void apm_debugfs_init(struct msm_apm_ctrl_dev *ctrl_dev)
-+{}
-+
-+static void apm_debugfs_deinit(struct msm_apm_ctrl_dev *ctrl_dev)
-+{}
-+
-+static void apm_debugfs_base_remove(void)
-+{}
-+
-+#endif
-+
-+static const struct of_device_id msm_apm_match_table[] = {
-+      {
-+              .compatible = "qcom,msm-apm",
-+              .data = (void *)(uintptr_t)MSM8996_ID,
-+      },
-+      {
-+              .compatible = "qcom,msm8953-apm",
-+              .data = (void *)(uintptr_t)MSM8953_ID,
-+      },
-+      {
-+              .compatible = "qcom,ipq807x-apm",
-+              .data = (void *)(uintptr_t)IPQ807x_ID,
-+      },
-+      {}
-+};
-+
-+static int msm_apm_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct msm_apm_ctrl_dev *ctrl;
-+      int ret = 0;
-+
-+      dev_dbg(dev, "probing MSM Array Power Mux driver\n");
-+
-+      if (!dev->of_node) {
-+              dev_err(dev, "Device tree node is missing\n");
-+              return -ENODEV;
-+      }
-+
-+      ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
-+      if (!ctrl) {
-+              dev_err(dev, "MSM APM controller memory allocation failed\n");
-+              return -ENOMEM;
-+      }
-+
-+      INIT_LIST_HEAD(&ctrl->list);
-+      spin_lock_init(&ctrl->lock);
-+      ctrl->dev = dev;
-+      ctrl->msm_id = (uintptr_t)of_device_get_match_data(dev);
-+      platform_set_drvdata(pdev, ctrl);
-+
-+      switch (ctrl->msm_id) {
-+      case MSM8996_ID:
-+              ret = msm_apm_ctrl_devm_ioremap(pdev, ctrl);
-+              if (ret) {
-+                      dev_err(dev, "Failed to add APM controller device\n");
-+                      return ret;
-+              }
-+              break;
-+      case MSM8953_ID:
-+      case IPQ807x_ID:
-+              ret = msm8953_apm_ctrl_init(pdev, ctrl);
-+              if (ret) {
-+                      dev_err(dev, "Failed to initialize APM controller device: ret=%d\n",
-+                              ret);
-+                      return ret;
-+              }
-+              break;
-+      default:
-+              dev_err(dev, "unable to add APM controller device for msm_id:%d\n",
-+                      ctrl->msm_id);
-+              return -ENODEV;
-+      }
-+
-+      apm_debugfs_init(ctrl);
-+      mutex_lock(&apm_ctrl_list_mutex);
-+      list_add_tail(&ctrl->list, &apm_ctrl_list);
-+      mutex_unlock(&apm_ctrl_list_mutex);
-+
-+      dev_dbg(dev, "MSM Array Power Mux driver probe successful");
-+
-+      return ret;
-+}
-+
-+static void msm_apm_remove(struct platform_device *pdev)
-+{
-+      struct msm_apm_ctrl_dev *ctrl_dev;
-+
-+      ctrl_dev = platform_get_drvdata(pdev);
-+      if (ctrl_dev) {
-+              mutex_lock(&apm_ctrl_list_mutex);
-+              list_del(&ctrl_dev->list);
-+              mutex_unlock(&apm_ctrl_list_mutex);
-+              apm_debugfs_deinit(ctrl_dev);
-+      }
-+}
-+
-+static struct platform_driver msm_apm_driver = {
-+      .driver         = {
-+              .name           = MSM_APM_DRIVER_NAME,
-+              .of_match_table = msm_apm_match_table,
-+      },
-+      .probe          = msm_apm_probe,
-+      .remove         = msm_apm_remove,
-+};
-+
-+static int __init msm_apm_init(void)
-+{
-+      apm_debugfs_base_init();
-+      return platform_driver_register(&msm_apm_driver);
-+}
-+
-+static void __exit msm_apm_exit(void)
-+{
-+      platform_driver_unregister(&msm_apm_driver);
-+      apm_debugfs_base_remove();
-+}
-+
-+arch_initcall(msm_apm_init);
-+module_exit(msm_apm_exit);
-+
-+MODULE_DESCRIPTION("MSM Array Power Mux driver");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/include/linux/power/qcom/apm.h
-@@ -0,0 +1,48 @@
-+/*
-+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __LINUX_POWER_QCOM_APM_H__
-+#define __LINUX_POWER_QCOM_APM_H__
-+
-+#include <linux/device.h>
-+#include <linux/err.h>
-+
-+/**
-+ * enum msm_apm_supply - supported power rails to supply memory arrays
-+ * %MSM_APM_SUPPLY_APCC:      to enable selection of VDD_APCC rail as supply
-+ * %MSM_APM_SUPPLY_MX:                to enable selection of VDD_MX rail as supply
-+ */
-+enum msm_apm_supply {
-+      MSM_APM_SUPPLY_APCC,
-+      MSM_APM_SUPPLY_MX,
-+};
-+
-+/* Handle used to identify an APM controller device  */
-+struct msm_apm_ctrl_dev;
-+
-+#ifdef CONFIG_QCOM_APM
-+struct msm_apm_ctrl_dev *msm_apm_ctrl_dev_get(struct device *dev);
-+int msm_apm_set_supply(struct msm_apm_ctrl_dev *ctrl_dev,
-+                     enum msm_apm_supply supply);
-+int msm_apm_get_supply(struct msm_apm_ctrl_dev *ctrl_dev);
-+
-+#else
-+static inline struct msm_apm_ctrl_dev *msm_apm_ctrl_dev_get(struct device *dev)
-+{ return ERR_PTR(-EPERM); }
-+static inline int msm_apm_set_supply(struct msm_apm_ctrl_dev *ctrl_dev,
-+                     enum msm_apm_supply supply)
-+{ return -EPERM; }
-+static inline int msm_apm_get_supply(struct msm_apm_ctrl_dev *ctrl_dev)
-+{ return -EPERM; }
-+#endif
-+#endif
diff --git a/target/linux/qualcommax/patches-6.12/0901-regulator-add-Qualcomm-CPR-regulators.patch b/target/linux/qualcommax/patches-6.12/0901-regulator-add-Qualcomm-CPR-regulators.patch
deleted file mode 100644 (file)
index 267ed2b..0000000
+++ /dev/null
@@ -1,11674 +0,0 @@
-From c9df32c057e43e38c8113199e64f7a64f8d341df Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 11 Apr 2022 14:35:36 +0200
-Subject: [PATCH] regulator: add Qualcomm CPR regulators
-
-Allow building Qualcomm CPR regulators.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/regulator/Kconfig               |   33 +
- drivers/regulator/Makefile              |    3 +
- drivers/regulator/cpr3-npu-regulator.c  |  695 +++
- drivers/regulator/cpr3-regulator.c      | 5111 +++++++++++++++++++++++
- drivers/regulator/cpr3-regulator.h      | 1211 ++++++
- drivers/regulator/cpr3-util.c           | 2750 ++++++++++++
- drivers/regulator/cpr4-apss-regulator.c | 1819 ++++++++
- include/soc/qcom/socinfo.h              |  463 ++
- 8 files changed, 12085 insertions(+)
- create mode 100644 drivers/regulator/cpr3-npu-regulator.c
- create mode 100644 drivers/regulator/cpr3-regulator.c
- create mode 100644 drivers/regulator/cpr3-regulator.h
- create mode 100644 drivers/regulator/cpr3-util.c
- create mode 100644 drivers/regulator/cpr4-apss-regulator.c
- create mode 100644 include/soc/qcom/socinfo.h
-
---- a/drivers/regulator/Kconfig
-+++ b/drivers/regulator/Kconfig
-@@ -1720,4 +1720,37 @@ config REGULATOR_QCOM_LABIBB
-         boost regulator and IBB can be used as a negative boost regulator
-         for LCD display panel.
-+config REGULATOR_CPR3
-+      bool "QCOM CPR3 regulator core support"
-+      help
-+        This driver supports Core Power Reduction (CPR) version 3 controllers
-+        which are used by some Qualcomm Technologies, Inc. SoCs to
-+        manage important voltage regulators.  CPR3 controllers are capable of
-+        monitoring several ring oscillator sensing loops simultaneously.  The
-+        CPR3 controller informs software when the silicon conditions require
-+        the supply voltage to be increased or decreased.  On certain supply
-+        rails, the CPR3 controller is able to propagate the voltage increase
-+        or decrease requests all the way to the PMIC without software
-+        involvement.
-+
-+config REGULATOR_CPR3_NPU
-+      bool "QCOM CPR3 regulator for NPU"
-+      depends on OF && REGULATOR_CPR3
-+      help
-+        This driver supports Qualcomm Technologies, Inc. NPU CPR3
-+        regulator Which will always operate in open loop.
-+
-+config REGULATOR_CPR4_APSS
-+      bool "QCOM CPR4 regulator for APSS"
-+      depends on OF && REGULATOR_CPR3
-+      help
-+        This driver supports Qualcomm Technologies, Inc. APSS application
-+        processor specific features including memory array power mux (APM)
-+        switching, one CPR4 thread which monitor the two APSS clusters that
-+        are both powered by a shared supply, hardware closed-loop auto
-+        voltage stepping, voltage adjustments based on online core count,
-+        voltage adjustments based on temperature readings, and voltage
-+        adjustments for performance boost mode. This driver reads both initial
-+        voltage and CPR target quotient values out of hardware fuses.
-+
- endif
---- a/drivers/regulator/Makefile
-+++ b/drivers/regulator/Makefile
-@@ -121,6 +121,9 @@ obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qco
- obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
- obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
- obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
-+obj-$(CONFIG_REGULATOR_CPR3) += cpr3-regulator.o cpr3-util.o
-+obj-$(CONFIG_REGULATOR_CPR3_NPU) += cpr3-npu-regulator.o
-+obj-$(CONFIG_REGULATOR_CPR4_APSS) += cpr4-apss-regulator.o
- obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
- obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
- obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
---- /dev/null
-+++ b/drivers/regulator/cpr3-npu-regulator.c
-@@ -0,0 +1,689 @@
-+/*
-+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/slab.h>
-+#include <linux/thermal.h>
-+
-+#include "cpr3-regulator.h"
-+
-+#define IPQ807x_NPU_FUSE_CORNERS              2
-+#define IPQ817x_NPU_FUSE_CORNERS              1
-+#define IPQ807x_NPU_FUSE_STEP_VOLT            8000
-+#define IPQ807x_NPU_VOLTAGE_FUSE_SIZE         6
-+#define IPQ807x_NPU_CPR_CLOCK_RATE            19200000
-+
-+#define IPQ807x_NPU_CPR_TCSR_START            6
-+#define IPQ807x_NPU_CPR_TCSR_END              7
-+
-+#define NPU_TSENS                             5
-+
-+u32 g_valid_npu_fuse_count = IPQ807x_NPU_FUSE_CORNERS;
-+/**
-+ * struct cpr3_ipq807x_npu_fuses - NPU specific fuse data for IPQ807x
-+ * @init_voltage:     Initial (i.e. open-loop) voltage fuse parameter value
-+ *                    for each fuse corner (raw, not converted to a voltage)
-+ * This struct holds the values for all of the fuses read from memory.
-+ */
-+struct cpr3_ipq807x_npu_fuses {
-+      u64     init_voltage[IPQ807x_NPU_FUSE_CORNERS];
-+};
-+
-+/*
-+ * Constants which define the name of each fuse corner.
-+ */
-+enum cpr3_ipq807x_npu_fuse_corner {
-+      CPR3_IPQ807x_NPU_FUSE_CORNER_NOM        = 0,
-+      CPR3_IPQ807x_NPU_FUSE_CORNER_TURBO      = 1,
-+};
-+
-+static const char * const cpr3_ipq807x_npu_fuse_corner_name[] = {
-+      [CPR3_IPQ807x_NPU_FUSE_CORNER_NOM]      = "NOM",
-+      [CPR3_IPQ807x_NPU_FUSE_CORNER_TURBO]    = "TURBO",
-+};
-+
-+/*
-+ * IPQ807x NPU fuse parameter locations:
-+ *
-+ * Structs are organized with the following dimensions:
-+ *    Outer: 0 to 1 for fuse corners from lowest to highest corner
-+ *    Inner: large enough to hold the longest set of parameter segments which
-+ *            fully defines a fuse parameter, +1 (for NULL termination).
-+ *            Each segment corresponds to a contiguous group of bits from a
-+ *            single fuse row.  These segments are concatentated together in
-+ *            order to form the full fuse parameter value.  The segments for
-+ *            a given parameter may correspond to different fuse rows.
-+ */
-+static struct cpr3_fuse_param
-+ipq807x_npu_init_voltage_param[IPQ807x_NPU_FUSE_CORNERS][2] = {
-+      {{73, 22, 27}, {} },
-+      {{73, 16, 21}, {} },
-+};
-+
-+/*
-+ * Open loop voltage fuse reference voltages in microvolts for IPQ807x
-+ */
-+static int
-+ipq807x_npu_fuse_ref_volt [IPQ807x_NPU_FUSE_CORNERS] = {
-+      912000,
-+      992000,
-+};
-+
-+/*
-+ * IPQ9574 (Few parameters are changed, remaining are same as IPQ807x)
-+ */
-+#define IPQ9574_NPU_FUSE_CORNERS              2
-+#define IPQ9574_NPU_FUSE_STEP_VOLT            10000
-+#define IPQ9574_NPU_CPR_CLOCK_RATE            24000000
-+
-+/*
-+ * fues parameters for IPQ9574
-+ */
-+static struct cpr3_fuse_param
-+ipq9574_npu_init_voltage_param[IPQ9574_NPU_FUSE_CORNERS][2] = {
-+      {{105, 12, 17}, {} },
-+      {{105,  6, 11}, {} },
-+};
-+
-+/*
-+ * Open loop voltage fuse reference voltages in microvolts for IPQ9574
-+ */
-+static int
-+ipq9574_npu_fuse_ref_volt [IPQ9574_NPU_FUSE_CORNERS] = {
-+      862500,
-+      987500,
-+};
-+
-+struct cpr3_controller *g_ctrl;
-+
-+void cpr3_npu_temp_notify(int sensor, int temp, int low_notif)
-+{
-+      u32 prev_sensor_state;
-+
-+      if (sensor != NPU_TSENS)
-+              return;
-+
-+      prev_sensor_state = g_ctrl->cur_sensor_state;
-+      if (low_notif)
-+              g_ctrl->cur_sensor_state |= BIT(sensor);
-+      else
-+              g_ctrl->cur_sensor_state &= ~BIT(sensor);
-+
-+      if (!prev_sensor_state && g_ctrl->cur_sensor_state)
-+              cpr3_handle_temp_open_loop_adjustment(g_ctrl, true);
-+      else if (prev_sensor_state && !g_ctrl->cur_sensor_state)
-+              cpr3_handle_temp_open_loop_adjustment(g_ctrl, false);
-+}
-+
-+/**
-+ * cpr3_ipq807x_npu_read_fuse_data() - load NPU specific fuse parameter values
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function allocates a cpr3_ipq807x_npu_fuses struct, fills it with
-+ * values read out of hardware fuses, and finally copies common fuse values
-+ * into the CPR3 regulator struct.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_ipq807x_npu_read_fuse_data(struct cpr3_regulator *vreg)
-+{
-+      void __iomem *base = vreg->thread->ctrl->fuse_base;
-+      struct cpr3_ipq807x_npu_fuses *fuse;
-+      int i, rc;
-+
-+      fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
-+      if (!fuse)
-+              return -ENOMEM;
-+
-+      for (i = 0; i < g_valid_npu_fuse_count; i++) {
-+              rc = cpr3_read_fuse_param(base,
-+                                        vreg->cpr3_regulator_data->init_voltage_param[i],
-+                                        &fuse->init_voltage[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
-+                               i, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      vreg->fuse_corner_count = g_valid_npu_fuse_count;
-+      vreg->platform_fuses    = fuse;
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_npu_parse_corner_data() - parse NPU corner data from device tree
-+ *            properties of the CPR3 regulator's device node
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_npu_parse_corner_data(struct cpr3_regulator *vreg)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_common_corner_data(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_ipq807x_npu_calculate_open_loop_voltages() - calculate the open-loop
-+ *            voltage for each corner of a CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @temp_correction:    Temperature based correction
-+ *
-+ * If open-loop voltage interpolation is allowed in device tree, then
-+ * this function calculates the open-loop voltage for a given corner using
-+ * linear interpolation.  This interpolation is performed using the processor
-+ * frequencies of the lower and higher Fmax corners along with their fused
-+ * open-loop voltages.
-+ *
-+ * If open-loop voltage interpolation is not allowed, then this function uses
-+ * the Fmax fused open-loop voltage for all of the corners associated with a
-+ * given fuse corner.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_ipq807x_npu_calculate_open_loop_voltages(
-+                      struct cpr3_regulator *vreg, bool temp_correction)
-+{
-+      struct cpr3_ipq807x_npu_fuses *fuse = vreg->platform_fuses;
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      int i, j, rc = 0;
-+      u64 freq_low, volt_low, freq_high, volt_high;
-+      int *fuse_volt;
-+      int *fmax_corner;
-+
-+      fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
-+                          GFP_KERNEL);
-+      fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
-+                            GFP_KERNEL);
-+      if (!fuse_volt || !fmax_corner) {
-+              rc = -ENOMEM;
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->fuse_corner_count; i++) {
-+              if (ctrl->cpr_global_setting == CPR_DISABLED)
-+                      fuse_volt[i] = vreg->cpr3_regulator_data->fuse_ref_volt[i];
-+              else
-+                      fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
-+                              vreg->cpr3_regulator_data->fuse_ref_volt[i],
-+                              vreg->cpr3_regulator_data->fuse_step_volt,
-+                              fuse->init_voltage[i],
-+                              IPQ807x_NPU_VOLTAGE_FUSE_SIZE);
-+
-+              /* Log fused open-loop voltage values for debugging purposes. */
-+              cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n",
-+                        cpr3_ipq807x_npu_fuse_corner_name[i],
-+                        fuse_volt[i]);
-+      }
-+
-+      rc = cpr3_determine_part_type(vreg,
-+                      fuse_volt[CPR3_IPQ807x_NPU_FUSE_CORNER_TURBO]);
-+      if (rc) {
-+              cpr3_err(vreg,
-+                      "fused part type detection failed failed, rc=%d\n", rc);
-+              goto done;
-+      }
-+
-+      rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
-+      if (rc) {
-+              cpr3_err(vreg,
-+                      "fused open-loop voltage adjustment failed, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+      if (temp_correction) {
-+              rc = cpr3_determine_temp_base_open_loop_correction(vreg,
-+                                                              fuse_volt);
-+              if (rc) {
-+                      cpr3_err(vreg,
-+                              "temp open-loop voltage adj. failed, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      for (i = 1; i < vreg->fuse_corner_count; i++) {
-+              if (fuse_volt[i] < fuse_volt[i - 1]) {
-+                      cpr3_info(vreg,
-+                              "fuse corner %d voltage=%d uV < fuse corner %d \
-+                              voltage=%d uV; overriding: fuse corner %d \
-+                              voltage=%d\n",
-+                                i, fuse_volt[i], i - 1, fuse_volt[i - 1],
-+                                i, fuse_volt[i - 1]);
-+                      fuse_volt[i] = fuse_volt[i - 1];
-+              }
-+      }
-+
-+      /* Determine highest corner mapped to each fuse corner */
-+      j = vreg->fuse_corner_count - 1;
-+      for (i = vreg->corner_count - 1; i >= 0; i--) {
-+              if (vreg->corner[i].cpr_fuse_corner == j) {
-+                      fmax_corner[j] = i;
-+                      j--;
-+              }
-+      }
-+
-+      if (j >= 0) {
-+              cpr3_err(vreg, "invalid fuse corner mapping\n");
-+              rc = -EINVAL;
-+              goto done;
-+      }
-+
-+      /*
-+       * Interpolation is not possible for corners mapped to the lowest fuse
-+       * corner so use the fuse corner value directly.
-+       */
-+      for (i = 0; i <= fmax_corner[0]; i++)
-+              vreg->corner[i].open_loop_volt = fuse_volt[0];
-+
-+      /* Interpolate voltages for the higher fuse corners. */
-+      for (i = 1; i < vreg->fuse_corner_count; i++) {
-+              freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
-+              volt_low = fuse_volt[i - 1];
-+              freq_high = vreg->corner[fmax_corner[i]].proc_freq;
-+              volt_high = fuse_volt[i];
-+
-+              for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
-+                      vreg->corner[j].open_loop_volt = cpr3_interpolate(
-+                              freq_low, volt_low, freq_high, volt_high,
-+                              vreg->corner[j].proc_freq);
-+      }
-+
-+done:
-+      if (rc == 0) {
-+              cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
-+              for (i = 0; i < vreg->corner_count; i++)
-+                      cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
-+                                 vreg->corner[i].open_loop_volt);
-+
-+              rc = cpr3_adjust_open_loop_voltages(vreg);
-+              if (rc)
-+                      cpr3_err(vreg,
-+                              "open-loop voltage adjustment failed, rc=%d\n",
-+                               rc);
-+      }
-+
-+      kfree(fuse_volt);
-+      kfree(fmax_corner);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_npu_print_settings() - print out NPU CPR configuration settings into
-+ *            the kernel log for debugging purposes
-+ * @vreg:             Pointer to the CPR3 regulator
-+ */
-+static void cpr3_npu_print_settings(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_corner *corner;
-+      int i;
-+
-+      cpr3_debug(vreg,
-+              "Corner: Frequency (Hz), Fuse Corner, Floor (uV), \
-+              Open-Loop (uV), Ceiling (uV)\n");
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              corner = &vreg->corner[i];
-+              cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
-+                         i, corner->proc_freq, corner->cpr_fuse_corner,
-+                         corner->floor_volt, corner->open_loop_volt,
-+                         corner->ceiling_volt);
-+      }
-+
-+      if (vreg->thread->ctrl->apm)
-+              cpr3_debug(vreg, "APM threshold = %d uV, APM adjust = %d uV\n",
-+                         vreg->thread->ctrl->apm_threshold_volt,
-+                         vreg->thread->ctrl->apm_adj_volt);
-+}
-+
-+/**
-+ * cpr3_ipq807x_npu_calc_temp_based_ol_voltages() - Calculate the open loop
-+ * voltages based on temperature based correction margins
-+ * @vreg:               Pointer to the CPR3 regulator
-+ */
-+
-+static int
-+cpr3_ipq807x_npu_calc_temp_based_ol_voltages(struct cpr3_regulator *vreg,
-+                                              bool temp_correction)
-+{
-+      int rc, i;
-+
-+      rc = cpr3_ipq807x_npu_calculate_open_loop_voltages(vreg,
-+                                                      temp_correction);
-+      if (rc) {
-+              cpr3_err(vreg,
-+                      "unable to calculate open-loop voltages, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_limit_open_loop_voltages(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      cpr3_open_loop_voltage_as_ceiling(vreg);
-+
-+      rc = cpr3_limit_floor_voltages(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              if (temp_correction)
-+                      vreg->corner[i].cold_temp_open_loop_volt =
-+                              vreg->corner[i].open_loop_volt;
-+              else
-+                      vreg->corner[i].normal_temp_open_loop_volt =
-+                              vreg->corner[i].open_loop_volt;
-+      }
-+
-+      cpr3_npu_print_settings(vreg);
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_npu_init_thread() - perform steps necessary to initialize the
-+ *            configuration data for a CPR3 thread
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_npu_init_thread(struct cpr3_thread *thread)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_common_thread_data(thread);
-+      if (rc) {
-+              cpr3_err(thread->ctrl,
-+                      "thread %u CPR thread data from DT- failed, rc=%d\n",
-+                       thread->thread_id, rc);
-+              return rc;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_npu_init_regulator() - perform all steps necessary to initialize the
-+ *            configuration data for a CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_npu_init_regulator(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_ipq807x_npu_fuses *fuse;
-+      int rc, cold_temp = 0;
-+      bool can_adj_cold_temp = cpr3_can_adjust_cold_temp(vreg);
-+
-+      rc = cpr3_ipq807x_npu_read_fuse_data(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      fuse = vreg->platform_fuses;
-+
-+      rc = cpr3_npu_parse_corner_data(vreg);
-+      if (rc) {
-+              cpr3_err(vreg,
-+                      "Cannot read CPR corner data from DT, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_mem_acc_init(vreg);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(vreg,
-+                      "Cannot initialize mem-acc regulator settings, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      if (can_adj_cold_temp) {
-+              rc = cpr3_ipq807x_npu_calc_temp_based_ol_voltages(vreg, true);
-+              if (rc) {
-+                      cpr3_err(vreg,
-+                      "unable to calculate open-loop voltages, rc=%d\n", rc);
-+                      return rc;
-+              }
-+      }
-+
-+      rc = cpr3_ipq807x_npu_calc_temp_based_ol_voltages(vreg, false);
-+      if (rc) {
-+              cpr3_err(vreg,
-+                      "unable to calculate open-loop voltages, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      if (can_adj_cold_temp) {
-+              cpr3_info(vreg,
-+              "Normal and Cold condition init done. Default to normal.\n");
-+
-+              rc = cpr3_get_cold_temp_threshold(vreg, &cold_temp);
-+              if (rc) {
-+                      cpr3_err(vreg,
-+                      "Get cold temperature threshold failed, rc=%d\n", rc);
-+                      return rc;
-+              }
-+              register_low_temp_notif(NPU_TSENS, cold_temp,
-+                                                      cpr3_npu_temp_notify);
-+      }
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_npu_init_controller() - perform NPU CPR3 controller specific
-+ *            initializations
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_npu_init_controller(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_open_loop_common_ctrl_data(ctrl);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
-+                               rc);
-+              return rc;
-+      }
-+
-+      ctrl->ctrl_type = CPR_CTRL_TYPE_CPR3;
-+      ctrl->supports_hw_closed_loop = false;
-+
-+      return 0;
-+}
-+
-+static const struct cpr3_reg_data ipq807x_cpr_npu = {
-+      .cpr_valid_fuse_count = IPQ807x_NPU_FUSE_CORNERS,
-+      .init_voltage_param = ipq807x_npu_init_voltage_param,
-+      .fuse_ref_volt = ipq807x_npu_fuse_ref_volt,
-+      .fuse_step_volt = IPQ807x_NPU_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ807x_NPU_CPR_CLOCK_RATE,
-+};
-+
-+static const struct cpr3_reg_data ipq817x_cpr_npu = {
-+      .cpr_valid_fuse_count = IPQ817x_NPU_FUSE_CORNERS,
-+      .init_voltage_param = ipq807x_npu_init_voltage_param,
-+      .fuse_ref_volt = ipq807x_npu_fuse_ref_volt,
-+      .fuse_step_volt = IPQ807x_NPU_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ807x_NPU_CPR_CLOCK_RATE,
-+};
-+
-+static const struct cpr3_reg_data ipq9574_cpr_npu = {
-+      .cpr_valid_fuse_count = IPQ9574_NPU_FUSE_CORNERS,
-+      .init_voltage_param = ipq9574_npu_init_voltage_param,
-+      .fuse_ref_volt = ipq9574_npu_fuse_ref_volt,
-+      .fuse_step_volt = IPQ9574_NPU_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ9574_NPU_CPR_CLOCK_RATE,
-+};
-+
-+static const struct of_device_id cpr3_regulator_match_table[] = {
-+      {
-+              .compatible = "qcom,cpr3-ipq807x-npu-regulator",
-+              .data = &ipq807x_cpr_npu
-+      },
-+      {
-+              .compatible = "qcom,cpr3-ipq817x-npu-regulator",
-+              .data = &ipq817x_cpr_npu
-+      },
-+      {
-+              .compatible = "qcom,cpr3-ipq9574-npu-regulator",
-+              .data = &ipq9574_cpr_npu
-+      },
-+      {}
-+};
-+
-+static int cpr3_npu_regulator_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct cpr3_controller *ctrl;
-+      int i, rc;
-+      const struct cpr3_reg_data *cpr_data;
-+
-+      if (!dev->of_node) {
-+              dev_err(dev, "Device tree node is missing\n");
-+              return -EINVAL;
-+      }
-+
-+      ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
-+      if (!ctrl)
-+              return -ENOMEM;
-+      g_ctrl = ctrl;
-+
-+      cpr_data = of_device_get_match_data(&pdev->dev);
-+      g_valid_npu_fuse_count = cpr_data->cpr_valid_fuse_count;
-+      dev_info(dev, "NPU CPR valid fuse count: %d\n", g_valid_npu_fuse_count);
-+      ctrl->cpr_clock_rate = cpr_data->cpr_clk_rate;
-+
-+      ctrl->dev = dev;
-+      /* Set to false later if anything precludes CPR operation. */
-+      ctrl->cpr_allowed_hw = true;
-+
-+      rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
-+                                   &ctrl->name);
-+      if (rc) {
-+              cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_map_fuse_base(ctrl, pdev);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not map fuse base address\n");
-+              return rc;
-+      }
-+
-+      rc = cpr3_read_tcsr_setting(ctrl, pdev, IPQ807x_NPU_CPR_TCSR_START,
-+                                  IPQ807x_NPU_CPR_TCSR_END);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not read CPR tcsr rsetting\n");
-+              return rc;
-+      }
-+
-+      rc = cpr3_allocate_threads(ctrl, 0, 0);
-+      if (rc) {
-+              cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      if (ctrl->thread_count != 1) {
-+              cpr3_err(ctrl, "expected 1 thread but found %d\n",
-+                       ctrl->thread_count);
-+              return -EINVAL;
-+      }
-+
-+      rc = cpr3_npu_init_controller(ctrl);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
-+                               rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_npu_init_thread(&ctrl->thread[0]);
-+      if (rc) {
-+              cpr3_err(ctrl, "thread initialization failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      for (i = 0; i < ctrl->thread[0].vreg_count; i++) {
-+              ctrl->thread[0].vreg[i].cpr3_regulator_data = cpr_data;
-+              rc = cpr3_npu_init_regulator(&ctrl->thread[0].vreg[i]);
-+              if (rc) {
-+                      cpr3_err(&ctrl->thread[0].vreg[i], "regulator initialization failed, rc=%d\n",
-+                               rc);
-+                      return rc;
-+              }
-+      }
-+
-+      platform_set_drvdata(pdev, ctrl);
-+
-+      return cpr3_open_loop_regulator_register(pdev, ctrl);
-+}
-+
-+static void cpr3_npu_regulator_remove(struct platform_device *pdev)
-+{
-+      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
-+
-+      cpr3_open_loop_regulator_unregister(ctrl);
-+}
-+
-+static struct platform_driver cpr3_npu_regulator_driver = {
-+      .driver         = {
-+              .name           = "qcom,cpr3-npu-regulator",
-+              .of_match_table = cpr3_regulator_match_table,
-+      },
-+      .probe          = cpr3_npu_regulator_probe,
-+      .remove         = cpr3_npu_regulator_remove,
-+};
-+
-+static int cpr3_regulator_init(void)
-+{
-+      return platform_driver_register(&cpr3_npu_regulator_driver);
-+}
-+arch_initcall(cpr3_regulator_init);
-+
-+static void cpr3_regulator_exit(void)
-+{
-+      platform_driver_unregister(&cpr3_npu_regulator_driver);
-+}
-+module_exit(cpr3_regulator_exit);
-+
-+MODULE_DESCRIPTION("QCOM CPR3 NPU regulator driver");
-+MODULE_LICENSE("Dual BSD/GPLv2");
-+MODULE_ALIAS("platform:npu-ipq807x");
---- /dev/null
-+++ b/drivers/regulator/cpr3-regulator.c
-@@ -0,0 +1,5111 @@
-+/*
-+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#define pr_fmt(fmt) "%s: " fmt, __func__
-+
-+#include <linux/bitops.h>
-+#include <linux/debugfs.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/ktime.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+#include <linux/slab.h>
-+#include <linux/sort.h>
-+#include <linux/string.h>
-+#include <linux/uaccess.h>
-+#include <linux/regulator/driver.h>
-+#include <linux/regulator/machine.h>
-+#include <linux/regulator/of_regulator.h>
-+#include <linux/panic_notifier.h>
-+
-+#include "cpr3-regulator.h"
-+
-+#define CPR3_REGULATOR_CORNER_INVALID (-1)
-+#define CPR3_RO_MASK                  GENMASK(CPR3_RO_COUNT - 1, 0)
-+
-+/* CPR3 registers */
-+#define CPR3_REG_CPR_CTL                      0x4
-+#define CPR3_CPR_CTL_LOOP_EN_MASK             BIT(0)
-+#define CPR3_CPR_CTL_LOOP_ENABLE              BIT(0)
-+#define CPR3_CPR_CTL_LOOP_DISABLE             0
-+#define CPR3_CPR_CTL_IDLE_CLOCKS_MASK         GENMASK(5, 1)
-+#define CPR3_CPR_CTL_IDLE_CLOCKS_SHIFT                1
-+#define CPR3_CPR_CTL_COUNT_MODE_MASK          GENMASK(7, 6)
-+#define CPR3_CPR_CTL_COUNT_MODE_SHIFT         6
-+#define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN       0
-+#define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MAX       1
-+#define CPR3_CPR_CTL_COUNT_MODE_STAGGERED     2
-+#define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_AGE       3
-+#define CPR3_CPR_CTL_COUNT_REPEAT_MASK                GENMASK(31, 9)
-+#define CPR3_CPR_CTL_COUNT_REPEAT_SHIFT               9
-+
-+#define CPR3_REG_CPR_STATUS                   0x8
-+#define CPR3_CPR_STATUS_BUSY_MASK             BIT(0)
-+#define CPR3_CPR_STATUS_AGING_MEASUREMENT_MASK        BIT(1)
-+
-+/*
-+ * This register is not present on controllers that support HW closed-loop
-+ * except CPR4 APSS controller.
-+ */
-+#define CPR3_REG_CPR_TIMER_AUTO_CONT          0xC
-+
-+#define CPR3_REG_CPR_STEP_QUOT                        0x14
-+#define CPR3_CPR_STEP_QUOT_MIN_MASK           GENMASK(5, 0)
-+#define CPR3_CPR_STEP_QUOT_MIN_SHIFT          0
-+#define CPR3_CPR_STEP_QUOT_MAX_MASK           GENMASK(11, 6)
-+#define CPR3_CPR_STEP_QUOT_MAX_SHIFT          6
-+
-+#define CPR3_REG_GCNT(ro)                     (0xA0 + 0x4 * (ro))
-+
-+#define CPR3_REG_SENSOR_BYPASS_WRITE(sensor)  (0xE0 + 0x4 * ((sensor) / 32))
-+#define CPR3_REG_SENSOR_BYPASS_WRITE_BANK(bank)       (0xE0 + 0x4 * (bank))
-+
-+#define CPR3_REG_SENSOR_MASK_WRITE(sensor)    (0x120 + 0x4 * ((sensor) / 32))
-+#define CPR3_REG_SENSOR_MASK_WRITE_BANK(bank) (0x120 + 0x4 * (bank))
-+#define CPR3_REG_SENSOR_MASK_READ(sensor)     (0x140 + 0x4 * ((sensor) / 32))
-+
-+#define CPR3_REG_SENSOR_OWNER(sensor) (0x200 + 0x4 * (sensor))
-+
-+#define CPR3_REG_CONT_CMD             0x800
-+#define CPR3_CONT_CMD_ACK             0x1
-+#define CPR3_CONT_CMD_NACK            0x0
-+
-+#define CPR3_REG_THRESH(thread)               (0x808 + 0x440 * (thread))
-+#define CPR3_THRESH_CONS_DOWN_MASK    GENMASK(3, 0)
-+#define CPR3_THRESH_CONS_DOWN_SHIFT   0
-+#define CPR3_THRESH_CONS_UP_MASK      GENMASK(7, 4)
-+#define CPR3_THRESH_CONS_UP_SHIFT     4
-+#define CPR3_THRESH_DOWN_THRESH_MASK  GENMASK(12, 8)
-+#define CPR3_THRESH_DOWN_THRESH_SHIFT 8
-+#define CPR3_THRESH_UP_THRESH_MASK    GENMASK(17, 13)
-+#define CPR3_THRESH_UP_THRESH_SHIFT   13
-+
-+#define CPR3_REG_RO_MASK(thread)      (0x80C + 0x440 * (thread))
-+
-+#define CPR3_REG_RESULT0(thread)      (0x810 + 0x440 * (thread))
-+#define CPR3_RESULT0_BUSY_MASK                BIT(0)
-+#define CPR3_RESULT0_STEP_DN_MASK     BIT(1)
-+#define CPR3_RESULT0_STEP_UP_MASK     BIT(2)
-+#define CPR3_RESULT0_ERROR_STEPS_MASK GENMASK(7, 3)
-+#define CPR3_RESULT0_ERROR_STEPS_SHIFT        3
-+#define CPR3_RESULT0_ERROR_MASK               GENMASK(19, 8)
-+#define CPR3_RESULT0_ERROR_SHIFT      8
-+#define CPR3_RESULT0_NEGATIVE_MASK    BIT(20)
-+
-+#define CPR3_REG_RESULT1(thread)      (0x814 + 0x440 * (thread))
-+#define CPR3_RESULT1_QUOT_MIN_MASK    GENMASK(11, 0)
-+#define CPR3_RESULT1_QUOT_MIN_SHIFT   0
-+#define CPR3_RESULT1_QUOT_MAX_MASK    GENMASK(23, 12)
-+#define CPR3_RESULT1_QUOT_MAX_SHIFT   12
-+#define CPR3_RESULT1_RO_MIN_MASK      GENMASK(27, 24)
-+#define CPR3_RESULT1_RO_MIN_SHIFT     24
-+#define CPR3_RESULT1_RO_MAX_MASK      GENMASK(31, 28)
-+#define CPR3_RESULT1_RO_MAX_SHIFT     28
-+
-+#define CPR3_REG_RESULT2(thread)              (0x818 + 0x440 * (thread))
-+#define CPR3_RESULT2_STEP_QUOT_MIN_MASK               GENMASK(5, 0)
-+#define CPR3_RESULT2_STEP_QUOT_MIN_SHIFT      0
-+#define CPR3_RESULT2_STEP_QUOT_MAX_MASK               GENMASK(11, 6)
-+#define CPR3_RESULT2_STEP_QUOT_MAX_SHIFT      6
-+#define CPR3_RESULT2_SENSOR_MIN_MASK          GENMASK(23, 16)
-+#define CPR3_RESULT2_SENSOR_MIN_SHIFT         16
-+#define CPR3_RESULT2_SENSOR_MAX_MASK          GENMASK(31, 24)
-+#define CPR3_RESULT2_SENSOR_MAX_SHIFT         24
-+
-+#define CPR3_REG_IRQ_EN                       0x81C
-+#define CPR3_REG_IRQ_CLEAR            0x820
-+#define CPR3_REG_IRQ_STATUS           0x824
-+#define CPR3_IRQ_UP                   BIT(3)
-+#define CPR3_IRQ_MID                  BIT(2)
-+#define CPR3_IRQ_DOWN                 BIT(1)
-+
-+#define CPR3_REG_TARGET_QUOT(thread, ro) \
-+                                      (0x840 + 0x440 * (thread) + 0x4 * (ro))
-+
-+/* Registers found only on controllers that support HW closed-loop. */
-+#define CPR3_REG_PD_THROTTLE          0xE8
-+#define CPR3_PD_THROTTLE_DISABLE      0x0
-+
-+#define CPR3_REG_HW_CLOSED_LOOP               0x3000
-+#define CPR3_HW_CLOSED_LOOP_ENABLE    0x0
-+#define CPR3_HW_CLOSED_LOOP_DISABLE   0x1
-+
-+#define CPR3_REG_CPR_TIMER_MID_CONT   0x3004
-+#define CPR3_REG_CPR_TIMER_UP_DN_CONT 0x3008
-+
-+#define CPR3_REG_LAST_MEASUREMENT             0x7F8
-+#define CPR3_LAST_MEASUREMENT_THREAD_DN_SHIFT 0
-+#define CPR3_LAST_MEASUREMENT_THREAD_UP_SHIFT 4
-+#define CPR3_LAST_MEASUREMENT_THREAD_DN(thread) \
-+              (BIT(thread) << CPR3_LAST_MEASUREMENT_THREAD_DN_SHIFT)
-+#define CPR3_LAST_MEASUREMENT_THREAD_UP(thread) \
-+              (BIT(thread) << CPR3_LAST_MEASUREMENT_THREAD_UP_SHIFT)
-+#define CPR3_LAST_MEASUREMENT_AGGR_DN         BIT(8)
-+#define CPR3_LAST_MEASUREMENT_AGGR_MID                BIT(9)
-+#define CPR3_LAST_MEASUREMENT_AGGR_UP         BIT(10)
-+#define CPR3_LAST_MEASUREMENT_VALID           BIT(11)
-+#define CPR3_LAST_MEASUREMENT_SAW_ERROR               BIT(12)
-+#define CPR3_LAST_MEASUREMENT_PD_BYPASS_MASK  GENMASK(23, 16)
-+#define CPR3_LAST_MEASUREMENT_PD_BYPASS_SHIFT 16
-+
-+/* CPR4 controller specific registers and bit definitions */
-+#define CPR4_REG_CPR_TIMER_CLAMP                      0x10
-+#define CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN    BIT(27)
-+
-+#define CPR4_REG_MISC                         0x700
-+#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK        GENMASK(23, 20)
-+#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT       20
-+#define CPR4_MISC_TEMP_SENSOR_ID_START_MASK   GENMASK(27, 24)
-+#define CPR4_MISC_TEMP_SENSOR_ID_START_SHIFT  24
-+#define CPR4_MISC_TEMP_SENSOR_ID_END_MASK     GENMASK(31, 28)
-+#define CPR4_MISC_TEMP_SENSOR_ID_END_SHIFT    28
-+
-+#define CPR4_REG_SAW_ERROR_STEP_LIMIT         0x7A4
-+#define CPR4_SAW_ERROR_STEP_LIMIT_UP_MASK     GENMASK(4, 0)
-+#define CPR4_SAW_ERROR_STEP_LIMIT_UP_SHIFT    0
-+#define CPR4_SAW_ERROR_STEP_LIMIT_DN_MASK     GENMASK(9, 5)
-+#define CPR4_SAW_ERROR_STEP_LIMIT_DN_SHIFT    5
-+
-+#define CPR4_REG_MARGIN_TEMP_CORE_TIMERS                      0x7A8
-+#define CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_MASK        GENMASK(28, 18)
-+#define CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_SHIFT       18
-+
-+#define CPR4_REG_MARGIN_TEMP_CORE(core)               (0x7AC + 0x4 * (core))
-+#define CPR4_MARGIN_TEMP_CORE_ADJ_MASK                GENMASK(7, 0)
-+#define CPR4_MARGIN_TEMP_CORE_ADJ_SHIFT               8
-+
-+#define CPR4_REG_MARGIN_TEMP_POINT0N1         0x7F0
-+#define CPR4_MARGIN_TEMP_POINT0_MASK          GENMASK(11, 0)
-+#define CPR4_MARGIN_TEMP_POINT0_SHIFT         0
-+#define CPR4_MARGIN_TEMP_POINT1_MASK          GENMASK(23, 12)
-+#define CPR4_MARGIN_TEMP_POINT1_SHIFT         12
-+#define CPR4_REG_MARGIN_TEMP_POINT2           0x7F4
-+#define CPR4_MARGIN_TEMP_POINT2_MASK          GENMASK(11, 0)
-+#define CPR4_MARGIN_TEMP_POINT2_SHIFT         0
-+
-+#define CPR4_REG_MARGIN_ADJ_CTL                                       0x7F8
-+#define CPR4_MARGIN_ADJ_CTL_BOOST_EN                          BIT(0)
-+#define CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN                               BIT(1)
-+#define CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN                               BIT(2)
-+#define CPR4_MARGIN_ADJ_CTL_TIMER_SETTLE_VOLTAGE_EN           BIT(3)
-+#define CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK            BIT(4)
-+#define CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE             BIT(4)
-+#define CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE            0
-+#define CPR4_MARGIN_ADJ_CTL_PER_RO_KV_MARGIN_EN                       BIT(7)
-+#define CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN                  BIT(8)
-+#define CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_MASK                       GENMASK(16, 12)
-+#define CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_SHIFT              12
-+#define CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_MASK            GENMASK(21, 19)
-+#define CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_SHIFT           19
-+#define CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_MASK                        GENMASK(25, 22)
-+#define CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_SHIFT                       22
-+#define CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_MASK      GENMASK(31, 26)
-+#define CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_SHIFT     26
-+
-+#define CPR4_REG_CPR_MASK_THREAD(thread)      (0x80C + 0x440 * (thread))
-+#define CPR4_CPR_MASK_THREAD_DISABLE_THREAD           BIT(31)
-+#define CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK      GENMASK(15, 0)
-+
-+/*
-+ * The amount of time to wait for the CPR controller to become idle when
-+ * performing an aging measurement.
-+ */
-+#define CPR3_AGING_MEASUREMENT_TIMEOUT_NS     5000000
-+
-+/*
-+ * The number of individual aging measurements to perform which are then
-+ * averaged together in order to determine the final aging adjustment value.
-+ */
-+#define CPR3_AGING_MEASUREMENT_ITERATIONS     16
-+
-+/*
-+ * Aging measurements for the aged and unaged ring oscillators take place a few
-+ * microseconds apart.  If the vdd-supply voltage fluctuates between the two
-+ * measurements, then the difference between them will be incorrect.  The
-+ * difference could end up too high or too low.  This constant defines the
-+ * number of lowest and highest measurements to ignore when averaging.
-+ */
-+#define CPR3_AGING_MEASUREMENT_FILTER         3
-+
-+/*
-+ * The number of times to attempt the full aging measurement sequence before
-+ * declaring a measurement failure.
-+ */
-+#define CPR3_AGING_RETRY_COUNT                        5
-+
-+/*
-+ * The maximum time to wait in microseconds for a CPR register write to
-+ * complete.
-+ */
-+#define CPR3_REGISTER_WRITE_DELAY_US          200
-+
-+static DEFINE_MUTEX(cpr3_controller_list_mutex);
-+static LIST_HEAD(cpr3_controller_list);
-+static struct dentry *cpr3_debugfs_base;
-+
-+/**
-+ * cpr3_read() - read four bytes from the memory address specified
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @offset:           Offset in bytes from the CPR3 controller's base address
-+ *
-+ * Return: memory address value
-+ */
-+static inline u32 cpr3_read(struct cpr3_controller *ctrl, u32 offset)
-+{
-+      if (!ctrl->cpr_enabled) {
-+              cpr3_err(ctrl, "CPR register reads are not possible when CPR clocks are disabled\n");
-+              return 0;
-+      }
-+
-+      return readl_relaxed(ctrl->cpr_ctrl_base + offset);
-+}
-+
-+/**
-+ * cpr3_write() - write four bytes to the memory address specified
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @offset:           Offset in bytes from the CPR3 controller's base address
-+ * @value:            Value to write to the memory address
-+ *
-+ * Return: none
-+ */
-+static inline void cpr3_write(struct cpr3_controller *ctrl, u32 offset,
-+                              u32 value)
-+{
-+      if (!ctrl->cpr_enabled) {
-+              cpr3_err(ctrl, "CPR register writes are not possible when CPR clocks are disabled\n");
-+              return;
-+      }
-+
-+      writel_relaxed(value, ctrl->cpr_ctrl_base + offset);
-+}
-+
-+/**
-+ * cpr3_masked_write() - perform a read-modify-write sequence so that only
-+ *            masked bits are modified
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @offset:           Offset in bytes from the CPR3 controller's base address
-+ * @mask:             Mask identifying the bits that should be modified
-+ * @value:            Value to write to the memory address
-+ *
-+ * Return: none
-+ */
-+static inline void cpr3_masked_write(struct cpr3_controller *ctrl, u32 offset,
-+                              u32 mask, u32 value)
-+{
-+      u32 reg_val, orig_val;
-+
-+      if (!ctrl->cpr_enabled) {
-+              cpr3_err(ctrl, "CPR register writes are not possible when CPR clocks are disabled\n");
-+              return;
-+      }
-+
-+      reg_val = orig_val = readl_relaxed(ctrl->cpr_ctrl_base + offset);
-+      reg_val &= ~mask;
-+      reg_val |= value & mask;
-+
-+      if (reg_val != orig_val)
-+              writel_relaxed(reg_val, ctrl->cpr_ctrl_base + offset);
-+}
-+
-+/**
-+ * cpr3_ctrl_loop_enable() - enable the CPR sensing loop for a given controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: none
-+ */
-+static inline void cpr3_ctrl_loop_enable(struct cpr3_controller *ctrl)
-+{
-+      if (ctrl->cpr_enabled && !(ctrl->aggr_corner.sdelta
-+              && ctrl->aggr_corner.sdelta->allow_boost))
-+              cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
-+                      CPR3_CPR_CTL_LOOP_EN_MASK, CPR3_CPR_CTL_LOOP_ENABLE);
-+}
-+
-+/**
-+ * cpr3_ctrl_loop_disable() - disable the CPR sensing loop for a given
-+ *            controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: none
-+ */
-+static inline void cpr3_ctrl_loop_disable(struct cpr3_controller *ctrl)
-+{
-+      if (ctrl->cpr_enabled)
-+              cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
-+                      CPR3_CPR_CTL_LOOP_EN_MASK, CPR3_CPR_CTL_LOOP_DISABLE);
-+}
-+
-+/**
-+ * cpr3_clock_enable() - prepare and enable all clocks used by this CPR3
-+ *            controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_clock_enable(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      rc = clk_prepare_enable(ctrl->bus_clk);
-+      if (rc) {
-+              cpr3_err(ctrl, "failed to enable bus clock, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      rc = clk_prepare_enable(ctrl->iface_clk);
-+      if (rc) {
-+              cpr3_err(ctrl, "failed to enable interface clock, rc=%d\n", rc);
-+              clk_disable_unprepare(ctrl->bus_clk);
-+              return rc;
-+      }
-+
-+      rc = clk_prepare_enable(ctrl->core_clk);
-+      if (rc) {
-+              cpr3_err(ctrl, "failed to enable core clock, rc=%d\n", rc);
-+              clk_disable_unprepare(ctrl->iface_clk);
-+              clk_disable_unprepare(ctrl->bus_clk);
-+              return rc;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_clock_disable() - disable and unprepare all clocks used by this CPR3
-+ *            controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: none
-+ */
-+static void cpr3_clock_disable(struct cpr3_controller *ctrl)
-+{
-+      clk_disable_unprepare(ctrl->core_clk);
-+      clk_disable_unprepare(ctrl->iface_clk);
-+      clk_disable_unprepare(ctrl->bus_clk);
-+}
-+
-+/**
-+ * cpr3_ctrl_clear_cpr4_config() - clear the CPR4 register configuration
-+ *            programmed for current aggregated corner of a given controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static inline int cpr3_ctrl_clear_cpr4_config(struct cpr3_controller *ctrl)
-+{
-+      struct cpr4_sdelta *aggr_sdelta = ctrl->aggr_corner.sdelta;
-+      bool cpr_enabled = ctrl->cpr_enabled;
-+      int i, rc = 0;
-+
-+      if (!aggr_sdelta || !(aggr_sdelta->allow_core_count_adj
-+              || aggr_sdelta->allow_temp_adj || aggr_sdelta->allow_boost))
-+              /* cpr4 features are not enabled */
-+              return 0;
-+
-+      /* Ensure that CPR clocks are enabled before writing to registers. */
-+      if (!cpr_enabled) {
-+              rc = cpr3_clock_enable(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
-+                      return rc;
-+              }
-+              ctrl->cpr_enabled = true;
-+      }
-+
-+      /*
-+       * Clear feature enable configuration made for current
-+       * aggregated corner.
-+       */
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+              CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_MASK
-+              | CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN
-+              | CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN
-+              | CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN
-+              | CPR4_MARGIN_ADJ_CTL_BOOST_EN
-+              | CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK, 0);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MISC,
-+                      CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK,
-+                      0 << CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT);
-+
-+      for (i = 0; i <= aggr_sdelta->max_core_count; i++) {
-+              /* Clear voltage margin adjustments programmed in TEMP_COREi */
-+              cpr3_write(ctrl, CPR4_REG_MARGIN_TEMP_CORE(i), 0);
-+      }
-+
-+      /* Turn off CPR clocks if they were off before this function call. */
-+      if (!cpr_enabled) {
-+              cpr3_clock_disable(ctrl);
-+              ctrl->cpr_enabled = false;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_closed_loop_enable() - enable logical CPR closed-loop operation
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_closed_loop_enable(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      if (!ctrl->cpr_allowed_hw || !ctrl->cpr_allowed_sw) {
-+              cpr3_err(ctrl, "cannot enable closed-loop CPR operation because it is disallowed\n");
-+              return -EPERM;
-+      } else if (ctrl->cpr_enabled) {
-+              /* Already enabled */
-+              return 0;
-+      } else if (ctrl->cpr_suspended) {
-+              /*
-+               * CPR must remain disabled as the system is entering suspend.
-+               */
-+              return 0;
-+      }
-+
-+      rc = cpr3_clock_enable(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "unable to enable CPR clocks, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      ctrl->cpr_enabled = true;
-+      cpr3_debug(ctrl, "CPR closed-loop operation enabled\n");
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_closed_loop_disable() - disable logical CPR closed-loop operation
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static inline int cpr3_closed_loop_disable(struct cpr3_controller *ctrl)
-+{
-+      if (!ctrl->cpr_enabled) {
-+              /* Already disabled */
-+              return 0;
-+      }
-+
-+      cpr3_clock_disable(ctrl);
-+      ctrl->cpr_enabled = false;
-+      cpr3_debug(ctrl, "CPR closed-loop operation disabled\n");
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_get_gcnt() - returns the GCNT register value corresponding
-+ *            to the clock rate and sensor time of the CPR3 controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: GCNT value
-+ */
-+static u32 cpr3_regulator_get_gcnt(struct cpr3_controller *ctrl)
-+{
-+      u64 temp;
-+      unsigned int remainder;
-+      u32 gcnt;
-+
-+      temp = (u64)ctrl->cpr_clock_rate * (u64)ctrl->sensor_time;
-+      remainder = do_div(temp, 1000000000);
-+      if (remainder)
-+              temp++;
-+      /*
-+       * GCNT == 0 corresponds to a single ref clock measurement interval so
-+       * offset GCNT values by 1.
-+       */
-+      gcnt = temp - 1;
-+
-+      return gcnt;
-+}
-+
-+/**
-+ * cpr3_regulator_init_thread() - performs hardware initialization of CPR
-+ *            thread registers
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * CPR interface/bus clocks must be enabled before calling this function.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_init_thread(struct cpr3_thread *thread)
-+{
-+      u32 reg;
-+
-+      reg = (thread->consecutive_up << CPR3_THRESH_CONS_UP_SHIFT)
-+              & CPR3_THRESH_CONS_UP_MASK;
-+      reg |= (thread->consecutive_down << CPR3_THRESH_CONS_DOWN_SHIFT)
-+              & CPR3_THRESH_CONS_DOWN_MASK;
-+      reg |= (thread->up_threshold << CPR3_THRESH_UP_THRESH_SHIFT)
-+              & CPR3_THRESH_UP_THRESH_MASK;
-+      reg |= (thread->down_threshold << CPR3_THRESH_DOWN_THRESH_SHIFT)
-+              & CPR3_THRESH_DOWN_THRESH_MASK;
-+
-+      cpr3_write(thread->ctrl, CPR3_REG_THRESH(thread->thread_id), reg);
-+
-+      /*
-+       * Mask all RO's initially so that unused thread doesn't contribute
-+       * to closed-loop voltage.
-+       */
-+      cpr3_write(thread->ctrl, CPR3_REG_RO_MASK(thread->thread_id),
-+              CPR3_RO_MASK);
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr4_regulator_init_temp_points() - performs hardware initialization of CPR4
-+ *            registers to track tsen temperature data and also specify the
-+ *            temperature band range values to apply different voltage margins
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * CPR interface/bus clocks must be enabled before calling this function.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_regulator_init_temp_points(struct cpr3_controller *ctrl)
-+{
-+      if (!ctrl->allow_temp_adj)
-+              return 0;
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MISC,
-+                              CPR4_MISC_TEMP_SENSOR_ID_START_MASK,
-+                              ctrl->temp_sensor_id_start
-+                              << CPR4_MISC_TEMP_SENSOR_ID_START_SHIFT);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MISC,
-+                              CPR4_MISC_TEMP_SENSOR_ID_END_MASK,
-+                              ctrl->temp_sensor_id_end
-+                              << CPR4_MISC_TEMP_SENSOR_ID_END_SHIFT);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_POINT2,
-+              CPR4_MARGIN_TEMP_POINT2_MASK,
-+              (ctrl->temp_band_count == 4 ? ctrl->temp_points[2] : 0x7FF)
-+              << CPR4_MARGIN_TEMP_POINT2_SHIFT);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_POINT0N1,
-+              CPR4_MARGIN_TEMP_POINT1_MASK,
-+              (ctrl->temp_band_count >= 3 ? ctrl->temp_points[1] : 0x7FF)
-+              << CPR4_MARGIN_TEMP_POINT1_SHIFT);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_POINT0N1,
-+              CPR4_MARGIN_TEMP_POINT0_MASK,
-+              (ctrl->temp_band_count >= 2 ? ctrl->temp_points[0] : 0x7FF)
-+              << CPR4_MARGIN_TEMP_POINT0_SHIFT);
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_init_cpr4() - performs hardware initialization at the
-+ *            controller and thread level required for CPR4 operation.
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * CPR interface/bus clocks must be enabled before calling this function.
-+ * This function allocates sdelta structures and sdelta tables for aggregated
-+ * corners of the controller and its threads.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_init_cpr4(struct cpr3_controller *ctrl)
-+{
-+      struct cpr3_thread *thread;
-+      struct cpr3_regulator *vreg;
-+      struct cpr4_sdelta *sdelta;
-+      int i, j, ctrl_max_core_count, thread_max_core_count, rc = 0;
-+      bool ctrl_valid_sdelta, thread_valid_sdelta;
-+      u32 pmic_step_size = 1;
-+      int thread_id = 0;
-+      u64 temp;
-+
-+      if (ctrl->supports_hw_closed_loop) {
-+              if (ctrl->saw_use_unit_mV)
-+                      pmic_step_size = ctrl->step_volt / 1000;
-+              cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                                CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_MASK,
-+                                (pmic_step_size
-+                                << CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_SHIFT));
-+
-+              cpr3_masked_write(ctrl, CPR4_REG_SAW_ERROR_STEP_LIMIT,
-+                                CPR4_SAW_ERROR_STEP_LIMIT_DN_MASK,
-+                                (ctrl->down_error_step_limit
-+                                      << CPR4_SAW_ERROR_STEP_LIMIT_DN_SHIFT));
-+
-+              cpr3_masked_write(ctrl, CPR4_REG_SAW_ERROR_STEP_LIMIT,
-+                                CPR4_SAW_ERROR_STEP_LIMIT_UP_MASK,
-+                                (ctrl->up_error_step_limit
-+                                      << CPR4_SAW_ERROR_STEP_LIMIT_UP_SHIFT));
-+
-+              /*
-+               * Enable thread aggregation regardless of which threads are
-+               * enabled or disabled.
-+               */
-+              cpr3_masked_write(ctrl, CPR4_REG_CPR_TIMER_CLAMP,
-+                                CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN,
-+                                CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN);
-+
-+              switch (ctrl->thread_count) {
-+              case 0:
-+                      /* Disable both threads */
-+                      cpr3_masked_write(ctrl, CPR4_REG_CPR_MASK_THREAD(0),
-+                              CPR4_CPR_MASK_THREAD_DISABLE_THREAD
-+                                  | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK,
-+                              CPR4_CPR_MASK_THREAD_DISABLE_THREAD
-+                                  | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK);
-+
-+                      cpr3_masked_write(ctrl, CPR4_REG_CPR_MASK_THREAD(1),
-+                              CPR4_CPR_MASK_THREAD_DISABLE_THREAD
-+                                  | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK,
-+                              CPR4_CPR_MASK_THREAD_DISABLE_THREAD
-+                                  | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK);
-+                      break;
-+              case 1:
-+                      /* Disable unused thread */
-+                      thread_id = ctrl->thread[0].thread_id ? 0 : 1;
-+                      cpr3_masked_write(ctrl,
-+                              CPR4_REG_CPR_MASK_THREAD(thread_id),
-+                              CPR4_CPR_MASK_THREAD_DISABLE_THREAD
-+                                  | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK,
-+                              CPR4_CPR_MASK_THREAD_DISABLE_THREAD
-+                                  | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK);
-+                      break;
-+              }
-+      }
-+
-+      if (!ctrl->allow_core_count_adj && !ctrl->allow_temp_adj
-+              && !ctrl->allow_boost) {
-+              /*
-+               * Skip below configuration as none of the features
-+               * are enabled.
-+               */
-+              return rc;
-+      }
-+
-+      if (ctrl->supports_hw_closed_loop)
-+              cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                                CPR4_MARGIN_ADJ_CTL_TIMER_SETTLE_VOLTAGE_EN,
-+                                CPR4_MARGIN_ADJ_CTL_TIMER_SETTLE_VOLTAGE_EN);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                      CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_MASK,
-+                      ctrl->step_quot_fixed
-+                      << CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_SHIFT);
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                      CPR4_MARGIN_ADJ_CTL_PER_RO_KV_MARGIN_EN,
-+                      (ctrl->use_dynamic_step_quot
-+                      ? CPR4_MARGIN_ADJ_CTL_PER_RO_KV_MARGIN_EN : 0));
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                      CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_MASK,
-+                      ctrl->initial_temp_band
-+                      << CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_SHIFT);
-+
-+      rc = cpr4_regulator_init_temp_points(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "initialize temp points failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      if (ctrl->voltage_settling_time) {
-+              /*
-+               * Configure the settling timer used to account for
-+               * one VDD supply step.
-+               */
-+              temp = (u64)ctrl->cpr_clock_rate
-+                              * (u64)ctrl->voltage_settling_time;
-+              do_div(temp, 1000000000);
-+              cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_CORE_TIMERS,
-+                      CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_MASK,
-+                      temp
-+                  << CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_SHIFT);
-+      }
-+
-+      /*
-+       * Allocate memory for cpr4_sdelta structure and sdelta table for
-+       * controller aggregated corner by finding the maximum core count
-+       * used by any cpr3 regulators.
-+       */
-+      ctrl_max_core_count = 1;
-+      ctrl_valid_sdelta = false;
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              thread = &ctrl->thread[i];
-+
-+              /*
-+               * Allocate memory for cpr4_sdelta structure and sdelta table
-+               * for thread aggregated corner by finding the maximum core
-+               * count used by any cpr3 regulators of the thread.
-+               */
-+              thread_max_core_count = 1;
-+              thread_valid_sdelta = false;
-+              for (j = 0; j < thread->vreg_count; j++) {
-+                      vreg = &thread->vreg[j];
-+                      thread_max_core_count = max(thread_max_core_count,
-+                                                      vreg->max_core_count);
-+                      thread_valid_sdelta |= (vreg->allow_core_count_adj
-+                                                      | vreg->allow_temp_adj
-+                                                      | vreg->allow_boost);
-+              }
-+              if (thread_valid_sdelta) {
-+                      sdelta = devm_kzalloc(ctrl->dev, sizeof(*sdelta),
-+                                      GFP_KERNEL);
-+                      if (!sdelta)
-+                              return -ENOMEM;
-+
-+                      sdelta->table = devm_kcalloc(ctrl->dev,
-+                                              thread_max_core_count
-+                                              * ctrl->temp_band_count,
-+                                              sizeof(*sdelta->table),
-+                                              GFP_KERNEL);
-+                      if (!sdelta->table)
-+                              return -ENOMEM;
-+
-+                      sdelta->boost_table = devm_kcalloc(ctrl->dev,
-+                                              ctrl->temp_band_count,
-+                                              sizeof(*sdelta->boost_table),
-+                                              GFP_KERNEL);
-+                      if (!sdelta->boost_table)
-+                              return -ENOMEM;
-+
-+                      thread->aggr_corner.sdelta = sdelta;
-+              }
-+
-+              ctrl_valid_sdelta |= thread_valid_sdelta;
-+              ctrl_max_core_count = max(ctrl_max_core_count,
-+                                              thread_max_core_count);
-+      }
-+
-+      if (ctrl_valid_sdelta) {
-+              sdelta = devm_kzalloc(ctrl->dev, sizeof(*sdelta), GFP_KERNEL);
-+              if (!sdelta)
-+                      return -ENOMEM;
-+
-+              sdelta->table = devm_kcalloc(ctrl->dev, ctrl_max_core_count
-+                                      * ctrl->temp_band_count,
-+                                      sizeof(*sdelta->table), GFP_KERNEL);
-+              if (!sdelta->table)
-+                      return -ENOMEM;
-+
-+              sdelta->boost_table = devm_kcalloc(ctrl->dev,
-+                                      ctrl->temp_band_count,
-+                                      sizeof(*sdelta->boost_table),
-+                                      GFP_KERNEL);
-+              if (!sdelta->boost_table)
-+                      return -ENOMEM;
-+
-+              ctrl->aggr_corner.sdelta = sdelta;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_write_temp_core_margin() - programs hardware SDELTA registers with
-+ *            the voltage margin adjustments that need to be applied for
-+ *            different online core-count and temperature bands.
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @addr:             SDELTA register address
-+ * @temp_core_adj:    Array of voltage margin values for different temperature
-+ *                    bands.
-+ *
-+ * CPR interface/bus clocks must be enabled before calling this function.
-+ *
-+ * Return: none
-+ */
-+static void cpr3_write_temp_core_margin(struct cpr3_controller *ctrl,
-+                               int addr, int *temp_core_adj)
-+{
-+      int i, margin_steps;
-+      u32 reg = 0;
-+
-+      for (i = 0; i < ctrl->temp_band_count; i++) {
-+              margin_steps = max(min(temp_core_adj[i], 127), -128);
-+              reg |= (margin_steps & CPR4_MARGIN_TEMP_CORE_ADJ_MASK) <<
-+                      (i * CPR4_MARGIN_TEMP_CORE_ADJ_SHIFT);
-+      }
-+
-+      cpr3_write(ctrl, addr, reg);
-+      cpr3_debug(ctrl, "sdelta offset=0x%08x, val=0x%08x\n", addr, reg);
-+}
-+
-+/**
-+ * cpr3_controller_program_sdelta() - programs hardware SDELTA registers with
-+ *            the voltage margin adjustments that need to be applied at
-+ *            different online core-count and temperature bands. Also,
-+ *            programs hardware register configuration for per-online-core
-+ *            and per-temperature based adjustments.
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * CPR interface/bus clocks must be enabled before calling this function.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_controller_program_sdelta(struct cpr3_controller *ctrl)
-+{
-+      struct cpr3_corner *corner = &ctrl->aggr_corner;
-+      struct cpr4_sdelta *sdelta = corner->sdelta;
-+      int i, index, max_core_count, rc = 0;
-+      bool cpr_enabled = ctrl->cpr_enabled;
-+
-+      if (!sdelta)
-+              /* cpr4_sdelta not defined for current aggregated corner */
-+              return 0;
-+
-+      if (ctrl->supports_hw_closed_loop && ctrl->cpr_enabled) {
-+              cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                      CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
-+                      (ctrl->use_hw_closed_loop && !sdelta->allow_boost)
-+                      ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE : 0);
-+      }
-+
-+      if (!sdelta->allow_core_count_adj && !sdelta->allow_temp_adj
-+              && !sdelta->allow_boost) {
-+              /*
-+               * Per-online-core, per-temperature and voltage boost
-+               * adjustments are disabled for this aggregation corner.
-+               */
-+              return 0;
-+      }
-+
-+      /* Ensure that CPR clocks are enabled before writing to registers. */
-+      if (!cpr_enabled) {
-+              rc = cpr3_clock_enable(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
-+                      return rc;
-+              }
-+              ctrl->cpr_enabled = true;
-+      }
-+
-+      max_core_count = sdelta->max_core_count;
-+
-+      if (sdelta->allow_core_count_adj || sdelta->allow_temp_adj) {
-+              if (sdelta->allow_core_count_adj) {
-+                      /* Program TEMP_CORE0 to same margins as TEMP_CORE1 */
-+                      cpr3_write_temp_core_margin(ctrl,
-+                              CPR4_REG_MARGIN_TEMP_CORE(0),
-+                              &sdelta->table[0]);
-+              }
-+
-+              for (i = 0; i < max_core_count; i++) {
-+                      index = i * sdelta->temp_band_count;
-+                      /*
-+                       * Program TEMP_COREi with voltage margin adjustments
-+                       * that need to be applied when the number of cores
-+                       * becomes i.
-+                       */
-+                      cpr3_write_temp_core_margin(ctrl,
-+                              CPR4_REG_MARGIN_TEMP_CORE(
-+                                              sdelta->allow_core_count_adj
-+                                              ? i + 1 : max_core_count),
-+                                              &sdelta->table[index]);
-+              }
-+      }
-+
-+      if (sdelta->allow_boost) {
-+              /* Program only boost_num_cores row of SDELTA */
-+              cpr3_write_temp_core_margin(ctrl,
-+                      CPR4_REG_MARGIN_TEMP_CORE(sdelta->boost_num_cores),
-+                                      &sdelta->boost_table[0]);
-+      }
-+
-+      if (!sdelta->allow_core_count_adj && !sdelta->allow_boost) {
-+              cpr3_masked_write(ctrl, CPR4_REG_MISC,
-+                      CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK,
-+                      max_core_count
-+                      << CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT);
-+      }
-+
-+      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+              CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_MASK
-+              | CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN
-+              | CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN
-+              | CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN
-+              | CPR4_MARGIN_ADJ_CTL_BOOST_EN,
-+              max_core_count << CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_SHIFT
-+              | ((sdelta->allow_core_count_adj || sdelta->allow_boost)
-+                      ? CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN : 0)
-+              | ((sdelta->allow_temp_adj && ctrl->supports_hw_closed_loop)
-+                      ? CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN : 0)
-+              | (((ctrl->use_hw_closed_loop && !sdelta->allow_boost)
-+                  || !ctrl->supports_hw_closed_loop)
-+                      ? CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN : 0)
-+              | (sdelta->allow_boost
-+                      ?  CPR4_MARGIN_ADJ_CTL_BOOST_EN : 0));
-+
-+      /*
-+       * Ensure that all previous CPR register writes have completed before
-+       * continuing.
-+       */
-+      mb();
-+
-+      /* Turn off CPR clocks if they were off before this function call. */
-+      if (!cpr_enabled) {
-+              cpr3_clock_disable(ctrl);
-+              ctrl->cpr_enabled = false;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_init_ctrl() - performs hardware initialization of CPR
-+ *            controller registers
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_init_ctrl(struct cpr3_controller *ctrl)
-+{
-+      int i, j, k, m, rc;
-+      u32 ro_used = 0;
-+      u32 gcnt, cont_dly, up_down_dly, val;
-+      u64 temp;
-+      char *mode;
-+
-+      if (ctrl->core_clk) {
-+              rc = clk_set_rate(ctrl->core_clk, ctrl->cpr_clock_rate);
-+              if (rc) {
-+                      cpr3_err(ctrl, "clk_set_rate(core_clk, %u) failed, rc=%d\n",
-+                              ctrl->cpr_clock_rate, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      rc = cpr3_clock_enable(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+      ctrl->cpr_enabled = true;
-+
-+      /* Find all RO's used by any corner of any regulator. */
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++)
-+                      for (k = 0; k < ctrl->thread[i].vreg[j].corner_count;
-+                           k++)
-+                              for (m = 0; m < CPR3_RO_COUNT; m++)
-+                                      if (ctrl->thread[i].vreg[j].corner[k].
-+                                          target_quot[m])
-+                                              ro_used |= BIT(m);
-+
-+      /* Configure the GCNT of the RO's that will be used */
-+      gcnt = cpr3_regulator_get_gcnt(ctrl);
-+      for (i = 0; i < CPR3_RO_COUNT; i++)
-+              if (ro_used & BIT(i))
-+                      cpr3_write(ctrl, CPR3_REG_GCNT(i), gcnt);
-+
-+      /* Configure the loop delay time */
-+      temp = (u64)ctrl->cpr_clock_rate * (u64)ctrl->loop_time;
-+      do_div(temp, 1000000000);
-+      cont_dly = temp;
-+      if (ctrl->supports_hw_closed_loop
-+              && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3)
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_MID_CONT, cont_dly);
-+      else
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_AUTO_CONT, cont_dly);
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              temp = (u64)ctrl->cpr_clock_rate *
-+                              (u64)ctrl->up_down_delay_time;
-+              do_div(temp, 1000000000);
-+              up_down_dly = temp;
-+              if (ctrl->supports_hw_closed_loop)
-+                      cpr3_write(ctrl, CPR3_REG_CPR_TIMER_UP_DN_CONT,
-+                              up_down_dly);
-+              cpr3_debug(ctrl, "up_down_dly=%u, up_down_delay_time=%u ns\n",
-+                      up_down_dly, ctrl->up_down_delay_time);
-+      }
-+
-+      cpr3_debug(ctrl, "cpr_clock_rate=%u HZ, sensor_time=%u ns, loop_time=%u ns, gcnt=%u, cont_dly=%u\n",
-+              ctrl->cpr_clock_rate, ctrl->sensor_time, ctrl->loop_time,
-+              gcnt, cont_dly);
-+
-+      /* Configure CPR sensor operation */
-+      val = (ctrl->idle_clocks << CPR3_CPR_CTL_IDLE_CLOCKS_SHIFT)
-+              & CPR3_CPR_CTL_IDLE_CLOCKS_MASK;
-+      val |= (ctrl->count_mode << CPR3_CPR_CTL_COUNT_MODE_SHIFT)
-+              & CPR3_CPR_CTL_COUNT_MODE_MASK;
-+      val |= (ctrl->count_repeat << CPR3_CPR_CTL_COUNT_REPEAT_SHIFT)
-+              & CPR3_CPR_CTL_COUNT_REPEAT_MASK;
-+      cpr3_write(ctrl, CPR3_REG_CPR_CTL, val);
-+
-+      cpr3_debug(ctrl, "idle_clocks=%u, count_mode=%u, count_repeat=%u; CPR_CTL=0x%08X\n",
-+              ctrl->idle_clocks, ctrl->count_mode, ctrl->count_repeat, val);
-+
-+      /* Configure CPR default step quotients */
-+      val = (ctrl->step_quot_init_min << CPR3_CPR_STEP_QUOT_MIN_SHIFT)
-+              & CPR3_CPR_STEP_QUOT_MIN_MASK;
-+      val |= (ctrl->step_quot_init_max << CPR3_CPR_STEP_QUOT_MAX_SHIFT)
-+              & CPR3_CPR_STEP_QUOT_MAX_MASK;
-+      cpr3_write(ctrl, CPR3_REG_CPR_STEP_QUOT, val);
-+
-+      cpr3_debug(ctrl, "step_quot_min=%u, step_quot_max=%u; STEP_QUOT=0x%08X\n",
-+              ctrl->step_quot_init_min, ctrl->step_quot_init_max, val);
-+
-+      /* Configure the CPR sensor ownership */
-+      for (i = 0; i < ctrl->sensor_count; i++)
-+              cpr3_write(ctrl, CPR3_REG_SENSOR_OWNER(i),
-+                         ctrl->sensor_owner[i]);
-+
-+      /* Configure per-thread registers */
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              rc = cpr3_regulator_init_thread(&ctrl->thread[i]);
-+              if (rc) {
-+                      cpr3_err(ctrl, "CPR thread register initialization failed, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+      }
-+
-+      if (ctrl->supports_hw_closed_loop) {
-+              if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+                      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                              CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
-+                              ctrl->use_hw_closed_loop
-+                              ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
-+                              : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
-+              } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+                      cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
-+                              ctrl->use_hw_closed_loop
-+                              ? CPR3_HW_CLOSED_LOOP_ENABLE
-+                              : CPR3_HW_CLOSED_LOOP_DISABLE);
-+
-+                      cpr3_debug(ctrl, "PD_THROTTLE=0x%08X\n",
-+                              ctrl->proc_clock_throttle);
-+              }
-+
-+              if ((ctrl->use_hw_closed_loop ||
-+                   ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) &&
-+                  ctrl->vdd_limit_regulator) {
-+                      rc = regulator_enable(ctrl->vdd_limit_regulator);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "CPR limit regulator enable failed, rc=%d\n",
-+                                      rc);
-+                              return rc;
-+                      }
-+              }
-+      }
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_regulator_init_cpr4(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "CPR4-specific controller initialization failed, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+      }
-+
-+      /* Ensure that all register writes complete before disabling clocks. */
-+      wmb();
-+
-+      cpr3_clock_disable(ctrl);
-+      ctrl->cpr_enabled = false;
-+
-+      if (!ctrl->cpr_allowed_sw || !ctrl->cpr_allowed_hw)
-+              mode = "open-loop";
-+      else if (ctrl->supports_hw_closed_loop)
-+              mode = ctrl->use_hw_closed_loop
-+                      ? "HW closed-loop" : "SW closed-loop";
-+      else
-+              mode = "closed-loop";
-+
-+      cpr3_info(ctrl, "Default CPR mode = %s", mode);
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_set_target_quot() - configure the target quotient for each
-+ *            RO of the CPR3 thread and set the RO mask
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_set_target_quot(struct cpr3_thread *thread)
-+{
-+      u32 new_quot, last_quot;
-+      int i;
-+
-+      if (thread->aggr_corner.ro_mask == CPR3_RO_MASK
-+          && thread->last_closed_loop_aggr_corner.ro_mask == CPR3_RO_MASK) {
-+              /* Avoid writing target quotients since all RO's are masked. */
-+              return;
-+      } else if (thread->aggr_corner.ro_mask == CPR3_RO_MASK) {
-+              cpr3_write(thread->ctrl, CPR3_REG_RO_MASK(thread->thread_id),
-+                      CPR3_RO_MASK);
-+              thread->last_closed_loop_aggr_corner.ro_mask = CPR3_RO_MASK;
-+              /*
-+               * Only the RO_MASK register needs to be written since all
-+               * RO's are masked.
-+               */
-+              return;
-+      } else if (thread->aggr_corner.ro_mask
-+                      != thread->last_closed_loop_aggr_corner.ro_mask) {
-+              cpr3_write(thread->ctrl, CPR3_REG_RO_MASK(thread->thread_id),
-+                      thread->aggr_corner.ro_mask);
-+      }
-+
-+      for (i = 0; i < CPR3_RO_COUNT; i++) {
-+              new_quot = thread->aggr_corner.target_quot[i];
-+              last_quot = thread->last_closed_loop_aggr_corner.target_quot[i];
-+              if (new_quot != last_quot)
-+                      cpr3_write(thread->ctrl,
-+                              CPR3_REG_TARGET_QUOT(thread->thread_id, i),
-+                              new_quot);
-+      }
-+
-+      thread->last_closed_loop_aggr_corner = thread->aggr_corner;
-+
-+      return;
-+}
-+
-+/**
-+ * cpr3_update_vreg_closed_loop_volt() - update the last known settled
-+ *            closed loop voltage for a CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @vdd_volt:         Last known settled voltage in microvolts for the
-+ *                    VDD supply
-+ * @reg_last_measurement: Value read from the LAST_MEASUREMENT register
-+ *
-+ * Return: none
-+ */
-+static void cpr3_update_vreg_closed_loop_volt(struct cpr3_regulator *vreg,
-+                              int vdd_volt, u32 reg_last_measurement)
-+{
-+      bool step_dn, step_up, aggr_step_up, aggr_step_dn, aggr_step_mid;
-+      bool valid, pd_valid, saw_error;
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      struct cpr3_corner *corner;
-+      u32 id;
-+
-+      if (vreg->last_closed_loop_corner == CPR3_REGULATOR_CORNER_INVALID)
-+              return;
-+      else
-+              corner = &vreg->corner[vreg->last_closed_loop_corner];
-+
-+      if (vreg->thread->last_closed_loop_aggr_corner.ro_mask
-+          == CPR3_RO_MASK  || !vreg->aggregated) {
-+              return;
-+      } else if (!ctrl->cpr_enabled || !ctrl->last_corner_was_closed_loop) {
-+              return;
-+      } else if (ctrl->thread_count == 1
-+               && vdd_volt >= corner->floor_volt
-+               && vdd_volt <= corner->ceiling_volt) {
-+              corner->last_volt = vdd_volt;
-+              cpr3_debug(vreg, "last_volt updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d\n",
-+                         vreg->last_closed_loop_corner, corner->last_volt,
-+                         vreg->last_closed_loop_corner,
-+                         corner->ceiling_volt,
-+                         vreg->last_closed_loop_corner,
-+                         corner->floor_volt);
-+              return;
-+      } else if (!ctrl->supports_hw_closed_loop) {
-+              return;
-+      } else if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPR3) {
-+              corner->last_volt = vdd_volt;
-+              cpr3_debug(vreg, "last_volt updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d\n",
-+                         vreg->last_closed_loop_corner, corner->last_volt,
-+                         vreg->last_closed_loop_corner,
-+                         corner->ceiling_volt,
-+                         vreg->last_closed_loop_corner,
-+                         corner->floor_volt);
-+              return;
-+      }
-+
-+      /* CPR clocks are on and HW closed loop is supported */
-+      valid = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_VALID);
-+      if (!valid) {
-+              cpr3_debug(vreg, "CPR_LAST_VALID_MEASUREMENT=0x%X valid bit not set\n",
-+                         reg_last_measurement);
-+              return;
-+      }
-+
-+      id = vreg->thread->thread_id;
-+
-+      step_dn
-+             = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_THREAD_DN(id));
-+      step_up
-+             = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_THREAD_UP(id));
-+      aggr_step_dn = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_AGGR_DN);
-+      aggr_step_mid
-+              = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_AGGR_MID);
-+      aggr_step_up = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_AGGR_UP);
-+      saw_error = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_SAW_ERROR);
-+      pd_valid
-+           = !((((reg_last_measurement & CPR3_LAST_MEASUREMENT_PD_BYPASS_MASK)
-+                     >> CPR3_LAST_MEASUREMENT_PD_BYPASS_SHIFT)
-+                    & vreg->pd_bypass_mask) == vreg->pd_bypass_mask);
-+
-+      if (!pd_valid) {
-+              cpr3_debug(vreg, "CPR_LAST_VALID_MEASUREMENT=0x%X, all power domains bypassed\n",
-+                         reg_last_measurement);
-+              return;
-+      } else if (step_dn && step_up) {
-+              cpr3_err(vreg, "both up and down status bits set, CPR_LAST_VALID_MEASUREMENT=0x%X\n",
-+                       reg_last_measurement);
-+              return;
-+      } else if (aggr_step_dn && step_dn && vdd_volt < corner->last_volt
-+                 && vdd_volt >= corner->floor_volt) {
-+              corner->last_volt = vdd_volt;
-+      } else if (aggr_step_up && step_up && vdd_volt > corner->last_volt
-+                 && vdd_volt <= corner->ceiling_volt) {
-+              corner->last_volt = vdd_volt;
-+      } else if (aggr_step_mid
-+                 && vdd_volt >= corner->floor_volt
-+                 && vdd_volt <= corner->ceiling_volt) {
-+              corner->last_volt = vdd_volt;
-+      } else if (saw_error && (vdd_volt == corner->ceiling_volt
-+                               || vdd_volt == corner->floor_volt)) {
-+              corner->last_volt = vdd_volt;
-+      } else {
-+              cpr3_debug(vreg, "last_volt not updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d, vdd_volt=%d, CPR_LAST_VALID_MEASUREMENT=0x%X\n",
-+                         vreg->last_closed_loop_corner, corner->last_volt,
-+                         vreg->last_closed_loop_corner,
-+                         corner->ceiling_volt,
-+                         vreg->last_closed_loop_corner, corner->floor_volt,
-+                         vdd_volt, reg_last_measurement);
-+              return;
-+      }
-+
-+      cpr3_debug(vreg, "last_volt updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d, CPR_LAST_VALID_MEASUREMENT=0x%X\n",
-+                 vreg->last_closed_loop_corner, corner->last_volt,
-+                 vreg->last_closed_loop_corner, corner->ceiling_volt,
-+                 vreg->last_closed_loop_corner, corner->floor_volt,
-+                 reg_last_measurement);
-+}
-+
-+/**
-+ * cpr3_regulator_mem_acc_bhs_used() - determines if mem-acc regulators powered
-+ *            through a BHS are associated with the CPR3 controller or any of
-+ *            the CPR3 regulators it controls.
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * This function determines if the CPR3 controller or any of its CPR3 regulators
-+ * need to manage mem-acc regulators that are currently powered through a BHS
-+ * and whose corner selection is based upon a particular voltage threshold.
-+ *
-+ * Return: true or false
-+ */
-+static bool cpr3_regulator_mem_acc_bhs_used(struct cpr3_controller *ctrl)
-+{
-+      struct cpr3_regulator *vreg;
-+      int i, j;
-+
-+      if (!ctrl->mem_acc_threshold_volt)
-+              return false;
-+
-+      if (ctrl->mem_acc_regulator)
-+              return true;
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+
-+                      if (vreg->mem_acc_regulator)
-+                              return true;
-+              }
-+      }
-+
-+      return false;
-+}
-+
-+/**
-+ * cpr3_regulator_config_bhs_mem_acc() - configure the mem-acc regulator
-+ *            settings for hardware blocks currently powered through the BHS.
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @new_volt:         New voltage in microvolts that VDD supply needs to
-+ *                    end up at
-+ * @last_volt:                Pointer to the last known voltage in microvolts for the
-+ *                    VDD supply
-+ * @aggr_corner:      Pointer to the CPR3 corner which corresponds to the max
-+ *                    corner aggregated from all CPR3 threads managed by the
-+ *                    CPR3 controller
-+ *
-+ * This function programs the mem-acc regulator corners for CPR3 regulators
-+ * whose LDO regulators are in bypassed state. The function also handles
-+ * CPR3 controllers which utilize mem-acc regulators that operate independently
-+ * from the LDO hardware and that must be programmed when the VDD supply
-+ * crosses a particular voltage threshold.
-+ *
-+ * Return: 0 on success, errno on failure. If the VDD supply voltage is
-+ * modified, last_volt is updated to reflect the new voltage setpoint.
-+ */
-+static int cpr3_regulator_config_bhs_mem_acc(struct cpr3_controller *ctrl,
-+                                   int new_volt, int *last_volt,
-+                                   struct cpr3_corner *aggr_corner)
-+{
-+      struct cpr3_regulator *vreg;
-+      int i, j, rc, mem_acc_corn, safe_volt;
-+      int mem_acc_volt = ctrl->mem_acc_threshold_volt;
-+      int ref_volt;
-+
-+      if (!cpr3_regulator_mem_acc_bhs_used(ctrl))
-+              return 0;
-+
-+      ref_volt = ctrl->use_hw_closed_loop ? aggr_corner->floor_volt :
-+              new_volt;
-+
-+      if (((*last_volt < mem_acc_volt && mem_acc_volt <= ref_volt) ||
-+           (*last_volt >= mem_acc_volt && mem_acc_volt > ref_volt))) {
-+              if (ref_volt < *last_volt)
-+                      safe_volt = max(mem_acc_volt, aggr_corner->last_volt);
-+              else
-+                      safe_volt = max(mem_acc_volt, *last_volt);
-+
-+              rc = regulator_set_voltage(ctrl->vdd_regulator, safe_volt,
-+                                         new_volt < *last_volt ?
-+                                         ctrl->aggr_corner.ceiling_volt :
-+                                         new_volt);
-+              if (rc) {
-+                      cpr3_err(ctrl, "regulator_set_voltage(vdd) == %d failed, rc=%d\n",
-+                               safe_volt, rc);
-+                      return rc;
-+              }
-+
-+              *last_volt = safe_volt;
-+
-+              mem_acc_corn = ref_volt < mem_acc_volt ?
-+                      ctrl->mem_acc_corner_map[CPR3_MEM_ACC_LOW_CORNER] :
-+                      ctrl->mem_acc_corner_map[CPR3_MEM_ACC_HIGH_CORNER];
-+
-+              if (ctrl->mem_acc_regulator) {
-+                      rc = regulator_set_voltage(ctrl->mem_acc_regulator,
-+                                                 mem_acc_corn, mem_acc_corn);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "regulator_set_voltage(mem_acc) == %d failed, rc=%d\n",
-+                                       mem_acc_corn, rc);
-+                              return rc;
-+                      }
-+              }
-+
-+              for (i = 0; i < ctrl->thread_count; i++) {
-+                      for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                              vreg = &ctrl->thread[i].vreg[j];
-+
-+                              if (!vreg->mem_acc_regulator)
-+                                      continue;
-+
-+                              rc = regulator_set_voltage(
-+                                      vreg->mem_acc_regulator, mem_acc_corn,
-+                                      mem_acc_corn);
-+                              if (rc) {
-+                                      cpr3_err(vreg, "regulator_set_voltage(mem_acc) == %d failed, rc=%d\n",
-+                                               mem_acc_corn, rc);
-+                                      return rc;
-+                              }
-+                      }
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_switch_apm_mode() - switch the mode of the APM controller
-+ *            associated with a given CPR3 controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @new_volt:         New voltage in microvolts that VDD supply needs to
-+ *                    end up at
-+ * @last_volt:                Pointer to the last known voltage in microvolts for the
-+ *                    VDD supply
-+ * @aggr_corner:      Pointer to the CPR3 corner which corresponds to the max
-+ *                    corner aggregated from all CPR3 threads managed by the
-+ *                    CPR3 controller
-+ *
-+ * This function requests a switch of the APM mode while guaranteeing
-+ * any LDO regulator hardware requirements are satisfied. The function must
-+ * be called once it is known a new VDD supply setpoint crosses the APM
-+ * voltage threshold.
-+ *
-+ * Return: 0 on success, errno on failure. If the VDD supply voltage is
-+ * modified, last_volt is updated to reflect the new voltage setpoint.
-+ */
-+static int cpr3_regulator_switch_apm_mode(struct cpr3_controller *ctrl,
-+                                        int new_volt, int *last_volt,
-+                                        struct cpr3_corner *aggr_corner)
-+{
-+      struct regulator *vdd = ctrl->vdd_regulator;
-+      int apm_volt = ctrl->apm_threshold_volt;
-+      int orig_last_volt = *last_volt;
-+      int rc;
-+
-+      rc = regulator_set_voltage(vdd, apm_volt, apm_volt);
-+      if (rc) {
-+              cpr3_err(ctrl, "regulator_set_voltage(vdd) == %d failed, rc=%d\n",
-+                       apm_volt, rc);
-+              return rc;
-+      }
-+
-+      *last_volt = apm_volt;
-+
-+      rc = msm_apm_set_supply(ctrl->apm, new_volt >= apm_volt
-+                              ? ctrl->apm_high_supply : ctrl->apm_low_supply);
-+      if (rc) {
-+              cpr3_err(ctrl, "APM switch failed, rc=%d\n", rc);
-+              /* Roll back the voltage. */
-+              regulator_set_voltage(vdd, orig_last_volt, INT_MAX);
-+              *last_volt = orig_last_volt;
-+              return rc;
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_config_voltage_crossings() - configure APM and mem-acc
-+ *            settings depending upon a new VDD supply setpoint
-+ *
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @new_volt:         New voltage in microvolts that VDD supply needs to
-+ *                    end up at
-+ * @last_volt:                Pointer to the last known voltage in microvolts for the
-+ *                    VDD supply
-+ * @aggr_corner:      Pointer to the CPR3 corner which corresponds to the max
-+ *                    corner aggregated from all CPR3 threads managed by the
-+ *                    CPR3 controller
-+ *
-+ * This function handles the APM and mem-acc regulator reconfiguration if
-+ * the new VDD supply voltage will result in crossing their respective voltage
-+ * thresholds.
-+ *
-+ * Return: 0 on success, errno on failure. If the VDD supply voltage is
-+ * modified, last_volt is updated to reflect the new voltage setpoint.
-+ */
-+static int cpr3_regulator_config_voltage_crossings(struct cpr3_controller *ctrl,
-+                                 int new_volt, int *last_volt,
-+                                 struct cpr3_corner *aggr_corner)
-+{
-+      bool apm_crossing = false, mem_acc_crossing = false;
-+      bool mem_acc_bhs_used;
-+      int apm_volt = ctrl->apm_threshold_volt;
-+      int mem_acc_volt = ctrl->mem_acc_threshold_volt;
-+      int ref_volt, rc;
-+
-+      if (ctrl->apm && apm_volt > 0
-+          && ((*last_volt < apm_volt && apm_volt <= new_volt)
-+              || (*last_volt >= apm_volt && apm_volt > new_volt)))
-+              apm_crossing = true;
-+
-+      mem_acc_bhs_used = cpr3_regulator_mem_acc_bhs_used(ctrl);
-+
-+      ref_volt = ctrl->use_hw_closed_loop ? aggr_corner->floor_volt :
-+              new_volt;
-+
-+      if (mem_acc_bhs_used &&
-+          (((*last_volt < mem_acc_volt && mem_acc_volt <= ref_volt) ||
-+            (*last_volt >= mem_acc_volt && mem_acc_volt > ref_volt))))
-+              mem_acc_crossing = true;
-+
-+      if (apm_crossing && mem_acc_crossing) {
-+              if ((new_volt < *last_volt && apm_volt >= mem_acc_volt) ||
-+                  (new_volt >= *last_volt && apm_volt < mem_acc_volt)) {
-+                      rc = cpr3_regulator_switch_apm_mode(ctrl, new_volt,
-+                                                          last_volt,
-+                                                          aggr_corner);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "unable to switch APM mode\n");
-+                              return rc;
-+                      }
-+
-+                      rc = cpr3_regulator_config_bhs_mem_acc(ctrl, new_volt,
-+                                                     last_volt, aggr_corner);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "unable to configure BHS mem-acc settings\n");
-+                              return rc;
-+                      }
-+              } else {
-+                      rc = cpr3_regulator_config_bhs_mem_acc(ctrl, new_volt,
-+                                                     last_volt, aggr_corner);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "unable to configure BHS mem-acc settings\n");
-+                              return rc;
-+                      }
-+
-+                      rc = cpr3_regulator_switch_apm_mode(ctrl, new_volt,
-+                                                          last_volt,
-+                                                          aggr_corner);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "unable to switch APM mode\n");
-+                              return rc;
-+                      }
-+              }
-+      } else if (apm_crossing) {
-+              rc = cpr3_regulator_switch_apm_mode(ctrl, new_volt, last_volt,
-+                                                  aggr_corner);
-+              if (rc) {
-+                      cpr3_err(ctrl, "unable to switch APM mode\n");
-+                      return rc;
-+              }
-+      } else if (mem_acc_crossing) {
-+              rc = cpr3_regulator_config_bhs_mem_acc(ctrl, new_volt,
-+                                                     last_volt, aggr_corner);
-+              if (rc) {
-+                      cpr3_err(ctrl, "unable to configure BHS mem-acc settings\n");
-+                      return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_config_mem_acc() - configure the corner of the mem-acc
-+ *                    regulator associated with the CPR3 controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @aggr_corner:      Pointer to the CPR3 corner which corresponds to the max
-+ *                    corner aggregated from all CPR3 threads managed by the
-+ *                    CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_config_mem_acc(struct cpr3_controller *ctrl,
-+                                       struct cpr3_corner *aggr_corner)
-+{
-+      int rc;
-+
-+      if (ctrl->mem_acc_regulator && aggr_corner->mem_acc_volt) {
-+              rc = regulator_set_voltage(ctrl->mem_acc_regulator,
-+                                         aggr_corner->mem_acc_volt,
-+                                         aggr_corner->mem_acc_volt);
-+              if (rc) {
-+                      cpr3_err(ctrl, "regulator_set_voltage(mem_acc) == %d failed, rc=%d\n",
-+                               aggr_corner->mem_acc_volt, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_scale_vdd_voltage() - scale the CPR controlled VDD supply
-+ *            voltage to the new level while satisfying any other hardware
-+ *            requirements
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @new_volt:         New voltage in microvolts that VDD supply needs to end
-+ *                    up at
-+ * @last_volt:                Last known voltage in microvolts for the VDD supply
-+ * @aggr_corner:      Pointer to the CPR3 corner which corresponds to the max
-+ *                    corner aggregated from all CPR3 threads managed by the
-+ *                    CPR3 controller
-+ *
-+ * This function scales the CPR controlled VDD supply voltage from its
-+ * current level to the new voltage that is specified.  If the supply is
-+ * configured to use the APM and the APM threshold is crossed as a result of
-+ * the voltage scaling, then this function also stops at the APM threshold,
-+ * switches the APM source, and finally sets the final new voltage.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_scale_vdd_voltage(struct cpr3_controller *ctrl,
-+                              int new_volt, int last_volt,
-+                              struct cpr3_corner *aggr_corner)
-+{
-+      struct regulator *vdd = ctrl->vdd_regulator;
-+      int rc;
-+
-+      if (new_volt < last_volt) {
-+                      rc = cpr3_regulator_config_mem_acc(ctrl, aggr_corner);
-+                      if (rc)
-+                              return rc;
-+      } else {
-+              /* Increasing VDD voltage */
-+              if (ctrl->system_regulator) {
-+                      rc = regulator_set_voltage(ctrl->system_regulator,
-+                              aggr_corner->system_volt, INT_MAX);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "regulator_set_voltage(system) == %d failed, rc=%d\n",
-+                                      aggr_corner->system_volt, rc);
-+                              return rc;
-+                      }
-+              }
-+      }
-+
-+      rc = cpr3_regulator_config_voltage_crossings(ctrl, new_volt, &last_volt,
-+                                                   aggr_corner);
-+      if (rc) {
-+              cpr3_err(ctrl, "unable to handle voltage threshold crossing configurations, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      /*
-+       * Subtract a small amount from the min_uV parameter so that the
-+       * set voltage request is not dropped by the framework due to being
-+       * duplicate.  This is needed in order to switch from hardware
-+       * closed-loop to open-loop successfully.
-+       */
-+      rc = regulator_set_voltage(vdd, new_volt - (ctrl->cpr_enabled ? 0 : 1),
-+                                 aggr_corner->ceiling_volt);
-+      if (rc) {
-+              cpr3_err(ctrl, "regulator_set_voltage(vdd) == %d failed, rc=%d\n",
-+                      new_volt, rc);
-+              return rc;
-+      }
-+
-+      if (new_volt == last_volt && ctrl->supports_hw_closed_loop
-+          && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              /*
-+               * CPR4 features enforce voltage reprogramming when the last
-+               * set voltage and new set voltage are same. This way, we can
-+               * ensure that SAW PMIC STATUS register is updated with newly
-+               * programmed voltage.
-+               */
-+              rc = regulator_sync_voltage(vdd);
-+              if (rc) {
-+                      cpr3_err(ctrl, "regulator_sync_voltage(vdd) == %d failed, rc=%d\n",
-+                              new_volt, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      if (new_volt >= last_volt) {
-+              rc = cpr3_regulator_config_mem_acc(ctrl, aggr_corner);
-+              if (rc)
-+                      return rc;
-+      } else {
-+              /* Decreasing VDD voltage */
-+              if (ctrl->system_regulator) {
-+                      rc = regulator_set_voltage(ctrl->system_regulator,
-+                              aggr_corner->system_volt, INT_MAX);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "regulator_set_voltage(system) == %d failed, rc=%d\n",
-+                                      aggr_corner->system_volt, rc);
-+                              return rc;
-+                      }
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_get_dynamic_floor_volt() - returns the current dynamic floor
-+ *            voltage based upon static configurations and the state of all
-+ *            power domains during the last CPR measurement
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @reg_last_measurement: Value read from the LAST_MEASUREMENT register
-+ *
-+ * When using HW closed-loop, the dynamic floor voltage is always returned
-+ * regardless of the current state of the power domains.
-+ *
-+ * Return: dynamic floor voltage in microvolts or 0 if dynamic floor is not
-+ *         currently required
-+ */
-+static int cpr3_regulator_get_dynamic_floor_volt(struct cpr3_controller *ctrl,
-+              u32 reg_last_measurement)
-+{
-+      int dynamic_floor_volt = 0;
-+      struct cpr3_regulator *vreg;
-+      bool valid, pd_valid;
-+      u32 bypass_bits;
-+      int i, j;
-+
-+      if (!ctrl->supports_hw_closed_loop)
-+              return 0;
-+
-+      if (likely(!ctrl->use_hw_closed_loop)) {
-+              valid = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_VALID);
-+              bypass_bits
-+               = (reg_last_measurement & CPR3_LAST_MEASUREMENT_PD_BYPASS_MASK)
-+                      >> CPR3_LAST_MEASUREMENT_PD_BYPASS_SHIFT;
-+      } else {
-+              /*
-+               * Ensure that the dynamic floor voltage is always used for
-+               * HW closed-loop since the conditions below cannot be evaluated
-+               * after each CPR measurement.
-+               */
-+              valid = false;
-+              bypass_bits = 0;
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+
-+                      if (!vreg->uses_dynamic_floor)
-+                              continue;
-+
-+                      pd_valid = !((bypass_bits & vreg->pd_bypass_mask)
-+                                      == vreg->pd_bypass_mask);
-+
-+                      if (!valid || !pd_valid)
-+                              dynamic_floor_volt = max(dynamic_floor_volt,
-+                                      vreg->corner[
-+                                       vreg->dynamic_floor_corner].last_volt);
-+              }
-+      }
-+
-+      return dynamic_floor_volt;
-+}
-+
-+/**
-+ * cpr3_regulator_max_sdelta_diff() - returns the maximum voltage difference in
-+ *            microvolts that can result from different operating conditions
-+ *            for the specified sdelta struct
-+ * @sdelta:           Pointer to the sdelta structure
-+ * @step_volt:                Step size in microvolts between available set
-+ *                    points of the VDD supply.
-+ *
-+ * Return: voltage difference between the highest and lowest adjustments if
-+ *    sdelta and sdelta->table are valid, else 0.
-+ */
-+static int cpr3_regulator_max_sdelta_diff(const struct cpr4_sdelta *sdelta,
-+                              int step_volt)
-+{
-+      int i, j, index, sdelta_min = INT_MAX, sdelta_max = INT_MIN;
-+
-+      if (!sdelta || !sdelta->table)
-+              return 0;
-+
-+      for (i = 0; i < sdelta->max_core_count; i++) {
-+              for (j = 0; j < sdelta->temp_band_count; j++) {
-+                      index = i * sdelta->temp_band_count + j;
-+                      sdelta_min = min(sdelta_min, sdelta->table[index]);
-+                      sdelta_max = max(sdelta_max, sdelta->table[index]);
-+              }
-+      }
-+
-+      return (sdelta_max - sdelta_min) * step_volt;
-+}
-+
-+/**
-+ * cpr3_regulator_aggregate_sdelta() - check open-loop voltages of current
-+ *            aggregated corner and current corner of a given regulator
-+ *            and adjust the sdelta strucuture data of aggregate corner.
-+ * @aggr_corner:      Pointer to accumulated aggregated corner which
-+ *                    is both an input and an output
-+ * @corner:           Pointer to the corner to be aggregated with
-+ *                    aggr_corner
-+ * @step_volt:                Step size in microvolts between available set
-+ *                    points of the VDD supply.
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_aggregate_sdelta(
-+                              struct cpr3_corner *aggr_corner,
-+                              const struct cpr3_corner *corner, int step_volt)
-+{
-+      struct cpr4_sdelta *aggr_sdelta, *sdelta;
-+      int aggr_core_count, core_count, temp_band_count;
-+      u32 aggr_index, index;
-+      int i, j, sdelta_size, cap_steps, adjust_sdelta;
-+
-+      aggr_sdelta = aggr_corner->sdelta;
-+      sdelta = corner->sdelta;
-+
-+      if (aggr_corner->open_loop_volt < corner->open_loop_volt) {
-+              /*
-+               * Found the new dominant regulator as its open-loop requirement
-+               * is higher than previous dominant regulator. Calculate cap
-+               * voltage to limit the SDELTA values to make sure the runtime
-+               * (Core-count/temp) adjustments do not violate other
-+               * regulators' voltage requirements. Use cpr4_sdelta values of
-+               * new dominant regulator.
-+               */
-+              aggr_sdelta->cap_volt = min(aggr_sdelta->cap_volt,
-+                                              (corner->open_loop_volt -
-+                                              aggr_corner->open_loop_volt));
-+
-+              /* Clear old data in the sdelta table */
-+              sdelta_size = aggr_sdelta->max_core_count
-+                                      * aggr_sdelta->temp_band_count;
-+
-+              if (aggr_sdelta->allow_core_count_adj
-+                      || aggr_sdelta->allow_temp_adj)
-+                      memset(aggr_sdelta->table, 0, sdelta_size
-+                                      * sizeof(*aggr_sdelta->table));
-+
-+              if (sdelta->allow_temp_adj || sdelta->allow_core_count_adj) {
-+                      /* Copy new data in sdelta table */
-+                      sdelta_size = sdelta->max_core_count
-+                                              * sdelta->temp_band_count;
-+                      if (sdelta->table)
-+                              memcpy(aggr_sdelta->table, sdelta->table,
-+                                      sdelta_size * sizeof(*sdelta->table));
-+              }
-+
-+              if (sdelta->allow_boost) {
-+                      memcpy(aggr_sdelta->boost_table, sdelta->boost_table,
-+                              sdelta->temp_band_count
-+                              * sizeof(*sdelta->boost_table));
-+                      aggr_sdelta->boost_num_cores = sdelta->boost_num_cores;
-+              } else if (aggr_sdelta->allow_boost) {
-+                      for (i = 0; i < aggr_sdelta->temp_band_count; i++) {
-+                              adjust_sdelta = (corner->open_loop_volt
-+                                              - aggr_corner->open_loop_volt)
-+                                              / step_volt;
-+                              aggr_sdelta->boost_table[i] += adjust_sdelta;
-+                              aggr_sdelta->boost_table[i]
-+                                      = min(aggr_sdelta->boost_table[i], 0);
-+                      }
-+              }
-+
-+              aggr_corner->open_loop_volt = corner->open_loop_volt;
-+              aggr_sdelta->allow_temp_adj = sdelta->allow_temp_adj;
-+              aggr_sdelta->allow_core_count_adj
-+                                      = sdelta->allow_core_count_adj;
-+              aggr_sdelta->max_core_count = sdelta->max_core_count;
-+              aggr_sdelta->temp_band_count = sdelta->temp_band_count;
-+      } else if (aggr_corner->open_loop_volt > corner->open_loop_volt) {
-+              /*
-+               * Adjust the cap voltage if the open-loop requirement of new
-+               * regulator is the next highest.
-+               */
-+              aggr_sdelta->cap_volt = min(aggr_sdelta->cap_volt,
-+                                              (aggr_corner->open_loop_volt
-+                                              - corner->open_loop_volt));
-+
-+              if (sdelta->allow_boost) {
-+                      for (i = 0; i < aggr_sdelta->temp_band_count; i++) {
-+                              adjust_sdelta = (aggr_corner->open_loop_volt
-+                                              - corner->open_loop_volt)
-+                                              / step_volt;
-+                              aggr_sdelta->boost_table[i] =
-+                                      sdelta->boost_table[i] + adjust_sdelta;
-+                              aggr_sdelta->boost_table[i]
-+                                      = min(aggr_sdelta->boost_table[i], 0);
-+                      }
-+                      aggr_sdelta->boost_num_cores = sdelta->boost_num_cores;
-+              }
-+      } else {
-+              /*
-+               * Found another dominant regulator with same open-loop
-+               * requirement. Make cap voltage to '0'. Disable core-count
-+               * adjustments as we couldn't support for both regulators.
-+               * Keep enable temp based adjustments if enabled for both
-+               * regulators and choose mininum margin adjustment values
-+               * between them.
-+               */
-+              aggr_sdelta->cap_volt = 0;
-+              aggr_sdelta->allow_core_count_adj = false;
-+
-+              if (aggr_sdelta->allow_temp_adj
-+                                      && sdelta->allow_temp_adj) {
-+                      aggr_core_count = aggr_sdelta->max_core_count - 1;
-+                      core_count = sdelta->max_core_count - 1;
-+                      temp_band_count = sdelta->temp_band_count;
-+                      for (j = 0; j < temp_band_count; j++) {
-+                              aggr_index = aggr_core_count * temp_band_count
-+                                              + j;
-+                              index = core_count * temp_band_count + j;
-+                              aggr_sdelta->table[aggr_index] =
-+                                      min(aggr_sdelta->table[aggr_index],
-+                                              sdelta->table[index]);
-+                      }
-+              } else {
-+                      aggr_sdelta->allow_temp_adj = false;
-+              }
-+
-+              if (sdelta->allow_boost) {
-+                      memcpy(aggr_sdelta->boost_table, sdelta->boost_table,
-+                              sdelta->temp_band_count
-+                              * sizeof(*sdelta->boost_table));
-+                      aggr_sdelta->boost_num_cores = sdelta->boost_num_cores;
-+              }
-+      }
-+
-+      /* Keep non-dominant clients boost enable state */
-+      aggr_sdelta->allow_boost |= sdelta->allow_boost;
-+      if (aggr_sdelta->allow_boost)
-+              aggr_sdelta->allow_core_count_adj = false;
-+
-+      if (aggr_sdelta->cap_volt && !(aggr_sdelta->cap_volt == INT_MAX)) {
-+              core_count = aggr_sdelta->max_core_count;
-+              temp_band_count = aggr_sdelta->temp_band_count;
-+              /*
-+               * Convert cap voltage from uV to PMIC steps and use to limit
-+               * sdelta margin adjustments.
-+               */
-+              cap_steps = aggr_sdelta->cap_volt / step_volt;
-+              for (i = 0; i < core_count; i++)
-+                      for (j = 0; j < temp_band_count; j++) {
-+                              index = i * temp_band_count + j;
-+                              aggr_sdelta->table[index] =
-+                                              min(aggr_sdelta->table[index],
-+                                                      cap_steps);
-+              }
-+      }
-+}
-+
-+/**
-+ * cpr3_regulator_aggregate_corners() - aggregate two corners together
-+ * @aggr_corner:              Pointer to accumulated aggregated corner which
-+ *                            is both an input and an output
-+ * @corner:                   Pointer to the corner to be aggregated with
-+ *                            aggr_corner
-+ * @aggr_quot:                        Flag indicating that target quotients should be
-+ *                            aggregated as well.
-+ * @step_volt:                        Step size in microvolts between available set
-+ *                            points of the VDD supply.
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_aggregate_corners(struct cpr3_corner *aggr_corner,
-+                      const struct cpr3_corner *corner, bool aggr_quot,
-+                      int step_volt)
-+{
-+      int i;
-+
-+      aggr_corner->ceiling_volt
-+              = max(aggr_corner->ceiling_volt, corner->ceiling_volt);
-+      aggr_corner->floor_volt
-+              = max(aggr_corner->floor_volt, corner->floor_volt);
-+      aggr_corner->last_volt
-+              = max(aggr_corner->last_volt, corner->last_volt);
-+      aggr_corner->system_volt
-+              = max(aggr_corner->system_volt, corner->system_volt);
-+      aggr_corner->mem_acc_volt
-+              = max(aggr_corner->mem_acc_volt, corner->mem_acc_volt);
-+      aggr_corner->irq_en |= corner->irq_en;
-+      aggr_corner->use_open_loop |= corner->use_open_loop;
-+
-+      if (aggr_quot) {
-+              aggr_corner->ro_mask &= corner->ro_mask;
-+
-+              for (i = 0; i < CPR3_RO_COUNT; i++)
-+                      aggr_corner->target_quot[i]
-+                              = max(aggr_corner->target_quot[i],
-+                                    corner->target_quot[i]);
-+      }
-+
-+      if (aggr_corner->sdelta && corner->sdelta
-+              && (aggr_corner->sdelta->table
-+              || aggr_corner->sdelta->boost_table)) {
-+              cpr3_regulator_aggregate_sdelta(aggr_corner, corner, step_volt);
-+      } else {
-+              aggr_corner->open_loop_volt
-+                      = max(aggr_corner->open_loop_volt,
-+                              corner->open_loop_volt);
-+      }
-+}
-+
-+/**
-+ * cpr3_regulator_update_ctrl_state() - update the state of the CPR controller
-+ *            to reflect the corners used by all CPR3 regulators as well as
-+ *            the CPR operating mode
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * This function aggregates the CPR parameters for all CPR3 regulators
-+ * associated with the VDD supply.  Upon success, it sets the aggregated last
-+ * known good voltage.
-+ *
-+ * The VDD supply voltage will not be physically configured unless this
-+ * condition is met by at least one of the regulators of the controller:
-+ * regulator->vreg_enabled == true &&
-+ * regulator->current_corner != CPR3_REGULATOR_CORNER_INVALID
-+ *
-+ * CPR registers for the controller and each thread are updated as long as
-+ * ctrl->cpr_enabled == true.
-+ *
-+ * Note, CPR3 controller lock must be held by the caller.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int _cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
-+{
-+      struct cpr3_corner aggr_corner = {};
-+      struct cpr3_thread *thread;
-+      struct cpr3_regulator *vreg;
-+      struct cpr4_sdelta *sdelta;
-+      bool valid = false;
-+      bool thread_valid;
-+      int i, j, rc, new_volt, vdd_volt, dynamic_floor_volt, last_corner_volt;
-+      u32 reg_last_measurement = 0, sdelta_size;
-+      int *sdelta_table, *boost_table;
-+
-+      last_corner_volt = 0;
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      vdd_volt = regulator_get_voltage(ctrl->vdd_regulator);
-+      if (vdd_volt < 0) {
-+              cpr3_err(ctrl, "regulator_get_voltage(vdd) failed, rc=%d\n",
-+                       vdd_volt);
-+              return vdd_volt;
-+      }
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              /*
-+               * Save aggregated corner open-loop voltage which was programmed
-+               * during last corner switch which is used when programming new
-+               * aggregated corner open-loop voltage.
-+               */
-+              last_corner_volt = ctrl->aggr_corner.open_loop_volt;
-+      }
-+
-+      if (ctrl->cpr_enabled && ctrl->use_hw_closed_loop &&
-+              ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3)
-+              reg_last_measurement
-+                      = cpr3_read(ctrl, CPR3_REG_LAST_MEASUREMENT);
-+
-+      aggr_corner.sdelta = ctrl->aggr_corner.sdelta;
-+      if (aggr_corner.sdelta) {
-+              sdelta = aggr_corner.sdelta;
-+              sdelta_table = sdelta->table;
-+              if (sdelta_table) {
-+                      sdelta_size = sdelta->max_core_count *
-+                                      sdelta->temp_band_count;
-+                      memset(sdelta_table, 0, sdelta_size
-+                                      * sizeof(*sdelta_table));
-+              }
-+
-+              boost_table = sdelta->boost_table;
-+              if (boost_table)
-+                      memset(boost_table, 0, sdelta->temp_band_count
-+                                      * sizeof(*boost_table));
-+
-+              memset(sdelta, 0, sizeof(*sdelta));
-+              sdelta->table = sdelta_table;
-+              sdelta->cap_volt = INT_MAX;
-+              sdelta->boost_table = boost_table;
-+      }
-+
-+      /* Aggregate the requests of all threads */
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              thread = &ctrl->thread[i];
-+              thread_valid = false;
-+
-+              sdelta = thread->aggr_corner.sdelta;
-+              if (sdelta) {
-+                      sdelta_table = sdelta->table;
-+                      if (sdelta_table) {
-+                              sdelta_size = sdelta->max_core_count *
-+                                              sdelta->temp_band_count;
-+                              memset(sdelta_table, 0, sdelta_size
-+                                              * sizeof(*sdelta_table));
-+                      }
-+
-+                      boost_table = sdelta->boost_table;
-+                      if (boost_table)
-+                              memset(boost_table, 0, sdelta->temp_band_count
-+                                              * sizeof(*boost_table));
-+
-+                      memset(sdelta, 0, sizeof(*sdelta));
-+                      sdelta->table = sdelta_table;
-+                      sdelta->cap_volt = INT_MAX;
-+                      sdelta->boost_table = boost_table;
-+              }
-+
-+              memset(&thread->aggr_corner, 0, sizeof(thread->aggr_corner));
-+              thread->aggr_corner.sdelta = sdelta;
-+              thread->aggr_corner.ro_mask = CPR3_RO_MASK;
-+
-+              for (j = 0; j < thread->vreg_count; j++) {
-+                      vreg = &thread->vreg[j];
-+
-+                      if (ctrl->cpr_enabled && ctrl->use_hw_closed_loop)
-+                              cpr3_update_vreg_closed_loop_volt(vreg,
-+                                              vdd_volt, reg_last_measurement);
-+
-+                      if (!vreg->vreg_enabled
-+                          || vreg->current_corner
-+                                          == CPR3_REGULATOR_CORNER_INVALID) {
-+                              /* Cannot participate in aggregation. */
-+                              vreg->aggregated = false;
-+                              continue;
-+                      } else {
-+                              vreg->aggregated = true;
-+                              thread_valid = true;
-+                      }
-+
-+                      cpr3_regulator_aggregate_corners(&thread->aggr_corner,
-+                                      &vreg->corner[vreg->current_corner],
-+                                      true, ctrl->step_volt);
-+              }
-+
-+              valid |= thread_valid;
-+
-+              if (thread_valid)
-+                      cpr3_regulator_aggregate_corners(&aggr_corner,
-+                                      &thread->aggr_corner,
-+                                      false, ctrl->step_volt);
-+      }
-+
-+      if (valid && ctrl->cpr_allowed_hw && ctrl->cpr_allowed_sw) {
-+              rc = cpr3_closed_loop_enable(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "could not enable CPR, rc=%d\n", rc);
-+                      return rc;
-+              }
-+      } else {
-+              rc = cpr3_closed_loop_disable(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "could not disable CPR, rc=%d\n", rc);
-+                      return rc;
-+              }
-+      }
-+
-+      /* No threads are enabled with a valid corner so exit. */
-+      if (!valid)
-+              return 0;
-+
-+      /*
-+       * When using CPR hardware closed-loop, the voltage may vary anywhere
-+       * between the floor and ceiling voltage without software notification.
-+       * Therefore, it is required that the floor to ceiling range for the
-+       * aggregated corner not intersect the APM threshold voltage.  Adjust
-+       * the floor to ceiling range if this requirement is violated.
-+       *
-+       * The following algorithm is applied in the case that
-+       * floor < threshold <= ceiling:
-+       *      if open_loop >= threshold - adj, then floor = threshold
-+       *      else ceiling = threshold - step
-+       * where adj = an adjustment factor to ensure sufficient voltage margin
-+       * and step = VDD output step size
-+       *
-+       * The open-loop and last known voltages are also bounded by the new
-+       * floor or ceiling value as needed.
-+       */
-+      if (ctrl->use_hw_closed_loop
-+          && aggr_corner.ceiling_volt >= ctrl->apm_threshold_volt
-+          && aggr_corner.floor_volt < ctrl->apm_threshold_volt) {
-+
-+              if (aggr_corner.open_loop_volt
-+                  >= ctrl->apm_threshold_volt - ctrl->apm_adj_volt)
-+                      aggr_corner.floor_volt = ctrl->apm_threshold_volt;
-+              else
-+                      aggr_corner.ceiling_volt
-+                              = ctrl->apm_threshold_volt - ctrl->step_volt;
-+
-+              aggr_corner.last_volt
-+                  = max(aggr_corner.last_volt, aggr_corner.floor_volt);
-+              aggr_corner.last_volt
-+                  = min(aggr_corner.last_volt, aggr_corner.ceiling_volt);
-+              aggr_corner.open_loop_volt
-+                  = max(aggr_corner.open_loop_volt, aggr_corner.floor_volt);
-+              aggr_corner.open_loop_volt
-+                  = min(aggr_corner.open_loop_volt, aggr_corner.ceiling_volt);
-+      }
-+
-+      if (ctrl->use_hw_closed_loop
-+          && aggr_corner.ceiling_volt >= ctrl->mem_acc_threshold_volt
-+          && aggr_corner.floor_volt < ctrl->mem_acc_threshold_volt) {
-+              aggr_corner.floor_volt = ctrl->mem_acc_threshold_volt;
-+              aggr_corner.last_volt = max(aggr_corner.last_volt,
-+                                           aggr_corner.floor_volt);
-+              aggr_corner.open_loop_volt = max(aggr_corner.open_loop_volt,
-+                                                aggr_corner.floor_volt);
-+      }
-+
-+      if (ctrl->use_hw_closed_loop) {
-+              dynamic_floor_volt
-+                      = cpr3_regulator_get_dynamic_floor_volt(ctrl,
-+                                                      reg_last_measurement);
-+              if (aggr_corner.floor_volt < dynamic_floor_volt) {
-+                      aggr_corner.floor_volt = dynamic_floor_volt;
-+                      aggr_corner.last_volt = max(aggr_corner.last_volt,
-+                                                      aggr_corner.floor_volt);
-+                      aggr_corner.open_loop_volt
-+                              = max(aggr_corner.open_loop_volt,
-+                                      aggr_corner.floor_volt);
-+                      aggr_corner.ceiling_volt = max(aggr_corner.ceiling_volt,
-+                                                      aggr_corner.floor_volt);
-+              }
-+      }
-+
-+      if (ctrl->cpr_enabled && ctrl->last_corner_was_closed_loop) {
-+              /*
-+               * Always program open-loop voltage for CPR4 controllers which
-+               * support hardware closed-loop.  Storing the last closed loop
-+               * voltage in corner structure can still help with debugging.
-+               */
-+              if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3)
-+                      new_volt = aggr_corner.last_volt;
-+              else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4
-+                       && ctrl->supports_hw_closed_loop)
-+                      new_volt = aggr_corner.open_loop_volt;
-+              else
-+                      new_volt = min(aggr_corner.last_volt +
-+                            cpr3_regulator_max_sdelta_diff(aggr_corner.sdelta,
-+                                                           ctrl->step_volt),
-+                                     aggr_corner.ceiling_volt);
-+
-+              aggr_corner.last_volt = new_volt;
-+      } else {
-+              new_volt = aggr_corner.open_loop_volt;
-+              aggr_corner.last_volt = aggr_corner.open_loop_volt;
-+      }
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4
-+          && ctrl->supports_hw_closed_loop) {
-+              /*
-+               * Store last aggregated corner open-loop voltage in vdd_volt
-+               * which is used when programming current aggregated corner
-+               * required voltage.
-+               */
-+              vdd_volt = last_corner_volt;
-+      }
-+
-+      cpr3_debug(ctrl, "setting new voltage=%d uV\n", new_volt);
-+      rc = cpr3_regulator_scale_vdd_voltage(ctrl, new_volt,
-+                                            vdd_volt, &aggr_corner);
-+      if (rc) {
-+              cpr3_err(ctrl, "vdd voltage scaling failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      /* Only update registers if CPR is enabled. */
-+      if (ctrl->cpr_enabled) {
-+              if (ctrl->use_hw_closed_loop) {
-+                      /* Hardware closed-loop */
-+
-+                      /* Set ceiling and floor limits in hardware */
-+                      rc = regulator_set_voltage(ctrl->vdd_limit_regulator,
-+                              aggr_corner.floor_volt,
-+                              aggr_corner.ceiling_volt);
-+                      if (rc) {
-+                              cpr3_err(ctrl, "could not configure HW closed-loop voltage limits, rc=%d\n",
-+                                      rc);
-+                              return rc;
-+                      }
-+              } else {
-+                      /* Software closed-loop */
-+
-+                      /*
-+                       * Disable UP or DOWN interrupts when at ceiling or
-+                       * floor respectively.
-+                       */
-+                      if (new_volt == aggr_corner.floor_volt)
-+                              aggr_corner.irq_en &= ~CPR3_IRQ_DOWN;
-+                      if (new_volt == aggr_corner.ceiling_volt)
-+                              aggr_corner.irq_en &= ~CPR3_IRQ_UP;
-+
-+                      cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR,
-+                              CPR3_IRQ_UP | CPR3_IRQ_DOWN);
-+                      cpr3_write(ctrl, CPR3_REG_IRQ_EN, aggr_corner.irq_en);
-+              }
-+
-+              for (i = 0; i < ctrl->thread_count; i++) {
-+                      cpr3_regulator_set_target_quot(&ctrl->thread[i]);
-+
-+                      for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                              vreg = &ctrl->thread[i].vreg[j];
-+
-+                              if (vreg->vreg_enabled)
-+                                      vreg->last_closed_loop_corner
-+                                              = vreg->current_corner;
-+                      }
-+              }
-+
-+              if (ctrl->proc_clock_throttle) {
-+                      if (aggr_corner.ceiling_volt > aggr_corner.floor_volt
-+                          && (ctrl->use_hw_closed_loop
-+                                      || new_volt < aggr_corner.ceiling_volt))
-+                              cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
-+                                              ctrl->proc_clock_throttle);
-+                      else
-+                              cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
-+                                              CPR3_PD_THROTTLE_DISABLE);
-+              }
-+
-+              /*
-+               * Ensure that all CPR register writes complete before
-+               * re-enabling CPR loop operation.
-+               */
-+              wmb();
-+      } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4
-+                 && ctrl->vdd_limit_regulator) {
-+              /* Set ceiling and floor limits in hardware */
-+              rc = regulator_set_voltage(ctrl->vdd_limit_regulator,
-+                      aggr_corner.floor_volt,
-+                      aggr_corner.ceiling_volt);
-+              if (rc) {
-+                      cpr3_err(ctrl, "could not configure HW closed-loop voltage limits, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+      }
-+
-+      ctrl->aggr_corner = aggr_corner;
-+
-+      if (ctrl->allow_core_count_adj || ctrl->allow_temp_adj
-+              || ctrl->allow_boost) {
-+              rc = cpr3_controller_program_sdelta(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "failed to program sdelta, rc=%d\n", rc);
-+                      return rc;
-+              }
-+      }
-+
-+      /*
-+       * Only enable the CPR controller if it is possible to set more than
-+       * one vdd-supply voltage.
-+       */
-+      if (aggr_corner.ceiling_volt > aggr_corner.floor_volt &&
-+                      !aggr_corner.use_open_loop)
-+              cpr3_ctrl_loop_enable(ctrl);
-+
-+      ctrl->last_corner_was_closed_loop = ctrl->cpr_enabled;
-+      cpr3_debug(ctrl, "CPR configuration updated\n");
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_wait_for_idle() - wait for the CPR controller to no longer be
-+ *            busy
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @max_wait_ns:      Max wait time in nanoseconds
-+ *
-+ * Return: 0 on success or -ETIMEDOUT if the controller was still busy after
-+ *       the maximum delay time
-+ */
-+static int cpr3_regulator_wait_for_idle(struct cpr3_controller *ctrl,
-+                                      s64 max_wait_ns)
-+{
-+      ktime_t start, end;
-+      s64 time_ns;
-+      u32 reg;
-+
-+      /*
-+       * Ensure that all previous CPR register writes have completed before
-+       * checking the status register.
-+       */
-+      mb();
-+
-+      start = ktime_get();
-+      do {
-+              end = ktime_get();
-+              time_ns = ktime_to_ns(ktime_sub(end, start));
-+              if (time_ns > max_wait_ns) {
-+                      cpr3_err(ctrl, "CPR controller still busy after %lld us\n",
-+                              div_s64(time_ns, 1000));
-+                      return -ETIMEDOUT;
-+              }
-+              usleep_range(50, 100);
-+              reg = cpr3_read(ctrl, CPR3_REG_CPR_STATUS);
-+      } while (reg & CPR3_CPR_STATUS_BUSY_MASK);
-+
-+      return 0;
-+}
-+
-+/**
-+ * cmp_int() - int comparison function to be passed into the sort() function
-+ *            which leads to ascending sorting
-+ * @a:                        First int value
-+ * @b:                        Second int value
-+ *
-+ * Return: >0 if a > b, 0 if a == b, <0 if a < b
-+ */
-+static int cmp_int(const void *a, const void *b)
-+{
-+      return *(int *)a - *(int *)b;
-+}
-+
-+/**
-+ * cpr3_regulator_measure_aging() - measure the quotient difference for the
-+ *            specified CPR aging sensor
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @aging_sensor:     Aging sensor to measure
-+ *
-+ * Note that vdd-supply must be configured to the aging reference voltage before
-+ * calling this function.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
-+                              struct cpr3_aging_sensor_info *aging_sensor)
-+{
-+      u32 mask, reg, result, quot_min, quot_max, sel_min, sel_max;
-+      u32 quot_min_scaled, quot_max_scaled;
-+      u32 gcnt, gcnt_ref, gcnt0_restore, gcnt1_restore, irq_restore;
-+      u32 ro_mask_restore, cont_dly_restore, up_down_dly_restore = 0;
-+      int quot_delta, quot_delta_scaled, quot_delta_scaled_sum;
-+      int *quot_delta_results;
-+      int rc, rc2, i, aging_measurement_count, filtered_count;
-+      bool is_aging_measurement;
-+
-+      quot_delta_results = kcalloc(CPR3_AGING_MEASUREMENT_ITERATIONS,
-+                      sizeof(*quot_delta_results), GFP_KERNEL);
-+      if (!quot_delta_results)
-+              return -ENOMEM;
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc);
-+                      kfree(quot_delta_results);
-+                      return rc;
-+              }
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      /* Enable up, down, and mid CPR interrupts */
-+      irq_restore = cpr3_read(ctrl, CPR3_REG_IRQ_EN);
-+      cpr3_write(ctrl, CPR3_REG_IRQ_EN,
-+                      CPR3_IRQ_UP | CPR3_IRQ_DOWN | CPR3_IRQ_MID);
-+
-+      /* Ensure that the aging sensor is assigned to CPR thread 0 */
-+      cpr3_write(ctrl, CPR3_REG_SENSOR_OWNER(aging_sensor->sensor_id), 0);
-+
-+      /* Switch from HW to SW closed-loop if necessary */
-+      if (ctrl->supports_hw_closed_loop) {
-+              if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+                      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                              CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
-+                              CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
-+              } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+                      cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
-+                              CPR3_HW_CLOSED_LOOP_DISABLE);
-+              }
-+      }
-+
-+      /* Configure the GCNT for RO0 and RO1 that are used for aging */
-+      gcnt0_restore = cpr3_read(ctrl, CPR3_REG_GCNT(0));
-+      gcnt1_restore = cpr3_read(ctrl, CPR3_REG_GCNT(1));
-+      gcnt_ref = cpr3_regulator_get_gcnt(ctrl);
-+      gcnt = gcnt_ref * 3 / 2;
-+      cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt);
-+      cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt);
-+
-+      /* Unmask all RO's */
-+      ro_mask_restore = cpr3_read(ctrl, CPR3_REG_RO_MASK(0));
-+      cpr3_write(ctrl, CPR3_REG_RO_MASK(0), 0);
-+
-+      /*
-+       * Mask all sensors except for the one to measure and bypass all
-+       * sensors in collapsible domains.
-+       */
-+      for (i = 0; i <= ctrl->sensor_count / 32; i++) {
-+              mask = GENMASK(min(31, ctrl->sensor_count - i * 32), 0);
-+              if (aging_sensor->sensor_id / 32 >= i
-+                  && aging_sensor->sensor_id / 32 < (i + 1))
-+                      mask &= ~BIT(aging_sensor->sensor_id % 32);
-+              cpr3_write(ctrl, CPR3_REG_SENSOR_MASK_WRITE_BANK(i), mask);
-+              cpr3_write(ctrl, CPR3_REG_SENSOR_BYPASS_WRITE_BANK(i),
-+                              aging_sensor->bypass_mask[i]);
-+      }
-+
-+      /* Set CPR loop delays to 0 us */
-+      if (ctrl->supports_hw_closed_loop
-+              && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              cont_dly_restore = cpr3_read(ctrl, CPR3_REG_CPR_TIMER_MID_CONT);
-+              up_down_dly_restore = cpr3_read(ctrl,
-+                                              CPR3_REG_CPR_TIMER_UP_DN_CONT);
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_MID_CONT, 0);
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_UP_DN_CONT, 0);
-+      } else {
-+              cont_dly_restore = cpr3_read(ctrl,
-+                                              CPR3_REG_CPR_TIMER_AUTO_CONT);
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_AUTO_CONT, 0);
-+      }
-+
-+      /* Set count mode to all-at-once min with no repeat */
-+      cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
-+              CPR3_CPR_CTL_COUNT_MODE_MASK | CPR3_CPR_CTL_COUNT_REPEAT_MASK,
-+              CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN
-+                      << CPR3_CPR_CTL_COUNT_MODE_SHIFT);
-+
-+      cpr3_ctrl_loop_enable(ctrl);
-+
-+      rc = cpr3_regulator_wait_for_idle(ctrl,
-+                                      CPR3_AGING_MEASUREMENT_TIMEOUT_NS);
-+      if (rc)
-+              goto cleanup;
-+
-+      /* Set count mode to all-at-once aging */
-+      cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL, CPR3_CPR_CTL_COUNT_MODE_MASK,
-+                      CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_AGE
-+                              << CPR3_CPR_CTL_COUNT_MODE_SHIFT);
-+
-+      aging_measurement_count = 0;
-+      for (i = 0; i < CPR3_AGING_MEASUREMENT_ITERATIONS; i++) {
-+              /* Send CONT_NACK */
-+              cpr3_write(ctrl, CPR3_REG_CONT_CMD, CPR3_CONT_CMD_NACK);
-+
-+              rc = cpr3_regulator_wait_for_idle(ctrl,
-+                                      CPR3_AGING_MEASUREMENT_TIMEOUT_NS);
-+              if (rc)
-+                      goto cleanup;
-+
-+              /* Check for PAGE_IS_AGE flag in status register */
-+              reg = cpr3_read(ctrl, CPR3_REG_CPR_STATUS);
-+              is_aging_measurement
-+                      = reg & CPR3_CPR_STATUS_AGING_MEASUREMENT_MASK;
-+
-+              /* Read CPR measurement results */
-+              result = cpr3_read(ctrl, CPR3_REG_RESULT1(0));
-+              quot_min = (result & CPR3_RESULT1_QUOT_MIN_MASK)
-+                              >> CPR3_RESULT1_QUOT_MIN_SHIFT;
-+              quot_max = (result & CPR3_RESULT1_QUOT_MAX_MASK)
-+                              >> CPR3_RESULT1_QUOT_MAX_SHIFT;
-+              sel_min = (result & CPR3_RESULT1_RO_MIN_MASK)
-+                              >> CPR3_RESULT1_RO_MIN_SHIFT;
-+              sel_max = (result & CPR3_RESULT1_RO_MAX_MASK)
-+                              >> CPR3_RESULT1_RO_MAX_SHIFT;
-+
-+              /*
-+               * Scale the quotients so that they are equivalent to the fused
-+               * values.  This accounts for the difference in measurement
-+               * interval times.
-+               */
-+              quot_min_scaled = quot_min * (gcnt_ref + 1) / (gcnt + 1);
-+              quot_max_scaled = quot_max * (gcnt_ref + 1) / (gcnt + 1);
-+
-+              if (sel_max == 1) {
-+                      quot_delta = quot_max - quot_min;
-+                      quot_delta_scaled = quot_max_scaled - quot_min_scaled;
-+              } else {
-+                      quot_delta = quot_min - quot_max;
-+                      quot_delta_scaled = quot_min_scaled - quot_max_scaled;
-+              }
-+
-+              if (is_aging_measurement)
-+                      quot_delta_results[aging_measurement_count++]
-+                              = quot_delta_scaled;
-+
-+              cpr3_debug(ctrl, "aging results: page_is_age=%u, sel_min=%u, sel_max=%u, quot_min=%u, quot_max=%u, quot_delta=%d, quot_min_scaled=%u, quot_max_scaled=%u, quot_delta_scaled=%d\n",
-+                      is_aging_measurement, sel_min, sel_max, quot_min,
-+                      quot_max, quot_delta, quot_min_scaled, quot_max_scaled,
-+                      quot_delta_scaled);
-+      }
-+
-+      filtered_count
-+              = aging_measurement_count - CPR3_AGING_MEASUREMENT_FILTER * 2;
-+      if (filtered_count > 0) {
-+              sort(quot_delta_results, aging_measurement_count,
-+                      sizeof(*quot_delta_results), cmp_int, NULL);
-+
-+              quot_delta_scaled_sum = 0;
-+              for (i = 0; i < filtered_count; i++)
-+                      quot_delta_scaled_sum
-+                              += quot_delta_results[i
-+                                      + CPR3_AGING_MEASUREMENT_FILTER];
-+
-+              aging_sensor->measured_quot_diff
-+                      = quot_delta_scaled_sum / filtered_count;
-+              cpr3_info(ctrl, "average quotient delta=%d (count=%d)\n",
-+                      aging_sensor->measured_quot_diff,
-+                      filtered_count);
-+      } else {
-+              cpr3_err(ctrl, "%d aging measurements completed after %d iterations\n",
-+                      aging_measurement_count,
-+                      CPR3_AGING_MEASUREMENT_ITERATIONS);
-+              rc = -EBUSY;
-+      }
-+
-+cleanup:
-+      kfree(quot_delta_results);
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc2 = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc2) {
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc2);
-+                      rc = rc2;
-+              }
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      cpr3_write(ctrl, CPR3_REG_IRQ_EN, irq_restore);
-+
-+      cpr3_write(ctrl, CPR3_REG_RO_MASK(0), ro_mask_restore);
-+
-+      cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt0_restore);
-+      cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt1_restore);
-+
-+      if (ctrl->supports_hw_closed_loop
-+              && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_MID_CONT, cont_dly_restore);
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_UP_DN_CONT,
-+                              up_down_dly_restore);
-+      } else {
-+              cpr3_write(ctrl, CPR3_REG_CPR_TIMER_AUTO_CONT,
-+                              cont_dly_restore);
-+      }
-+
-+      for (i = 0; i <= ctrl->sensor_count / 32; i++) {
-+              cpr3_write(ctrl, CPR3_REG_SENSOR_MASK_WRITE_BANK(i), 0);
-+              cpr3_write(ctrl, CPR3_REG_SENSOR_BYPASS_WRITE_BANK(i), 0);
-+      }
-+
-+      cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
-+              CPR3_CPR_CTL_COUNT_MODE_MASK | CPR3_CPR_CTL_COUNT_REPEAT_MASK,
-+              (ctrl->count_mode << CPR3_CPR_CTL_COUNT_MODE_SHIFT)
-+              | (ctrl->count_repeat << CPR3_CPR_CTL_COUNT_REPEAT_SHIFT));
-+
-+      cpr3_write(ctrl, CPR3_REG_SENSOR_OWNER(aging_sensor->sensor_id),
-+                      ctrl->sensor_owner[aging_sensor->sensor_id]);
-+
-+      cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR,
-+                      CPR3_IRQ_UP | CPR3_IRQ_DOWN | CPR3_IRQ_MID);
-+
-+      if (ctrl->supports_hw_closed_loop) {
-+              if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+                      cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                              CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
-+                              ctrl->use_hw_closed_loop
-+                              ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
-+                              : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
-+              } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+                      cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
-+                              ctrl->use_hw_closed_loop
-+                              ? CPR3_HW_CLOSED_LOOP_ENABLE
-+                              : CPR3_HW_CLOSED_LOOP_DISABLE);
-+              }
-+      }
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_regulator_readjust_volt_and_quot() - readjust the target quotients as
-+ *            well as the floor, ceiling, and open-loop voltages for the
-+ *            regulator by removing the old adjustment and adding the new one
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @old_adjust_volt:  Old aging adjustment voltage in microvolts
-+ * @new_adjust_volt:  New aging adjustment voltage in microvolts
-+ *
-+ * Also reset the cached closed loop voltage (last_volt) to equal the open-loop
-+ * voltage for each corner.
-+ *
-+ * Return: None
-+ */
-+static void cpr3_regulator_readjust_volt_and_quot(struct cpr3_regulator *vreg,
-+              int old_adjust_volt, int new_adjust_volt)
-+{
-+      unsigned long long temp;
-+      int i, j, old_volt, new_volt, rounded_volt;
-+
-+      if (!vreg->aging_allowed)
-+              return;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              temp = (unsigned long long)old_adjust_volt
-+                      * (unsigned long long)vreg->corner[i].aging_derate;
-+              do_div(temp, 1000);
-+              old_volt = temp;
-+
-+              temp = (unsigned long long)new_adjust_volt
-+                      * (unsigned long long)vreg->corner[i].aging_derate;
-+              do_div(temp, 1000);
-+              new_volt = temp;
-+
-+              old_volt = min(vreg->aging_max_adjust_volt, old_volt);
-+              new_volt = min(vreg->aging_max_adjust_volt, new_volt);
-+
-+              for (j = 0; j < CPR3_RO_COUNT; j++) {
-+                      if (vreg->corner[i].target_quot[j] != 0) {
-+                              vreg->corner[i].target_quot[j]
-+                                      += cpr3_quot_adjustment(
-+                                              vreg->corner[i].ro_scale[j],
-+                                              new_volt)
-+                                         - cpr3_quot_adjustment(
-+                                              vreg->corner[i].ro_scale[j],
-+                                              old_volt);
-+                      }
-+              }
-+
-+              rounded_volt = CPR3_ROUND(new_volt,
-+                                      vreg->thread->ctrl->step_volt);
-+
-+              if (!vreg->aging_allow_open_loop_adj)
-+                      rounded_volt = 0;
-+
-+              vreg->corner[i].ceiling_volt
-+                      = vreg->corner[i].unaged_ceiling_volt + rounded_volt;
-+              vreg->corner[i].ceiling_volt = min(vreg->corner[i].ceiling_volt,
-+                                            vreg->corner[i].abs_ceiling_volt);
-+              vreg->corner[i].floor_volt
-+                      = vreg->corner[i].unaged_floor_volt + rounded_volt;
-+              vreg->corner[i].floor_volt = min(vreg->corner[i].floor_volt,
-+                                              vreg->corner[i].ceiling_volt);
-+              vreg->corner[i].open_loop_volt
-+                      = vreg->corner[i].unaged_open_loop_volt + rounded_volt;
-+              vreg->corner[i].open_loop_volt
-+                      = min(vreg->corner[i].open_loop_volt,
-+                              vreg->corner[i].ceiling_volt);
-+
-+              vreg->corner[i].last_volt = vreg->corner[i].open_loop_volt;
-+
-+              cpr3_debug(vreg, "corner %d: applying %d uV closed-loop and %d uV open-loop voltage margin adjustment\n",
-+                      i, new_volt, rounded_volt);
-+      }
-+}
-+
-+/**
-+ * cpr3_regulator_set_aging_ref_adjustment() - adjust target quotients for the
-+ *            regulators managed by this CPR controller to account for aging
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @ref_adjust_volt:  New aging reference adjustment voltage in microvolts to
-+ *                    apply to all regulators managed by this CPR controller
-+ *
-+ * The existing aging adjustment as defined by ctrl->aging_ref_adjust_volt is
-+ * first removed and then the adjustment is applied.  Lastly, the value of
-+ * ctrl->aging_ref_adjust_volt is updated to ref_adjust_volt.
-+ */
-+static void cpr3_regulator_set_aging_ref_adjustment(
-+              struct cpr3_controller *ctrl, int ref_adjust_volt)
-+{
-+      struct cpr3_regulator *vreg;
-+      int i, j;
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+                      cpr3_regulator_readjust_volt_and_quot(vreg,
-+                              ctrl->aging_ref_adjust_volt, ref_adjust_volt);
-+              }
-+      }
-+
-+      ctrl->aging_ref_adjust_volt = ref_adjust_volt;
-+}
-+
-+/**
-+ * cpr3_regulator_aging_adjust() - adjust the target quotients for regulators
-+ *            based on the output of CPR aging sensors
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_aging_adjust(struct cpr3_controller *ctrl)
-+{
-+      struct cpr3_regulator *vreg;
-+      struct cpr3_corner restore_aging_corner;
-+      struct cpr3_corner *corner;
-+      int *restore_current_corner;
-+      bool *restore_vreg_enabled;
-+      int i, j, id, rc, rc2, vreg_count, aging_volt, max_aging_volt = 0;
-+      u32 reg;
-+
-+      if (!ctrl->aging_required || !ctrl->cpr_enabled
-+          || ctrl->aggr_corner.ceiling_volt == 0
-+          || ctrl->aggr_corner.ceiling_volt > ctrl->aging_ref_volt)
-+              return 0;
-+
-+      for (i = 0, vreg_count = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+                      vreg_count++;
-+
-+                      if (vreg->aging_allowed && vreg->vreg_enabled
-+                          && vreg->current_corner > vreg->aging_corner)
-+                              return 0;
-+              }
-+      }
-+
-+      /* Verify that none of the aging sensors are currently masked. */
-+      for (i = 0; i < ctrl->aging_sensor_count; i++) {
-+              id = ctrl->aging_sensor[i].sensor_id;
-+              reg = cpr3_read(ctrl, CPR3_REG_SENSOR_MASK_READ(id));
-+              if (reg & BIT(id % 32))
-+                      return 0;
-+      }
-+
-+      /*
-+       * Verify that the aging possible register (if specified) has an
-+       * acceptable value.
-+       */
-+      if (ctrl->aging_possible_reg) {
-+              reg = readl_relaxed(ctrl->aging_possible_reg);
-+              reg &= ctrl->aging_possible_mask;
-+              if (reg != ctrl->aging_possible_val)
-+                      return 0;
-+      }
-+
-+      restore_current_corner = kcalloc(vreg_count,
-+                              sizeof(*restore_current_corner), GFP_KERNEL);
-+      restore_vreg_enabled = kcalloc(vreg_count,
-+                              sizeof(*restore_vreg_enabled), GFP_KERNEL);
-+      if (!restore_current_corner || !restore_vreg_enabled) {
-+              kfree(restore_current_corner);
-+              kfree(restore_vreg_enabled);
-+              return -ENOMEM;
-+      }
-+
-+      /* Force all regulators to the aging corner */
-+      for (i = 0, vreg_count = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++, vreg_count++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+
-+                      restore_current_corner[vreg_count]
-+                              = vreg->current_corner;
-+                      restore_vreg_enabled[vreg_count]
-+                              = vreg->vreg_enabled;
-+
-+                      vreg->current_corner = vreg->aging_corner;
-+                      vreg->vreg_enabled = true;
-+              }
-+      }
-+
-+      /* Force one of the regulators to require the aging reference voltage */
-+      vreg = &ctrl->thread[0].vreg[0];
-+      corner = &vreg->corner[vreg->current_corner];
-+      restore_aging_corner = *corner;
-+      corner->ceiling_volt = ctrl->aging_ref_volt;
-+      corner->floor_volt = ctrl->aging_ref_volt;
-+      corner->open_loop_volt = ctrl->aging_ref_volt;
-+      corner->last_volt = ctrl->aging_ref_volt;
-+
-+      /* Skip last_volt caching */
-+      ctrl->last_corner_was_closed_loop = false;
-+
-+      /* Set the vdd supply voltage to the aging reference voltage */
-+      rc = _cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "unable to force vdd-supply to the aging reference voltage=%d uV, rc=%d\n",
-+                      ctrl->aging_ref_volt, rc);
-+              goto cleanup;
-+      }
-+
-+      if (ctrl->aging_vdd_mode) {
-+              rc = regulator_set_mode(ctrl->vdd_regulator,
-+                                      ctrl->aging_vdd_mode);
-+              if (rc) {
-+                      cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
-+                              ctrl->aging_vdd_mode, rc);
-+                      goto cleanup;
-+              }
-+      }
-+
-+      /* Perform aging measurement on all aging sensors */
-+      for (i = 0; i < ctrl->aging_sensor_count; i++) {
-+              for (j = 0; j < CPR3_AGING_RETRY_COUNT; j++) {
-+                      rc = cpr3_regulator_measure_aging(ctrl,
-+                                      &ctrl->aging_sensor[i]);
-+                      if (!rc)
-+                              break;
-+              }
-+
-+              if (!rc) {
-+                      aging_volt =
-+                              cpr3_voltage_adjustment(
-+                                      ctrl->aging_sensor[i].ro_scale,
-+                                      ctrl->aging_sensor[i].measured_quot_diff
-+                                      - ctrl->aging_sensor[i].init_quot_diff);
-+                      max_aging_volt = max(max_aging_volt, aging_volt);
-+              } else {
-+                      cpr3_err(ctrl, "CPR aging measurement failed after %d tries, rc=%d\n",
-+                              j, rc);
-+                      ctrl->aging_failed = true;
-+                      ctrl->aging_required = false;
-+                      goto cleanup;
-+              }
-+      }
-+
-+cleanup:
-+      vreg = &ctrl->thread[0].vreg[0];
-+      vreg->corner[vreg->current_corner] = restore_aging_corner;
-+
-+      for (i = 0, vreg_count = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++, vreg_count++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+                      vreg->current_corner
-+                              = restore_current_corner[vreg_count];
-+                      vreg->vreg_enabled = restore_vreg_enabled[vreg_count];
-+              }
-+      }
-+
-+      kfree(restore_current_corner);
-+      kfree(restore_vreg_enabled);
-+
-+      /* Adjust the CPR target quotients according to the aging measurement */
-+      if (!rc) {
-+              cpr3_regulator_set_aging_ref_adjustment(ctrl, max_aging_volt);
-+
-+              cpr3_info(ctrl, "aging measurement successful; aging reference adjustment voltage=%d uV\n",
-+                      ctrl->aging_ref_adjust_volt);
-+              ctrl->aging_succeeded = true;
-+              ctrl->aging_required = false;
-+      }
-+
-+      if (ctrl->aging_complete_vdd_mode) {
-+              rc = regulator_set_mode(ctrl->vdd_regulator,
-+                                      ctrl->aging_complete_vdd_mode);
-+              if (rc)
-+                      cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
-+                              ctrl->aging_complete_vdd_mode, rc);
-+      }
-+
-+      /* Skip last_volt caching */
-+      ctrl->last_corner_was_closed_loop = false;
-+
-+      /*
-+       * Restore vdd-supply to the voltage before the aging measurement and
-+       * restore the CPR3 controller hardware state.
-+       */
-+      rc2 = _cpr3_regulator_update_ctrl_state(ctrl);
-+
-+      /* Stop last_volt caching on for the next request */
-+      ctrl->last_corner_was_closed_loop = false;
-+
-+      return rc ? rc : rc2;
-+}
-+
-+/**
-+ * cpr3_regulator_update_ctrl_state() - update the state of the CPR controller
-+ *            to reflect the corners used by all CPR3 regulators as well as
-+ *            the CPR operating mode and perform aging adjustments if needed
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Note, CPR3 controller lock must be held by the caller.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      rc = _cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc)
-+              return rc;
-+
-+      return cpr3_regulator_aging_adjust(ctrl);
-+}
-+
-+/**
-+ * cpr3_regulator_set_voltage() - set the voltage corner for the CPR3 regulator
-+ *                    associated with the regulator device
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ * @corner:           New voltage corner to set (offset by CPR3_CORNER_OFFSET)
-+ * @corner_max:               Maximum voltage corner allowed (offset by
-+ *                    CPR3_CORNER_OFFSET)
-+ * @selector:         Pointer which is filled with the selector value for the
-+ *                    corner
-+ *
-+ * This function is passed as a callback function into the regulator ops that
-+ * are registered for each cpr3-regulator device.  The VDD voltage will not be
-+ * physically configured until both this function and cpr3_regulator_enable()
-+ * are called.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_set_voltage(struct regulator_dev *rdev,
-+              int corner, int corner_max, unsigned *selector)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      int rc = 0;
-+      int last_corner;
-+
-+      corner -= CPR3_CORNER_OFFSET;
-+      corner_max -= CPR3_CORNER_OFFSET;
-+      *selector = corner;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (!vreg->vreg_enabled) {
-+              vreg->current_corner = corner;
-+              cpr3_debug(vreg, "stored corner=%d\n", corner);
-+              goto done;
-+      } else if (vreg->current_corner == corner) {
-+              goto done;
-+      }
-+
-+      last_corner = vreg->current_corner;
-+      vreg->current_corner = corner;
-+
-+      if (vreg->cpr4_regulator_data != NULL)
-+              if (vreg->cpr4_regulator_data->mem_acc_funcs != NULL)
-+                      vreg->cpr4_regulator_data->mem_acc_funcs->set_mem_acc(rdev);
-+
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(vreg, "could not update CPR state, rc=%d\n", rc);
-+              vreg->current_corner = last_corner;
-+      }
-+
-+      if (vreg->cpr4_regulator_data != NULL)
-+              if (vreg->cpr4_regulator_data->mem_acc_funcs != NULL)
-+                      vreg->cpr4_regulator_data->mem_acc_funcs->clear_mem_acc(rdev);
-+
-+      cpr3_debug(vreg, "set corner=%d\n", corner);
-+done:
-+      mutex_unlock(&ctrl->lock);
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_handle_temp_open_loop_adjustment() - voltage based cold temperature
-+ *
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ * @is_cold:          Flag to denote enter/exit cold condition
-+ *
-+ * This function is adjusts voltage margin based on cold condition
-+ *
-+ * Return: 0 = success
-+ */
-+
-+int cpr3_handle_temp_open_loop_adjustment(struct cpr3_controller *ctrl,
-+                                                              bool is_cold)
-+{
-+      int i ,j, k, rc;
-+      struct cpr3_regulator *vreg;
-+
-+      mutex_lock(&ctrl->lock);
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+                      for (k = 0; k < vreg->corner_count; k++) {
-+                              vreg->corner[k].open_loop_volt = is_cold ?
-+                                  vreg->corner[k].cold_temp_open_loop_volt :
-+                                  vreg->corner[k].normal_temp_open_loop_volt;
-+                      }
-+              }
-+      }
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      mutex_unlock(&ctrl->lock);
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_regulator_get_voltage() - get the voltage corner for the CPR3 regulator
-+ *                    associated with the regulator device
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ *
-+ * This function is passed as a callback function into the regulator ops that
-+ * are registered for each cpr3-regulator device.
-+ *
-+ * Return: voltage corner value offset by CPR3_CORNER_OFFSET
-+ */
-+static int cpr3_regulator_get_voltage(struct regulator_dev *rdev)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+
-+      if (vreg->current_corner == CPR3_REGULATOR_CORNER_INVALID)
-+              return CPR3_CORNER_OFFSET;
-+      else
-+              return vreg->current_corner + CPR3_CORNER_OFFSET;
-+}
-+
-+/**
-+ * cpr3_regulator_list_voltage() - return the voltage corner mapped to the
-+ *                    specified selector
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ * @selector:         Regulator selector
-+ *
-+ * This function is passed as a callback function into the regulator ops that
-+ * are registered for each cpr3-regulator device.
-+ *
-+ * Return: voltage corner value offset by CPR3_CORNER_OFFSET
-+ */
-+static int cpr3_regulator_list_voltage(struct regulator_dev *rdev,
-+              unsigned selector)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+
-+      if (selector < vreg->corner_count)
-+              return selector + CPR3_CORNER_OFFSET;
-+      else
-+              return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_is_enabled() - return the enable state of the CPR3 regulator
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ *
-+ * This function is passed as a callback function into the regulator ops that
-+ * are registered for each cpr3-regulator device.
-+ *
-+ * Return: true if regulator is enabled, false if regulator is disabled
-+ */
-+static int cpr3_regulator_is_enabled(struct regulator_dev *rdev)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+
-+      return vreg->vreg_enabled;
-+}
-+
-+/**
-+ * cpr3_regulator_enable() - enable the CPR3 regulator
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ *
-+ * This function is passed as a callback function into the regulator ops that
-+ * are registered for each cpr3-regulator device.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_enable(struct regulator_dev *rdev)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      int rc = 0;
-+
-+      if (vreg->vreg_enabled == true)
-+              return 0;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (ctrl->system_regulator) {
-+              rc = regulator_enable(ctrl->system_regulator);
-+              if (rc) {
-+                      cpr3_err(ctrl, "regulator_enable(system) failed, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      rc = regulator_enable(ctrl->vdd_regulator);
-+      if (rc) {
-+              cpr3_err(vreg, "regulator_enable(vdd) failed, rc=%d\n", rc);
-+              goto done;
-+      }
-+
-+      vreg->vreg_enabled = true;
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(vreg, "could not update CPR state, rc=%d\n", rc);
-+              regulator_disable(ctrl->vdd_regulator);
-+              vreg->vreg_enabled = false;
-+              goto done;
-+      }
-+
-+      cpr3_debug(vreg, "Enabled\n");
-+done:
-+      mutex_unlock(&ctrl->lock);
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_regulator_disable() - disable the CPR3 regulator
-+ * @rdev:             Regulator device pointer for the cpr3-regulator
-+ *
-+ * This function is passed as a callback function into the regulator ops that
-+ * are registered for each cpr3-regulator device.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_disable(struct regulator_dev *rdev)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      int rc, rc2;
-+
-+      if (vreg->vreg_enabled == false)
-+              return 0;
-+
-+      mutex_lock(&ctrl->lock);
-+      rc = regulator_disable(ctrl->vdd_regulator);
-+      if (rc) {
-+              cpr3_err(vreg, "regulator_disable(vdd) failed, rc=%d\n", rc);
-+              goto done;
-+      }
-+
-+      vreg->vreg_enabled = false;
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(vreg, "could not update CPR state, rc=%d\n", rc);
-+              rc2 = regulator_enable(ctrl->vdd_regulator);
-+              vreg->vreg_enabled = true;
-+              goto done;
-+      }
-+
-+      if (ctrl->system_regulator) {
-+              rc = regulator_disable(ctrl->system_regulator);
-+              if (rc) {
-+                      cpr3_err(ctrl, "regulator_disable(system) failed, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      cpr3_debug(vreg, "Disabled\n");
-+done:
-+      mutex_unlock(&ctrl->lock);
-+
-+      return rc;
-+}
-+
-+static struct regulator_ops cpr3_regulator_ops = {
-+      .enable                 = cpr3_regulator_enable,
-+      .disable                = cpr3_regulator_disable,
-+      .is_enabled             = cpr3_regulator_is_enabled,
-+      .set_voltage            = cpr3_regulator_set_voltage,
-+      .get_voltage            = cpr3_regulator_get_voltage,
-+      .list_voltage           = cpr3_regulator_list_voltage,
-+};
-+
-+/**
-+ * cpr3_print_result() - print CPR measurement results to the kernel log for
-+ *            debugging purposes
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: None
-+ */
-+static void cpr3_print_result(struct cpr3_thread *thread)
-+{
-+      struct cpr3_controller *ctrl = thread->ctrl;
-+      u32 result[3], busy, step_dn, step_up, error_steps, error, negative;
-+      u32 quot_min, quot_max, ro_min, ro_max, step_quot_min, step_quot_max;
-+      u32 sensor_min, sensor_max;
-+      char *sign;
-+
-+      result[0] = cpr3_read(ctrl, CPR3_REG_RESULT0(thread->thread_id));
-+      result[1] = cpr3_read(ctrl, CPR3_REG_RESULT1(thread->thread_id));
-+      result[2] = cpr3_read(ctrl, CPR3_REG_RESULT2(thread->thread_id));
-+
-+      busy = !!(result[0] & CPR3_RESULT0_BUSY_MASK);
-+      step_dn = !!(result[0] & CPR3_RESULT0_STEP_DN_MASK);
-+      step_up = !!(result[0] & CPR3_RESULT0_STEP_UP_MASK);
-+      error_steps = (result[0] & CPR3_RESULT0_ERROR_STEPS_MASK)
-+                      >> CPR3_RESULT0_ERROR_STEPS_SHIFT;
-+      error = (result[0] & CPR3_RESULT0_ERROR_MASK)
-+                      >> CPR3_RESULT0_ERROR_SHIFT;
-+      negative = !!(result[0] & CPR3_RESULT0_NEGATIVE_MASK);
-+
-+      quot_min = (result[1] & CPR3_RESULT1_QUOT_MIN_MASK)
-+                      >> CPR3_RESULT1_QUOT_MIN_SHIFT;
-+      quot_max = (result[1] & CPR3_RESULT1_QUOT_MAX_MASK)
-+                      >> CPR3_RESULT1_QUOT_MAX_SHIFT;
-+      ro_min = (result[1] & CPR3_RESULT1_RO_MIN_MASK)
-+                      >> CPR3_RESULT1_RO_MIN_SHIFT;
-+      ro_max = (result[1] & CPR3_RESULT1_RO_MAX_MASK)
-+                      >> CPR3_RESULT1_RO_MAX_SHIFT;
-+
-+      step_quot_min = (result[2] & CPR3_RESULT2_STEP_QUOT_MIN_MASK)
-+                      >> CPR3_RESULT2_STEP_QUOT_MIN_SHIFT;
-+      step_quot_max = (result[2] & CPR3_RESULT2_STEP_QUOT_MAX_MASK)
-+                      >> CPR3_RESULT2_STEP_QUOT_MAX_SHIFT;
-+      sensor_min = (result[2] & CPR3_RESULT2_SENSOR_MIN_MASK)
-+                      >> CPR3_RESULT2_SENSOR_MIN_SHIFT;
-+      sensor_max = (result[2] & CPR3_RESULT2_SENSOR_MAX_MASK)
-+                      >> CPR3_RESULT2_SENSOR_MAX_SHIFT;
-+
-+      sign = negative ? "-" : "";
-+      cpr3_debug(ctrl, "thread %u: busy=%u, step_dn=%u, step_up=%u, error_steps=%s%u, error=%s%u\n",
-+              thread->thread_id, busy, step_dn, step_up, sign, error_steps,
-+              sign, error);
-+      cpr3_debug(ctrl, "thread %u: quot_min=%u, quot_max=%u, ro_min=%u, ro_max=%u\n",
-+              thread->thread_id, quot_min, quot_max, ro_min, ro_max);
-+      cpr3_debug(ctrl, "thread %u: step_quot_min=%u, step_quot_max=%u, sensor_min=%u, sensor_max=%u\n",
-+              thread->thread_id, step_quot_min, step_quot_max, sensor_min,
-+              sensor_max);
-+}
-+
-+/**
-+ * cpr3_thread_busy() - returns if the specified CPR3 thread is busy taking
-+ *            a measurement
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: CPR3 busy status
-+ */
-+static bool cpr3_thread_busy(struct cpr3_thread *thread)
-+{
-+      u32 result;
-+
-+      result = cpr3_read(thread->ctrl, CPR3_REG_RESULT0(thread->thread_id));
-+
-+      return !!(result & CPR3_RESULT0_BUSY_MASK);
-+}
-+
-+/**
-+ * cpr3_irq_handler() - CPR interrupt handler callback function used for
-+ *            software closed-loop operation
-+ * @irq:              CPR interrupt number
-+ * @data:             Private data corresponding to the CPR3 controller
-+ *                    pointer
-+ *
-+ * This function increases or decreases the vdd supply voltage based upon the
-+ * CPR controller recommendation.
-+ *
-+ * Return: IRQ_HANDLED
-+ */
-+static irqreturn_t cpr3_irq_handler(int irq, void *data)
-+{
-+      struct cpr3_controller *ctrl = data;
-+      struct cpr3_corner *aggr = &ctrl->aggr_corner;
-+      u32 cont = CPR3_CONT_CMD_NACK;
-+      u32 reg_last_measurement = 0;
-+      struct cpr3_regulator *vreg;
-+      struct cpr3_corner *corner;
-+      unsigned long flags;
-+      int i, j, new_volt, last_volt, dynamic_floor_volt, rc;
-+      u32 irq_en, status, cpr_status, ctl;
-+      bool up, down;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (!ctrl->cpr_enabled) {
-+              cpr3_debug(ctrl, "CPR interrupt received but CPR is disabled\n");
-+              mutex_unlock(&ctrl->lock);
-+              return IRQ_HANDLED;
-+      } else if (ctrl->use_hw_closed_loop) {
-+              cpr3_debug(ctrl, "CPR interrupt received but CPR is using HW closed-loop\n");
-+              goto done;
-+      }
-+
-+      /*
-+       * CPR IRQ status checking and CPR controller disabling must happen
-+       * atomically and without invening delay in order to avoid an interrupt
-+       * storm caused by the handler racing with the CPR controller.
-+       */
-+      local_irq_save(flags);
-+      preempt_disable();
-+
-+      status = cpr3_read(ctrl, CPR3_REG_IRQ_STATUS);
-+      up = status & CPR3_IRQ_UP;
-+      down = status & CPR3_IRQ_DOWN;
-+
-+      if (!up && !down) {
-+              /*
-+               * Toggle the CPR controller off and then back on since the
-+               * hardware and software states are out of sync.  This condition
-+               * occurs after an aging measurement completes as the CPR IRQ
-+               * physically triggers during the aging measurement but the
-+               * handler is stuck waiting on the mutex lock.
-+               */
-+              cpr3_ctrl_loop_disable(ctrl);
-+
-+              local_irq_restore(flags);
-+              preempt_enable();
-+
-+              /* Wait for the loop disable write to complete */
-+              mb();
-+
-+              /* Wait for BUSY=1 and LOOP_EN=0 in CPR controller registers. */
-+              for (i = 0; i < CPR3_REGISTER_WRITE_DELAY_US / 10; i++) {
-+                      cpr_status = cpr3_read(ctrl, CPR3_REG_CPR_STATUS);
-+                      ctl = cpr3_read(ctrl, CPR3_REG_CPR_CTL);
-+                      if (cpr_status & CPR3_CPR_STATUS_BUSY_MASK
-+                          && (ctl & CPR3_CPR_CTL_LOOP_EN_MASK)
-+                                      == CPR3_CPR_CTL_LOOP_DISABLE)
-+                              break;
-+                      udelay(10);
-+              }
-+              if (i == CPR3_REGISTER_WRITE_DELAY_US / 10)
-+                      cpr3_debug(ctrl, "CPR controller not disabled after %d us\n",
-+                              CPR3_REGISTER_WRITE_DELAY_US);
-+
-+              /* Clear interrupt status */
-+              cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR,
-+                      CPR3_IRQ_UP | CPR3_IRQ_DOWN);
-+
-+              /* Wait for the interrupt clearing write to complete */
-+              mb();
-+
-+              /* Wait for IRQ_STATUS register to be cleared. */
-+              for (i = 0; i < CPR3_REGISTER_WRITE_DELAY_US / 10; i++) {
-+                      status = cpr3_read(ctrl, CPR3_REG_IRQ_STATUS);
-+                      if (!(status & (CPR3_IRQ_UP | CPR3_IRQ_DOWN)))
-+                              break;
-+                      udelay(10);
-+              }
-+              if (i == CPR3_REGISTER_WRITE_DELAY_US / 10)
-+                      cpr3_debug(ctrl, "CPR interrupts not cleared after %d us\n",
-+                              CPR3_REGISTER_WRITE_DELAY_US);
-+
-+              cpr3_ctrl_loop_enable(ctrl);
-+
-+              cpr3_debug(ctrl, "CPR interrupt received but no up or down status bit is set\n");
-+
-+              mutex_unlock(&ctrl->lock);
-+              return IRQ_HANDLED;
-+      } else if (up && down) {
-+              cpr3_debug(ctrl, "both up and down status bits set\n");
-+              /* The up flag takes precedence over the down flag. */
-+              down = false;
-+      }
-+
-+      if (ctrl->supports_hw_closed_loop)
-+              reg_last_measurement
-+                      = cpr3_read(ctrl, CPR3_REG_LAST_MEASUREMENT);
-+      dynamic_floor_volt = cpr3_regulator_get_dynamic_floor_volt(ctrl,
-+                                                      reg_last_measurement);
-+
-+      local_irq_restore(flags);
-+      preempt_enable();
-+
-+      irq_en = aggr->irq_en;
-+      last_volt = aggr->last_volt;
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              if (cpr3_thread_busy(&ctrl->thread[i])) {
-+                      cpr3_debug(ctrl, "CPR thread %u busy when it should be waiting for SW cont\n",
-+                              ctrl->thread[i].thread_id);
-+                      goto done;
-+              }
-+      }
-+
-+      new_volt = up ? last_volt + ctrl->step_volt
-+                    : last_volt - ctrl->step_volt;
-+
-+      /* Re-enable UP/DOWN interrupt when its opposite is received. */
-+      irq_en |= up ? CPR3_IRQ_DOWN : CPR3_IRQ_UP;
-+
-+      if (new_volt > aggr->ceiling_volt) {
-+              new_volt = aggr->ceiling_volt;
-+              irq_en &= ~CPR3_IRQ_UP;
-+              cpr3_debug(ctrl, "limiting to ceiling=%d uV\n",
-+                      aggr->ceiling_volt);
-+      } else if (new_volt < aggr->floor_volt) {
-+              new_volt = aggr->floor_volt;
-+              irq_en &= ~CPR3_IRQ_DOWN;
-+              cpr3_debug(ctrl, "limiting to floor=%d uV\n", aggr->floor_volt);
-+      }
-+
-+      if (down && new_volt < dynamic_floor_volt) {
-+              /*
-+               * The vdd-supply voltage should not be decreased below the
-+               * dynamic floor voltage.  However, it is not necessary (and
-+               * counter productive) to force the voltage up to this level
-+               * if it happened to be below it since the closed-loop voltage
-+               * must have gotten there in a safe manner while the power
-+               * domains for the CPR3 regulator imposing the dynamic floor
-+               * were not bypassed.
-+               */
-+              new_volt = last_volt;
-+              irq_en &= ~CPR3_IRQ_DOWN;
-+              cpr3_debug(ctrl, "limiting to dynamic floor=%d uV\n",
-+                      dynamic_floor_volt);
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              cpr3_print_result(&ctrl->thread[i]);
-+
-+      cpr3_debug(ctrl, "%s: new_volt=%d uV, last_volt=%d uV\n",
-+              up ? "UP" : "DN", new_volt, last_volt);
-+
-+      if (ctrl->proc_clock_throttle && last_volt == aggr->ceiling_volt
-+          && new_volt < last_volt)
-+              cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
-+                              ctrl->proc_clock_throttle);
-+
-+      if (new_volt != last_volt) {
-+              rc = cpr3_regulator_scale_vdd_voltage(ctrl, new_volt,
-+                                                    last_volt,
-+                                                    aggr);
-+              if (rc) {
-+                      cpr3_err(ctrl, "scale_vdd() failed to set vdd=%d uV, rc=%d\n",
-+                               new_volt, rc);
-+                      goto done;
-+              }
-+              cont = CPR3_CONT_CMD_ACK;
-+
-+              /*
-+               * Update the closed-loop voltage for all regulators managed
-+               * by this CPR controller.
-+               */
-+              for (i = 0; i < ctrl->thread_count; i++) {
-+                      for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                              vreg = &ctrl->thread[i].vreg[j];
-+                              cpr3_update_vreg_closed_loop_volt(vreg,
-+                                      new_volt, reg_last_measurement);
-+                      }
-+              }
-+      }
-+
-+      if (ctrl->proc_clock_throttle && new_volt == aggr->ceiling_volt)
-+              cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
-+                              CPR3_PD_THROTTLE_DISABLE);
-+
-+      corner = &ctrl->thread[0].vreg[0].corner[
-+                      ctrl->thread[0].vreg[0].current_corner];
-+
-+      if (irq_en != aggr->irq_en) {
-+              aggr->irq_en = irq_en;
-+              cpr3_write(ctrl, CPR3_REG_IRQ_EN, irq_en);
-+      }
-+
-+      aggr->last_volt = new_volt;
-+
-+done:
-+      /* Clear interrupt status */
-+      cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR, CPR3_IRQ_UP | CPR3_IRQ_DOWN);
-+
-+      /* ACK or NACK the CPR controller */
-+      cpr3_write(ctrl, CPR3_REG_CONT_CMD, cont);
-+
-+      mutex_unlock(&ctrl->lock);
-+      return IRQ_HANDLED;
-+}
-+
-+/**
-+ * cpr3_ceiling_irq_handler() - CPR ceiling reached interrupt handler callback
-+ *            function used for hardware closed-loop operation
-+ * @irq:              CPR ceiling interrupt number
-+ * @data:             Private data corresponding to the CPR3 controller
-+ *                    pointer
-+ *
-+ * This function disables processor clock throttling and closed-loop operation
-+ * when the ceiling voltage is reached.
-+ *
-+ * Return: IRQ_HANDLED
-+ */
-+static irqreturn_t cpr3_ceiling_irq_handler(int irq, void *data)
-+{
-+      struct cpr3_controller *ctrl = data;
-+      int volt;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (!ctrl->cpr_enabled) {
-+              cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is disabled\n");
-+              goto done;
-+      } else if (!ctrl->use_hw_closed_loop) {
-+              cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is using SW closed-loop\n");
-+              goto done;
-+      }
-+
-+      volt = regulator_get_voltage(ctrl->vdd_regulator);
-+      if (volt < 0) {
-+              cpr3_err(ctrl, "could not get vdd voltage, rc=%d\n", volt);
-+              goto done;
-+      } else if (volt != ctrl->aggr_corner.ceiling_volt) {
-+              cpr3_debug(ctrl, "CPR ceiling interrupt received but vdd voltage: %d uV != ceiling voltage: %d uV\n",
-+                      volt, ctrl->aggr_corner.ceiling_volt);
-+              goto done;
-+      }
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              /*
-+               * Since the ceiling voltage has been reached, disable processor
-+               * clock throttling as well as CPR closed-loop operation.
-+               */
-+              cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
-+                              CPR3_PD_THROTTLE_DISABLE);
-+              cpr3_ctrl_loop_disable(ctrl);
-+              cpr3_debug(ctrl, "CPR closed-loop and throttling disabled\n");
-+      }
-+
-+done:
-+      mutex_unlock(&ctrl->lock);
-+      return IRQ_HANDLED;
-+}
-+
-+/**
-+ * cpr3_regulator_vreg_register() - register a regulator device for a CPR3
-+ *            regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function initializes all regulator framework related structures and then
-+ * calls regulator_register() for the CPR3 regulator.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_vreg_register(struct cpr3_regulator *vreg)
-+{
-+      struct regulator_config config = {};
-+      struct regulator_desc *rdesc;
-+      struct regulator_init_data *init_data;
-+      int rc;
-+
-+      init_data = of_get_regulator_init_data(vreg->thread->ctrl->dev,
-+                                              vreg->of_node, &vreg->rdesc);
-+      if (!init_data) {
-+              cpr3_err(vreg, "regulator init data is missing\n");
-+              return -EINVAL;
-+      }
-+
-+      init_data->constraints.input_uV = init_data->constraints.max_uV;
-+      rdesc                   = &vreg->rdesc;
-+      init_data->constraints.valid_ops_mask |=
-+              REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
-+      rdesc->ops = &cpr3_regulator_ops;
-+
-+      rdesc->n_voltages       = vreg->corner_count;
-+      rdesc->name             = init_data->constraints.name;
-+      rdesc->owner            = THIS_MODULE;
-+      rdesc->type             = REGULATOR_VOLTAGE;
-+
-+      config.dev              = vreg->thread->ctrl->dev;
-+      config.driver_data      = vreg;
-+      config.init_data        = init_data;
-+      config.of_node          = vreg->of_node;
-+
-+      vreg->rdev = regulator_register(vreg->thread->ctrl->dev, rdesc, &config);
-+      if (IS_ERR(vreg->rdev)) {
-+              rc = PTR_ERR(vreg->rdev);
-+              cpr3_err(vreg, "regulator_register failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      return 0;
-+}
-+
-+static int debugfs_int_set(void *data, u64 val)
-+{
-+      *(int *)data = val;
-+      return 0;
-+}
-+
-+static int debugfs_int_get(void *data, u64 *val)
-+{
-+      *val = *(int *)data;
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_int, debugfs_int_get, debugfs_int_set, "%lld\n");
-+DEFINE_SIMPLE_ATTRIBUTE(fops_int_ro, debugfs_int_get, NULL, "%lld\n");
-+DEFINE_SIMPLE_ATTRIBUTE(fops_int_wo, NULL, debugfs_int_set, "%lld\n");
-+
-+/**
-+ * debugfs_create_int - create a debugfs file that is used to read and write a
-+ *            signed int value
-+ * @name:             Pointer to a string containing the name of the file to
-+ *                    create
-+ * @mode:             The permissions that the file should have
-+ * @parent:           Pointer to the parent dentry for this file.  This should
-+ *                    be a directory dentry if set.  If this parameter is
-+ *                    %NULL, then the file will be created in the root of the
-+ *                    debugfs filesystem.
-+ * @value:            Pointer to the variable that the file should read to and
-+ *                    write from
-+ *
-+ * This function creates a file in debugfs with the given name that
-+ * contains the value of the variable @value.  If the @mode variable is so
-+ * set, it can be read from, and written to.
-+ *
-+ * This function will return a pointer to a dentry if it succeeds.  This
-+ * pointer must be passed to the debugfs_remove() function when the file is
-+ * to be removed.  If an error occurs, %NULL will be returned.
-+ */
-+static struct dentry *debugfs_create_int(const char *name, umode_t mode,
-+                              struct dentry *parent, int *value)
-+{
-+      /* if there are no write bits set, make read only */
-+      if (!(mode & S_IWUGO))
-+              return debugfs_create_file(name, mode, parent, value,
-+                                         &fops_int_ro);
-+      /* if there are no read bits set, make write only */
-+      if (!(mode & S_IRUGO))
-+              return debugfs_create_file(name, mode, parent, value,
-+                                         &fops_int_wo);
-+
-+      return debugfs_create_file(name, mode, parent, value, &fops_int);
-+}
-+
-+static int debugfs_bool_get(void *data, u64 *val)
-+{
-+      *val = *(bool *)data;
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%lld\n");
-+
-+/**
-+ * struct cpr3_debug_corner_info - data structure used by the
-+ *            cpr3_debugfs_create_corner_int function
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @index:            Pointer to the corner array index
-+ * @member_offset:    Offset in bytes from the beginning of struct cpr3_corner
-+ *                    to the beginning of the value to be read from
-+ * @corner:           Pointer to the CPR3 corner array
-+ */
-+struct cpr3_debug_corner_info {
-+      struct cpr3_regulator   *vreg;
-+      int                     *index;
-+      size_t                  member_offset;
-+      struct cpr3_corner      *corner;
-+};
-+
-+static int cpr3_debug_corner_int_get(void *data, u64 *val)
-+{
-+      struct cpr3_debug_corner_info *info = data;
-+      struct cpr3_controller *ctrl = info->vreg->thread->ctrl;
-+      int i;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      i = *info->index;
-+      if (i < 0)
-+              i = 0;
-+
-+      *val = *(int *)((char *)&info->vreg->corner[i] + info->member_offset);
-+
-+      mutex_unlock(&ctrl->lock);
-+
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_corner_int_fops, cpr3_debug_corner_int_get,
-+                      NULL, "%lld\n");
-+
-+/**
-+ * cpr3_debugfs_create_corner_int - create a debugfs file that is used to read
-+ *            a signed int value out of a CPR3 regulator's corner array
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @name:             Pointer to a string containing the name of the file to
-+ *                    create
-+ * @mode:             The permissions that the file should have
-+ * @parent:           Pointer to the parent dentry for this file.  This should
-+ *                    be a directory dentry if set.  If this parameter is
-+ *                    %NULL, then the file will be created in the root of the
-+ *                    debugfs filesystem.
-+ * @index:            Pointer to the corner array index
-+ * @member_offset:    Offset in bytes from the beginning of struct cpr3_corner
-+ *                    to the beginning of the value to be read from
-+ *
-+ * This function creates a file in debugfs with the given name that
-+ * contains the value of the int type variable vreg->corner[index].member
-+ * where member_offset == offsetof(struct cpr3_corner, member).
-+ */
-+static struct dentry *cpr3_debugfs_create_corner_int(
-+              struct cpr3_regulator *vreg, const char *name, umode_t mode,
-+              struct dentry *parent, int *index, size_t member_offset)
-+{
-+      struct cpr3_debug_corner_info *info;
-+
-+      info = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return NULL;
-+
-+      info->vreg = vreg;
-+      info->index = index;
-+      info->member_offset = member_offset;
-+
-+      return debugfs_create_file(name, mode, parent, info,
-+                                 &cpr3_debug_corner_int_fops);
-+}
-+
-+static int cpr3_debug_quot_open(struct inode *inode, struct file *file)
-+{
-+      struct cpr3_debug_corner_info *info = inode->i_private;
-+      struct cpr3_thread *thread = info->vreg->thread;
-+      int size, i, pos;
-+      u32 *quot;
-+      char *buf;
-+
-+      /*
-+       * Max size:
-+       *  - 10 digits + ' ' or '\n' = 11 bytes per number
-+       *  - terminating '\0'
-+       */
-+      size = CPR3_RO_COUNT * 11;
-+      buf = kzalloc(size + 1, GFP_KERNEL);
-+      if (!buf)
-+              return -ENOMEM;
-+
-+      file->private_data = buf;
-+
-+      mutex_lock(&thread->ctrl->lock);
-+
-+      quot = info->corner[*info->index].target_quot;
-+
-+      for (i = 0, pos = 0; i < CPR3_RO_COUNT; i++)
-+              pos += scnprintf(buf + pos, size - pos, "%u%c",
-+                      quot[i], i < CPR3_RO_COUNT - 1 ? ' ' : '\n');
-+
-+      mutex_unlock(&thread->ctrl->lock);
-+
-+      return nonseekable_open(inode, file);
-+}
-+
-+static ssize_t cpr3_debug_quot_read(struct file *file, char __user *buf,
-+              size_t len, loff_t *ppos)
-+{
-+      return simple_read_from_buffer(buf, len, ppos, file->private_data,
-+                                      strlen(file->private_data));
-+}
-+
-+static int cpr3_debug_quot_release(struct inode *inode, struct file *file)
-+{
-+      kfree(file->private_data);
-+
-+      return 0;
-+}
-+
-+static const struct file_operations cpr3_debug_quot_fops = {
-+      .owner   = THIS_MODULE,
-+      .open    = cpr3_debug_quot_open,
-+      .release = cpr3_debug_quot_release,
-+      .read    = cpr3_debug_quot_read,
-+};
-+
-+/**
-+ * cpr3_regulator_debugfs_corner_add() - add debugfs files to expose
-+ *            configuration data for the CPR corner
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @corner_dir:               Pointer to the parent corner dentry for the new files
-+ * @index:            Pointer to the corner array index
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_debugfs_corner_add(struct cpr3_regulator *vreg,
-+              struct dentry *corner_dir, int *index)
-+{
-+      struct cpr3_debug_corner_info *info;
-+      struct dentry *temp;
-+
-+      temp = cpr3_debugfs_create_corner_int(vreg, "floor_volt", S_IRUGO,
-+              corner_dir, index, offsetof(struct cpr3_corner, floor_volt));
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "floor_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = cpr3_debugfs_create_corner_int(vreg, "ceiling_volt", S_IRUGO,
-+              corner_dir, index, offsetof(struct cpr3_corner, ceiling_volt));
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "ceiling_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = cpr3_debugfs_create_corner_int(vreg, "open_loop_volt", S_IRUGO,
-+              corner_dir, index,
-+              offsetof(struct cpr3_corner, open_loop_volt));
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "open_loop_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = cpr3_debugfs_create_corner_int(vreg, "last_volt", S_IRUGO,
-+              corner_dir, index, offsetof(struct cpr3_corner, last_volt));
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "last_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      info = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return;
-+
-+      info->vreg = vreg;
-+      info->index = index;
-+      info->corner = vreg->corner;
-+
-+      temp = debugfs_create_file("target_quots", S_IRUGO, corner_dir,
-+                              info, &cpr3_debug_quot_fops);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "target_quots debugfs file creation failed\n");
-+              return;
-+      }
-+}
-+
-+/**
-+ * cpr3_debug_corner_index_set() - debugfs callback used to change the
-+ *            value of the CPR3 regulator debug_corner index
-+ * @data:             Pointer to private data which is equal to the CPR3
-+ *                    regulator pointer
-+ * @val:              New value for debug_corner
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_corner_index_set(void *data, u64 val)
-+{
-+      struct cpr3_regulator *vreg = data;
-+
-+      if (val < CPR3_CORNER_OFFSET || val > vreg->corner_count) {
-+              cpr3_err(vreg, "invalid corner index %llu; allowed values: %d-%d\n",
-+                      val, CPR3_CORNER_OFFSET, vreg->corner_count);
-+              return -EINVAL;
-+      }
-+
-+      mutex_lock(&vreg->thread->ctrl->lock);
-+      vreg->debug_corner = val - CPR3_CORNER_OFFSET;
-+      mutex_unlock(&vreg->thread->ctrl->lock);
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_debug_corner_index_get() - debugfs callback used to retrieve
-+ *            the value of the CPR3 regulator debug_corner index
-+ * @data:             Pointer to private data which is equal to the CPR3
-+ *                    regulator pointer
-+ * @val:              Output parameter written with the value of
-+ *                    debug_corner
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_corner_index_get(void *data, u64 *val)
-+{
-+      struct cpr3_regulator *vreg = data;
-+
-+      *val = vreg->debug_corner + CPR3_CORNER_OFFSET;
-+
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_corner_index_fops,
-+                      cpr3_debug_corner_index_get,
-+                      cpr3_debug_corner_index_set,
-+                      "%llu\n");
-+
-+/**
-+ * cpr3_debug_current_corner_index_get() - debugfs callback used to retrieve
-+ *            the value of the CPR3 regulator current_corner index
-+ * @data:             Pointer to private data which is equal to the CPR3
-+ *                    regulator pointer
-+ * @val:              Output parameter written with the value of
-+ *                    current_corner
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_current_corner_index_get(void *data, u64 *val)
-+{
-+      struct cpr3_regulator *vreg = data;
-+
-+      *val = vreg->current_corner + CPR3_CORNER_OFFSET;
-+
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_current_corner_index_fops,
-+                      cpr3_debug_current_corner_index_get,
-+                      NULL, "%llu\n");
-+
-+/**
-+ * cpr3_regulator_debugfs_vreg_add() - add debugfs files to expose configuration
-+ *            data for the CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @thread_dir                CPR3 thread debugfs directory handle
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
-+                              struct dentry *thread_dir)
-+{
-+      struct dentry *temp, *corner_dir, *vreg_dir;
-+
-+      vreg_dir = debugfs_create_dir(vreg->name, thread_dir);
-+      if (IS_ERR_OR_NULL(vreg_dir)) {
-+              cpr3_err(vreg, "%s debugfs directory creation failed\n",
-+                      vreg->name);
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("speed_bin_fuse", S_IRUGO, vreg_dir,
-+                                &vreg->speed_bin_fuse);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "speed_bin_fuse debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("cpr_rev_fuse", S_IRUGO, vreg_dir,
-+                                &vreg->cpr_rev_fuse);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "cpr_rev_fuse debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("fuse_combo", S_IRUGO, vreg_dir,
-+                                &vreg->fuse_combo);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "fuse_combo debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("corner_count", S_IRUGO, vreg_dir,
-+                                &vreg->corner_count);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "corner_count debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      corner_dir = debugfs_create_dir("corner", vreg_dir);
-+      if (IS_ERR_OR_NULL(corner_dir)) {
-+              cpr3_err(vreg, "corner debugfs directory creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_file("index", S_IRUGO | S_IWUSR, corner_dir,
-+                              vreg, &cpr3_debug_corner_index_fops);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "index debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      cpr3_regulator_debugfs_corner_add(vreg, corner_dir,
-+                                      &vreg->debug_corner);
-+
-+      corner_dir = debugfs_create_dir("current_corner", vreg_dir);
-+      if (IS_ERR_OR_NULL(corner_dir)) {
-+              cpr3_err(vreg, "current_corner debugfs directory creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_file("index", S_IRUGO, corner_dir,
-+                              vreg, &cpr3_debug_current_corner_index_fops);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(vreg, "index debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      cpr3_regulator_debugfs_corner_add(vreg, corner_dir,
-+                                        &vreg->current_corner);
-+}
-+
-+/**
-+ * cpr3_regulator_debugfs_thread_add() - add debugfs files to expose
-+ *            configuration data for the CPR thread
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
-+{
-+      struct cpr3_controller *ctrl = thread->ctrl;
-+      struct dentry *aggr_dir, *temp, *thread_dir;
-+      struct cpr3_debug_corner_info *info;
-+      char buf[20];
-+      int *index;
-+      int i;
-+
-+      scnprintf(buf, sizeof(buf), "thread%u", thread->thread_id);
-+      thread_dir = debugfs_create_dir(buf, thread->ctrl->debugfs);
-+      if (IS_ERR_OR_NULL(thread_dir)) {
-+              cpr3_err(ctrl, "thread %u %s debugfs directory creation failed\n",
-+                      thread->thread_id, buf);
-+              return;
-+      }
-+
-+      aggr_dir = debugfs_create_dir("max_aggregated_params", thread_dir);
-+      if (IS_ERR_OR_NULL(aggr_dir)) {
-+              cpr3_err(ctrl, "thread %u max_aggregated_params debugfs directory creation failed\n",
-+                      thread->thread_id);
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("floor_volt", S_IRUGO, aggr_dir,
-+                                &thread->aggr_corner.floor_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "thread %u aggr floor_volt debugfs file creation failed\n",
-+                      thread->thread_id);
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("ceiling_volt", S_IRUGO, aggr_dir,
-+                                &thread->aggr_corner.ceiling_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "thread %u aggr ceiling_volt debugfs file creation failed\n",
-+                      thread->thread_id);
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("open_loop_volt", S_IRUGO, aggr_dir,
-+                                &thread->aggr_corner.open_loop_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "thread %u aggr open_loop_volt debugfs file creation failed\n",
-+                      thread->thread_id);
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("last_volt", S_IRUGO, aggr_dir,
-+                                &thread->aggr_corner.last_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "thread %u aggr last_volt debugfs file creation failed\n",
-+                      thread->thread_id);
-+              return;
-+      }
-+
-+      info = devm_kzalloc(thread->ctrl->dev, sizeof(*info), GFP_KERNEL);
-+      index = devm_kzalloc(thread->ctrl->dev, sizeof(*index), GFP_KERNEL);
-+      if (!info || !index)
-+              return;
-+      *index = 0;
-+      info->vreg = &thread->vreg[0];
-+      info->index = index;
-+      info->corner = &thread->aggr_corner;
-+
-+      temp = debugfs_create_file("target_quots", S_IRUGO, aggr_dir,
-+                              info, &cpr3_debug_quot_fops);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "thread %u target_quots debugfs file creation failed\n",
-+                      thread->thread_id);
-+              return;
-+      }
-+
-+      for (i = 0; i < thread->vreg_count; i++)
-+              cpr3_regulator_debugfs_vreg_add(&thread->vreg[i], thread_dir);
-+}
-+
-+/**
-+ * cpr3_debug_closed_loop_enable_set() - debugfs callback used to change the
-+ *            value of the CPR controller cpr_allowed_sw flag which enables or
-+ *            disables closed-loop operation
-+ * @data:             Pointer to private data which is equal to the CPR
-+ *                    controller pointer
-+ * @val:              New value for cpr_allowed_sw
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_closed_loop_enable_set(void *data, u64 val)
-+{
-+      struct cpr3_controller *ctrl = data;
-+      bool enable = !!val;
-+      int rc;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (ctrl->cpr_allowed_sw == enable)
-+              goto done;
-+
-+      if (enable && !ctrl->cpr_allowed_hw) {
-+              cpr3_err(ctrl, "CPR closed-loop operation is not allowed\n");
-+              goto done;
-+      }
-+
-+      ctrl->cpr_allowed_sw = enable;
-+
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not change CPR enable state=%u, rc=%d\n",
-+                       enable, rc);
-+              goto done;
-+      }
-+
-+      if (ctrl->proc_clock_throttle && !ctrl->cpr_enabled) {
-+              rc = cpr3_clock_enable(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "clock enable failed, rc=%d\n",
-+                               rc);
-+                      goto done;
-+              }
-+              ctrl->cpr_enabled = true;
-+
-+              cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
-+                         CPR3_PD_THROTTLE_DISABLE);
-+
-+              cpr3_clock_disable(ctrl);
-+              ctrl->cpr_enabled = false;
-+      }
-+
-+      cpr3_debug(ctrl, "closed-loop=%s\n", enable ? "enabled" : "disabled");
-+done:
-+      mutex_unlock(&ctrl->lock);
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_debug_closed_loop_enable_get() - debugfs callback used to retrieve
-+ *            the value of the CPR controller cpr_allowed_sw flag which
-+ *            indicates if closed-loop operation is enabled
-+ * @data:             Pointer to private data which is equal to the CPR
-+ *                    controller pointer
-+ * @val:              Output parameter written with the value of
-+ *                    cpr_allowed_sw
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_closed_loop_enable_get(void *data, u64 *val)
-+{
-+      struct cpr3_controller *ctrl = data;
-+
-+      *val = ctrl->cpr_allowed_sw;
-+
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_closed_loop_enable_fops,
-+                      cpr3_debug_closed_loop_enable_get,
-+                      cpr3_debug_closed_loop_enable_set,
-+                      "%llu\n");
-+
-+/**
-+ * cpr3_debug_hw_closed_loop_enable_set() - debugfs callback used to change the
-+ *            value of the CPR controller use_hw_closed_loop flag which
-+ *            switches between software closed-loop and hardware closed-loop
-+ *            operation for CPR3 and CPR4 controllers and between open-loop
-+ *            and full hardware closed-loop operation for CPRh controllers.
-+ * @data:             Pointer to private data which is equal to the CPR
-+ *                    controller pointer
-+ * @val:              New value for use_hw_closed_loop
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
-+{
-+      struct cpr3_controller *ctrl = data;
-+      bool use_hw_closed_loop = !!val;
-+      struct cpr3_regulator *vreg;
-+      bool cpr_enabled;
-+      int i, j, k, rc;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (ctrl->use_hw_closed_loop == use_hw_closed_loop)
-+              goto done;
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      ctrl->use_hw_closed_loop = use_hw_closed_loop;
-+
-+      cpr_enabled = ctrl->cpr_enabled;
-+
-+      /* Ensure that CPR clocks are enabled before writing to registers. */
-+      if (!cpr_enabled) {
-+              rc = cpr3_clock_enable(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
-+                      goto done;
-+              }
-+              ctrl->cpr_enabled = true;
-+      }
-+
-+      if (ctrl->use_hw_closed_loop)
-+              cpr3_write(ctrl, CPR3_REG_IRQ_EN, 0);
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
-+                      CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
-+                      ctrl->use_hw_closed_loop
-+                      ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
-+                      : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
-+      } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
-+                      ctrl->use_hw_closed_loop
-+                      ? CPR3_HW_CLOSED_LOOP_ENABLE
-+                      : CPR3_HW_CLOSED_LOOP_DISABLE);
-+      }
-+
-+      /* Turn off CPR clocks if they were off before this function call. */
-+      if (!cpr_enabled) {
-+              cpr3_clock_disable(ctrl);
-+              ctrl->cpr_enabled = false;
-+      }
-+
-+      if (ctrl->use_hw_closed_loop && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              rc = regulator_enable(ctrl->vdd_limit_regulator);
-+              if (rc) {
-+                      cpr3_err(ctrl, "CPR limit regulator enable failed, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      } else if (!ctrl->use_hw_closed_loop
-+                      && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              rc = regulator_disable(ctrl->vdd_limit_regulator);
-+              if (rc) {
-+                      cpr3_err(ctrl, "CPR limit regulator disable failed, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      /*
-+       * Due to APM and mem-acc floor restriction constraints,
-+       * the closed-loop voltage may be different when using
-+       * software closed-loop vs hardware closed-loop.  Therefore,
-+       * reset the cached closed-loop voltage for all corners to the
-+       * corresponding open-loop voltage when switching between
-+       * SW and HW closed-loop mode.
-+       */
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+                      for (k = 0; k < vreg->corner_count; k++)
-+                              vreg->corner[k].last_volt
-+                              = vreg->corner[k].open_loop_volt;
-+              }
-+      }
-+
-+      /* Skip last_volt caching */
-+      ctrl->last_corner_was_closed_loop = false;
-+
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not change CPR HW closed-loop enable state=%u, rc=%d\n",
-+                       use_hw_closed_loop, rc);
-+              goto done;
-+      }
-+
-+      cpr3_debug(ctrl, "CPR mode=%s\n",
-+                 use_hw_closed_loop ?
-+                 "HW closed-loop" : "SW closed-loop");
-+done:
-+      mutex_unlock(&ctrl->lock);
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_debug_hw_closed_loop_enable_get() - debugfs callback used to retrieve
-+ *            the value of the CPR controller use_hw_closed_loop flag which
-+ *            indicates if hardware closed-loop operation is being used in
-+ *            place of software closed-loop operation
-+ * @data:             Pointer to private data which is equal to the CPR
-+ *                    controller pointer
-+ * @val:              Output parameter written with the value of
-+ *                    use_hw_closed_loop
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_hw_closed_loop_enable_get(void *data, u64 *val)
-+{
-+      struct cpr3_controller *ctrl = data;
-+
-+      *val = ctrl->use_hw_closed_loop;
-+
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_hw_closed_loop_enable_fops,
-+                      cpr3_debug_hw_closed_loop_enable_get,
-+                      cpr3_debug_hw_closed_loop_enable_set,
-+                      "%llu\n");
-+
-+/**
-+ * cpr3_debug_trigger_aging_measurement_set() - debugfs callback used to trigger
-+ *            another CPR measurement
-+ * @data:             Pointer to private data which is equal to the CPR
-+ *                    controller pointer
-+ * @val:              Unused
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_debug_trigger_aging_measurement_set(void *data, u64 val)
-+{
-+      struct cpr3_controller *ctrl = data;
-+      int rc;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      cpr3_regulator_set_aging_ref_adjustment(ctrl, INT_MAX);
-+      ctrl->aging_required = true;
-+      ctrl->aging_succeeded = false;
-+      ctrl->aging_failed = false;
-+
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not update the CPR controller state, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+done:
-+      mutex_unlock(&ctrl->lock);
-+      return 0;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_trigger_aging_measurement_fops,
-+                      NULL,
-+                      cpr3_debug_trigger_aging_measurement_set,
-+                      "%llu\n");
-+
-+/**
-+ * cpr3_regulator_debugfs_ctrl_add() - add debugfs files to expose configuration
-+ *            data for the CPR controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
-+{
-+      struct dentry *temp, *aggr_dir;
-+      int i;
-+
-+      /* Add cpr3-regulator base directory if it isn't present already. */
-+      if (cpr3_debugfs_base == NULL) {
-+              cpr3_debugfs_base = debugfs_create_dir("cpr3-regulator", NULL);
-+              if (IS_ERR_OR_NULL(cpr3_debugfs_base)) {
-+                      cpr3_err(ctrl, "cpr3-regulator debugfs base directory creation failed\n");
-+                      cpr3_debugfs_base = NULL;
-+                      return;
-+              }
-+      }
-+
-+      ctrl->debugfs = debugfs_create_dir(ctrl->name, cpr3_debugfs_base);
-+      if (IS_ERR_OR_NULL(ctrl->debugfs)) {
-+              cpr3_err(ctrl, "cpr3-regulator controller debugfs directory creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_file("cpr_closed_loop_enable", S_IRUGO | S_IWUSR,
-+                                      ctrl->debugfs, ctrl,
-+                                      &cpr3_debug_closed_loop_enable_fops);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "cpr_closed_loop_enable debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      if (ctrl->supports_hw_closed_loop) {
-+              temp = debugfs_create_file("use_hw_closed_loop",
-+                                      S_IRUGO | S_IWUSR, ctrl->debugfs, ctrl,
-+                                      &cpr3_debug_hw_closed_loop_enable_fops);
-+              if (IS_ERR_OR_NULL(temp)) {
-+                      cpr3_err(ctrl, "use_hw_closed_loop debugfs file creation failed\n");
-+                      return;
-+              }
-+      }
-+
-+      temp = debugfs_create_int("thread_count", S_IRUGO, ctrl->debugfs,
-+                                &ctrl->thread_count);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "thread_count debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      if (ctrl->apm) {
-+              temp = debugfs_create_int("apm_threshold_volt", S_IRUGO,
-+                              ctrl->debugfs, &ctrl->apm_threshold_volt);
-+              if (IS_ERR_OR_NULL(temp)) {
-+                      cpr3_err(ctrl, "apm_threshold_volt debugfs file creation failed\n");
-+                      return;
-+              }
-+      }
-+
-+      if (ctrl->aging_required || ctrl->aging_succeeded
-+          || ctrl->aging_failed) {
-+              temp = debugfs_create_int("aging_adj_volt", S_IRUGO,
-+                              ctrl->debugfs, &ctrl->aging_ref_adjust_volt);
-+              if (IS_ERR_OR_NULL(temp)) {
-+                      cpr3_err(ctrl, "aging_adj_volt debugfs file creation failed\n");
-+                      return;
-+              }
-+
-+              temp = debugfs_create_file("aging_succeeded", S_IRUGO,
-+                      ctrl->debugfs, &ctrl->aging_succeeded, &fops_bool_ro);
-+              if (IS_ERR_OR_NULL(temp)) {
-+                      cpr3_err(ctrl, "aging_succeeded debugfs file creation failed\n");
-+                      return;
-+              }
-+
-+              temp = debugfs_create_file("aging_failed", S_IRUGO,
-+                      ctrl->debugfs, &ctrl->aging_failed, &fops_bool_ro);
-+              if (IS_ERR_OR_NULL(temp)) {
-+                      cpr3_err(ctrl, "aging_failed debugfs file creation failed\n");
-+                      return;
-+              }
-+
-+              temp = debugfs_create_file("aging_trigger", S_IWUSR,
-+                      ctrl->debugfs, ctrl,
-+                      &cpr3_debug_trigger_aging_measurement_fops);
-+              if (IS_ERR_OR_NULL(temp)) {
-+                      cpr3_err(ctrl, "aging_trigger debugfs file creation failed\n");
-+                      return;
-+              }
-+      }
-+
-+      aggr_dir = debugfs_create_dir("max_aggregated_voltages", ctrl->debugfs);
-+      if (IS_ERR_OR_NULL(aggr_dir)) {
-+              cpr3_err(ctrl, "max_aggregated_voltages debugfs directory creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("floor_volt", S_IRUGO, aggr_dir,
-+                                &ctrl->aggr_corner.floor_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "aggr floor_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("ceiling_volt", S_IRUGO, aggr_dir,
-+                                &ctrl->aggr_corner.ceiling_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "aggr ceiling_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("open_loop_volt", S_IRUGO, aggr_dir,
-+                                &ctrl->aggr_corner.open_loop_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "aggr open_loop_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      temp = debugfs_create_int("last_volt", S_IRUGO, aggr_dir,
-+                                &ctrl->aggr_corner.last_volt);
-+      if (IS_ERR_OR_NULL(temp)) {
-+              cpr3_err(ctrl, "aggr last_volt debugfs file creation failed\n");
-+              return;
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              cpr3_regulator_debugfs_thread_add(&ctrl->thread[i]);
-+}
-+
-+/**
-+ * cpr3_regulator_debugfs_ctrl_remove() - remove debugfs files for the CPR
-+ *            controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Note, this function must be called after the controller has been removed from
-+ * cpr3_controller_list and while the cpr3_controller_list_mutex lock is held.
-+ *
-+ * Return: none
-+ */
-+static void cpr3_regulator_debugfs_ctrl_remove(struct cpr3_controller *ctrl)
-+{
-+      if (list_empty(&cpr3_controller_list)) {
-+              debugfs_remove_recursive(cpr3_debugfs_base);
-+              cpr3_debugfs_base = NULL;
-+      } else {
-+              debugfs_remove_recursive(ctrl->debugfs);
-+      }
-+}
-+
-+/**
-+ * cpr3_regulator_init_ctrl_data() - performs initialization of CPR controller
-+ *                                    elements
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_init_ctrl_data(struct cpr3_controller *ctrl)
-+{
-+      /* Read the initial vdd voltage from hardware. */
-+      ctrl->aggr_corner.last_volt
-+              = regulator_get_voltage(ctrl->vdd_regulator);
-+      if (ctrl->aggr_corner.last_volt < 0) {
-+              cpr3_err(ctrl, "regulator_get_voltage(vdd) failed, rc=%d\n",
-+                              ctrl->aggr_corner.last_volt);
-+              return ctrl->aggr_corner.last_volt;
-+      }
-+      ctrl->aggr_corner.open_loop_volt = ctrl->aggr_corner.last_volt;
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_init_vreg_data() - performs initialization of common CPR3
-+ *            regulator elements and validate aging configurations
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_init_vreg_data(struct cpr3_regulator *vreg)
-+{
-+      int i, j;
-+      bool init_aging;
-+
-+      vreg->current_corner = CPR3_REGULATOR_CORNER_INVALID;
-+      vreg->last_closed_loop_corner = CPR3_REGULATOR_CORNER_INVALID;
-+
-+      init_aging = vreg->aging_allowed && vreg->thread->ctrl->aging_required;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              vreg->corner[i].last_volt = vreg->corner[i].open_loop_volt;
-+              vreg->corner[i].irq_en = CPR3_IRQ_UP | CPR3_IRQ_DOWN;
-+
-+              vreg->corner[i].ro_mask = 0;
-+              for (j = 0; j < CPR3_RO_COUNT; j++) {
-+                      if (vreg->corner[i].target_quot[j] == 0)
-+                              vreg->corner[i].ro_mask |= BIT(j);
-+              }
-+
-+              if (init_aging) {
-+                      vreg->corner[i].unaged_floor_volt
-+                              = vreg->corner[i].floor_volt;
-+                      vreg->corner[i].unaged_ceiling_volt
-+                              = vreg->corner[i].ceiling_volt;
-+                      vreg->corner[i].unaged_open_loop_volt
-+                              = vreg->corner[i].open_loop_volt;
-+              }
-+
-+              if (vreg->aging_allowed) {
-+                      if (vreg->corner[i].unaged_floor_volt <= 0) {
-+                              cpr3_err(vreg, "invalid unaged_floor_volt[%d] = %d\n",
-+                                      i, vreg->corner[i].unaged_floor_volt);
-+                              return -EINVAL;
-+                      }
-+                      if (vreg->corner[i].unaged_ceiling_volt <= 0) {
-+                              cpr3_err(vreg, "invalid unaged_ceiling_volt[%d] = %d\n",
-+                                      i, vreg->corner[i].unaged_ceiling_volt);
-+                              return -EINVAL;
-+                      }
-+                      if (vreg->corner[i].unaged_open_loop_volt <= 0) {
-+                              cpr3_err(vreg, "invalid unaged_open_loop_volt[%d] = %d\n",
-+                                    i, vreg->corner[i].unaged_open_loop_volt);
-+                              return -EINVAL;
-+                      }
-+              }
-+      }
-+
-+      if (vreg->aging_allowed && vreg->corner[vreg->aging_corner].ceiling_volt
-+          > vreg->thread->ctrl->aging_ref_volt) {
-+              cpr3_err(vreg, "aging corner %d ceiling voltage = %d > aging ref voltage = %d uV\n",
-+                      vreg->aging_corner,
-+                      vreg->corner[vreg->aging_corner].ceiling_volt,
-+                      vreg->thread->ctrl->aging_ref_volt);
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_suspend() - perform common required CPR3 power down steps
-+ *            before the system enters suspend
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_regulator_suspend(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc);
-+                      mutex_unlock(&ctrl->lock);
-+                      return rc;
-+              }
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      rc = cpr3_closed_loop_disable(ctrl);
-+      if (rc)
-+              cpr3_err(ctrl, "could not disable CPR, rc=%d\n", rc);
-+
-+      ctrl->cpr_suspended = true;
-+
-+      mutex_unlock(&ctrl->lock);
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_resume() - perform common required CPR3 power up steps after
-+ *            the system resumes from suspend
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_regulator_resume(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      mutex_lock(&ctrl->lock);
-+
-+      ctrl->cpr_suspended = false;
-+      rc = cpr3_regulator_update_ctrl_state(ctrl);
-+      if (rc)
-+              cpr3_err(ctrl, "could not enable CPR, rc=%d\n", rc);
-+
-+      mutex_unlock(&ctrl->lock);
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_regulator_validate_controller() - verify the data passed in via the
-+ *            cpr3_controller data structure
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_regulator_validate_controller(struct cpr3_controller *ctrl)
-+{
-+      struct cpr3_thread *thread;
-+      struct cpr3_regulator *vreg;
-+      int i, j, allow_boost_vreg_count = 0;
-+
-+      if (!ctrl->vdd_regulator) {
-+              cpr3_err(ctrl, "vdd regulator missing\n");
-+              return -EINVAL;
-+      } else if (ctrl->sensor_count <= 0
-+                 || ctrl->sensor_count > CPR3_MAX_SENSOR_COUNT) {
-+              cpr3_err(ctrl, "invalid CPR sensor count=%d\n",
-+                      ctrl->sensor_count);
-+              return -EINVAL;
-+      } else if (!ctrl->sensor_owner) {
-+              cpr3_err(ctrl, "CPR sensor ownership table missing\n");
-+              return -EINVAL;
-+      }
-+
-+      if (ctrl->aging_required) {
-+              for (i = 0; i < ctrl->aging_sensor_count; i++) {
-+                      if (ctrl->aging_sensor[i].sensor_id
-+                          >= ctrl->sensor_count) {
-+                              cpr3_err(ctrl, "aging_sensor[%d] id=%u is not in the value range 0-%d",
-+                                      i, ctrl->aging_sensor[i].sensor_id,
-+                                      ctrl->sensor_count - 1);
-+                              return -EINVAL;
-+                      }
-+              }
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              thread = &ctrl->thread[i];
-+              for (j = 0; j < thread->vreg_count; j++) {
-+                      vreg = &thread->vreg[j];
-+                      if (vreg->allow_boost)
-+                              allow_boost_vreg_count++;
-+              }
-+      }
-+
-+      if (allow_boost_vreg_count > 1) {
-+              /*
-+               * Boost feature is not allowed to be used for more
-+               * than one CPR3 regulator of a CPR3 controller.
-+               */
-+              cpr3_err(ctrl, "Boost feature is enabled for more than one regulator\n");
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_panic_callback() - panic notification callback function. This function
-+ *            is invoked when a kernel panic occurs.
-+ * @nfb:      Notifier block pointer of CPR3 controller
-+ * @event:    Value passed unmodified to notifier function
-+ * @data:     Pointer passed unmodified to notifier function
-+ *
-+ * Return: NOTIFY_OK
-+ */
-+static int cpr3_panic_callback(struct notifier_block *nfb,
-+                      unsigned long event, void *data)
-+{
-+      struct cpr3_controller *ctrl = container_of(nfb,
-+                              struct cpr3_controller, panic_notifier);
-+      struct cpr3_panic_regs_info *regs_info = ctrl->panic_regs_info;
-+      struct cpr3_reg_info *reg;
-+      int i = 0;
-+
-+      for (i = 0; i < regs_info->reg_count; i++) {
-+              reg = &(regs_info->regs[i]);
-+              reg->value = readl_relaxed(reg->virt_addr);
-+              pr_err("%s[0x%08x] = 0x%08x\n", reg->name, reg->addr,
-+                      reg->value);
-+      }
-+      /*
-+       * Barrier to ensure that the information has been updated in the
-+       * structure.
-+       */
-+      mb();
-+
-+      return NOTIFY_OK;
-+}
-+
-+/**
-+ * cpr3_regulator_register() - register the regulators for a CPR3 controller and
-+ *            perform CPR hardware initialization
-+ * @pdev:             Platform device pointer for the CPR3 controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_regulator_register(struct platform_device *pdev,
-+                      struct cpr3_controller *ctrl)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct resource *res;
-+      int i, j, rc;
-+
-+      if (!dev->of_node) {
-+              dev_err(dev, "%s: Device tree node is missing\n", __func__);
-+              return -EINVAL;
-+      }
-+
-+      if (!ctrl || !ctrl->name) {
-+              dev_err(dev, "%s: CPR controller data is missing\n", __func__);
-+              return -EINVAL;
-+      }
-+
-+      rc = cpr3_regulator_validate_controller(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "controller validation failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      mutex_init(&ctrl->lock);
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cpr_ctrl");
-+      if (!res || !res->start) {
-+              cpr3_err(ctrl, "CPR controller address is missing\n");
-+              return -ENXIO;
-+      }
-+      ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res));
-+
-+      if (ctrl->aging_possible_mask) {
-+              /*
-+               * Aging possible register address is required if an aging
-+               * possible mask has been specified.
-+               */
-+              res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+                                              "aging_allowed");
-+              if (!res || !res->start) {
-+                      cpr3_err(ctrl, "CPR aging allowed address is missing\n");
-+                      return -ENXIO;
-+              }
-+              ctrl->aging_possible_reg = devm_ioremap(dev, res->start,
-+                                                      resource_size(res));
-+      }
-+
-+      ctrl->irq = platform_get_irq_byname(pdev, "cpr");
-+      if (ctrl->irq < 0) {
-+              cpr3_err(ctrl, "missing CPR interrupt\n");
-+              return ctrl->irq;
-+      }
-+
-+      if (ctrl->supports_hw_closed_loop) {
-+              if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+                      ctrl->ceiling_irq = platform_get_irq_byname(pdev,
-+                                              "ceiling");
-+                      if (ctrl->ceiling_irq < 0) {
-+                              cpr3_err(ctrl, "missing ceiling interrupt\n");
-+                              return ctrl->ceiling_irq;
-+                      }
-+              }
-+      }
-+
-+      rc = cpr3_regulator_init_ctrl_data(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "CPR controller data initialization failed, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      rc = cpr3_regulator_init_vreg_data(
-+                                              &ctrl->thread[i].vreg[j]);
-+                      if (rc)
-+                              return rc;
-+                      cpr3_print_quots(&ctrl->thread[i].vreg[j]);
-+              }
-+      }
-+
-+      /*
-+       * Add the maximum possible aging voltage margin until it is possible
-+       * to perform an aging measurement.
-+       */
-+      if (ctrl->aging_required)
-+              cpr3_regulator_set_aging_ref_adjustment(ctrl, INT_MAX);
-+
-+      rc = cpr3_regulator_init_ctrl(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "CPR controller initialization failed, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      /* Register regulator devices for all threads. */
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      rc = cpr3_regulator_vreg_register(
-+                                      &ctrl->thread[i].vreg[j]);
-+                      if (rc) {
-+                              cpr3_err(&ctrl->thread[i].vreg[j], "failed to register regulator, rc=%d\n",
-+                                      rc);
-+                              goto free_regulators;
-+                      }
-+              }
-+      }
-+
-+      rc = devm_request_threaded_irq(dev, ctrl->irq, NULL,
-+                                     cpr3_irq_handler,
-+                                     IRQF_ONESHOT |
-+                                     IRQF_TRIGGER_RISING,
-+                                     "cpr3", ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not request IRQ %d, rc=%d\n",
-+                       ctrl->irq, rc);
-+              goto free_regulators;
-+      }
-+
-+      if (ctrl->supports_hw_closed_loop &&
-+          ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
-+              rc = devm_request_threaded_irq(dev, ctrl->ceiling_irq, NULL,
-+                      cpr3_ceiling_irq_handler,
-+                      IRQF_ONESHOT | IRQF_TRIGGER_RISING,
-+                      "cpr3_ceiling", ctrl);
-+              if (rc) {
-+                      cpr3_err(ctrl, "could not request ceiling IRQ %d, rc=%d\n",
-+                              ctrl->ceiling_irq, rc);
-+                      goto free_regulators;
-+              }
-+      }
-+
-+      mutex_lock(&cpr3_controller_list_mutex);
-+      cpr3_regulator_debugfs_ctrl_add(ctrl);
-+      list_add(&ctrl->list, &cpr3_controller_list);
-+      mutex_unlock(&cpr3_controller_list_mutex);
-+
-+      if (ctrl->panic_regs_info) {
-+              /* Register panic notification call back */
-+              ctrl->panic_notifier.notifier_call = cpr3_panic_callback;
-+              atomic_notifier_chain_register(&panic_notifier_list,
-+                      &ctrl->panic_notifier);
-+      }
-+
-+      return 0;
-+
-+free_regulators:
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++)
-+                      if (!IS_ERR_OR_NULL(ctrl->thread[i].vreg[j].rdev))
-+                              regulator_unregister(
-+                                      ctrl->thread[i].vreg[j].rdev);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_open_loop_regulator_register() - register the regulators for a CPR3
-+ *                    controller which will always work in Open loop and
-+ *                    won't support close loop.
-+ * @pdev:             Platform device pointer for the CPR3 controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_open_loop_regulator_register(struct platform_device *pdev,
-+                                    struct cpr3_controller *ctrl)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct cpr3_regulator *vreg;
-+      int i, j, rc;
-+
-+      if (!dev->of_node) {
-+              dev_err(dev, "%s: Device tree node is missing\n", __func__);
-+              return -EINVAL;
-+      }
-+
-+      if (!ctrl || !ctrl->name) {
-+              dev_err(dev, "%s: CPR controller data is missing\n", __func__);
-+              return -EINVAL;
-+      }
-+
-+      if (!ctrl->vdd_regulator) {
-+              cpr3_err(ctrl, "vdd regulator missing\n");
-+              return -EINVAL;
-+      }
-+
-+      mutex_init(&ctrl->lock);
-+
-+      rc = cpr3_regulator_init_ctrl_data(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "CPR controller data initialization failed, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      vreg = &ctrl->thread[i].vreg[j];
-+                      vreg->corner[i].last_volt =
-+                              vreg->corner[i].open_loop_volt;
-+              }
-+      }
-+
-+      /* Register regulator devices for all threads. */
-+      for (i = 0; i < ctrl->thread_count; i++) {
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
-+                      rc = cpr3_regulator_vreg_register(
-+                                      &ctrl->thread[i].vreg[j]);
-+                      if (rc) {
-+                              cpr3_err(&ctrl->thread[i].vreg[j], "failed to register regulator, rc=%d\n",
-+                                       rc);
-+                              goto free_regulators;
-+                      }
-+              }
-+      }
-+
-+      mutex_lock(&cpr3_controller_list_mutex);
-+      list_add(&ctrl->list, &cpr3_controller_list);
-+      mutex_unlock(&cpr3_controller_list_mutex);
-+
-+      return 0;
-+
-+free_regulators:
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++)
-+                      if (!IS_ERR_OR_NULL(ctrl->thread[i].vreg[j].rdev))
-+                              regulator_unregister(
-+                                      ctrl->thread[i].vreg[j].rdev);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_regulator_unregister() - unregister the regulators for a CPR3 controller
-+ *            and perform CPR hardware shutdown
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_regulator_unregister(struct cpr3_controller *ctrl)
-+{
-+      int i, j, rc = 0;
-+
-+      mutex_lock(&cpr3_controller_list_mutex);
-+      list_del(&ctrl->list);
-+      cpr3_regulator_debugfs_ctrl_remove(ctrl);
-+      mutex_unlock(&cpr3_controller_list_mutex);
-+
-+      if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
-+              rc = cpr3_ctrl_clear_cpr4_config(ctrl);
-+              if (rc)
-+                      cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
-+                              rc);
-+      }
-+
-+      cpr3_ctrl_loop_disable(ctrl);
-+
-+      cpr3_closed_loop_disable(ctrl);
-+
-+      if (ctrl->vdd_limit_regulator) {
-+              regulator_disable(ctrl->vdd_limit_regulator);
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++)
-+                      regulator_unregister(ctrl->thread[i].vreg[j].rdev);
-+
-+      if (ctrl->panic_notifier.notifier_call)
-+              atomic_notifier_chain_unregister(&panic_notifier_list,
-+                      &ctrl->panic_notifier);
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_open_loop_regulator_unregister() - unregister the regulators for a CPR3
-+ *                    open loop controller and perform CPR hardware shutdown
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_open_loop_regulator_unregister(struct cpr3_controller *ctrl)
-+{
-+      int i, j;
-+
-+      mutex_lock(&cpr3_controller_list_mutex);
-+      list_del(&ctrl->list);
-+      mutex_unlock(&cpr3_controller_list_mutex);
-+
-+      if (ctrl->vdd_limit_regulator) {
-+              regulator_disable(ctrl->vdd_limit_regulator);
-+      }
-+
-+      for (i = 0; i < ctrl->thread_count; i++)
-+              for (j = 0; j < ctrl->thread[i].vreg_count; j++)
-+                      regulator_unregister(ctrl->thread[i].vreg[j].rdev);
-+
-+      if (ctrl->panic_notifier.notifier_call)
-+              atomic_notifier_chain_unregister(&panic_notifier_list,
-+                      &ctrl->panic_notifier);
-+
-+      return 0;
-+}
---- /dev/null
-+++ b/drivers/regulator/cpr3-regulator.h
-@@ -0,0 +1,1211 @@
-+/*
-+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __REGULATOR_CPR3_REGULATOR_H__
-+#define __REGULATOR_CPR3_REGULATOR_H__
-+
-+#include <linux/clk.h>
-+#include <linux/mutex.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/types.h>
-+#include <linux/power/qcom/apm.h>
-+#include <linux/regulator/driver.h>
-+
-+struct cpr3_controller;
-+struct cpr3_thread;
-+
-+/**
-+ * struct cpr3_fuse_param - defines one contiguous segment of a fuse parameter
-+ *                        that is contained within a given row.
-+ * @row:      Fuse row number
-+ * @bit_start:        The first bit within the row of the fuse parameter segment
-+ * @bit_end:  The last bit within the row of the fuse parameter segment
-+ *
-+ * Each fuse row is 64 bits in length.  bit_start and bit_end may take values
-+ * from 0 to 63.  bit_start must be less than or equal to bit_end.
-+ */
-+struct cpr3_fuse_param {
-+      unsigned                row;
-+      unsigned                bit_start;
-+      unsigned                bit_end;
-+};
-+
-+/* Each CPR3 sensor has 16 ring oscillators */
-+#define CPR3_RO_COUNT         16
-+
-+/* The maximum number of sensors that can be present on a single CPR loop. */
-+#define CPR3_MAX_SENSOR_COUNT 256
-+
-+/* This constant is used when allocating array printing buffers. */
-+#define MAX_CHARS_PER_INT     10
-+
-+/**
-+ * struct cpr4_sdelta - CPR4 controller specific data structure for the sdelta
-+ *                    adjustment table which is used to adjust the VDD supply
-+ *                    voltage automatically based upon the temperature and/or
-+ *                    the number of online CPU cores.
-+ * @allow_core_count_adj: Core count adjustments are allowed.
-+ * @allow_temp_adj:   Temperature based adjustments are allowed.
-+ * @max_core_count:   Maximum number of cores considered for core count
-+ *                    adjustment logic.
-+ * @temp_band_count:  Number of temperature bands considered for temperature
-+ *                    based adjustment logic.
-+ * @cap_volt:         CAP in uV to apply to SDELTA margins with multiple
-+ *                    cpr3-regulators defined for single controller.
-+ * @table:            SDELTA table with per-online-core and temperature based
-+ *                    adjustments of size (max_core_count * temp_band_count)
-+ *                    Outer: core count
-+ *                    Inner: temperature band
-+ *                    Each element has units of VDD supply steps. Positive
-+ *                    values correspond to a reduction in voltage and negative
-+ *                    value correspond to an increase (this follows the SDELTA
-+ *                    register semantics).
-+ * @allow_boost:      Voltage boost allowed.
-+ * @boost_num_cores:  The number of online cores at which the boost voltage
-+ *                    adjustments will be applied
-+ * @boost_table:      SDELTA table with boost voltage adjustments of size
-+ *                    temp_band_count. Each element has units of VDD supply
-+ *                    steps. Positive values correspond to a reduction in
-+ *                    voltage and negative value correspond to an increase
-+ *                    (this follows the SDELTA register semantics).
-+ */
-+struct cpr4_sdelta {
-+      bool    allow_core_count_adj;
-+      bool    allow_temp_adj;
-+      int     max_core_count;
-+      int     temp_band_count;
-+      int     cap_volt;
-+      int     *table;
-+      bool    allow_boost;
-+      int     boost_num_cores;
-+      int     *boost_table;
-+};
-+
-+/**
-+ * struct cpr3_corner - CPR3 virtual voltage corner data structure
-+ * @floor_volt:               CPR closed-loop floor voltage in microvolts
-+ * @ceiling_volt:     CPR closed-loop ceiling voltage in microvolts
-+ * @open_loop_volt:   CPR open-loop voltage (i.e. initial voltage) in
-+ *                    microvolts
-+ * @last_volt:                Last known settled CPR closed-loop voltage which is used
-+ *                    when switching to a new corner
-+ * @abs_ceiling_volt: The absolute CPR closed-loop ceiling voltage in
-+ *                    microvolts.  This is used to limit the ceiling_volt
-+ *                    value when it is increased as a result of aging
-+ *                    adjustment.
-+ * @unaged_floor_volt:        The CPR closed-loop floor voltage in microvolts before
-+ *                    any aging adjustment is performed
-+ * @unaged_ceiling_volt: The CPR closed-loop ceiling voltage in microvolts
-+ *                    before any aging adjustment is performed
-+ * @unaged_open_loop_volt: The CPR open-loop voltage (i.e. initial voltage) in
-+ *                    microvolts before any aging adjusment is performed
-+ * @system_volt:      The system-supply voltage in microvolts or corners or
-+ *                    levels
-+ * @mem_acc_volt:     The mem-acc-supply voltage in corners
-+ * @proc_freq:                Processor frequency in Hertz. For CPR rev. 3 and 4
-+ *                    conrollers, this field is only used by platform specific
-+ *                    CPR3 driver for interpolation. For CPRh-compliant
-+ *                    controllers, this frequency is also utilized by the
-+ *                    clock driver to determine the corner to CPU clock
-+ *                    frequency mappings.
-+ * @cpr_fuse_corner:  Fused corner index associated with this virtual corner
-+ *                    (only used by platform specific CPR3 driver for
-+ *                    mapping purposes)
-+ * @target_quot:      Array of target quotient values to use for each ring
-+ *                    oscillator (RO) for this corner.  A value of 0 should be
-+ *                    specified as the target quotient for each RO that is
-+ *                    unused by this corner.
-+ * @ro_scale:         Array of CPR ring oscillator (RO) scaling factors.  The
-+ *                    scaling factor for each RO is defined from RO0 to RO15
-+ *                    with units of QUOT/V.  A value of 0 may be specified for
-+ *                    an RO that is unused.
-+ * @ro_mask:          Bitmap where each of the 16 LSBs indicate if the
-+ *                    corresponding ROs should be masked for this corner
-+ * @irq_en:           Bitmap of the CPR interrupts to enable for this corner
-+ * @aging_derate:     The amount to derate the aging voltage adjustment
-+ *                    determined for the reference corner in units of uV/mV.
-+ *                    E.g. a value of 900 would imply that the adjustment for
-+ *                    this corner should be 90% (900/1000) of that for the
-+ *                    reference corner.
-+ * @use_open_loop:    Boolean indicating that open-loop (i.e CPR disabled) as
-+ *                    opposed to closed-loop operation must be used for this
-+ *                    corner on CPRh controllers.
-+ * @sdelta:           The CPR4 controller specific data for this corner. This
-+ *                    field is applicable for CPR4 controllers.
-+ *
-+ * The value of last_volt is initialized inside of the cpr3_regulator_register()
-+ * call with the open_loop_volt value.  It can later be updated to the settled
-+ * VDD supply voltage.  The values for unaged_floor_volt, unaged_ceiling_volt,
-+ * and unaged_open_loop_volt are initialized inside of cpr3_regulator_register()
-+ * if ctrl->aging_required == true.  These three values must be pre-initialized
-+ * if cpr3_regulator_register() is called with ctrl->aging_required == false and
-+ * ctrl->aging_succeeded == true.
-+ *
-+ * The values of ro_mask and irq_en are initialized inside of the
-+ * cpr3_regulator_register() call.
-+ */
-+struct cpr3_corner {
-+      int                     floor_volt;
-+      int                     ceiling_volt;
-+      int                     cold_temp_open_loop_volt;
-+      int                     normal_temp_open_loop_volt;
-+      int                     open_loop_volt;
-+      int                     last_volt;
-+      int                     abs_ceiling_volt;
-+      int                     unaged_floor_volt;
-+      int                     unaged_ceiling_volt;
-+      int                     unaged_open_loop_volt;
-+      int                     system_volt;
-+      int                     mem_acc_volt;
-+      u32                     proc_freq;
-+      int                     cpr_fuse_corner;
-+      u32                     target_quot[CPR3_RO_COUNT];
-+      u32                     ro_scale[CPR3_RO_COUNT];
-+      u32                     ro_mask;
-+      u32                     irq_en;
-+      int                     aging_derate;
-+      bool                    use_open_loop;
-+      struct cpr4_sdelta      *sdelta;
-+};
-+
-+/**
-+ * struct cprh_corner_band - CPRh controller specific data structure which
-+ *                    encapsulates the range of corners and the SDELTA
-+ *                    adjustment table to be applied to the corners within
-+ *                    the min and max bounds of the corner band.
-+ * @corner:           Corner number which defines the corner band boundary
-+ * @sdelta:           The SDELTA adjustment table which contains core-count
-+ *                    and temp based margin adjustments that are applicable
-+ *                    to the corner band.
-+ */
-+struct cprh_corner_band {
-+      int                     corner;
-+      struct cpr4_sdelta      *sdelta;
-+};
-+
-+/**
-+ * struct cpr3_fuse_parameters - CPR4 fuse specific data structure which has
-+ *                    the required fuse parameters need for Close Loop CPR
-+ * @(*apss_ro_sel_param)[2]:       Pointer to RO select fuse details
-+ * @(*apss_init_voltage_param)[2]: Pointer to Target voltage fuse details
-+ * @(*apss_target_quot_param)[2]:  Pointer to Target quot fuse details
-+ * @(*apss_quot_offset_param)[2]:  Pointer to quot offset fuse details
-+ * @cpr_fusing_rev_param:          Pointer to CPR revision fuse details
-+ * @apss_speed_bin_param:          Pointer to Speed bin fuse details
-+ * @cpr_boost_fuse_cfg_param:      Pointer to Boost fuse cfg details
-+ * @apss_boost_fuse_volt_param:    Pointer to Boost fuse volt details
-+ * @misc_fuse_volt_adj_param:      Pointer to Misc fuse volt fuse details
-+ */
-+struct cpr3_fuse_parameters {
-+      struct cpr3_fuse_param (*apss_ro_sel_param)[2];
-+      struct cpr3_fuse_param (*apss_init_voltage_param)[2];
-+      struct cpr3_fuse_param (*apss_target_quot_param)[2];
-+      struct cpr3_fuse_param (*apss_quot_offset_param)[2];
-+      struct cpr3_fuse_param *cpr_fusing_rev_param;
-+      struct cpr3_fuse_param *apss_speed_bin_param;
-+      struct cpr3_fuse_param *cpr_boost_fuse_cfg_param;
-+      struct cpr3_fuse_param *apss_boost_fuse_volt_param;
-+      struct cpr3_fuse_param *misc_fuse_volt_adj_param;
-+};
-+
-+struct cpr4_mem_acc_func {
-+      void (*set_mem_acc)(struct regulator_dev *);
-+      void (*clear_mem_acc)(struct regulator_dev *);
-+};
-+
-+/**
-+ * struct cpr4_reg_data - CPR4 regulator specific data structure which is
-+ * target specific
-+ * @cpr_valid_fuse_count: Number of valid fuse corners
-+ * @fuse_ref_volt:      Pointer to fuse reference voltage
-+ * @fuse_step_volt:     CPR step voltage available in fuse
-+ * @cpr_clk_rate:       CPR clock rate
-+ * @boost_fuse_ref_volt:  Boost fuse reference voltage
-+ * @boost_ceiling_volt:   Boost ceiling voltage
-+ * @boost_floor_volt:           Boost floor voltage
-+ * @cpr3_fuse_params:     Pointer to CPR fuse parameters
-+ * @mem_acc_funcs:        Pointer to MEM ACC set/clear functions
-+ **/
-+struct cpr4_reg_data {
-+      u32 cpr_valid_fuse_count;
-+      int *fuse_ref_volt;
-+      u32 fuse_step_volt;
-+      u32 cpr_clk_rate;
-+      int boost_fuse_ref_volt;
-+      int boost_ceiling_volt;
-+      int boost_floor_volt;
-+      struct cpr3_fuse_parameters *cpr3_fuse_params;
-+      struct cpr4_mem_acc_func *mem_acc_funcs;
-+};
-+/**
-+ * struct cpr3_reg_data - CPR3 regulator specific data structure which is
-+ * target specific
-+ * @cpr_valid_fuse_count: Number of valid fuse corners
-+ * @(*init_voltage_param)[2]: Pointer to Target voltage fuse details
-+ * @fuse_ref_volt:      Pointer to fuse reference voltage
-+ * @fuse_step_volt:     CPR step voltage available in fuse
-+ * @cpr_clk_rate:       CPR clock rate
-+ * @cpr3_fuse_params:     Pointer to CPR fuse parameters
-+ **/
-+struct cpr3_reg_data {
-+      u32 cpr_valid_fuse_count;
-+      struct cpr3_fuse_param (*init_voltage_param)[2];
-+      int *fuse_ref_volt;
-+      u32 fuse_step_volt;
-+      u32 cpr_clk_rate;
-+};
-+
-+/**
-+ * struct cpr3_regulator - CPR3 logical regulator instance associated with a
-+ *                    given CPR3 hardware thread
-+ * @of_node:          Device node associated with the device tree child node
-+ *                    of this CPR3 regulator
-+ * @thread:           Pointer to the CPR3 thread which manages this CPR3
-+ *                    regulator
-+ * @name:             Unique name for this CPR3 regulator which is filled
-+ *                    using the device tree regulator-name property
-+ * @rdesc:            Regulator description for this CPR3 regulator
-+ * @rdev:             Regulator device pointer for the regulator registered
-+ *                    for this CPR3 regulator
-+ * @mem_acc_regulator:        Pointer to the optional mem-acc supply regulator used
-+ *                    to manage memory circuitry settings based upon CPR3
-+ *                    regulator output voltage.
-+ * @corner:           Array of all corners supported by this CPR3 regulator
-+ * @corner_count:     The number of elements in the corner array
-+ * @corner_band:      Array of all corner bands supported by CPRh compatible
-+ *                    controllers
-+ * @cpr4_regulator_data Target specific cpr4 regulator data
-+ * @cpr3_regulator_data Target specific cpr3 regulator data
-+ * @corner_band_count:        The number of elements in the corner band array
-+ * @platform_fuses:   Pointer to platform specific CPR fuse data (only used by
-+ *                    platform specific CPR3 driver)
-+ * @speed_bin_fuse:   Value read from the speed bin fuse parameter
-+ * @speed_bins_supported: The number of speed bins supported by the device tree
-+ *                    configuration for this CPR3 regulator
-+ * @cpr_rev_fuse:     Value read from the CPR fusing revision fuse parameter
-+ * @fuse_combo:               Platform specific enum value identifying the specific
-+ *                    combination of fuse values found on a given chip
-+ * @fuse_combos_supported: The number of fuse combinations supported by the
-+ *                    device tree configuration for this CPR3 regulator
-+ * @fuse_corner_count:        Number of corners defined by fuse parameters
-+ * @fuse_corner_map:  Array of length fuse_corner_count which specifies the
-+ *                    highest corner associated with each fuse corner.  Note
-+ *                    that each element must correspond to a valid corner
-+ *                    and that element values must be strictly increasing.
-+ *                    Also, it is acceptable for the lowest fuse corner to map
-+ *                    to a corner other than the lowest.  Likewise, it is
-+ *                    acceptable for the highest fuse corner to map to a
-+ *                    corner other than the highest.
-+ * @fuse_combo_corner_sum: The sum of the corner counts across all fuse combos
-+ * @fuse_combo_offset:        The device tree property array offset for the selected
-+ *                    fuse combo
-+ * @speed_bin_corner_sum: The sum of the corner counts across all speed bins
-+ *                    This may be specified as 0 if per speed bin parsing
-+ *                    support is not required.
-+ * @speed_bin_offset: The device tree property array offset for the selected
-+ *                    speed bin
-+ * @fuse_combo_corner_band_sum: The sum of the corner band counts across all
-+ *                    fuse combos
-+ * @fuse_combo_corner_band_offset: The device tree property array offset for
-+ *                    the corner band count corresponding to the selected
-+ *                    fuse combo
-+ * @speed_bin_corner_band_sum: The sum of the corner band counts across all
-+ *                    speed bins. This may be specified as 0 if per speed bin
-+ *                    parsing support is not required
-+ * @speed_bin_corner_band_offset: The device tree property array offset for the
-+ *                    corner band count corresponding to the selected speed
-+ *                    bin
-+ * @pd_bypass_mask:   Bit mask of power domains associated with this CPR3
-+ *                    regulator
-+ * @dynamic_floor_corner: Index identifying the voltage corner for the CPR3
-+ *                    regulator whose last_volt value should be used as the
-+ *                    global CPR floor voltage if all of the power domains
-+ *                    associated with this CPR3 regulator are bypassed
-+ * @uses_dynamic_floor: Boolean flag indicating that dynamic_floor_corner should
-+ *                    be utilized for the CPR3 regulator
-+ * @current_corner:   Index identifying the currently selected voltage corner
-+ *                    for the CPR3 regulator or less than 0 if no corner has
-+ *                    been requested
-+ * @last_closed_loop_corner: Index identifying the last voltage corner for the
-+ *                    CPR3 regulator which was configured when operating in
-+ *                    CPR closed-loop mode or less than 0 if no corner has
-+ *                    been requested.  CPR registers are only written to when
-+ *                    using closed-loop mode.
-+ * @aggregated:               Boolean flag indicating that this CPR3 regulator
-+ *                    participated in the last aggregation event
-+ * @debug_corner:     Index identifying voltage corner used for displaying
-+ *                    corner configuration values in debugfs
-+ * @vreg_enabled:     Boolean defining the enable state of the CPR3
-+ *                    regulator's regulator within the regulator framework.
-+ * @aging_allowed:    Boolean defining if CPR aging adjustments are allowed
-+ *                    for this CPR3 regulator given the fuse combo of the
-+ *                    device
-+ * @aging_allow_open_loop_adj: Boolean defining if the open-loop voltage of each
-+ *                    corner of this regulator should be adjusted as a result
-+ *                    of an aging measurement.  This flag can be set to false
-+ *                    when the open-loop voltage adjustments have been
-+ *                    specified such that they include the maximum possible
-+ *                    aging adjustment.  This flag is only used if
-+ *                    aging_allowed == true.
-+ * @aging_corner:     The corner that should be configured for this regulator
-+ *                    when an aging measurement is performed.
-+ * @aging_max_adjust_volt: The maximum aging voltage margin in microvolts that
-+ *                    may be added to the target quotients of this regulator.
-+ *                    A value of 0 may be specified if this regulator does not
-+ *                    require any aging adjustment.
-+ * @allow_core_count_adj: Core count adjustments are allowed for this regulator.
-+ * @allow_temp_adj:   Temperature based adjustments are allowed for this
-+ *                    regulator.
-+ * @max_core_count:   Maximum number of cores considered for core count
-+ *                    adjustment logic.
-+ * @allow_boost:      Voltage boost allowed for this regulator.
-+ *
-+ * This structure contains both configuration and runtime state data.  The
-+ * elements current_corner, last_closed_loop_corner, aggregated, debug_corner,
-+ * and vreg_enabled are state variables.
-+ */
-+struct cpr3_regulator {
-+      struct device_node      *of_node;
-+      struct cpr3_thread      *thread;
-+      const char              *name;
-+      struct regulator_desc   rdesc;
-+      struct regulator_dev    *rdev;
-+      struct regulator        *mem_acc_regulator;
-+      struct cpr3_corner      *corner;
-+      int                     corner_count;
-+      struct cprh_corner_band *corner_band;
-+      const struct cpr4_reg_data    *cpr4_regulator_data;
-+      const struct cpr3_reg_data    *cpr3_regulator_data;
-+      u32                     corner_band_count;
-+
-+      void                    *platform_fuses;
-+      int                     speed_bin_fuse;
-+      int                     speed_bins_supported;
-+      int                     cpr_rev_fuse;
-+      int                     part_type;
-+      int                     part_type_supported;
-+      int                     fuse_combo;
-+      int                     fuse_combos_supported;
-+      int                     fuse_corner_count;
-+      int                     *fuse_corner_map;
-+      int                     fuse_combo_corner_sum;
-+      int                     fuse_combo_offset;
-+      int                     speed_bin_corner_sum;
-+      int                     speed_bin_offset;
-+      int                     fuse_combo_corner_band_sum;
-+      int                     fuse_combo_corner_band_offset;
-+      int                     speed_bin_corner_band_sum;
-+      int                     speed_bin_corner_band_offset;
-+      u32                     pd_bypass_mask;
-+      int                     dynamic_floor_corner;
-+      bool                    uses_dynamic_floor;
-+
-+      int                     current_corner;
-+      int                     last_closed_loop_corner;
-+      bool                    aggregated;
-+      int                     debug_corner;
-+      bool                    vreg_enabled;
-+
-+      bool                    aging_allowed;
-+      bool                    aging_allow_open_loop_adj;
-+      int                     aging_corner;
-+      int                     aging_max_adjust_volt;
-+
-+      bool                    allow_core_count_adj;
-+      bool                    allow_temp_adj;
-+      int                     max_core_count;
-+      bool                    allow_boost;
-+};
-+
-+/**
-+ * struct cpr3_thread - CPR3 hardware thread data structure
-+ * @thread_id:                Hardware thread ID
-+ * @of_node:          Device node associated with the device tree child node
-+ *                    of this CPR3 thread
-+ * @ctrl:             Pointer to the CPR3 controller which manages this thread
-+ * @vreg:             Array of CPR3 regulators handled by the CPR3 thread
-+ * @vreg_count:               Number of elements in the vreg array
-+ * @aggr_corner:      CPR corner containing the in process aggregated voltage
-+ *                    and target quotient configurations which will be applied
-+ * @last_closed_loop_aggr_corner: CPR corner containing the most recent
-+ *                    configurations which were written into hardware
-+ *                    registers when operating in closed loop mode (i.e. with
-+ *                    CPR enabled)
-+ * @consecutive_up:   The number of consecutive CPR step up events needed to
-+ *                    to trigger an up interrupt
-+ * @consecutive_down: The number of consecutive CPR step down events needed to
-+ *                    to trigger a down interrupt
-+ * @up_threshold:     The number CPR error steps required to generate an up
-+ *                    event
-+ * @down_threshold:   The number CPR error steps required to generate a down
-+ *                    event
-+ *
-+ * This structure contains both configuration and runtime state data.  The
-+ * elements aggr_corner and last_closed_loop_aggr_corner are state variables.
-+ */
-+struct cpr3_thread {
-+      u32                     thread_id;
-+      struct device_node      *of_node;
-+      struct cpr3_controller  *ctrl;
-+      struct cpr3_regulator   *vreg;
-+      int                     vreg_count;
-+      struct cpr3_corner      aggr_corner;
-+      struct cpr3_corner      last_closed_loop_aggr_corner;
-+
-+      u32                     consecutive_up;
-+      u32                     consecutive_down;
-+      u32                     up_threshold;
-+      u32                     down_threshold;
-+};
-+
-+/* Per CPR controller data */
-+/**
-+ * enum cpr3_mem_acc_corners - Constants which define the number of mem-acc
-+ *            regulator corners available in the mem-acc corner map array.
-+ * %CPR3_MEM_ACC_LOW_CORNER:  Index in mem-acc corner map array mapping to the
-+ *                            mem-acc regulator corner
-+ *                            to be used for low voltage vdd supply
-+ * %CPR3_MEM_ACC_HIGH_CORNER: Index in mem-acc corner map array mapping to the
-+ *                            mem-acc regulator corner to be used for high
-+ *                            voltage vdd supply
-+ * %CPR3_MEM_ACC_CORNERS:     Number of elements in the mem-acc corner map
-+ *                            array
-+ */
-+enum cpr3_mem_acc_corners {
-+      CPR3_MEM_ACC_LOW_CORNER         = 0,
-+      CPR3_MEM_ACC_HIGH_CORNER        = 1,
-+      CPR3_MEM_ACC_CORNERS            = 2,
-+};
-+
-+/**
-+ * enum cpr3_count_mode - CPR3 controller count mode which defines the
-+ *            method that CPR sensor data is acquired
-+ * %CPR3_COUNT_MODE_ALL_AT_ONCE_MIN:  Capture all CPR sensor readings
-+ *                                    simultaneously and report the minimum
-+ *                                    value seen in successive measurements
-+ * %CPR3_COUNT_MODE_ALL_AT_ONCE_MAX:  Capture all CPR sensor readings
-+ *                                    simultaneously and report the maximum
-+ *                                    value seen in successive measurements
-+ * %CPR3_COUNT_MODE_STAGGERED:                Read one sensor at a time in a
-+ *                                    sequential fashion
-+ * %CPR3_COUNT_MODE_ALL_AT_ONCE_AGE:  Capture all CPR aging sensor readings
-+ *                                    simultaneously.
-+ */
-+enum cpr3_count_mode {
-+      CPR3_COUNT_MODE_ALL_AT_ONCE_MIN = 0,
-+      CPR3_COUNT_MODE_ALL_AT_ONCE_MAX = 1,
-+      CPR3_COUNT_MODE_STAGGERED       = 2,
-+      CPR3_COUNT_MODE_ALL_AT_ONCE_AGE = 3,
-+};
-+
-+/**
-+ * enum cpr_controller_type - supported CPR controller hardware types
-+ * %CPR_CTRL_TYPE_CPR3:       HW has CPR3 controller
-+ * %CPR_CTRL_TYPE_CPR4:       HW has CPR4 controller
-+ */
-+enum cpr_controller_type {
-+      CPR_CTRL_TYPE_CPR3,
-+      CPR_CTRL_TYPE_CPR4,
-+};
-+
-+/**
-+ * cpr_setting - supported CPR global settings
-+ * %CPR_DEFAULT: default mode from dts will be used
-+ * %CPR_DISABLED: ceiling voltage will be used for all the corners
-+ * %CPR_OPEN_LOOP_EN: CPR will work in OL
-+ * %CPR_CLOSED_LOOP_EN: CPR will work in CL, if supported
-+ */
-+enum cpr_setting {
-+      CPR_DEFAULT             = 0,
-+      CPR_DISABLED            = 1,
-+      CPR_OPEN_LOOP_EN        = 2,
-+      CPR_CLOSED_LOOP_EN      = 3,
-+};
-+
-+/**
-+ * struct cpr3_aging_sensor_info - CPR3 aging sensor information
-+ * @sensor_id         The index of the CPR3 sensor to be used in the aging
-+ *                    measurement.
-+ * @ro_scale          The CPR ring oscillator (RO) scaling factor for the
-+ *                    aging sensor with units of QUOT/V.
-+ * @init_quot_diff:   The fused quotient difference between aged and un-aged
-+ *                    paths that was measured at manufacturing time.
-+ * @measured_quot_diff: The quotient difference measured at runtime.
-+ * @bypass_mask:      Bit mask of the CPR sensors that must be bypassed during
-+ *                    the aging measurement for this sensor
-+ *
-+ * This structure contains both configuration and runtime state data.  The
-+ * element measured_quot_diff is a state variable.
-+ */
-+struct cpr3_aging_sensor_info {
-+      u32                     sensor_id;
-+      u32                     ro_scale;
-+      int                     init_quot_diff;
-+      int                     measured_quot_diff;
-+      u32                     bypass_mask[CPR3_MAX_SENSOR_COUNT / 32];
-+};
-+
-+/**
-+ * struct cpr3_reg_info - Register information data structure
-+ * @name:     Register name
-+ * @addr:     Register physical address
-+ * @value:    Register content
-+ * @virt_addr:        Register virtual address
-+ *
-+ * This data structure is used to dump some critical register contents
-+ * when the device crashes due to a kernel panic.
-+ */
-+struct cpr3_reg_info {
-+      const char      *name;
-+      u32             addr;
-+      u32             value;
-+      void __iomem    *virt_addr;
-+};
-+
-+/**
-+ * struct cpr3_panic_regs_info - Data structure to dump critical register
-+ *            contents.
-+ * @reg_count:                Number of elements in the regs array
-+ * @regs:             Array of critical registers information
-+ *
-+ * This data structure is used to dump critical register contents when
-+ * the device crashes due to a kernel panic.
-+ */
-+struct cpr3_panic_regs_info {
-+      int                     reg_count;
-+      struct cpr3_reg_info    *regs;
-+};
-+
-+/**
-+ * struct cpr3_controller - CPR3 controller data structure
-+ * @dev:              Device pointer for the CPR3 controller device
-+ * @name:             Unique name for the CPR3 controller
-+ * @ctrl_id:          Controller ID corresponding to the VDD supply number
-+ *                    that this CPR3 controller manages.
-+ * @cpr_ctrl_base:    Virtual address of the CPR3 controller base register
-+ * @fuse_base:                Virtual address of fuse row 0
-+ * @aging_possible_reg:       Virtual address of an optional platform-specific
-+ *                    register that must be ready to determine if it is
-+ *                    possible to perform an aging measurement.
-+ * @list:             list head used in a global cpr3-regulator list so that
-+ *                    cpr3-regulator structs can be found easily in RAM dumps
-+ * @thread:           Array of CPR3 threads managed by the CPR3 controller
-+ * @thread_count:     Number of elements in the thread array
-+ * @sensor_owner:     Array of thread IDs indicating which thread owns a given
-+ *                    CPR sensor
-+ * @sensor_count:     The number of CPR sensors found on the CPR loop managed
-+ *                    by this CPR controller.  Must be equal to the number of
-+ *                    elements in the sensor_owner array
-+ * @soc_revision:     Revision number of the SoC.  This may be unused by
-+ *                    platforms that do not have different behavior for
-+ *                    different SoC revisions.
-+ * @lock:             Mutex lock used to ensure mutual exclusion between
-+ *                    all of the threads associated with the controller
-+ * @vdd_regulator:    Pointer to the VDD supply regulator which this CPR3
-+ *                    controller manages
-+ * @system_regulator: Pointer to the optional system-supply regulator upon
-+ *                    which the VDD supply regulator depends.
-+ * @mem_acc_regulator:        Pointer to the optional mem-acc supply regulator used
-+ *                    to manage memory circuitry settings based upon the
-+ *                    VDD supply output voltage.
-+ * @vdd_limit_regulator: Pointer to the VDD supply limit regulator which is used
-+ *                    for hardware closed-loop in order specify ceiling and
-+ *                    floor voltage limits (platform specific)
-+ * @system_supply_max_volt: Voltage in microvolts which corresponds to the
-+ *                    absolute ceiling voltage of the system-supply
-+ * @mem_acc_threshold_volt: mem-acc threshold voltage in microvolts
-+ * @mem_acc_corner_map: mem-acc regulator corners mapping to low and high
-+ *                    voltage mem-acc settings for the memories powered by
-+ *                    this CPR3 controller and its associated CPR3 regulators
-+ * @mem_acc_crossover_volt: Voltage in microvolts corresponding to the voltage
-+ *                    that the VDD supply must be set to while a MEM ACC
-+ *                    switch is in progress. This element must be initialized
-+ *                    for CPRh controllers when a MEM ACC threshold voltage is
-+ *                    defined.
-+ * @core_clk:         Pointer to the CPR3 controller core clock
-+ * @iface_clk:                Pointer to the CPR3 interface clock (platform specific)
-+ * @bus_clk:          Pointer to the CPR3 bus clock (platform specific)
-+ * @irq:              CPR interrupt number
-+ * @irq_affinity_mask:        The cpumask for the CPUs which the CPR interrupt should
-+ *                    have affinity for
-+ * @cpu_hotplug_notifier: CPU hotplug notifier used to reset IRQ affinity when a
-+ *                    CPU is brought back online
-+ * @ceiling_irq:      Interrupt number for the interrupt that is triggered
-+ *                    when hardware closed-loop attempts to exceed the ceiling
-+ *                    voltage
-+ * @apm:              Handle to the array power mux (APM)
-+ * @apm_threshold_volt:       Voltage in microvolts which defines the threshold
-+ *                    voltage to determine the APM supply selection for
-+ *                    each corner
-+ * @apm_crossover_volt:       Voltage in microvolts corresponding to the voltage that
-+ *                    the VDD supply must be set to while an APM switch is in
-+ *                    progress. This element must be initialized for CPRh
-+ *                    controllers when an APM threshold voltage is defined
-+ * @apm_adj_volt:     Minimum difference between APM threshold voltage and
-+ *                    open-loop voltage which allows the APM threshold voltage
-+ *                    to be used as a ceiling
-+ * @apm_high_supply:  APM supply to configure if VDD voltage is greater than
-+ *                    or equal to the APM threshold voltage
-+ * @apm_low_supply:   APM supply to configure if the VDD voltage is less than
-+ *                    the APM threshold voltage
-+ * @base_volt:                Minimum voltage in microvolts supported by the VDD
-+ *                    supply managed by this CPR controller
-+ * @corner_switch_delay_time: The delay time in nanoseconds used by the CPR
-+ *                    controller to wait for voltage settling before
-+ *                    acknowledging the OSM block after corner changes
-+ * @cpr_clock_rate:   CPR reference clock frequency in Hz.
-+ * @sensor_time:      The time in nanoseconds that each sensor takes to
-+ *                    perform a measurement.
-+ * @loop_time:                The time in nanoseconds between consecutive CPR
-+ *                    measurements.
-+ * @up_down_delay_time: The time to delay in nanoseconds between consecutive CPR
-+ *                    measurements when the last measurement recommended
-+ *                    increasing or decreasing the vdd-supply voltage.
-+ *                    (platform specific)
-+ * @idle_clocks:      Number of CPR reference clock ticks that the CPR
-+ *                    controller waits in transitional states.
-+ * @step_quot_init_min:       The default minimum CPR step quotient value.  The step
-+ *                    quotient is the number of additional ring oscillator
-+ *                    ticks observed when increasing one step in vdd-supply
-+ *                    output voltage.
-+ * @step_quot_init_max:       The default maximum CPR step quotient value.
-+ * @step_volt:                Step size in microvolts between available set points
-+ *                    of the VDD supply
-+ * @down_error_step_limit: CPR4 hardware closed-loop down error step limit which
-+ *                    defines the maximum number of VDD supply regulator steps
-+ *                    that the voltage may be reduced as the result of a
-+ *                    single CPR measurement.
-+ * @up_error_step_limit: CPR4 hardware closed-loop up error step limit which
-+ *                    defines the maximum number of VDD supply regulator steps
-+ *                    that the voltage may be increased as the result of a
-+ *                    single CPR measurement.
-+ * @count_mode:               CPR controller count mode
-+ * @count_repeat:     Number of times to perform consecutive sensor
-+ *                    measurements when using all-at-once count modes.
-+ * @proc_clock_throttle: Defines the processor clock frequency throttling
-+ *                    register value to use.  This can be used to reduce the
-+ *                    clock frequency when a power domain exits a low power
-+ *                    mode until CPR settles at a new voltage.
-+ *                    (platform specific)
-+ * @cpr_allowed_hw:   Boolean which indicates if closed-loop CPR operation is
-+ *                    permitted for a given chip based upon hardware fuse
-+ *                    values
-+ * @cpr_allowed_sw:   Boolean which indicates if closed-loop CPR operation is
-+ *                    permitted based upon software policies
-+ * @supports_hw_closed_loop: Boolean which indicates if this CPR3/4 controller
-+ *                    physically supports hardware closed-loop CPR operation
-+ * @use_hw_closed_loop:       Boolean which indicates that this controller will be
-+ *                    using hardware closed-loop operation in place of
-+ *                    software closed-loop operation.
-+ * @ctrl_type:                CPR controller type
-+ * @saw_use_unit_mV:  Boolean which indicates the unit used in SAW PVC
-+ *                    interface is mV.
-+ * @aggr_corner:      CPR corner containing the most recently aggregated
-+ *                    voltage configurations which are being used currently
-+ * @cpr_enabled:      Boolean which indicates that the CPR controller is
-+ *                    enabled and operating in closed-loop mode.  CPR clocks
-+ *                    have been prepared and enabled whenever this flag is
-+ *                    true.
-+ * @last_corner_was_closed_loop: Boolean indicating if the last known corners
-+ *                    were updated during closed loop operation.
-+ * @cpr_suspended:    Boolean which indicates that CPR has been temporarily
-+ *                    disabled while enterring system suspend.
-+ * @debugfs:          Pointer to the debugfs directory of this CPR3 controller
-+ * @aging_ref_volt:   Reference voltage in microvolts to configure when
-+ *                    performing CPR aging measurements.
-+ * @aging_vdd_mode:   vdd-supply regulator mode to configure before performing
-+ *                    a CPR aging measurement.  It should be one of
-+ *                    REGULATOR_MODE_*.
-+ * @aging_complete_vdd_mode: vdd-supply regulator mode to configure after
-+ *                    performing a CPR aging measurement.  It should be one of
-+ *                    REGULATOR_MODE_*.
-+ * @aging_ref_adjust_volt: The reference aging voltage margin in microvolts that
-+ *                    should be added to the target quotients of the
-+ *                    regulators managed by this controller after derating.
-+ * @aging_required:   Flag which indicates that a CPR aging measurement still
-+ *                    needs to be performed for this CPR3 controller.
-+ * @aging_succeeded:  Flag which indicates that a CPR aging measurement has
-+ *                    completed successfully.
-+ * @aging_failed:     Flag which indicates that a CPR aging measurement has
-+ *                    failed to complete successfully.
-+ * @aging_sensor:     Array of CPR3 aging sensors which are used to perform
-+ *                    aging measurements at a runtime.
-+ * @aging_sensor_count:       Number of elements in the aging_sensor array
-+ * @aging_possible_mask: Optional bitmask used to mask off the
-+ *                    aging_possible_reg register.
-+ * @aging_possible_val:       Optional value that the masked aging_possible_reg
-+ *                    register must have in order for a CPR aging measurement
-+ *                    to be possible.
-+ * @step_quot_fixed:  Fixed step quotient value used for target quotient
-+ *                    adjustment if use_dynamic_step_quot is not set.
-+ *                    This parameter is only relevant for CPR4 controllers
-+ *                    when using the per-online-core or per-temperature
-+ *                    adjustments.
-+ * @initial_temp_band:        Temperature band used for calculation of base-line
-+ *                    target quotients (fused).
-+ * @use_dynamic_step_quot: Boolean value which indicates that margin adjustment
-+ *                    of target quotient will be based on the step quotient
-+ *                    calculated dynamically in hardware for each RO.
-+ * @allow_core_count_adj: Core count adjustments are allowed for this controller
-+ * @allow_temp_adj:   Temperature based adjustments are allowed for
-+ *                    this controller
-+ * @allow_boost:      Voltage boost allowed for this controller.
-+ * @temp_band_count:  Number of temperature bands used for temperature based
-+ *                    adjustment logic
-+ * @temp_points:      Array of temperature points in decidegrees Celsius used
-+ *                    to specify the ranges for selected temperature bands.
-+ *                    The array must have (temp_band_count - 1) elements
-+ *                    allocated.
-+ * @temp_sensor_id_start: Start ID of temperature sensors used for temperature
-+ *                    based adjustments.
-+ * @temp_sensor_id_end:       End ID of temperature sensors used for temperature
-+ *                    based adjustments.
-+ * @voltage_settling_time: The time in nanoseconds that it takes for the
-+ *                    VDD supply voltage to settle after being increased or
-+ *                    decreased by step_volt microvolts which is used when
-+ *                    SDELTA voltage margin adjustments are applied.
-+ * @cpr_global_setting:       Global setting for this CPR controller
-+ * @panic_regs_info:  Array of panic registers information which provides the
-+ *                    list of registers to dump when the device crashes.
-+ * @panic_notifier:   Notifier block registered to global panic notifier list.
-+ *
-+ * This structure contains both configuration and runtime state data.  The
-+ * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
-+ * last_corner_was_closed_loop, cpr_suspended, aging_ref_adjust_volt,
-+ * aging_required, aging_succeeded, and aging_failed are state variables.
-+ *
-+ * The apm* elements do not need to be initialized if the VDD supply managed by
-+ * the CPR3 controller does not utilize an APM.
-+ *
-+ * The elements step_quot_fixed, initial_temp_band, allow_core_count_adj,
-+ * allow_temp_adj and temp* need to be initialized for CPR4 controllers which
-+ * are using per-online-core or per-temperature adjustments.
-+ */
-+struct cpr3_controller {
-+      struct device           *dev;
-+      const char              *name;
-+      int                     ctrl_id;
-+      void __iomem            *cpr_ctrl_base;
-+      void __iomem            *fuse_base;
-+      void __iomem            *aging_possible_reg;
-+      struct list_head        list;
-+      struct cpr3_thread      *thread;
-+      int                     thread_count;
-+      u8                      *sensor_owner;
-+      int                     sensor_count;
-+      int                     soc_revision;
-+      struct mutex            lock;
-+      struct regulator        *vdd_regulator;
-+      struct regulator        *system_regulator;
-+      struct regulator        *mem_acc_regulator;
-+      struct regulator        *vdd_limit_regulator;
-+      int                     system_supply_max_volt;
-+      int                     mem_acc_threshold_volt;
-+      int                     mem_acc_corner_map[CPR3_MEM_ACC_CORNERS];
-+      int                     mem_acc_crossover_volt;
-+      struct clk              *core_clk;
-+      struct clk              *iface_clk;
-+      struct clk              *bus_clk;
-+      int                     irq;
-+      struct cpumask          irq_affinity_mask;
-+      struct notifier_block   cpu_hotplug_notifier;
-+      int                     ceiling_irq;
-+      struct msm_apm_ctrl_dev *apm;
-+      int                     apm_threshold_volt;
-+      int                     apm_crossover_volt;
-+      int                     apm_adj_volt;
-+      enum msm_apm_supply     apm_high_supply;
-+      enum msm_apm_supply     apm_low_supply;
-+      int                     base_volt;
-+      u32                     corner_switch_delay_time;
-+      u32                     cpr_clock_rate;
-+      u32                     sensor_time;
-+      u32                     loop_time;
-+      u32                     up_down_delay_time;
-+      u32                     idle_clocks;
-+      u32                     step_quot_init_min;
-+      u32                     step_quot_init_max;
-+      int                     step_volt;
-+      u32                     down_error_step_limit;
-+      u32                     up_error_step_limit;
-+      enum cpr3_count_mode    count_mode;
-+      u32                     count_repeat;
-+      u32                     proc_clock_throttle;
-+      bool                    cpr_allowed_hw;
-+      bool                    cpr_allowed_sw;
-+      bool                    supports_hw_closed_loop;
-+      bool                    use_hw_closed_loop;
-+      enum cpr_controller_type ctrl_type;
-+      bool                    saw_use_unit_mV;
-+      struct cpr3_corner      aggr_corner;
-+      bool                    cpr_enabled;
-+      bool                    last_corner_was_closed_loop;
-+      bool                    cpr_suspended;
-+      struct dentry           *debugfs;
-+
-+      int                     aging_ref_volt;
-+      unsigned int            aging_vdd_mode;
-+      unsigned int            aging_complete_vdd_mode;
-+      int                     aging_ref_adjust_volt;
-+      bool                    aging_required;
-+      bool                    aging_succeeded;
-+      bool                    aging_failed;
-+      struct cpr3_aging_sensor_info *aging_sensor;
-+      int                     aging_sensor_count;
-+      u32                     cur_sensor_state;
-+      u32                     aging_possible_mask;
-+      u32                     aging_possible_val;
-+
-+      u32                     step_quot_fixed;
-+      u32                     initial_temp_band;
-+      bool                    use_dynamic_step_quot;
-+      bool                    allow_core_count_adj;
-+      bool                    allow_temp_adj;
-+      bool                    allow_boost;
-+      int                     temp_band_count;
-+      int                     *temp_points;
-+      u32                     temp_sensor_id_start;
-+      u32                     temp_sensor_id_end;
-+      u32                     voltage_settling_time;
-+      enum cpr_setting        cpr_global_setting;
-+      struct cpr3_panic_regs_info *panic_regs_info;
-+      struct notifier_block   panic_notifier;
-+};
-+
-+/* Used for rounding voltages to the closest physically available set point. */
-+#define CPR3_ROUND(n, d) (DIV_ROUND_UP(n, d) * (d))
-+
-+#define cpr3_err(cpr3_thread, message, ...) \
-+      pr_err("%s: " message, (cpr3_thread)->name, ##__VA_ARGS__)
-+#define cpr3_info(cpr3_thread, message, ...) \
-+      pr_info("%s: " message, (cpr3_thread)->name, ##__VA_ARGS__)
-+#define cpr3_debug(cpr3_thread, message, ...) \
-+      pr_debug("%s: " message, (cpr3_thread)->name, ##__VA_ARGS__)
-+
-+/*
-+ * Offset subtracted from voltage corner values passed in from the regulator
-+ * framework in order to get internal voltage corner values.  This is needed
-+ * since the regulator framework treats 0 as an error value at regulator
-+ * registration time.
-+ */
-+#define CPR3_CORNER_OFFSET    1
-+
-+#ifdef CONFIG_REGULATOR_CPR3
-+
-+int cpr3_regulator_register(struct platform_device *pdev,
-+                      struct cpr3_controller *ctrl);
-+int cpr3_open_loop_regulator_register(struct platform_device *pdev,
-+                                    struct cpr3_controller *ctrl);
-+int cpr3_regulator_unregister(struct cpr3_controller *ctrl);
-+int cpr3_open_loop_regulator_unregister(struct cpr3_controller *ctrl);
-+int cpr3_regulator_suspend(struct cpr3_controller *ctrl);
-+int cpr3_regulator_resume(struct cpr3_controller *ctrl);
-+
-+int cpr3_allocate_threads(struct cpr3_controller *ctrl, u32 min_thread_id,
-+                      u32 max_thread_id);
-+int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
-+                      struct platform_device *pdev);
-+int cpr3_read_tcsr_setting(struct cpr3_controller *ctrl,
-+                         struct platform_device *pdev, u8 start, u8 end);
-+int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
-+                      const struct cpr3_fuse_param *param, u64 *param_value);
-+int cpr3_convert_open_loop_voltage_fuse(int ref_volt, int step_volt, u32 fuse,
-+                      int fuse_len);
-+u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x);
-+int cpr3_parse_array_property(struct cpr3_regulator *vreg,
-+                      const char *prop_name, int tuple_size, u32 *out);
-+int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
-+                      const char *prop_name, int tuple_size, u32 *out);
-+int cpr3_parse_corner_band_array_property(struct cpr3_regulator *vreg,
-+                      const char *prop_name, int tuple_size, u32 *out);
-+int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg);
-+int cpr3_parse_thread_u32(struct cpr3_thread *thread, const char *propname,
-+                      u32 *out_value, u32 value_min, u32 value_max);
-+int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl, const char *propname,
-+                      u32 *out_value, u32 value_min, u32 value_max);
-+int cpr3_parse_common_thread_data(struct cpr3_thread *thread);
-+int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl);
-+int cpr3_parse_open_loop_common_ctrl_data(struct cpr3_controller *ctrl);
-+int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg);
-+void cpr3_open_loop_voltage_as_ceiling(struct cpr3_regulator *vreg);
-+int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg);
-+void cpr3_print_quots(struct cpr3_regulator *vreg);
-+int cpr3_determine_part_type(struct cpr3_regulator *vreg, int fuse_volt);
-+int cpr3_determine_temp_base_open_loop_correction(struct cpr3_regulator *vreg,
-+                      int *fuse_volt);
-+int cpr3_adjust_fused_open_loop_voltages(struct cpr3_regulator *vreg,
-+                      int *fuse_volt);
-+int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg);
-+int cpr3_quot_adjustment(int ro_scale, int volt_adjust);
-+int cpr3_voltage_adjustment(int ro_scale, int quot_adjust);
-+int cpr3_parse_closed_loop_voltage_adjustments(struct cpr3_regulator *vreg,
-+                      u64 *ro_sel, int *volt_adjust,
-+                      int *volt_adjust_fuse, int *ro_scale);
-+int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg,
-+                      bool use_corner_band);
-+int cpr3_apm_init(struct cpr3_controller *ctrl);
-+int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
-+void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg);
-+void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg);
-+int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
-+                      int *fuse_volt_adjust);
-+int cpr3_handle_temp_open_loop_adjustment(struct cpr3_controller *ctrl,
-+                      bool is_cold);
-+int cpr3_get_cold_temp_threshold(struct cpr3_regulator *vreg, int *cold_temp);
-+bool cpr3_can_adjust_cold_temp(struct cpr3_regulator *vreg);
-+
-+#else
-+
-+static inline int cpr3_regulator_register(struct platform_device *pdev,
-+                      struct cpr3_controller *ctrl)
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int
-+cpr3_open_loop_regulator_register(struct platform_device *pdev,
-+                                struct cpr3_controller *ctrl);
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int cpr3_regulator_unregister(struct cpr3_controller *ctrl)
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int
-+cpr3_open_loop_regulator_unregister(struct cpr3_controller *ctrl)
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int cpr3_regulator_suspend(struct cpr3_controller *ctrl)
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int cpr3_regulator_resume(struct cpr3_controller *ctrl)
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int cpr3_get_thread_name(struct cpr3_thread *thread,
-+                      struct device_node *thread_node)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_allocate_threads(struct cpr3_controller *ctrl,
-+                      u32 min_thread_id, u32 max_thread_id)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
-+                      struct platform_device *pdev)
-+{
-+      return -ENXIO;
-+}
-+
-+static inline int cpr3_read_tcsr_setting(struct cpr3_controller *ctrl,
-+                         struct platform_device *pdev, u8 start, u8 end)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
-+                      const struct cpr3_fuse_param *param, u64 *param_value)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_convert_open_loop_voltage_fuse(int ref_volt,
-+                      int step_volt, u32 fuse, int fuse_len)
-+{
-+      return -EPERM;
-+}
-+
-+static inline u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr3_parse_array_property(struct cpr3_regulator *vreg,
-+                      const char *prop_name, int tuple_size, u32 *out)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
-+                      const char *prop_name, int tuple_size, u32 *out)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_corner_band_array_property(
-+                      struct cpr3_regulator *vreg, const char *prop_name,
-+                      int tuple_size, u32 *out)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_thread_u32(struct cpr3_thread *thread,
-+                      const char *propname, u32 *out_value, u32 value_min,
-+                      u32 value_max)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl,
-+                      const char *propname, u32 *out_value, u32 value_min,
-+                      u32 value_max)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int
-+cpr3_parse_open_loop_common_ctrl_data(struct cpr3_controller *ctrl)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg)
-+{
-+      return -EPERM;
-+}
-+
-+static inline void cpr3_open_loop_voltage_as_ceiling(
-+                      struct cpr3_regulator *vreg)
-+{
-+      return;
-+}
-+
-+static inline int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
-+{
-+      return -EPERM;
-+}
-+
-+static inline void cpr3_print_quots(struct cpr3_regulator *vreg)
-+{
-+      return;
-+}
-+
-+static inline int
-+cpr3_determine_part_type(struct cpr3_regulator *vreg, int fuse_volt)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int
-+cpr3_determine_temp_base_open_loop_correction(struct cpr3_regulator *vreg,
-+                      int *fuse_volt)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_adjust_fused_open_loop_voltages(
-+                      struct cpr3_regulator *vreg, int *fuse_volt)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg)
-+{
-+      return -EPERM;
-+}
-+
-+static inline int cpr3_quot_adjustment(int ro_scale, int volt_adjust)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr3_voltage_adjustment(int ro_scale, int quot_adjust)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr3_parse_closed_loop_voltage_adjustments(
-+                      struct cpr3_regulator *vreg, u64 *ro_sel,
-+                      int *volt_adjust, int *volt_adjust_fuse, int *ro_scale)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr4_parse_core_count_temp_voltage_adj(
-+                      struct cpr3_regulator *vreg, bool use_corner_band)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr3_apm_init(struct cpr3_controller *ctrl)
-+{
-+      return 0;
-+}
-+
-+static inline int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
-+{
-+      return 0;
-+}
-+
-+static inline void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
-+{
-+}
-+
-+static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
-+{
-+}
-+
-+static inline int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
-+                      int *fuse_volt_adjust)
-+{
-+      return 0;
-+}
-+
-+static inline int
-+cpr3_handle_temp_open_loop_adjustment(struct cpr3_controller *ctrl,
-+                      bool is_cold)
-+{
-+      return 0;
-+}
-+
-+static inline bool
-+cpr3_can_adjust_cold_temp(struct cpr3_regulator *vreg)
-+{
-+      return false;
-+}
-+
-+static inline int
-+cpr3_get_cold_temp_threshold(struct cpr3_regulator *vreg, int *cold_temp)
-+{
-+      return 0;
-+}
-+#endif /* CONFIG_REGULATOR_CPR3 */
-+
-+#endif /* __REGULATOR_CPR_REGULATOR_H__ */
---- /dev/null
-+++ b/drivers/regulator/cpr3-util.c
-@@ -0,0 +1,2758 @@
-+/*
-+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+/*
-+ * This file contains utility functions to be used by platform specific CPR3
-+ * regulator drivers.
-+ */
-+
-+#define pr_fmt(fmt) "%s: " fmt, __func__
-+
-+#include <linux/cpumask.h>
-+#include <linux/device.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+
-+#include "cpr3-regulator.h"
-+
-+#define BYTES_PER_FUSE_ROW            8
-+#define MAX_FUSE_ROW_BIT              63
-+
-+#define CPR3_CONSECUTIVE_UP_DOWN_MIN  0
-+#define CPR3_CONSECUTIVE_UP_DOWN_MAX  15
-+#define CPR3_UP_DOWN_THRESHOLD_MIN    0
-+#define CPR3_UP_DOWN_THRESHOLD_MAX    31
-+#define CPR3_STEP_QUOT_MIN            0
-+#define CPR3_STEP_QUOT_MAX            63
-+#define CPR3_IDLE_CLOCKS_MIN          0
-+#define CPR3_IDLE_CLOCKS_MAX          31
-+
-+/* This constant has units of uV/mV so 1000 corresponds to 100%. */
-+#define CPR3_AGING_DERATE_UNITY               1000
-+
-+static inline int read_ipq_soc_version_major(void)
-+{
-+      const int *prop;
-+      prop = of_get_property(of_find_node_by_path("/"), "soc_version_major",
-+                              NULL);
-+
-+      if (!prop)
-+              return -EINVAL;
-+
-+      return le32_to_cpu(*prop);
-+}
-+
-+/**
-+ * cpr3_allocate_regulators() - allocate and initialize CPR3 regulators for a
-+ *            given thread based upon device tree data
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * This function allocates the thread->vreg array based upon the number of
-+ * device tree regulator subnodes.  It also initializes generic elements of each
-+ * regulator struct such as name, of_node, and thread.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_allocate_regulators(struct cpr3_thread *thread)
-+{
-+      struct device_node *node;
-+      int i, rc;
-+
-+      thread->vreg_count = 0;
-+
-+      for_each_available_child_of_node(thread->of_node, node) {
-+              thread->vreg_count++;
-+      }
-+
-+      thread->vreg = devm_kcalloc(thread->ctrl->dev, thread->vreg_count,
-+                      sizeof(*thread->vreg), GFP_KERNEL);
-+      if (!thread->vreg)
-+              return -ENOMEM;
-+
-+      i = 0;
-+      for_each_available_child_of_node(thread->of_node, node) {
-+              thread->vreg[i].of_node = node;
-+              thread->vreg[i].thread = thread;
-+
-+              rc = of_property_read_string(node, "regulator-name",
-+                                              &thread->vreg[i].name);
-+              if (rc) {
-+                      dev_err(thread->ctrl->dev, "could not find regulator name, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              i++;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_allocate_threads() - allocate and initialize CPR3 threads for a given
-+ *                         controller based upon device tree data
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @min_thread_id:    Minimum allowed hardware thread ID for this controller
-+ * @max_thread_id:    Maximum allowed hardware thread ID for this controller
-+ *
-+ * This function allocates the ctrl->thread array based upon the number of
-+ * device tree thread subnodes.  It also initializes generic elements of each
-+ * thread struct such as thread_id, of_node, ctrl, and vreg array.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_allocate_threads(struct cpr3_controller *ctrl, u32 min_thread_id,
-+                      u32 max_thread_id)
-+{
-+      struct device *dev = ctrl->dev;
-+      struct device_node *thread_node;
-+      int i, j, rc;
-+
-+      ctrl->thread_count = 0;
-+
-+      for_each_available_child_of_node(dev->of_node, thread_node) {
-+              ctrl->thread_count++;
-+      }
-+
-+      ctrl->thread = devm_kcalloc(dev, ctrl->thread_count,
-+                      sizeof(*ctrl->thread), GFP_KERNEL);
-+      if (!ctrl->thread)
-+              return -ENOMEM;
-+
-+      i = 0;
-+      for_each_available_child_of_node(dev->of_node, thread_node) {
-+              ctrl->thread[i].of_node = thread_node;
-+              ctrl->thread[i].ctrl = ctrl;
-+
-+              rc = of_property_read_u32(thread_node, "qcom,cpr-thread-id",
-+                                        &ctrl->thread[i].thread_id);
-+              if (rc) {
-+                      dev_err(dev, "could not read DT property qcom,cpr-thread-id, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              if (ctrl->thread[i].thread_id < min_thread_id ||
-+                              ctrl->thread[i].thread_id > max_thread_id) {
-+                      dev_err(dev, "invalid thread id = %u; not within [%u, %u]\n",
-+                              ctrl->thread[i].thread_id, min_thread_id,
-+                              max_thread_id);
-+                      return -EINVAL;
-+              }
-+
-+              /* Verify that the thread ID is unique for all child nodes. */
-+              for (j = 0; j < i; j++) {
-+                      if (ctrl->thread[j].thread_id
-+                                      == ctrl->thread[i].thread_id) {
-+                              dev_err(dev, "duplicate thread id = %u found\n",
-+                                      ctrl->thread[i].thread_id);
-+                              return -EINVAL;
-+                      }
-+              }
-+
-+              rc = cpr3_allocate_regulators(&ctrl->thread[i]);
-+              if (rc)
-+                      return rc;
-+
-+              i++;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_map_fuse_base() - ioremap the base address of the fuse region
-+ * @ctrl:     Pointer to the CPR3 controller
-+ * @pdev:     Platform device pointer for the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
-+                      struct platform_device *pdev)
-+{
-+      struct resource *res;
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fuse_base");
-+      if (!res || !res->start) {
-+              dev_err(&pdev->dev, "fuse base address is missing\n");
-+              return -ENXIO;
-+      }
-+
-+      ctrl->fuse_base = devm_ioremap(&pdev->dev, res->start,
-+                                              resource_size(res));
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_read_tcsr_setting - reads the CPR setting bits from TCSR register
-+ * @ctrl:     Pointer to the CPR3 controller
-+ * @pdev:     Platform device pointer for the CPR3 controller
-+ * @start:    start bit in TCSR register
-+ * @end:      end bit in TCSR register
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_read_tcsr_setting(struct cpr3_controller *ctrl,
-+                         struct platform_device *pdev, u8 start, u8 end)
-+{
-+      struct resource *res;
-+      void __iomem *tcsr_reg;
-+      u32 val;
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-+                                         "cpr_tcsr_reg");
-+      if (!res || !res->start)
-+              return 0;
-+
-+      tcsr_reg = ioremap(res->start, resource_size(res));
-+      if (!tcsr_reg) {
-+              dev_err(&pdev->dev, "tcsr ioremap failed\n");
-+              return 0;
-+      }
-+
-+      val = readl_relaxed(tcsr_reg);
-+      val &= GENMASK(end, start);
-+      val >>= start;
-+
-+      switch (val) {
-+      case 1:
-+              ctrl->cpr_global_setting = CPR_DISABLED;
-+              break;
-+      case 2:
-+              ctrl->cpr_global_setting = CPR_OPEN_LOOP_EN;
-+              break;
-+      case 3:
-+              ctrl->cpr_global_setting = CPR_CLOSED_LOOP_EN;
-+              break;
-+      default:
-+              ctrl->cpr_global_setting = CPR_DEFAULT;
-+      }
-+
-+      iounmap(tcsr_reg);
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_read_fuse_param() - reads a CPR3 fuse parameter out of eFuses
-+ * @fuse_base_addr:   Virtual memory address of the eFuse base address
-+ * @param:            Null terminated array of fuse param segments to read
-+ *                    from
-+ * @param_value:      Output with value read from the eFuses
-+ *
-+ * This function reads from each of the parameter segments listed in the param
-+ * array and concatenates their values together.  Reading stops when an element
-+ * is reached which has all 0 struct values.  The total number of bits specified
-+ * for the fuse parameter across all segments must be less than or equal to 64.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
-+              const struct cpr3_fuse_param *param, u64 *param_value)
-+{
-+      u64 fuse_val, val;
-+      int bits;
-+      int bits_total = 0;
-+
-+      *param_value = 0;
-+
-+      while (param->row || param->bit_start || param->bit_end) {
-+              if (param->bit_start > param->bit_end
-+                  || param->bit_end > MAX_FUSE_ROW_BIT) {
-+                      pr_err("Invalid fuse parameter segment: row=%u, start=%u, end=%u\n",
-+                              param->row, param->bit_start, param->bit_end);
-+                      return -EINVAL;
-+              }
-+
-+              bits = param->bit_end - param->bit_start + 1;
-+              if (bits_total + bits > 64) {
-+                      pr_err("Invalid fuse parameter segments; total bits = %d\n",
-+                              bits_total + bits);
-+                      return -EINVAL;
-+              }
-+
-+              fuse_val = readq_relaxed(fuse_base_addr
-+                                       + param->row * BYTES_PER_FUSE_ROW);
-+              val = (fuse_val >> param->bit_start) & ((1ULL << bits) - 1);
-+              *param_value |= val << bits_total;
-+              bits_total += bits;
-+
-+              param++;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_convert_open_loop_voltage_fuse() - converts an open loop voltage fuse
-+ *            value into an absolute voltage with units of microvolts
-+ * @ref_volt:         Reference voltage in microvolts
-+ * @step_volt:                The step size in microvolts of the fuse LSB
-+ * @fuse:             Open loop voltage fuse value
-+ * @fuse_len:         The bit length of the fuse value
-+ *
-+ * The MSB of the fuse parameter corresponds to a sign bit.  If it is set, then
-+ * the lower bits correspond to the number of steps to go down from the
-+ * reference voltage.  If it is not set, then the lower bits correspond to the
-+ * number of steps to go up from the reference voltage.
-+ */
-+int cpr3_convert_open_loop_voltage_fuse(int ref_volt, int step_volt, u32 fuse,
-+                                      int fuse_len)
-+{
-+      int sign, steps;
-+
-+      sign = (fuse & (1 << (fuse_len - 1))) ? -1 : 1;
-+      steps = fuse & ((1 << (fuse_len - 1)) - 1);
-+
-+      return ref_volt + sign * steps * step_volt;
-+}
-+
-+/**
-+ * cpr3_interpolate() - performs linear interpolation
-+ * @x1                Lower known x value
-+ * @y1                Lower known y value
-+ * @x2                Upper known x value
-+ * @y2                Upper known y value
-+ * @x         Intermediate x value
-+ *
-+ * Returns y where (x, y) falls on the line between (x1, y1) and (x2, y2).
-+ * It is required that x1 < x2, y1 <= y2, and x1 <= x <= x2.  If these
-+ * conditions are not met, then y2 will be returned.
-+ */
-+u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x)
-+{
-+      u64 temp;
-+
-+      if (x1 >= x2 || y1 > y2 || x1 > x || x > x2)
-+              return y2;
-+
-+      temp = (x2 - x) * (y2 - y1);
-+      do_div(temp, (u32)(x2 - x1));
-+
-+      return y2 - temp;
-+}
-+
-+/**
-+ * cpr3_parse_array_property() - fill an array from a portion of the values
-+ *            specified for a device tree property
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @prop_name:                The name of the device tree property to read from
-+ * @tuple_size:               The number of elements in each tuple
-+ * @out:              Output data array which must be of size tuple_size
-+ *
-+ * cpr3_parse_common_corner_data() must be called for vreg before this function
-+ * is called so that fuse combo and speed bin size elements are initialized.
-+ *
-+ * Three formats are supported for the device tree property:
-+ * 1. Length == tuple_size
-+ *    (reading begins at index 0)
-+ * 2. Length == tuple_size * vreg->fuse_combos_supported
-+ *    (reading begins at index tuple_size * vreg->fuse_combo)
-+ * 3. Length == tuple_size * vreg->speed_bins_supported
-+ *    (reading begins at index tuple_size * vreg->speed_bin_fuse)
-+ *
-+ * All other property lengths are treated as errors.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_array_property(struct cpr3_regulator *vreg,
-+              const char *prop_name, int tuple_size, u32 *out)
-+{
-+      struct device_node *node = vreg->of_node;
-+      int len = 0;
-+      int i, offset, rc;
-+
-+      if (!of_find_property(node, prop_name, &len)) {
-+              cpr3_err(vreg, "property %s is missing\n", prop_name);
-+              return -EINVAL;
-+      }
-+
-+      if (len == tuple_size * sizeof(u32)) {
-+              offset = 0;
-+      } else if (len == tuple_size * vreg->fuse_combos_supported
-+                                   * sizeof(u32)) {
-+              offset = tuple_size * vreg->fuse_combo;
-+      } else if (vreg->speed_bins_supported > 0 &&
-+               len == tuple_size * vreg->speed_bins_supported * sizeof(u32)) {
-+              offset = tuple_size * vreg->speed_bin_fuse;
-+      } else {
-+              if (vreg->speed_bins_supported > 0)
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
-+                              prop_name, len,
-+                              tuple_size * sizeof(u32),
-+                              tuple_size * vreg->speed_bins_supported
-+                                         * sizeof(u32),
-+                              tuple_size * vreg->fuse_combos_supported
-+                                         * sizeof(u32));
-+              else
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
-+                              prop_name, len,
-+                              tuple_size * sizeof(u32),
-+                              tuple_size * vreg->fuse_combos_supported
-+                                         * sizeof(u32));
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < tuple_size; i++) {
-+              rc = of_property_read_u32_index(node, prop_name, offset + i,
-+                                              &out[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading property %s, rc=%d\n",
-+                              prop_name, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_parse_corner_array_property() - fill a per-corner array from a portion
-+ *            of the values specified for a device tree property
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @prop_name:                The name of the device tree property to read from
-+ * @tuple_size:               The number of elements in each per-corner tuple
-+ * @out:              Output data array which must be of size:
-+ *                    tuple_size * vreg->corner_count
-+ *
-+ * cpr3_parse_common_corner_data() must be called for vreg before this function
-+ * is called so that fuse combo and speed bin size elements are initialized.
-+ *
-+ * Three formats are supported for the device tree property:
-+ * 1. Length == tuple_size * vreg->corner_count
-+ *    (reading begins at index 0)
-+ * 2. Length == tuple_size * vreg->fuse_combo_corner_sum
-+ *    (reading begins at index tuple_size * vreg->fuse_combo_offset)
-+ * 3. Length == tuple_size * vreg->speed_bin_corner_sum
-+ *    (reading begins at index tuple_size * vreg->speed_bin_offset)
-+ *
-+ * All other property lengths are treated as errors.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
-+              const char *prop_name, int tuple_size, u32 *out)
-+{
-+      struct device_node *node = vreg->of_node;
-+      int len = 0;
-+      int i, offset, rc;
-+
-+      if (!of_find_property(node, prop_name, &len)) {
-+              cpr3_err(vreg, "property %s is missing\n", prop_name);
-+              return -EINVAL;
-+      }
-+
-+      if (len == tuple_size * vreg->corner_count * sizeof(u32)) {
-+              offset = 0;
-+      } else if (len == tuple_size * vreg->fuse_combo_corner_sum
-+                                   * sizeof(u32)) {
-+              offset = tuple_size * vreg->fuse_combo_offset;
-+      } else if (vreg->speed_bin_corner_sum > 0 &&
-+               len == tuple_size * vreg->speed_bin_corner_sum * sizeof(u32)) {
-+              offset = tuple_size * vreg->speed_bin_offset;
-+      } else {
-+              if (vreg->speed_bin_corner_sum > 0)
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
-+                              prop_name, len,
-+                              tuple_size * vreg->corner_count * sizeof(u32),
-+                              tuple_size * vreg->speed_bin_corner_sum
-+                                         * sizeof(u32),
-+                              tuple_size * vreg->fuse_combo_corner_sum
-+                                         * sizeof(u32));
-+              else
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
-+                              prop_name, len,
-+                              tuple_size * vreg->corner_count * sizeof(u32),
-+                              tuple_size * vreg->fuse_combo_corner_sum
-+                                         * sizeof(u32));
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < tuple_size * vreg->corner_count; i++) {
-+              rc = of_property_read_u32_index(node, prop_name, offset + i,
-+                                              &out[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading property %s, rc=%d\n",
-+                              prop_name, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_parse_corner_band_array_property() - fill a per-corner band array
-+ *            from a portion of the values specified for a device tree
-+ *            property
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @prop_name:                The name of the device tree property to read from
-+ * @tuple_size:               The number of elements in each per-corner band tuple
-+ * @out:              Output data array which must be of size:
-+ *                    tuple_size * vreg->corner_band_count
-+ *
-+ * cpr3_parse_common_corner_data() must be called for vreg before this function
-+ * is called so that fuse combo and speed bin size elements are initialized.
-+ * In addition, corner band fuse combo and speed bin sum and offset elements
-+ * must be initialized prior to executing this function.
-+ *
-+ * Three formats are supported for the device tree property:
-+ * 1. Length == tuple_size * vreg->corner_band_count
-+ *    (reading begins at index 0)
-+ * 2. Length == tuple_size * vreg->fuse_combo_corner_band_sum
-+ *    (reading begins at index tuple_size *
-+ *            vreg->fuse_combo_corner_band_offset)
-+ * 3. Length == tuple_size * vreg->speed_bin_corner_band_sum
-+ *    (reading begins at index tuple_size *
-+ *            vreg->speed_bin_corner_band_offset)
-+ *
-+ * All other property lengths are treated as errors.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_corner_band_array_property(struct cpr3_regulator *vreg,
-+              const char *prop_name, int tuple_size, u32 *out)
-+{
-+      struct device_node *node = vreg->of_node;
-+      int len = 0;
-+      int i, offset, rc;
-+
-+      if (!of_find_property(node, prop_name, &len)) {
-+              cpr3_err(vreg, "property %s is missing\n", prop_name);
-+              return -EINVAL;
-+      }
-+
-+      if (len == tuple_size * vreg->corner_band_count * sizeof(u32)) {
-+              offset = 0;
-+      } else if (len == tuple_size * vreg->fuse_combo_corner_band_sum
-+                                   * sizeof(u32)) {
-+              offset = tuple_size * vreg->fuse_combo_corner_band_offset;
-+      } else if (vreg->speed_bin_corner_band_sum > 0 &&
-+               len == tuple_size * vreg->speed_bin_corner_band_sum *
-+                 sizeof(u32)) {
-+              offset = tuple_size * vreg->speed_bin_corner_band_offset;
-+      } else {
-+              if (vreg->speed_bin_corner_band_sum > 0)
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
-+                              prop_name, len,
-+                              tuple_size * vreg->corner_band_count *
-+                               sizeof(u32),
-+                              tuple_size * vreg->speed_bin_corner_band_sum
-+                                         * sizeof(u32),
-+                              tuple_size * vreg->fuse_combo_corner_band_sum
-+                                         * sizeof(u32));
-+              else
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
-+                              prop_name, len,
-+                              tuple_size * vreg->corner_band_count *
-+                               sizeof(u32),
-+                              tuple_size * vreg->fuse_combo_corner_band_sum
-+                                         * sizeof(u32));
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < tuple_size * vreg->corner_band_count; i++) {
-+              rc = of_property_read_u32_index(node, prop_name, offset + i,
-+                                              &out[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading property %s, rc=%d\n",
-+                              prop_name, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_parse_common_corner_data() - parse common CPR3 properties relating to
-+ *            the corners supported by a CPR3 regulator from device tree
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function reads, validates, and utilizes the following device tree
-+ * properties: qcom,cpr-fuse-corners, qcom,cpr-fuse-combos, qcom,cpr-speed-bins,
-+ * qcom,cpr-speed-bin-corners, qcom,cpr-corners, qcom,cpr-voltage-ceiling,
-+ * qcom,cpr-voltage-floor, qcom,corner-frequencies,
-+ * and qcom,cpr-corner-fmax-map.
-+ *
-+ * It initializes these CPR3 regulator elements: corner, corner_count,
-+ * fuse_combos_supported, fuse_corner_map, and speed_bins_supported.  It
-+ * initializes these elements for each corner: ceiling_volt, floor_volt,
-+ * proc_freq, and cpr_fuse_corner.
-+ *
-+ * It requires that the following CPR3 regulator elements be initialized before
-+ * being called: fuse_corner_count, fuse_combo, and speed_bin_fuse.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
-+{
-+      struct device_node *node = vreg->of_node;
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      u32 max_fuse_combos, fuse_corners, aging_allowed = 0;
-+      u32 max_speed_bins = 0;
-+      u32 *combo_corners;
-+      u32 *speed_bin_corners;
-+      u32 *temp;
-+      int i, j, rc;
-+
-+      rc = of_property_read_u32(node, "qcom,cpr-fuse-corners", &fuse_corners);
-+      if (rc) {
-+              cpr3_err(vreg, "error reading property qcom,cpr-fuse-corners, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      if (vreg->fuse_corner_count != fuse_corners) {
-+              cpr3_err(vreg, "device tree config supports %d fuse corners but the hardware has %d fuse corners\n",
-+                      fuse_corners, vreg->fuse_corner_count);
-+              return -EINVAL;
-+      }
-+
-+      rc = of_property_read_u32(node, "qcom,cpr-fuse-combos",
-+                              &max_fuse_combos);
-+      if (rc) {
-+              cpr3_err(vreg, "error reading property qcom,cpr-fuse-combos, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      /*
-+       * Sanity check against arbitrarily large value to avoid excessive
-+       * memory allocation.
-+       */
-+      if (max_fuse_combos > 100 || max_fuse_combos == 0) {
-+              cpr3_err(vreg, "qcom,cpr-fuse-combos is invalid: %u\n",
-+                      max_fuse_combos);
-+              return -EINVAL;
-+      }
-+
-+      if (vreg->fuse_combo >= max_fuse_combos) {
-+              cpr3_err(vreg, "device tree config supports fuse combos 0-%u but the hardware has combo %d\n",
-+                      max_fuse_combos - 1, vreg->fuse_combo);
-+              BUG_ON(1);
-+              return -EINVAL;
-+      }
-+
-+      vreg->fuse_combos_supported = max_fuse_combos;
-+
-+      of_property_read_u32(node, "qcom,cpr-speed-bins", &max_speed_bins);
-+
-+      /*
-+       * Sanity check against arbitrarily large value to avoid excessive
-+       * memory allocation.
-+       */
-+      if (max_speed_bins > 100) {
-+              cpr3_err(vreg, "qcom,cpr-speed-bins is invalid: %u\n",
-+                      max_speed_bins);
-+              return -EINVAL;
-+      }
-+
-+      if (max_speed_bins && vreg->speed_bin_fuse >= max_speed_bins) {
-+              cpr3_err(vreg, "device tree config supports speed bins 0-%u but the hardware has speed bin %d\n",
-+                      max_speed_bins - 1, vreg->speed_bin_fuse);
-+              BUG();
-+              return -EINVAL;
-+      }
-+
-+      vreg->speed_bins_supported = max_speed_bins;
-+
-+      combo_corners = kcalloc(vreg->fuse_combos_supported,
-+                              sizeof(*combo_corners), GFP_KERNEL);
-+      if (!combo_corners)
-+              return -ENOMEM;
-+
-+      rc = of_property_read_u32_array(node, "qcom,cpr-corners", combo_corners,
-+                                      vreg->fuse_combos_supported);
-+      if (rc == -EOVERFLOW) {
-+              /* Single value case */
-+              rc = of_property_read_u32(node, "qcom,cpr-corners",
-+                                      combo_corners);
-+              for (i = 1; i < vreg->fuse_combos_supported; i++)
-+                      combo_corners[i] = combo_corners[0];
-+      }
-+      if (rc) {
-+              cpr3_err(vreg, "error reading property qcom,cpr-corners, rc=%d\n",
-+                      rc);
-+              kfree(combo_corners);
-+              return rc;
-+      }
-+
-+      vreg->fuse_combo_offset = 0;
-+      vreg->fuse_combo_corner_sum = 0;
-+      for (i = 0; i < vreg->fuse_combos_supported; i++) {
-+              vreg->fuse_combo_corner_sum += combo_corners[i];
-+              if (i < vreg->fuse_combo)
-+                      vreg->fuse_combo_offset += combo_corners[i];
-+      }
-+
-+      vreg->corner_count = combo_corners[vreg->fuse_combo];
-+
-+      kfree(combo_corners);
-+
-+      vreg->speed_bin_offset = 0;
-+      vreg->speed_bin_corner_sum = 0;
-+      if (vreg->speed_bins_supported > 0) {
-+              speed_bin_corners = kcalloc(vreg->speed_bins_supported,
-+                                      sizeof(*speed_bin_corners), GFP_KERNEL);
-+              if (!speed_bin_corners)
-+                      return -ENOMEM;
-+
-+              rc = of_property_read_u32_array(node,
-+                              "qcom,cpr-speed-bin-corners", speed_bin_corners,
-+                              vreg->speed_bins_supported);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading property qcom,cpr-speed-bin-corners, rc=%d\n",
-+                              rc);
-+                      kfree(speed_bin_corners);
-+                      return rc;
-+              }
-+
-+              for (i = 0; i < vreg->speed_bins_supported; i++) {
-+                      vreg->speed_bin_corner_sum += speed_bin_corners[i];
-+                      if (i < vreg->speed_bin_fuse)
-+                              vreg->speed_bin_offset += speed_bin_corners[i];
-+              }
-+
-+              if (speed_bin_corners[vreg->speed_bin_fuse]
-+                  != vreg->corner_count) {
-+                      cpr3_err(vreg, "qcom,cpr-corners and qcom,cpr-speed-bin-corners conflict on number of corners: %d vs %u\n",
-+                              vreg->corner_count,
-+                              speed_bin_corners[vreg->speed_bin_fuse]);
-+                      kfree(speed_bin_corners);
-+                      return -EINVAL;
-+              }
-+
-+              kfree(speed_bin_corners);
-+      }
-+
-+      vreg->corner = devm_kcalloc(ctrl->dev, vreg->corner_count,
-+                                  sizeof(*vreg->corner), GFP_KERNEL);
-+      temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
-+      if (!vreg->corner || !temp)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-ceiling",
-+                      1, temp);
-+      if (rc)
-+              goto free_temp;
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              vreg->corner[i].ceiling_volt
-+                      = CPR3_ROUND(temp[i], ctrl->step_volt);
-+              vreg->corner[i].abs_ceiling_volt = vreg->corner[i].ceiling_volt;
-+      }
-+
-+      rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-floor",
-+                      1, temp);
-+      if (rc)
-+              goto free_temp;
-+      for (i = 0; i < vreg->corner_count; i++)
-+              vreg->corner[i].floor_volt
-+                      = CPR3_ROUND(temp[i], ctrl->step_volt);
-+
-+      /* Validate ceiling and floor values */
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              if (vreg->corner[i].floor_volt
-+                  > vreg->corner[i].ceiling_volt) {
-+                      cpr3_err(vreg, "CPR floor[%d]=%d > ceiling[%d]=%d uV\n",
-+                              i, vreg->corner[i].floor_volt,
-+                              i, vreg->corner[i].ceiling_volt);
-+                      rc = -EINVAL;
-+                      goto free_temp;
-+              }
-+      }
-+
-+      /* Load optional system-supply voltages */
-+      if (of_property_present(vreg->of_node, "qcom,system-voltage")) {
-+              rc = cpr3_parse_corner_array_property(vreg,
-+                      "qcom,system-voltage", 1, temp);
-+              if (rc)
-+                      goto free_temp;
-+              for (i = 0; i < vreg->corner_count; i++)
-+                      vreg->corner[i].system_volt = temp[i];
-+      }
-+
-+      rc = cpr3_parse_corner_array_property(vreg, "qcom,corner-frequencies",
-+                      1, temp);
-+      if (rc)
-+              goto free_temp;
-+      for (i = 0; i < vreg->corner_count; i++)
-+              vreg->corner[i].proc_freq = temp[i];
-+
-+      /* Validate frequencies */
-+      for (i = 1; i < vreg->corner_count; i++) {
-+              if (vreg->corner[i].proc_freq
-+                  < vreg->corner[i - 1].proc_freq) {
-+                      cpr3_err(vreg, "invalid frequency: freq[%d]=%u < freq[%d]=%u\n",
-+                              i, vreg->corner[i].proc_freq, i - 1,
-+                              vreg->corner[i - 1].proc_freq);
-+                      rc = -EINVAL;
-+                      goto free_temp;
-+              }
-+      }
-+
-+      vreg->fuse_corner_map = devm_kcalloc(ctrl->dev, vreg->fuse_corner_count,
-+                                  sizeof(*vreg->fuse_corner_map), GFP_KERNEL);
-+      if (!vreg->fuse_corner_map) {
-+              rc = -ENOMEM;
-+              goto free_temp;
-+      }
-+
-+      rc = cpr3_parse_array_property(vreg, "qcom,cpr-corner-fmax-map",
-+              vreg->fuse_corner_count, temp);
-+      if (rc)
-+              goto free_temp;
-+      for (i = 0; i < vreg->fuse_corner_count; i++) {
-+              vreg->fuse_corner_map[i] = temp[i] - CPR3_CORNER_OFFSET;
-+              if (temp[i] < CPR3_CORNER_OFFSET
-+                  || temp[i] > vreg->corner_count + CPR3_CORNER_OFFSET) {
-+                      cpr3_err(vreg, "invalid corner value specified in qcom,cpr-corner-fmax-map: %u\n",
-+                              temp[i]);
-+                      rc = -EINVAL;
-+                      goto free_temp;
-+              } else if (i > 0 && temp[i - 1] >= temp[i]) {
-+                      cpr3_err(vreg, "invalid corner %u less than or equal to previous corner %u\n",
-+                              temp[i], temp[i - 1]);
-+                      rc = -EINVAL;
-+                      goto free_temp;
-+              }
-+      }
-+      if (temp[vreg->fuse_corner_count - 1] != vreg->corner_count)
-+              cpr3_debug(vreg, "Note: highest Fmax corner %u in qcom,cpr-corner-fmax-map does not match highest supported corner %d\n",
-+                      temp[vreg->fuse_corner_count - 1],
-+                      vreg->corner_count);
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              for (j = 0; j < vreg->fuse_corner_count; j++) {
-+                      if (i + CPR3_CORNER_OFFSET <= temp[j]) {
-+                              vreg->corner[i].cpr_fuse_corner = j;
-+                              break;
-+                      }
-+              }
-+              if (j == vreg->fuse_corner_count) {
-+                      /*
-+                       * Handle the case where the highest fuse corner maps
-+                       * to a corner below the highest corner.
-+                       */
-+                      vreg->corner[i].cpr_fuse_corner
-+                              = vreg->fuse_corner_count - 1;
-+              }
-+      }
-+
-+      if (of_property_present(vreg->of_node,
-+                              "qcom,allow-aging-voltage-adjustment")) {
-+              rc = cpr3_parse_array_property(vreg,
-+                      "qcom,allow-aging-voltage-adjustment",
-+                      1, &aging_allowed);
-+              if (rc)
-+                      goto free_temp;
-+
-+              vreg->aging_allowed = aging_allowed;
-+      }
-+
-+      if (of_property_present(vreg->of_node,
-+                     "qcom,allow-aging-open-loop-voltage-adjustment")) {
-+              rc = cpr3_parse_array_property(vreg,
-+                      "qcom,allow-aging-open-loop-voltage-adjustment",
-+                      1, &aging_allowed);
-+              if (rc)
-+                      goto free_temp;
-+
-+              vreg->aging_allow_open_loop_adj = aging_allowed;
-+      }
-+
-+      if (vreg->aging_allowed) {
-+              if (ctrl->aging_ref_volt <= 0) {
-+                      cpr3_err(ctrl, "qcom,cpr-aging-ref-voltage must be specified\n");
-+                      rc = -EINVAL;
-+                      goto free_temp;
-+              }
-+
-+              rc = cpr3_parse_array_property(vreg,
-+                      "qcom,cpr-aging-max-voltage-adjustment",
-+                      1, &vreg->aging_max_adjust_volt);
-+              if (rc)
-+                      goto free_temp;
-+
-+              rc = cpr3_parse_array_property(vreg,
-+                      "qcom,cpr-aging-ref-corner", 1, &vreg->aging_corner);
-+              if (rc) {
-+                      goto free_temp;
-+              } else if (vreg->aging_corner < CPR3_CORNER_OFFSET
-+                         || vreg->aging_corner > vreg->corner_count - 1
-+                                                      + CPR3_CORNER_OFFSET) {
-+                      cpr3_err(vreg, "aging reference corner=%d not in range [%d, %d]\n",
-+                              vreg->aging_corner, CPR3_CORNER_OFFSET,
-+                              vreg->corner_count - 1 + CPR3_CORNER_OFFSET);
-+                      rc = -EINVAL;
-+                      goto free_temp;
-+              }
-+              vreg->aging_corner -= CPR3_CORNER_OFFSET;
-+
-+              if (of_property_present(vreg->of_node, "qcom,cpr-aging-derate")) {
-+                      rc = cpr3_parse_corner_array_property(vreg,
-+                              "qcom,cpr-aging-derate", 1, temp);
-+                      if (rc)
-+                              goto free_temp;
-+
-+                      for (i = 0; i < vreg->corner_count; i++)
-+                              vreg->corner[i].aging_derate = temp[i];
-+              } else {
-+                      for (i = 0; i < vreg->corner_count; i++)
-+                              vreg->corner[i].aging_derate
-+                                      = CPR3_AGING_DERATE_UNITY;
-+              }
-+      }
-+
-+free_temp:
-+      kfree(temp);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_parse_thread_u32() - parse the specified property from the CPR3 thread's
-+ *            device tree node and verify that it is within the allowed limits
-+ * @thread:           Pointer to the CPR3 thread
-+ * @propname:         The name of the device tree property to read
-+ * @out_value:                The output pointer to fill with the value read
-+ * @value_min:                The minimum allowed property value
-+ * @value_max:                The maximum allowed property value
-+ *
-+ * This function prints a verbose error message if the property is missing or
-+ * has a value which is not within the specified range.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_thread_u32(struct cpr3_thread *thread, const char *propname,
-+                     u32 *out_value, u32 value_min, u32 value_max)
-+{
-+      int rc;
-+
-+      rc = of_property_read_u32(thread->of_node, propname, out_value);
-+      if (rc) {
-+              cpr3_err(thread->ctrl, "thread %u error reading property %s, rc=%d\n",
-+                      thread->thread_id, propname, rc);
-+              return rc;
-+      }
-+
-+      if (*out_value < value_min || *out_value > value_max) {
-+              cpr3_err(thread->ctrl, "thread %u %s=%u is invalid; allowed range: [%u, %u]\n",
-+                      thread->thread_id, propname, *out_value, value_min,
-+                      value_max);
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_parse_ctrl_u32() - parse the specified property from the CPR3
-+ *            controller's device tree node and verify that it is within the
-+ *            allowed limits
-+ * @ctrl:             Pointer to the CPR3 controller
-+ * @propname:         The name of the device tree property to read
-+ * @out_value:                The output pointer to fill with the value read
-+ * @value_min:                The minimum allowed property value
-+ * @value_max:                The maximum allowed property value
-+ *
-+ * This function prints a verbose error message if the property is missing or
-+ * has a value which is not within the specified range.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl, const char *propname,
-+                     u32 *out_value, u32 value_min, u32 value_max)
-+{
-+      int rc;
-+
-+      rc = of_property_read_u32(ctrl->dev->of_node, propname, out_value);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading property %s, rc=%d\n",
-+                      propname, rc);
-+              return rc;
-+      }
-+
-+      if (*out_value < value_min || *out_value > value_max) {
-+              cpr3_err(ctrl, "%s=%u is invalid; allowed range: [%u, %u]\n",
-+                      propname, *out_value, value_min, value_max);
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_parse_common_thread_data() - parse common CPR3 thread properties from
-+ *            device tree
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_thread_u32(thread, "qcom,cpr-consecutive-up",
-+                      &thread->consecutive_up, CPR3_CONSECUTIVE_UP_DOWN_MIN,
-+                      CPR3_CONSECUTIVE_UP_DOWN_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_thread_u32(thread, "qcom,cpr-consecutive-down",
-+                      &thread->consecutive_down, CPR3_CONSECUTIVE_UP_DOWN_MIN,
-+                      CPR3_CONSECUTIVE_UP_DOWN_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_thread_u32(thread, "qcom,cpr-up-threshold",
-+                      &thread->up_threshold, CPR3_UP_DOWN_THRESHOLD_MIN,
-+                      CPR3_UP_DOWN_THRESHOLD_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_thread_u32(thread, "qcom,cpr-down-threshold",
-+                      &thread->down_threshold, CPR3_UP_DOWN_THRESHOLD_MIN,
-+                      CPR3_UP_DOWN_THRESHOLD_MAX);
-+      if (rc)
-+              return rc;
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_parse_irq_affinity() - parse CPR IRQ affinity information
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_parse_irq_affinity(struct cpr3_controller *ctrl)
-+{
-+      struct device_node *cpu_node;
-+      int i, cpu;
-+      int len = 0;
-+
-+      if (!of_find_property(ctrl->dev->of_node, "qcom,cpr-interrupt-affinity",
-+                            &len)) {
-+              /* No IRQ affinity required */
-+              return 0;
-+      }
-+
-+      len /= sizeof(u32);
-+
-+      for (i = 0; i < len; i++) {
-+              cpu_node = of_parse_phandle(ctrl->dev->of_node,
-+                                          "qcom,cpr-interrupt-affinity", i);
-+              if (!cpu_node) {
-+                      cpr3_err(ctrl, "could not find CPU node %d\n", i);
-+                      return -EINVAL;
-+              }
-+
-+              for_each_possible_cpu(cpu) {
-+                      if (of_get_cpu_node(cpu, NULL) == cpu_node) {
-+                              cpumask_set_cpu(cpu, &ctrl->irq_affinity_mask);
-+                              break;
-+                      }
-+              }
-+              of_node_put(cpu_node);
-+      }
-+
-+      return 0;
-+}
-+
-+static int cpr3_panic_notifier_init(struct cpr3_controller *ctrl)
-+{
-+      struct device_node *node = ctrl->dev->of_node;
-+      struct cpr3_panic_regs_info *panic_regs_info;
-+      struct cpr3_reg_info *regs;
-+      int i, reg_count, len, rc = 0;
-+
-+      if (!of_find_property(node, "qcom,cpr-panic-reg-addr-list", &len)) {
-+              /* panic register address list not specified */
-+              return rc;
-+      }
-+
-+      reg_count = len / sizeof(u32);
-+      if (!reg_count) {
-+              cpr3_err(ctrl, "qcom,cpr-panic-reg-addr-list has invalid len = %d\n",
-+                      len);
-+              return -EINVAL;
-+      }
-+
-+      if (!of_property_present(node, "qcom,cpr-panic-reg-name-list")) {
-+              cpr3_err(ctrl, "property qcom,cpr-panic-reg-name-list not specified\n");
-+              return -EINVAL;
-+      }
-+
-+      len = of_property_count_strings(node, "qcom,cpr-panic-reg-name-list");
-+      if (reg_count != len) {
-+              cpr3_err(ctrl, "qcom,cpr-panic-reg-name-list should have %d strings\n",
-+                      reg_count);
-+              return -EINVAL;
-+      }
-+
-+      panic_regs_info = devm_kzalloc(ctrl->dev, sizeof(*panic_regs_info),
-+                                      GFP_KERNEL);
-+      if (!panic_regs_info)
-+              return -ENOMEM;
-+
-+      regs = devm_kcalloc(ctrl->dev, reg_count, sizeof(*regs), GFP_KERNEL);
-+      if (!regs)
-+              return -ENOMEM;
-+
-+      for (i = 0; i < reg_count; i++) {
-+              rc = of_property_read_string_index(node,
-+                              "qcom,cpr-panic-reg-name-list", i,
-+                              &(regs[i].name));
-+              if (rc) {
-+                      cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-name-list, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              rc = of_property_read_u32_index(node,
-+                              "qcom,cpr-panic-reg-addr-list", i,
-+                              &(regs[i].addr));
-+              if (rc) {
-+                      cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-addr-list, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+              regs[i].virt_addr = devm_ioremap(ctrl->dev, regs[i].addr, 0x4);
-+              if (!regs[i].virt_addr) {
-+                      pr_err("Unable to map panic register addr 0x%08x\n",
-+                              regs[i].addr);
-+                      return -EINVAL;
-+              }
-+              regs[i].value = 0xFFFFFFFF;
-+      }
-+
-+      panic_regs_info->reg_count = reg_count;
-+      panic_regs_info->regs = regs;
-+      ctrl->panic_regs_info = panic_regs_info;
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from
-+ *            device tree
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-sensor-time",
-+                      &ctrl->sensor_time, 0, UINT_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-loop-time",
-+                      &ctrl->loop_time, 0, UINT_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-idle-cycles",
-+                      &ctrl->idle_clocks, CPR3_IDLE_CLOCKS_MIN,
-+                      CPR3_IDLE_CLOCKS_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-step-quot-init-min",
-+                      &ctrl->step_quot_init_min, CPR3_STEP_QUOT_MIN,
-+                      CPR3_STEP_QUOT_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-step-quot-init-max",
-+                      &ctrl->step_quot_init_max, CPR3_STEP_QUOT_MIN,
-+                      CPR3_STEP_QUOT_MAX);
-+      if (rc)
-+              return rc;
-+
-+      rc = of_property_read_u32(ctrl->dev->of_node, "qcom,voltage-step",
-+                              &ctrl->step_volt);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading property qcom,voltage-step, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+      if (ctrl->step_volt <= 0) {
-+              cpr3_err(ctrl, "qcom,voltage-step=%d is invalid\n",
-+                      ctrl->step_volt);
-+              return -EINVAL;
-+      }
-+
-+      rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-count-mode",
-+                      &ctrl->count_mode, CPR3_COUNT_MODE_ALL_AT_ONCE_MIN,
-+                      CPR3_COUNT_MODE_STAGGERED);
-+      if (rc)
-+              return rc;
-+
-+      /* Count repeat is optional */
-+      ctrl->count_repeat = 0;
-+      of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-count-repeat",
-+                      &ctrl->count_repeat);
-+
-+      ctrl->cpr_allowed_sw =
-+              of_property_read_bool(ctrl->dev->of_node, "qcom,cpr-enable") ||
-+              ctrl->cpr_global_setting == CPR_CLOSED_LOOP_EN;
-+
-+      rc = cpr3_parse_irq_affinity(ctrl);
-+      if (rc)
-+              return rc;
-+
-+      /* Aging reference voltage is optional */
-+      ctrl->aging_ref_volt = 0;
-+      of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage",
-+                      &ctrl->aging_ref_volt);
-+
-+      /* Aging possible bitmask is optional */
-+      ctrl->aging_possible_mask = 0;
-+      of_property_read_u32(ctrl->dev->of_node,
-+                      "qcom,cpr-aging-allowed-reg-mask",
-+                      &ctrl->aging_possible_mask);
-+
-+      if (ctrl->aging_possible_mask) {
-+              /*
-+               * Aging possible register value required if bitmask is
-+               * specified
-+               */
-+              rc = cpr3_parse_ctrl_u32(ctrl,
-+                              "qcom,cpr-aging-allowed-reg-value",
-+                              &ctrl->aging_possible_val, 0, UINT_MAX);
-+              if (rc)
-+                      return rc;
-+      }
-+
-+      if (of_property_present(ctrl->dev->of_node, "clock-names")) {
-+              ctrl->core_clk = devm_clk_get(ctrl->dev, "core_clk");
-+              if (IS_ERR(ctrl->core_clk)) {
-+                      rc = PTR_ERR(ctrl->core_clk);
-+                      if (rc != -EPROBE_DEFER)
-+                              cpr3_err(ctrl, "unable request core clock, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+      }
-+
-+      rc = cpr3_panic_notifier_init(ctrl);
-+      if (rc)
-+              return rc;
-+
-+      if (of_property_present(ctrl->dev->of_node, "vdd-supply")) {
-+              ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
-+              if (IS_ERR(ctrl->vdd_regulator)) {
-+                      rc = PTR_ERR(ctrl->vdd_regulator);
-+                      if (rc != -EPROBE_DEFER)
-+                              cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
-+                                       rc);
-+                      return rc;
-+              }
-+      } else {
-+              cpr3_err(ctrl, "vdd supply is not defined\n");
-+              return -ENODEV;
-+      }
-+
-+      ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
-+                                                              "system");
-+      if (IS_ERR(ctrl->system_regulator)) {
-+              rc = PTR_ERR(ctrl->system_regulator);
-+              if (rc != -EPROBE_DEFER) {
-+                      rc = 0;
-+                      ctrl->system_regulator = NULL;
-+              } else {
-+                      return rc;
-+              }
-+      }
-+
-+      ctrl->mem_acc_regulator = devm_regulator_get_optional(ctrl->dev,
-+                                                            "mem-acc");
-+      if (IS_ERR(ctrl->mem_acc_regulator)) {
-+              rc = PTR_ERR(ctrl->mem_acc_regulator);
-+              if (rc != -EPROBE_DEFER) {
-+                      rc = 0;
-+                      ctrl->mem_acc_regulator = NULL;
-+              } else {
-+                      return rc;
-+              }
-+      }
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_parse_open_loop_common_ctrl_data() - parse common open loop CPR3
-+ *                    controller properties from device tree
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_open_loop_common_ctrl_data(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      rc = of_property_read_u32(ctrl->dev->of_node, "qcom,voltage-step",
-+                                &ctrl->step_volt);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading property qcom,voltage-step, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      if (ctrl->step_volt <= 0) {
-+              cpr3_err(ctrl, "qcom,voltage-step=%d is invalid\n",
-+                       ctrl->step_volt);
-+              return -EINVAL;
-+      }
-+
-+      if (of_property_present(ctrl->dev->of_node, "vdd-supply")) {
-+              ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
-+              if (IS_ERR(ctrl->vdd_regulator)) {
-+                      rc = PTR_ERR(ctrl->vdd_regulator);
-+                      if (rc != -EPROBE_DEFER)
-+                              cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
-+                                       rc);
-+                      return rc;
-+              }
-+      } else {
-+              cpr3_err(ctrl, "vdd supply is not defined\n");
-+              return -ENODEV;
-+      }
-+
-+      ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
-+                                                              "system");
-+      if (IS_ERR(ctrl->system_regulator)) {
-+              rc = PTR_ERR(ctrl->system_regulator);
-+              if (rc != -EPROBE_DEFER) {
-+                      rc = 0;
-+                      ctrl->system_regulator = NULL;
-+              } else {
-+                      return rc;
-+              }
-+      } else {
-+              rc = regulator_enable(ctrl->system_regulator);
-+      }
-+
-+      ctrl->mem_acc_regulator = devm_regulator_get_optional(ctrl->dev,
-+                                                            "mem-acc");
-+      if (IS_ERR(ctrl->mem_acc_regulator)) {
-+              rc = PTR_ERR(ctrl->mem_acc_regulator);
-+              if (rc != -EPROBE_DEFER) {
-+                      rc = 0;
-+                      ctrl->mem_acc_regulator = NULL;
-+              } else {
-+                      return rc;
-+              }
-+      }
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_limit_open_loop_voltages() - modify the open-loop voltage of each corner
-+ *                            so that it fits within the floor to ceiling
-+ *                            voltage range of the corner
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function clips the open-loop voltage for each corner so that it is
-+ * limited to the floor to ceiling range.  It also rounds each open-loop voltage
-+ * so that it corresponds to a set point available to the underlying regulator.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg)
-+{
-+      int i, volt;
-+
-+      cpr3_debug(vreg, "open-loop voltages after trimming and rounding:\n");
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              volt = CPR3_ROUND(vreg->corner[i].open_loop_volt,
-+                                      vreg->thread->ctrl->step_volt);
-+              if (volt < vreg->corner[i].floor_volt)
-+                      volt = vreg->corner[i].floor_volt;
-+              else if (volt > vreg->corner[i].ceiling_volt)
-+                      volt = vreg->corner[i].ceiling_volt;
-+              vreg->corner[i].open_loop_volt = volt;
-+              cpr3_debug(vreg, "corner[%2d]: open-loop=%d uV\n", i, volt);
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_open_loop_voltage_as_ceiling() - configures the ceiling voltage for each
-+ *            corner to equal the open-loop voltage if the relevant device
-+ *            tree property is found for the CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function assumes that the the open-loop voltage for each corner has
-+ * already been rounded to the nearest allowed set point and that it falls
-+ * within the floor to ceiling range.
-+ *
-+ * Return: none
-+ */
-+void cpr3_open_loop_voltage_as_ceiling(struct cpr3_regulator *vreg)
-+{
-+      int i;
-+
-+      if (!of_property_read_bool(vreg->of_node,
-+                              "qcom,cpr-scaled-open-loop-voltage-as-ceiling"))
-+              return;
-+
-+      for (i = 0; i < vreg->corner_count; i++)
-+              vreg->corner[i].ceiling_volt
-+                      = vreg->corner[i].open_loop_volt;
-+}
-+
-+/**
-+ * cpr3_limit_floor_voltages() - raise the floor voltage of each corner so that
-+ *            the optional maximum floor to ceiling voltage range specified in
-+ *            device tree is satisfied
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function also ensures that the open-loop voltage for each corner falls
-+ * within the final floor to ceiling voltage range and that floor voltages
-+ * increase monotonically.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
-+{
-+      char *prop = "qcom,cpr-floor-to-ceiling-max-range";
-+      int i, floor_new;
-+      u32 *floor_range;
-+      int rc = 0;
-+
-+      if (!of_property_present(vreg->of_node, prop))
-+              goto enforce_monotonicity;
-+
-+      floor_range = kcalloc(vreg->corner_count, sizeof(*floor_range),
-+                              GFP_KERNEL);
-+      if (!floor_range)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_corner_array_property(vreg, prop, 1, floor_range);
-+      if (rc)
-+              goto free_floor_adjust;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              if ((s32)floor_range[i] >= 0) {
-+                      floor_new = CPR3_ROUND(vreg->corner[i].ceiling_volt
-+                                                      - floor_range[i],
-+                                              vreg->thread->ctrl->step_volt);
-+
-+                      vreg->corner[i].floor_volt = max(floor_new,
-+                                              vreg->corner[i].floor_volt);
-+                      if (vreg->corner[i].open_loop_volt
-+                          < vreg->corner[i].floor_volt)
-+                              vreg->corner[i].open_loop_volt
-+                                      = vreg->corner[i].floor_volt;
-+              }
-+      }
-+
-+free_floor_adjust:
-+      kfree(floor_range);
-+
-+enforce_monotonicity:
-+      /* Ensure that floor voltages increase monotonically. */
-+      for (i = 1; i < vreg->corner_count; i++) {
-+              if (vreg->corner[i].floor_volt
-+                  < vreg->corner[i - 1].floor_volt) {
-+                      cpr3_debug(vreg, "corner %d floor voltage=%d uV < corner %d voltage=%d uV; overriding: corner %d voltage=%d\n",
-+                              i, vreg->corner[i].floor_volt,
-+                              i - 1, vreg->corner[i - 1].floor_volt,
-+                              i, vreg->corner[i - 1].floor_volt);
-+                      vreg->corner[i].floor_volt
-+                              = vreg->corner[i - 1].floor_volt;
-+
-+                      if (vreg->corner[i].open_loop_volt
-+                          < vreg->corner[i].floor_volt)
-+                              vreg->corner[i].open_loop_volt
-+                                      = vreg->corner[i].floor_volt;
-+                      if (vreg->corner[i].ceiling_volt
-+                          < vreg->corner[i].floor_volt)
-+                              vreg->corner[i].ceiling_volt
-+                                      = vreg->corner[i].floor_volt;
-+              }
-+      }
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_print_quots() - print CPR target quotients into the kernel log for
-+ *            debugging purposes
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: none
-+ */
-+void cpr3_print_quots(struct cpr3_regulator *vreg)
-+{
-+      int i, j, pos;
-+      size_t buflen;
-+      char *buf;
-+
-+      buflen = sizeof(*buf) * CPR3_RO_COUNT * (MAX_CHARS_PER_INT + 2);
-+      buf = kzalloc(buflen, GFP_KERNEL);
-+      if (!buf)
-+              return;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              for (j = 0, pos = 0; j < CPR3_RO_COUNT; j++)
-+                      pos += scnprintf(buf + pos, buflen - pos, " %u",
-+                              vreg->corner[i].target_quot[j]);
-+              cpr3_debug(vreg, "target quots[%2d]:%s\n", i, buf);
-+      }
-+
-+      kfree(buf);
-+}
-+
-+/**
-+ * cpr3_determine_part_type() - determine the part type (SS/TT/FF).
-+ *
-+ * qcom,cpr-part-types prop tells the number of part types for which correction
-+ * voltages are different. Another prop qcom,cpr-parts-voltage will contain the
-+ * open loop fuse voltage which will be compared with this part voltage
-+ * and accordingly part type will de determined.
-+ *
-+ * if qcom,cpr-part-types has value n, then qcom,cpr-parts-voltage will be
-+ * array of n - 1 elements which will contain the voltage in increasing order.
-+ * This function compares the fused volatge with all these voltage and returns
-+ * the first index for which the fused volatge is greater.
-+ *
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @fuse_volt:                fused open loop voltage which will be compared with
-+ *                      qcom,cpr-parts-voltage array
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_determine_part_type(struct cpr3_regulator *vreg, int fuse_volt)
-+{
-+      int i, rc, len;
-+      u32 volt;
-+      int soc_version_major;
-+      char prop_name[100];
-+      const char prop_name_def[] = "qcom,cpr-parts-voltage";
-+      const char prop_name_v2[] = "qcom,cpr-parts-voltage-v2";
-+
-+      soc_version_major = read_ipq_soc_version_major();
-+      BUG_ON(soc_version_major <= 0);
-+
-+      if (of_property_read_u32(vreg->of_node, "qcom,cpr-part-types",
-+                                &vreg->part_type_supported))
-+              return 0;
-+
-+      if (soc_version_major > 1)
-+              strscpy(prop_name, prop_name_v2, sizeof(prop_name_v2));
-+      else
-+              strscpy(prop_name, prop_name_def, sizeof(prop_name_def));
-+
-+      if (!of_find_property(vreg->of_node, prop_name, &len)) {
-+              cpr3_err(vreg, "property %s is missing\n", prop_name);
-+              return -EINVAL;
-+      }
-+
-+      if (len != (vreg->part_type_supported - 1) * sizeof(u32)) {
-+              cpr3_err(vreg, "wrong len in qcom,cpr-parts-voltage\n");
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < vreg->part_type_supported - 1; i++) {
-+              rc = of_property_read_u32_index(vreg->of_node,
-+                                      prop_name, i, &volt);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading property %s, rc=%d\n",
-+                               prop_name, rc);
-+                      return rc;
-+              }
-+
-+              if (fuse_volt < volt)
-+                      break;
-+      }
-+
-+      vreg->part_type = i;
-+      return 0;
-+}
-+
-+int cpr3_determine_temp_base_open_loop_correction(struct cpr3_regulator *vreg,
-+              int *fuse_volt)
-+{
-+      int i, rc, prev_volt;
-+      int *volt_adjust;
-+      char prop_str[75];
-+      int soc_version_major = read_ipq_soc_version_major();
-+
-+      BUG_ON(soc_version_major <= 0);
-+
-+      if (vreg->part_type_supported) {
-+              if (soc_version_major > 1)
-+                      snprintf(prop_str, sizeof(prop_str),
-+                      "qcom,cpr-cold-temp-voltage-adjustment-v2-%d",
-+                      vreg->part_type);
-+              else
-+                      snprintf(prop_str, sizeof(prop_str),
-+                      "qcom,cpr-cold-temp-voltage-adjustment-%d",
-+                      vreg->part_type);
-+      } else {
-+              strscpy(prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
-+                      sizeof(prop_str));
-+      }
-+
-+      if (!of_property_present(vreg->of_node, prop_str)) {
-+              /* No adjustment required. */
-+              cpr3_info(vreg, "No cold temperature adjustment required.\n");
-+              return 0;
-+      }
-+
-+      volt_adjust = kcalloc(vreg->fuse_corner_count, sizeof(*volt_adjust),
-+      GFP_KERNEL);
-+      if (!volt_adjust)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_array_property(vreg, prop_str,
-+                      vreg->fuse_corner_count, volt_adjust);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load cold temp voltage adjustments, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->fuse_corner_count; i++) {
-+              if (volt_adjust[i]) {
-+                      prev_volt = fuse_volt[i];
-+                      fuse_volt[i] += volt_adjust[i];
-+                      cpr3_debug(vreg,
-+                              "adjusted fuse corner %d open-loop voltage: %d -> %d uV\n",
-+                              i, prev_volt, fuse_volt[i]);
-+              }
-+      }
-+
-+done:
-+      kfree(volt_adjust);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_can_adjust_cold_temp() - Is cold temperature adjustment available
-+ *
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function checks the cold temperature threshold is available
-+ *
-+ * Return: true on cold temperature threshold is available, else false
-+ */
-+bool cpr3_can_adjust_cold_temp(struct cpr3_regulator *vreg)
-+{
-+      char prop_str[75];
-+      int soc_version_major = read_ipq_soc_version_major();
-+
-+      BUG_ON(soc_version_major <= 0);
-+
-+      if (soc_version_major > 1)
-+              strscpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
-+                      sizeof(prop_str));
-+      else
-+              strscpy(prop_str, "qcom,cpr-cold-temp-threshold",
-+                      sizeof(prop_str));
-+
-+      if (!of_property_present(vreg->of_node, prop_str)) {
-+              /* No adjustment required. */
-+              return false;
-+      } else
-+              return true;
-+}
-+
-+/**
-+ * cpr3_get_cold_temp_threshold() - get cold temperature threshold
-+ *
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @cold_temp:                cold temperature read.
-+ *
-+ * This function reads the cold temperature threshold below which
-+ * cold temperature adjustment margins will be applied.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_get_cold_temp_threshold(struct cpr3_regulator *vreg, int *cold_temp)
-+{
-+      int rc;
-+      u32 temp;
-+      char req_prop_str[75], prop_str[75];
-+      int soc_version_major = read_ipq_soc_version_major();
-+
-+      BUG_ON(soc_version_major <= 0);
-+
-+      if (vreg->part_type_supported) {
-+              if (soc_version_major > 1)
-+                      snprintf(req_prop_str, sizeof(req_prop_str),
-+                      "qcom,cpr-cold-temp-voltage-adjustment-v2-%d",
-+                      vreg->part_type);
-+              else
-+                      snprintf(req_prop_str, sizeof(req_prop_str),
-+                      "qcom,cpr-cold-temp-voltage-adjustment-%d",
-+                      vreg->part_type);
-+      } else {
-+              strscpy(req_prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
-+                      sizeof(req_prop_str));
-+      }
-+
-+      if (soc_version_major > 1)
-+              strscpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
-+                      sizeof(prop_str));
-+      else
-+              strscpy(prop_str, "qcom,cpr-cold-temp-threshold",
-+                      sizeof(prop_str));
-+
-+      if (!of_property_present(vreg->of_node, req_prop_str)) {
-+              /* No adjustment required. */
-+              cpr3_info(vreg, "Cold temperature adjustment not required.\n");
-+              return 0;
-+      }
-+
-+      if (!of_property_present(vreg->of_node, prop_str)) {
-+              /* No adjustment required. */
-+              cpr3_err(vreg, "Missing %s required for %s\n",
-+                      prop_str, req_prop_str);
-+              return -EINVAL;
-+      }
-+
-+      rc = of_property_read_u32(vreg->of_node, prop_str, &temp);
-+      if (rc) {
-+              cpr3_err(vreg, "error reading property %s, rc=%d\n",
-+                      prop_str, rc);
-+              return rc;
-+      }
-+
-+      *cold_temp = temp;
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_adjust_fused_open_loop_voltages() - adjust the fused open-loop voltages
-+ *            for each fuse corner according to device tree values
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @fuse_volt:                Pointer to an array of the fused open-loop voltage
-+ *                    values
-+ *
-+ * Voltage values in fuse_volt are modified in place.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_adjust_fused_open_loop_voltages(struct cpr3_regulator *vreg,
-+              int *fuse_volt)
-+{
-+      int i, rc, prev_volt;
-+      int *volt_adjust;
-+      char prop_str[75];
-+      int soc_version_major = read_ipq_soc_version_major();
-+
-+      BUG_ON(soc_version_major <= 0);
-+
-+      if (vreg->part_type_supported) {
-+              if (soc_version_major > 1)
-+                      snprintf(prop_str, sizeof(prop_str),
-+                      "qcom,cpr-open-loop-voltage-fuse-adjustment-v2-%d",
-+                      vreg->part_type);
-+              else
-+              snprintf(prop_str, sizeof(prop_str),
-+                       "qcom,cpr-open-loop-voltage-fuse-adjustment-%d",
-+                       vreg->part_type);
-+      } else {
-+              strscpy(prop_str, "qcom,cpr-open-loop-voltage-fuse-adjustment",
-+                      sizeof(prop_str));
-+      }
-+
-+      if (!of_property_present(vreg->of_node, prop_str)) {
-+              /* No adjustment required. */
-+              return 0;
-+      }
-+
-+      volt_adjust = kcalloc(vreg->fuse_corner_count, sizeof(*volt_adjust),
-+                              GFP_KERNEL);
-+      if (!volt_adjust)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_array_property(vreg,
-+              prop_str, vreg->fuse_corner_count, volt_adjust);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load open-loop fused voltage adjustments, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->fuse_corner_count; i++) {
-+              if (volt_adjust[i]) {
-+                      prev_volt = fuse_volt[i];
-+                      fuse_volt[i] += volt_adjust[i];
-+                      cpr3_debug(vreg, "adjusted fuse corner %d open-loop voltage: %d --> %d uV\n",
-+                              i, prev_volt, fuse_volt[i]);
-+              }
-+      }
-+
-+done:
-+      kfree(volt_adjust);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_adjust_open_loop_voltages() - adjust the open-loop voltages for each
-+ *            corner according to device tree values
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg)
-+{
-+      int i, rc, prev_volt, min_volt;
-+      int *volt_adjust, *volt_diff;
-+
-+      if (!of_property_present(vreg->of_node,
-+                      "qcom,cpr-open-loop-voltage-adjustment")) {
-+              /* No adjustment required. */
-+              return 0;
-+      }
-+
-+      volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
-+                              GFP_KERNEL);
-+      volt_diff = kcalloc(vreg->corner_count, sizeof(*volt_diff), GFP_KERNEL);
-+      if (!volt_adjust || !volt_diff) {
-+              rc = -ENOMEM;
-+              goto done;
-+      }
-+
-+      rc = cpr3_parse_corner_array_property(vreg,
-+              "qcom,cpr-open-loop-voltage-adjustment", 1, volt_adjust);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load open-loop voltage adjustments, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              if (volt_adjust[i]) {
-+                      prev_volt = vreg->corner[i].open_loop_volt;
-+                      vreg->corner[i].open_loop_volt += volt_adjust[i];
-+                      cpr3_debug(vreg, "adjusted corner %d open-loop voltage: %d --> %d uV\n",
-+                              i, prev_volt, vreg->corner[i].open_loop_volt);
-+              }
-+      }
-+
-+      if (of_property_present(vreg->of_node,
-+                      "qcom,cpr-open-loop-voltage-min-diff")) {
-+              rc = cpr3_parse_corner_array_property(vreg,
-+                      "qcom,cpr-open-loop-voltage-min-diff", 1, volt_diff);
-+              if (rc) {
-+                      cpr3_err(vreg, "could not load minimum open-loop voltage differences, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      /*
-+       * Ensure that open-loop voltages increase monotonically with respect
-+       * to configurable minimum allowed differences.
-+       */
-+      for (i = 1; i < vreg->corner_count; i++) {
-+              min_volt = vreg->corner[i - 1].open_loop_volt + volt_diff[i];
-+              if (vreg->corner[i].open_loop_volt < min_volt) {
-+                      cpr3_debug(vreg, "adjusted corner %d open-loop voltage=%d uV < corner %d voltage=%d uV + min diff=%d uV; overriding: corner %d voltage=%d\n",
-+                              i, vreg->corner[i].open_loop_volt,
-+                              i - 1, vreg->corner[i - 1].open_loop_volt,
-+                              volt_diff[i], i, min_volt);
-+                      vreg->corner[i].open_loop_volt = min_volt;
-+              }
-+      }
-+
-+done:
-+      kfree(volt_diff);
-+      kfree(volt_adjust);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_quot_adjustment() - returns the quotient adjustment value resulting from
-+ *            the specified voltage adjustment and RO scaling factor
-+ * @ro_scale:         The CPR ring oscillator (RO) scaling factor with units
-+ *                    of QUOT/V
-+ * @volt_adjust:      The amount to adjust the voltage by in units of
-+ *                    microvolts.  This value may be positive or negative.
-+ */
-+int cpr3_quot_adjustment(int ro_scale, int volt_adjust)
-+{
-+      unsigned long long temp;
-+      int quot_adjust;
-+      int sign = 1;
-+
-+      if (ro_scale < 0) {
-+              sign = -sign;
-+              ro_scale = -ro_scale;
-+      }
-+
-+      if (volt_adjust < 0) {
-+              sign = -sign;
-+              volt_adjust = -volt_adjust;
-+      }
-+
-+      temp = (unsigned long long)ro_scale * (unsigned long long)volt_adjust;
-+      do_div(temp, 1000000);
-+
-+      quot_adjust = temp;
-+      quot_adjust *= sign;
-+
-+      return quot_adjust;
-+}
-+
-+/**
-+ * cpr3_voltage_adjustment() - returns the voltage adjustment value resulting
-+ *            from the specified quotient adjustment and RO scaling factor
-+ * @ro_scale:         The CPR ring oscillator (RO) scaling factor with units
-+ *                    of QUOT/V
-+ * @quot_adjust:      The amount to adjust the quotient by in units of
-+ *                    QUOT.  This value may be positive or negative.
-+ */
-+int cpr3_voltage_adjustment(int ro_scale, int quot_adjust)
-+{
-+      unsigned long long temp;
-+      int volt_adjust;
-+      int sign = 1;
-+
-+      if (ro_scale < 0) {
-+              sign = -sign;
-+              ro_scale = -ro_scale;
-+      }
-+
-+      if (quot_adjust < 0) {
-+              sign = -sign;
-+              quot_adjust = -quot_adjust;
-+      }
-+
-+      if (ro_scale == 0)
-+              return 0;
-+
-+      temp = (unsigned long long)quot_adjust * 1000000;
-+      do_div(temp, ro_scale);
-+
-+      volt_adjust = temp;
-+      volt_adjust *= sign;
-+
-+      return volt_adjust;
-+}
-+
-+/**
-+ * cpr3_parse_closed_loop_voltage_adjustments() - load per-fuse-corner and
-+ *            per-corner closed-loop adjustment values from device tree
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @ro_sel:           Array of ring oscillator values selected for each
-+ *                    fuse corner
-+ * @volt_adjust:      Pointer to array which will be filled with the
-+ *                    per-corner closed-loop adjustment voltages
-+ * @volt_adjust_fuse: Pointer to array which will be filled with the
-+ *                    per-fuse-corner closed-loop adjustment voltages
-+ * @ro_scale:         Pointer to array which will be filled with the
-+ *                    per-fuse-corner RO scaling factor values with units of
-+ *                    QUOT/V
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_parse_closed_loop_voltage_adjustments(
-+                      struct cpr3_regulator *vreg, u64 *ro_sel,
-+                      int *volt_adjust, int *volt_adjust_fuse, int *ro_scale)
-+{
-+      int i, rc;
-+      u32 *ro_all_scale;
-+
-+      char volt_adj[] = "qcom,cpr-closed-loop-voltage-adjustment";
-+      char volt_fuse_adj[] = "qcom,cpr-closed-loop-voltage-fuse-adjustment";
-+      char ro_scaling[] = "qcom,cpr-ro-scaling-factor";
-+
-+      if (!of_property_present(vreg->of_node, volt_adj)
-+          && !of_property_present(vreg->of_node, volt_fuse_adj)
-+          && !vreg->aging_allowed) {
-+              /* No adjustment required. */
-+              return 0;
-+      } else if (!of_property_present(vreg->of_node, ro_scaling)) {
-+              cpr3_err(vreg, "Missing %s required for closed-loop voltage adjustment.\n",
-+                              ro_scaling);
-+              return -EINVAL;
-+      }
-+
-+      ro_all_scale = kcalloc(vreg->fuse_corner_count * CPR3_RO_COUNT,
-+                              sizeof(*ro_all_scale), GFP_KERNEL);
-+      if (!ro_all_scale)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_array_property(vreg, ro_scaling,
-+              vreg->fuse_corner_count * CPR3_RO_COUNT, ro_all_scale);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->fuse_corner_count; i++)
-+              ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + ro_sel[i]];
-+
-+      for (i = 0; i < vreg->corner_count; i++)
-+              memcpy(vreg->corner[i].ro_scale,
-+               &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT],
-+               sizeof(*ro_all_scale) * CPR3_RO_COUNT);
-+
-+      if (of_property_present(vreg->of_node, volt_fuse_adj)) {
-+              rc = cpr3_parse_array_property(vreg, volt_fuse_adj,
-+                      vreg->fuse_corner_count, volt_adjust_fuse);
-+              if (rc) {
-+                      cpr3_err(vreg, "could not load closed-loop fused voltage adjustments, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      if (of_property_present(vreg->of_node, volt_adj)) {
-+              rc = cpr3_parse_corner_array_property(vreg, volt_adj,
-+                      1, volt_adjust);
-+              if (rc) {
-+                      cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+done:
-+      kfree(ro_all_scale);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_apm_init() - initialize APM data for a CPR3 controller
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * This function loads memory array power mux (APM) data from device tree
-+ * if it is present and requests a handle to the appropriate APM controller
-+ * device.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_apm_init(struct cpr3_controller *ctrl)
-+{
-+      struct device_node *node = ctrl->dev->of_node;
-+      int rc;
-+
-+      if (!of_property_present(node, "qcom,apm-ctrl")) {
-+              /* No APM used */
-+              return 0;
-+      }
-+
-+      ctrl->apm = msm_apm_ctrl_dev_get(ctrl->dev);
-+      if (IS_ERR(ctrl->apm)) {
-+              rc = PTR_ERR(ctrl->apm);
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(ctrl, "APM get failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      rc = of_property_read_u32(node, "qcom,apm-threshold-voltage",
-+                              &ctrl->apm_threshold_volt);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading qcom,apm-threshold-voltage, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+      ctrl->apm_threshold_volt
-+              = CPR3_ROUND(ctrl->apm_threshold_volt, ctrl->step_volt);
-+
-+      /* No error check since this is an optional property. */
-+      of_property_read_u32(node, "qcom,apm-hysteresis-voltage",
-+                              &ctrl->apm_adj_volt);
-+      ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
-+
-+      ctrl->apm_high_supply = MSM_APM_SUPPLY_APCC;
-+      ctrl->apm_low_supply = MSM_APM_SUPPLY_MX;
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr3_mem_acc_init() - initialize mem-acc regulator data for
-+ *            a CPR3 regulator
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      u32 *temp;
-+      int i, rc;
-+
-+      if (!ctrl->mem_acc_regulator) {
-+              cpr3_info(ctrl, "not using memory accelerator regulator\n");
-+              return 0;
-+      }
-+
-+      temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
-+      if (!temp)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_corner_array_property(vreg, "qcom,mem-acc-voltage",
-+                                            1, temp);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not load mem-acc corners, rc=%d\n", rc);
-+      } else {
-+              for (i = 0; i < vreg->corner_count; i++)
-+                      vreg->corner[i].mem_acc_volt = temp[i];
-+      }
-+
-+      kfree(temp);
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_load_core_and_temp_adj() - parse amount of voltage adjustment for
-+ *            per-online-core and per-temperature voltage adjustment for a
-+ *            given corner or corner band from device tree.
-+ * @vreg:     Pointer to the CPR3 regulator
-+ * @num:      Corner number or corner band number
-+ * @use_corner_band:  Boolean indicating if the CPR3 regulator supports
-+ *                    adjustments per corner band
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_load_core_and_temp_adj(struct cpr3_regulator *vreg,
-+                                      int num, bool use_corner_band)
-+{
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      struct cpr4_sdelta *sdelta;
-+      int sdelta_size, i, j, pos, rc = 0;
-+      char str[75];
-+      size_t buflen;
-+      char *buf;
-+
-+      sdelta = use_corner_band ? vreg->corner_band[num].sdelta :
-+              vreg->corner[num].sdelta;
-+
-+      if (!sdelta->allow_core_count_adj && !sdelta->allow_temp_adj) {
-+              /* corner doesn't need sdelta table */
-+              sdelta->max_core_count = 0;
-+              sdelta->temp_band_count = 0;
-+              return rc;
-+      }
-+
-+      sdelta_size = sdelta->max_core_count * sdelta->temp_band_count;
-+      if (use_corner_band)
-+              snprintf(str, sizeof(str),
-+                       "corner_band=%d core_config_count=%d temp_band_count=%d sdelta_size=%d\n",
-+                       num, sdelta->max_core_count,
-+                       sdelta->temp_band_count, sdelta_size);
-+      else
-+              snprintf(str, sizeof(str),
-+                       "corner=%d core_config_count=%d temp_band_count=%d sdelta_size=%d\n",
-+                       num, sdelta->max_core_count,
-+                       sdelta->temp_band_count, sdelta_size);
-+
-+      cpr3_debug(vreg, "%s", str);
-+
-+      sdelta->table = devm_kcalloc(ctrl->dev, sdelta_size,
-+                              sizeof(*sdelta->table), GFP_KERNEL);
-+      if (!sdelta->table)
-+              return -ENOMEM;
-+
-+      if (use_corner_band)
-+              snprintf(str, sizeof(str),
-+                       "qcom,cpr-corner-band%d-temp-core-voltage-adjustment",
-+                       num + CPR3_CORNER_OFFSET);
-+      else
-+              snprintf(str, sizeof(str),
-+                       "qcom,cpr-corner%d-temp-core-voltage-adjustment",
-+                       num + CPR3_CORNER_OFFSET);
-+
-+      rc = cpr3_parse_array_property(vreg, str, sdelta_size,
-+                              sdelta->table);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load %s, rc=%d\n", str, rc);
-+              return rc;
-+      }
-+
-+      /*
-+       * Convert sdelta margins from uV to PMIC steps and apply negation to
-+       * follow the SDELTA register semantics.
-+       */
-+      for (i = 0; i < sdelta_size; i++)
-+              sdelta->table[i] = -(sdelta->table[i] / ctrl->step_volt);
-+
-+      buflen = sizeof(*buf) * sdelta_size * (MAX_CHARS_PER_INT + 2);
-+      buf = kzalloc(buflen, GFP_KERNEL);
-+      if (!buf)
-+              return rc;
-+
-+      for (i = 0; i < sdelta->max_core_count; i++) {
-+              for (j = 0, pos = 0; j < sdelta->temp_band_count; j++)
-+                      pos += scnprintf(buf + pos, buflen - pos, " %u",
-+                       sdelta->table[i * sdelta->temp_band_count + j]);
-+              cpr3_debug(vreg, "sdelta[%d]:%s\n", i, buf);
-+      }
-+
-+      kfree(buf);
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_parse_core_count_temp_voltage_adj() - parse configuration data for
-+ *            per-online-core and per-temperature voltage adjustment for
-+ *            a CPR3 regulator from device tree.
-+ * @vreg:     Pointer to the CPR3 regulator
-+ * @use_corner_band:  Boolean indicating if the CPR3 regulator supports
-+ *                    adjustments per corner band
-+ *
-+ * This function supports parsing of per-online-core and per-temperature
-+ * adjustments per corner or per corner band. CPR controllers which support
-+ * corner bands apply the same adjustments to all corners within a corner band.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr4_parse_core_count_temp_voltage_adj(
-+                      struct cpr3_regulator *vreg, bool use_corner_band)
-+{
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      struct device_node *node = vreg->of_node;
-+      struct cpr3_corner *corner;
-+      struct cpr4_sdelta *sdelta;
-+      int i, sdelta_table_count, rc = 0;
-+      int *allow_core_count_adj = NULL, *allow_temp_adj = NULL;
-+      char prop_str[75];
-+
-+      if (of_property_present(node, use_corner_band ?
-+                           "qcom,corner-band-allow-temp-adjustment"
-+                           : "qcom,corner-allow-temp-adjustment")) {
-+              if (!ctrl->allow_temp_adj) {
-+                      cpr3_err(ctrl, "Temperature adjustment configurations missing\n");
-+                      return -EINVAL;
-+              }
-+
-+              vreg->allow_temp_adj = true;
-+      }
-+
-+      if (of_property_present(node, use_corner_band ?
-+                           "qcom,corner-band-allow-core-count-adjustment"
-+                           : "qcom,corner-allow-core-count-adjustment")) {
-+              rc = of_property_read_u32(node, "qcom,max-core-count",
-+                              &vreg->max_core_count);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading qcom,max-core-count, rc=%d\n",
-+                              rc);
-+                      return -EINVAL;
-+              }
-+
-+              vreg->allow_core_count_adj = true;
-+              ctrl->allow_core_count_adj = true;
-+      }
-+
-+      if (!vreg->allow_temp_adj && !vreg->allow_core_count_adj) {
-+              /*
-+               * Both per-online-core and temperature based adjustments are
-+               * disabled for this regulator.
-+               */
-+              return 0;
-+      } else if (!vreg->allow_core_count_adj) {
-+              /*
-+               * Only per-temperature voltage adjusments are allowed.
-+               * Keep max core count value as 1 to allocate SDELTA.
-+               */
-+              vreg->max_core_count = 1;
-+      }
-+
-+      if (vreg->allow_core_count_adj) {
-+              allow_core_count_adj = kcalloc(vreg->corner_count,
-+                                      sizeof(*allow_core_count_adj),
-+                                      GFP_KERNEL);
-+              if (!allow_core_count_adj)
-+                      return -ENOMEM;
-+
-+              snprintf(prop_str, sizeof(prop_str), "%s", use_corner_band ?
-+                       "qcom,corner-band-allow-core-count-adjustment" :
-+                       "qcom,corner-allow-core-count-adjustment");
-+
-+              rc = use_corner_band ?
-+                      cpr3_parse_corner_band_array_property(vreg, prop_str,
-+                                            1, allow_core_count_adj) :
-+                      cpr3_parse_corner_array_property(vreg, prop_str,
-+                                               1, allow_core_count_adj);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading %s, rc=%d\n", prop_str,
-+                               rc);
-+                      goto done;
-+              }
-+      }
-+
-+      if (vreg->allow_temp_adj) {
-+              allow_temp_adj = kcalloc(vreg->corner_count,
-+                                      sizeof(*allow_temp_adj), GFP_KERNEL);
-+              if (!allow_temp_adj) {
-+                      rc = -ENOMEM;
-+                      goto done;
-+              }
-+
-+              snprintf(prop_str, sizeof(prop_str), "%s", use_corner_band ?
-+                       "qcom,corner-band-allow-temp-adjustment" :
-+                       "qcom,corner-allow-temp-adjustment");
-+
-+              rc = use_corner_band ?
-+                      cpr3_parse_corner_band_array_property(vreg, prop_str,
-+                                                    1, allow_temp_adj) :
-+                      cpr3_parse_corner_array_property(vreg, prop_str,
-+                                               1, allow_temp_adj);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading %s, rc=%d\n", prop_str,
-+                               rc);
-+                      goto done;
-+              }
-+      }
-+
-+      sdelta_table_count = use_corner_band ? vreg->corner_band_count :
-+              vreg->corner_count;
-+
-+      for (i = 0; i < sdelta_table_count; i++) {
-+              sdelta = devm_kzalloc(ctrl->dev, sizeof(*corner->sdelta),
-+                                    GFP_KERNEL);
-+              if (!sdelta) {
-+                      rc = -ENOMEM;
-+                      goto done;
-+              }
-+
-+              if (allow_core_count_adj)
-+                      sdelta->allow_core_count_adj = allow_core_count_adj[i];
-+              if (allow_temp_adj)
-+                      sdelta->allow_temp_adj = allow_temp_adj[i];
-+              sdelta->max_core_count = vreg->max_core_count;
-+              sdelta->temp_band_count = ctrl->temp_band_count;
-+
-+              if (use_corner_band)
-+                      vreg->corner_band[i].sdelta = sdelta;
-+              else
-+                      vreg->corner[i].sdelta = sdelta;
-+
-+              rc = cpr4_load_core_and_temp_adj(vreg, i, use_corner_band);
-+              if (rc) {
-+                      cpr3_err(vreg, "corner/band %d core and temp adjustment loading failed, rc=%d\n",
-+                               i, rc);
-+                      goto done;
-+              }
-+      }
-+
-+done:
-+      kfree(allow_core_count_adj);
-+      kfree(allow_temp_adj);
-+
-+      return rc;
-+}
-+
-+/**
-+ * cprh_adjust_voltages_for_apm() - adjust per-corner floor and ceiling voltages
-+ *            so that they do not overlap the APM threshold voltage.
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * The memory array power mux (APM) must be configured for a specific supply
-+ * based upon where the VDD voltage lies with respect to the APM threshold
-+ * voltage.  When using CPR hardware closed-loop, the voltage may vary anywhere
-+ * between the floor and ceiling voltage without software notification.
-+ * Therefore, it is required that the floor to ceiling range for every corner
-+ * not intersect the APM threshold voltage.  This function adjusts the floor to
-+ * ceiling range for each corner which violates this requirement.
-+ *
-+ * The following algorithm is applied:
-+ *    if floor < threshold <= ceiling:
-+ *            if open_loop >= threshold, then floor = threshold - adj
-+ *            else ceiling = threshold - step
-+ * where:
-+ *    adj = APM hysteresis voltage established to minimize the number of
-+ *          corners with artificially increased floor voltages
-+ *    step = voltage in microvolts of a single step of the VDD supply
-+ *
-+ * The open-loop voltage is also bounded by the new floor or ceiling value as
-+ * needed.
-+ *
-+ * Return: none
-+ */
-+void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      struct cpr3_corner *corner;
-+      int i, adj, threshold, prev_ceiling, prev_floor, prev_open_loop;
-+
-+      if (!ctrl->apm_threshold_volt) {
-+              /* APM not being used. */
-+              return;
-+      }
-+
-+      ctrl->apm_threshold_volt = CPR3_ROUND(ctrl->apm_threshold_volt,
-+                                              ctrl->step_volt);
-+      ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
-+
-+      threshold = ctrl->apm_threshold_volt;
-+      adj = ctrl->apm_adj_volt;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              corner = &vreg->corner[i];
-+
-+              if (threshold <= corner->floor_volt
-+                  || threshold > corner->ceiling_volt)
-+                      continue;
-+
-+              prev_floor = corner->floor_volt;
-+              prev_ceiling = corner->ceiling_volt;
-+              prev_open_loop = corner->open_loop_volt;
-+
-+              if (corner->open_loop_volt >= threshold) {
-+                      corner->floor_volt = max(corner->floor_volt,
-+                                               threshold - adj);
-+                      if (corner->open_loop_volt < corner->floor_volt)
-+                              corner->open_loop_volt = corner->floor_volt;
-+              } else {
-+                      corner->ceiling_volt = threshold - ctrl->step_volt;
-+              }
-+
-+              if (corner->floor_volt != prev_floor
-+                  || corner->ceiling_volt != prev_ceiling
-+                  || corner->open_loop_volt != prev_open_loop)
-+                      cpr3_debug(vreg, "APM threshold=%d, APM adj=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
-+                              threshold, adj, i, prev_floor, prev_ceiling,
-+                              prev_open_loop, corner->floor_volt,
-+                              corner->ceiling_volt, corner->open_loop_volt);
-+      }
-+}
-+
-+/**
-+ * cprh_adjust_voltages_for_mem_acc() - adjust per-corner floor and ceiling
-+ *            voltages so that they do not intersect the MEM ACC threshold
-+ *            voltage
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * The following algorithm is applied:
-+ *    if floor < threshold <= ceiling:
-+ *            if open_loop >= threshold, then floor = threshold
-+ *            else ceiling = threshold - step
-+ * where:
-+ *    step = voltage in microvolts of a single step of the VDD supply
-+ *
-+ * The open-loop voltage is also bounded by the new floor or ceiling value as
-+ * needed.
-+ *
-+ * Return: none
-+ */
-+void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      struct cpr3_corner *corner;
-+      int i, threshold, prev_ceiling, prev_floor, prev_open_loop;
-+
-+      if (!ctrl->mem_acc_threshold_volt) {
-+              /* MEM ACC not being used. */
-+              return;
-+      }
-+
-+      ctrl->mem_acc_threshold_volt = CPR3_ROUND(ctrl->mem_acc_threshold_volt,
-+                                              ctrl->step_volt);
-+
-+      threshold = ctrl->mem_acc_threshold_volt;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              corner = &vreg->corner[i];
-+
-+              if (threshold <= corner->floor_volt
-+                  || threshold > corner->ceiling_volt)
-+                      continue;
-+
-+              prev_floor = corner->floor_volt;
-+              prev_ceiling = corner->ceiling_volt;
-+              prev_open_loop = corner->open_loop_volt;
-+
-+              if (corner->open_loop_volt >= threshold) {
-+                      corner->floor_volt = max(corner->floor_volt, threshold);
-+                      if (corner->open_loop_volt < corner->floor_volt)
-+                              corner->open_loop_volt = corner->floor_volt;
-+              } else {
-+                      corner->ceiling_volt = threshold - ctrl->step_volt;
-+              }
-+
-+              if (corner->floor_volt != prev_floor
-+                  || corner->ceiling_volt != prev_ceiling
-+                  || corner->open_loop_volt != prev_open_loop)
-+                      cpr3_debug(vreg, "MEM ACC threshold=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
-+                              threshold, i, prev_floor, prev_ceiling,
-+                              prev_open_loop, corner->floor_volt,
-+                              corner->ceiling_volt, corner->open_loop_volt);
-+      }
-+}
-+
-+/**
-+ * cpr3_apply_closed_loop_offset_voltages() - modify the closed-loop voltage
-+ *            adjustments by the amounts that are needed for this
-+ *            fuse combo
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @volt_adjust:      Array of closed-loop voltage adjustment values of length
-+ *                    vreg->corner_count which is further adjusted based upon
-+ *                    offset voltage fuse values.
-+ * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
-+ *                    vreg->fuse_corner_count.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr3_apply_closed_loop_offset_voltages(struct cpr3_regulator *vreg,
-+                      int *volt_adjust, int *fuse_volt_adjust)
-+{
-+      u32 *corner_map;
-+      int rc = 0, i;
-+
-+      if (!of_property_present(vreg->of_node,
-+              "qcom,cpr-fused-closed-loop-voltage-adjustment-map")) {
-+              /* No closed-loop offset required. */
-+              return 0;
-+      }
-+
-+      corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map),
-+                              GFP_KERNEL);
-+      if (!corner_map)
-+              return -ENOMEM;
-+
-+      rc = cpr3_parse_corner_array_property(vreg,
-+              "qcom,cpr-fused-closed-loop-voltage-adjustment-map",
-+              1, corner_map);
-+      if (rc)
-+              goto done;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              if (corner_map[i] == 0) {
-+                      continue;
-+              } else if (corner_map[i] > vreg->fuse_corner_count) {
-+                      cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n",
-+                              i, corner_map[i]);
-+                      rc = -EINVAL;
-+                      goto done;
-+              }
-+
-+              volt_adjust[i] += fuse_volt_adjust[corner_map[i] - 1];
-+      }
-+
-+done:
-+      kfree(corner_map);
-+      return rc;
-+}
-+
-+/**
-+ * cpr3_enforce_inc_quotient_monotonicity() - Ensure that target quotients
-+ *            increase monotonically from lower to higher corners
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static void cpr3_enforce_inc_quotient_monotonicity(struct cpr3_regulator *vreg)
-+{
-+      int i, j;
-+
-+      for (i = 1; i < vreg->corner_count; i++) {
-+              for (j = 0; j < CPR3_RO_COUNT; j++) {
-+                      if (vreg->corner[i].target_quot[j]
-+                          && vreg->corner[i].target_quot[j]
-+                                      < vreg->corner[i - 1].target_quot[j]) {
-+                              cpr3_debug(vreg, "corner %d RO%u target quot=%u < corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
-+                                      i, j,
-+                                      vreg->corner[i].target_quot[j],
-+                                      i - 1, j,
-+                                      vreg->corner[i - 1].target_quot[j],
-+                                      i, j,
-+                                      vreg->corner[i - 1].target_quot[j]);
-+                              vreg->corner[i].target_quot[j]
-+                                      = vreg->corner[i - 1].target_quot[j];
-+                      }
-+              }
-+      }
-+}
-+
-+/**
-+ * cpr3_enforce_dec_quotient_monotonicity() - Ensure that target quotients
-+ *            decrease monotonically from higher to lower corners
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static void cpr3_enforce_dec_quotient_monotonicity(struct cpr3_regulator *vreg)
-+{
-+      int i, j;
-+
-+      for (i = vreg->corner_count - 2; i >= 0; i--) {
-+              for (j = 0; j < CPR3_RO_COUNT; j++) {
-+                      if (vreg->corner[i + 1].target_quot[j]
-+                          && vreg->corner[i].target_quot[j]
-+                                      > vreg->corner[i + 1].target_quot[j]) {
-+                              cpr3_debug(vreg, "corner %d RO%u target quot=%u > corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
-+                                      i, j,
-+                                      vreg->corner[i].target_quot[j],
-+                                      i + 1, j,
-+                                      vreg->corner[i + 1].target_quot[j],
-+                                      i, j,
-+                                      vreg->corner[i + 1].target_quot[j]);
-+                              vreg->corner[i].target_quot[j]
-+                                      = vreg->corner[i + 1].target_quot[j];
-+                      }
-+              }
-+      }
-+}
-+
-+/**
-+ * _cpr3_adjust_target_quotients() - adjust the target quotients for each
-+ *            corner of the regulator according to input adjustment and
-+ *            scaling arrays
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @volt_adjust:      Pointer to an array of closed-loop voltage adjustments
-+ *                    with units of microvolts.  The array must have
-+ *                    vreg->corner_count number of elements.
-+ * @ro_scale:         Pointer to a flattened 2D array of RO scaling factors.
-+ *                    The array must have an inner dimension of CPR3_RO_COUNT
-+ *                    and an outer dimension of vreg->corner_count
-+ * @label:            Null terminated string providing a label for the type
-+ *                    of adjustment.
-+ *
-+ * Return: true if any corners received a positive voltage adjustment (> 0),
-+ *       else false
-+ */
-+static bool _cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
-+              const int *volt_adjust, const int *ro_scale, const char *label)
-+{
-+      int i, j, quot_adjust;
-+      bool is_increasing = false;
-+      u32 prev_quot;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              for (j = 0; j < CPR3_RO_COUNT; j++) {
-+                      if (vreg->corner[i].target_quot[j]) {
-+                              quot_adjust = cpr3_quot_adjustment(
-+                                      ro_scale[i * CPR3_RO_COUNT + j],
-+                                      volt_adjust[i]);
-+                              if (quot_adjust) {
-+                                      prev_quot = vreg->corner[i].
-+                                                      target_quot[j];
-+                                      vreg->corner[i].target_quot[j]
-+                                              += quot_adjust;
-+                                      cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n",
-+                                              i, j, label, prev_quot,
-+                                              vreg->corner[i].target_quot[j],
-+                                              volt_adjust[i]);
-+                              }
-+                      }
-+              }
-+              if (volt_adjust[i] > 0)
-+                      is_increasing = true;
-+      }
-+
-+      return is_increasing;
-+}
-+
-+/**
-+ * cpr3_adjust_target_quotients() - adjust the target quotients for each
-+ *                    corner according to device tree values and fuse values
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
-+ *                    vreg->fuse_corner_count. This parameter could be null
-+ *                    pointer when no fused adjustments are needed.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
-+                      int *fuse_volt_adjust)
-+{
-+      int i, rc;
-+      int *volt_adjust, *ro_scale;
-+      bool explicit_adjustment, fused_adjustment, is_increasing;
-+
-+      explicit_adjustment = of_property_present(vreg->of_node,
-+              "qcom,cpr-closed-loop-voltage-adjustment");
-+      fused_adjustment = of_property_present(vreg->of_node,
-+              "qcom,cpr-fused-closed-loop-voltage-adjustment-map");
-+
-+      if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
-+              /* No adjustment required. */
-+              return 0;
-+      } else if (!of_property_present(vreg->of_node,
-+                      "qcom,cpr-ro-scaling-factor")) {
-+              cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
-+              return -EINVAL;
-+      }
-+
-+      volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
-+                              GFP_KERNEL);
-+      ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT,
-+                              sizeof(*ro_scale), GFP_KERNEL);
-+      if (!volt_adjust || !ro_scale) {
-+              rc = -ENOMEM;
-+              goto done;
-+      }
-+
-+      rc = cpr3_parse_corner_array_property(vreg,
-+                      "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->corner_count; i++)
-+              memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT],
-+                      sizeof(*ro_scale) * CPR3_RO_COUNT);
-+
-+      if (explicit_adjustment) {
-+              rc = cpr3_parse_corner_array_property(vreg,
-+                      "qcom,cpr-closed-loop-voltage-adjustment",
-+                      1, volt_adjust);
-+              if (rc) {
-+                      cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+
-+              _cpr3_adjust_target_quotients(vreg, volt_adjust, ro_scale,
-+                      "from DT");
-+              cpr3_enforce_inc_quotient_monotonicity(vreg);
-+      }
-+
-+      if (fused_adjustment && fuse_volt_adjust) {
-+              memset(volt_adjust, 0,
-+                      sizeof(*volt_adjust) * vreg->corner_count);
-+
-+              rc = cpr3_apply_closed_loop_offset_voltages(vreg, volt_adjust,
-+                              fuse_volt_adjust);
-+              if (rc) {
-+                      cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+
-+              is_increasing = _cpr3_adjust_target_quotients(vreg, volt_adjust,
-+                                      ro_scale, "from fuse");
-+              if (is_increasing)
-+                      cpr3_enforce_inc_quotient_monotonicity(vreg);
-+              else
-+                      cpr3_enforce_dec_quotient_monotonicity(vreg);
-+      }
-+
-+done:
-+      kfree(volt_adjust);
-+      kfree(ro_scale);
-+      return rc;
-+}
---- /dev/null
-+++ b/drivers/regulator/cpr4-apss-regulator.c
-@@ -0,0 +1,1813 @@
-+/*
-+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#define pr_fmt(fmt) "%s: " fmt, __func__
-+
-+#include <linux/bitops.h>
-+#include <linux/debugfs.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/uaccess.h>
-+#include <linux/regulator/driver.h>
-+#include <linux/regulator/machine.h>
-+#include <linux/regulator/of_regulator.h>
-+
-+#include "cpr3-regulator.h"
-+
-+#define IPQ807x_APSS_FUSE_CORNERS     4
-+#define IPQ817x_APPS_FUSE_CORNERS     2
-+#define IPQ6018_APSS_FUSE_CORNERS     4
-+#define IPQ9574_APSS_FUSE_CORNERS       4
-+
-+u32 g_valid_fuse_count = IPQ807x_APSS_FUSE_CORNERS;
-+
-+/**
-+ * struct cpr4_ipq807x_apss_fuses - APSS specific fuse data for IPQ807x
-+ * @ro_sel:           Ring oscillator select fuse parameter value for each
-+ *                    fuse corner
-+ * @init_voltage:     Initial (i.e. open-loop) voltage fuse parameter value
-+ *                    for each fuse corner (raw, not converted to a voltage)
-+ * @target_quot:      CPR target quotient fuse parameter value for each fuse
-+ *                    corner
-+ * @quot_offset:      CPR target quotient offset fuse parameter value for each
-+ *                    fuse corner (raw, not unpacked) used for target quotient
-+ *                    interpolation
-+ * @speed_bin:                Application processor speed bin fuse parameter value for
-+ *                    the given chip
-+ * @cpr_fusing_rev:   CPR fusing revision fuse parameter value
-+ * @boost_cfg:                CPR boost configuration fuse parameter value
-+ * @boost_voltage:    CPR boost voltage fuse parameter value (raw, not
-+ *                    converted to a voltage)
-+ *
-+ * This struct holds the values for all of the fuses read from memory.
-+ */
-+struct cpr4_ipq807x_apss_fuses {
-+      u64     ro_sel[IPQ807x_APSS_FUSE_CORNERS];
-+      u64     init_voltage[IPQ807x_APSS_FUSE_CORNERS];
-+      u64     target_quot[IPQ807x_APSS_FUSE_CORNERS];
-+      u64     quot_offset[IPQ807x_APSS_FUSE_CORNERS];
-+      u64     speed_bin;
-+      u64     cpr_fusing_rev;
-+      u64     boost_cfg;
-+      u64     boost_voltage;
-+      u64     misc;
-+};
-+
-+/*
-+ * fuse combo = fusing revision + 8 * (speed bin)
-+ * where: fusing revision = 0 - 7 and speed bin = 0 - 7
-+ */
-+#define CPR4_IPQ807x_APSS_FUSE_COMBO_COUNT    64
-+
-+/*
-+ * Constants which define the name of each fuse corner.
-+ */
-+enum cpr4_ipq807x_apss_fuse_corner {
-+      CPR4_IPQ807x_APSS_FUSE_CORNER_SVS       = 0,
-+      CPR4_IPQ807x_APSS_FUSE_CORNER_NOM       = 1,
-+      CPR4_IPQ807x_APSS_FUSE_CORNER_TURBO     = 2,
-+      CPR4_IPQ807x_APSS_FUSE_CORNER_STURBO    = 3,
-+};
-+
-+static const char * const cpr4_ipq807x_apss_fuse_corner_name[] = {
-+      [CPR4_IPQ807x_APSS_FUSE_CORNER_SVS]     = "SVS",
-+      [CPR4_IPQ807x_APSS_FUSE_CORNER_NOM]     = "NOM",
-+      [CPR4_IPQ807x_APSS_FUSE_CORNER_TURBO]   = "TURBO",
-+      [CPR4_IPQ807x_APSS_FUSE_CORNER_STURBO]  = "STURBO",
-+};
-+
-+/*
-+ * IPQ807x APSS fuse parameter locations:
-+ *
-+ * Structs are organized with the following dimensions:
-+ *    Outer: 0 to 3 for fuse corners from lowest to highest corner
-+ *    Inner: large enough to hold the longest set of parameter segments which
-+ *            fully defines a fuse parameter, +1 (for NULL termination).
-+ *            Each segment corresponds to a contiguous group of bits from a
-+ *            single fuse row.  These segments are concatentated together in
-+ *            order to form the full fuse parameter value.  The segments for
-+ *            a given parameter may correspond to different fuse rows.
-+ */
-+static struct cpr3_fuse_param
-+ipq807x_apss_ro_sel_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
-+      {{73,  8, 11}, {} },
-+      {{73,  4,  7}, {} },
-+      {{73,  0,  3}, {} },
-+      {{73, 12, 15}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq807x_apss_init_voltage_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
-+      {{71, 18, 23}, {} },
-+      {{71, 12, 17}, {} },
-+      {{71,  6, 11}, {} },
-+      {{71,  0,  5}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq807x_apss_target_quot_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
-+      {{72, 32, 43}, {} },
-+      {{72, 20, 31}, {} },
-+      {{72,  8, 19}, {} },
-+      {{72, 44, 55}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq807x_apss_quot_offset_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
-+      {{} },
-+      {{71, 46, 52}, {} },
-+      {{71, 39, 45}, {} },
-+      {{71, 32, 38}, {} },
-+};
-+
-+static struct cpr3_fuse_param ipq807x_cpr_fusing_rev_param[] = {
-+      {71, 53, 55},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq807x_apss_speed_bin_param[] = {
-+      {36, 40, 42},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq807x_cpr_boost_fuse_cfg_param[] = {
-+      {36, 43, 45},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq807x_apss_boost_fuse_volt_param[] = {
-+      {71, 0, 5},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq807x_misc_fuse_volt_adj_param[] = {
-+      {36, 54, 54},
-+      {},
-+};
-+
-+static struct cpr3_fuse_parameters ipq807x_fuse_params = {
-+      .apss_ro_sel_param = ipq807x_apss_ro_sel_param,
-+      .apss_init_voltage_param = ipq807x_apss_init_voltage_param,
-+      .apss_target_quot_param = ipq807x_apss_target_quot_param,
-+      .apss_quot_offset_param = ipq807x_apss_quot_offset_param,
-+      .cpr_fusing_rev_param = ipq807x_cpr_fusing_rev_param,
-+      .apss_speed_bin_param = ipq807x_apss_speed_bin_param,
-+      .cpr_boost_fuse_cfg_param = ipq807x_cpr_boost_fuse_cfg_param,
-+      .apss_boost_fuse_volt_param = ipq807x_apss_boost_fuse_volt_param,
-+      .misc_fuse_volt_adj_param = ipq807x_misc_fuse_volt_adj_param
-+};
-+
-+/*
-+ * The number of possible values for misc fuse is
-+ * 2^(#bits defined for misc fuse)
-+ */
-+#define IPQ807x_MISC_FUSE_VAL_COUNT           BIT(1)
-+
-+/*
-+ * Open loop voltage fuse reference voltages in microvolts for IPQ807x
-+ */
-+static int ipq807x_apss_fuse_ref_volt
-+      [IPQ807x_APSS_FUSE_CORNERS] = {
-+      720000,
-+      864000,
-+      992000,
-+      1064000,
-+};
-+
-+#define IPQ807x_APSS_FUSE_STEP_VOLT           8000
-+#define IPQ807x_APSS_VOLTAGE_FUSE_SIZE        6
-+#define IPQ807x_APSS_QUOT_OFFSET_SCALE        5
-+
-+#define IPQ807x_APSS_CPR_SENSOR_COUNT 6
-+
-+#define IPQ807x_APSS_CPR_CLOCK_RATE           19200000
-+
-+#define IPQ807x_APSS_MAX_TEMP_POINTS  3
-+#define IPQ807x_APSS_TEMP_SENSOR_ID_START     4
-+#define IPQ807x_APSS_TEMP_SENSOR_ID_END       13
-+/*
-+ * Boost voltage fuse reference and ceiling voltages in microvolts for
-+ * IPQ807x.
-+ */
-+#define IPQ807x_APSS_BOOST_FUSE_REF_VOLT      1140000
-+#define IPQ807x_APSS_BOOST_CEILING_VOLT       1140000
-+#define IPQ807x_APSS_BOOST_FLOOR_VOLT 900000
-+#define MAX_BOOST_CONFIG_FUSE_VALUE           8
-+
-+#define IPQ807x_APSS_CPR_SDELTA_CORE_COUNT    15
-+
-+#define IPQ807x_APSS_CPR_TCSR_START           8
-+#define IPQ807x_APSS_CPR_TCSR_END             9
-+
-+/*
-+ * Array of integer values mapped to each of the boost config fuse values to
-+ * indicate boost enable/disable status.
-+ */
-+static bool boost_fuse[MAX_BOOST_CONFIG_FUSE_VALUE] = {0, 1, 1, 1, 1, 1, 1, 1};
-+
-+/*
-+ * IPQ6018 (Few parameters are changed, remaining are same as IPQ807x)
-+ */
-+#define IPQ6018_APSS_FUSE_STEP_VOLT           12500
-+#define IPQ6018_APSS_CPR_CLOCK_RATE           24000000
-+
-+static struct cpr3_fuse_param
-+ipq6018_apss_ro_sel_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
-+      {{75,  8, 11}, {} },
-+      {{75,  4,  7}, {} },
-+      {{75,  0,  3}, {} },
-+      {{75, 12, 15}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq6018_apss_init_voltage_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
-+      {{73, 18, 23}, {} },
-+      {{73, 12, 17}, {} },
-+      {{73,  6, 11}, {} },
-+      {{73,  0,  5}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq6018_apss_target_quot_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
-+      {{74, 32, 43}, {} },
-+      {{74, 20, 31}, {} },
-+      {{74,  8, 19}, {} },
-+      {{74, 44, 55}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq6018_apss_quot_offset_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
-+      {{} },
-+      {{73, 48, 55}, {} },
-+      {{73, 40, 47}, {} },
-+      {{73, 32, 39}, {} },
-+};
-+
-+static struct cpr3_fuse_param ipq6018_cpr_fusing_rev_param[] = {
-+      {75, 16, 18},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq6018_apss_speed_bin_param[] = {
-+      {36, 40, 42},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq6018_cpr_boost_fuse_cfg_param[] = {
-+      {36, 43, 45},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq6018_apss_boost_fuse_volt_param[] = {
-+      {73, 0, 5},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq6018_misc_fuse_volt_adj_param[] = {
-+      {36, 54, 54},
-+      {},
-+};
-+
-+static struct cpr3_fuse_parameters ipq6018_fuse_params = {
-+      .apss_ro_sel_param = ipq6018_apss_ro_sel_param,
-+      .apss_init_voltage_param = ipq6018_apss_init_voltage_param,
-+      .apss_target_quot_param = ipq6018_apss_target_quot_param,
-+      .apss_quot_offset_param = ipq6018_apss_quot_offset_param,
-+      .cpr_fusing_rev_param = ipq6018_cpr_fusing_rev_param,
-+      .apss_speed_bin_param = ipq6018_apss_speed_bin_param,
-+      .cpr_boost_fuse_cfg_param = ipq6018_cpr_boost_fuse_cfg_param,
-+      .apss_boost_fuse_volt_param = ipq6018_apss_boost_fuse_volt_param,
-+      .misc_fuse_volt_adj_param = ipq6018_misc_fuse_volt_adj_param
-+};
-+
-+
-+/*
-+ * Boost voltage fuse reference and ceiling voltages in microvolts for
-+ * IPQ6018.
-+ */
-+#define IPQ6018_APSS_BOOST_FUSE_REF_VOLT      1140000
-+#define IPQ6018_APSS_BOOST_CEILING_VOLT       1140000
-+#define IPQ6018_APSS_BOOST_FLOOR_VOLT 900000
-+
-+/*
-+ * Open loop voltage fuse reference voltages in microvolts for IPQ807x
-+ */
-+static int ipq6018_apss_fuse_ref_volt
-+      [IPQ6018_APSS_FUSE_CORNERS] = {
-+      725000,
-+      862500,
-+      987500,
-+      1062500,
-+};
-+
-+/*
-+ * IPQ6018 Memory ACC settings on TCSR
-+ *
-+ * Turbo_L1: write TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0 0x10
-+ *           write TCSR_CUSTOM_VDDAPC0_ACC_1            0x1
-+ * Other modes: write TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0 0x0
-+ *              write TCSR_CUSTOM_VDDAPC0_ACC_1            0x0
-+ *
-+ */
-+#define IPQ6018_APSS_MEM_ACC_TCSR_COUNT         2
-+#define TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0    0x1946178
-+#define TCSR_CUSTOM_VDDAPC0_ACC_1               0x1946124
-+
-+struct mem_acc_tcsr {
-+      u32 phy_addr;
-+      void __iomem *ioremap_addr;
-+      u32 value;
-+};
-+
-+static struct mem_acc_tcsr ipq6018_mem_acc_tcsr[IPQ6018_APSS_MEM_ACC_TCSR_COUNT] = {
-+      {TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0, NULL, 0x10},
-+      {TCSR_CUSTOM_VDDAPC0_ACC_1, NULL, 0x1},
-+};
-+
-+/*
-+ * IPQ9574 (Few parameters are changed, remaining are same as IPQ6018)
-+ */
-+#define IPQ9574_APSS_FUSE_STEP_VOLT             10000
-+
-+static struct cpr3_fuse_param
-+ipq9574_apss_ro_sel_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
-+      {{107, 4, 7}, {} },
-+      {{107, 0, 3}, {} },
-+      {{106, 4, 7}, {} },
-+      {{106, 0, 3}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq9574_apss_init_voltage_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
-+      {{104, 24, 29}, {} },
-+      {{104, 18, 23}, {} },
-+      {{104, 12, 17}, {} },
-+      {{104,  6, 11}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq9574_apss_target_quot_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
-+      {{106, 32, 43}, {} },
-+      {{106, 20, 31}, {} },
-+      {{106,  8, 19}, {} },
-+      {{106, 44, 55}, {} },
-+};
-+
-+static struct cpr3_fuse_param
-+ipq9574_apss_quot_offset_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
-+      {{} },
-+      {{105, 48, 55}, {} },
-+      {{105, 40, 47}, {} },
-+      {{105, 32, 39}, {} },
-+};
-+
-+static struct cpr3_fuse_param ipq9574_cpr_fusing_rev_param[] = {
-+      {107, 8, 10},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq9574_apss_speed_bin_param[] = {
-+      {0, 40, 42},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq9574_cpr_boost_fuse_cfg_param[] = {
-+      {0, 43, 45},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq9574_apss_boost_fuse_volt_param[] = {
-+      {104, 0, 5},
-+      {},
-+};
-+
-+static struct cpr3_fuse_param ipq9574_misc_fuse_volt_adj_param[] = {
-+      {0, 54, 54},
-+      {},
-+};
-+
-+static struct cpr3_fuse_parameters ipq9574_fuse_params = {
-+      .apss_ro_sel_param = ipq9574_apss_ro_sel_param,
-+      .apss_init_voltage_param = ipq9574_apss_init_voltage_param,
-+      .apss_target_quot_param = ipq9574_apss_target_quot_param,
-+      .apss_quot_offset_param = ipq9574_apss_quot_offset_param,
-+      .cpr_fusing_rev_param = ipq9574_cpr_fusing_rev_param,
-+      .apss_speed_bin_param = ipq9574_apss_speed_bin_param,
-+      .cpr_boost_fuse_cfg_param = ipq9574_cpr_boost_fuse_cfg_param,
-+      .apss_boost_fuse_volt_param = ipq9574_apss_boost_fuse_volt_param,
-+      .misc_fuse_volt_adj_param = ipq9574_misc_fuse_volt_adj_param
-+};
-+
-+/*
-+ * Open loop voltage fuse reference voltages in microvolts for IPQ9574
-+ */
-+static int ipq9574_apss_fuse_ref_volt
-+      [IPQ9574_APSS_FUSE_CORNERS] = {
-+      725000,
-+      862500,
-+      987500,
-+      1062500,
-+};
-+
-+/**
-+ * cpr4_ipq807x_apss_read_fuse_data() - load APSS specific fuse parameter values
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * This function allocates a cpr4_ipq807x_apss_fuses struct, fills it with
-+ * values read out of hardware fuses, and finally copies common fuse values
-+ * into the CPR3 regulator struct.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_ipq807x_apss_read_fuse_data(struct cpr3_regulator *vreg)
-+{
-+      void __iomem *base = vreg->thread->ctrl->fuse_base;
-+      struct cpr4_ipq807x_apss_fuses *fuse;
-+      int i, rc;
-+
-+      fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
-+      if (!fuse)
-+              return -ENOMEM;
-+
-+      rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->apss_speed_bin_param,
-+                                &fuse->speed_bin);
-+      if (rc) {
-+              cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
-+              return rc;
-+      }
-+      cpr3_info(vreg, "speed bin = %llu\n", fuse->speed_bin);
-+
-+      rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->cpr_fusing_rev_param,
-+                                &fuse->cpr_fusing_rev);
-+      if (rc) {
-+              cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+      cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
-+
-+      rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->misc_fuse_volt_adj_param,
-+                                &fuse->misc);
-+      if (rc) {
-+              cpr3_err(vreg, "Unable to read misc voltage adjustment fuse, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+      cpr3_info(vreg, "CPR misc fuse value = %llu\n", fuse->misc);
-+      if (fuse->misc >= IPQ807x_MISC_FUSE_VAL_COUNT) {
-+              cpr3_err(vreg, "CPR misc fuse value = %llu, should be < %lu\n",
-+                      fuse->misc, IPQ807x_MISC_FUSE_VAL_COUNT);
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < g_valid_fuse_count; i++) {
-+              rc = cpr3_read_fuse_param(base,
-+                              vreg->cpr4_regulator_data->cpr3_fuse_params->apss_init_voltage_param[i],
-+                              &fuse->init_voltage[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
-+                              i, rc);
-+                      return rc;
-+              }
-+
-+              rc = cpr3_read_fuse_param(base,
-+                              vreg->cpr4_regulator_data->cpr3_fuse_params->apss_target_quot_param[i],
-+                              &fuse->target_quot[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
-+                              i, rc);
-+                      return rc;
-+              }
-+
-+              rc = cpr3_read_fuse_param(base,
-+                              vreg->cpr4_regulator_data->cpr3_fuse_params->apss_ro_sel_param[i],
-+                              &fuse->ro_sel[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
-+                              i, rc);
-+                      return rc;
-+              }
-+
-+              rc = cpr3_read_fuse_param(base,
-+                              vreg->cpr4_regulator_data->cpr3_fuse_params->apss_quot_offset_param[i],
-+                              &fuse->quot_offset[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
-+                              i, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->cpr_boost_fuse_cfg_param,
-+                                &fuse->boost_cfg);
-+      if (rc) {
-+              cpr3_err(vreg, "Unable to read CPR boost config fuse, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+      cpr3_info(vreg, "Voltage boost fuse config = %llu boost = %s\n",
-+                      fuse->boost_cfg, boost_fuse[fuse->boost_cfg]
-+                      ? "enable" : "disable");
-+
-+      rc = cpr3_read_fuse_param(base,
-+                              vreg->cpr4_regulator_data->cpr3_fuse_params->apss_boost_fuse_volt_param,
-+                              &fuse->boost_voltage);
-+      if (rc) {
-+              cpr3_err(vreg, "failed to read boost fuse voltage, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
-+      if (vreg->fuse_combo >= CPR4_IPQ807x_APSS_FUSE_COMBO_COUNT) {
-+              cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
-+                      vreg->fuse_combo);
-+              return -EINVAL;
-+      }
-+
-+      vreg->speed_bin_fuse    = fuse->speed_bin;
-+      vreg->cpr_rev_fuse      = fuse->cpr_fusing_rev;
-+      vreg->fuse_corner_count = g_valid_fuse_count;
-+      vreg->platform_fuses    = fuse;
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr4_apss_parse_corner_data() - parse APSS corner data from device tree
-+ *            properties of the CPR3 regulator's device node
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_parse_corner_data(struct cpr3_regulator *vreg)
-+{
-+      struct device_node *node = vreg->of_node;
-+      struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
-+      u32 *temp = NULL;
-+      int i, rc;
-+
-+      rc = cpr3_parse_common_corner_data(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      /* If fuse has incorrect RO Select values and dtsi has "qcom,cpr-ro-sel"
-+       * entry with RO select values other than zero, then dtsi values will
-+       * be used.
-+       */
-+      if (of_property_present(node, "qcom,cpr-ro-sel")) {
-+              temp = kcalloc(vreg->fuse_corner_count, sizeof(*temp),
-+                              GFP_KERNEL);
-+              if (!temp)
-+                      return -ENOMEM;
-+
-+              rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-sel",
-+                              vreg->fuse_corner_count, temp);
-+              if (rc)
-+                      goto done;
-+
-+              for (i = 0; i < vreg->fuse_corner_count; i++) {
-+                      if (temp[i] != 0)
-+                              fuse->ro_sel[i] = temp[i];
-+              }
-+      }
-+done:
-+      kfree(temp);
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_apss_parse_misc_fuse_voltage_adjustments() - fill an array from a
-+ *            portion of the voltage adjustments specified based on
-+ *            miscellaneous fuse bits.
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @volt_adjust:      Voltage adjustment output data array which must be
-+ *                    of size vreg->corner_count
-+ *
-+ * cpr3_parse_common_corner_data() must be called for vreg before this function
-+ * is called so that speed bin size elements are initialized.
-+ *
-+ * Two formats are supported for the device tree property:
-+ * 1. Length == tuple_list_size * vreg->corner_count
-+ *    (reading begins at index 0)
-+ * 2. Length == tuple_list_size * vreg->speed_bin_corner_sum
-+ *    (reading begins at index tuple_list_size * vreg->speed_bin_offset)
-+ *
-+ * Here, tuple_list_size is the number of possible values for misc fuse.
-+ * All other property lengths are treated as errors.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_parse_misc_fuse_voltage_adjustments(
-+      struct cpr3_regulator *vreg, u32 *volt_adjust)
-+{
-+      struct device_node *node = vreg->of_node;
-+      struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
-+      int tuple_list_size = IPQ807x_MISC_FUSE_VAL_COUNT;
-+      int i, offset, rc, len = 0;
-+      const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment";
-+
-+      if (!of_find_property(node, prop_name, &len)) {
-+              cpr3_err(vreg, "property %s is missing\n", prop_name);
-+              return -EINVAL;
-+      }
-+
-+      if (len == tuple_list_size * vreg->corner_count * sizeof(u32)) {
-+              offset = 0;
-+      } else if (vreg->speed_bin_corner_sum > 0 &&
-+                      len == tuple_list_size * vreg->speed_bin_corner_sum
-+                      * sizeof(u32)) {
-+              offset = tuple_list_size * vreg->speed_bin_offset
-+                      + fuse->misc * vreg->corner_count;
-+      } else {
-+              if (vreg->speed_bin_corner_sum > 0)
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
-+                              prop_name, len,
-+                              tuple_list_size * vreg->corner_count
-+                                      * sizeof(u32),
-+                              tuple_list_size * vreg->speed_bin_corner_sum
-+                                      * sizeof(u32));
-+              else
-+                      cpr3_err(vreg, "property %s has invalid length=%d, should be %zu\n",
-+                              prop_name, len,
-+                              tuple_list_size * vreg->corner_count
-+                              * sizeof(u32));
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              rc = of_property_read_u32_index(node, prop_name, offset + i,
-+                                              &volt_adjust[i]);
-+              if (rc) {
-+                      cpr3_err(vreg, "error reading property %s, rc=%d\n",
-+                              prop_name, rc);
-+                      return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr4_ipq807x_apss_calculate_open_loop_voltages() - calculate the open-loop
-+ *            voltage for each corner of a CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * If open-loop voltage interpolation is allowed in device tree, then
-+ * this function calculates the open-loop voltage for a given corner using
-+ * linear interpolation.  This interpolation is performed using the processor
-+ * frequencies of the lower and higher Fmax corners along with their fused
-+ * open-loop voltages.
-+ *
-+ * If open-loop voltage interpolation is not allowed, then this function uses
-+ * the Fmax fused open-loop voltage for all of the corners associated with a
-+ * given fuse corner.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_ipq807x_apss_calculate_open_loop_voltages(
-+                      struct cpr3_regulator *vreg)
-+{
-+      struct device_node *node = vreg->of_node;
-+      struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      int i, j, rc = 0;
-+      bool allow_interpolation;
-+      u64 freq_low, volt_low, freq_high, volt_high;
-+      int *fuse_volt, *misc_adj_volt;
-+      int *fmax_corner;
-+
-+      fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
-+                              GFP_KERNEL);
-+      fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
-+                              GFP_KERNEL);
-+      if (!fuse_volt || !fmax_corner) {
-+              rc = -ENOMEM;
-+              goto done;
-+      }
-+
-+      for (i = 0; i < vreg->fuse_corner_count; i++) {
-+              if (ctrl->cpr_global_setting == CPR_DISABLED)
-+                      fuse_volt[i] = vreg->cpr4_regulator_data->fuse_ref_volt[i];
-+              else
-+                      fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
-+                              vreg->cpr4_regulator_data->fuse_ref_volt[i],
-+                              vreg->cpr4_regulator_data->fuse_step_volt,
-+                              fuse->init_voltage[i],
-+                              IPQ807x_APSS_VOLTAGE_FUSE_SIZE);
-+
-+              /* Log fused open-loop voltage values for debugging purposes. */
-+              cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n",
-+                        cpr4_ipq807x_apss_fuse_corner_name[i],
-+                        fuse_volt[i]);
-+      }
-+
-+      rc = cpr3_determine_part_type(vreg,
-+                        fuse_volt[vreg->fuse_corner_count - 1]);
-+      if (rc) {
-+              cpr3_err(vreg, "fused part type detection failed failed, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
-+      if (rc) {
-+              cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      allow_interpolation = of_property_read_bool(node,
-+                              "qcom,allow-voltage-interpolation");
-+
-+      for (i = 1; i < vreg->fuse_corner_count; i++) {
-+              if (fuse_volt[i] < fuse_volt[i - 1]) {
-+                      cpr3_info(vreg, "fuse corner %d voltage=%d uV < fuse corner %d voltage=%d uV; overriding: fuse corner %d voltage=%d\n",
-+                              i, fuse_volt[i], i - 1, fuse_volt[i - 1],
-+                              i, fuse_volt[i - 1]);
-+                      fuse_volt[i] = fuse_volt[i - 1];
-+              }
-+      }
-+
-+      if (!allow_interpolation) {
-+              /* Use fused open-loop voltage for lower frequencies. */
-+              for (i = 0; i < vreg->corner_count; i++)
-+                      vreg->corner[i].open_loop_volt
-+                              = fuse_volt[vreg->corner[i].cpr_fuse_corner];
-+              goto done;
-+      }
-+
-+      /* Determine highest corner mapped to each fuse corner */
-+      j = vreg->fuse_corner_count - 1;
-+      for (i = vreg->corner_count - 1; i >= 0; i--) {
-+              if (vreg->corner[i].cpr_fuse_corner == j) {
-+                      fmax_corner[j] = i;
-+                      j--;
-+              }
-+      }
-+      if (j >= 0) {
-+              cpr3_err(vreg, "invalid fuse corner mapping\n");
-+              rc = -EINVAL;
-+              goto done;
-+      }
-+
-+      /*
-+       * Interpolation is not possible for corners mapped to the lowest fuse
-+       * corner so use the fuse corner value directly.
-+       */
-+      for (i = 0; i <= fmax_corner[0]; i++)
-+              vreg->corner[i].open_loop_volt = fuse_volt[0];
-+
-+      /* Interpolate voltages for the higher fuse corners. */
-+      for (i = 1; i < vreg->fuse_corner_count; i++) {
-+              freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
-+              volt_low = fuse_volt[i - 1];
-+              freq_high = vreg->corner[fmax_corner[i]].proc_freq;
-+              volt_high = fuse_volt[i];
-+
-+              for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
-+                      vreg->corner[j].open_loop_volt = cpr3_interpolate(
-+                              freq_low, volt_low, freq_high, volt_high,
-+                              vreg->corner[j].proc_freq);
-+      }
-+
-+done:
-+      if (rc == 0) {
-+              cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
-+              for (i = 0; i < vreg->corner_count; i++)
-+                      cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
-+                              vreg->corner[i].open_loop_volt);
-+
-+              rc = cpr3_adjust_open_loop_voltages(vreg);
-+              if (rc)
-+                      cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
-+                              rc);
-+
-+              if (of_property_present(node,
-+                      "qcom,cpr-misc-fuse-voltage-adjustment"
-+                      )) {
-+                      misc_adj_volt = kcalloc(vreg->corner_count,
-+                                      sizeof(*misc_adj_volt), GFP_KERNEL);
-+                      if (!misc_adj_volt) {
-+                              rc = -ENOMEM;
-+                              goto _exit;
-+                      }
-+
-+                      rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
-+                              misc_adj_volt);
-+                      if (rc) {
-+                              cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
-+                                      rc);
-+                              kfree(misc_adj_volt);
-+                              goto _exit;
-+                      }
-+
-+                      for (i = 0; i < vreg->corner_count; i++)
-+                              vreg->corner[i].open_loop_volt
-+                                              += misc_adj_volt[i];
-+                      kfree(misc_adj_volt);
-+              }
-+      }
-+
-+_exit:
-+      kfree(fuse_volt);
-+      kfree(fmax_corner);
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_ipq807x_apss_set_no_interpolation_quotients() - use the fused target
-+ *            quotient values for lower frequencies.
-+ * @vreg:             Pointer to the CPR3 regulator
-+ * @volt_adjust:      Pointer to array of per-corner closed-loop adjustment
-+ *                    voltages
-+ * @volt_adjust_fuse: Pointer to array of per-fuse-corner closed-loop
-+ *                    adjustment voltages
-+ * @ro_scale:         Pointer to array of per-fuse-corner RO scaling factor
-+ *                    values with units of QUOT/V
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_ipq807x_apss_set_no_interpolation_quotients(
-+                      struct cpr3_regulator *vreg, int *volt_adjust,
-+                      int *volt_adjust_fuse, int *ro_scale)
-+{
-+      struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
-+      u32 quot, ro;
-+      int quot_adjust;
-+      int i, fuse_corner;
-+
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              fuse_corner = vreg->corner[i].cpr_fuse_corner;
-+              quot = fuse->target_quot[fuse_corner];
-+              quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
-+                                         volt_adjust_fuse[fuse_corner] +
-+                                         volt_adjust[i]);
-+              ro = fuse->ro_sel[fuse_corner];
-+              vreg->corner[i].target_quot[ro] = quot + quot_adjust;
-+              cpr3_debug(vreg, "corner=%d RO=%u target quot=%u\n",
-+                        i, ro, quot);
-+
-+              if (quot_adjust)
-+                      cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %u --> %u (%d uV)\n",
-+                                i, ro, quot, vreg->corner[i].target_quot[ro],
-+                                volt_adjust_fuse[fuse_corner] +
-+                                volt_adjust[i]);
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr4_ipq807x_apss_calculate_target_quotients() - calculate the CPR target
-+ *            quotient for each corner of a CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * If target quotient interpolation is allowed in device tree, then this
-+ * function calculates the target quotient for a given corner using linear
-+ * interpolation.  This interpolation is performed using the processor
-+ * frequencies of the lower and higher Fmax corners along with the fused
-+ * target quotient and quotient offset of the higher Fmax corner.
-+ *
-+ * If target quotient interpolation is not allowed, then this function uses
-+ * the Fmax fused target quotient for all of the corners associated with a
-+ * given fuse corner.
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_ipq807x_apss_calculate_target_quotients(
-+                      struct cpr3_regulator *vreg)
-+{
-+      struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
-+      int rc;
-+      bool allow_interpolation;
-+      u64 freq_low, freq_high, prev_quot;
-+      u64 *quot_low;
-+      u64 *quot_high;
-+      u32 quot, ro;
-+      int i, j, fuse_corner, quot_adjust;
-+      int *fmax_corner;
-+      int *volt_adjust, *volt_adjust_fuse, *ro_scale;
-+      int *voltage_adj_misc;
-+
-+      /* Log fused quotient values for debugging purposes. */
-+      for (i = CPR4_IPQ807x_APSS_FUSE_CORNER_SVS;
-+              i < vreg->fuse_corner_count; i++)
-+              cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu, quot_offset[%2llu]=%4llu\n",
-+                      cpr4_ipq807x_apss_fuse_corner_name[i],
-+                      fuse->ro_sel[i], fuse->target_quot[i],
-+                      fuse->ro_sel[i], fuse->quot_offset[i] *
-+                      IPQ807x_APSS_QUOT_OFFSET_SCALE);
-+
-+      allow_interpolation = of_property_read_bool(vreg->of_node,
-+                                      "qcom,allow-quotient-interpolation");
-+
-+      volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
-+                                      GFP_KERNEL);
-+      volt_adjust_fuse = kcalloc(vreg->fuse_corner_count,
-+                                      sizeof(*volt_adjust_fuse), GFP_KERNEL);
-+      ro_scale = kcalloc(vreg->fuse_corner_count, sizeof(*ro_scale),
-+                                      GFP_KERNEL);
-+      fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
-+                                      GFP_KERNEL);
-+      quot_low = kcalloc(vreg->fuse_corner_count, sizeof(*quot_low),
-+                                      GFP_KERNEL);
-+      quot_high = kcalloc(vreg->fuse_corner_count, sizeof(*quot_high),
-+                                      GFP_KERNEL);
-+      if (!volt_adjust || !volt_adjust_fuse || !ro_scale ||
-+          !fmax_corner || !quot_low || !quot_high) {
-+              rc = -ENOMEM;
-+              goto done;
-+      }
-+
-+      rc = cpr3_parse_closed_loop_voltage_adjustments(vreg, &fuse->ro_sel[0],
-+                              volt_adjust, volt_adjust_fuse, ro_scale);
-+      if (rc) {
-+              cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
-+                      rc);
-+              goto done;
-+      }
-+
-+      if (of_property_present(vreg->of_node,
-+              "qcom,cpr-misc-fuse-voltage-adjustment")) {
-+              voltage_adj_misc = kcalloc(vreg->corner_count,
-+                              sizeof(*voltage_adj_misc), GFP_KERNEL);
-+              if (!voltage_adj_misc) {
-+                      rc = -ENOMEM;
-+                      goto done;
-+              }
-+
-+              rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
-+                      voltage_adj_misc);
-+              if (rc) {
-+                      cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
-+                              rc);
-+                      kfree(voltage_adj_misc);
-+                      goto done;
-+              }
-+
-+              for (i = 0; i < vreg->corner_count; i++)
-+                      volt_adjust[i] += voltage_adj_misc[i];
-+
-+              kfree(voltage_adj_misc);
-+      }
-+
-+      if (!allow_interpolation) {
-+              /* Use fused target quotients for lower frequencies. */
-+              return cpr4_ipq807x_apss_set_no_interpolation_quotients(
-+                              vreg, volt_adjust, volt_adjust_fuse, ro_scale);
-+      }
-+
-+      /* Determine highest corner mapped to each fuse corner */
-+      j = vreg->fuse_corner_count - 1;
-+      for (i = vreg->corner_count - 1; i >= 0; i--) {
-+              if (vreg->corner[i].cpr_fuse_corner == j) {
-+                      fmax_corner[j] = i;
-+                      j--;
-+              }
-+      }
-+      if (j >= 0) {
-+              cpr3_err(vreg, "invalid fuse corner mapping\n");
-+              rc = -EINVAL;
-+              goto done;
-+      }
-+
-+      /*
-+       * Interpolation is not possible for corners mapped to the lowest fuse
-+       * corner so use the fuse corner value directly.
-+       */
-+      i = CPR4_IPQ807x_APSS_FUSE_CORNER_SVS;
-+      quot_adjust = cpr3_quot_adjustment(ro_scale[i], volt_adjust_fuse[i]);
-+      quot = fuse->target_quot[i] + quot_adjust;
-+      quot_high[i] = quot_low[i] = quot;
-+      ro = fuse->ro_sel[i];
-+      if (quot_adjust)
-+              cpr3_debug(vreg, "adjusted fuse corner %d RO%u target quot: %llu --> %u (%d uV)\n",
-+                      i, ro, fuse->target_quot[i], quot, volt_adjust_fuse[i]);
-+
-+      for (i = 0; i <= fmax_corner[CPR4_IPQ807x_APSS_FUSE_CORNER_SVS];
-+              i++)
-+              vreg->corner[i].target_quot[ro] = quot;
-+
-+      for (i = CPR4_IPQ807x_APSS_FUSE_CORNER_NOM;
-+           i < vreg->fuse_corner_count; i++) {
-+              quot_high[i] = fuse->target_quot[i];
-+              if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
-+                      quot_low[i] = quot_high[i - 1];
-+              else
-+                      quot_low[i] = quot_high[i]
-+                                      - fuse->quot_offset[i]
-+                                        * IPQ807x_APSS_QUOT_OFFSET_SCALE;
-+              if (quot_high[i] < quot_low[i]) {
-+                      cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu; overriding: quot_high[%d]=%llu\n",
-+                              i, quot_high[i], i, quot_low[i],
-+                              i, quot_low[i]);
-+                      quot_high[i] = quot_low[i];
-+              }
-+      }
-+
-+      /* Perform per-fuse-corner target quotient adjustment */
-+      for (i = 1; i < vreg->fuse_corner_count; i++) {
-+              quot_adjust = cpr3_quot_adjustment(ro_scale[i],
-+                                                 volt_adjust_fuse[i]);
-+              if (quot_adjust) {
-+                      prev_quot = quot_high[i];
-+                      quot_high[i] += quot_adjust;
-+                      cpr3_debug(vreg, "adjusted fuse corner %d RO%llu target quot: %llu --> %llu (%d uV)\n",
-+                              i, fuse->ro_sel[i], prev_quot, quot_high[i],
-+                              volt_adjust_fuse[i]);
-+              }
-+
-+              if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
-+                      quot_low[i] = quot_high[i - 1];
-+              else
-+                      quot_low[i] += cpr3_quot_adjustment(ro_scale[i],
-+                                                  volt_adjust_fuse[i - 1]);
-+
-+              if (quot_high[i] < quot_low[i]) {
-+                      cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu after adjustment; overriding: quot_high[%d]=%llu\n",
-+                              i, quot_high[i], i, quot_low[i],
-+                              i, quot_low[i]);
-+                      quot_high[i] = quot_low[i];
-+              }
-+      }
-+
-+      /* Interpolate voltages for the higher fuse corners. */
-+      for (i = 1; i < vreg->fuse_corner_count; i++) {
-+              freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
-+              freq_high = vreg->corner[fmax_corner[i]].proc_freq;
-+
-+              ro = fuse->ro_sel[i];
-+              for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
-+                      vreg->corner[j].target_quot[ro] = cpr3_interpolate(
-+                              freq_low, quot_low[i], freq_high, quot_high[i],
-+                              vreg->corner[j].proc_freq);
-+      }
-+
-+      /* Perform per-corner target quotient adjustment */
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              fuse_corner = vreg->corner[i].cpr_fuse_corner;
-+              ro = fuse->ro_sel[fuse_corner];
-+              quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
-+                                                 volt_adjust[i]);
-+              if (quot_adjust) {
-+                      prev_quot = vreg->corner[i].target_quot[ro];
-+                      vreg->corner[i].target_quot[ro] += quot_adjust;
-+                      cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %llu --> %u (%d uV)\n",
-+                              i, ro, prev_quot,
-+                              vreg->corner[i].target_quot[ro],
-+                              volt_adjust[i]);
-+              }
-+      }
-+
-+      /* Ensure that target quotients increase monotonically */
-+      for (i = 1; i < vreg->corner_count; i++) {
-+              ro = fuse->ro_sel[vreg->corner[i].cpr_fuse_corner];
-+              if (fuse->ro_sel[vreg->corner[i - 1].cpr_fuse_corner] == ro
-+                  && vreg->corner[i].target_quot[ro]
-+                              < vreg->corner[i - 1].target_quot[ro]) {
-+                      cpr3_debug(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
-+                              i, ro, vreg->corner[i].target_quot[ro],
-+                              i - 1, ro, vreg->corner[i - 1].target_quot[ro],
-+                              i, ro, vreg->corner[i - 1].target_quot[ro]);
-+                      vreg->corner[i].target_quot[ro]
-+                              = vreg->corner[i - 1].target_quot[ro];
-+              }
-+      }
-+
-+done:
-+      kfree(volt_adjust);
-+      kfree(volt_adjust_fuse);
-+      kfree(ro_scale);
-+      kfree(fmax_corner);
-+      kfree(quot_low);
-+      kfree(quot_high);
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_apss_print_settings() - print out APSS CPR configuration settings into
-+ *            the kernel log for debugging purposes
-+ * @vreg:             Pointer to the CPR3 regulator
-+ */
-+static void cpr4_apss_print_settings(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_corner *corner;
-+      int i;
-+
-+      cpr3_debug(vreg, "Corner: Frequency (Hz), Fuse Corner, Floor (uV), Open-Loop (uV), Ceiling (uV)\n");
-+      for (i = 0; i < vreg->corner_count; i++) {
-+              corner = &vreg->corner[i];
-+              cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
-+                      i, corner->proc_freq, corner->cpr_fuse_corner,
-+                      corner->floor_volt, corner->open_loop_volt,
-+                      corner->ceiling_volt);
-+      }
-+
-+      if (vreg->thread->ctrl->apm)
-+              cpr3_debug(vreg, "APM threshold = %d uV, APM adjust = %d uV\n",
-+                      vreg->thread->ctrl->apm_threshold_volt,
-+                      vreg->thread->ctrl->apm_adj_volt);
-+}
-+
-+/**
-+ * cpr4_apss_init_thread() - perform steps necessary to initialize the
-+ *            configuration data for a CPR3 thread
-+ * @thread:           Pointer to the CPR3 thread
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_init_thread(struct cpr3_thread *thread)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_common_thread_data(thread);
-+      if (rc) {
-+              cpr3_err(thread->ctrl, "thread %u unable to read CPR thread data from device tree, rc=%d\n",
-+                      thread->thread_id, rc);
-+              return rc;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * cpr4_apss_parse_temp_adj_properties() - parse temperature based
-+ *            adjustment properties from device tree.
-+ * @ctrl:     Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_parse_temp_adj_properties(struct cpr3_controller *ctrl)
-+{
-+      struct device_node *of_node = ctrl->dev->of_node;
-+      int rc, i, len, temp_point_count;
-+
-+      if (!of_find_property(of_node, "qcom,cpr-temp-point-map", &len)) {
-+              /*
-+               * Temperature based adjustments are not defined. Single
-+               * temperature band is still valid for per-online-core
-+               * adjustments.
-+               */
-+              ctrl->temp_band_count = 1;
-+              return 0;
-+      }
-+
-+      temp_point_count = len / sizeof(u32);
-+      if (temp_point_count <= 0 ||
-+          temp_point_count > IPQ807x_APSS_MAX_TEMP_POINTS) {
-+              cpr3_err(ctrl, "invalid number of temperature points %d > %d (max)\n",
-+                       temp_point_count, IPQ807x_APSS_MAX_TEMP_POINTS);
-+              return -EINVAL;
-+      }
-+
-+      ctrl->temp_points = devm_kcalloc(ctrl->dev, temp_point_count,
-+                                      sizeof(*ctrl->temp_points), GFP_KERNEL);
-+      if (!ctrl->temp_points)
-+              return -ENOMEM;
-+
-+      rc = of_property_read_u32_array(of_node, "qcom,cpr-temp-point-map",
-+                                      ctrl->temp_points, temp_point_count);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading property qcom,cpr-temp-point-map, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      for (i = 0; i < temp_point_count; i++)
-+              cpr3_debug(ctrl, "Temperature Point %d=%d\n", i,
-+                                 ctrl->temp_points[i]);
-+
-+      /*
-+       * If t1, t2, and t3 are the temperature points, then the temperature
-+       * bands are: (-inf, t1], (t1, t2], (t2, t3], and (t3, inf).
-+       */
-+      ctrl->temp_band_count = temp_point_count + 1;
-+      cpr3_debug(ctrl, "Number of temp bands =%d\n", ctrl->temp_band_count);
-+
-+      rc = of_property_read_u32(of_node, "qcom,cpr-initial-temp-band",
-+                                &ctrl->initial_temp_band);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading qcom,cpr-initial-temp-band, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      if (ctrl->initial_temp_band >= ctrl->temp_band_count) {
-+              cpr3_err(ctrl, "Initial temperature band value %d should be in range [0 - %d]\n",
-+                      ctrl->initial_temp_band, ctrl->temp_band_count - 1);
-+              return -EINVAL;
-+      }
-+
-+      ctrl->temp_sensor_id_start = IPQ807x_APSS_TEMP_SENSOR_ID_START;
-+      ctrl->temp_sensor_id_end = IPQ807x_APSS_TEMP_SENSOR_ID_END;
-+      ctrl->allow_temp_adj = true;
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_apss_parse_boost_properties() - parse configuration data for boost
-+ *            voltage adjustment for CPR3 regulator from device tree.
-+ * @vreg:     Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_parse_boost_properties(struct cpr3_regulator *vreg)
-+{
-+      struct cpr3_controller *ctrl = vreg->thread->ctrl;
-+      struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
-+      struct cpr3_corner *corner;
-+      int i, boost_voltage, final_boost_volt, rc = 0;
-+      int *boost_table = NULL, *boost_temp_adj = NULL;
-+      int boost_voltage_adjust = 0, boost_num_cores = 0;
-+      u32 boost_allowed = 0;
-+
-+      if (!boost_fuse[fuse->boost_cfg])
-+              /* Voltage boost is disabled in fuse */
-+              return 0;
-+
-+      if (of_property_present(vreg->of_node, "qcom,allow-boost")) {
-+              rc = cpr3_parse_array_property(vreg, "qcom,allow-boost", 1,
-+                              &boost_allowed);
-+              if (rc)
-+                      return rc;
-+      }
-+
-+      if (!boost_allowed) {
-+              /* Voltage boost is not enabled for this regulator */
-+              return 0;
-+      }
-+
-+      boost_voltage = cpr3_convert_open_loop_voltage_fuse(
-+                              vreg->cpr4_regulator_data->boost_fuse_ref_volt,
-+                              vreg->cpr4_regulator_data->fuse_step_volt,
-+                              fuse->boost_voltage,
-+                              IPQ807x_APSS_VOLTAGE_FUSE_SIZE);
-+
-+      /* Log boost voltage value for debugging purposes. */
-+      cpr3_info(vreg, "Boost open-loop=%7d uV\n", boost_voltage);
-+
-+      if (of_property_present(vreg->of_node,
-+                      "qcom,cpr-boost-voltage-fuse-adjustment")) {
-+              rc = cpr3_parse_array_property(vreg,
-+                      "qcom,cpr-boost-voltage-fuse-adjustment",
-+                      1, &boost_voltage_adjust);
-+              if (rc) {
-+                      cpr3_err(vreg, "qcom,cpr-boost-voltage-fuse-adjustment reading failed, rc=%d\n",
-+                              rc);
-+                      return rc;
-+              }
-+
-+              boost_voltage += boost_voltage_adjust;
-+              /* Log boost voltage value for debugging purposes. */
-+              cpr3_info(vreg, "Adjusted boost open-loop=%7d uV\n",
-+                      boost_voltage);
-+      }
-+
-+      /* Limit boost voltage value between ceiling and floor voltage limits */
-+      boost_voltage = min(boost_voltage, vreg->cpr4_regulator_data->boost_ceiling_volt);
-+      boost_voltage = max(boost_voltage, vreg->cpr4_regulator_data->boost_floor_volt);
-+
-+      /*
-+       * The boost feature can only be used for the highest voltage corner.
-+       * Also, keep core-count adjustments disabled when the boost feature
-+       * is enabled.
-+       */
-+      corner = &vreg->corner[vreg->corner_count - 1];
-+      if (!corner->sdelta) {
-+              /*
-+               * If core-count/temp adjustments are not defined, the cpr4
-+               * sdelta for this corner will not be allocated. Allocate it
-+               * here for boost configuration.
-+               */
-+              corner->sdelta = devm_kzalloc(ctrl->dev,
-+                                      sizeof(*corner->sdelta), GFP_KERNEL);
-+              if (!corner->sdelta)
-+                      return -ENOMEM;
-+      }
-+      corner->sdelta->temp_band_count = ctrl->temp_band_count;
-+
-+      rc = of_property_read_u32(vreg->of_node, "qcom,cpr-num-boost-cores",
-+                              &boost_num_cores);
-+      if (rc) {
-+              cpr3_err(vreg, "qcom,cpr-num-boost-cores reading failed, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      if (boost_num_cores <= 0 ||
-+          boost_num_cores > IPQ807x_APSS_CPR_SDELTA_CORE_COUNT) {
-+              cpr3_err(vreg, "Invalid boost number of cores = %d\n",
-+                      boost_num_cores);
-+              return -EINVAL;
-+      }
-+      corner->sdelta->boost_num_cores = boost_num_cores;
-+
-+      boost_table = devm_kcalloc(ctrl->dev, corner->sdelta->temp_band_count,
-+                                      sizeof(*boost_table), GFP_KERNEL);
-+      if (!boost_table)
-+              return -ENOMEM;
-+
-+      if (of_property_present(vreg->of_node,
-+                              "qcom,cpr-boost-temp-adjustment")) {
-+              boost_temp_adj = kcalloc(corner->sdelta->temp_band_count,
-+                                      sizeof(*boost_temp_adj), GFP_KERNEL);
-+              if (!boost_temp_adj)
-+                      return -ENOMEM;
-+
-+              rc = cpr3_parse_array_property(vreg,
-+                              "qcom,cpr-boost-temp-adjustment",
-+                              corner->sdelta->temp_band_count,
-+                              boost_temp_adj);
-+              if (rc) {
-+                      cpr3_err(vreg, "qcom,cpr-boost-temp-adjustment reading failed, rc=%d\n",
-+                              rc);
-+                      goto done;
-+              }
-+      }
-+
-+      for (i = 0; i < corner->sdelta->temp_band_count; i++) {
-+              /* Apply static adjustments to boost voltage */
-+              final_boost_volt = boost_voltage + (boost_temp_adj == NULL
-+                                              ? 0 : boost_temp_adj[i]);
-+              /*
-+               * Limit final adjusted boost voltage value between ceiling
-+               * and floor voltage limits
-+               */
-+              final_boost_volt = min(final_boost_volt,
-+                                      vreg->cpr4_regulator_data->boost_ceiling_volt);
-+              final_boost_volt = max(final_boost_volt,
-+                                      vreg->cpr4_regulator_data->boost_floor_volt);
-+
-+              boost_table[i] = (corner->open_loop_volt - final_boost_volt)
-+                                      / ctrl->step_volt;
-+              cpr3_debug(vreg, "Adjusted boost voltage margin for temp band %d = %d steps\n",
-+                      i, boost_table[i]);
-+      }
-+
-+      corner->ceiling_volt = vreg->cpr4_regulator_data->boost_ceiling_volt;
-+      corner->sdelta->boost_table = boost_table;
-+      corner->sdelta->allow_boost = true;
-+      corner->sdelta->allow_core_count_adj = false;
-+      vreg->allow_boost = true;
-+      ctrl->allow_boost = true;
-+done:
-+      kfree(boost_temp_adj);
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_apss_init_regulator() - perform all steps necessary to initialize the
-+ *            configuration data for a CPR3 regulator
-+ * @vreg:             Pointer to the CPR3 regulator
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg)
-+{
-+      struct cpr4_ipq807x_apss_fuses *fuse;
-+      int rc;
-+
-+      rc = cpr4_ipq807x_apss_read_fuse_data(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      fuse = vreg->platform_fuses;
-+
-+      rc = cpr4_apss_parse_corner_data(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_mem_acc_init(vreg);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(vreg, "unable to initialize mem-acc regulator settings, rc=%d\n",
-+                               rc);
-+              return rc;
-+      }
-+
-+      rc = cpr4_ipq807x_apss_calculate_open_loop_voltages(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_limit_open_loop_voltages(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      cpr3_open_loop_voltage_as_ceiling(vreg);
-+
-+      rc = cpr3_limit_floor_voltages(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      rc = cpr4_ipq807x_apss_calculate_target_quotients(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to calculate target quotients, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      rc = cpr4_parse_core_count_temp_voltage_adj(vreg, false);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to parse temperature and core count voltage adjustments, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      if (vreg->allow_core_count_adj && (vreg->max_core_count <= 0
-+                                 || vreg->max_core_count >
-+                                 IPQ807x_APSS_CPR_SDELTA_CORE_COUNT)) {
-+              cpr3_err(vreg, "qcom,max-core-count has invalid value = %d\n",
-+                       vreg->max_core_count);
-+              return -EINVAL;
-+      }
-+
-+      rc = cpr4_apss_parse_boost_properties(vreg);
-+      if (rc) {
-+              cpr3_err(vreg, "unable to parse boost adjustments, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      cpr4_apss_print_settings(vreg);
-+
-+      return rc;
-+}
-+
-+/**
-+ * cpr4_apss_init_controller() - perform APSS CPR4 controller specific
-+ *            initializations
-+ * @ctrl:             Pointer to the CPR3 controller
-+ *
-+ * Return: 0 on success, errno on failure
-+ */
-+static int cpr4_apss_init_controller(struct cpr3_controller *ctrl)
-+{
-+      int rc;
-+
-+      rc = cpr3_parse_common_ctrl_data(ctrl);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
-+                              rc);
-+              return rc;
-+      }
-+
-+      rc = of_property_read_u32(ctrl->dev->of_node,
-+                                "qcom,cpr-down-error-step-limit",
-+                                &ctrl->down_error_step_limit);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading qcom,cpr-down-error-step-limit, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      rc = of_property_read_u32(ctrl->dev->of_node,
-+                                "qcom,cpr-up-error-step-limit",
-+                                &ctrl->up_error_step_limit);
-+      if (rc) {
-+              cpr3_err(ctrl, "error reading qcom,cpr-up-error-step-limit, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      /*
-+       * Use fixed step quotient if specified otherwise use dynamic
-+       * calculated per RO step quotient
-+       */
-+      of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-step-quot-fixed",
-+                      &ctrl->step_quot_fixed);
-+      ctrl->use_dynamic_step_quot = ctrl->step_quot_fixed ? false : true;
-+
-+      ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node,
-+                                      "qcom,cpr-saw-use-unit-mV");
-+
-+      of_property_read_u32(ctrl->dev->of_node,
-+                      "qcom,cpr-voltage-settling-time",
-+                      &ctrl->voltage_settling_time);
-+
-+      if (of_property_present(ctrl->dev->of_node, "vdd-limit-supply")) {
-+              ctrl->vdd_limit_regulator =
-+                      devm_regulator_get(ctrl->dev, "vdd-limit");
-+              if (IS_ERR(ctrl->vdd_limit_regulator)) {
-+                      rc = PTR_ERR(ctrl->vdd_limit_regulator);
-+                      if (rc != -EPROBE_DEFER)
-+                              cpr3_err(ctrl, "unable to request vdd-limit regulator, rc=%d\n",
-+                                       rc);
-+                      return rc;
-+              }
-+      }
-+
-+      rc = cpr3_apm_init(ctrl);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(ctrl, "unable to initialize APM settings, rc=%d\n",
-+                              rc);
-+              return rc;
-+      }
-+
-+      rc = cpr4_apss_parse_temp_adj_properties(ctrl);
-+      if (rc) {
-+              cpr3_err(ctrl, "unable to parse temperature adjustment properties, rc=%d\n",
-+                       rc);
-+              return rc;
-+      }
-+
-+      ctrl->sensor_count = IPQ807x_APSS_CPR_SENSOR_COUNT;
-+
-+      /*
-+       * APSS only has one thread (0) per controller so the zeroed
-+       * array does not need further modification.
-+       */
-+      ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
-+              sizeof(*ctrl->sensor_owner), GFP_KERNEL);
-+      if (!ctrl->sensor_owner)
-+              return -ENOMEM;
-+
-+      ctrl->ctrl_type = CPR_CTRL_TYPE_CPR4;
-+      ctrl->supports_hw_closed_loop = false;
-+      ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
-+                                              "qcom,cpr-hw-closed-loop");
-+      return 0;
-+}
-+
-+static int cpr4_apss_regulator_suspend(struct platform_device *pdev,
-+                              pm_message_t state)
-+{
-+      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
-+
-+      return cpr3_regulator_suspend(ctrl);
-+}
-+
-+static int cpr4_apss_regulator_resume(struct platform_device *pdev)
-+{
-+      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
-+
-+      return cpr3_regulator_resume(ctrl);
-+}
-+
-+static void ipq6018_set_mem_acc(struct regulator_dev *rdev)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+
-+      ipq6018_mem_acc_tcsr[0].ioremap_addr =
-+              ioremap(ipq6018_mem_acc_tcsr[0].phy_addr, 0x4);
-+      ipq6018_mem_acc_tcsr[1].ioremap_addr =
-+              ioremap(ipq6018_mem_acc_tcsr[1].phy_addr, 0x4);
-+
-+      if ((ipq6018_mem_acc_tcsr[0].ioremap_addr != NULL) &&
-+                      (ipq6018_mem_acc_tcsr[1].ioremap_addr != NULL) &&
-+                      (vreg->current_corner == (vreg->corner_count - CPR3_CORNER_OFFSET))) {
-+
-+              writel_relaxed(ipq6018_mem_acc_tcsr[0].value,
-+                              ipq6018_mem_acc_tcsr[0].ioremap_addr);
-+              writel_relaxed(ipq6018_mem_acc_tcsr[1].value,
-+                              ipq6018_mem_acc_tcsr[1].ioremap_addr);
-+      }
-+}
-+
-+static void ipq6018_clr_mem_acc(struct regulator_dev *rdev)
-+{
-+      struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
-+
-+      if ((ipq6018_mem_acc_tcsr[0].ioremap_addr != NULL) &&
-+                      (ipq6018_mem_acc_tcsr[1].ioremap_addr != NULL) &&
-+                      (vreg->current_corner != vreg->corner_count - CPR3_CORNER_OFFSET)) {
-+              writel_relaxed(0x0, ipq6018_mem_acc_tcsr[0].ioremap_addr);
-+              writel_relaxed(0x0, ipq6018_mem_acc_tcsr[1].ioremap_addr);
-+      }
-+
-+      iounmap(ipq6018_mem_acc_tcsr[0].ioremap_addr);
-+      iounmap(ipq6018_mem_acc_tcsr[1].ioremap_addr);
-+}
-+
-+static struct cpr4_mem_acc_func ipq6018_mem_acc_funcs = {
-+      .set_mem_acc = ipq6018_set_mem_acc,
-+      .clear_mem_acc = ipq6018_clr_mem_acc
-+};
-+
-+static const struct cpr4_reg_data ipq807x_cpr_apss = {
-+      .cpr_valid_fuse_count = IPQ807x_APSS_FUSE_CORNERS,
-+      .fuse_ref_volt = ipq807x_apss_fuse_ref_volt,
-+      .fuse_step_volt = IPQ807x_APSS_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ807x_APSS_CPR_CLOCK_RATE,
-+      .boost_fuse_ref_volt= IPQ807x_APSS_BOOST_FUSE_REF_VOLT,
-+      .boost_ceiling_volt= IPQ807x_APSS_BOOST_CEILING_VOLT,
-+      .boost_floor_volt= IPQ807x_APSS_BOOST_FLOOR_VOLT,
-+      .cpr3_fuse_params = &ipq807x_fuse_params,
-+      .mem_acc_funcs = NULL,
-+};
-+
-+static const struct cpr4_reg_data ipq817x_cpr_apss = {
-+      .cpr_valid_fuse_count = IPQ817x_APPS_FUSE_CORNERS,
-+      .fuse_ref_volt = ipq807x_apss_fuse_ref_volt,
-+      .fuse_step_volt = IPQ807x_APSS_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ807x_APSS_CPR_CLOCK_RATE,
-+      .boost_fuse_ref_volt= IPQ807x_APSS_BOOST_FUSE_REF_VOLT,
-+      .boost_ceiling_volt= IPQ807x_APSS_BOOST_CEILING_VOLT,
-+      .boost_floor_volt= IPQ807x_APSS_BOOST_FLOOR_VOLT,
-+      .cpr3_fuse_params = &ipq807x_fuse_params,
-+      .mem_acc_funcs = NULL,
-+};
-+
-+static const struct cpr4_reg_data ipq6018_cpr_apss = {
-+      .cpr_valid_fuse_count = IPQ6018_APSS_FUSE_CORNERS,
-+      .fuse_ref_volt = ipq6018_apss_fuse_ref_volt,
-+      .fuse_step_volt = IPQ6018_APSS_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ6018_APSS_CPR_CLOCK_RATE,
-+      .boost_fuse_ref_volt = IPQ6018_APSS_BOOST_FUSE_REF_VOLT,
-+      .boost_ceiling_volt = IPQ6018_APSS_BOOST_CEILING_VOLT,
-+      .boost_floor_volt = IPQ6018_APSS_BOOST_FLOOR_VOLT,
-+      .cpr3_fuse_params = &ipq6018_fuse_params,
-+      .mem_acc_funcs = &ipq6018_mem_acc_funcs,
-+};
-+
-+static const struct cpr4_reg_data ipq9574_cpr_apss = {
-+      .cpr_valid_fuse_count = IPQ9574_APSS_FUSE_CORNERS,
-+      .fuse_ref_volt = ipq9574_apss_fuse_ref_volt,
-+      .fuse_step_volt = IPQ9574_APSS_FUSE_STEP_VOLT,
-+      .cpr_clk_rate = IPQ6018_APSS_CPR_CLOCK_RATE,
-+      .boost_fuse_ref_volt = IPQ6018_APSS_BOOST_FUSE_REF_VOLT,
-+      .boost_ceiling_volt = IPQ6018_APSS_BOOST_CEILING_VOLT,
-+      .boost_floor_volt = IPQ6018_APSS_BOOST_FLOOR_VOLT,
-+      .cpr3_fuse_params = &ipq9574_fuse_params,
-+      .mem_acc_funcs = NULL,
-+};
-+
-+static const struct of_device_id cpr4_regulator_match_table[] = {
-+      {
-+              .compatible = "qcom,cpr4-ipq807x-apss-regulator",
-+              .data = &ipq807x_cpr_apss
-+      },
-+      {
-+              .compatible = "qcom,cpr4-ipq817x-apss-regulator",
-+              .data = &ipq817x_cpr_apss
-+      },
-+      {
-+              .compatible = "qcom,cpr4-ipq6018-apss-regulator",
-+              .data = &ipq6018_cpr_apss
-+      },
-+      {
-+              .compatible = "qcom,cpr4-ipq9574-apss-regulator",
-+              .data = &ipq9574_cpr_apss
-+      },
-+      {}
-+};
-+
-+static int cpr4_apss_regulator_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct cpr3_controller *ctrl;
-+      const struct cpr4_reg_data *cpr_data;
-+      int i, rc;
-+
-+      if (!dev->of_node) {
-+              dev_err(dev, "Device tree node is missing\n");
-+              return -EINVAL;
-+      }
-+
-+      ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
-+      if (!ctrl)
-+              return -ENOMEM;
-+
-+      cpr_data = of_device_get_match_data(&pdev->dev);
-+      g_valid_fuse_count = cpr_data->cpr_valid_fuse_count;
-+      dev_info(dev, "CPR valid fuse count: %d\n", g_valid_fuse_count);
-+      ctrl->cpr_clock_rate = cpr_data->cpr_clk_rate;
-+
-+      ctrl->dev = dev;
-+      /* Set to false later if anything precludes CPR operation. */
-+      ctrl->cpr_allowed_hw = true;
-+
-+      rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
-+                                      &ctrl->name);
-+      if (rc) {
-+              cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      rc = cpr3_map_fuse_base(ctrl, pdev);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not map fuse base address\n");
-+              return rc;
-+      }
-+
-+      rc = cpr3_read_tcsr_setting(ctrl, pdev, IPQ807x_APSS_CPR_TCSR_START,
-+                                  IPQ807x_APSS_CPR_TCSR_END);
-+      if (rc) {
-+              cpr3_err(ctrl, "could not read CPR tcsr setting\n");
-+              return rc;
-+      }
-+
-+      rc = cpr3_allocate_threads(ctrl, 0, 0);
-+      if (rc) {
-+              cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
-+                      rc);
-+              return rc;
-+      }
-+
-+      if (ctrl->thread_count != 1) {
-+              cpr3_err(ctrl, "expected 1 thread but found %d\n",
-+                      ctrl->thread_count);
-+              return -EINVAL;
-+      }
-+
-+      rc = cpr4_apss_init_controller(ctrl);
-+      if (rc) {
-+              if (rc != -EPROBE_DEFER)
-+                      cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
-+                              rc);
-+              return rc;
-+      }
-+
-+      rc = cpr4_apss_init_thread(&ctrl->thread[0]);
-+      if (rc) {
-+              cpr3_err(ctrl, "thread initialization failed, rc=%d\n", rc);
-+              return rc;
-+      }
-+
-+      for (i = 0; i < ctrl->thread[0].vreg_count; i++) {
-+              ctrl->thread[0].vreg[i].cpr4_regulator_data = cpr_data;
-+              rc = cpr4_apss_init_regulator(&ctrl->thread[0].vreg[i]);
-+              if (rc) {
-+                      cpr3_err(&ctrl->thread[0].vreg[i], "regulator initialization failed, rc=%d\n",
-+                               rc);
-+                      return rc;
-+              }
-+      }
-+
-+      platform_set_drvdata(pdev, ctrl);
-+
-+      return cpr3_regulator_register(pdev, ctrl);
-+}
-+
-+static void cpr4_apss_regulator_remove(struct platform_device *pdev)
-+{
-+      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
-+
-+      cpr3_regulator_unregister(ctrl);
-+}
-+
-+static struct platform_driver cpr4_apss_regulator_driver = {
-+      .driver         = {
-+              .name           = "qcom,cpr4-apss-regulator",
-+              .of_match_table = cpr4_regulator_match_table,
-+      },
-+      .probe          = cpr4_apss_regulator_probe,
-+      .remove         = cpr4_apss_regulator_remove,
-+      .suspend        = cpr4_apss_regulator_suspend,
-+      .resume         = cpr4_apss_regulator_resume,
-+};
-+
-+static int cpr4_regulator_init(void)
-+{
-+      return platform_driver_register(&cpr4_apss_regulator_driver);
-+}
-+
-+static void cpr4_regulator_exit(void)
-+{
-+      platform_driver_unregister(&cpr4_apss_regulator_driver);
-+}
-+
-+MODULE_DESCRIPTION("CPR4 APSS regulator driver");
-+MODULE_LICENSE("GPL v2");
-+
-+arch_initcall(cpr4_regulator_init);
-+module_exit(cpr4_regulator_exit);
diff --git a/target/linux/qualcommax/patches-6.12/0902-arm64-dts-ipq8074-add-label-to-clocks.patch b/target/linux/qualcommax/patches-6.12/0902-arm64-dts-ipq8074-add-label-to-clocks.patch
deleted file mode 100644 (file)
index 9b8b4df..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From 6baf7e4abcea6f7ac21eccf072a20078b39d064c Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 9 Feb 2022 23:13:26 +0100
-Subject: [PATCH] arm64: dts: ipq8074: add label to clocks
-
-Add label to clocks node as that makes it easy to add the NSS fixed
-clocks that are required in their DTSI.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -15,7 +15,7 @@
-       compatible = "qcom,ipq8074";
-       interrupt-parent = <&intc>;
--      clocks {
-+      clocks: clocks {
-               sleep_clk: sleep_clk {
-                       compatible = "fixed-clock";
-                       clock-frequency = <32768>;
diff --git a/target/linux/qualcommax/patches-6.12/0903-psci-dont-advertise-OSI-support-for-IPQ6018.patch b/target/linux/qualcommax/patches-6.12/0903-psci-dont-advertise-OSI-support-for-IPQ6018.patch
deleted file mode 100644 (file)
index 5fcb900..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-From 563db68137475d011b355bfe674d1b7a24778091 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Sat, 8 Oct 2022 22:26:31 +0200
-Subject: [PATCH] psci: dont advertise OSI support for IPQ6018
-
-Some older IPQ60xx SoC series boards ship with TrustZone/QSEE firmware
-older than TZ.WNS.5.1-00084 which will advertise OSI[1] but are broken
-and trying to use OSI will cause the board to hang until WDT kicks in.
-
-So workaround it by checking for SoC compatible and returning false so
-OSI is not used.
-
-[1] https://www.spinics.net/lists/linux-arm-msm/msg79916.html
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/firmware/psci/psci.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/firmware/psci/psci.c
-+++ b/drivers/firmware/psci/psci.c
-@@ -87,6 +87,18 @@ static inline bool psci_has_ext_power_st
- bool psci_has_osi_support(void)
- {
-+      /*
-+       * Some older IPQ60xx SoC series boards ship with
-+       * TrustZone/QSEE firmware older than TZ.WNS.5.1-00084
-+       * which will advertise OSI but is broken and trying
-+       * to use OSI will cause the board to hang until WDT
-+       * kicks in.
-+       * So workaround it by checking for SoC compatible
-+       * and returning false so OSI is not used.
-+       */
-+      if (of_machine_is_compatible("qcom,ipq6018"))
-+              return false;
-+
-       return psci_cpu_suspend_feature & PSCI_1_0_OS_INITIATED;
- }
diff --git a/target/linux/qualcommax/patches-6.12/0904-clk-qcom-ipq6018-workaround-networking-clock-parenti.patch b/target/linux/qualcommax/patches-6.12/0904-clk-qcom-ipq6018-workaround-networking-clock-parenti.patch
deleted file mode 100644 (file)
index 30c6ece..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-From 0c5b5243ad55ae744e790ba90c5ad37a93bd1377 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Tue, 11 Oct 2022 23:38:45 +0200
-Subject: [PATCH] clk: qcom: ipq6018: workaround networking clock parenting
-
-Currently, networking clocks are only looked up by fw_name however,
-these are registered and setup by SSDK and are not available to the
-GCC driver at all, so work around that by providing a global name
-fallback.
-
-While we are here, provide global fallback for bias_pll_cc_clk and
-bias_pll_nss_noc_clk as well as these are fixed clocks also not available
-to the driver.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/clk/qcom/gcc-ipq6018.c | 39 +++++++++++++++++-----------------
- 1 file changed, 19 insertions(+), 20 deletions(-)
-
---- a/drivers/clk/qcom/gcc-ipq6018.c
-+++ b/drivers/clk/qcom/gcc-ipq6018.c
-@@ -360,7 +360,7 @@ static const struct freq_tbl ftbl_nss_pp
- static const struct clk_parent_data gcc_xo_bias_gpll0_gpll4_nss_ubi32[] = {
-       { .fw_name = "xo" },
--      { .fw_name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
-       { .hw = &gpll0.clkr.hw },
-       { .hw = &gpll4.clkr.hw },
-       { .hw = &nss_crypto_pll.clkr.hw },
-@@ -534,12 +534,12 @@ static const struct freq_multi_tbl ftbl_
- static const struct clk_parent_data
- gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
-       { .fw_name = "xo" },
--      { .fw_name = "uniphy0_gcc_rx_clk" },
--      { .fw_name = "uniphy0_gcc_tx_clk" },
--      { .fw_name = "uniphy1_gcc_rx_clk" },
--      { .fw_name = "uniphy1_gcc_tx_clk" },
-+      { .fw_name = "uniphy0_gcc_rx_clk", .name = "uniphy0_gcc_rx_clk" },
-+      { .fw_name = "uniphy0_gcc_tx_clk", .name = "uniphy0_gcc_tx_clk" },
-+      { .fw_name = "uniphy1_gcc_rx_clk", .name = "uniphy1_gcc_rx_clk" },
-+      { .fw_name = "uniphy1_gcc_tx_clk", .name = "uniphy1_gcc_tx_clk" },
-       { .hw = &ubi32_pll.clkr.hw },
--      { .fw_name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map
-@@ -589,12 +589,12 @@ static const struct freq_multi_tbl ftbl_
- static const struct clk_parent_data
- gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
-       { .fw_name = "xo" },
--      { .fw_name = "uniphy0_gcc_tx_clk" },
--      { .fw_name = "uniphy0_gcc_rx_clk" },
--      { .fw_name = "uniphy1_gcc_tx_clk" },
--      { .fw_name = "uniphy1_gcc_rx_clk" },
-+      { .fw_name = "uniphy0_gcc_tx_clk", .name = "uniphy0_gcc_tx_clk" },
-+      { .fw_name = "uniphy0_gcc_rx_clk", .name = "uniphy0_gcc_rx_clk" },
-+      { .fw_name = "uniphy1_gcc_tx_clk", .name = "uniphy1_gcc_tx_clk" },
-+      { .fw_name = "uniphy1_gcc_rx_clk", .name = "uniphy1_gcc_rx_clk" },
-       { .hw = &ubi32_pll.clkr.hw },
--      { .fw_name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map
-@@ -730,10 +730,10 @@ static const struct freq_tbl ftbl_nss_po
- static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_ubi32_bias[] = {
-       { .fw_name = "xo" },
--      { .fw_name = "uniphy0_gcc_rx_clk" },
--      { .fw_name = "uniphy0_gcc_tx_clk" },
-+      { .fw_name = "uniphy0_gcc_rx_clk", .name = "uniphy0_gcc_rx_clk" },
-+      { .fw_name = "uniphy0_gcc_tx_clk", .name = "uniphy0_gcc_tx_clk" },
-       { .hw = &ubi32_pll.clkr.hw },
--      { .fw_name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map gcc_xo_uniphy0_rx_tx_ubi32_bias_map[] = {
-@@ -766,10 +766,10 @@ static const struct freq_tbl ftbl_nss_po
- static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_ubi32_bias[] = {
-       { .fw_name = "xo" },
--      { .fw_name = "uniphy0_gcc_tx_clk" },
--      { .fw_name = "uniphy0_gcc_rx_clk" },
-+      { .fw_name = "uniphy0_gcc_tx_clk", .name = "uniphy0_gcc_tx_clk" },
-+      { .fw_name = "uniphy0_gcc_rx_clk", .name = "uniphy0_gcc_rx_clk" },
-       { .hw = &ubi32_pll.clkr.hw },
--      { .fw_name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map gcc_xo_uniphy0_tx_rx_ubi32_bias_map[] = {
-@@ -1915,12 +1915,11 @@ static const struct freq_tbl ftbl_ubi32_
-       { }
- };
--static const struct clk_parent_data
--                      gcc_xo_gpll0_gpll2_bias_pll_nss_noc_clk[] = {
-+static const struct clk_parent_data gcc_xo_gpll0_gpll2_bias_pll_nss_noc_clk[] = {
-       { .fw_name = "xo" },
-       { .hw = &gpll0.clkr.hw },
-       { .hw = &gpll2.clkr.hw },
--      { .fw_name = "bias_pll_nss_noc_clk" },
-+      { .fw_name = "bias_pll_nss_noc_clk", .name = "bias_pll_nss_noc_clk" },
- };
- static const struct parent_map gcc_xo_gpll0_gpll2_bias_pll_nss_noc_clk_map[] = {
diff --git a/target/linux/qualcommax/patches-6.12/0905-remoteproc-q6v5_wcss-change-ssr-name-for-ipq6018-wif.patch b/target/linux/qualcommax/patches-6.12/0905-remoteproc-q6v5_wcss-change-ssr-name-for-ipq6018-wif.patch
deleted file mode 100644 (file)
index af7f45c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-From 505f9c8653fc218ca47a153ec58ebc16bef5502f Mon Sep 17 00:00:00 2001
-From: Mantas Pucka <mantas@8devices.com>
-Date: Tue, 16 Jan 2024 10:42:40 +0200
-Subject: [PATCH 16/19] remoteproc: q6v5_wcss: change ssr name for ipq6018 wifi
- subsystem
-
-On IPQ6018 this string ends up being sent to RPM when remoteproc stops
-(on crash or rmmod ath11k). "q6wcss" is not a valid name (not found by
-`strings` in rpm.mbn), so this causes RPM do 'something' (presumably crash)
-causing a system reboot followed by hang in XBL, with no WDT running.
-Let's change ssr_name to a more sensible 'wcnss', that does not cause such
-issues.
-
-Signed-off-by: Mantas Pucka <mantas@8devices.com>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -1143,9 +1143,9 @@ static int q6v5_wcss_probe(struct platfo
-       if (ret)
-               return ret;
--      qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
-+      qcom_add_glink_subdev(rproc, &wcss->glink_subdev, desc->ssr_name);
-       qcom_add_pdm_subdev(rproc, &wcss->pdm_subdev);
--      qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
-+      qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, desc->ssr_name);
-       if (desc->ssctl_id)
-               wcss->sysmon = qcom_add_sysmon_subdev(rproc,
-@@ -1195,7 +1195,7 @@ static const struct wcss_data wcss_ipq60
-       .aon_reset_required = true,
-       .wcss_q6_reset_required = true,
-       .bcr_reset_required = false,
--      .ssr_name = "q6wcss",
-+      .ssr_name = "wcnss",
-       .ops = &q6v5_wcss_ipq8074_ops,
-       .requires_force_stop = true,
-       .need_mem_protection = true,
diff --git a/target/linux/qualcommax/patches-6.12/0906-arm64-dts-qcom-ipq6018-add-wifi-node.patch b/target/linux/qualcommax/patches-6.12/0906-arm64-dts-qcom-ipq6018-add-wifi-node.patch
deleted file mode 100644 (file)
index aac8cd5..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-From 153c74fc80b9f33ed1a50d7790bf6979fdceb370 Mon Sep 17 00:00:00 2001
-From: Mantas Pucka <mantas@8devices.com>
-Date: Tue, 16 Jan 2024 11:41:06 +0200
-Subject: [PATCH 19/19] arm64: dts: qcom: ipq6018: add wifi node
-
-IPQ6018 has a AHB based Q6v5 802.11ax radios that are supported
-by the ath11k.
-
-Add the required DT node to enable the built-in radios.
-
-Signed-off-by: Mantas Pucka <mantas@8devices.com>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 96 +++++++++++++++++++++++++++++++++++
- 1 file changed, 96 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -831,6 +831,102 @@
-                       };
-               };
-+              wifi: wifi@c000000 {
-+                      compatible = "qcom,ipq6018-wifi";
-+                      reg = <0x0 0xc000000 0x0 0x1000000>;
-+                      qcom,rproc = <&q6v5_wcss>;
-+                      interrupts = <GIC_SPI 320 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 319 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 318 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 317 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 316 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 315 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 314 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 311 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 310 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 40 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 302 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 301 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 293 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 292 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 291 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 290 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 289 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 288 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 239 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 236 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 235 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 234 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 233 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 232 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 231 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 230 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 228 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 224 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 223 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 163 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 160 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 159 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 158 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 157 IRQ_TYPE_EDGE_RISING>,
-+                                   <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
-+                      interrupt-names = "misc-pulse1", "misc-latch", "sw-exception",
-+                                        "watchdog", "ce0", "ce1", "ce2", "ce3", "ce4",
-+                                        "ce5", "ce6", "ce7", "ce8", "ce9", "ce10",
-+                                        "ce11", "host2wbm-desc-feed",
-+                                        "host2reo-re-injection", "host2reo-command",
-+                                        "host2rxdma-monitor-ring3",
-+                                        "host2rxdma-monitor-ring2",
-+                                        "host2rxdma-monitor-ring1",
-+                                        "reo2ost-exception", "wbm2host-rx-release",
-+                                        "reo2host-status",
-+                                        "reo2host-destination-ring4",
-+                                        "reo2host-destination-ring3",
-+                                        "reo2host-destination-ring2",
-+                                        "reo2host-destination-ring1",
-+                                        "rxdma2host-monitor-destination-mac3",
-+                                        "rxdma2host-monitor-destination-mac2",
-+                                        "rxdma2host-monitor-destination-mac1",
-+                                        "ppdu-end-interrupts-mac3",
-+                                        "ppdu-end-interrupts-mac2",
-+                                        "ppdu-end-interrupts-mac1",
-+                                        "rxdma2host-monitor-status-ring-mac3",
-+                                        "rxdma2host-monitor-status-ring-mac2",
-+                                        "rxdma2host-monitor-status-ring-mac1",
-+                                        "host2rxdma-host-buf-ring-mac3",
-+                                        "host2rxdma-host-buf-ring-mac2",
-+                                        "host2rxdma-host-buf-ring-mac1",
-+                                        "rxdma2host-destination-ring-mac3",
-+                                        "rxdma2host-destination-ring-mac2",
-+                                        "rxdma2host-destination-ring-mac1",
-+                                        "host2tcl-input-ring4",
-+                                        "host2tcl-input-ring3",
-+                                        "host2tcl-input-ring2",
-+                                        "host2tcl-input-ring1",
-+                                        "wbm2host-tx-completions-ring3",
-+                                        "wbm2host-tx-completions-ring2",
-+                                        "wbm2host-tx-completions-ring1",
-+                                        "tcl2host-status-ring";
-+                      status = "disabled";
-+              };
-+
-               q6v5_wcss: remoteproc@cd00000 {
-                       compatible = "qcom,ipq6018-wcss-pil";
-                       reg = <0x0 0x0cd00000 0x0 0x4040>,
diff --git a/target/linux/qualcommax/patches-6.12/0907-soc-qcom-fix-smp2p-ack-on-ipq6018.patch b/target/linux/qualcommax/patches-6.12/0907-soc-qcom-fix-smp2p-ack-on-ipq6018.patch
deleted file mode 100644 (file)
index 9dc8cd4..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From d93936f175bd914067df8f63f5fbe6e3b77bb4d2 Mon Sep 17 00:00:00 2001
-From: Mantas Pucka <mantas@8devices.com>
-Date: Tue, 23 May 2023 14:46:28 +0300
-Subject: [PATCH 11/19] soc: qcom: fix smp2p ack on ipq6018
-
-IPQ6018 seem to need different ack mechanism for smp2p messaging. This
-fixes q6v5_wcss remoteproc firmware reloading. Without this first load
-is OK, but subsequent loads would hang and fail to complete.
-
-Signed-off-by: Mantas Pucka <mantas@8devices.com>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi | 1 +
- drivers/soc/qcom/smp2p.c              | 6 +++++-
- 2 files changed, 6 insertions(+), 1 deletion(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -1183,6 +1183,7 @@
-               wcss_smp2p_out: master-kernel {
-                       qcom,entry-name = "master-kernel";
-+                      qcom,smp2p-feature-ssr-ack;
-                       #qcom,smem-state-cells = <1>;
-               };
---- a/drivers/soc/qcom/smp2p.c
-+++ b/drivers/soc/qcom/smp2p.c
-@@ -159,6 +159,8 @@ struct qcom_smp2p {
-       struct list_head inbound;
-       struct list_head outbound;
-+
-+      bool need_ssr_ack;
- };
- #define CREATE_TRACE_POINTS
-@@ -316,7 +318,7 @@ static irqreturn_t qcom_smp2p_intr(int i
-               ack_restart = qcom_smp2p_check_ssr(smp2p);
-               qcom_smp2p_notify_in(smp2p);
--              if (ack_restart)
-+              if (ack_restart || smp2p->need_ssr_ack)
-                       qcom_smp2p_do_ssr_ack(smp2p);
-       }
-@@ -447,6 +449,7 @@ static int qcom_smp2p_outbound_entry(str
-       /* Make the logical entry reference the physical value */
-       entry->value = &out->entries[out->valid_entries].value;
-+      smp2p->need_ssr_ack = of_property_read_bool(node, "qcom,smp2p-feature-ssr-ack");
-       out->valid_entries++;
diff --git a/target/linux/qualcommax/patches-6.12/0908-remoteproc-qcom_q6v5_wcss-add-optional-qdss_at-clock.patch b/target/linux/qualcommax/patches-6.12/0908-remoteproc-qcom_q6v5_wcss-add-optional-qdss_at-clock.patch
deleted file mode 100644 (file)
index ae2e500..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-From 87dbcc69a7e3fe6ccddf4fe9bdbf51330f5e4a77 Mon Sep 17 00:00:00 2001
-From: Mantas Pucka <mantas@8devices.com>
-Date: Tue, 23 Jan 2024 11:04:04 +0200
-Subject: [PATCH] remoteproc: qcom_q6v5_wcss: add optional qdss_at clock
-
-IPQ6018 needs QDSS_AT clock enabled when loading wifi. Optionally enable it
-when provided by DT.
-
-Signed-off-by: Mantas Pucka <mantas@8devices.com>
----
- drivers/remoteproc/qcom_q6v5_wcss.c | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
---- a/drivers/remoteproc/qcom_q6v5_wcss.c
-+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
-@@ -120,6 +120,7 @@ struct q6v5_wcss {
-       struct clk *qdsp6ss_core_gfmux;
-       struct clk *lcc_bcr_sleep;
-       struct clk *prng_clk;
-+      struct clk *qdss_clk;
-       struct regulator *cx_supply;
-       struct qcom_sysmon *sysmon;
-@@ -260,6 +261,9 @@ static int q6v5_wcss_start(struct rproc
-               return ret;
-       }
-+      if (wcss->qdss_clk)
-+              clk_prepare_enable(wcss->qdss_clk);
-+
-       qcom_q6v5_prepare(&wcss->q6v5);
-       if (wcss->need_mem_protection) {
-@@ -773,6 +777,8 @@ static int q6v5_wcss_stop(struct rproc *
-       }
- pas_done:
-+      if (wcss->qdss_clk)
-+              clk_disable_unprepare(wcss->qdss_clk);
-       clk_disable_unprepare(wcss->prng_clk);
-       qcom_q6v5_unprepare(&wcss->q6v5);
-@@ -981,6 +987,12 @@ static int ipq_init_clock(struct q6v5_wc
-                       dev_err(wcss->dev, "Failed to get prng clock\n");
-               return ret;
-       }
-+
-+      wcss->qdss_clk = devm_clk_get(wcss->dev, "qdss");
-+      if (IS_ERR(wcss->qdss_clk)) {
-+              wcss->qdss_clk = NULL;
-+      }
-+
-       return 0;
- }
diff --git a/target/linux/qualcommax/patches-6.12/0909-arm64-dts-qcom-ipq6018-assign-QDSS_AT-clock-to-wifi-.patch b/target/linux/qualcommax/patches-6.12/0909-arm64-dts-qcom-ipq6018-assign-QDSS_AT-clock-to-wifi-.patch
deleted file mode 100644 (file)
index 2a2fa5f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From 71f30e25d21ae4981ecef6653a4ba7dfeb80db7b Mon Sep 17 00:00:00 2001
-From: Mantas Pucka <mantas@8devices.com>
-Date: Tue, 23 Jan 2024 11:04:57 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq6018: assign QDSS_AT clock to wifi remoteproc
-
-IPQ6018 needs to enable QDSS_AT clock when loading wifi firmware,
-add it to wifi remoteproc clock list.
-
-Signed-off-by: Mantas Pucka <mantas@8devices.com>
----
- arch/arm64/boot/dts/qcom/ipq6018.dtsi          | 15 ++++++++-------
- 1 file changed, 9 insertions(+), 8 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
-@@ -952,8 +952,8 @@
-                                     "wcss_reset",
-                                     "wcss_q6_reset";
--                      clocks = <&gcc GCC_PRNG_AHB_CLK>;
--                      clock-names = "prng";
-+                      clocks = <&gcc GCC_PRNG_AHB_CLK>, <&gcc GCC_QDSS_AT_CLK>;
-+                      clock-names = "prng", "qdss" ;
-                       qcom,halt-regs = <&tcsr 0x18000 0x1b000 0xe000>;
diff --git a/target/linux/qualcommax/patches-6.12/0911-arm64-cmdline-replacement.patch b/target/linux/qualcommax/patches-6.12/0911-arm64-cmdline-replacement.patch
deleted file mode 100644 (file)
index 127677d..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-Subject: qualcommax: add kernel cmdline replacement hack 
-
-Add kernel command line replacement hack to qualcommax. Now we can
-find and replace arguments in the kernel command line by setting
-bootargs-find-1, bootargs-replace-1, bootargs-exact-match-1
-and bootargs-find-2, bootargs-replace-2, bootargs-exact-match-2
-under the chosen node in the device tree.
-
-This hack replaces the first occurence of bootargs-find-X with
-bootargs-replace-X. If bootargs-exact-match-X is set to "y",
-then the replacement happens only if the kernel command line is
-identical to bootargs-find-X.
-
-Signed-off-by: Qiyuan Zhang <zhang.github@outlook.com>
----
- drivers/of/fdt.c |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 71 insertions(+)
-
---- a/drivers/of/fdt.c
-+++ b/drivers/of/fdt.c
-@@ -1021,6 +1021,14 @@ int __init early_init_dt_scan_chosen(cha
-       const void *rng_seed;
-       const void *fdt = initial_boot_params;
-+      int i, cmd_len, f_len, r_len, offset, step;
-+      char *s_ptr, *l_end, *r_end, *cur_ptr, *end_ptr;
-+      const char *exact_match;
-+      const int bootargs_replace_num = 2;
-+      const char *bootargs_replace_props[2][3] =
-+              { {"bootargs-find-1", "bootargs-replace-1", "bootargs-exact-match-1"},
-+              {"bootargs-find-2", "bootargs-replace-2", "bootargs-exact-match-2"} };
-+
-       node = fdt_path_offset(fdt, "/chosen");
-       if (node < 0)
-               node = fdt_path_offset(fdt, "/chosen@0");
-@@ -1049,6 +1057,69 @@ int __init early_init_dt_scan_chosen(cha
-       p = of_get_flat_dt_prop(node, "bootargs", &l);
-       if (p != NULL && l > 0)
-               strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE));
-+
-+      for(i = 0; i < bootargs_replace_num; i++) {
-+              p = of_get_flat_dt_prop(node, bootargs_replace_props[i][0], &f_len);
-+
-+              if (p == NULL || f_len == 0 )
-+                      continue;
-+
-+              exact_match = of_get_flat_dt_prop(node, bootargs_replace_props[i][2], &l);
-+
-+              if (exact_match != NULL && l > 0 && exact_match[0] == 'y') {
-+                      if(strncmp(cmdline, p, r_len) == 0)
-+                              s_ptr = cmdline;
-+                      else
-+                              s_ptr = NULL;
-+              } else {
-+                      s_ptr = strstr(cmdline, p);
-+              }
-+
-+              if(!s_ptr)
-+                      continue;
-+
-+              p = of_get_flat_dt_prop(node, bootargs_replace_props[i][1], &r_len);
-+
-+              if (p == NULL || r_len == 0)
-+                      continue;
-+
-+              pr_info("Input kernel commad line: %s\n", cmdline);
-+
-+              cmd_len = strlen(cmdline);
-+
-+              if (cmd_len - f_len + r_len < COMMAND_LINE_SIZE) {
-+
-+                      pr_info("Replace kernel command line with %s\n", bootargs_replace_props[i][1]);
-+
-+                      offset = r_len - f_len;
-+
-+                      if (offset != 0) {
-+                              l_end = s_ptr + f_len - 1;
-+                              r_end = cmdline + cmd_len;
-+
-+                              if (offset > 0) {
-+                                      step = -1;
-+                                      cur_ptr = r_end;
-+                                      end_ptr = l_end + step;
-+                              } else {
-+                                      step = 1;
-+                                      cur_ptr = l_end;
-+                                      end_ptr = r_end + step;
-+                              }
-+
-+                              for (; cur_ptr != end_ptr; cur_ptr += step)
-+                                      *(cur_ptr + offset) = *cur_ptr;
-+                      }
-+
-+                      memcpy(s_ptr, p, r_len - 1);
-+
-+                      pr_info("Kernel command line after replacement: %s\n", cmdline);
-+              } else {
-+                      pr_err("Replace kernel command line with %s failed\n", bootargs_replace_props[i][1]);
-+              }
-+
-+      }
-+
-       p = of_get_flat_dt_prop(node, "bootargs-append", &l);
-       if (p != NULL && l > 0)
-               strlcat(cmdline, p, COMMAND_LINE_SIZE);
diff --git a/target/linux/qualcommax/patches-6.12/0912-arm64-dts-qcom-ipq5018-remove-cpufreq-scaling.patch b/target/linux/qualcommax/patches-6.12/0912-arm64-dts-qcom-ipq5018-remove-cpufreq-scaling.patch
deleted file mode 100644 (file)
index 8432679..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From 08910d6f438475bafec40654ff1c3e722d34d809 Mon Sep 17 00:00:00 2001
-From: Robert Senderek <robert.senderek@10g.pl>
-Date: Thu, 25 Dec 2025 12:14:46 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq5018:  remove cpufreq scaling
-
-ipq5018 do not support freq scaling and therefore stuck on 800Mhz
-This patch allows CPU to run with 1.008 Ghz as designed
-
-Signed-off-by: Robert Senderek <robert.senderek@10g.pl>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 6 ------
- 1 file changed, 6 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -95,12 +95,6 @@
-               compatible = "operating-points-v2";
-               opp-shared;
--              opp-800000000 {
--                      opp-hz = /bits/ 64 <800000000>;
--                      opp-microvolt = <1100000>;
--                      clock-latency-ns = <200000>;
--              };
--
-               opp-1008000000 {
-                       opp-hz = /bits/ 64 <1008000000>;
-                       opp-microvolt = <1100000>;
diff --git a/target/linux/qualcommax/patches-6.12/0917-clk-qcom-gcc-ipq6018-mark-gcc_xo_clk_src-as-critical.patch b/target/linux/qualcommax/patches-6.12/0917-clk-qcom-gcc-ipq6018-mark-gcc_xo_clk_src-as-critical.patch
deleted file mode 100644 (file)
index 1844803..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From: John Crispin <john@phrozen.org>
-Date: Wed, 05 Mar 2026 12:00:00 +0100
-Subject: clk: qcom: gcc-ipq6018: mark gcc_xo_clk_src as critical
-
-The XO clock source is always-on in hardware and cannot be gated.
-Without CLK_IS_CRITICAL, runtime PM of downstream consumers (such as
-the CMN PLL driver) cascades a disable up to gcc_xo_clk_src, causing
-a branch status timeout warning.
-
-The IPQ8074 GCC driver already marks this clock as CLK_IS_CRITICAL.
-Apply the same fix to IPQ6018.
-
-Signed-off-by: John Crispin <john@phrozen.org>
----
- drivers/clk/qcom/gcc-ipq6018.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/qcom/gcc-ipq6018.c
-+++ b/drivers/clk/qcom/gcc-ipq6018.c
-@@ -400,7 +400,7 @@ static struct clk_branch gcc_xo_clk_src
-                               .fw_name = "xo",
-                       },
-                       .num_parents = 1,
--                      .flags = CLK_SET_RATE_PARENT,
-+                      .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
-                       .ops = &clk_branch2_ops,
-               },
-       },
diff --git a/target/linux/qualcommax/patches-6.12/0920-clk-add-clk_hw_recalc_rate-to-trigger-HW-clk-rate-re.patch b/target/linux/qualcommax/patches-6.12/0920-clk-add-clk_hw_recalc_rate-to-trigger-HW-clk-rate-re.patch
deleted file mode 100644 (file)
index 7344439..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-From 49ae1f081626f1a8c91b283d06868a178a0a2e5a Mon Sep 17 00:00:00 2001
-From: Christian Marangi <ansuelsmth@gmail.com>
-Date: Tue, 17 Mar 2026 17:41:45 +0100
-Subject: [PATCH] clk: add clk_hw_recalc_rate() to trigger HW clk rate
- recalculation
-
-There is currently a latent problem with HW clk that only expose a
-.recalc_rate OP and doesn't have a .set_rate() and also have the
-CLK_GET_RATE_NOCACHE flag set. In such case the rate in clk core is
-parsed only (and set) only at init and when the full clk_set_rate()
-is called. In every other case .recalc_rate() is never called.
-
-It's also possible that an HW clk of this type, initially report 0 as rate
-as the register are still not configured and the HW clk effectively doesn't
-return any rate.
-
-This gets especially problematic when a clock provider use such clk as a
-parent and require the rate for parent selection for the final rate
-calculation.
-
-In such case, since the HW clk rate is never updated after init, it's still
-0 and cause problems with any other HW clk that use .determine_rate() or
-.round_rate() and search for the closest rate using clk_hw_get_rate() on
-the parents.
-
-This doesn't happen if the full clk_get_rate() is used instead as it will
-check if CLK_GET_RATE_NOCACHE is set and recalculate the rate accordingly.
-
-Updating the clk_hw_get_rate() to align to what clk_get_rate() does is not
-possible as it should be lockless and might cause problems in any user of
-clk_hw_get_rate().
-
-A more safe approach is the introduction of a direct function that triggers
-the HW clk rate recalculation, clk_hw_recalc_rate().
-
-Any driver that implement an HW clk that entirely depends on some register
-to configure the rate (that are externally configured) and have only
-.recalc_rate() and set CLK_GET_RATE_NOCACHE (aka the case where the HW clk
-rate actually change and depends on the external register configuration)
-will have to call clk_hw_recalc_rate() on the HW clk after changing the
-register configuration to sync the CCF with the new rate for the HW clk.
-
-Example:
-
- - All register zero -> HW clk rate = 0
- - PCS configure USXGMII mode -> HW clk rate = 0
- - PCS call clk_hw_recalc_rate() -> HW clk rate = 312MHz
- - Port goes UP
- - PCS/MAC scale the PHY port clock correctly by having
-   the correct reference clock as parent (instead of 0)
-
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
----
- drivers/clk/clk.c            | 23 +++++++++++++++++++++++
- include/linux/clk-provider.h |  1 +
- 2 files changed, 24 insertions(+)
-
---- a/drivers/clk/clk.c
-+++ b/drivers/clk/clk.c
-@@ -1990,6 +1990,29 @@ static unsigned long clk_core_get_rate_r
- }
- /**
-+ * clk_hw_recalc_rate - trigger rate recalculation for clk_hw
-+ * @hw: clk_hw associated with the clk to recalculate for
-+ *
-+ * Use clk_hw_recalc_rate() for the hw clk where the rate
-+ * entirely depend on register configuration and doesn't have
-+ * a .set_rate() OP. In such case, after modifying the register
-+ * that would change the rate for the hw clk, call
-+ * clk_hw_recalc_rate() to sync the CCF with the new clk rate.
-+ */
-+void clk_hw_recalc_rate(const struct clk_hw *hw)
-+{
-+      struct clk_core *core = hw->core;
-+
-+      if (!core || !(core->flags & CLK_GET_RATE_NOCACHE))
-+              return;
-+
-+      clk_prepare_lock();
-+      __clk_recalc_rates(core, false, 0);
-+      clk_prepare_unlock();
-+}
-+EXPORT_SYMBOL_GPL(clk_hw_recalc_rate);
-+
-+/**
-  * clk_get_rate - return the rate of clk
-  * @clk: the clk whose rate is being returned
-  *
---- a/include/linux/clk-provider.h
-+++ b/include/linux/clk-provider.h
-@@ -1355,6 +1355,7 @@ int clk_hw_get_parent_index(struct clk_h
- int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *new_parent);
- unsigned int __clk_get_enable_count(struct clk *clk);
- unsigned long clk_hw_get_rate(const struct clk_hw *hw);
-+void clk_hw_recalc_rate(const struct clk_hw *hw);
- unsigned long clk_hw_get_flags(const struct clk_hw *hw);
- #define clk_hw_can_set_rate_parent(hw) \
-       (clk_hw_get_flags((hw)) & CLK_SET_RATE_PARENT)
diff --git a/target/linux/qualcommax/patches-6.12/0950-net-dsa-add-out-of-band-tagging-protocol.patch b/target/linux/qualcommax/patches-6.12/0950-net-dsa-add-out-of-band-tagging-protocol.patch
deleted file mode 100644 (file)
index 142c8bb..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-From a32e16b3c2fc1954ad6e09737439f60e5890278e Mon Sep 17 00:00:00 2001
-From: Maxime Chevallier <maxime.chevallier@bootlin.com>
-Date: Fri, 4 Nov 2022 18:41:49 +0100
-Subject: [PATCH] net: dsa: add out-of-band tagging protocol
-
-This tagging protocol is designed for the situation where the link
-between the MAC and the Switch is designed such that the Destination
-Port, which is usually embedded in some part of the Ethernet Header, is
-sent out-of-band, and isn't present at all in the Ethernet frame.
-
-This can happen when the MAC and Switch are tightly integrated on an
-SoC, as is the case with the Qualcomm IPQ4019 for example, where the DSA
-tag is inserted directly into the DMA descriptors. In that case,
-the MAC driver is responsible for sending the tag to the switch using
-the out-of-band medium. To do so, the MAC driver needs to have the
-information of the destination port for that skb.
-
-Add a new tagging protocol based on SKB extensions to convey the
-information about the destination port to the MAC driver
-
-Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
----
- Documentation/networking/dsa/dsa.rst | 13 +++++++-
- MAINTAINERS                          |  1 +
- include/linux/dsa/oob.h              | 16 +++++++++
- include/linux/skbuff.h               |  3 ++
- include/net/dsa.h                    |  2 ++
- net/core/skbuff.c                    | 10 ++++++
- net/dsa/Kconfig                      |  9 +++++
- net/dsa/Makefile                     |  1 +
- net/dsa/tag_oob.c                    | 49 ++++++++++++++++++++++++++++
- 9 files changed, 103 insertions(+), 1 deletion(-)
- create mode 100644 include/linux/dsa/oob.h
- create mode 100644 net/dsa/tag_oob.c
-
---- a/Documentation/networking/dsa/dsa.rst
-+++ b/Documentation/networking/dsa/dsa.rst
-@@ -70,7 +70,8 @@ Switch tagging protocols
- ------------------------
- DSA supports many vendor-specific tagging protocols, one software-defined
--tagging protocol, and a tag-less mode as well (``DSA_TAG_PROTO_NONE``).
-+tagging protocol, a tag-less mode as well (``DSA_TAG_PROTO_NONE``) and an
-+out-of-band tagging protocol (``DSA_TAG_PROTO_OOB``).
- The exact format of the tag protocol is vendor specific, but in general, they
- all contain something which:
-@@ -221,6 +222,16 @@ receive all frames regardless of the val
- setting the ``promisc_on_conduit`` property of the ``struct dsa_device_ops``.
- Note that this assumes a DSA-unaware conduit driver, which is the norm.
-+Some SoCs have a tight integration between the conduit network interface and the
-+embedded switch, such that the DSA tag isn't transmitted in the packet data,
-+but through another media, using so-called out-of-band tagging. In that case,
-+the host MAC driver is in charge of transmitting the tag to the switch.
-+An example is the IPQ4019 SoC, that transmits the tag between the ipqess
-+ethernet controller and the qca8k switch using the DMA descriptor. In that
-+configuration, tag-chaining is permitted, but the OOB tag will always be the
-+top-most switch in the tree. The tagger (``DSA_TAG_PROTO_OOB``) uses skb
-+extensions to transmit the tag to and from the MAC driver.
-+
- Conduit network devices
- -----------------------
---- /dev/null
-+++ b/include/linux/dsa/oob.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: GPL-2.0-only
-+ * Copyright (C) 2022 Maxime Chevallier <maxime.chevallier@bootlin.com>
-+ */
-+
-+#ifndef _NET_DSA_OOB_H
-+#define _NET_DSA_OOB_H
-+
-+#include <linux/skbuff.h>
-+
-+struct dsa_oob_tag_info {
-+      u16 port;
-+};
-+
-+int dsa_oob_tag_push(struct sk_buff *skb, struct dsa_oob_tag_info *ti);
-+int dsa_oob_tag_pop(struct sk_buff *skb, struct dsa_oob_tag_info *ti);
-+#endif
---- a/include/linux/skbuff.h
-+++ b/include/linux/skbuff.h
-@@ -4852,6 +4852,9 @@ enum skb_ext_id {
- #if IS_ENABLED(CONFIG_MCTP_FLOWS)
-       SKB_EXT_MCTP,
- #endif
-+#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
-+      SKB_EXT_DSA_OOB,
-+#endif
-       SKB_EXT_NUM, /* must be last */
- };
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -57,6 +57,7 @@ struct tc_action;
- #define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE   29
- #define DSA_TAG_PROTO_MXL862_VALUE            30
- #define DSA_TAG_PROTO_MXL862_8021Q_VALUE      31
-+#define DSA_TAG_PROTO_OOB_VALUE                       32
- enum dsa_tag_protocol {
-       DSA_TAG_PROTO_NONE              = DSA_TAG_PROTO_NONE_VALUE,
-@@ -91,6 +92,7 @@ enum dsa_tag_protocol {
-       DSA_TAG_PROTO_VSC73XX_8021Q     = DSA_TAG_PROTO_VSC73XX_8021Q_VALUE,
-       DSA_TAG_PROTO_MXL862            = DSA_TAG_PROTO_MXL862_VALUE,
-       DSA_TAG_PROTO_MXL862_8021Q      = DSA_TAG_PROTO_MXL862_8021Q_VALUE,
-+      DSA_TAG_PROTO_OOB               = DSA_TAG_PROTO_OOB_VALUE,
- };
- struct dsa_switch;
---- a/net/core/skbuff.c
-+++ b/net/core/skbuff.c
-@@ -65,8 +65,12 @@
- #include <linux/kcov.h>
- #include <linux/iov_iter.h>
- #include <linux/if.h>
-+#ifdef CONFIG_NET_DSA_TAG_OOB
-+#include <linux/dsa/oob.h>
-+#endif
- #include <net/protocol.h>
-+#include <net/dsa.h>
- #include <net/dst.h>
- #include <net/sock.h>
- #include <net/checksum.h>
-@@ -5097,6 +5101,9 @@ static const u8 skb_ext_type_len[] = {
- #if IS_ENABLED(CONFIG_MCTP_FLOWS)
-       [SKB_EXT_MCTP] = SKB_EXT_CHUNKSIZEOF(struct mctp_flow),
- #endif
-+#if IS_ENABLED(CONFIG_NET_DSA_TAG_OOB)
-+      [SKB_EXT_DSA_OOB] = SKB_EXT_CHUNKSIZEOF(struct dsa_oob_tag_info),
-+#endif
- };
- static __always_inline unsigned int skb_ext_total_length(void)
---- a/net/dsa/Kconfig
-+++ b/net/dsa/Kconfig
-@@ -145,6 +145,15 @@ config NET_DSA_TAG_OCELOT_8021Q
-         this mode, less TCAM resources (VCAP IS1, IS2, ES0) are available for
-         use with tc-flower.
-+config NET_DSA_TAG_OOB
-+      select SKB_EXTENSIONS
-+      tristate "Tag driver for Out-of-band tagging drivers"
-+      help
-+        Say Y or M if you want to enable support for pairs of embedded
-+        switches and host MAC drivers which perform demultiplexing and
-+        packet steering to ports using out of band metadata processed
-+        by the DSA master, rather than tags present in the packets.
-+
- config NET_DSA_TAG_QCA
-       tristate "Tag driver for Qualcomm Atheros QCA8K switches"
-       help
---- a/net/dsa/Makefile
-+++ b/net/dsa/Makefile
-@@ -33,6 +33,7 @@ obj-$(CONFIG_NET_DSA_TAG_MXL_862XX_8021Q
- obj-$(CONFIG_NET_DSA_TAG_NONE) += tag_none.o
- obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o
- obj-$(CONFIG_NET_DSA_TAG_OCELOT_8021Q) += tag_ocelot_8021q.o
-+obj-$(CONFIG_NET_DSA_TAG_OOB) += tag_oob.o
- obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
- obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
- obj-$(CONFIG_NET_DSA_TAG_RTL8_4) += tag_rtl8_4.o
---- /dev/null
-+++ b/net/dsa/tag_oob.c
-@@ -0,0 +1,51 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+
-+/* Copyright (c) 2022, Maxime Chevallier <maxime.chevallier@bootlin.com> */
-+
-+#include <linux/bitfield.h>
-+#include <linux/dsa/oob.h>
-+#include <linux/skbuff.h>
-+
-+#include "tag.h"
-+
-+#define OOB_NAME "oob"
-+
-+static struct sk_buff *oob_tag_xmit(struct sk_buff *skb,
-+                                  struct net_device *dev)
-+{
-+      struct dsa_oob_tag_info *tag_info = skb_ext_add(skb, SKB_EXT_DSA_OOB);
-+      struct dsa_port *dp = dsa_user_to_port(dev);
-+
-+      tag_info->port = dp->index;
-+
-+      return skb;
-+}
-+
-+static struct sk_buff *oob_tag_rcv(struct sk_buff *skb,
-+                                 struct net_device *dev)
-+{
-+      struct dsa_oob_tag_info *tag_info = skb_ext_find(skb, SKB_EXT_DSA_OOB);
-+
-+      if (!tag_info)
-+              return NULL;
-+
-+      skb->dev = dsa_conduit_find_user(dev, 0, tag_info->port);
-+      if (!skb->dev)
-+              return NULL;
-+
-+      return skb;
-+}
-+
-+static const struct dsa_device_ops oob_tag_dsa_ops = {
-+      .name   = OOB_NAME,
-+      .proto  = DSA_TAG_PROTO_OOB,
-+      .xmit   = oob_tag_xmit,
-+      .rcv    = oob_tag_rcv,
-+};
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("DSA tag driver for out-of-band tagging");
-+MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
-+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OOB, OOB_NAME);
-+
-+module_dsa_tag_driver(oob_tag_dsa_ops);
diff --git a/target/linux/qualcommax/patches-6.12/0951-net-pcs-add-uniphy-pcs.patch b/target/linux/qualcommax/patches-6.12/0951-net-pcs-add-uniphy-pcs.patch
deleted file mode 100644 (file)
index 05ab189..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
---- a/drivers/net/pcs/Kconfig
-+++ b/drivers/net/pcs/Kconfig
-@@ -51,4 +51,13 @@ config PCS_RZN1_MIIC
-         on RZ/N1 SoCs. This PCS converts MII to RMII/RGMII or can be set in
-         pass-through mode for MII.
-+config PCS_QCA_UNIPHY
-+      tristate "Qualcomm 802.11ax UNIPHY PCS driver"
-+      select PHYLINK
-+      select FWNODE_PCS
-+      help
-+        PCS driver for the UNIPHY SerDes blocks in Qualcomm 802.11ax SoCs.
-+        Provides PSGMII and SGMII interface modes and registers the UNIPHY
-+        PLL clock providers needed for port clock muxing.
-+
- endmenu
---- a/drivers/net/pcs/Makefile
-+++ b/drivers/net/pcs/Makefile
-@@ -10,3 +10,4 @@ obj-$(CONFIG_PCS_LYNX)               += pcs-lynx.o
- obj-$(CONFIG_PCS_MTK_LYNXI)   += pcs-mtk-lynxi.o
- obj-$(CONFIG_PCS_RZN1_MIIC)   += pcs-rzn1-miic.o
- obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o
-+obj-$(CONFIG_PCS_QCA_UNIPHY)  += pcs-qca-uniphy.o
diff --git a/target/linux/qualcommax/patches-6.12/0952-net-ethernet-qca-add-ppe.patch b/target/linux/qualcommax/patches-6.12/0952-net-ethernet-qca-add-ppe.patch
deleted file mode 100644 (file)
index bec1451..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
---- a/drivers/net/ethernet/qualcomm/Kconfig
-+++ b/drivers/net/ethernet/qualcomm/Kconfig
-@@ -61,6 +61,13 @@ config QCOM_EMAC
-         low power, Receive-Side Scaling (RSS), and IEEE 1588-2008
-         Precision Clock Synchronization Protocol.
-+config QCOM_80211AX_PPE
-+      tristate "Qualcomm 802.11ax PPE switch driver"
-+      select PHYLINK
-+      help
-+        Driver for Qualcomm 802.11ax PPE (Packet Processing Engine) switches.
-+
-+
- source "drivers/net/ethernet/qualcomm/rmnet/Kconfig"
- endif # NET_VENDOR_QUALCOMM
---- a/drivers/net/ethernet/qualcomm/Makefile
-+++ b/drivers/net/ethernet/qualcomm/Makefile
-@@ -8,6 +8,8 @@ obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
- qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
- obj-$(CONFIG_QCA7000_UART) += qcauart.o
- qcauart-objs := qca_uart.o
-+obj-$(CONFIG_QCOM_80211AX_PPE) += qca_ppe.o
-+qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o
- obj-y += emac/
diff --git a/target/linux/qualcommax/patches-6.12/0953-net-ethernet-qca-add-EDMA.patch b/target/linux/qualcommax/patches-6.12/0953-net-ethernet-qca-add-EDMA.patch
deleted file mode 100644 (file)
index 6244773..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
---- a/drivers/net/ethernet/qualcomm/Kconfig
-+++ b/drivers/net/ethernet/qualcomm/Kconfig
-@@ -67,6 +67,11 @@ config QCOM_80211AX_PPE
-       help
-         Driver for Qualcomm 802.11ax PPE (Packet Processing Engine) switches.
-+config QCOM_EDMA
-+      tristate "EDMA dataplane ethernet driver for Qualcomm IPQ platforms"
-+      help
-+        EDMA dataplane ethernet driver for Qualcomm IPQ platforms.
-+
- source "drivers/net/ethernet/qualcomm/rmnet/Kconfig"
---- a/drivers/net/ethernet/qualcomm/Makefile
-+++ b/drivers/net/ethernet/qualcomm/Makefile
-@@ -10,6 +10,7 @@ obj-$(CONFIG_QCA7000_UART) += qcauart.o
- qcauart-objs := qca_uart.o
- obj-$(CONFIG_QCOM_80211AX_PPE) += qca_ppe.o
- qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o
-+obj-$(CONFIG_QCOM_EDMA) += qca_edma.o
- obj-y += emac/
diff --git a/target/linux/qualcommax/patches-6.12/0954-net-stmmac-Introduce-Qualcomm-IPQ5018-DWMAC-driver.patch b/target/linux/qualcommax/patches-6.12/0954-net-stmmac-Introduce-Qualcomm-IPQ5018-DWMAC-driver.patch
deleted file mode 100644 (file)
index f0cf29a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
-+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-@@ -78,6 +78,14 @@ config DWMAC_INGENIC
-         device driver. This driver is used on for the Ingenic SoCs
-         MAC ethernet controller.
-+config DWMAC_IPQ5018
-+      tristate "Qualcomm IPQ5018 DWMAC driver"
-+      depends on OF && (ARCH_QCOM || COMPILE_TEST)
-+      help
-+        Support for ethernet controller on Qualcomm IPQ5018 SoCs.
-+
-+        This selects the IPQ5018 SoC glue layer support for the stmmac driver.
-+
- config DWMAC_IPQ806X
-       tristate "QCA IPQ806x DWMAC support"
-       default ARCH_QCOM
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -15,6 +15,7 @@ stmmac-$(CONFIG_STMMAC_SELFTESTS) += stm
- obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
- obj-$(CONFIG_DWMAC_ANARION)   += dwmac-anarion.o
- obj-$(CONFIG_DWMAC_INGENIC)   += dwmac-ingenic.o
-+obj-$(CONFIG_DWMAC_IPQ5018)   += dwmac-ipq5018.o
- obj-$(CONFIG_DWMAC_IPQ806X)   += dwmac-ipq806x.o
- obj-$(CONFIG_DWMAC_LPC18XX)   += dwmac-lpc18xx.o
- obj-$(CONFIG_DWMAC_MEDIATEK)  += dwmac-mediatek.o