ipq807x: rename target to qualcommax
authorRobert Marko <robimarko@gmail.com>
Sun, 11 Jun 2023 17:32:52 +0000 (19:32 +0200)
committerChristian Marangi <ansuelsmth@gmail.com>
Fri, 16 Jun 2023 09:11:08 +0000 (11:11 +0200)
Currently, ipq807x only covers Qualcomm IPQ807x SoC-s.
However, Qualcomm also has IPQ60xx and IPQ50xx SoC-s under the AX WiSoC-s
and they share a lot of stuff with IPQ807x, especially IPQ60xx so to avoid
duplicating kernel patches and everything lets make a common target with
per SoC subtargets.

Start doing that by renaming ipq807x to qualcommax so that dependencies
on ipq807x target can be updated.

Signed-off-by: Robert Marko <robimarko@gmail.com>
164 files changed:
.github/labeler.yml
config/Config-images.in
package/boot/uboot-envtools/files/ipq807x [deleted file]
package/boot/uboot-envtools/files/qualcommax [new file with mode: 0644]
package/firmware/ipq-wifi/Makefile
package/kernel/linux/modules/netsupport.mk
package/kernel/linux/modules/usb.mk
package/kernel/mac80211/ath.mk
package/kernel/qca-nss-dp/Makefile
package/kernel/qca-ssdk/Makefile
target/linux/ipq807x/Makefile [deleted file]
target/linux/ipq807x/base-files/etc/board.d/01_leds [deleted file]
target/linux/ipq807x/base-files/etc/board.d/02_network [deleted file]
target/linux/ipq807x/base-files/etc/hotplug.d/firmware/11-ath11k-caldata [deleted file]
target/linux/ipq807x/base-files/etc/init.d/bootcount [deleted file]
target/linux/ipq807x/base-files/lib/upgrade/buffalo.sh [deleted file]
target/linux/ipq807x/base-files/lib/upgrade/mmc.sh [deleted file]
target/linux/ipq807x/base-files/lib/upgrade/platform.sh [deleted file]
target/linux/ipq807x/config-6.1 [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax6.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-eap102.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-301w.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-ax9000.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-dl-wrx36.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-haze.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-512m.dtsi [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-ac-cpu.dtsi [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-cpr-regulator.dtsi [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-ess.dtsi [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-hk-cpu.dtsi [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts [deleted file]
target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-wxr-5950ax12.dts [deleted file]
target/linux/ipq807x/generic/target.mk [deleted file]
target/linux/ipq807x/image/Makefile [deleted file]
target/linux/ipq807x/image/generic.mk [deleted file]
target/linux/ipq807x/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch [deleted file]
target/linux/ipq807x/patches-6.1/0002-v6.2-thermal-drivers-tsens-Add-support-for-combined-inter.patch [deleted file]
target/linux/ipq807x/patches-6.1/0003-v6.2-thermal-drivers-tsens-Allow-configuring-min-and-max-.patch [deleted file]
target/linux/ipq807x/patches-6.1/0004-v6.2-thermal-drivers-tsens-Add-IPQ8074-support.patch [deleted file]
target/linux/ipq807x/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch [deleted file]
target/linux/ipq807x/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch [deleted file]
target/linux/ipq807x/patches-6.1/0007-v6.2-clk-qcom-ipq8074-convert-to-parent-data.patch [deleted file]
target/linux/ipq807x/patches-6.1/0008-v6.2-clk-qcom-reset-support-resetting-multiple-bits.patch [deleted file]
target/linux/ipq807x/patches-6.1/0009-v6.2-dt-bindings-clock-qcom-ipq8074-add-missing-networkin.patch [deleted file]
target/linux/ipq807x/patches-6.1/0010-v6.2-clk-qcom-ipq8074-add-missing-networking-resets.patch [deleted file]
target/linux/ipq807x/patches-6.1/0011-v6.2-clk-qcom-ipq8074-populate-fw_name-for-all-parents.patch [deleted file]
target/linux/ipq807x/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch [deleted file]
target/linux/ipq807x/patches-6.1/0013-v6.2-arm64-dts-qcom-add-PMP8074-DTSI.patch [deleted file]
target/linux/ipq807x/patches-6.1/0014-v6.2-arm64-dts-qcom-ipq8074-hk01-add-VQMMC-supply.patch [deleted file]
target/linux/ipq807x/patches-6.1/0015-v6.2-arm64-dts-qcom-hk01-use-GPIO-flags-for-tlmm.patch [deleted file]
target/linux/ipq807x/patches-6.1/0016-v6.2-arm64-dts-qcom-ipq8074-Fix-up-comments.patch [deleted file]
target/linux/ipq807x/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch [deleted file]
target/linux/ipq807x/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch [deleted file]
target/linux/ipq807x/patches-6.1/0020-v6.3-PCI-qcom-Add-support-for-IPQ8074-Gen3-port.patch [deleted file]
target/linux/ipq807x/patches-6.1/0021-v6.3-clk-qcom-ipq8074-populate-fw_name-for-usb3phy-s.patch [deleted file]
target/linux/ipq807x/patches-6.1/0022-v6.5-soc-qcom-mdt_loader-Fix-unconditional-call-to-scm_pa.patch [deleted file]
target/linux/ipq807x/patches-6.1/0100-clk-qcom-clk-rcg2-introduce-support-for-multiple-con.patch [deleted file]
target/linux/ipq807x/patches-6.1/0101-clk-qcom-gcc-ipq8074-rework-nss_port5-6-clock-to-mul.patch [deleted file]
target/linux/ipq807x/patches-6.1/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch [deleted file]
target/linux/ipq807x/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch [deleted file]
target/linux/ipq807x/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch [deleted file]
target/linux/ipq807x/patches-6.1/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch [deleted file]
target/linux/ipq807x/patches-6.1/0113-remoteproc-qcom-Add-secure-PIL-support.patch [deleted file]
target/linux/ipq807x/patches-6.1/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch [deleted file]
target/linux/ipq807x/patches-6.1/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch [deleted file]
target/linux/ipq807x/patches-6.1/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch [deleted file]
target/linux/ipq807x/patches-6.1/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch [deleted file]
target/linux/ipq807x/patches-6.1/0118-clk-qcom-Add-WCSSAON-reset.patch [deleted file]
target/linux/ipq807x/patches-6.1/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch [deleted file]
target/linux/ipq807x/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch [deleted file]
target/linux/ipq807x/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch [deleted file]
target/linux/ipq807x/patches-6.1/0122-arm64-dts-ipq8074-add-CPU-clock.patch [deleted file]
target/linux/ipq807x/patches-6.1/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch [deleted file]
target/linux/ipq807x/patches-6.1/0128-cpufreq-qcom-nvmem-add-support-for-IPQ8074.patch [deleted file]
target/linux/ipq807x/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch [deleted file]
target/linux/ipq807x/patches-6.1/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch [deleted file]
target/linux/ipq807x/patches-6.1/0132-mmc-core-disable-TRIM-on-Micron-MTFC4GACAJCN-1M.patch [deleted file]
target/linux/ipq807x/patches-6.1/0133-mmc-core-disable-TRIM-on-Kingston-EMMC04G-M627.patch [deleted file]
target/linux/ipq807x/patches-6.1/0134-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch [deleted file]
target/linux/ipq807x/patches-6.1/0900-power-Add-Qualcomm-APM.patch [deleted file]
target/linux/ipq807x/patches-6.1/0901-regulator-add-Qualcomm-CPR-regulators.patch [deleted file]
target/linux/ipq807x/patches-6.1/0902-arm64-dts-ipq8074-add-label-to-clocks.patch [deleted file]
target/linux/qualcommax/Makefile [new file with mode: 0644]
target/linux/qualcommax/base-files/etc/board.d/01_leds [new file with mode: 0644]
target/linux/qualcommax/base-files/etc/board.d/02_network [new file with mode: 0644]
target/linux/qualcommax/base-files/etc/hotplug.d/firmware/11-ath11k-caldata [new file with mode: 0644]
target/linux/qualcommax/base-files/etc/init.d/bootcount [new file with mode: 0755]
target/linux/qualcommax/base-files/lib/upgrade/buffalo.sh [new file with mode: 0644]
target/linux/qualcommax/base-files/lib/upgrade/mmc.sh [new file with mode: 0644]
target/linux/qualcommax/base-files/lib/upgrade/platform.sh [new file with mode: 0644]
target/linux/qualcommax/config-6.1 [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax6.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-eap102.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-301w.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-ax9000.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-dl-wrx36.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-haze.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-512m.dtsi [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-ac-cpu.dtsi [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-cpr-regulator.dtsi [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-ess.dtsi [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-hk-cpu.dtsi [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts [new file with mode: 0644]
target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-wxr-5950ax12.dts [new file with mode: 0644]
target/linux/qualcommax/generic/target.mk [new file with mode: 0644]
target/linux/qualcommax/image/Makefile [new file with mode: 0644]
target/linux/qualcommax/image/generic.mk [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0002-v6.2-thermal-drivers-tsens-Add-support-for-combined-inter.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0003-v6.2-thermal-drivers-tsens-Allow-configuring-min-and-max-.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0004-v6.2-thermal-drivers-tsens-Add-IPQ8074-support.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0007-v6.2-clk-qcom-ipq8074-convert-to-parent-data.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0008-v6.2-clk-qcom-reset-support-resetting-multiple-bits.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0009-v6.2-dt-bindings-clock-qcom-ipq8074-add-missing-networkin.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0010-v6.2-clk-qcom-ipq8074-add-missing-networking-resets.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0011-v6.2-clk-qcom-ipq8074-populate-fw_name-for-all-parents.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0013-v6.2-arm64-dts-qcom-add-PMP8074-DTSI.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0014-v6.2-arm64-dts-qcom-ipq8074-hk01-add-VQMMC-supply.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0015-v6.2-arm64-dts-qcom-hk01-use-GPIO-flags-for-tlmm.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0016-v6.2-arm64-dts-qcom-ipq8074-Fix-up-comments.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0020-v6.3-PCI-qcom-Add-support-for-IPQ8074-Gen3-port.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0021-v6.3-clk-qcom-ipq8074-populate-fw_name-for-usb3phy-s.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0022-v6.5-soc-qcom-mdt_loader-Fix-unconditional-call-to-scm_pa.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0100-clk-qcom-clk-rcg2-introduce-support-for-multiple-con.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0101-clk-qcom-gcc-ipq8074-rework-nss_port5-6-clock-to-mul.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0113-remoteproc-qcom-Add-secure-PIL-support.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0118-clk-qcom-Add-WCSSAON-reset.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0122-arm64-dts-ipq8074-add-CPU-clock.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0128-cpufreq-qcom-nvmem-add-support-for-IPQ8074.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0132-mmc-core-disable-TRIM-on-Micron-MTFC4GACAJCN-1M.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0133-mmc-core-disable-TRIM-on-Kingston-EMMC04G-M627.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0134-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0900-power-Add-Qualcomm-APM.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0901-regulator-add-Qualcomm-CPR-regulators.patch [new file with mode: 0644]
target/linux/qualcommax/patches-6.1/0902-arm64-dts-ipq8074-add-label-to-clocks.patch [new file with mode: 0644]

index 6d53d5810637263afeff9d132d47d0fa923e3502..e22f074604fea6d2f3e78eaf5dc90adc2684d1a8 100644 (file)
@@ -41,8 +41,8 @@
   - "target/linux/ipq40xx/**"
 "target/ipq806x":
   - "target/linux/ipq806x/**"
-"target/ipq807x":
-  - "target/linux/ipq807x/**"
+"target/qualcommax":
+  - "target/linux/qualcommax/**"
 "target/kirkwood":
   - "target/linux/kirkwood/**"
   - "package/boot/uboot-kirkwood/**"
index ea7b3d37c3d5decc4adb0c192d483576197fd572..c37537b1a71cdac34447f8bca7290ed4ecd4b617 100644 (file)
@@ -17,7 +17,7 @@ menu "Target Images"
                        default TARGET_INITRAMFS_COMPRESSION_LZMA if TARGET_lantiq
                        default TARGET_INITRAMFS_COMPRESSION_LZMA if TARGET_mpc85xx
                        default TARGET_INITRAMFS_COMPRESSION_LZMA if TARGET_ramips
-                       default TARGET_INITRAMFS_COMPRESSION_ZSTD if TARGET_ipq807x
+                       default TARGET_INITRAMFS_COMPRESSION_ZSTD if TARGET_qualcommax
                        default TARGET_INITRAMFS_COMPRESSION_XZ if USES_SEPARATE_INITRAMFS
                        default TARGET_INITRAMFS_COMPRESSION_NONE
                        depends on TARGET_ROOTFS_INITRAMFS
diff --git a/package/boot/uboot-envtools/files/ipq807x b/package/boot/uboot-envtools/files/ipq807x
deleted file mode 100644 (file)
index 345cdad..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-[ -e /etc/config/ubootenv ] && exit 0
-
-touch /etc/config/ubootenv
-
-. /lib/uboot-envtools.sh
-. /lib/functions.sh
-
-board=$(board_name)
-
-case "$board" in
-dynalink,dl-wrx36|\
-netgear,wax218)
-       idx="$(find_mtd_index 0:appsblenv)"
-       [ -n "$idx" ] && \
-               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x40000" "0x20000" "2"
-       ;;
-compex,wpq873|\
-edgecore,eap102|\
-zyxel,nbg7815)
-       idx="$(find_mtd_index 0:appsblenv)"
-       [ -n "$idx" ] && \
-               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000" "1"
-       ;;
-edimax,cax1800)
-       idx="$(find_mtd_index 0:appsblenv)"
-       [ -n "$idx" ] && \
-               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x20000"
-       ;;
-redmi,ax6|\
-xiaomi,ax3600|\
-xiaomi,ax9000)
-       idx="$(find_mtd_index 0:appsblenv)"
-       [ -n "$idx" ] && \
-               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x20000"
-       idx2="$(find_mtd_index bdata)"
-       [ -n "$idx2" ] && \
-               ubootenv_add_uci_sys_config "/dev/mtd$idx2" "0x0" "0x10000" "0x20000"
-       ;;
-prpl,haze)
-       mmcpart="$(find_mmc_part 0:APPSBLENV)"
-       [ -n "$mmcpart" ] && \
-               ubootenv_add_uci_config "$mmcpart" "0x0" "0x40000" "0x400" "0x100"
-       ;;
-qnap,301w)
-       idx="$(find_mtd_index 0:appsblenv)"
-       [ -n "$idx" ] && \
-               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x20000" "0x20000" "1"
-       ;;
-esac
-
-config_load ubootenv
-config_foreach ubootenv_add_app_config
-
-exit 0
diff --git a/package/boot/uboot-envtools/files/qualcommax b/package/boot/uboot-envtools/files/qualcommax
new file mode 100644 (file)
index 0000000..345cdad
--- /dev/null
@@ -0,0 +1,54 @@
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+dynalink,dl-wrx36|\
+netgear,wax218)
+       idx="$(find_mtd_index 0:appsblenv)"
+       [ -n "$idx" ] && \
+               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x40000" "0x20000" "2"
+       ;;
+compex,wpq873|\
+edgecore,eap102|\
+zyxel,nbg7815)
+       idx="$(find_mtd_index 0:appsblenv)"
+       [ -n "$idx" ] && \
+               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000" "1"
+       ;;
+edimax,cax1800)
+       idx="$(find_mtd_index 0:appsblenv)"
+       [ -n "$idx" ] && \
+               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x20000"
+       ;;
+redmi,ax6|\
+xiaomi,ax3600|\
+xiaomi,ax9000)
+       idx="$(find_mtd_index 0:appsblenv)"
+       [ -n "$idx" ] && \
+               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x20000"
+       idx2="$(find_mtd_index bdata)"
+       [ -n "$idx2" ] && \
+               ubootenv_add_uci_sys_config "/dev/mtd$idx2" "0x0" "0x10000" "0x20000"
+       ;;
+prpl,haze)
+       mmcpart="$(find_mmc_part 0:APPSBLENV)"
+       [ -n "$mmcpart" ] && \
+               ubootenv_add_uci_config "$mmcpart" "0x0" "0x40000" "0x400" "0x100"
+       ;;
+qnap,301w)
+       idx="$(find_mtd_index 0:appsblenv)"
+       [ -n "$idx" ] && \
+               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x20000" "0x20000" "1"
+       ;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config
+
+exit 0
index 0c6941050b0a432e40fa4fa84fbf333125c017d9..2bffd2a1b74073574190116e011fd0b6ba9890f2 100644 (file)
@@ -48,7 +48,7 @@ define Package/ipq-wifi-default
   SUBMENU:=ath10k Board-Specific Overrides
   SECTION:=firmware
   CATEGORY:=Firmware
-  DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_ipq807x)
+  DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax)
   TITLE:=Custom Board
 endef
 
index 0c5d2da9504b73a50c6226f2a0897044cd64320a..cb85c46b78517a8dce1d5545f6d8467da29f6be8 100644 (file)
@@ -1511,7 +1511,7 @@ $(eval $(call KernelPackage,qrtr-tun))
 define KernelPackage/qrtr-smd
   SUBMENU:=$(NETWORK_SUPPORT_MENU)
   TITLE:=SMD IPC Router channels
-  DEPENDS:=+kmod-qrtr @TARGET_ipq807x
+  DEPENDS:=+kmod-qrtr @TARGET_qualcommax
   KCONFIG:=CONFIG_QRTR_SMD
   FILES:= $(LINUX_DIR)/net/qrtr/qrtr-smd.ko
   AUTOLOAD:=$(call AutoProbe,qrtr-smd)
index 644365ed19e1fab89495d0eaa61846f84740ae02..45efd7449f8db8ad04114e36190cf2513edb6237 100644 (file)
@@ -483,7 +483,7 @@ $(eval $(call KernelPackage,usb-dwc3))
 
 define KernelPackage/usb-dwc3-qcom
   TITLE:=DWC3 Qualcomm USB driver
-  DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_ipq807x) +kmod-usb-dwc3
+  DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax) +kmod-usb-dwc3
   KCONFIG:= CONFIG_USB_DWC3_QCOM
   FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3-qcom.ko
   AUTOLOAD:=$(call AutoLoad,53,dwc3-qcom,1)
index dc08df4f6fec566a460a5b3b7f4f6ee7fcb8af16..c75630a8bb0b672c11ad9a6d6923bfbd0e7179fd 100644 (file)
@@ -317,7 +317,7 @@ define KernelPackage/ath11k/config
        config ATH11K_THERMAL
                bool "Enable thermal sensors and throttling support"
                depends on PACKAGE_kmod-ath11k
-               default y if TARGET_ipq807x
+               default y if TARGET_qualcommax
 
 endef
 
@@ -325,7 +325,7 @@ define KernelPackage/ath11k-ahb
   $(call KernelPackage/mac80211/Default)
   TITLE:=Qualcomm 802.11ax AHB wireless chipset support
   URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath11k
-  DEPENDS+= @TARGET_ipq807x +kmod-ath11k +kmod-qrtr-smd
+  DEPENDS+= @TARGET_qualcommax +kmod-ath11k +kmod-qrtr-smd
   FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath11k/ath11k_ahb.ko
   AUTOLOAD:=$(call AutoProbe,ath11k_ahb)
 endef
index e9d9706141f0cf85ca6a6fb06f7ca293bfcfd2cb..aad49b80552cf8c3ba90f8ee60f75a11e8eb4376 100644 (file)
@@ -19,7 +19,7 @@ define KernelPackage/qca-nss-dp
   SECTION:=kernel
   CATEGORY:=Kernel modules
   SUBMENU:=Network Devices
-  DEPENDS:=@TARGET_ipq807x +kmod-qca-ssdk
+  DEPENDS:=@TARGET_qualcommax +kmod-qca-ssdk
   TITLE:=Qualcom NSS dataplane ethernet driver
   FILES:=$(PKG_BUILD_DIR)/qca-nss-dp.ko
   AUTOLOAD:=$(call AutoLoad,31,qca-nss-dp,1)
index 92f7b66490be97fa0203cd0fd7c1463c94092071..169252663b75b8195b91af86de5469d2adc3871f 100644 (file)
@@ -20,7 +20,7 @@ define KernelPackage/qca-ssdk
   CATEGORY:=Kernel modules
   SUBMENU:=Network Devices
   TITLE:=Qualcom SSDK switch driver
-  DEPENDS:=@(TARGET_ipq807x)
+  DEPENDS:=@(TARGET_qualcommax)
   FILES:=$(PKG_BUILD_DIR)/build/bin/qca-ssdk.ko
   AUTOLOAD:=$(call AutoLoad,30,qca-ssdk)
 endef
diff --git a/target/linux/ipq807x/Makefile b/target/linux/ipq807x/Makefile
deleted file mode 100644 (file)
index e434288..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-include $(TOPDIR)/rules.mk
-
-ARCH:=aarch64
-BOARD:=ipq807x
-BOARDNAME:=Qualcomm Atheros IPQ807x
-FEATURES:=squashfs ramdisk fpu nand rtc emmc
-KERNELNAME:=Image dtbs
-CPU_TYPE:=cortex-a53
-SUBTARGETS:=generic
-
-KERNEL_PATCHVER:=6.1
-
-include $(INCLUDE_DIR)/target.mk
-DEFAULT_PACKAGES += \
-       kmod-usb3 kmod-usb-dwc3 kmod-usb-dwc3-qcom \
-       kmod-leds-gpio kmod-gpio-button-hotplug \
-       kmod-phy-aquantia kmod-qca-nss-dp \
-       ath11k-firmware-ipq8074 kmod-ath11k-ahb \
-       wpad-basic-mbedtls uboot-envtools \
-       e2fsprogs kmod-fs-ext4 losetup
-
-$(eval $(call BuildTarget))
diff --git a/target/linux/ipq807x/base-files/etc/board.d/01_leds b/target/linux/ipq807x/base-files/etc/board.d/01_leds
deleted file mode 100644 (file)
index a89b4c1..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-
-. /lib/functions/uci-defaults.sh
-
-board_config_update
-
-board=$(board_name)
-
-case "$board" in
-edgecore,eap102)
-       ucidef_set_led_netdev "wan" "WAN" "green:wanpoe" "wan"
-       ;;
-netgear,wax218)
-       ucidef_set_led_netdev "lan" "LAN" "blue:lan" "lan"
-       ucidef_set_led_wlan "wlan5g" "WIFI 5GHz" "blue:wlan5g" "phy0radio"
-       ucidef_set_led_wlan "wlan2g" "WIFI 2.4GHz" "blue:wlan2g" "phy1radio"
-       ;;
-redmi,ax6|\
-xiaomi,ax3600)
-       ucidef_set_led_netdev "wan" "WAN" "blue:network" "wan"
-       ;;
-qnap,301w)
-       ucidef_set_led_netdev "lan1" "LAN1" "green:lan1" "lan1"
-       ucidef_set_led_netdev "lan2" "LAN2" "green:lan2" "lan2"
-       ucidef_set_led_netdev "lan3" "LAN3" "green:lan3" "lan3"
-       ucidef_set_led_netdev "lan4" "LAN4" "green:lan4" "lan4"
-       ucidef_set_led_netdev "10G_1" "10G_1" "green:10g_1" "10g-1"
-       ucidef_set_led_netdev "10G_2" "10G_2" "green:10g_2" "10g-2"
-       ;;
-esac
-
-board_config_flush
-
-exit 0
diff --git a/target/linux/ipq807x/base-files/etc/board.d/02_network b/target/linux/ipq807x/base-files/etc/board.d/02_network
deleted file mode 100644 (file)
index 8175a99..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# Copyright (c) 2015 The Linux Foundation. All rights reserved.
-# Copyright (c) 2011-2015 OpenWrt.org
-#
-
-. /lib/functions/uci-defaults.sh
-. /lib/functions/system.sh
-
-ipq807x_setup_interfaces()
-{
-       local board="$1"
-
-       case "$board" in
-       buffalo,wxr-5950ax12|\
-       dynalink,dl-wrx36|\
-       xiaomi,ax9000)
-               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan"
-               ;;
-       edgecore,eap102)
-               ucidef_set_interfaces_lan_wan "lan" "wan"
-               ;;
-       edimax,cax1800)
-               ucidef_set_interfaces_lan_wan "lan"
-               ;;
-       netgear,wax218)
-               ucidef_set_interface_lan "lan" "dhcp"
-               ;;
-       prpl,haze)
-               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
-               ;;
-       qnap,301w)
-               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4 10g-2" "10g-1"
-               ;;
-       compex,wpq873|\
-       redmi,ax6|\
-       xiaomi,ax3600)
-               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
-               ;;
-       zyxel,nbg7815)
-               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4 10g" "wan"
-               ;;
-       *)
-               echo "Unsupported hardware. Network interfaces not initialized"
-               ;;
-       esac
-}
-
-board_config_update
-board=$(board_name)
-ipq807x_setup_interfaces $board
-board_config_flush
-
-exit 0
diff --git a/target/linux/ipq807x/base-files/etc/hotplug.d/firmware/11-ath11k-caldata b/target/linux/ipq807x/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
deleted file mode 100644 (file)
index f931557..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-
-[ -e /lib/firmware/$FIRMWARE ] && exit 0
-
-. /lib/functions/caldata.sh
-
-board=$(board_name)
-
-case "$FIRMWARE" in
-"ath11k/IPQ8074/hw2.0/cal-ahb-c000000.wifi.bin")
-       case "$board" in
-       buffalo,wxr-5950ax12|\
-       compex,wpq873|\
-       edgecore,eap102|\
-       edimax,cax1800|\
-       dynalink,dl-wrx36|\
-       netgear,wax218|\
-       qnap,301w|\
-       redmi,ax6|\
-       xiaomi,ax3600|\
-       xiaomi,ax9000|\
-       zyxel,nbg7815)
-               caldata_extract "0:art" 0x1000 0x20000
-               ;;
-       prpl,haze)
-                caldata_extract_mmc "0:ART" 0x1000 0x20000
-               ;;
-       esac
-       ;;
-"ath11k/QCN9074/hw1.0/cal-pci-0000:01:00.0.bin"|\
-"ath11k/QCN9074/hw1.0/cal-pci-0001:01:00.0.bin")
-       case "$board" in
-       prpl,haze)
-                caldata_extract_mmc "0:ART" 0x26800 0x20000
-               ;;
-       xiaomi,ax9000)
-               caldata_extract "0:art" 0x26800 0x20000
-               ;;
-       esac
-       ;;
-*)
-       exit 1
-       ;;
-esac
diff --git a/target/linux/ipq807x/base-files/etc/init.d/bootcount b/target/linux/ipq807x/base-files/etc/init.d/bootcount
deleted file mode 100755 (executable)
index 6917446..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh /etc/rc.common
-
-START=99
-
-boot() {
-       case $(board_name) in
-       edgecore,eap102)
-               fw_setenv upgrade_available 0
-               # Unset changed flag after sysupgrade complete
-               fw_setenv changed
-       ;;
-       esac
-}
diff --git a/target/linux/ipq807x/base-files/lib/upgrade/buffalo.sh b/target/linux/ipq807x/base-files/lib/upgrade/buffalo.sh
deleted file mode 100644 (file)
index d0ed258..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-. /lib/functions.sh
-
-# Prepare UBI devices for OpenWrt installation
-# - rootfs (mtd22)
-#   - remove "ubi_rootfs" volume (rootfs on stock)
-#   - remove "fw_hash" volume (firmware hash)
-# - user_property (mtd24)
-#   - remove "user_property_ubi" volume (user configuration)
-#   - remove "extra_property" volume (gzipped syslog)
-buffalo_upgrade_prepare() {
-       local ubi_rootdev ubi_propdev
-
-       if ! ubi_rootdev="$(nand_attach_ubi rootfs)" || \
-          ! ubi_propdev="$(nand_attach_ubi user_property)"; then
-               echo "failed to attach UBI volume \"rootfs\" or \"user_property\", rebooting..."
-               reboot -f
-       fi
-
-       ubirmvol /dev/$ubi_rootdev -N ubi_rootfs &> /dev/null || true
-       ubirmvol /dev/$ubi_rootdev -N fw_hash &> /dev/null || true
-
-       ubirmvol /dev/$ubi_propdev -N user_property_ubi &> /dev/null || true
-       ubirmvol /dev/$ubi_propdev -N extra_property &> /dev/null || true
-}
-
-# Re-create small dummy ubi_rootfs volume and update
-# fw_hash volume to pass the checking by U-Boot
-# - rootfs (mtd22)
-#   - re-create "ubi_rootfs" volume
-#   - re-create and update "fw_hash" volume
-# - rootfs_recover (mtd23)
-#   - update "fw_hash" volume
-buffalo_upgrade_optvol() {
-       local ubi_rootdev ubi_rcvrdev
-       local hashvol_root hashvol_rcvr
-
-       if ! ubi_rootdev="$(nand_attach_ubi rootfs)" || \
-          ! ubi_rcvrdev="$(nand_attach_ubi rootfs_recover)"; then
-               echo "failed to attach UBI volume \"rootfs\" or \"rootfs_recover\", rebooting..."
-               reboot -f
-       fi
-
-       ubimkvol /dev/$ubi_rootdev -N ubi_rootfs -S 1
-       ubimkvol /dev/$ubi_rootdev -N fw_hash -S 1 -t static
-
-       if ! hashvol_root="$(nand_find_volume $ubi_rootdev fw_hash)" || \
-          ! hashvol_rcvr="$(nand_find_volume $ubi_rcvrdev fw_hash)"; then
-               echo "\"fw_hash\" volume in \"rootfs\" or \"rootfs_recover\" not found, rebooting..."
-               reboot -f
-       fi
-
-       echo -n "00000000000000000000000000000000" > /tmp/dummyhash.txt
-       ubiupdatevol /dev/$hashvol_root /tmp/dummyhash.txt
-       ubiupdatevol /dev/$hashvol_rcvr /tmp/dummyhash.txt
-}
diff --git a/target/linux/ipq807x/base-files/lib/upgrade/mmc.sh b/target/linux/ipq807x/base-files/lib/upgrade/mmc.sh
deleted file mode 100644 (file)
index dac9ddd..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# Copyright (C) 2016 lede-project.org
-#
-
-# this can be used as a generic mmc upgrade script
-# just add a device entry in platform.sh, 
-# define "kernelname" and "rootfsname" and call mmc_do_upgrade
-# after the kernel and rootfs flash a loopdev (as overlay) is 
-# setup on top of the rootfs partition
-# for the proper function a padded rootfs image is needed, basically 
-# append "pad-to 64k" to the image definition
-# this is based on the ipq806x zyxel.sh mmc upgrade
-
-. /lib/functions.sh
-
-mmc_do_upgrade() {
-       local tar_file="$1"
-       local rootfs=
-       local kernel=
-
-                       [ -z "$kernel" ] && kernel=$(find_mmc_part ${kernelname})
-                       [ -z "$rootfs" ] && rootfs=$(find_mmc_part ${rootfsname})
-
-                       [ -z "$kernel" ] && echo "Upgrade failed: kernel partition not found! Rebooting..." && reboot -f
-                       [ -z "$rootfs" ] && echo "Upgrade failed: rootfs partition not found! Rebooting..." && reboot -f
-
-       mmc_do_flash $tar_file $kernel $rootfs
-
-       return 0
-}
-
-mmc_do_flash() {
-       local tar_file=$1
-       local kernel=$2
-       local rootfs=$3
-       
-       # keep sure its unbound
-       losetup --detach-all || {
-               echo Failed to detach all loop devices. Skip this try.
-               reboot -f
-       }
-
-       # use the first found directory in the tar archive
-       local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
-       board_dir=${board_dir%/}
-
-       echo "flashing kernel to $kernel"
-       tar xf $tar_file ${board_dir}/kernel -O >$kernel
-
-       echo "flashing rootfs to ${rootfs}"
-       tar xf $tar_file ${board_dir}/root -O >"${rootfs}"
-
-       # a padded rootfs is needed for overlay fs creation
-       local offset=$(tar xf $tar_file ${board_dir}/root -O | wc -c)
-       [ $offset -lt 65536 ] && {
-               echo Wrong size for rootfs: $offset
-               sleep 10
-               reboot -f
-       }
-
-       # Mount loop for rootfs_data
-       local loopdev="$(losetup -f)"
-       losetup -o $offset $loopdev $rootfs || {
-               echo "Failed to mount looped rootfs_data."
-               sleep 10
-               reboot -f
-       }
-
-       echo "Format new rootfs_data at position ${offset}."
-       mkfs.ext4 -F -L rootfs_data $loopdev
-       mkdir /tmp/new_root
-       mount -t ext4 $loopdev /tmp/new_root && {
-               echo "Saving config to rootfs_data at position ${offset}."
-               cp -v "$UPGRADE_BACKUP" "/tmp/new_root/$BACKUP_FILE"
-               umount /tmp/new_root
-       }
-
-       # Cleanup
-       losetup -d $loopdev >/dev/null 2>&1
-       sync
-       umount -a
-       reboot -f
-}
diff --git a/target/linux/ipq807x/base-files/lib/upgrade/platform.sh b/target/linux/ipq807x/base-files/lib/upgrade/platform.sh
deleted file mode 100644 (file)
index 458eb16..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-PART_NAME=firmware
-REQUIRE_IMAGE_METADATA=1
-
-RAMFS_COPY_BIN='fw_printenv fw_setenv head'
-RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
-
-xiaomi_initramfs_prepare() {
-       # Wipe UBI if running initramfs
-       [ "$(rootfs_type)" = "tmpfs" ] || return 0
-
-       local rootfs_mtdnum="$( find_mtd_index rootfs )"
-       if [ ! "$rootfs_mtdnum" ]; then
-               echo "unable to find mtd partition rootfs"
-               return 1
-       fi
-
-       local kern_mtdnum="$( find_mtd_index ubi_kernel )"
-       if [ ! "$kern_mtdnum" ]; then
-               echo "unable to find mtd partition ubi_kernel"
-               return 1
-       fi
-
-       ubidetach -m "$rootfs_mtdnum"
-       ubiformat /dev/mtd$rootfs_mtdnum -y
-
-       ubidetach -m "$kern_mtdnum"
-       ubiformat /dev/mtd$kern_mtdnum -y
-}
-
-platform_check_image() {
-       return 0;
-}
-
-platform_pre_upgrade() {
-       case "$(board_name)" in
-       redmi,ax6|\
-       xiaomi,ax3600|\
-       xiaomi,ax9000)
-               xiaomi_initramfs_prepare
-               ;;
-       esac
-}
-
-platform_do_upgrade() {
-       case "$(board_name)" in
-       buffalo,wxr-5950ax12)
-               CI_KERN_UBIPART="rootfs"
-               CI_ROOT_UBIPART="user_property"
-               buffalo_upgrade_prepare
-               nand_do_flash_file "$1" || nand_do_upgrade_failed
-               nand_do_restore_config || nand_do_upgrade_failed
-               buffalo_upgrade_optvol
-               ;;
-       dynalink,dl-wrx36)
-               nand_do_upgrade "$1"
-               ;;
-       edgecore,eap102)
-               active="$(fw_printenv -n active)"
-               if [ "$active" -eq "1" ]; then
-                       CI_UBIPART="rootfs2"
-               else
-                       CI_UBIPART="rootfs1"
-               fi
-               # force altbootcmd which handles partition change in u-boot
-               fw_setenv bootcount 3
-               fw_setenv upgrade_available 1
-               nand_do_upgrade "$1"
-               ;;
-       compex,wpq873|\
-       edimax,cax1800|\
-       netgear,wax218)
-               nand_do_upgrade "$1"
-               ;;
-       prpl,haze|\
-       qnap,301w)
-               kernelname="0:HLOS"
-               rootfsname="rootfs"
-               mmc_do_upgrade "$1"
-               ;;
-       zyxel,nbg7815)
-               local config_mtdnum="$(find_mtd_index 0:bootconfig)"
-               [ -z "$config_mtdnum" ] && reboot
-               part_num="$(hexdump -e '1/1 "%01x|"' -n 1 -s 168 -C /dev/mtd$config_mtdnum | cut -f 1 -d "|" | head -n1)"
-               if [ "$part_num" -eq "0" ]; then
-                       kernelname="0:HLOS"
-                       rootfsname="rootfs"
-                       mmc_do_upgrade "$1"
-               else
-                       kernelname="0:HLOS_1"
-                       rootfsname="rootfs_1"
-                       mmc_do_upgrade "$1"
-               fi
-               ;;
-       redmi,ax6|\
-       xiaomi,ax3600|\
-       xiaomi,ax9000)
-               # Make sure that UART is enabled
-               fw_setenv boot_wait on
-               fw_setenv uart_en 1
-
-               # Enforce single partition.
-               fw_setenv flag_boot_rootfs 0
-               fw_setenv flag_last_success 0
-               fw_setenv flag_boot_success 1
-               fw_setenv flag_try_sys1_failed 8
-               fw_setenv flag_try_sys2_failed 8
-
-               # Kernel and rootfs are placed in 2 different UBI
-               CI_KERN_UBIPART="ubi_kernel"
-               CI_ROOT_UBIPART="rootfs"
-               nand_do_upgrade "$1"
-               ;;
-       *)
-               default_do_upgrade "$1"
-               ;;
-       esac
-}
diff --git a/target/linux/ipq807x/config-6.1 b/target/linux/ipq807x/config-6.1
deleted file mode 100644 (file)
index 2fa4aa3..0000000
+++ /dev/null
@@ -1,560 +0,0 @@
-CONFIG_64BIT=y
-# CONFIG_APQ_GCC_8084 is not set
-# CONFIG_APQ_MMCC_8084 is not set
-CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
-CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_ARCH_FORCE_MAX_ORDER=11
-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_NR_GPIO=0
-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_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_PAGE_SHIFT=12
-CONFIG_ARM64_PA_BITS=48
-CONFIG_ARM64_PA_BITS_48=y
-CONFIG_ARM64_PTR_AUTH=y
-CONFIG_ARM64_PTR_AUTH_KERNEL=y
-CONFIG_ARM64_SME=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_GIC_V3_ITS_PCI=y
-# CONFIG_ARM_MHU_V2 is not set
-CONFIG_ARM_PSCI_CPUIDLE=y
-CONFIG_ARM_PSCI_CPUIDLE_DOMAIN=y
-CONFIG_ARM_PSCI_FW=y
-# CONFIG_ARM_QCOM_CPUFREQ_HW is not set
-CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y
-CONFIG_AUDIT_ARCH_COMPAT_GENERIC=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_CAVIUM_TX2_ERRATUM_219=y
-CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
-CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
-CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
-CONFIG_CC_NO_ARRAY_BOUNDS=y
-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_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_QCE=y
-CONFIG_CRYPTO_DEV_QCE_AEAD=y
-# CONFIG_CRYPTO_DEV_QCE_ENABLE_AEAD is not set
-CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL=y
-# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set
-# CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER is not set
-CONFIG_CRYPTO_DEV_QCE_SHA=y
-CONFIG_CRYPTO_DEV_QCE_SKCIPHER=y
-CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512
-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_SHA1=y
-CONFIG_CRYPTO_LIB_SHA256=y
-CONFIG_CRYPTO_LIB_UTILS=y
-CONFIG_CRYPTO_LZO=y
-# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set
-CONFIG_CRYPTO_RNG=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_SHA256=y
-# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
-# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
-CONFIG_CRYPTO_XTS=y
-CONFIG_CRYPTO_ZSTD=y
-CONFIG_DCACHE_WORD_ACCESS=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEV_COREDUMP=y
-CONFIG_DMADEVICES=y
-CONFIG_DMA_DIRECT_REMAP=y
-CONFIG_DMA_ENGINE=y
-CONFIG_DMA_OF=y
-CONFIG_DMA_VIRTUAL_CHANNELS=y
-CONFIG_DTC=y
-CONFIG_DT_IDLE_GENPD=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_FUJITSU_ERRATUM_010001=y
-CONFIG_FWNODE_MDIO=y
-CONFIG_FW_LOADER_PAGED_BUF=y
-CONFIG_FW_LOADER_SYSFS=y
-CONFIG_GCC11_NO_ARRAY_BOUNDS=y
-CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS=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_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_SHOW=y
-CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
-CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
-CONFIG_GENERIC_MSI_IRQ=y
-CONFIG_GENERIC_MSI_IRQ_DOMAIN=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_HARDIRQS_SW_RESEND=y
-CONFIG_HAS_DMA=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT_MAP=y
-CONFIG_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_QCOM=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_IPQ_APSS_6018=y
-CONFIG_IPQ_APSS_PLL=y
-# CONFIG_IPQ_GCC_4019 is not set
-# CONFIG_IPQ_GCC_6018 is not set
-# CONFIG_IPQ_GCC_806X is not set
-CONFIG_IPQ_GCC_8074=y
-# CONFIG_IPQ_LCC_806X 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_WORK=y
-# CONFIG_KPSS_XCC is not set
-CONFIG_LIBFDT=y
-CONFIG_LOCK_DEBUGGING_SUPPORT=y
-CONFIG_LOCK_SPIN_ON_OWNER=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_MDM_GCC_9615 is not set
-# CONFIG_MDM_LCC_9615 is not set
-CONFIG_MEMFD_CREATE=y
-# CONFIG_MFD_HI6421_SPMI is not set
-# CONFIG_MFD_QCOM_RPM is not set
-CONFIG_MFD_SPMI_PMIC=y
-CONFIG_MFD_SYSCON=y
-CONFIG_MIGRATION=y
-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_PCI is not set
-CONFIG_MMC_SDHCI_PLTFM=y
-CONFIG_MODULES_USE_ELF_RELA=y
-# CONFIG_MSM_GCC_8660 is not set
-# CONFIG_MSM_GCC_8909 is not set
-# CONFIG_MSM_GCC_8916 is not set
-# CONFIG_MSM_GCC_8939 is not set
-# CONFIG_MSM_GCC_8960 is not set
-# CONFIG_MSM_GCC_8974 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_LCC_8960 is not set
-# CONFIG_MSM_MMCC_8960 is not set
-# CONFIG_MSM_MMCC_8974 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_FLOW_LIMIT=y
-CONFIG_NET_SELFTESTS=y
-CONFIG_NET_SWITCHDEV=y
-CONFIG_NLS=y
-CONFIG_NO_HZ_COMMON=y
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NR_CPUS=4
-CONFIG_NVIDIA_CARMEL_CNP_ERRATUM=y
-CONFIG_NVMEM=y
-CONFIG_NVMEM_QCOM_QFPROM=y
-# CONFIG_NVMEM_SPMI_SDAM is not set
-CONFIG_NVMEM_SYSFS=y
-CONFIG_NVMEM_U_BOOT_ENV=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_PCI_DOMAINS=y
-CONFIG_PCI_DOMAINS_GENERIC=y
-CONFIG_PCI_MSI=y
-CONFIG_PCI_MSI_IRQ_DOMAIN=y
-CONFIG_PGTABLE_LEVELS=3
-CONFIG_PHYLIB=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_IPQ4019_USB is not set
-# CONFIG_PHY_QCOM_IPQ806X_SATA is not set
-# CONFIG_PHY_QCOM_IPQ806X_USB is not set
-# CONFIG_PHY_QCOM_PCIE2 is not set
-CONFIG_PHY_QCOM_QMP=y
-CONFIG_PHY_QCOM_QUSB2=y
-# 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_IPQ6018 is not set
-CONFIG_PINCTRL_IPQ8074=y
-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_SPMI_PMIC=y
-# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
-# CONFIG_PINCTRL_QCS404 is not set
-# CONFIG_PINCTRL_SC7180 is not set
-# CONFIG_PINCTRL_SC8280XP is not set
-# CONFIG_PINCTRL_SDM660 is not set
-# CONFIG_PINCTRL_SDM845 is not set
-# CONFIG_PINCTRL_SM6350 is not set
-# CONFIG_PINCTRL_SM6375 is not set
-# CONFIG_PINCTRL_SM8150 is not set
-# CONFIG_PINCTRL_SM8250 is not set
-# CONFIG_PINCTRL_SM8450 is not set
-CONFIG_PM=y
-# CONFIG_PM8916_WATCHDOG is not set
-CONFIG_PM_CLK=y
-CONFIG_PM_GENERIC_DOMAINS=y
-CONFIG_PM_GENERIC_DOMAINS_OF=y
-CONFIG_PM_OPP=y
-CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
-CONFIG_POWER_RESET=y
-# CONFIG_POWER_RESET_MSM is not set
-# CONFIG_POWER_RESET_QCOM_PON is not set
-CONFIG_POWER_SUPPLY=y
-CONFIG_PREEMPT_NONE_BUILD=y
-CONFIG_PRINTK_TIME=y
-CONFIG_PTP_1588_CLOCK_OPTIONAL=y
-# CONFIG_QCM_DISPCC_2290 is not set
-# CONFIG_QCM_GCC_2290 is not set
-# CONFIG_QCOM_A53PLL is not set
-# CONFIG_QCOM_AOSS_QMP is not set
-CONFIG_QCOM_APCS_IPC=y
-CONFIG_QCOM_APM=y
-# 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_CLK_APCS_SDX55 is not set
-# CONFIG_QCOM_COINCELL is not set
-# CONFIG_QCOM_COMMAND_DB is not set
-# CONFIG_QCOM_CPR is not set
-# CONFIG_QCOM_EBI2 is not set
-# CONFIG_QCOM_FASTRPC is not set
-CONFIG_QCOM_GDSC=y
-# 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_IPCC is not set
-# CONFIG_QCOM_LLCC is not set
-CONFIG_QCOM_MDT_LOADER=y
-# CONFIG_QCOM_MPM is not set
-# 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_MSS is not set
-# CONFIG_QCOM_Q6V5_PAS is not set
-CONFIG_QCOM_Q6V5_WCSS=y
-# CONFIG_QCOM_RMTFS_MEM is not set
-# CONFIG_QCOM_RPMH is not set
-CONFIG_QCOM_RPROC_COMMON=y
-CONFIG_QCOM_SCM=y
-# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set
-# 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_SPMI_ADC5=y
-# CONFIG_QCOM_SPMI_RRADC is not set
-# CONFIG_QCOM_STATS is not set
-# CONFIG_QCOM_SYSMON is not set
-CONFIG_QCOM_TSENS=y
-CONFIG_QCOM_VADC_COMMON=y
-# 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_QUEUED_RWLOCKS=y
-CONFIG_QUEUED_SPINLOCKS=y
-CONFIG_RANDSTRUCT_NONE=y
-CONFIG_RAS=y
-CONFIG_RATIONAL=y
-CONFIG_REGMAP=y
-CONFIG_REGMAP_MMIO=y
-CONFIG_REGMAP_SPMI=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_CPR3=y
-# CONFIG_REGULATOR_CPR3_NPU is not set
-CONFIG_REGULATOR_CPR4_APSS=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
-# CONFIG_REGULATOR_QCOM_LABIBB is not set
-CONFIG_REGULATOR_QCOM_SPMI=y
-# CONFIG_REGULATOR_QCOM_USB_VBUS is not set
-# 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_DRV_PM8XXX=y
-CONFIG_RTC_I2C_AND_SPI=y
-CONFIG_RWSEM_SPIN_ON_OWNER=y
-# CONFIG_SCHED_CORE is not set
-CONFIG_SCHED_MC=y
-CONFIG_SCHED_SMT=y
-CONFIG_SCHED_THERMAL_PRESSURE=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_DISPCC_7180 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_LPASS_CORECC_7180 is not set
-# CONFIG_SC_LPASS_CORECC_7280 is not set
-# CONFIG_SC_MSS_7180 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_65 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_SMP=y
-# CONFIG_SM_CAMCC_8450 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_GPUCC_6350 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_VIDEOCC_8150 is not set
-# CONFIG_SM_VIDEOCC_8250 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_QUP=y
-CONFIG_SPMI=y
-# CONFIG_SPMI_HISI3670 is not set
-CONFIG_SPMI_MSM_PMIC_ARB=y
-# CONFIG_SPMI_PMIC_CLKDIV is not set
-CONFIG_SRCU=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_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_VIRTIO=y
-CONFIG_VIRTIO_ANCHOR=y
-# CONFIG_VIRTIO_BLK 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/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts
deleted file mode 100644 (file)
index 2c9cbd5..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2021, Dirk Buchwalder <buchwalder@posteo.de> */
-
-/dts-v1/;
-
-#include "ipq8074-512m.dtsi"
-#include "ipq8074-ac-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-
-/ {
-       model = "Edimax CAX1800";
-       compatible = "edimax,cax1800", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               led-boot = &led_system_red;
-               led-failsafe = &led_system_red;
-               led-running = &led_system_green;
-               led-upgrade = &led_system_red;
-               /* Aliases as required by u-boot to patch MAC addresses */
-               ethernet0 = &dp5;
-               label-mac-device = &dp5;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " root=/dev/ubiblock0_1";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 32 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_system_red: system-red {
-                       label = "red:system";
-                       gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_system_green: system-green {
-                       label = "green:system";
-                       gpios = <&tlmm 26 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_system_blue: system-blue {
-                       label = "blue:system";
-                       gpios = <&tlmm 27 GPIO_ACTIVE_HIGH>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "rootfs";
-                               reg = <0x0000000 0x3400000>;
-                       };
-               };
-       };
-};
-
-&blsp1_spi1 {
-       pinctrl-0 = <&spi_0_pins>;
-       pinctrl-names = "default";
-       cs-select = <0>;
-       status = "ok";
-
-       m25p80@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-               use-default-sizes;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "0:sbl1";
-                               reg = <0x0 0x50000>;
-                               read-only;
-                       };
-
-                       partition@50000 {
-                               label = "0:mibib";
-                               reg = <0x50000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@60000 {
-                               label = "0:bootconfig";
-                               reg = <0x60000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@80000 {
-                               label = "0:bootconfig1";
-                               reg = <0x80000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@a0000 {
-                               label = "0:qsee";
-                               reg = <0xa0000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@220000 {
-                               label = "0:qsee_1";
-                               reg = <0x220000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@3a0000 {
-                               label = "0:devcfg";
-                               reg = <0x3a0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3b0000 {
-                               label = "0:devcfg_1";
-                               reg = <0x3b0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3c0000 {
-                               label = "0:apdp";
-                               reg = <0x3c0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3d0000 {
-                               label = "0:apdp_1";
-                               reg = <0x3d0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3e0000 {
-                               label = "0:rpm";
-                               reg = <0x3e0000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@420000 {
-                               label = "0:rpm_1";
-                               reg = <0x420000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@460000 {
-                               label = "0:cdt";
-                               reg = <0x460000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@470000 {
-                               label = "0:cdt_1";
-                               reg = <0x470000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@480000 {
-                               label = "0:appsblenv";
-                               reg = <0x480000 0x10000>;
-                       };
-
-                       partition@490000 {
-                               label = "0:appsbl";
-                               reg = <0x490000 0xa0000>;
-                               read-only;
-                       };
-
-                       partition@530000 {
-                               label = "0:appsbl_1";
-                               reg = <0x530000 0xa0000>;
-                               read-only;
-                       };
-
-                       partition@5d0000 {
-                               label = "0:art";
-                               reg = <0x5d0000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@610000 {
-                               label = "0:ethphyfw";
-                               reg = <0x610000 0x80000>;
-                               read-only;
-                       };
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       qca8075: ethernet-phy@4 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <4>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x1e>; /* lan port bitmap */
-       switch_wan_bmp = <0x20>; /* wan port bitmap */
-       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0>;
-               };
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-               port@4 {
-                       port_id = <5>;
-                       phy_address = <4>;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp5 {
-       status = "okay";
-       phy-handle = <&qca8075>;
-       label = "lan";
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Edimax-CAX1800";
-       qcom,ath11k-fw-memory-mode = <1>;
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dts
deleted file mode 100644 (file)
index f3e82e2..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2021, Robert Marko <robimarko@gmail.com> */
-
-/dts-v1/;
-
-#include "ipq8071-ax3600.dtsi"
-
-/ {
-       model = "Xiaomi AX3600";
-       compatible = "xiaomi,ax3600", "qcom,ipq8074";
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_system_blue: system-blue {
-                       label = "blue:system";
-                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_system_yellow: system-yellow {
-                       label = "yellow:system";
-                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
-               };
-
-               network-yellow {
-                       label = "yellow:network";
-                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
-               };
-
-               network-blue {
-                       label = "blue:network";
-                       gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-               };
-
-               aiot {
-                       label = "blue:aiot";
-                       gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
-                       linux,default-trigger = "phy0tpt";
-               };
-       };
-};
-
-&pcie_qmp0 {
-       status = "okay";
-};
-
-&pcie0 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 52 GPIO_ACTIVE_HIGH>;
-
-       bridge@0,0 {
-               reg = <0x00000000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-
-               wifi0: wifi@1,0 {
-                       status = "okay";
-
-                       compatible = "qcom,ath10k";
-                       reg = <0x00010000 0 0 0 0>;
-
-                       qcom,ath10k-calibration-variant = "Xiaomi-AX3600";
-                       nvmem-cell-names = "calibration";
-                       nvmem-cells = <&caldata_qca9889>;
-               };
-       };
-};
-
-&wifi {
-       qcom,ath11k-calibration-variant = "Xiaomi-AX3600";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi
deleted file mode 100644 (file)
index c18cef5..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2021, Robert Marko <robimarko@gmail.com> */
-
-#include "ipq8074-512m.dtsi"
-#include "ipq8074-ac-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-
-/ {
-       aliases {
-               serial0 = &blsp1_uart5;
-               led-boot = &led_system_yellow;
-               led-failsafe = &led_system_yellow;
-               led-running = &led_system_blue;
-               led-upgrade = &led_system_yellow;
-               label-mac-device = &dp2;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " root=/dev/ubiblock0_0";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       /*
-        * Bootloader will find the NAND DT node by the compatible and
-        * then "fixup" it by adding the partitions from the SMEM table
-        * using the legacy bindings thus making it impossible for us
-        * to change the partition table or utilize NVMEM for calibration.
-        * So add a dummy partitions node that bootloader will populate
-        * and set it as disabled so the kernel ignores it instead of
-        * printing warnings due to the broken way bootloader adds the
-        * partitions.
-        */
-       partitions {
-               status = "disabled";
-       };
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "0:sbl1";
-                               reg = <0x0 0x100000>;
-                               read-only;
-                       };
-
-                       partition@100000 {
-                               label = "0:mibib";
-                               reg = <0x100000 0x100000>;
-                               read-only;
-                       };
-
-                       partition@200000 {
-                               label = "0:qsee";
-                               reg = <0x200000 0x300000>;
-                               read-only;
-                       };
-
-                       partition@500000 {
-                               label = "0:devcfg";
-                               reg = <0x500000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@580000 {
-                               label = "0:rpm";
-                               reg = <0x580000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@600000 {
-                               label = "0:cdt";
-                               reg = <0x600000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@680000 {
-                               label = "0:appsblenv";
-                               reg = <0x680000 0x80000>;
-                       };
-
-                       partition@700000 {
-                               label = "0:appsbl";
-                               reg = <0x700000 0x100000>;
-                               read-only;
-                       };
-
-                       partition@800000 {
-                               label = "0:art";
-                               reg = <0x800000 0x80000>;
-                               read-only;
-
-                               compatible = "nvmem-cells";
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-
-                               macaddr_dp2: macaddr@6 {
-                                       reg = <0x6 0x6>;
-                               };
-
-                               macaddr_dp3: macaddr@c {
-                                       reg = <0xc 0x6>;
-                               };
-
-                               macaddr_dp4: macaddr@12 {
-                                       reg = <0x12 0x6>;
-                               };
-
-                               macaddr_dp5: macaddr@18 {
-                                       reg = <0x18 0x6>;
-                               };
-
-                               caldata_qca9889: caldata@4d000 {
-                                       reg = <0x33000 0x844>;
-                               };
-                       };
-
-                       partition@880000 {
-                               label = "bdata";
-                               reg = <0x880000 0x80000>;
-                       };
-
-                       partition@900000 {
-                               /* This is crash + crash_syslog parts combined */
-                               label = "pstore";
-                               reg = <0x900000 0x100000>;
-                       };
-
-                       /* Make the first rootfs a dedicated ubi partition for kernel */
-                       partition@a00000 {
-                               label = "ubi_kernel";
-                               reg = <0xa00000 0x23c0000>;
-                       };
-
-                       /* Place the real rootfs in the original second rootfs and
-                        * expand it to the end of the nand
-                        */
-                       rootfs: partition@2dc0000 {
-                               label = "rootfs";
-                               reg = <0x2dc0000 0xd240000>;
-                       };
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       qca8075_1: ethernet-phy@1 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <1>;
-       };
-
-       qca8075_2: ethernet-phy@2 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <2>;
-       };
-
-       qca8075_3: ethernet-phy@3 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <3>;
-       };
-
-       qca8075_4: ethernet-phy@4 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <4>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x1e>; /* lan port bitmap */
-       switch_wan_bmp = <0x20>; /* wan port bitmap */
-       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0>;
-               };
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-               port@4 {
-                       port_id = <5>;
-                       phy_address = <4>;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_1>;
-       label = "wan";
-       nvmem-cells = <&macaddr_dp2>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_2>;
-       label = "lan1";
-       nvmem-cells = <&macaddr_dp3>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_3>;
-       label = "lan2";
-       nvmem-cells = <&macaddr_dp4>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp5 {
-       status = "okay";
-       phy-handle = <&qca8075_4>;
-       label = "lan3";
-       nvmem-cells = <&macaddr_dp5>;
-       nvmem-cell-names = "mac-address";
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-fw-memory-mode = <1>;
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax6.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-ax6.dts
deleted file mode 100644 (file)
index 6611a8f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2021, Zhijun You <hujy652@gmail.com> */
-
-/dts-v1/;
-
-#include "ipq8071-ax3600.dtsi"
-
-/ {
-       model = "Redmi AX6";
-       compatible = "redmi,ax6", "qcom,ipq8074";
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_system_blue: system-blue {
-                       label = "blue:system";
-                       gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_system_yellow: system-yellow {
-                       label = "yellow:system";
-                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
-               };
-
-               network-blue {
-                       label = "blue:network";
-                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
-               };
-
-               network-yellow {
-                       label = "yellow:network";
-                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
-               };
-       };
-};
-
-/* AX6 can both have NAND of 256MiB or 128MiB.
- * To be on the safe side, assume 128MiB of NAND.
- */
-&rootfs {
-       reg = <0x2dc0000 0x5220000>;
-};
-
-&wifi {
-       qcom,ath11k-calibration-variant = "Redmi-AX6";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-eap102.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8071-eap102.dts
deleted file mode 100644 (file)
index 357b636..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2022, Matthew Hagan <mnhagan88@gmail.com> */
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-ac-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-
-/ {
-       model = "Edgecore EAP102";
-       compatible = "edgecore,eap102", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               serial1 = &blsp1_uart3;
-               led-boot = &led_system_green;
-               led-failsafe = &led_system_green;
-               led-running = &led_system_green;
-               led-upgrade = &led_system_green;
-               /* Aliases as required by u-boot to patch MAC addresses */
-               ethernet0 = &dp5;
-               ethernet1 = &dp6;
-               label-mac-device = &dp5;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " root=/dev/ubiblock0_1";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-               pinctrl-0 = <&button_pins>;
-               pinctrl-names = "default";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 66 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_wanpoe {
-                       label = "green:wanpoe";
-                       gpios = <&tlmm 46 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_wlan2g {
-                       label = "green:wlan2g";
-                       gpio = <&tlmm 47 GPIO_ACTIVE_HIGH>;
-                       linux,default-trigger = "phy1radio";
-               };
-
-               led_wlan5g {
-                       label = "green:wlan5g";
-                       gpio = <&tlmm 48 GPIO_ACTIVE_HIGH>;
-                       linux,default-trigger = "phy0radio";
-               };
-
-               led_system_green: led_system {
-                       label = "green:power";
-                       gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       button_pins: button_pins {
-               reset_button {
-                       pins = "gpio66";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_spi1 {
-       status = "okay";
-
-       flash@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "0:sbl1";
-                               reg = <0x0 0x50000>;
-                               read-only;
-                       };
-
-                       partition@50000 {
-                               label = "0:mibib";
-                               reg = <0x50000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@60000 {
-                               label = "0:bootconfig";
-                               reg = <0x60000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@80000 {
-                               label = "0:bootconfig1";
-                               reg = <0x80000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@a0000 {
-                               label = "0:qsee";
-                               reg = <0xa0000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@220000 {
-                               label = "0:qsee_1";
-                               reg = <0x220000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@3a0000 {
-                               label = "0:devcfg";
-                               reg = <0x3a0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3b0000 {
-                               label = "0:devcfg_1";
-                               reg = <0x3b0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3c0000 {
-                               label = "0:apdp";
-                               reg = <0x3c0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3d0000 {
-                               label = "0:apdp_1";
-                               reg = <0x3d0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3e0000 {
-                               label = "0:rpm";
-                               reg = <0x3e0000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@420000 {
-                               label = "0:rpm_1";
-                               reg = <0x420000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@460000 {
-                               label = "0:cdt";
-                               reg = <0x460000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@470000 {
-                               label = "0:cdt_1";
-                               reg = <0x470000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@480000 {
-                               label = "0:appsblenv";
-                               reg = <0x480000 0x10000>;
-                       };
-
-                       partition@490000 {
-                               label = "0:appsbl";
-                               reg = <0x490000 0xc0000>;
-                               read-only;
-                       };
-
-                       partition@550000 {
-                               label = "0:appsbl_1";
-                               reg = <0x530000 0xc0000>;
-                               read-only;
-                       };
-
-                       partition@610000 {
-                               label = "0:art";
-                               reg = <0x610000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@650000 {
-                               label = "0:ethphyfw";
-                               reg = <0x650000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@6d0000 {
-                               label = "0:product_info";
-                               reg = <0x6d0000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@750000 {
-                               label = "priv_data1";
-                               reg = <0x750000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@760000 {
-                               label = "priv_data2";
-                               reg = <0x760000 0x10000>;
-                               read-only;
-                       };
-               };
-       };
-};
-
-&blsp1_uart3 {
-       status = "okay";
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <8>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "rootfs1";
-                               reg = <0x0000000 0x3400000>;
-                       };
-
-                       partition@3400000 {
-                               label = "0:wififw";
-                               reg = <0x3400000 0x800000>;
-                               read-only;
-                       };
-
-                       partition@3c00000 {
-                               label = "rootfs2";
-                               reg = <0x3c00000 0x3400000>;
-                       };
-
-                       partition@7000000 {
-                               label = "0:wififw_1";
-                               reg = <0x7000000 0x800000>;
-                               read-only;
-                       };
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-
-       qca8081_24: ethernet-phy@24 {
-               compatible = "ethernet-phy-id004d.d101";
-               reg = <24>;
-               reset-gpios = <&tlmm 33 GPIO_ACTIVE_LOW>;
-       };
-
-       qca8081_28: ethernet-phy@28 {
-               compatible = "ethernet-phy-id004d.d101";
-               reg = <28>;
-               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x3e>; /* lan port bitmap */
-       switch_wan_bmp = <0x40>; /* wan port bitmap */
-       switch_mac_mode = <0xff>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xf>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xf>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@4 {
-                       port_id = <5>;
-                       phy_address = <24>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-               port@5 {
-                       port_id = <6>;
-                       phy_address = <28>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp5 {
-       status = "okay";
-       phy-handle = <&qca8081_28>;
-       label = "wan";
-};
-
-&dp6 {
-       status = "okay";
-       phy-handle = <&qca8081_24>;
-       label = "lan";
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Edgecore-EAP102";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-301w.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-301w.dts
deleted file mode 100644 (file)
index 5521a48..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2021, Dirk Buchwalder <buchwalder@posteo.de> */
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
-
-/ {
-       model = "QNAP 301w";
-       compatible = "qnap,301w", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               /*
-                * Aliases as required by u-boot
-                * to patch MAC addresses
-                */
-               led-boot = &led_system_red;
-               led-failsafe = &led_system_red;
-               led-running = &led_pwr_green;
-               led-upgrade = &led_system_red;
-               ethernet0 = &dp1;
-               ethernet1 = &dp2;
-               ethernet2 = &dp3;
-               ethernet3 = &dp4;
-               ethernet4 = &dp5;
-               ethernet5 = &dp6_syn;
-               label-mac-device = &dp1;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-               pinctrl-0 = <&button_pins>;
-               pinctrl-names = "default";
-
-               wps-button {
-                       label = "wps";
-                       gpios = <&tlmm 57 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WPS_BUTTON>;
-               };
-
-               reset-button {
-                       label = "reset";
-                       gpios = <&tlmm 67 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-               pinctrl-0 = <&leds_pins>;
-               pinctrl-names = "default";
-
-               led_system_green: led-system-green {
-                       label = "green:system";
-                       gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led_system_red: led-system-red {
-                       label = "red:system";
-                       gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-               };
-
-               led_pwr_green: led-pwr-green {
-                       label = "green:pwr";
-                       gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-wifi-green {
-                       label = "green:wifi";
-                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-lan4-green {
-                       label = "green:lan4";
-                       gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-lan4-amber {
-                       label = "amber:lan4";
-                       gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_AMBER>;
-               };
-
-               led-lan3-green {
-                       label = "green:lan3";
-                       gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-lan3-amber {
-                       label = "amber:lan3";
-                       gpios = <&tlmm 11 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_AMBER>;
-               };
-
-               led-lan2-green {
-                       label = "green:lan2";
-                       gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-lan2-amber {
-                       label = "amber:lan2";
-                       gpios = <&tlmm 13 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_AMBER>;
-               };
-
-               led-lan1-green {
-                       label = "green:lan1";
-                       gpios = <&tlmm 14 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-lan1-amber {
-                       label = "amber:lan1";
-                       gpios = <&tlmm 15 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_AMBER>;
-               };
-
-               led-10g-1-green {
-                       label = "green:10g_1";
-                       gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-10g-1-amber {
-                       label = "amber:10g_1";
-                       gpios = <&tlmm 56 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_AMBER>;
-               };
-
-               led-10g-2-green {
-                       label = "green:10g_2";
-                       gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led-10g-2-amber {
-                       label = "amber:10g_2";
-                       gpios = <&tlmm 52 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_AMBER>;
-               };
-       };
-};
-
-&tlmm {
-
-       mdio_pins: mdio-state {
-               mdc-pins {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio-pins {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       button_pins: button-state {
-               wps-pins {
-                       pins = "gpio57";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               rst-pins {
-                       pins = "gpio67";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       leds_pins: leds-state {
-               pins = "gpio1", "gpio3", "gpio4", "gpio6", "gpio7", "gpio8",
-                      "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio42",
-                      "gpio51", "gpio52", "gpio54", "gpio56";
-               function = "gpio";
-               drive-strength = <8>;
-               bias-pull-down;
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&ssphy_1 {
-       status = "okay";
-};
-
-&qusb_phy_1 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&usb_1 {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&blsp1_spi1 { /* BLSP1 QUP1 */
-       pinctrl-0 = <&spi_0_pins>;
-       pinctrl-names = "default";
-       cs-gpios = <0>;
-       status = "okay";
-
-       flash@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-
-               partitions {
-                       compatible = "qcom,smem-part";
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       aqr113c_0: ethernet-phy@0 {
-               compatible ="ethernet-phy-ieee802.3-c45";
-               reg = <0>;
-               reset-gpios = <&tlmm 59 GPIO_ACTIVE_LOW>;
-       };
-
-       aqr113c_8: ethernet-phy@8 {
-               compatible ="ethernet-phy-ieee802.3-c45";
-               reg = <8>;
-               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-       };
-
-       qca8075_16: ethernet-phy@16 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <16>;
-       };
-
-       qca8075_17: ethernet-phy@17 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <17>;
-       };
-
-       qca8075_18: ethernet-phy@18 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <18>;
-       };
-
-       qca8075_19: ethernet-phy@19 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <19>;
-       };
-};
-
-&sdhc_1 {
-       status = "okay";
-
-       /* According to the stock dts from the QNAP gpl drop
-        * the emmc has a problem with the hs400 > hs200 speed switch.
-        * Therefore remove the mmc-hs400-1_8v property
-       */
-       /delete-property/ mmc-hs400-1_8v;
-       mmc-hs200-1_8v;
-       mmc-ddr-1_8v;
-       vqmmc-supply = <&l11>;
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x3e>; /* lan port bitmap */
-       switch_wan_bmp = <0xc0>; /* wan port bitmap */
-       switch_mac_mode = <0xb>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xd>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xd>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <16>;
-               };
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <17>;
-               };
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <18>;
-               };
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <19>;
-               };
-               port@4 {
-                       port_id = <5>;
-                       phy_address = <8>;
-                       compatible = "ethernet-phy-ieee802.3-c45";
-                       ethernet-phy-ieee802.3-c45;
-               };
-               port@5 {
-                       port_id = <6>;
-                       phy_address = <0>;
-                       compatible = "ethernet-phy-ieee802.3-c45";
-                       ethernet-phy-ieee802.3-c45;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp1 {
-       status = "okay";
-       phy-handle = <&qca8075_16>;
-       label = "lan4";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_17>;
-       label = "lan3";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_18>;
-       label = "lan2";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_19>;
-       label = "lan1";
-};
-
-&dp5 {
-       status = "okay";
-       qcom,mactype = <1>;
-       phy-handle = <&aqr113c_8>;
-       label = "10g-1";
-};
-
-&dp6_syn {
-       status = "okay";
-       phy-handle = <&aqr113c_0>;
-       label = "10g-2";
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "QNAP-301w";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-ax9000.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-ax9000.dts
deleted file mode 100644 (file)
index 801aa05..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2021, Robert Marko <robimarko@gmail.com> */
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
-
-/ {
-       model = "Xiaomi AX9000";
-       compatible = "xiaomi,ax9000", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               led-boot = &led_system_yellow;
-               led-failsafe = &led_system_yellow;
-               led-running = &led_system_blue;
-               led-upgrade = &led_system_yellow;
-               label-mac-device = &dp5;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " root=/dev/ubiblock0_0";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-
-               wps {
-                       label = "wps"; /* Labeled Mesh on the device */
-                       gpios = <&tlmm 46 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WPS_BUTTON>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_system_blue: system-blue {
-                       label = "blue:system";
-                       gpios = <&tlmm 48 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_BLUE>;
-               };
-
-               led_system_yellow: system-yellow {
-                       label = "yellow:system";
-                       gpios = <&tlmm 52 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_YELLOW>;
-               };
-
-               network-yellow {
-                       label = "yellow:network";
-                       gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_YELLOW>;
-               };
-
-               network-blue {
-                       label = "blue:network";
-                       gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_BLUE>;
-               };
-
-               top-red {
-                       label = "red:top";
-                       gpios = <&tlmm 63 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-                       default-state = "keep";
-               };
-
-               top-green {
-                       label = "green:top";
-                       gpios = <&tlmm 64 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-                       default-state = "keep";
-               };
-
-               top-blue {
-                       label = "blue:top";
-                       gpios = <&tlmm 66 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_BLUE>;
-                       default-state = "keep";
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       i2c_pins: i2c-pins {
-               pins = "gpio0", "gpio2";
-               function = "blsp5_i2c";
-               drive-strength = <8>;
-               bias-disable;
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&blsp1_i2c6 {
-       status = "okay";
-
-       pinctrl-0 = <&i2c_pins>;
-       pinctrl-names = "default";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       /*
-        * Bootloader will find the NAND DT node by the compatible and
-        * then "fixup" it by adding the partitions from the SMEM table
-        * using the legacy bindings thus making it impossible for us
-        * to change the partition table or utilize NVMEM for calibration.
-        * So add a dummy partitions node that bootloader will populate
-        * and set it as disabled so the kernel ignores it instead of
-        * printing warnings due to the broken way bootloader adds the
-        * partitions.
-        */
-       partitions {
-               status = "disabled";
-       };
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "0:sbl1";
-                               reg = <0x0 0x100000>;
-                               read-only;
-                       };
-
-                       partition@100000 {
-                               label = "0:mibib";
-                               reg = <0x100000 0x100000>;
-                               read-only;
-                       };
-
-                       partition@200000 {
-                               label = "0:bootconfig";
-                               reg = <0x200000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@280000 {
-                               label = "0:bootconfig1";
-                               reg = <0x280000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@300000 {
-                               label = "0:qsee";
-                               reg = <0x300000 0x300000>;
-                               read-only;
-                       };
-
-                       partition@600000 {
-                               label = "0:qsee_1";
-                               reg = <0x600000 0x300000>;
-                               read-only;
-                       };
-
-                       partition@900000 {
-                               label = "0:devcfg";
-                               reg = <0x900000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@980000 {
-                               label = "0:devcfg_1";
-                               reg = <0x980000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@a00000 {
-                               label = "0:apdp";
-                               reg = <0xa00000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@a80000 {
-                               label = "0:apdp_1";
-                               reg = <0xa80000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@b00000 {
-                               label = "0:rpm";
-                               reg = <0xb00000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@b80000 {
-                               label = "0:rpm_1";
-                               reg = <0xb80000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@c00000 {
-                               label = "0:cdt";
-                               reg = <0xc00000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@c80000 {
-                               label = "0:cdt_1";
-                               reg = <0xc80000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@d00000 {
-                               label = "0:appsblenv";
-                               reg = <0xd00000 0x80000>;
-                       };
-
-                       partition@d80000 {
-                               label = "0:appsbl";
-                               reg = <0xd80000 0x100000>;
-                               read-only;
-                       };
-
-                       partition@e80000 {
-                               label = "0:appsbl_1";
-                               reg = <0xe80000 0x100000>;
-                               read-only;
-                       };
-
-                       partition@f80000 {
-                               label = "0:art";
-                               reg = <0xf80000 0x80000>;
-                               read-only;
-
-                               compatible = "nvmem-cells";
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-
-                               macaddr_dp1: macaddr@0 {
-                                       reg = <0x0 0x6>;
-                               };
-
-                               macaddr_dp2: macaddr@6 {
-                                       reg = <0x6 0x6>;
-                               };
-
-                               macaddr_dp3: macaddr@c {
-                                       reg = <0xc 0x6>;
-                               };
-
-                               macaddr_dp4: macaddr@12 {
-                                       reg = <0x12 0x6>;
-                               };
-
-                               macaddr_dp5: macaddr@18 {
-                                       reg = <0x18 0x6>;
-                               };
-
-                               caldata_qca9889: caldata@4d000 {
-                                       reg = <0x4d000 0x844>;
-                               };
-                       };
-
-                       partition@1000000 {
-                               label = "bdata";
-                               reg = <0x1000000 0x80000>;
-                       };
-
-                       partition@1080000 {
-                               /* This is crash + crash_syslog parts combined */
-                               label = "pstore";
-                               reg = <0x1080000 0x100000>;
-                       };
-
-                       partition@1180000 {
-                               label = "ubi_kernel";
-                               reg = <0x1180000 0x3800000>;
-                       };
-
-                       partition@4980000 {
-                               label = "rootfs";
-                               reg = <0x4980000 0xb680000>;
-                       };
-               };
-       };
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       qca8075_0: ethernet-phy@0 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0>;
-       };
-
-       qca8075_1: ethernet-phy@1 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <1>;
-       };
-
-       qca8075_2: ethernet-phy@2 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <2>;
-       };
-
-       qca8075_3: ethernet-phy@3 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <3>;
-       };
-
-       qca8081: ethernet-phy@24 {
-               compatible = "ethernet-phy-id004d.d101";
-               reg = <24>;
-               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x1e>; /* lan port bitmap */
-       switch_wan_bmp = <0x20>; /* wan port bitmap */
-       switch_mac_mode = <0xb>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xc>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0>;
-               };
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-               port@4 {
-                       port_id = <5>;
-                       phy_address = <24>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp1 {
-       status = "okay";
-       phy-handle = <&qca8075_0>;
-       label = "lan4";
-       nvmem-cells = <&macaddr_dp1>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_1>;
-       label = "lan3";
-       nvmem-cells = <&macaddr_dp2>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_2>;
-       label = "lan2";
-       nvmem-cells = <&macaddr_dp3>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_3>;
-       label = "lan1";
-       nvmem-cells = <&macaddr_dp4>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp5 {
-       status = "okay";
-       phy-handle = <&qca8081>;
-       label = "wan";
-       nvmem-cells = <&macaddr_dp5>;
-       nvmem-cell-names = "mac-address";
-};
-
-&pcie_qmp0 {
-       status = "okay";
-};
-
-&pcie0 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 58 GPIO_ACTIVE_LOW>;
-
-       bridge@0,0 {
-               reg = <0x00000000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-
-               wifi@1,0 {
-                       status = "okay";
-
-                       /* ath11k has no DT compatible for PCI cards */
-                       compatible = "pci17cb,1104";
-                       reg = <0x00010000 0 0 0 0>;
-
-                       qcom,ath11k-calibration-variant = "Xiaomi-AX9000";
-               };
-       };
-};
-
-&pcie_qmp1 {
-       status = "okay";
-};
-
-&pcie1 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 62 GPIO_ACTIVE_HIGH>;
-
-       bridge@1,0 {
-               reg = <0x00010000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-
-               wifi@1,0 {
-                       status = "okay";
-
-                       compatible = "qcom,ath10k";
-                       reg = <0x00010000 0 0 0 0>;
-
-                       qcom,ath10k-calibration-variant = "Xiaomi-AX9000";
-                       nvmem-cell-names = "calibration";
-                       nvmem-cells = <&caldata_qca9889>;
-               };
-       };
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Xiaomi-AX9000";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-dl-wrx36.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-dl-wrx36.dts
deleted file mode 100644 (file)
index 5468e9e..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright (c) 2022, Robert Marko <robimarko@gmail.com> */
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
-
-/ {
-       model = "Dynalink DL-WRX36";
-       compatible = "dynalink,dl-wrx36", "qcom,ipq8074";
-
-       aliases {
-               led-boot = &led_system_red;
-               led-failsafe = &led_system_red;
-               led-running = &led_system_blue;
-               led-upgrade = &led_system_red;
-               serial0 = &blsp1_uart5;
-               /* Aliases as required by u-boot to patch MAC addresses */
-               ethernet0 = &dp6_syn;
-               ethernet1 = &dp4;
-               ethernet2 = &dp3;
-               ethernet3 = &dp2;
-               ethernet4 = &dp1;
-               label-mac-device = &dp6_syn;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " root=/dev/ubiblock0_1";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-
-               wps {
-                       label = "wps";
-                       gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WPS_BUTTON>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_system_blue: system-blue {
-                       label = "blue:system";
-                       gpios = <&tlmm 26 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_BLUE>;
-               };
-
-               led_system_red: system-red {
-                       label = "red:system";
-                       gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <8>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "qcom,smem-part";
-               };
-       };
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       qca8075_0: ethernet-phy@0 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0>;
-       };
-
-       qca8075_1: ethernet-phy@1 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <1>;
-       };
-
-       qca8075_2: ethernet-phy@2 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <2>;
-       };
-
-       qca8075_3: ethernet-phy@3 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <3>;
-       };
-
-       qca8081: ethernet-phy@28 {
-               compatible = "ethernet-phy-id004d.d101";
-               reg = <28>;
-               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x3e>; /* lan port bitmap */
-       switch_wan_bmp = <0x40>; /* wan port bitmap */
-       switch_mac_mode = <0xb>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xc>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0>;
-               };
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-               port@5 {
-                       port_id = <6>;
-                       phy_address = <28>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp1 {
-       status = "okay";
-       phy-handle = <&qca8075_0>;
-       label = "lan4";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_1>;
-       label = "lan3";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_2>;
-       label = "lan2";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_3>;
-       label = "lan1";
-};
-
-&dp6_syn {
-       status = "okay";
-       phy-handle = <&qca8081>;
-       label = "wan";
-};
-
-&wifi {
-       status = "okay";
-       qcom,ath11k-calibration-variant = "Dynalink-DL-WRX36";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-haze.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-haze.dts
deleted file mode 100644 (file)
index 8a5200b..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
-
-/ {
-       model = "prpl Foundation Haze";
-       compatible = "prpl,haze", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               /* Aliases are required by U-Boot to patch MAC addresses */
-               ethernet0 = &dp6_syn;
-               ethernet1 = &dp4;
-               ethernet2 = &dp3;
-               ethernet3 = &dp2;
-               label-mac-device = &dp6_syn;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-               pinctrl-0 = <&button_pins>;
-               pinctrl-names = "default";
-
-               wps-button {
-                       label = "wps";
-                       gpios = <&tlmm 42 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WPS_BUTTON>;
-               };
-
-               reset-button {
-                       label = "reset";
-                       gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-state {
-               mdc-pins {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio-pins {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       button_pins: button-state {
-               wps-pins {
-                       pins = "gpio42";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               rst-pins {
-                       pins = "gpio44";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&ssphy_1 {
-       status = "okay";
-};
-
-&qusb_phy_1 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&usb_1 {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&blsp1_spi1 { /* BLSP1 QUP1 */
-       pinctrl-0 = <&spi_0_pins>;
-       pinctrl-names = "default";
-       cs-gpios = <0>;
-       status = "okay";
-
-       flash@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-
-               partitions {
-                       compatible = "qcom,smem-part";
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 22 GPIO_ACTIVE_LOW>;
-
-       qca8075_1: ethernet-phy@0 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0>;
-       };
-
-       qca8075_2: ethernet-phy@1 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <1>;
-       };
-
-       qca8075_3: ethernet-phy@2 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <2>;
-       };
-
-       qca8075_4: ethernet-phy@3 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <3>;
-       };
-
-       aqr113c: ethernet-phy@5 {
-               compatible ="ethernet-phy-ieee802.3-c45";
-               reg = <8>;
-               reset-gpios = <&tlmm 43 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&sdhc_1 {
-       status = "okay";
-
-       vqmmc-supply = <&l11>;
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x1e>; /* lan port bitmap */
-       switch_wan_bmp = <0x60>; /* wan port bitmap */
-       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0xe>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0xd>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0>;
-               };
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-               port@4 {
-                       port_id = <6>;
-                       phy_address = <8>;
-                       compatible = "ethernet-phy-ieee802.3-c45";
-                       ethernet-phy-ieee802.3-c45;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-/* Dummy LAN port */
-&dp1 {
-       status = "disabled";
-       phy-handle = <&qca8075_1>;
-       label = "lan4";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_2>;
-       label = "lan3";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_3>;
-       label = "lan2";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_4>;
-       label = "lan1";
-};
-
-&dp6_syn {
-       status = "okay";
-       qcom,mactype = <1>;
-       phy-handle = <&aqr113c>;
-       label = "wan";
-};
-
-&pcie_qmp0 {
-       status = "okay";
-};
-
-&pcie0 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 58 GPIO_ACTIVE_LOW>;
-
-       bridge@0,0 {
-               reg = <0x00020000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-       };
-};
-
-&pcie_qmp1 {
-       status = "okay";
-};
-
-&pcie1 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 61 GPIO_ACTIVE_LOW>;
-
-       bridge@1,0 {
-               reg = <0x00010000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-
-               wifi@1,0 {
-                       status = "okay";
-
-                       /* ath11k has no DT compatible for PCI cards */
-                       compatible = "pci17cb,1104";
-                       reg = <0x00010000 0 0 0 0>;
-
-                       qcom,ath11k-calibration-variant = "prpl-Haze";
-               };
-       };
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "prpl-Haze";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts
deleted file mode 100644 (file)
index 5bfcdcc..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-       model = "Netgear WAX218";
-       compatible = "netgear,wax218", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               led-boot = &led_power_amber;
-               led-failsafe = &led_power_amber;
-               led-running = &led_power_amber;
-               led-upgrade = &led_power_amber;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               /*
-                * Netgear's U-Boot adds "ubi.mtd=rootfs root=mtd:ubi_rootfs"
-                * That fails to create a UBI block device, so add it here.
-               */
-               bootargs-append = " ubi.block=0,rootfs root=/dev/ubiblock0_1";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 52 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-
-       led_spi {
-               compatible = "spi-gpio";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               sck-gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>;
-               mosi-gpios = <&tlmm 19 GPIO_ACTIVE_HIGH>;
-
-               led_gpio: led_gpio@0 {
-                       compatible = "fairchild,74hc595";
-                       reg = <0>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-                       registers-number = <1>;
-                       enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
-                       spi-max-frequency = <1000000>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_power_amber: led_power {
-                       label = "amber:power";
-                       gpios = <&led_gpio 1 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_lan {
-                       label = "blue:lan";
-                       gpios = <&led_gpio 2 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_wlan_2g {
-                       label = "blue:wlan2g";
-                       gpios = <&led_gpio 3 GPIO_ACTIVE_HIGH>;
-               };
-
-               led_wlan_5g {
-                       label = "blue:wlan5g";
-                       gpios = <&led_gpio 4 GPIO_ACTIVE_HIGH>;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;
-       switch_lan_bmp = <0x3e>;
-       switch_wan_bmp = <0x40>;
-       switch_mac_mode = <0x00>;
-       switch_mac_mode1 = <0xff>;
-       switch_mac_mode2 = <0x0f>;
-       bm_tick_mode = <0>;
-       tm_tick_mode = <0>;
-
-       qcom,port_phyinfo {
-               port@5 {
-                       port_id = <6>;
-                       phy_address = <28>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-
-       qca8081_28: ethernet-phy@28 {
-               reg = <28>;
-       };
-};
-
-&dp6_syn {
-       status = "okay";
-       phy-handle = <&qca8081_28>;
-       label = "lan";
-       nvmem-cells = <&macaddr_ubootenv_ethaddr>;
-       nvmem-cell-names = "mac-address";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "qcom,smem-part";
-
-                       partition-0-appsblenv {
-                               compatible = "fixed-partitions";
-                               label = "0:appsblenv";
-                               read-only;
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-
-                               partition@0 {
-                                       compatible = "u-boot,env";
-                                       label = "env-data";
-                                       reg = <0x0 0x40000>;
-
-                                       macaddr_ubootenv_ethaddr: ethaddr {};
-                               };
-                       };
-               };
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Netgear-WAX218";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts
deleted file mode 100644 (file)
index 9779070..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/* Copyright 2023 Nokia */
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
-
-/ {
-       model = "Compex WPQ873";
-       compatible = "compex,wpq873", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               led-boot = &led_power_blue;
-               led-failsafe = &led_power_red;
-               led-running = &led_system_green;
-               led-upgrade = &led_system_blue;
-               /* Aliases as required by u-boot to patch MAC addresses */
-               ethernet0 = &dp6;
-               ethernet1 = &dp2;
-               ethernet2 = &dp3;
-               ethernet3 = &dp4;
-               label-mac-device = &dp6;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " root=/dev/ubiblock0_1";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 21 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led_power_red: power-red {
-                       label = "red:power";
-                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-               };
-
-               led_power_blue: power-blue {
-                       label = "blue:power";
-                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_BLUE>;
-               };
-
-               led_system_red: system-red {
-                       label = "red:system";
-                       gpios = <&tlmm 28 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-               };
-
-               led_system_green: system-green {
-                       label = "green:system";
-                       gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-               };
-
-               led_system_blue: system-blue {
-                       label = "blue:system";
-                       gpios = <&tlmm 19 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_BLUE>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       i2c_pins: i2c-pins {
-               pins = "gpio0", "gpio2";
-               function = "blsp5_i2c";
-               drive-strength = <8>;
-               bias-disable;
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&blsp1_i2c6 {
-       status = "okay";
-
-       pinctrl-0 = <&i2c_pins>;
-       pinctrl-names = "default";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&blsp1_spi1 {
-       status = "okay";
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-
-       button_pins: button_pins {
-               reset_button {
-                       pins = "gpio66";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_spi1 {
-       status = "okay";
-
-       flash@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "0:sbl1";
-                               reg = <0x0 0x50000>;
-                               read-only;
-                       };
-
-                       partition@50000 {
-                               label = "0:mibib";
-                               reg = <0x50000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@60000 {
-                               label = "0:bootconfig";
-                               reg = <0x60000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@80000 {
-                               label = "0:bootconfig1";
-                               reg = <0x80000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@a0000 {
-                               label = "0:qsee";
-                               reg = <0xa0000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@220000 {
-                               label = "0:qsee_1";
-                               reg = <0x220000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@3a0000 {
-                               label = "0:devcfg";
-                               reg = <0x3a0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3b0000 {
-                               label = "0:devcfg_1";
-                               reg = <0x3b0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3c0000 {
-                               label = "0:apdp";
-                               reg = <0x3c0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3d0000 {
-                               label = "0:apdp_1";
-                               reg = <0x3d0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3e0000 {
-                               label = "0:rpm";
-                               reg = <0x3e0000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@420000 {
-                               label = "0:rpm_1";
-                               reg = <0x420000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@460000 {
-                               label = "0:cdt";
-                               reg = <0x460000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@470000 {
-                               label = "0:cdt_1";
-                               reg = <0x470000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@480000 {
-                               label = "0:appsblenv";
-                               reg = <0x480000 0x10000>;
-                       };
-
-                       partition@490000 {
-                               label = "0:appsbl";
-                               reg = <0x490000 0xa0000>;
-                               read-only;
-                       };
-
-                       partition@550000 {
-                               label = "0:appsbl_1";
-                               reg = <0x530000 0xa0000>;
-                               read-only;
-                       };
-
-                       partition@610000 {
-                               label = "0:art";
-                               reg = <0x5d0000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@650000 {
-                               label = "0:ethphyfw";
-                               reg = <0x610000 0x80000>;
-                               read-only;
-                       };
-               };
-       };
-};
-
-&qpic_nand {
-       status = "okay";
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <8>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "rootfs";
-                               reg = <0x0000000 0x3400000>;
-                       };
-
-                       partition@3400000 {
-                               label = "0:wififw";
-                               reg = <0x3400000 0x800000>;
-                               read-only;
-                       };
-
-                       partition@3c00000 {
-                               label = "rootfs_1";
-                               reg = <0x3c00000 0x3400000>;
-                       };
-
-                       partition@7000000 {
-                               label = "0:wififw_1";
-                               reg = <0x7000000 0x800000>;
-                               read-only;
-                       };
-               };
-       };
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&qusb_phy_1 {
-       status = "okay";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&ssphy_1 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&usb_1 {
-       status = "okay";
-};
-
-
-&mdio {
-       status = "okay";
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       qca8075_1: ethernet-phy@1 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <1>;
-       };
-
-       qca8075_2: ethernet-phy@2 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <2>;
-       };
-
-       qca8075_3: ethernet-phy@3 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <3>;
-       };
-
-       qca8081: ethernet-phy@28 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <28>;
-               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
-       };
-
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-       switch_lan_bmp = <0x3e>; /* lan port bitmap */
-       switch_wan_bmp = <0x40>; /* wan port bitmap */
-       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
-       switch_mac_mode1 = <0x0f>; /* mac mode for uniphy instance1*/
-       switch_mac_mode2 = <0x0f>; /* mac mode for uniphy instance2*/
-       bm_tick_mode = <0>; /* bm tick mode */
-       tm_tick_mode = <0>; /* tm tick mode */
-
-       qcom,port_phyinfo {
-               port@2 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-               port@3 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-               port@4 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-               port@5 {
-                       port_id = <6>;
-                       phy_address = <28>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp2 {
-        status = "okay";
-        phy-handle = <&qca8075_1>;
-        label = "lan1";
-};
-
-&dp3 {
-        status = "okay";
-        phy-handle = <&qca8075_2>;
-        label = "lan2";
-};
-
-&dp4 {
-        status = "okay";
-        phy-handle = <&qca8075_3>;
-        label = "lan3";
-};
-
-&dp6 {
-        status = "okay";
-        phy-handle = <&qca8081>;
-        label = "wan";
-};
-
-&pcie_qmp0 {
-       status = "okay";
-};
-
-&pcie0 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 58 GPIO_ACTIVE_LOW>;
-
-       bridge@0,0 {
-               reg = <0x00020000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-       };
-};
-
-&pcie_qmp1 {
-       status = "okay";
-};
-
-&pcie1 {
-       status = "okay";
-
-       perst-gpio = <&tlmm 62 GPIO_ACTIVE_HIGH>;
-
-       bridge@1,0 {
-               reg = <0x00010000 0 0 0 0>;
-               #address-cells = <3>;
-               #size-cells = <2>;
-               ranges;
-       };
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Compex-WPQ873";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-512m.dtsi b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-512m.dtsi
deleted file mode 100644 (file)
index dace400..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include "ipq8074.dtsi"
-
-&tzapp_region {
-       reg = <0x0 0x4a400000 0x0 0x100000>;
-};
-
-&q6_region {
-       reg = <0x0 0x4b000000 0x0 0x3700000>;
-};
-
-&q6_etr_region {
-       reg = <0x0 0x4e700000 0x0 0x100000>;
-};
-
-&m3_dump_region {
-       reg = <0x0 0x4e800000 0x0 0x100000>;
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-ac-cpu.dtsi b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-ac-cpu.dtsi
deleted file mode 100644 (file)
index 057d592..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <dt-bindings/thermal/thermal.h>
-#include "ipq8074-cpr-regulator.dtsi"
-
-&CPU0 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-
-&CPU1 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-
-&CPU2 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-
-&CPU3 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-&cpu0_thermal {
-       trips {
-               cpu0_passive: cpu-passive {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu0_passive>;
-                       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>;
-               };
-       };
-};
-
-&cpu1_thermal {
-       trips {
-               cpu1_passive: cpu-passive {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu1_passive>;
-                       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>;
-               };
-       };
-};
-
-&cpu2_thermal {
-       trips {
-               cpu2_passive: cpu-passive {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu2_passive>;
-                       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>;
-               };
-       };
-};
-
-&cpu3_thermal {
-       trips {
-               cpu3_passive: cpu-passive {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu3_passive>;
-                       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>;
-               };
-       };
-};
-
-&cluster_thermal {
-       trips {
-               cluster_passive: cluster-passive {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cluster_passive>;
-                       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/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-cpr-regulator.dtsi b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-cpr-regulator.dtsi
deleted file mode 100644 (file)
index e351a2e..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include "pmp8074.dtsi"
-
-&soc {
-       apc_apm: apm@b111000 {
-               compatible = "qcom,ipq807x-apm";
-               reg = <0xb111000 0x1000>;
-               reg-names = "pm-apcc-glb";
-               qcom,apm-post-halt-delay = <0x2>;
-               qcom,apm-halt-clk-delay = <0x11>;
-               qcom,apm-resume-clk-delay = <0x10>;
-               qcom,apm-sel-switch-delay = <0x01>;
-       };
-
-       apc_cpr: cpr4-ctrl@b018000 {
-               compatible = "qcom,cpr4-ipq807x-apss-regulator";
-               reg = <0xb018000 0x4000>, <0xa4000 0x1000>, <0x0193d008 0x4>;
-               reg-names = "cpr_ctrl", "fuse_base", "cpr_tcsr_reg";
-               interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
-               interrupt-names = "cpr";
-               qcom,cpr-ctrl-name = "apc";
-               qcom,cpr-sensor-time = <1000>;
-               qcom,cpr-loop-time = <5000000>;
-               qcom,cpr-idle-cycles = <15>;
-               qcom,cpr-step-quot-init-min = <12>;
-               qcom,cpr-step-quot-init-max = <14>;
-               qcom,cpr-count-mode = <0>;              /* All-at-once */
-               qcom,cpr-count-repeat = <14>;
-               qcom,cpr-down-error-step-limit = <1>;
-               qcom,cpr-up-error-step-limit = <1>;
-               qcom,apm-ctrl = <&apc_apm>;
-               qcom,apm-threshold-voltage = <848000>;
-               vdd-supply = <&s3>;
-               qcom,voltage-step = <8000>;
-
-               thread@0 {
-                       qcom,cpr-thread-id = <0>;
-                       qcom,cpr-consecutive-up = <0>;
-                       qcom,cpr-consecutive-down = <0>;
-                       qcom,cpr-up-threshold = <4>;
-                       qcom,cpr-down-threshold = <1>;
-
-                       apc_vreg: regulator {
-                               regulator-name = "apc_corner";
-                               regulator-min-microvolt = <1>;
-                               regulator-max-microvolt = <6>;
-                               qcom,cpr-part-types = <2>;
-                               qcom,cpr-parts-voltage = <1048000>;
-                               qcom,cpr-parts-voltage-v2 = <992000>;
-                               qcom,cpr-fuse-corners = <4>;
-                               qcom,cpr-fuse-combos = <8>;
-                               qcom,cpr-corners = <6>;
-                               qcom,cpr-speed-bins = <1>;
-                               qcom,cpr-speed-bin-corners = <6>;
-                               qcom,cpr-corner-fmax-map = <1 3 5 6>;
-                               qcom,allow-voltage-interpolation;
-                               qcom,allow-quotient-interpolation;
-                               qcom,cpr-scaled-open-loop-voltage-as-ceiling;
-                               qcom,cpr-voltage-ceiling =
-                                       <840000 904000 944000
-                                        984000 992000 1064000>;
-                               qcom,cpr-voltage-floor =
-                                       <592000 648000 712000
-                                        744000 784000 848000>;
-                               qcom,corner-frequencies =
-                                       <1017600000 1382400000 1651200000
-                                       1843200000 1920000000 2208000000>;
-
-                               /* TT/FF parts i.e. turbo L1 OL voltage < 1048 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-0 =
-                                       /* Speed bin 0; CPR rev 0..7 */
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0 12000>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>;
-
-                               /* SS parts i.e turbo L1 OL voltage >= 1048 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-1 =
-                                       /* Speed bin 0; CPR rev 0..7 */
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       < 20000  26000      0 20000>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>;
-
-                               /* v2 - FF parts i.e. turbo L1 OL voltage < 992 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-0 =
-                                        /* Speed bin 0; CPR rev 0..7 */
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>;
-
-                               /* v2 - SS/TT parts i.e turbo L1 OL voltage >= 992 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-1 =
-                                       /* Speed bin 0; CPR rev 0..7 */
-                                       <     0      0      0     0>,
-                                       <     0   7000  36000  4000>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>;
-
-                               /* v2 - FF parts i.e. turbo L1 OL voltage < 992 mV */
-                               qcom,cpr-closed-loop-voltage-adjustment-v2-0 =
-                                       /* Speed bin 0; CPR rev 0..7 */
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>;
-
-                               /* v2 - SS/TT parts i.e turbo L1 OL voltage >= 992 mV */
-                               qcom,cpr-closed-loop-voltage-adjustment-v2-1 =
-                                       /* Speed bin 0; CPR rev 0..7 */
-                                       <     0      0      0     0>,
-                                       <     0      0      19000 0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>,
-                                       <     0      0      0     0>;
-
-                               qcom,cpr-ro-scaling-factor =
-                                       < 3970 4150 0    2280 2520 2470 2250 2280
-                                         2390 2330 2530 2500  850 2900 2510 2170 >,
-                                       < 3970 4150 0    2280 2520 2470 2250 2280
-                                         2390 2330 2530 2500  850 2900 2510 2170 >,
-                                       < 3970 4150 0    2280 2520 2470 2250 2280
-                                         2390 2330 2530 2500  850 2900 2510 2170 >,
-                                       < 3970 4150 0    2280 2520 2470 2250 2280
-                                         2390 2330 2530 2500  850 2900 2510 2170 >;
-
-                               qcom,cpr-floor-to-ceiling-max-range =
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>,
-                                       < 40000 40000 40000 40000 40000 40000>;
-                               regulator-always-on;
-                       };
-               };
-       };
-
-       npu_cpr: npu-cpr {
-               compatible = "qcom,cpr3-ipq807x-npu-regulator";
-               reg = <0xa4000 0x1000>, <0x0193d008 0x4>;
-               reg-names = "fuse_base", "cpr_tcsr_reg";
-               qcom,cpr-ctrl-name = "npu";
-               vdd-supply = <&s4>;
-               qcom,voltage-step = <8000>;
-               thread@0 {
-                       qcom,cpr-thread-id = <0>;
-                       qcom,cpr-consecutive-up = <0>;
-                       qcom,cpr-consecutive-down = <2>;
-                       qcom,cpr-up-threshold = <2>;
-                       qcom,cpr-down-threshold = <1>;
-
-                       npu_vreg: regulator {
-                               regulator-name = "npu_corner";
-                               regulator-min-microvolt = <1>;
-                               regulator-max-microvolt = <3>;
-                               qcom,cpr-part-types = <2>;
-                               qcom,cpr-parts-voltage = <968000>;
-                               qcom,cpr-parts-voltage-v2 = <832001>;
-                               qcom,cpr-cold-temp-threshold-v2 = <30>;
-                               qcom,cpr-fuse-corners = <2>;
-                               qcom,cpr-fuse-combos = <1>;
-                               qcom,cpr-corners = <2>;
-                               qcom,cpr-speed-bins = <1>;
-                               qcom,cpr-speed-bin-corners = <2>;
-                               qcom,allow-voltage-interpolation;
-                               qcom,cpr-corner-fmax-map = <1 2>;
-                               qcom,cpr-voltage-ceiling =
-                                       <912000 992000>;
-                               qcom,cpr-voltage-floor =
-                                       <752000 792000>;
-                               qcom,corner-frequencies =
-                                       <1497600000 1689600000>;
-
-                               /* TT/FF parts i.e. turbo OL voltage < 968 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-0 =
-                                       < 40000   40000>;
-
-                               /* SS parts i.e turbo OL voltage >= 968 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-1 =
-                                       < 24000   24000>;
-
-                               /* FF parts i.e. turbo OL voltage <= 832 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-0=
-                                       <40000   40000>;
-
-                                /* TT/SS parts i.e turbo OL voltage > 832 mV */
-                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-1=
-                                       <40000   40000>;
-
-                               /* FF parts i.e. turbo OL voltage <= 832 mV */
-                               qcom,cpr-cold-temp-voltage-adjustment-v2-0 =
-                                       <0   0>;
-
-                               /* TT/SS parts i.e turbo OL voltage > 832 mV */
-                               qcom,cpr-cold-temp-voltage-adjustment-v2-1 =
-                                       <35000   27000>;
-                       };
-               };
-       };
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-ess.dtsi b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-ess.dtsi
deleted file mode 100644 (file)
index 129266c..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-&clocks {
-       bias_pll_cc_clk {
-               compatible = "fixed-clock";
-               clock-frequency = <300000000>;
-               #clock-cells = <0>;
-       };
-
-       bias_pll_nss_noc_clk {
-               compatible = "fixed-clock";
-               clock-frequency = <416500000>;
-               #clock-cells = <0>;
-       };
-};
-
-&soc {
-       switch: ess-switch@3a000000 {
-               compatible = "qcom,ess-switch-ipq807x";
-               reg = <0x3a000000 0x1000000>;
-               switch_access_mode = "local bus";
-               switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
-               switch_inner_bmp = <0x80>; /*inner port bitmap*/
-               clocks = <&gcc GCC_CMN_12GPLL_AHB_CLK>,
-                        <&gcc GCC_CMN_12GPLL_SYS_CLK>,
-                        <&gcc GCC_UNIPHY0_AHB_CLK>,
-                        <&gcc GCC_UNIPHY0_SYS_CLK>,
-                        <&gcc GCC_UNIPHY1_AHB_CLK>,
-                        <&gcc GCC_UNIPHY1_SYS_CLK>,
-                        <&gcc GCC_UNIPHY2_AHB_CLK>,
-                        <&gcc GCC_UNIPHY2_SYS_CLK>,
-                        <&gcc GCC_PORT1_MAC_CLK>,
-                        <&gcc GCC_PORT2_MAC_CLK>,
-                        <&gcc GCC_PORT3_MAC_CLK>,
-                        <&gcc GCC_PORT4_MAC_CLK>,
-                        <&gcc GCC_PORT5_MAC_CLK>,
-                        <&gcc GCC_PORT6_MAC_CLK>,
-                        <&gcc GCC_NSS_PPE_CLK>,
-                        <&gcc GCC_NSS_PPE_CFG_CLK>,
-                        <&gcc GCC_NSSNOC_PPE_CLK>,
-                        <&gcc GCC_NSSNOC_PPE_CFG_CLK>,
-                        <&gcc GCC_NSS_EDMA_CLK>,
-                        <&gcc GCC_NSS_EDMA_CFG_CLK>,
-                        <&gcc GCC_NSS_PPE_IPE_CLK>,
-                        <&gcc GCC_NSS_PPE_BTQ_CLK>,
-                        <&gcc GCC_MDIO_AHB_CLK>,
-                        <&gcc GCC_NSS_NOC_CLK>,
-                        <&gcc GCC_NSSNOC_SNOC_CLK>,
-                        <&gcc GCC_MEM_NOC_NSS_AXI_CLK>,
-                        <&gcc GCC_NSS_CRYPTO_CLK>,
-                        <&gcc GCC_NSS_IMEM_CLK>,
-                        <&gcc GCC_NSS_PTP_REF_CLK>,
-                        <&gcc GCC_NSS_PORT1_RX_CLK>,
-                        <&gcc GCC_NSS_PORT1_TX_CLK>,
-                        <&gcc GCC_NSS_PORT2_RX_CLK>,
-                        <&gcc GCC_NSS_PORT2_TX_CLK>,
-                        <&gcc GCC_NSS_PORT3_RX_CLK>,
-                        <&gcc GCC_NSS_PORT3_TX_CLK>,
-                        <&gcc GCC_NSS_PORT4_RX_CLK>,
-                        <&gcc GCC_NSS_PORT4_TX_CLK>,
-                        <&gcc GCC_NSS_PORT5_RX_CLK>,
-                        <&gcc GCC_NSS_PORT5_TX_CLK>,
-                        <&gcc GCC_NSS_PORT6_RX_CLK>,
-                        <&gcc GCC_NSS_PORT6_TX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT1_RX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT1_TX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT2_RX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT2_TX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT3_RX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT3_TX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT4_RX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT4_TX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT5_RX_CLK>,
-                        <&gcc GCC_UNIPHY0_PORT5_TX_CLK>,
-                        <&gcc GCC_UNIPHY1_PORT5_RX_CLK>,
-                        <&gcc GCC_UNIPHY1_PORT5_TX_CLK>,
-                        <&gcc GCC_UNIPHY2_PORT6_RX_CLK>,
-                        <&gcc GCC_UNIPHY2_PORT6_TX_CLK>,
-                        <&gcc NSS_PORT5_RX_CLK_SRC>,
-                        <&gcc NSS_PORT5_TX_CLK_SRC>;
-               clock-names = "cmn_ahb_clk", "cmn_sys_clk",
-                             "uniphy0_ahb_clk", "uniphy0_sys_clk",
-                             "uniphy1_ahb_clk", "uniphy1_sys_clk",
-                             "uniphy2_ahb_clk", "uniphy2_sys_clk",
-                             "port1_mac_clk", "port2_mac_clk",
-                             "port3_mac_clk", "port4_mac_clk",
-                             "port5_mac_clk", "port6_mac_clk",
-                             "nss_ppe_clk", "nss_ppe_cfg_clk",
-                             "nssnoc_ppe_clk", "nssnoc_ppe_cfg_clk",
-                             "nss_edma_clk", "nss_edma_cfg_clk",
-                             "nss_ppe_ipe_clk", "nss_ppe_btq_clk",
-                             "gcc_mdio_ahb_clk", "gcc_nss_noc_clk",
-                             "gcc_nssnoc_snoc_clk",
-                             "gcc_mem_noc_nss_axi_clk",
-                             "gcc_nss_crypto_clk",
-                             "gcc_nss_imem_clk",
-                             "gcc_nss_ptp_ref_clk",
-                             "nss_port1_rx_clk", "nss_port1_tx_clk",
-                             "nss_port2_rx_clk", "nss_port2_tx_clk",
-                             "nss_port3_rx_clk", "nss_port3_tx_clk",
-                             "nss_port4_rx_clk", "nss_port4_tx_clk",
-                             "nss_port5_rx_clk", "nss_port5_tx_clk",
-                             "nss_port6_rx_clk", "nss_port6_tx_clk",
-                             "uniphy0_port1_rx_clk",
-                             "uniphy0_port1_tx_clk",
-                             "uniphy0_port2_rx_clk",
-                             "uniphy0_port2_tx_clk",
-                             "uniphy0_port3_rx_clk",
-                             "uniphy0_port3_tx_clk",
-                             "uniphy0_port4_rx_clk",
-                             "uniphy0_port4_tx_clk",
-                             "uniphy0_port5_rx_clk",
-                             "uniphy0_port5_tx_clk",
-                             "uniphy1_port5_rx_clk",
-                             "uniphy1_port5_tx_clk",
-                             "uniphy2_port6_rx_clk",
-                             "uniphy2_port6_tx_clk",
-                             "nss_port5_rx_clk_src",
-                             "nss_port5_tx_clk_src";
-               resets = <&gcc GCC_PPE_FULL_RESET>,
-                        <&gcc GCC_UNIPHY0_SOFT_RESET>,
-                        <&gcc GCC_UNIPHY0_XPCS_RESET>,
-                        <&gcc GCC_UNIPHY1_SOFT_RESET>,
-                        <&gcc GCC_UNIPHY1_XPCS_RESET>,
-                        <&gcc GCC_UNIPHY2_SOFT_RESET>,
-                        <&gcc GCC_UNIPHY2_XPCS_RESET>,
-                        <&gcc GCC_NSSPORT1_RESET>,
-                        <&gcc GCC_NSSPORT2_RESET>,
-                        <&gcc GCC_NSSPORT3_RESET>,
-                        <&gcc GCC_NSSPORT4_RESET>,
-                        <&gcc GCC_NSSPORT5_RESET>,
-                        <&gcc GCC_NSSPORT6_RESET>;
-               reset-names = "ppe_rst", "uniphy0_soft_rst",
-                             "uniphy0_xpcs_rst", "uniphy1_soft_rst",
-                             "uniphy1_xpcs_rst", "uniphy2_soft_rst",
-                             "uniphy2_xpcs_rst", "nss_port1_rst",
-                             "nss_port2_rst", "nss_port3_rst",
-                             "nss_port4_rst", "nss_port5_rst",
-                             "nss_port6_rst";
-               mdio-bus = <&mdio>;
-               status = "disabled";
-
-               port_scheduler_resource {
-                       port@0 {
-                               port_id = <0>;
-                               ucast_queue = <0 143>;
-                               mcast_queue = <256 271>;
-                               l0sp = <0 35>;
-                               l0cdrr = <0 47>;
-                               l0edrr = <0 47>;
-                               l1cdrr = <0 7>;
-                               l1edrr = <0 7>;
-                       };
-                       port@1 {
-                               port_id = <1>;
-                               ucast_queue = <144 159>;
-                               mcast_queue = <272 275>;
-                               l0sp = <36 39>;
-                               l0cdrr = <48 63>;
-                               l0edrr = <48 63>;
-                               l1cdrr = <8 11>;
-                               l1edrr = <8 11>;
-                       };
-                       port@2 {
-                               port_id = <2>;
-                               ucast_queue = <160 175>;
-                               mcast_queue = <276 279>;
-                               l0sp = <40 43>;
-                               l0cdrr = <64 79>;
-                               l0edrr = <64 79>;
-                               l1cdrr = <12 15>;
-                               l1edrr = <12 15>;
-                       };
-                       port@3 {
-                               port_id = <3>;
-                               ucast_queue = <176 191>;
-                               mcast_queue = <280 283>;
-                               l0sp = <44 47>;
-                               l0cdrr = <80 95>;
-                               l0edrr = <80 95>;
-                               l1cdrr = <16 19>;
-                               l1edrr = <16 19>;
-                       };
-                       port@4 {
-                               port_id = <4>;
-                               ucast_queue = <192 207>;
-                               mcast_queue = <284 287>;
-                               l0sp = <48 51>;
-                               l0cdrr = <96 111>;
-                               l0edrr = <96 111>;
-                               l1cdrr = <20 23>;
-                               l1edrr = <20 23>;
-                       };
-                       port@5 {
-                               port_id = <5>;
-                               ucast_queue = <208 223>;
-                               mcast_queue = <288 291>;
-                               l0sp = <52 55>;
-                               l0cdrr = <112 127>;
-                               l0edrr = <112 127>;
-                               l1cdrr = <24 27>;
-                               l1edrr = <24 27>;
-                       };
-                       port@6 {
-                               port_id = <6>;
-                               ucast_queue = <224 239>;
-                               mcast_queue = <292 295>;
-                               l0sp = <56 59>;
-                               l0cdrr = <128 143>;
-                               l0edrr = <128 143>;
-                               l1cdrr = <28 31>;
-                               l1edrr = <28 31>;
-                       };
-                       port@7 {
-                               port_id = <7>;
-                               ucast_queue = <240 255>;
-                               mcast_queue = <296 299>;
-                               l0sp = <60 63>;
-                               l0cdrr = <144 159>;
-                               l0edrr = <144 159>;
-                               l1cdrr = <32 35>;
-                               l1edrr = <32 35>;
-                       };
-               };
-               port_scheduler_config {
-                       port@0 {
-                               port_id = <0>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <0 1>; /*L0 SPs*/
-                                               /*cpri cdrr epri edrr*/
-                                               cfg = <0 0 0 0>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               /*unicast queues*/
-                                               ucast_queue = <0 4 8>;
-                                               /*multicast queues*/
-                                               mcast_queue = <256 260>;
-                                               /*sp cpri cdrr epri edrr*/
-                                               cfg = <0 0 0 0 0>;
-                                       };
-                                       group@1 {
-                                               ucast_queue = <1 5 9>;
-                                               mcast_queue = <257 261>;
-                                               cfg = <0 1 1 1 1>;
-                                       };
-                                       group@2 {
-                                               ucast_queue = <2 6 10>;
-                                               mcast_queue = <258 262>;
-                                               cfg = <0 2 2 2 2>;
-                                       };
-                                       group@3 {
-                                               ucast_queue = <3 7 11>;
-                                               mcast_queue = <259 263>;
-                                               cfg = <0 3 3 3 3>;
-                                       };
-                               };
-                       };
-                       port@1 {
-                               port_id = <1>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <36>;
-                                               cfg = <0 8 0 8>;
-                                       };
-                                       group@1 {
-                                               sp = <37>;
-                                               cfg = <1 9 1 9>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <144>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <272>;
-                                               mcast_loop_pri = <4>;
-                                               cfg = <36 0 48 0 48>;
-                                       };
-                               };
-                       };
-                       port@2 {
-                               port_id = <2>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <40>;
-                                               cfg = <0 12 0 12>;
-                                       };
-                                       group@1 {
-                                               sp = <41>;
-                                               cfg = <1 13 1 13>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <160>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <276>;
-                                               mcast_loop_pri = <4>;
-                                               cfg = <40 0 64 0 64>;
-                                       };
-                               };
-                       };
-                       port@3 {
-                               port_id = <3>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <44>;
-                                               cfg = <0 16 0 16>;
-                                       };
-                                       group@1 {
-                                               sp = <45>;
-                                               cfg = <1 17 1 17>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <176>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <280>;
-                                               mcast_loop_pri = <4>;
-                                               cfg = <44 0 80 0 80>;
-                                       };
-                               };
-                       };
-                       port@4 {
-                               port_id = <4>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <48>;
-                                               cfg = <0 20 0 20>;
-                                       };
-                                       group@1 {
-                                               sp = <49>;
-                                               cfg = <1 21 1 21>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <192>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <284>;
-                                               mcast_loop_pri = <4>;
-                                               cfg = <48 0 96 0 96>;
-                                       };
-                               };
-                       };
-                       port@5 {
-                               port_id = <5>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <52>;
-                                               cfg = <0 24 0 24>;
-                                       };
-                                       group@1 {
-                                               sp = <53>;
-                                               cfg = <1 25 1 25>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <208>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <288>;
-                                               mcast_loop_pri = <4>;
-                                               cfg = <52 0 112 0 112>;
-                                       };
-                               };
-                       };
-                       port@6 {
-                               port_id = <6>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <56>;
-                                               cfg = <0 28 0 28>;
-                                       };
-                                       group@1 {
-                                               sp = <57>;
-                                               cfg = <1 29 1 29>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <224>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <292>;
-                                               mcast_loop_pri = <4>;
-                                               cfg = <56 0 128 0 128>;
-                                       };
-                               };
-                       };
-                       port@7 {
-                               port_id = <7>;
-                               l1scheduler {
-                                       group@0 {
-                                               sp = <60>;
-                                               cfg = <0 32 0 32>;
-                                       };
-                                       group@1 {
-                                               sp = <61>;
-                                               cfg = <1 33 1 33>;
-                                       };
-                               };
-                               l0scheduler {
-                                       group@0 {
-                                               ucast_queue = <240>;
-                                               ucast_loop_pri = <16>;
-                                               mcast_queue = <296>;
-                                               cfg = <60 0 144 0 144>;
-                                       };
-                               };
-                       };
-               };
-       };
-
-       ess-uniphy@7a00000 {
-               compatible = "qcom,ess-uniphy";
-               reg = <0x7a00000 0x30000>;
-               uniphy_access_mode = "local bus";
-       };
-
-       edma: edma@3ab00000 {
-               compatible = "qcom,edma";
-               reg = <0x3ab00000 0x76900>;
-               reg-names = "edma-reg-base";
-               qcom,txdesc-ring-start = <23>;
-               qcom,txdesc-rings = <1>;
-               qcom,txcmpl-ring-start = <7>;
-               qcom,txcmpl-rings = <1>;
-               qcom,rxfill-ring-start = <7>;
-               qcom,rxfill-rings = <1>;
-               qcom,rxdesc-ring-start = <15>;
-               qcom,rxdesc-rings = <1>;
-               interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
-               resets = <&gcc GCC_EDMA_HW_RESET>;
-               reset-names = "edma_rst";
-               status = "disabled";
-       };
-
-       dp1: dp1 {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <1>;
-               reg = <0x3a001000 0x200>;
-               qcom,mactype = <0>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp2: dp2 {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <2>;
-               reg = <0x3a001200 0x200>;
-               qcom,mactype = <0>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp3: dp3 {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <3>;
-               reg = <0x3a001400 0x200>;
-               qcom,mactype = <0>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp4: dp4 {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <4>;
-               reg = <0x3a001600 0x200>;
-               qcom,mactype = <0>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp5: dp5 {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <5>;
-               reg = <0x3a001800 0x200>;
-               qcom,mactype = <0>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp6: dp6 {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <6>;
-               reg = <0x3a001a00 0x200>;
-               qcom,mactype = <0>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp5_syn: dp5-syn {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <5>;
-               reg = <0x3a003000 0x3fff>;
-               qcom,mactype = <1>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-
-       dp6_syn: dp6-syn {
-               device_type = "network";
-               compatible = "qcom,nss-dp";
-               qcom,id = <6>;
-               reg = <0x3a007000 0x3fff>;
-               qcom,mactype = <1>;
-               local-mac-address = [000000000000];
-               phy-mode = "sgmii";
-               status = "disabled";
-       };
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-hk-cpu.dtsi b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-hk-cpu.dtsi
deleted file mode 100644 (file)
index 37af7bb..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <dt-bindings/thermal/thermal.h>
-#include "ipq8074-cpr-regulator.dtsi"
-
-&CPU0 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-
-&CPU1 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-
-&CPU2 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-
-&CPU3 {
-       cpu-supply = <&apc_vreg>;
-       voltage-tolerance = <1>;
-};
-&cpu0_thermal {
-       trips {
-               cpu0_passive_low: cpu-passive-low {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-
-               cpu0_passive_high: cpu-passive-high {
-                       temperature = <100000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu0_passive_low>;
-                       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>;
-               };
-               map1 {
-                       trip = <&cpu0_passive_high>;
-                       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>;
-               };
-       };
-};
-
-&cpu1_thermal {
-       trips {
-               cpu1_passive_low: cpu-passive-low {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-
-               cpu1_passive_high: cpu-passive-high {
-                       temperature = <100000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu1_passive_low>;
-                       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>;
-               };
-               map1 {
-                       trip = <&cpu1_passive_high>;
-                       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>;
-               };
-       };
-};
-
-&cpu2_thermal {
-       trips {
-               cpu2_passive_low: cpu-passive-low {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-
-               cpu2_passive_high: cpu-passive-high {
-                       temperature = <100000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu2_passive_low>;
-                       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>;
-               };
-               map1 {
-                       trip = <&cpu2_passive_high>;
-                       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>;
-               };
-       };
-};
-
-&cpu3_thermal {
-       trips {
-               cpu3_passive_low: cpu-passive-low {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-
-               cpu3_passive_high: cpu-passive-high {
-                       temperature = <100000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cpu3_passive_low>;
-                       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>;
-               };
-               map1 {
-                       trip = <&cpu3_passive_high>;
-                       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>;
-               };
-       };
-};
-
-&cluster_thermal {
-       trips {
-               cluster_passive_low: cluster-passive {
-                       temperature = <95000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-
-               cluster_passive_high: cluster-passive-high {
-                       temperature = <100000>;
-                       hysteresis = <2000>;
-                       type = "passive";
-               };
-       };
-
-       cooling-maps {
-               map0 {
-                       trip = <&cluster_passive_low>;
-                       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>;
-               };
-               map1 {
-                       trip = <&cluster_passive_high>;
-                       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/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts
deleted file mode 100644 (file)
index d113b23..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright (c) 2022, Karol Przybylski <itor@o2.pl>
- * Copyright (c) 2023, Andre Valentin <avalentin@marcant.net>
- */
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/leds/common.h>
-#include <dt-bindings/input/input.h>
-
-
-/ {
-       model = "Zyxel NBG7815";
-       compatible = "zyxel,nbg7815", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               serial1 = &blsp1_uart3;
-               /* Alias as required by u-boot to patch MAC addresses */
-               ethernet0 = &dp1;
-               label-mac-device = &dp1;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               reset {
-                       label = "reset";
-                       linux,code = <KEY_RESTART>;
-                       gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
-               };
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-
-&blsp1_uart3 {
-       status = "okay";
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-
-&blsp1_spi1 {
-       pinctrl-0 = <&spi_0_pins>;
-       pinctrl-names = "default";
-       cs-gpios = <0>;
-       status = "okay";
-
-       /*
-        * Bootloader will find the NAND DT node by the compatible and
-        * then "fixup" it by adding the partitions from the SMEM table
-        * using the legacy bindings thus making it impossible for us
-        * to change the partition table or utilize NVMEM for calibration.
-        * So add a dummy partitions node that bootloader will populate
-        * and set it as disabled so the kernel ignores it instead of
-        * printing warnings due to the broken way bootloader adds the
-        * partitions.
-        */
-       partitions {
-               status = "disabled";
-       };
-
-
-       flash@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               reg = <0>;
-               compatible = "jedec,spi-nor";
-               spi-max-frequency = <50000000>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "0:sbl1";
-                               reg = <0x0 0x50000>;
-                               read-only;
-                       };
-
-                       partition@50000 {
-                               label = "0:mibib";
-                               reg = <0x50000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@60000 {
-                               label = "0:bootconfig";
-                               reg = <0x60000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@80000 {
-                               label = "0:bootconfig1";
-                               reg = <0x80000 0x20000>;
-                               read-only;
-                       };
-
-                       partition@a0000 {
-                               label = "0:qsee";
-                               reg = <0xa0000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@220000 {
-                               label = "0:qsee_1";
-                               reg = <0x220000 0x180000>;
-                               read-only;
-                       };
-
-                       partition@3a0000 {
-                               label = "0:devcfg";
-                               reg = <0x3a0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3b0000 {
-                               label = "0:devcfg_1";
-                               reg = <0x3b0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3c0000 {
-                               label = "0:apdp";
-                               reg = <0x3c0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3d0000 {
-                               label = "0:apdp_1";
-                               reg = <0x3d0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@3e0000 {
-                               label = "0:rpm";
-                               reg = <0x3e0000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@420000 {
-                               label = "0:rpm_1";
-                               reg = <0x420000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@460000 {
-                               label = "0:cdt";
-                               reg = <0x460000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@470000 {
-                               label = "0:cdt_1";
-                               reg = <0x470000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@480000 {
-                               label = "0:appsbl";
-                               reg = <0x480000 0xc0000>;
-                               read-only;
-                       };
-
-                       partition@540000 {
-                               label = "0:appsbl_1";
-                               reg = <0x540000 0xc0000>;
-                               read-only;
-                       };
-
-                       partition@600000 {
-                               compatible = "u-boot,env";
-                               label = "0:appsblenv";
-                               reg = <0x600000 0x10000>;
-
-                               macaddr_lan: ethaddr {
-                                       #nvmem-cell-cells = <1>;
-                               };
-                       };
-
-                       partition@610000 {
-                               label = "0:art";
-                               reg = <0x610000 0x40000>;
-                               read-only;
-                       };
-
-                       partition@650000 {
-                               label = "0:ethphyfw";
-                               reg = <0x650000 0x80000>;
-                               read-only;
-                       };
-
-                       partition@6d0000 {
-                               label = "0:crt";
-                               reg = <0x6d0000 0x10000>;
-                               read-only;
-                       };
-
-                       partition@6e0000 {
-                               label = "dual_flag";
-                               reg = <0x6e0000 0x10000>;
-                       };
-
-                       partition@6f0000 {
-                               label = "reserved";
-                               reg = <0x6f0000 0x110000>;
-                               read-only;
-                       };
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
-
-       qca8075_1: ethernet-phy@0 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0>;
-       };
-
-       qca8075_2: ethernet-phy@1 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <1>;
-       };
-
-       qca8075_3: ethernet-phy@2 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <2>;
-       };
-
-       qca8075_4: ethernet-phy@3 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <3>;
-       };
-
-       qca8081: ethernet-phy@4{
-               compatible = "ethernet-phy-id004d.d101";
-               reg = <28>;
-               reset-gpios = <&tlmm 31 GPIO_ACTIVE_LOW>;
-       };
-
-       aqr113c: ethernet-phy@5 {
-               compatible = "ethernet-phy-ieee802.3-c45";
-               reg = <8>;
-               reset-gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;
-       switch_lan_bmp = <0x3e>;
-       switch_wan_bmp = <0x40>;
-       switch_mac_mode = <0x0>;
-       switch_mac_mode1 = <0xf>;
-       switch_mac_mode2 = <0xd>;
-       bm_tick_mode = <0>;
-       tm_tick_mode = <0>;
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0>;
-               };
-
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <1>;
-               };
-
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <2>;
-               };
-
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <3>;
-               };
-
-               port@4 {
-                       port_id = <5>;
-                       phy_address = <28>;
-                       port_mac_sel = "QGMAC_PORT";
-               };
-
-               port@5 {
-                       port_id = <6>;
-                       ethernet-phy-ieee802.3-c45;
-                       phy_address = <8>;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp1 {
-       status = "okay";
-       phy-handle = <&qca8075_1>;
-       label = "lan1";
-       nvmem-cells = <&macaddr_lan 0>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_2>;
-       label = "lan2";
-       nvmem-cells = <&macaddr_lan 0>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_3>;
-       label = "lan3";
-       nvmem-cells = <&macaddr_lan 0>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_4>;
-       label = "lan4";
-       nvmem-cells = <&macaddr_lan 0>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp5 {
-       status = "okay";
-       phy-handle = <&qca8081>;
-       label = "wan";
-       nvmem-cells = <&macaddr_lan 1>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp6_syn {
-       status = "okay";
-       phy-handle = <&aqr113c>;
-       label = "10g";
-       nvmem-cells = <&macaddr_lan 0>;
-       nvmem-cell-names = "mac-address";
-};
-
-&blsp1_i2c2 {
-       pinctrl-0 = <&i2c_0_pins>;
-       pinctrl-names = "default";
-       status = "okay";
-
-       tmp103@70 {
-               compatible = "ti,tmp103";
-               reg = <0x70>;
-       };
-};
-
-&sdhc_1 {
-       status = "okay";
-       /* unstable, problem with the hs400 > h200 speed switch */
-       /delete-property/ mmc-hs400-1_8v;
-       mmc-hs200-1_8v;
-       mmc-ddr-1_8v;
-       vqmmc-supply = <&l11>;
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&ssphy_1 {
-       status = "okay";
-};
-
-&qusb_phy_1 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-};
-
-&usb_1 {
-       status = "okay";
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Zyxel-NBG7815";
-};
diff --git a/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-wxr-5950ax12.dts b/target/linux/ipq807x/files/arch/arm64/boot/dts/qcom/ipq8074-wxr-5950ax12.dts
deleted file mode 100644 (file)
index 32386dc..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-
-/dts-v1/;
-
-#include "ipq8074.dtsi"
-#include "ipq8074-hk-cpu.dtsi"
-#include "ipq8074-ess.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/leds/common.h>
-#include <dt-bindings/input/input.h>
-
-/ {
-       model = "Buffalo WXR-5950AX12";
-       compatible = "buffalo,wxr-5950ax12", "qcom,ipq8074";
-
-       aliases {
-               serial0 = &blsp1_uart5;
-               led-boot = &led_power_white;
-               led-failsafe = &led_power_red;
-               led-running = &led_power_white;
-               led-upgrade = &led_power_white;
-               label-mac-device = &dp5_syn;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-               bootargs-append = " ubi.mtd=user_property root=/dev/ubiblock1_0";
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led-0 {
-                       label = "white:router";
-                       gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_WHITE>;
-               };
-
-               led-1 {
-                       label = "red:router";
-                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-               };
-
-               led_power_red: led-2 {
-                       label = "red:power";
-                       gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-                       function = LED_FUNCTION_POWER;
-               };
-
-               led_power_white: led-3 {
-                       label = "white:power";
-                       gpios = <&tlmm 34 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_WHITE>;
-                       function = LED_FUNCTION_POWER;
-               };
-
-               led-4 {
-                       label = "white:internet";
-                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_WHITE>;
-               };
-
-               led-5 {
-                       label = "red:internet";
-                       gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-               };
-
-               led-6 {
-                       label = "red:wireless";
-                       gpios = <&tlmm 55 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_RED>;
-                       function = LED_FUNCTION_WLAN;
-               };
-
-               led-7 {
-                       label = "white:wireless";
-                       gpios = <&tlmm 56 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_WHITE>;
-                       function = LED_FUNCTION_WLAN;
-               };
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               /*
-                * mode: 3x position switch
-                *
-                * - ROUTER
-                * - AP
-                * - WB (Wireless Bridge)
-                */
-               ap {
-                       label = "mode-ap";
-                       gpios = <&tlmm 29 GPIO_ACTIVE_LOW>;
-                       linux,code = <BTN_0>;
-               };
-
-               bridge {
-                       label = "mode-wb";
-                       gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
-                       linux,code = <BTN_1>;
-               };
-
-               /*
-                * op: 2x position switch
-                *
-                * - AUTO
-                * - MANUAL (select Router/AP/WB manually)
-                */
-               manual {
-                       label = "op-manual";
-                       gpios = <&tlmm 52 GPIO_ACTIVE_LOW>;
-                       linux,code = <BTN_2>;
-               };
-
-               wps {
-                       label = "wps";
-                       gpios = <&tlmm 51 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WPS_BUTTON>;
-               };
-
-               reset {
-                       label = "reset";
-                       gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_RESTART>;
-               };
-       };
-
-       reg_usb_vbus: regulator-5v-vbus {
-               compatible = "regulator-fixed";
-               regulator-name = "vbus";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               gpio = <&tlmm 64 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-               regulator-always-on;
-       };
-};
-
-&tlmm {
-       mdio_pins: mdio-pins {
-               mdc {
-                       pins = "gpio68";
-                       function = "mdc";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-
-               mdio {
-                       pins = "gpio69";
-                       function = "mdio";
-                       drive-strength = <8>;
-                       bias-pull-up;
-               };
-       };
-};
-
-&blsp1_uart5 {
-       status = "okay";
-};
-
-&prng {
-       status = "okay";
-};
-
-&cryptobam {
-       status = "okay";
-};
-
-&crypto {
-       status = "okay";
-};
-
-&qpic_bam {
-       status = "okay";
-};
-
-&qpic_nand {
-       status = "okay";
-
-       nand@0 {
-               reg = <0>;
-               nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
-               nand-bus-width = <8>;
-
-               partitions {
-                       compatible = "qcom,smem-part";
-
-                       partition-0-appsblenv {
-                               compatible = "fixed-partitions";
-                               label = "0:appsblenv";
-                               read-only;
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-
-                               partition@0 {
-                                       compatible = "u-boot,env";
-                                       label = "env-data";
-                                       reg = <0x0 0x40000>;
-
-                                       macaddr_appsblenv_ethaddr: ethaddr {
-                                       };
-                               };
-                       };
-               };
-       };
-};
-
-&mdio {
-       status = "okay";
-       pinctrl-0 = <&mdio_pins>;
-       pinctrl-names = "default";
-       /*
-        * RESET pins of phy chips
-        *
-        * WXR-5950AX12 has 2x RESET pins for QCA8075 and AQR113C.
-        * The pin of QCA8075 is for the chip and not phys in the chip, the
-        * pin of AQR113C is for 2x chips. So both pins are not appropriate
-        * to declare them as reset-gpios in phy nodes.
-        * Multiple entries in reset-gpios of mdio may not be supported, but
-        * leave the following as-is to show that the those reset pin exists.
-        */
-       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>, /* QCA8075 RESET */
-                     <&tlmm 63 GPIO_ACTIVE_LOW>; /* AQR113C RESET (2x) */
-
-       aqr113c_1: ethernet-phy@0 {
-               compatible = "ethernet-phy-ieee802.3-c45";
-               reg = <0x0>;
-       };
-
-       aqr113c_2: ethernet-phy@8 {
-               compatible = "ethernet-phy-ieee802.3-c45";
-               reg = <0x8>;
-       };
-
-       qca8075_1: ethernet-phy@18 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0x18>;
-       };
-
-       qca8075_2: ethernet-phy@19 {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0x19>;
-       };
-
-       qca8075_3: ethernet-phy@1a {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0x1a>;
-       };
-
-       qca8075_4: ethernet-phy@1b {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0x1b>;
-       };
-
-       qca8075_5: ethernet-phy@1c {
-               compatible = "ethernet-phy-ieee802.3-c22";
-               reg = <0x1c>;
-       };
-};
-
-&switch {
-       status = "okay";
-
-       switch_cpu_bmp = <0x1>;
-       switch_lan_bmp = <0x3e>;
-       switch_wan_bmp = <0x40>;
-       switch_mac_mode = <0xb>;
-       switch_mac_mode1 = <0xd>;
-       switch_mac_mode2 = <0xd>;
-       bm_tick_mode = <0>;
-       tm_tick_mode = <0>;
-
-       qcom,port_phyinfo {
-               port@0 {
-                       port_id = <1>;
-                       phy_address = <0x18>;
-               };
-
-               port@1 {
-                       port_id = <2>;
-                       phy_address = <0x19>;
-               };
-
-               port@2 {
-                       port_id = <3>;
-                       phy_address = <0x1a>;
-               };
-
-               port@3 {
-                       port_id = <4>;
-                       phy_address = <0x1b>;
-               };
-
-               port@4 {
-                       port_id = <5>;
-                       ethernet-phy-ieee802.3-c45;
-                       phy_address = <0x0>;
-               };
-
-               port@5 {
-                       port_id = <6>;
-                       ethernet-phy-ieee802.3-c45;
-                       phy_address = <0x8>;
-               };
-       };
-};
-
-&edma {
-       status = "okay";
-};
-
-&dp2 {
-       status = "okay";
-       phy-handle = <&qca8075_2>;
-       label = "lan4";
-       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp3 {
-       status = "okay";
-       phy-handle = <&qca8075_3>;
-       label = "lan3";
-       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp4 {
-       status = "okay";
-       phy-handle = <&qca8075_4>;
-       label = "lan2";
-       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp5_syn {
-       status = "okay";
-       phy-handle = <&aqr113c_1>;
-       label = "wan";
-       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
-       nvmem-cell-names = "mac-address";
-};
-
-&dp6_syn {
-       status = "okay";
-       phy-handle = <&aqr113c_2>;
-       label = "lan1";
-       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
-       nvmem-cell-names = "mac-address";
-};
-
-&ssphy_0 {
-       status = "okay";
-};
-
-&qusb_phy_0 {
-       status = "okay";
-};
-
-&usb_0 {
-       status = "okay";
-
-       vbus-supply = <&reg_usb_vbus>;
-};
-
-&wifi {
-       status = "okay";
-
-       qcom,ath11k-calibration-variant = "Buffalo-WXR-5950AX12";
-};
diff --git a/target/linux/ipq807x/generic/target.mk b/target/linux/ipq807x/generic/target.mk
deleted file mode 100644 (file)
index f5cb1fb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-BOARDNAME:=Generic
diff --git a/target/linux/ipq807x/image/Makefile b/target/linux/ipq807x/image/Makefile
deleted file mode 100644 (file)
index f59ad0c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-include $(TOPDIR)/rules.mk
-include $(INCLUDE_DIR)/image.mk
-
-define Device/Default
-       PROFILES := Default
-       KERNEL_LOADADDR := 0x41000000
-       DEVICE_DTS = $$(SOC)-$(lastword $(subst _, ,$(1)))
-       DEVICE_DTS_CONFIG := config@1
-       DEVICE_DTS_DIR := $(DTS_DIR)/qcom
-       IMAGES := sysupgrade.bin
-       IMAGE/sysupgrade.bin = sysupgrade-tar | append-metadata
-       IMAGE/sysupgrade.bin/squashfs :=
-endef
-
-include $(SUBTARGET).mk
-
-$(eval $(call BuildImage))
diff --git a/target/linux/ipq807x/image/generic.mk b/target/linux/ipq807x/image/generic.mk
deleted file mode 100644 (file)
index 6003f2a..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-define Device/FitImage
-       KERNEL_SUFFIX := -uImage.itb
-       KERNEL = kernel-bin | libdeflate-gzip | fit gzip $$(KDIR)/image-$$(DEVICE_DTS).dtb
-       KERNEL_NAME := Image
-endef
-
-define Device/FitImageLzma
-       KERNEL_SUFFIX := -uImage.itb
-       KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
-       KERNEL_NAME := Image
-endef
-
-define Device/EmmcImage
-       IMAGES += factory.bin sysupgrade.bin
-       IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to 64k
-       IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-to 64k | sysupgrade-tar rootfs=$$$$@ | append-metadata
-endef
-
-define Device/UbiFit
-       KERNEL_IN_UBI := 1
-       IMAGES := factory.ubi sysupgrade.bin
-       IMAGE/factory.ubi := append-ubi
-       IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
-endef
-
-define Device/buffalo_wxr-5950ax12
-       $(call Device/FitImage)
-       DEVICE_VENDOR := Buffalo
-       DEVICE_MODEL := WXR-5950AX12
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@hk01
-       SOC := ipq8074
-       IMAGES := sysupgrade.bin
-       IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
-       DEVICE_PACKAGES := ipq-wifi-buffalo_wxr-5950ax12
-endef
-TARGET_DEVICES += buffalo_wxr-5950ax12
-
-define Device/compex_wpq873
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       DEVICE_VENDOR := Compex
-       DEVICE_MODEL := WPQ873
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@hk09.wpq873
-       SOC := ipq8072
-       IMAGE/factory.ubi := append-ubi | qsdk-ipq-factory-nand
-endef
-TARGET_DEVICES += compex_wpq873
-
-define Device/dynalink_dl-wrx36
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       DEVICE_VENDOR := Dynalink
-       DEVICE_MODEL := DL-WRX36
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@rt5010w-d350-rev0
-       SOC := ipq8072
-       DEVICE_PACKAGES := ipq-wifi-dynalink_dl-wrx36
-endef
-TARGET_DEVICES += dynalink_dl-wrx36
-
-define Device/edgecore_eap102
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       DEVICE_VENDOR := Edgecore
-       DEVICE_MODEL := EAP102
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@ac02
-       SOC := ipq8071
-       DEVICE_PACKAGES := ipq-wifi-edgecore_eap102
-       IMAGE/factory.ubi := append-ubi | qsdk-ipq-factory-nand
-endef
-TARGET_DEVICES += edgecore_eap102
-
-define Device/edimax_cax1800
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       DEVICE_VENDOR := Edimax
-       DEVICE_MODEL := CAX1800
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@ac03
-       SOC := ipq8070
-       DEVICE_PACKAGES := ipq-wifi-edimax_cax1800
-endef
-TARGET_DEVICES += edimax_cax1800
-
-define Device/netgear_wax218
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       ARTIFACTS := web-ui-factory.fit
-       DEVICE_VENDOR := Netgear
-       DEVICE_MODEL := WAX218
-       DEVICE_DTS_CONFIG := config@hk07
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       SOC := ipq8072
-       ARTIFACT/web-ui-factory.fit := append-image initramfs-uImage.itb | \
-               ubinize-kernel | qsdk-ipq-factory-nand
-       DEVICE_PACKAGES := kmod-spi-gpio kmod-spi-bitbang kmod-gpio-nxp-74hc164 \
-               ipq-wifi-netgear_wax218
-endef
-TARGET_DEVICES += netgear_wax218
-
-define Device/prpl_haze
-       $(call Device/FitImage)
-       $(call Device/EmmcImage)
-       DEVICE_VENDOR := prpl Foundation
-       DEVICE_MODEL := Haze
-       DEVICE_DTS_CONFIG := config@hk09
-       SOC := ipq8072
-       DEVICE_PACKAGES += ath11k-firmware-qcn9074 ipq-wifi-prpl_haze kmod-ath11k-pci
-endef
-TARGET_DEVICES += prpl_haze
-
-define Device/qnap_301w
-       $(call Device/FitImage)
-       $(call Device/EmmcImage)
-       DEVICE_VENDOR := QNAP
-       DEVICE_MODEL := 301w
-       DEVICE_DTS_CONFIG := config@hk01
-       KERNEL_SIZE := 16384k
-       SOC := ipq8072
-       DEVICE_PACKAGES += ipq-wifi-qnap_301w
-endef
-TARGET_DEVICES += qnap_301w
-
-define Device/redmi_ax6
-       $(call Device/xiaomi_ax3600)
-       DEVICE_VENDOR := Redmi
-       DEVICE_MODEL := AX6
-       DEVICE_PACKAGES := ipq-wifi-redmi_ax6
-endef
-TARGET_DEVICES += redmi_ax6
-
-define Device/xiaomi_ax3600
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       DEVICE_VENDOR := Xiaomi
-       DEVICE_MODEL := AX3600
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@ac04
-       SOC := ipq8071
-       KERNEL_SIZE := 36608k
-       DEVICE_PACKAGES := ipq-wifi-xiaomi_ax3600 kmod-ath10k-ct-smallbuffers ath10k-firmware-qca9887-ct
-ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
-       ARTIFACTS := initramfs-factory.ubi
-       ARTIFACT/initramfs-factory.ubi := append-image-stage initramfs-uImage.itb | ubinize-kernel
-endif
-endef
-TARGET_DEVICES += xiaomi_ax3600
-
-define Device/xiaomi_ax9000
-       $(call Device/FitImage)
-       $(call Device/UbiFit)
-       DEVICE_VENDOR := Xiaomi
-       DEVICE_MODEL := AX9000
-       BLOCKSIZE := 128k
-       PAGESIZE := 2048
-       DEVICE_DTS_CONFIG := config@hk14
-       SOC := ipq8072
-       KERNEL_SIZE := 57344k
-       DEVICE_PACKAGES := ipq-wifi-xiaomi_ax9000 kmod-ath11k-pci ath11k-firmware-qcn9074 \
-       kmod-ath10k-ct ath10k-firmware-qca9887-ct
-ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
-       ARTIFACTS := initramfs-factory.ubi
-       ARTIFACT/initramfs-factory.ubi := append-image-stage initramfs-uImage.itb | ubinize-kernel
-endif
-endef
-TARGET_DEVICES += xiaomi_ax9000
-
-define Device/zyxel_nbg7815
-       $(call Device/FitImage)
-       $(call Device/EmmcImage)
-       DEVICE_VENDOR := ZYXEL
-       DEVICE_MODEL := NBG7815
-       DEVICE_DTS_CONFIG := config@nbg7815
-       SOC := ipq8074
-       DEVICE_PACKAGES += ipq-wifi-zyxel_nbg7815 kmod-ath11k-pci kmod-hwmon-tmp103 \
-               kmod-bluetooth
-endef
-TARGET_DEVICES += zyxel_nbg7815
diff --git a/target/linux/ipq807x/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch b/target/linux/ipq807x/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch
deleted file mode 100644 (file)
index dd57eae..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From 6463c10bfdbd684ec7ecfd408ea541283215a088 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:06:28 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add A53 PLL node
-
-Add the required node for A53 PLL which will be used to provide the CPU
-clock via APCS for APSS scaling.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20220818220628.339366-9-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -675,6 +675,14 @@
-                       #mbox-cells = <1>;
-               };
-+              a53pll: clock@b116000 {
-+                      compatible = "qcom,ipq8074-a53pll";
-+                      reg = <0x0b116000 0x40>;
-+                      #clock-cells = <0>;
-+                      clocks = <&xo>;
-+                      clock-names = "xo";
-+              };
-+
-               timer@b120000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
diff --git a/target/linux/ipq807x/patches-6.1/0002-v6.2-thermal-drivers-tsens-Add-support-for-combined-inter.patch b/target/linux/ipq807x/patches-6.1/0002-v6.2-thermal-drivers-tsens-Add-support-for-combined-inter.patch
deleted file mode 100644 (file)
index 0320725..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-From e593e834fe8ba9bf314d8215ac05d8787f81efda Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:02:42 +0200
-Subject: [PATCH] thermal/drivers/tsens: Add support for combined interrupt
-
-Despite using tsens v2.3 IP, IPQ8074 and IPQ6018 only have one IRQ for
-signaling both up/low and critical trips.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Reviewed-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20220818220245.338396-2-robimarko@gmail.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens-8960.c |  1 +
- drivers/thermal/qcom/tsens-v0_1.c |  1 +
- drivers/thermal/qcom/tsens-v1.c   |  1 +
- drivers/thermal/qcom/tsens-v2.c   |  1 +
- drivers/thermal/qcom/tsens.c      | 38 ++++++++++++++++++++++++++-----
- drivers/thermal/qcom/tsens.h      |  2 ++
- 6 files changed, 38 insertions(+), 6 deletions(-)
-
---- a/drivers/thermal/qcom/tsens-8960.c
-+++ b/drivers/thermal/qcom/tsens-8960.c
-@@ -269,6 +269,7 @@ static const struct tsens_ops ops_8960 =
- static struct tsens_features tsens_8960_feat = {
-       .ver_major      = VER_0,
-       .crit_int       = 0,
-+      .combo_int      = 0,
-       .adc            = 1,
-       .srot_split     = 0,
-       .max_sensors    = 11,
---- a/drivers/thermal/qcom/tsens-v0_1.c
-+++ b/drivers/thermal/qcom/tsens-v0_1.c
-@@ -549,6 +549,7 @@ static int __init init_8939(struct tsens
- static struct tsens_features tsens_v0_1_feat = {
-       .ver_major      = VER_0_1,
-       .crit_int       = 0,
-+      .combo_int      = 0,
-       .adc            = 1,
-       .srot_split     = 1,
-       .max_sensors    = 11,
---- a/drivers/thermal/qcom/tsens-v1.c
-+++ b/drivers/thermal/qcom/tsens-v1.c
-@@ -273,6 +273,7 @@ static int calibrate_8976(struct tsens_p
- static struct tsens_features tsens_v1_feat = {
-       .ver_major      = VER_1_X,
-       .crit_int       = 0,
-+      .combo_int      = 0,
-       .adc            = 1,
-       .srot_split     = 1,
-       .max_sensors    = 11,
---- a/drivers/thermal/qcom/tsens-v2.c
-+++ b/drivers/thermal/qcom/tsens-v2.c
-@@ -31,6 +31,7 @@
- static struct tsens_features tsens_v2_feat = {
-       .ver_major      = VER_2_X,
-       .crit_int       = 1,
-+      .combo_int      = 0,
-       .adc            = 0,
-       .srot_split     = 1,
-       .max_sensors    = 16,
---- a/drivers/thermal/qcom/tsens.c
-+++ b/drivers/thermal/qcom/tsens.c
-@@ -532,6 +532,27 @@ static irqreturn_t tsens_irq_thread(int
-       return IRQ_HANDLED;
- }
-+/**
-+ * tsens_combined_irq_thread() - Threaded interrupt handler for combined interrupts
-+ * @irq: irq number
-+ * @data: tsens controller private data
-+ *
-+ * Handle the combined interrupt as if it were 2 separate interrupts, so call the
-+ * critical handler first and then the up/low one.
-+ *
-+ * Return: IRQ_HANDLED
-+ */
-+static irqreturn_t tsens_combined_irq_thread(int irq, void *data)
-+{
-+      irqreturn_t ret;
-+
-+      ret = tsens_critical_irq_thread(irq, data);
-+      if (ret != IRQ_HANDLED)
-+              return ret;
-+
-+      return tsens_irq_thread(irq, data);
-+}
-+
- static int tsens_set_trips(struct thermal_zone_device *tz, int low, int high)
- {
-       struct tsens_sensor *s = tz->devdata;
-@@ -1074,13 +1095,18 @@ static int tsens_register(struct tsens_p
-                                  tsens_mC_to_hw(priv->sensor, 0));
-       }
--      ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
--      if (ret < 0)
--              return ret;
-+      if (priv->feat->combo_int) {
-+              ret = tsens_register_irq(priv, "combined",
-+                                       tsens_combined_irq_thread);
-+      } else {
-+              ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
-+              if (ret < 0)
-+                      return ret;
--      if (priv->feat->crit_int)
--              ret = tsens_register_irq(priv, "critical",
--                                       tsens_critical_irq_thread);
-+              if (priv->feat->crit_int)
-+                      ret = tsens_register_irq(priv, "critical",
-+                                               tsens_critical_irq_thread);
-+      }
-       return ret;
- }
---- a/drivers/thermal/qcom/tsens.h
-+++ b/drivers/thermal/qcom/tsens.h
-@@ -493,6 +493,7 @@ enum regfield_ids {
-  * struct tsens_features - Features supported by the IP
-  * @ver_major: Major number of IP version
-  * @crit_int: does the IP support critical interrupts?
-+ * @combo_int: does the IP use one IRQ for up, low and critical thresholds?
-  * @adc:      do the sensors only output adc code (instead of temperature)?
-  * @srot_split: does the IP neatly splits the register space into SROT and TM,
-  *              with SROT only being available to secure boot firmware?
-@@ -502,6 +503,7 @@ enum regfield_ids {
- struct tsens_features {
-       unsigned int ver_major;
-       unsigned int crit_int:1;
-+      unsigned int combo_int:1;
-       unsigned int adc:1;
-       unsigned int srot_split:1;
-       unsigned int has_watchdog:1;
diff --git a/target/linux/ipq807x/patches-6.1/0003-v6.2-thermal-drivers-tsens-Allow-configuring-min-and-max-.patch b/target/linux/ipq807x/patches-6.1/0003-v6.2-thermal-drivers-tsens-Allow-configuring-min-and-max-.patch
deleted file mode 100644 (file)
index 3630618..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-From 7805365fee582056b32c69cf35aafbb94b14a8ca Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:02:43 +0200
-Subject: [PATCH] thermal/drivers/tsens: Allow configuring min and max trips
-
-IPQ8074 and IPQ6018 dont support negative trip temperatures and support
-up to 204 degrees C as the max trip temperature.
-
-So, instead of always setting the -40 as min and 120 degrees C as max
-allow it to be configured as part of the features.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-Link: https://lore.kernel.org/r/20220818220245.338396-3-robimarko@gmail.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens-8960.c | 2 ++
- drivers/thermal/qcom/tsens-v0_1.c | 2 ++
- drivers/thermal/qcom/tsens-v1.c   | 2 ++
- drivers/thermal/qcom/tsens-v2.c   | 2 ++
- drivers/thermal/qcom/tsens.c      | 4 ++--
- drivers/thermal/qcom/tsens.h      | 4 ++++
- 6 files changed, 14 insertions(+), 2 deletions(-)
-
---- a/drivers/thermal/qcom/tsens-8960.c
-+++ b/drivers/thermal/qcom/tsens-8960.c
-@@ -273,6 +273,8 @@ static struct tsens_features tsens_8960_
-       .adc            = 1,
-       .srot_split     = 0,
-       .max_sensors    = 11,
-+      .trip_min_temp  = -40000,
-+      .trip_max_temp  = 120000,
- };
- struct tsens_plat_data data_8960 = {
---- a/drivers/thermal/qcom/tsens-v0_1.c
-+++ b/drivers/thermal/qcom/tsens-v0_1.c
-@@ -553,6 +553,8 @@ static struct tsens_features tsens_v0_1_
-       .adc            = 1,
-       .srot_split     = 1,
-       .max_sensors    = 11,
-+      .trip_min_temp  = -40000,
-+      .trip_max_temp  = 120000,
- };
- static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
---- a/drivers/thermal/qcom/tsens-v1.c
-+++ b/drivers/thermal/qcom/tsens-v1.c
-@@ -277,6 +277,8 @@ static struct tsens_features tsens_v1_fe
-       .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] = {
---- a/drivers/thermal/qcom/tsens-v2.c
-+++ b/drivers/thermal/qcom/tsens-v2.c
-@@ -35,6 +35,8 @@ static struct tsens_features tsens_v2_fe
-       .adc            = 0,
-       .srot_split     = 1,
-       .max_sensors    = 16,
-+      .trip_min_temp  = -40000,
-+      .trip_max_temp  = 120000,
- };
- static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
---- a/drivers/thermal/qcom/tsens.c
-+++ b/drivers/thermal/qcom/tsens.c
-@@ -573,8 +573,8 @@ static int tsens_set_trips(struct therma
-       dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
-               hw_id, __func__, low, high);
--      cl_high = clamp_val(high, -40000, 120000);
--      cl_low  = clamp_val(low, -40000, 120000);
-+      cl_high = clamp_val(high, priv->feat->trip_min_temp, priv->feat->trip_max_temp);
-+      cl_low  = clamp_val(low, priv->feat->trip_min_temp, priv->feat->trip_max_temp);
-       high_val = tsens_mC_to_hw(s, cl_high);
-       low_val  = tsens_mC_to_hw(s, cl_low);
---- a/drivers/thermal/qcom/tsens.h
-+++ b/drivers/thermal/qcom/tsens.h
-@@ -499,6 +499,8 @@ enum regfield_ids {
-  *              with SROT only being available to secure boot firmware?
-  * @has_watchdog: does this IP support watchdog functionality?
-  * @max_sensors: maximum sensors supported by this version of the IP
-+ * @trip_min_temp: minimum trip temperature supported by this version of the IP
-+ * @trip_max_temp: maximum trip temperature supported by this version of the IP
-  */
- struct tsens_features {
-       unsigned int ver_major;
-@@ -508,6 +510,8 @@ struct tsens_features {
-       unsigned int srot_split:1;
-       unsigned int has_watchdog:1;
-       unsigned int max_sensors;
-+      int trip_min_temp;
-+      int trip_max_temp;
- };
- /**
diff --git a/target/linux/ipq807x/patches-6.1/0004-v6.2-thermal-drivers-tsens-Add-IPQ8074-support.patch b/target/linux/ipq807x/patches-6.1/0004-v6.2-thermal-drivers-tsens-Add-IPQ8074-support.patch
deleted file mode 100644 (file)
index eaea693..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-From 0164d794cbc58488a7321272e95958d10cf103a4 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:02:44 +0200
-Subject: [PATCH] thermal/drivers/tsens: Add IPQ8074 support
-
-Qualcomm IPQ8074 uses tsens v2.3 IP, however unlike other tsens v2 IP
-it only has one IRQ, that is used for up/low as well as critical.
-It also does not support negative trip temperatures.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-Link: https://lore.kernel.org/r/20220818220245.338396-4-robimarko@gmail.com
-Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
----
- drivers/thermal/qcom/tsens-v2.c | 17 +++++++++++++++++
- drivers/thermal/qcom/tsens.c    |  3 +++
- drivers/thermal/qcom/tsens.h    |  2 +-
- 3 files changed, 21 insertions(+), 1 deletion(-)
-
---- a/drivers/thermal/qcom/tsens-v2.c
-+++ b/drivers/thermal/qcom/tsens-v2.c
-@@ -39,6 +39,17 @@ static struct tsens_features tsens_v2_fe
-       .trip_max_temp  = 120000,
- };
-+static struct tsens_features ipq8074_feat = {
-+      .ver_major      = VER_2_X,
-+      .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 */
-@@ -104,6 +115,12 @@ struct tsens_plat_data data_tsens_v2 = {
-       .fields = tsens_v2_regfields,
- };
-+struct tsens_plat_data data_ipq8074 = {
-+      .ops            = &ops_generic_v2,
-+      .feat           = &ipq8074_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
-@@ -981,6 +981,9 @@ static const struct of_device_id tsens_t
-               .compatible = "qcom,ipq8064-tsens",
-               .data = &data_8960,
-       }, {
-+              .compatible = "qcom,ipq8074-tsens",
-+              .data = &data_ipq8074,
-+      }, {
-               .compatible = "qcom,mdm9607-tsens",
-               .data = &data_9607,
-       }, {
---- a/drivers/thermal/qcom/tsens.h
-+++ b/drivers/thermal/qcom/tsens.h
-@@ -597,6 +597,6 @@ extern struct tsens_plat_data data_8916,
- extern struct tsens_plat_data data_tsens_v1, data_8976, data_8956;
- /* TSENS v2 targets */
--extern struct tsens_plat_data data_8996, data_tsens_v2;
-+extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
- #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/ipq807x/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch b/target/linux/ipq807x/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch
deleted file mode 100644 (file)
index bad75e4..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-From c3cc0c2a17f552be2426200e47a9e2c62cf449ce Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:02:45 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add thermal nodes
-
-IPQ8074 has a tsens v2.3.0 peripheral which monitors
-temperatures around the various subsystems on the
-die.
-
-So lets add the tsens and thermal zone nodes, passive
-CPU cooling will come in later patches after CPU frequency
-scaling is supported.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20220818220245.338396-5-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 96 +++++++++++++++++++++++++++
- 1 file changed, 96 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -274,6 +274,16 @@
-                       status = "disabled";
-               };
-+              tsens: thermal-sensor@4a9000 {
-+                      compatible = "qcom,ipq8074-tsens";
-+                      reg = <0x4a9000 0x1000>, /* TM */
-+                            <0x4a8000 0x1000>; /* SROT */
-+                      interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-+                      interrupt-names = "combined";
-+                      #qcom,sensors = <16>;
-+                      #thermal-sensor-cells = <1>;
-+              };
-+
-               cryptobam: dma-controller@704000 {
-                       compatible = "qcom,bam-v1.7.0";
-                       reg = <0x00704000 0x20000>;
-@@ -874,4 +884,90 @@
-                            <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                            <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
-       };
-+
-+      thermal-zones {
-+              nss-top-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 4>;
-+              };
-+
-+              nss0-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 5>;
-+              };
-+
-+              nss1-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 6>;
-+              };
-+
-+              wcss-phya0-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 7>;
-+              };
-+
-+              wcss-phya1-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 8>;
-+              };
-+
-+              cpu0_thermal: cpu0-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 9>;
-+              };
-+
-+              cpu1_thermal: cpu1-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 10>;
-+              };
-+
-+              cpu2_thermal: cpu2-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 11>;
-+              };
-+
-+              cpu3_thermal: cpu3-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 12>;
-+              };
-+
-+              cluster_thermal: cluster-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 13>;
-+              };
-+
-+              wcss-phyb0-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 14>;
-+              };
-+
-+              wcss-phyb1-thermal {
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+
-+                      thermal-sensors = <&tsens 15>;
-+              };
-+      };
- };
diff --git a/target/linux/ipq807x/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch b/target/linux/ipq807x/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch
deleted file mode 100644 (file)
index e229851..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0df592a0a1a3fff9133977192677aa915afc174f Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:08:49 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add clocks to APCS
-
-APCS now has support for providing the APSS clocks as the child device
-for IPQ8074.
-
-So, add the A53 PLL and XO clocks in order to use APCS as the CPU
-clocksource for APSS scaling.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20220818220849.339732-4-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -680,6 +680,8 @@
-               apcs_glb: mailbox@b111000 {
-                       compatible = "qcom,ipq8074-apcs-apps-global";
-                       reg = <0x0b111000 0x1000>;
-+                      clocks = <&a53pll>, <&xo>;
-+                      clock-names = "pll", "xo";
-                       #clock-cells = <1>;
-                       #mbox-cells = <1>;
diff --git a/target/linux/ipq807x/patches-6.1/0007-v6.2-clk-qcom-ipq8074-convert-to-parent-data.patch b/target/linux/ipq807x/patches-6.1/0007-v6.2-clk-qcom-ipq8074-convert-to-parent-data.patch
deleted file mode 100644 (file)
index 9162ea5..0000000
+++ /dev/null
@@ -1,3601 +0,0 @@
-From e6c5115d6845f25eda7e162dcd783a2044215867 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Sun, 30 Oct 2022 18:57:01 +0100
-Subject: [PATCH] clk: qcom: ipq8074: convert to parent data
-
-Convert the IPQ8074 GCC driver to use parent data instead of global
-name matching.
-
-Utilize ARRAY_SIZE for num_parents instead of hardcoding the value.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221030175703.1103224-1-robimarko@gmail.com
----
- drivers/clk/qcom/gcc-ipq8074.c | 1781 +++++++++++++++-----------------
- 1 file changed, 813 insertions(+), 968 deletions(-)
-
---- a/drivers/clk/qcom/gcc-ipq8074.c
-+++ b/drivers/clk/qcom/gcc-ipq8074.c
-@@ -49,349 +49,6 @@ enum {
-       P_UNIPHY2_TX,
- };
--static const char * const gcc_xo_gpll0_gpll0_out_main_div2[] = {
--      "xo",
--      "gpll0",
--      "gpll0_out_main_div2",
--};
--
--static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--      { P_GPLL0_DIV2, 4 },
--};
--
--static const struct parent_map gcc_xo_gpll0_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--};
--
--static const char * const gcc_xo_gpll0_gpll2_gpll0_out_main_div2[] = {
--      "xo",
--      "gpll0",
--      "gpll2",
--      "gpll0_out_main_div2",
--};
--
--static const struct parent_map gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--      { P_GPLL2, 2 },
--      { P_GPLL0_DIV2, 4 },
--};
--
--static const char * const gcc_xo_gpll0_sleep_clk[] = {
--      "xo",
--      "gpll0",
--      "sleep_clk",
--};
--
--static const struct parent_map gcc_xo_gpll0_sleep_clk_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 2 },
--      { P_SLEEP_CLK, 6 },
--};
--
--static const char * const gcc_xo_gpll6_gpll0_gpll0_out_main_div2[] = {
--      "xo",
--      "gpll6",
--      "gpll0",
--      "gpll0_out_main_div2",
--};
--
--static const struct parent_map gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map[] = {
--      { P_XO, 0 },
--      { P_GPLL6, 1 },
--      { P_GPLL0, 3 },
--      { P_GPLL0_DIV2, 4 },
--};
--
--static const char * const gcc_xo_gpll0_out_main_div2_gpll0[] = {
--      "xo",
--      "gpll0_out_main_div2",
--      "gpll0",
--};
--
--static const struct parent_map gcc_xo_gpll0_out_main_div2_gpll0_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0_DIV2, 2 },
--      { P_GPLL0, 1 },
--};
--
--static const char * const gcc_usb3phy_0_cc_pipe_clk_xo[] = {
--      "usb3phy_0_cc_pipe_clk",
--      "xo",
--};
--
--static const struct parent_map gcc_usb3phy_0_cc_pipe_clk_xo_map[] = {
--      { P_USB3PHY_0_PIPE, 0 },
--      { P_XO, 2 },
--};
--
--static const char * const gcc_usb3phy_1_cc_pipe_clk_xo[] = {
--      "usb3phy_1_cc_pipe_clk",
--      "xo",
--};
--
--static const struct parent_map gcc_usb3phy_1_cc_pipe_clk_xo_map[] = {
--      { P_USB3PHY_1_PIPE, 0 },
--      { P_XO, 2 },
--};
--
--static const char * const gcc_pcie20_phy0_pipe_clk_xo[] = {
--      "pcie20_phy0_pipe_clk",
--      "xo",
--};
--
--static const struct parent_map gcc_pcie20_phy0_pipe_clk_xo_map[] = {
--      { P_PCIE20_PHY0_PIPE, 0 },
--      { P_XO, 2 },
--};
--
--static const char * const gcc_pcie20_phy1_pipe_clk_xo[] = {
--      "pcie20_phy1_pipe_clk",
--      "xo",
--};
--
--static const struct parent_map gcc_pcie20_phy1_pipe_clk_xo_map[] = {
--      { P_PCIE20_PHY1_PIPE, 0 },
--      { P_XO, 2 },
--};
--
--static const char * const gcc_xo_gpll0_gpll6_gpll0_div2[] = {
--      "xo",
--      "gpll0",
--      "gpll6",
--      "gpll0_out_main_div2",
--};
--
--static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_div2_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--      { P_GPLL6, 2 },
--      { P_GPLL0_DIV2, 4 },
--};
--
--static const char * const gcc_xo_gpll0_gpll6_gpll0_out_main_div2[] = {
--      "xo",
--      "gpll0",
--      "gpll6",
--      "gpll0_out_main_div2",
--};
--
--static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--      { P_GPLL6, 2 },
--      { P_GPLL0_DIV2, 3 },
--};
--
--static const char * const gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = {
--      "xo",
--      "bias_pll_nss_noc_clk",
--      "gpll0",
--      "gpll2",
--};
--
--static const struct parent_map gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map[] = {
--      { P_XO, 0 },
--      { P_BIAS_PLL_NSS_NOC, 1 },
--      { P_GPLL0, 2 },
--      { P_GPLL2, 3 },
--};
--
--static const char * const gcc_xo_nss_crypto_pll_gpll0[] = {
--      "xo",
--      "nss_crypto_pll",
--      "gpll0",
--};
--
--static const struct parent_map gcc_xo_nss_crypto_pll_gpll0_map[] = {
--      { P_XO, 0 },
--      { P_NSS_CRYPTO_PLL, 1 },
--      { P_GPLL0, 2 },
--};
--
--static const char * const gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6[] = {
--      "xo",
--      "ubi32_pll",
--      "gpll0",
--      "gpll2",
--      "gpll4",
--      "gpll6",
--};
--
--static const struct parent_map gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map[] = {
--      { P_XO, 0 },
--      { P_UBI32_PLL, 1 },
--      { P_GPLL0, 2 },
--      { P_GPLL2, 3 },
--      { P_GPLL4, 4 },
--      { P_GPLL6, 5 },
--};
--
--static const char * const gcc_xo_gpll0_out_main_div2[] = {
--      "xo",
--      "gpll0_out_main_div2",
--};
--
--static const struct parent_map gcc_xo_gpll0_out_main_div2_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0_DIV2, 1 },
--};
--
--static const char * const gcc_xo_bias_gpll0_gpll4_nss_ubi32[] = {
--      "xo",
--      "bias_pll_cc_clk",
--      "gpll0",
--      "gpll4",
--      "nss_crypto_pll",
--      "ubi32_pll",
--};
--
--static const struct parent_map gcc_xo_bias_gpll0_gpll4_nss_ubi32_map[] = {
--      { P_XO, 0 },
--      { P_BIAS_PLL, 1 },
--      { P_GPLL0, 2 },
--      { P_GPLL4, 3 },
--      { P_NSS_CRYPTO_PLL, 4 },
--      { P_UBI32_PLL, 5 },
--};
--
--static const char * const gcc_xo_gpll0_gpll4[] = {
--      "xo",
--      "gpll0",
--      "gpll4",
--};
--
--static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--      { P_GPLL4, 2 },
--};
--
--static const char * const gcc_xo_uniphy0_rx_tx_ubi32_bias[] = {
--      "xo",
--      "uniphy0_gcc_rx_clk",
--      "uniphy0_gcc_tx_clk",
--      "ubi32_pll",
--      "bias_pll_cc_clk",
--};
--
--static const struct parent_map gcc_xo_uniphy0_rx_tx_ubi32_bias_map[] = {
--      { P_XO, 0 },
--      { P_UNIPHY0_RX, 1 },
--      { P_UNIPHY0_TX, 2 },
--      { P_UBI32_PLL, 5 },
--      { P_BIAS_PLL, 6 },
--};
--
--static const char * const gcc_xo_uniphy0_tx_rx_ubi32_bias[] = {
--      "xo",
--      "uniphy0_gcc_tx_clk",
--      "uniphy0_gcc_rx_clk",
--      "ubi32_pll",
--      "bias_pll_cc_clk",
--};
--
--static const struct parent_map gcc_xo_uniphy0_tx_rx_ubi32_bias_map[] = {
--      { P_XO, 0 },
--      { P_UNIPHY0_TX, 1 },
--      { P_UNIPHY0_RX, 2 },
--      { P_UBI32_PLL, 5 },
--      { P_BIAS_PLL, 6 },
--};
--
--static const char * const gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
--      "xo",
--      "uniphy0_gcc_rx_clk",
--      "uniphy0_gcc_tx_clk",
--      "uniphy1_gcc_rx_clk",
--      "uniphy1_gcc_tx_clk",
--      "ubi32_pll",
--      "bias_pll_cc_clk",
--};
--
--static const struct parent_map
--gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = {
--      { P_XO, 0 },
--      { P_UNIPHY0_RX, 1 },
--      { P_UNIPHY0_TX, 2 },
--      { P_UNIPHY1_RX, 3 },
--      { P_UNIPHY1_TX, 4 },
--      { P_UBI32_PLL, 5 },
--      { P_BIAS_PLL, 6 },
--};
--
--static const char * const gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
--      "xo",
--      "uniphy0_gcc_tx_clk",
--      "uniphy0_gcc_rx_clk",
--      "uniphy1_gcc_tx_clk",
--      "uniphy1_gcc_rx_clk",
--      "ubi32_pll",
--      "bias_pll_cc_clk",
--};
--
--static const struct parent_map
--gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = {
--      { P_XO, 0 },
--      { P_UNIPHY0_TX, 1 },
--      { P_UNIPHY0_RX, 2 },
--      { P_UNIPHY1_TX, 3 },
--      { P_UNIPHY1_RX, 4 },
--      { P_UBI32_PLL, 5 },
--      { P_BIAS_PLL, 6 },
--};
--
--static const char * const gcc_xo_uniphy2_rx_tx_ubi32_bias[] = {
--      "xo",
--      "uniphy2_gcc_rx_clk",
--      "uniphy2_gcc_tx_clk",
--      "ubi32_pll",
--      "bias_pll_cc_clk",
--};
--
--static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
--      { P_XO, 0 },
--      { P_UNIPHY2_RX, 1 },
--      { P_UNIPHY2_TX, 2 },
--      { P_UBI32_PLL, 5 },
--      { P_BIAS_PLL, 6 },
--};
--
--static const char * const gcc_xo_uniphy2_tx_rx_ubi32_bias[] = {
--      "xo",
--      "uniphy2_gcc_tx_clk",
--      "uniphy2_gcc_rx_clk",
--      "ubi32_pll",
--      "bias_pll_cc_clk",
--};
--
--static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
--      { P_XO, 0 },
--      { P_UNIPHY2_TX, 1 },
--      { P_UNIPHY2_RX, 2 },
--      { P_UBI32_PLL, 5 },
--      { P_BIAS_PLL, 6 },
--};
--
--static const char * const gcc_xo_gpll0_gpll6_gpll0_sleep_clk[] = {
--      "xo",
--      "gpll0",
--      "gpll6",
--      "gpll0_out_main_div2",
--      "sleep_clk",
--};
--
--static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map[] = {
--      { P_XO, 0 },
--      { P_GPLL0, 1 },
--      { P_GPLL6, 2 },
--      { P_GPLL0_DIV2, 4 },
--      { P_SLEEP_CLK, 6 },
--};
--
- static struct clk_alpha_pll gpll0_main = {
-       .offset = 0x21000,
-       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
-@@ -400,8 +57,9 @@ static struct clk_alpha_pll gpll0_main =
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gpll0_main",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_alpha_pll_ops,
-@@ -414,9 +72,8 @@ static struct clk_fixed_factor gpll0_out
-       .div = 2,
-       .hw.init = &(struct clk_init_data){
-               .name = "gpll0_out_main_div2",
--              .parent_names = (const char *[]){
--                      "gpll0_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gpll0_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -429,9 +86,8 @@ static struct clk_alpha_pll_postdiv gpll
-       .width = 4,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gpll0",
--              .parent_names = (const char *[]){
--                      "gpll0_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gpll0_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_alpha_pll_postdiv_ro_ops,
-       },
-@@ -445,8 +101,9 @@ static struct clk_alpha_pll gpll2_main =
-               .enable_mask = BIT(2),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gpll2_main",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_alpha_pll_ops,
-@@ -461,9 +118,8 @@ static struct clk_alpha_pll_postdiv gpll
-       .width = 4,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gpll2",
--              .parent_names = (const char *[]){
--                      "gpll2_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gpll2_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_alpha_pll_postdiv_ro_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -478,8 +134,9 @@ static struct clk_alpha_pll gpll4_main =
-               .enable_mask = BIT(5),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gpll4_main",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_alpha_pll_ops,
-@@ -494,9 +151,8 @@ static struct clk_alpha_pll_postdiv gpll
-       .width = 4,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gpll4",
--              .parent_names = (const char *[]){
--                      "gpll4_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gpll4_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_alpha_pll_postdiv_ro_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -512,8 +168,9 @@ static struct clk_alpha_pll gpll6_main =
-               .enable_mask = BIT(7),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gpll6_main",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_alpha_pll_ops,
-@@ -528,9 +185,8 @@ static struct clk_alpha_pll_postdiv gpll
-       .width = 2,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gpll6",
--              .parent_names = (const char *[]){
--                      "gpll6_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gpll6_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_alpha_pll_postdiv_ro_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -542,9 +198,8 @@ static struct clk_fixed_factor gpll6_out
-       .div = 2,
-       .hw.init = &(struct clk_init_data){
-               .name = "gpll6_out_main_div2",
--              .parent_names = (const char *[]){
--                      "gpll6_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gpll6_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -560,8 +215,9 @@ static struct clk_alpha_pll ubi32_pll_ma
-               .enable_mask = BIT(6),
-               .hw.init = &(struct clk_init_data){
-                       .name = "ubi32_pll_main",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_alpha_pll_huayra_ops,
-@@ -575,9 +231,8 @@ static struct clk_alpha_pll_postdiv ubi3
-       .width = 2,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "ubi32_pll",
--              .parent_names = (const char *[]){
--                      "ubi32_pll_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &ubi32_pll_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_alpha_pll_postdiv_ro_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -592,8 +247,9 @@ static struct clk_alpha_pll nss_crypto_p
-               .enable_mask = BIT(4),
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_crypto_pll_main",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_alpha_pll_ops,
-@@ -607,9 +263,8 @@ static struct clk_alpha_pll_postdiv nss_
-       .width = 4,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_crypto_pll",
--              .parent_names = (const char *[]){
--                      "nss_crypto_pll_main"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &nss_crypto_pll_main.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_alpha_pll_postdiv_ro_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -623,6 +278,18 @@ static const struct freq_tbl ftbl_pcnoc_
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_gpll0_out_main_div2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw},
-+      { .hw = &gpll0_out_main_div2.hw},
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+      { P_GPLL0_DIV2, 4 },
-+};
-+
- static struct clk_rcg2 pcnoc_bfdcd_clk_src = {
-       .cmd_rcgr = 0x27000,
-       .freq_tbl = ftbl_pcnoc_bfdcd_clk_src,
-@@ -630,8 +297,8 @@ static struct clk_rcg2 pcnoc_bfdcd_clk_s
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "pcnoc_bfdcd_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-               .flags = CLK_IS_CRITICAL,
-       },
-@@ -642,9 +309,8 @@ static struct clk_fixed_factor pcnoc_clk
-       .div = 1,
-       .hw.init = &(struct clk_init_data){
-               .name = "pcnoc_clk_src",
--              .parent_names = (const char *[]){
--                      "pcnoc_bfdcd_clk_src"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_bfdcd_clk_src.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -658,8 +324,9 @@ static struct clk_branch gcc_sleep_clk_s
-               .enable_mask = BIT(1),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sleep_clk_src",
--                      .parent_names = (const char *[]){
--                              "sleep_clk"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "sleep_clk",
-+                              .name = "sleep_clk",
-                       },
-                       .num_parents = 1,
-                       .ops = &clk_branch2_ops,
-@@ -682,8 +349,8 @@ static struct clk_rcg2 blsp1_qup1_i2c_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup1_i2c_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -708,8 +375,8 @@ static struct clk_rcg2 blsp1_qup1_spi_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup1_spi_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -721,8 +388,8 @@ static struct clk_rcg2 blsp1_qup2_i2c_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup2_i2c_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -735,8 +402,8 @@ static struct clk_rcg2 blsp1_qup2_spi_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup2_spi_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -748,8 +415,8 @@ static struct clk_rcg2 blsp1_qup3_i2c_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup3_i2c_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -762,8 +429,8 @@ static struct clk_rcg2 blsp1_qup3_spi_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup3_spi_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -775,8 +442,8 @@ static struct clk_rcg2 blsp1_qup4_i2c_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup4_i2c_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -789,8 +456,8 @@ static struct clk_rcg2 blsp1_qup4_spi_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup4_spi_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -802,8 +469,8 @@ static struct clk_rcg2 blsp1_qup5_i2c_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup5_i2c_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -816,8 +483,8 @@ static struct clk_rcg2 blsp1_qup5_spi_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup5_spi_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -829,8 +496,8 @@ static struct clk_rcg2 blsp1_qup6_i2c_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup6_i2c_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -843,8 +510,8 @@ static struct clk_rcg2 blsp1_qup6_spi_ap
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_qup6_spi_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -877,8 +544,8 @@ static struct clk_rcg2 blsp1_uart1_apps_
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_uart1_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -891,8 +558,8 @@ static struct clk_rcg2 blsp1_uart2_apps_
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_uart2_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -905,8 +572,8 @@ static struct clk_rcg2 blsp1_uart3_apps_
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_uart3_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -919,8 +586,8 @@ static struct clk_rcg2 blsp1_uart4_apps_
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_uart4_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -933,8 +600,8 @@ static struct clk_rcg2 blsp1_uart5_apps_
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_uart5_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -947,8 +614,8 @@ static struct clk_rcg2 blsp1_uart6_apps_
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "blsp1_uart6_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -958,6 +625,11 @@ static const struct clk_parent_data gcc_
-       { .hw = &gpll0.clkr.hw },
- };
-+static const struct parent_map gcc_xo_gpll0_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+};
-+
- static const struct freq_tbl ftbl_pcie_axi_clk_src[] = {
-       F(19200000, P_XO, 1, 0, 0),
-       F(200000000, P_GPLL0, 4, 0, 0),
-@@ -972,7 +644,7 @@ static struct clk_rcg2 pcie0_axi_clk_src
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "pcie0_axi_clk_src",
-               .parent_data = gcc_xo_gpll0,
--              .num_parents = 2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -981,6 +653,18 @@ static const struct freq_tbl ftbl_pcie_a
-       F(19200000, P_XO, 1, 0, 0),
- };
-+static const struct clk_parent_data gcc_xo_gpll0_sleep_clk[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .fw_name = "sleep_clk", .name = "sleep_clk" },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_sleep_clk_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 2 },
-+      { P_SLEEP_CLK, 6 },
-+};
-+
- static struct clk_rcg2 pcie0_aux_clk_src = {
-       .cmd_rcgr = 0x75024,
-       .freq_tbl = ftbl_pcie_aux_clk_src,
-@@ -989,12 +673,22 @@ static struct clk_rcg2 pcie0_aux_clk_src
-       .parent_map = gcc_xo_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "pcie0_aux_clk_src",
--              .parent_names = gcc_xo_gpll0_sleep_clk,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-+static const struct clk_parent_data gcc_pcie20_phy0_pipe_clk_xo[] = {
-+      { .name = "pcie20_phy0_pipe_clk" },
-+      { .fw_name = "xo", .name = "xo" },
-+};
-+
-+static const struct parent_map gcc_pcie20_phy0_pipe_clk_xo_map[] = {
-+      { P_PCIE20_PHY0_PIPE, 0 },
-+      { P_XO, 2 },
-+};
-+
- static struct clk_regmap_mux pcie0_pipe_clk_src = {
-       .reg = 0x7501c,
-       .shift = 8,
-@@ -1003,8 +697,8 @@ static struct clk_regmap_mux pcie0_pipe_
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "pcie0_pipe_clk_src",
--                      .parent_names = gcc_pcie20_phy0_pipe_clk_xo,
--                      .num_parents = 2,
-+                      .parent_data = gcc_pcie20_phy0_pipe_clk_xo,
-+                      .num_parents = ARRAY_SIZE(gcc_pcie20_phy0_pipe_clk_xo),
-                       .ops = &clk_regmap_mux_closest_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-               },
-@@ -1019,7 +713,7 @@ static struct clk_rcg2 pcie1_axi_clk_src
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "pcie1_axi_clk_src",
-               .parent_data = gcc_xo_gpll0,
--              .num_parents = 2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1032,12 +726,22 @@ static struct clk_rcg2 pcie1_aux_clk_src
-       .parent_map = gcc_xo_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "pcie1_aux_clk_src",
--              .parent_names = gcc_xo_gpll0_sleep_clk,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-+static const struct clk_parent_data gcc_pcie20_phy1_pipe_clk_xo[] = {
-+      { .name = "pcie20_phy1_pipe_clk" },
-+      { .fw_name = "xo", .name = "xo" },
-+};
-+
-+static const struct parent_map gcc_pcie20_phy1_pipe_clk_xo_map[] = {
-+      { P_PCIE20_PHY1_PIPE, 0 },
-+      { P_XO, 2 },
-+};
-+
- static struct clk_regmap_mux pcie1_pipe_clk_src = {
-       .reg = 0x7601c,
-       .shift = 8,
-@@ -1046,8 +750,8 @@ static struct clk_regmap_mux pcie1_pipe_
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "pcie1_pipe_clk_src",
--                      .parent_names = gcc_pcie20_phy1_pipe_clk_xo,
--                      .num_parents = 2,
-+                      .parent_data = gcc_pcie20_phy1_pipe_clk_xo,
-+                      .num_parents = ARRAY_SIZE(gcc_pcie20_phy1_pipe_clk_xo),
-                       .ops = &clk_regmap_mux_closest_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-               },
-@@ -1066,6 +770,20 @@ static const struct freq_tbl ftbl_sdcc_a
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_gpll2_gpll0_out_main_div2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll2.clkr.hw },
-+      { .hw = &gpll0_out_main_div2.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+      { P_GPLL2, 2 },
-+      { P_GPLL0_DIV2, 4 },
-+};
-+
- static struct clk_rcg2 sdcc1_apps_clk_src = {
-       .cmd_rcgr = 0x42004,
-       .freq_tbl = ftbl_sdcc_apps_clk_src,
-@@ -1074,8 +792,8 @@ static struct clk_rcg2 sdcc1_apps_clk_sr
-       .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "sdcc1_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2_gpll0_out_main_div2),
-               .ops = &clk_rcg2_floor_ops,
-       },
- };
-@@ -1086,6 +804,20 @@ static const struct freq_tbl ftbl_sdcc_i
-       F(308570000, P_GPLL6, 3.5, 0, 0),
- };
-+static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_div2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll6.clkr.hw },
-+      { .hw = &gpll0_out_main_div2.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_div2_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+      { P_GPLL6, 2 },
-+      { P_GPLL0_DIV2, 4 },
-+};
-+
- static struct clk_rcg2 sdcc1_ice_core_clk_src = {
-       .cmd_rcgr = 0x5d000,
-       .freq_tbl = ftbl_sdcc_ice_core_clk_src,
-@@ -1094,8 +826,8 @@ static struct clk_rcg2 sdcc1_ice_core_cl
-       .parent_map = gcc_xo_gpll0_gpll6_gpll0_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "sdcc1_ice_core_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll6_gpll0_div2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_gpll0_gpll6_gpll0_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1108,8 +840,8 @@ static struct clk_rcg2 sdcc2_apps_clk_sr
-       .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "sdcc2_apps_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2_gpll0_out_main_div2),
-               .ops = &clk_rcg2_floor_ops,
-       },
- };
-@@ -1121,6 +853,18 @@ static const struct freq_tbl ftbl_usb_ma
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_out_main_div2_gpll0[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0_out_main_div2.hw },
-+      { .hw = &gpll0.clkr.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_out_main_div2_gpll0_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0_DIV2, 2 },
-+      { P_GPLL0, 1 },
-+};
-+
- static struct clk_rcg2 usb0_master_clk_src = {
-       .cmd_rcgr = 0x3e00c,
-       .freq_tbl = ftbl_usb_master_clk_src,
-@@ -1129,8 +873,8 @@ static struct clk_rcg2 usb0_master_clk_s
-       .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "usb0_master_clk_src",
--              .parent_names = gcc_xo_gpll0_out_main_div2_gpll0,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_out_main_div2_gpll0,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1148,8 +892,8 @@ static struct clk_rcg2 usb0_aux_clk_src
-       .parent_map = gcc_xo_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "usb0_aux_clk_src",
--              .parent_names = gcc_xo_gpll0_sleep_clk,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1161,6 +905,20 @@ static const struct freq_tbl ftbl_usb_mo
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll6_gpll0_gpll0_out_main_div2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll6.clkr.hw },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll0_out_main_div2.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL6, 1 },
-+      { P_GPLL0, 3 },
-+      { P_GPLL0_DIV2, 4 },
-+};
-+
- static struct clk_rcg2 usb0_mock_utmi_clk_src = {
-       .cmd_rcgr = 0x3e020,
-       .freq_tbl = ftbl_usb_mock_utmi_clk_src,
-@@ -1169,12 +927,22 @@ static struct clk_rcg2 usb0_mock_utmi_cl
-       .parent_map = gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "usb0_mock_utmi_clk_src",
--              .parent_names = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll6_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-+static const struct clk_parent_data gcc_usb3phy_0_cc_pipe_clk_xo[] = {
-+      { .name = "usb3phy_0_cc_pipe_clk" },
-+      { .fw_name = "xo", .name = "xo" },
-+};
-+
-+static const struct parent_map gcc_usb3phy_0_cc_pipe_clk_xo_map[] = {
-+      { P_USB3PHY_0_PIPE, 0 },
-+      { P_XO, 2 },
-+};
-+
- static struct clk_regmap_mux usb0_pipe_clk_src = {
-       .reg = 0x3e048,
-       .shift = 8,
-@@ -1183,8 +951,8 @@ static struct clk_regmap_mux usb0_pipe_c
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "usb0_pipe_clk_src",
--                      .parent_names = gcc_usb3phy_0_cc_pipe_clk_xo,
--                      .num_parents = 2,
-+                      .parent_data = gcc_usb3phy_0_cc_pipe_clk_xo,
-+                      .num_parents = ARRAY_SIZE(gcc_usb3phy_0_cc_pipe_clk_xo),
-                       .ops = &clk_regmap_mux_closest_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-               },
-@@ -1199,8 +967,8 @@ static struct clk_rcg2 usb1_master_clk_s
-       .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "usb1_master_clk_src",
--              .parent_names = gcc_xo_gpll0_out_main_div2_gpll0,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_out_main_div2_gpll0,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1213,8 +981,8 @@ static struct clk_rcg2 usb1_aux_clk_src
-       .parent_map = gcc_xo_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "usb1_aux_clk_src",
--              .parent_names = gcc_xo_gpll0_sleep_clk,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1227,12 +995,22 @@ static struct clk_rcg2 usb1_mock_utmi_cl
-       .parent_map = gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "usb1_mock_utmi_clk_src",
--              .parent_names = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll6_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-+static const struct clk_parent_data gcc_usb3phy_1_cc_pipe_clk_xo[] = {
-+      { .name = "usb3phy_1_cc_pipe_clk" },
-+      { .fw_name = "xo", .name = "xo" },
-+};
-+
-+static const struct parent_map gcc_usb3phy_1_cc_pipe_clk_xo_map[] = {
-+      { P_USB3PHY_1_PIPE, 0 },
-+      { P_XO, 2 },
-+};
-+
- static struct clk_regmap_mux usb1_pipe_clk_src = {
-       .reg = 0x3f048,
-       .shift = 8,
-@@ -1241,8 +1019,8 @@ static struct clk_regmap_mux usb1_pipe_c
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "usb1_pipe_clk_src",
--                      .parent_names = gcc_usb3phy_1_cc_pipe_clk_xo,
--                      .num_parents = 2,
-+                      .parent_data = gcc_usb3phy_1_cc_pipe_clk_xo,
-+                      .num_parents = ARRAY_SIZE(gcc_usb3phy_1_cc_pipe_clk_xo),
-                       .ops = &clk_regmap_mux_closest_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-               },
-@@ -1256,8 +1034,9 @@ static struct clk_branch gcc_xo_clk_src
-               .enable_mask = BIT(1),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_xo_clk_src",
--                      .parent_names = (const char *[]){
--                              "xo"
-+                      .parent_data = &(const struct clk_parent_data){
-+                              .fw_name = "xo",
-+                              .name = "xo",
-                       },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
-@@ -1271,9 +1050,8 @@ static struct clk_fixed_factor gcc_xo_di
-       .div = 4,
-       .hw.init = &(struct clk_init_data){
-               .name = "gcc_xo_div4_clk_src",
--              .parent_names = (const char *[]){
--                      "gcc_xo_clk_src"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_clk_src.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -1291,6 +1069,20 @@ static const struct freq_tbl ftbl_system
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_out_main_div2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll6.clkr.hw },
-+      { .hw = &gpll0_out_main_div2.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+      { P_GPLL6, 2 },
-+      { P_GPLL0_DIV2, 3 },
-+};
-+
- static struct clk_rcg2 system_noc_bfdcd_clk_src = {
-       .cmd_rcgr = 0x26004,
-       .freq_tbl = ftbl_system_noc_bfdcd_clk_src,
-@@ -1298,8 +1090,8 @@ static struct clk_rcg2 system_noc_bfdcd_
-       .parent_map = gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "system_noc_bfdcd_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll6_gpll0_out_main_div2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_gpll0_gpll6_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-               .flags = CLK_IS_CRITICAL,
-       },
-@@ -1310,9 +1102,8 @@ static struct clk_fixed_factor system_no
-       .div = 1,
-       .hw.init = &(struct clk_init_data){
-               .name = "system_noc_clk_src",
--              .parent_names = (const char *[]){
--                      "system_noc_bfdcd_clk_src"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &system_noc_bfdcd_clk_src.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -1333,7 +1124,7 @@ static struct clk_rcg2 nss_ce_clk_src =
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_ce_clk_src",
-               .parent_data = gcc_xo_gpll0,
--              .num_parents = 2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1344,6 +1135,20 @@ static const struct freq_tbl ftbl_nss_no
-       { }
- };
-+static const struct clk_parent_data gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "bias_pll_nss_noc_clk" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll2.clkr.hw },
-+};
-+
-+static const struct parent_map gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map[] = {
-+      { P_XO, 0 },
-+      { P_BIAS_PLL_NSS_NOC, 1 },
-+      { P_GPLL0, 2 },
-+      { P_GPLL2, 3 },
-+};
-+
- static struct clk_rcg2 nss_noc_bfdcd_clk_src = {
-       .cmd_rcgr = 0x68088,
-       .freq_tbl = ftbl_nss_noc_bfdcd_clk_src,
-@@ -1351,8 +1156,8 @@ static struct clk_rcg2 nss_noc_bfdcd_clk
-       .parent_map = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_noc_bfdcd_clk_src",
--              .parent_names = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2,
--              .num_parents = 4,
-+              .parent_data = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1362,9 +1167,8 @@ static struct clk_fixed_factor nss_noc_c
-       .div = 1,
-       .hw.init = &(struct clk_init_data){
-               .name = "nss_noc_clk_src",
--              .parent_names = (const char *[]){
--                      "nss_noc_bfdcd_clk_src"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_bfdcd_clk_src.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -1377,6 +1181,18 @@ static const struct freq_tbl ftbl_nss_cr
-       { }
- };
-+static const struct clk_parent_data gcc_xo_nss_crypto_pll_gpll0[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &nss_crypto_pll.clkr.hw },
-+      { .hw = &gpll0.clkr.hw },
-+};
-+
-+static const struct parent_map gcc_xo_nss_crypto_pll_gpll0_map[] = {
-+      { P_XO, 0 },
-+      { P_NSS_CRYPTO_PLL, 1 },
-+      { P_GPLL0, 2 },
-+};
-+
- static struct clk_rcg2 nss_crypto_clk_src = {
-       .cmd_rcgr = 0x68144,
-       .freq_tbl = ftbl_nss_crypto_clk_src,
-@@ -1385,8 +1201,8 @@ static struct clk_rcg2 nss_crypto_clk_sr
-       .parent_map = gcc_xo_nss_crypto_pll_gpll0_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_crypto_clk_src",
--              .parent_names = gcc_xo_nss_crypto_pll_gpll0,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_nss_crypto_pll_gpll0,
-+              .num_parents = ARRAY_SIZE(gcc_xo_nss_crypto_pll_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1400,6 +1216,24 @@ static const struct freq_tbl ftbl_nss_ub
-       { }
- };
-+static const struct clk_parent_data gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll2.clkr.hw },
-+      { .hw = &gpll4.clkr.hw },
-+      { .hw = &gpll6.clkr.hw },
-+};
-+
-+static const struct parent_map gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map[] = {
-+      { P_XO, 0 },
-+      { P_UBI32_PLL, 1 },
-+      { P_GPLL0, 2 },
-+      { P_GPLL2, 3 },
-+      { P_GPLL4, 4 },
-+      { P_GPLL6, 5 },
-+};
-+
- static struct clk_rcg2 nss_ubi0_clk_src = {
-       .cmd_rcgr = 0x68104,
-       .freq_tbl = ftbl_nss_ubi_clk_src,
-@@ -1407,8 +1241,8 @@ static struct clk_rcg2 nss_ubi0_clk_src
-       .parent_map = gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_ubi0_clk_src",
--              .parent_names = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
--              .num_parents = 6,
-+              .parent_data = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
-+              .num_parents = ARRAY_SIZE(gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6),
-               .ops = &clk_rcg2_ops,
-               .flags = CLK_SET_RATE_PARENT,
-       },
-@@ -1421,9 +1255,8 @@ static struct clk_regmap_div nss_ubi0_di
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_ubi0_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_ubi0_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ubi0_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ro_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1438,8 +1271,8 @@ static struct clk_rcg2 nss_ubi1_clk_src
-       .parent_map = gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_ubi1_clk_src",
--              .parent_names = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
--              .num_parents = 6,
-+              .parent_data = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
-+              .num_parents = ARRAY_SIZE(gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6),
-               .ops = &clk_rcg2_ops,
-               .flags = CLK_SET_RATE_PARENT,
-       },
-@@ -1452,9 +1285,8 @@ static struct clk_regmap_div nss_ubi1_di
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_ubi1_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_ubi1_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ubi1_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ro_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1468,6 +1300,16 @@ static const struct freq_tbl ftbl_ubi_mp
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_out_main_div2[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0_out_main_div2.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_out_main_div2_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0_DIV2, 1 },
-+};
-+
- static struct clk_rcg2 ubi_mpt_clk_src = {
-       .cmd_rcgr = 0x68090,
-       .freq_tbl = ftbl_ubi_mpt_clk_src,
-@@ -1475,8 +1317,8 @@ static struct clk_rcg2 ubi_mpt_clk_src =
-       .parent_map = gcc_xo_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "ubi_mpt_clk_src",
--              .parent_names = gcc_xo_gpll0_out_main_div2,
--              .num_parents = 2,
-+              .parent_data = gcc_xo_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1487,6 +1329,18 @@ static const struct freq_tbl ftbl_nss_im
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_gpll4[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll4.clkr.hw },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+      { P_GPLL4, 2 },
-+};
-+
- static struct clk_rcg2 nss_imem_clk_src = {
-       .cmd_rcgr = 0x68158,
-       .freq_tbl = ftbl_nss_imem_clk_src,
-@@ -1494,8 +1348,8 @@ static struct clk_rcg2 nss_imem_clk_src
-       .parent_map = gcc_xo_gpll0_gpll4_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_imem_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll4,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll4,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1506,6 +1360,24 @@ static const struct freq_tbl ftbl_nss_pp
-       { }
- };
-+static const struct clk_parent_data gcc_xo_bias_gpll0_gpll4_nss_ubi32[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "bias_pll_cc_clk" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll4.clkr.hw },
-+      { .hw = &nss_crypto_pll.clkr.hw },
-+      { .hw = &ubi32_pll.clkr.hw },
-+};
-+
-+static const struct parent_map gcc_xo_bias_gpll0_gpll4_nss_ubi32_map[] = {
-+      { P_XO, 0 },
-+      { P_BIAS_PLL, 1 },
-+      { P_GPLL0, 2 },
-+      { P_GPLL4, 3 },
-+      { P_NSS_CRYPTO_PLL, 4 },
-+      { P_UBI32_PLL, 5 },
-+};
-+
- static struct clk_rcg2 nss_ppe_clk_src = {
-       .cmd_rcgr = 0x68080,
-       .freq_tbl = ftbl_nss_ppe_clk_src,
-@@ -1513,8 +1385,8 @@ static struct clk_rcg2 nss_ppe_clk_src =
-       .parent_map = gcc_xo_bias_gpll0_gpll4_nss_ubi32_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_ppe_clk_src",
--              .parent_names = gcc_xo_bias_gpll0_gpll4_nss_ubi32,
--              .num_parents = 6,
-+              .parent_data = gcc_xo_bias_gpll0_gpll4_nss_ubi32,
-+              .num_parents = ARRAY_SIZE(gcc_xo_bias_gpll0_gpll4_nss_ubi32),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1524,9 +1396,8 @@ static struct clk_fixed_factor nss_ppe_c
-       .div = 4,
-       .hw.init = &(struct clk_init_data){
-               .name = "nss_ppe_cdiv_clk_src",
--              .parent_names = (const char *[]){
--                      "nss_ppe_clk_src"
--              },
-+              .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-               .num_parents = 1,
-               .ops = &clk_fixed_factor_ops,
-               .flags = CLK_SET_RATE_PARENT,
-@@ -1540,6 +1411,22 @@ static const struct freq_tbl ftbl_nss_po
-       { }
- };
-+static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_ubi32_bias[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "uniphy0_gcc_rx_clk" },
-+      { .name = "uniphy0_gcc_tx_clk" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .name = "bias_pll_cc_clk" },
-+};
-+
-+static const struct parent_map gcc_xo_uniphy0_rx_tx_ubi32_bias_map[] = {
-+      { P_XO, 0 },
-+      { P_UNIPHY0_RX, 1 },
-+      { P_UNIPHY0_TX, 2 },
-+      { P_UBI32_PLL, 5 },
-+      { P_BIAS_PLL, 6 },
-+};
-+
- static struct clk_rcg2 nss_port1_rx_clk_src = {
-       .cmd_rcgr = 0x68020,
-       .freq_tbl = ftbl_nss_port1_rx_clk_src,
-@@ -1547,8 +1434,8 @@ static struct clk_rcg2 nss_port1_rx_clk_
-       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port1_rx_clk_src",
--              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1560,9 +1447,8 @@ static struct clk_regmap_div nss_port1_r
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port1_rx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port1_rx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port1_rx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1577,6 +1463,22 @@ static const struct freq_tbl ftbl_nss_po
-       { }
- };
-+static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_ubi32_bias[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "uniphy0_gcc_tx_clk" },
-+      { .name = "uniphy0_gcc_rx_clk" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .name = "bias_pll_cc_clk" },
-+};
-+
-+static const struct parent_map gcc_xo_uniphy0_tx_rx_ubi32_bias_map[] = {
-+      { P_XO, 0 },
-+      { P_UNIPHY0_TX, 1 },
-+      { P_UNIPHY0_RX, 2 },
-+      { P_UBI32_PLL, 5 },
-+      { P_BIAS_PLL, 6 },
-+};
-+
- static struct clk_rcg2 nss_port1_tx_clk_src = {
-       .cmd_rcgr = 0x68028,
-       .freq_tbl = ftbl_nss_port1_tx_clk_src,
-@@ -1584,8 +1486,8 @@ static struct clk_rcg2 nss_port1_tx_clk_
-       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port1_tx_clk_src",
--              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1597,9 +1499,8 @@ static struct clk_regmap_div nss_port1_t
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port1_tx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port1_tx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port1_tx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1614,8 +1515,8 @@ static struct clk_rcg2 nss_port2_rx_clk_
-       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port2_rx_clk_src",
--              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1627,9 +1528,8 @@ static struct clk_regmap_div nss_port2_r
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port2_rx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port2_rx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port2_rx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1644,8 +1544,8 @@ static struct clk_rcg2 nss_port2_tx_clk_
-       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port2_tx_clk_src",
--              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1657,9 +1557,8 @@ static struct clk_regmap_div nss_port2_t
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port2_tx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port2_tx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port2_tx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1674,8 +1573,8 @@ static struct clk_rcg2 nss_port3_rx_clk_
-       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port3_rx_clk_src",
--              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1687,9 +1586,8 @@ static struct clk_regmap_div nss_port3_r
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port3_rx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port3_rx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port3_rx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1704,8 +1602,8 @@ static struct clk_rcg2 nss_port3_tx_clk_
-       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port3_tx_clk_src",
--              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1717,9 +1615,8 @@ static struct clk_regmap_div nss_port3_t
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port3_tx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port3_tx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port3_tx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1734,8 +1631,8 @@ static struct clk_rcg2 nss_port4_rx_clk_
-       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port4_rx_clk_src",
--              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1747,9 +1644,8 @@ static struct clk_regmap_div nss_port4_r
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port4_rx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port4_rx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port4_rx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1764,8 +1660,8 @@ static struct clk_rcg2 nss_port4_tx_clk_
-       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port4_tx_clk_src",
--              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1777,9 +1673,8 @@ static struct clk_regmap_div nss_port4_t
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port4_tx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port4_tx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port4_tx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1799,6 +1694,27 @@ static const struct freq_tbl ftbl_nss_po
-       { }
- };
-+static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "uniphy0_gcc_rx_clk" },
-+      { .name = "uniphy0_gcc_tx_clk" },
-+      { .name = "uniphy1_gcc_rx_clk" },
-+      { .name = "uniphy1_gcc_tx_clk" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .name = "bias_pll_cc_clk" },
-+};
-+
-+static const struct parent_map
-+gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = {
-+      { P_XO, 0 },
-+      { P_UNIPHY0_RX, 1 },
-+      { P_UNIPHY0_TX, 2 },
-+      { P_UNIPHY1_RX, 3 },
-+      { P_UNIPHY1_TX, 4 },
-+      { P_UBI32_PLL, 5 },
-+      { P_BIAS_PLL, 6 },
-+};
-+
- static struct clk_rcg2 nss_port5_rx_clk_src = {
-       .cmd_rcgr = 0x68060,
-       .freq_tbl = ftbl_nss_port5_rx_clk_src,
-@@ -1806,8 +1722,8 @@ static struct clk_rcg2 nss_port5_rx_clk_
-       .parent_map = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port5_rx_clk_src",
--              .parent_names = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias,
--              .num_parents = 7,
-+              .parent_data = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1819,9 +1735,8 @@ static struct clk_regmap_div nss_port5_r
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port5_rx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port5_rx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_rx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1841,6 +1756,27 @@ static const struct freq_tbl ftbl_nss_po
-       { }
- };
-+static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "uniphy0_gcc_tx_clk" },
-+      { .name = "uniphy0_gcc_rx_clk" },
-+      { .name = "uniphy1_gcc_tx_clk" },
-+      { .name = "uniphy1_gcc_rx_clk" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .name = "bias_pll_cc_clk" },
-+};
-+
-+static const struct parent_map
-+gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = {
-+      { P_XO, 0 },
-+      { P_UNIPHY0_TX, 1 },
-+      { P_UNIPHY0_RX, 2 },
-+      { P_UNIPHY1_TX, 3 },
-+      { P_UNIPHY1_RX, 4 },
-+      { P_UBI32_PLL, 5 },
-+      { P_BIAS_PLL, 6 },
-+};
-+
- static struct clk_rcg2 nss_port5_tx_clk_src = {
-       .cmd_rcgr = 0x68068,
-       .freq_tbl = ftbl_nss_port5_tx_clk_src,
-@@ -1848,8 +1784,8 @@ static struct clk_rcg2 nss_port5_tx_clk_
-       .parent_map = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port5_tx_clk_src",
--              .parent_names = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias,
--              .num_parents = 7,
-+              .parent_data = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1861,9 +1797,8 @@ static struct clk_regmap_div nss_port5_t
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port5_tx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port5_tx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_tx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1883,6 +1818,22 @@ static const struct freq_tbl ftbl_nss_po
-       { }
- };
-+static const struct clk_parent_data gcc_xo_uniphy2_rx_tx_ubi32_bias[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "uniphy2_gcc_rx_clk" },
-+      { .name = "uniphy2_gcc_tx_clk" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .name = "bias_pll_cc_clk" },
-+};
-+
-+static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
-+      { P_XO, 0 },
-+      { P_UNIPHY2_RX, 1 },
-+      { P_UNIPHY2_TX, 2 },
-+      { P_UBI32_PLL, 5 },
-+      { P_BIAS_PLL, 6 },
-+};
-+
- static struct clk_rcg2 nss_port6_rx_clk_src = {
-       .cmd_rcgr = 0x68070,
-       .freq_tbl = ftbl_nss_port6_rx_clk_src,
-@@ -1890,8 +1841,8 @@ static struct clk_rcg2 nss_port6_rx_clk_
-       .parent_map = gcc_xo_uniphy2_rx_tx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port6_rx_clk_src",
--              .parent_names = gcc_xo_uniphy2_rx_tx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy2_rx_tx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy2_rx_tx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1903,9 +1854,8 @@ static struct clk_regmap_div nss_port6_r
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port6_rx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port6_rx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port6_rx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1925,6 +1875,22 @@ static const struct freq_tbl ftbl_nss_po
-       { }
- };
-+static const struct clk_parent_data gcc_xo_uniphy2_tx_rx_ubi32_bias[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .name = "uniphy2_gcc_tx_clk" },
-+      { .name = "uniphy2_gcc_rx_clk" },
-+      { .hw = &ubi32_pll.clkr.hw },
-+      { .name = "bias_pll_cc_clk" },
-+};
-+
-+static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
-+      { P_XO, 0 },
-+      { P_UNIPHY2_TX, 1 },
-+      { P_UNIPHY2_RX, 2 },
-+      { P_UBI32_PLL, 5 },
-+      { P_BIAS_PLL, 6 },
-+};
-+
- static struct clk_rcg2 nss_port6_tx_clk_src = {
-       .cmd_rcgr = 0x68078,
-       .freq_tbl = ftbl_nss_port6_tx_clk_src,
-@@ -1932,8 +1898,8 @@ static struct clk_rcg2 nss_port6_tx_clk_
-       .parent_map = gcc_xo_uniphy2_tx_rx_ubi32_bias_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "nss_port6_tx_clk_src",
--              .parent_names = gcc_xo_uniphy2_tx_rx_ubi32_bias,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_uniphy2_tx_rx_ubi32_bias,
-+              .num_parents = ARRAY_SIZE(gcc_xo_uniphy2_tx_rx_ubi32_bias),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1945,9 +1911,8 @@ static struct clk_regmap_div nss_port6_t
-       .clkr = {
-               .hw.init = &(struct clk_init_data){
-                       .name = "nss_port6_tx_div_clk_src",
--                      .parent_names = (const char *[]){
--                              "nss_port6_tx_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port6_tx_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT,
-@@ -1970,8 +1935,8 @@ static struct clk_rcg2 crypto_clk_src =
-       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "crypto_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
--              .num_parents = 3,
-+              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -1981,6 +1946,22 @@ static struct freq_tbl ftbl_gp_clk_src[]
-       { }
- };
-+static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_sleep_clk[] = {
-+      { .fw_name = "xo", .name = "xo" },
-+      { .hw = &gpll0.clkr.hw },
-+      { .hw = &gpll6.clkr.hw },
-+      { .hw = &gpll0_out_main_div2.hw },
-+      { .fw_name = "sleep_clk", .name = "sleep_clk" },
-+};
-+
-+static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map[] = {
-+      { P_XO, 0 },
-+      { P_GPLL0, 1 },
-+      { P_GPLL6, 2 },
-+      { P_GPLL0_DIV2, 4 },
-+      { P_SLEEP_CLK, 6 },
-+};
-+
- static struct clk_rcg2 gp1_clk_src = {
-       .cmd_rcgr = 0x08004,
-       .freq_tbl = ftbl_gp_clk_src,
-@@ -1989,8 +1970,8 @@ static struct clk_rcg2 gp1_clk_src = {
-       .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gp1_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -2003,8 +1984,8 @@ static struct clk_rcg2 gp2_clk_src = {
-       .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gp2_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -2017,8 +1998,8 @@ static struct clk_rcg2 gp3_clk_src = {
-       .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "gp3_clk_src",
--              .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
--              .num_parents = 5,
-+              .parent_data = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_sleep_clk),
-               .ops = &clk_rcg2_ops,
-       },
- };
-@@ -2030,9 +2011,8 @@ static struct clk_branch gcc_blsp1_ahb_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2047,9 +2027,8 @@ static struct clk_branch gcc_blsp1_qup1_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup1_i2c_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup1_i2c_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup1_i2c_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2064,9 +2043,8 @@ static struct clk_branch gcc_blsp1_qup1_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup1_spi_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup1_spi_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup1_spi_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2081,9 +2059,8 @@ static struct clk_branch gcc_blsp1_qup2_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup2_i2c_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup2_i2c_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup2_i2c_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2098,9 +2075,8 @@ static struct clk_branch gcc_blsp1_qup2_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup2_spi_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup2_spi_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup2_spi_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2115,9 +2091,8 @@ static struct clk_branch gcc_blsp1_qup3_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup3_i2c_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup3_i2c_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup3_i2c_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2132,9 +2107,8 @@ static struct clk_branch gcc_blsp1_qup3_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup3_spi_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup3_spi_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup3_spi_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2149,9 +2123,8 @@ static struct clk_branch gcc_blsp1_qup4_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup4_i2c_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup4_i2c_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup4_i2c_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2166,9 +2139,8 @@ static struct clk_branch gcc_blsp1_qup4_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup4_spi_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup4_spi_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup4_spi_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2183,9 +2155,8 @@ static struct clk_branch gcc_blsp1_qup5_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup5_i2c_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup5_i2c_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup5_i2c_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2200,9 +2171,8 @@ static struct clk_branch gcc_blsp1_qup5_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup5_spi_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup5_spi_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup5_spi_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2217,9 +2187,8 @@ static struct clk_branch gcc_blsp1_qup6_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup6_i2c_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup6_i2c_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup6_i2c_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2234,9 +2203,8 @@ static struct clk_branch gcc_blsp1_qup6_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_qup6_spi_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_qup6_spi_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_qup6_spi_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2251,9 +2219,8 @@ static struct clk_branch gcc_blsp1_uart1
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_uart1_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_uart1_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_uart1_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2268,9 +2235,8 @@ static struct clk_branch gcc_blsp1_uart2
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_uart2_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_uart2_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_uart2_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2285,9 +2251,8 @@ static struct clk_branch gcc_blsp1_uart3
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_uart3_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_uart3_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_uart3_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2302,9 +2267,8 @@ static struct clk_branch gcc_blsp1_uart4
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_uart4_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_uart4_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_uart4_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2319,9 +2283,8 @@ static struct clk_branch gcc_blsp1_uart5
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_uart5_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_uart5_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_uart5_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2336,9 +2299,8 @@ static struct clk_branch gcc_blsp1_uart6
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_blsp1_uart6_apps_clk",
--                      .parent_names = (const char *[]){
--                              "blsp1_uart6_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &blsp1_uart6_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2354,9 +2316,8 @@ static struct clk_branch gcc_prng_ahb_cl
-               .enable_mask = BIT(8),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_prng_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2371,9 +2332,8 @@ static struct clk_branch gcc_qpic_ahb_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_qpic_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2388,9 +2348,8 @@ static struct clk_branch gcc_qpic_clk =
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_qpic_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2405,9 +2364,8 @@ static struct clk_branch gcc_pcie0_ahb_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie0_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2422,9 +2380,8 @@ static struct clk_branch gcc_pcie0_aux_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie0_aux_clk",
--                      .parent_names = (const char *[]){
--                              "pcie0_aux_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie0_aux_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2439,9 +2396,8 @@ static struct clk_branch gcc_pcie0_axi_m
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie0_axi_m_clk",
--                      .parent_names = (const char *[]){
--                              "pcie0_axi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie0_axi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2456,9 +2412,8 @@ static struct clk_branch gcc_pcie0_axi_s
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie0_axi_s_clk",
--                      .parent_names = (const char *[]){
--                              "pcie0_axi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie0_axi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2474,9 +2429,8 @@ static struct clk_branch gcc_pcie0_pipe_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie0_pipe_clk",
--                      .parent_names = (const char *[]){
--                              "pcie0_pipe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie0_pipe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2491,9 +2445,8 @@ static struct clk_branch gcc_sys_noc_pci
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sys_noc_pcie0_axi_clk",
--                      .parent_names = (const char *[]){
--                              "pcie0_axi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie0_axi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2508,9 +2461,8 @@ static struct clk_branch gcc_pcie1_ahb_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie1_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2525,9 +2477,8 @@ static struct clk_branch gcc_pcie1_aux_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie1_aux_clk",
--                      .parent_names = (const char *[]){
--                              "pcie1_aux_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie1_aux_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2542,9 +2493,8 @@ static struct clk_branch gcc_pcie1_axi_m
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie1_axi_m_clk",
--                      .parent_names = (const char *[]){
--                              "pcie1_axi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie1_axi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2559,9 +2509,8 @@ static struct clk_branch gcc_pcie1_axi_s
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie1_axi_s_clk",
--                      .parent_names = (const char *[]){
--                              "pcie1_axi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie1_axi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2577,9 +2526,8 @@ static struct clk_branch gcc_pcie1_pipe_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_pcie1_pipe_clk",
--                      .parent_names = (const char *[]){
--                              "pcie1_pipe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie1_pipe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2594,9 +2542,8 @@ static struct clk_branch gcc_sys_noc_pci
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sys_noc_pcie1_axi_clk",
--                      .parent_names = (const char *[]){
--                              "pcie1_axi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcie1_axi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2611,9 +2558,8 @@ static struct clk_branch gcc_usb0_aux_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb0_aux_clk",
--                      .parent_names = (const char *[]){
--                              "usb0_aux_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb0_aux_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2628,9 +2574,8 @@ static struct clk_branch gcc_sys_noc_usb
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sys_noc_usb0_axi_clk",
--                      .parent_names = (const char *[]){
--                              "usb0_master_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb0_master_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2645,9 +2590,8 @@ static struct clk_branch gcc_usb0_master
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb0_master_clk",
--                      .parent_names = (const char *[]){
--                              "usb0_master_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb0_master_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2662,9 +2606,8 @@ static struct clk_branch gcc_usb0_mock_u
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb0_mock_utmi_clk",
--                      .parent_names = (const char *[]){
--                              "usb0_mock_utmi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb0_mock_utmi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2679,9 +2622,8 @@ static struct clk_branch gcc_usb0_phy_cf
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb0_phy_cfg_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2697,9 +2639,8 @@ static struct clk_branch gcc_usb0_pipe_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb0_pipe_clk",
--                      .parent_names = (const char *[]){
--                              "usb0_pipe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb0_pipe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2714,9 +2655,8 @@ static struct clk_branch gcc_usb0_sleep_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb0_sleep_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_sleep_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_sleep_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2731,9 +2671,8 @@ static struct clk_branch gcc_usb1_aux_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb1_aux_clk",
--                      .parent_names = (const char *[]){
--                              "usb1_aux_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb1_aux_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2748,9 +2687,8 @@ static struct clk_branch gcc_sys_noc_usb
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sys_noc_usb1_axi_clk",
--                      .parent_names = (const char *[]){
--                              "usb1_master_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb1_master_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2765,9 +2703,8 @@ static struct clk_branch gcc_usb1_master
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb1_master_clk",
--                      .parent_names = (const char *[]){
--                              "usb1_master_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb1_master_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2782,9 +2719,8 @@ static struct clk_branch gcc_usb1_mock_u
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb1_mock_utmi_clk",
--                      .parent_names = (const char *[]){
--                              "usb1_mock_utmi_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb1_mock_utmi_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2799,9 +2735,8 @@ static struct clk_branch gcc_usb1_phy_cf
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb1_phy_cfg_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2817,9 +2752,8 @@ static struct clk_branch gcc_usb1_pipe_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb1_pipe_clk",
--                      .parent_names = (const char *[]){
--                              "usb1_pipe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &usb1_pipe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2834,9 +2768,8 @@ static struct clk_branch gcc_usb1_sleep_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_usb1_sleep_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_sleep_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_sleep_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2851,9 +2784,8 @@ static struct clk_branch gcc_sdcc1_ahb_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sdcc1_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2868,9 +2800,8 @@ static struct clk_branch gcc_sdcc1_apps_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sdcc1_apps_clk",
--                      .parent_names = (const char *[]){
--                              "sdcc1_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &sdcc1_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2885,9 +2816,8 @@ static struct clk_branch gcc_sdcc1_ice_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sdcc1_ice_core_clk",
--                      .parent_names = (const char *[]){
--                              "sdcc1_ice_core_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &sdcc1_ice_core_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2902,9 +2832,8 @@ static struct clk_branch gcc_sdcc2_ahb_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sdcc2_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2919,9 +2848,8 @@ static struct clk_branch gcc_sdcc2_apps_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_sdcc2_apps_clk",
--                      .parent_names = (const char *[]){
--                              "sdcc2_apps_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &sdcc2_apps_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2936,9 +2864,8 @@ static struct clk_branch gcc_mem_noc_nss
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_mem_noc_nss_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2953,9 +2880,8 @@ static struct clk_branch gcc_nss_ce_apb_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ce_apb_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2970,9 +2896,8 @@ static struct clk_branch gcc_nss_ce_axi_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ce_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -2987,9 +2912,8 @@ static struct clk_branch gcc_nss_cfg_clk
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_cfg_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3004,9 +2928,8 @@ static struct clk_branch gcc_nss_crypto_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_crypto_clk",
--                      .parent_names = (const char *[]){
--                              "nss_crypto_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_crypto_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3021,9 +2944,8 @@ static struct clk_branch gcc_nss_csr_clk
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_csr_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3038,9 +2960,8 @@ static struct clk_branch gcc_nss_edma_cf
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_edma_cfg_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3055,9 +2976,8 @@ static struct clk_branch gcc_nss_edma_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_edma_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3072,9 +2992,8 @@ static struct clk_branch gcc_nss_imem_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_imem_clk",
--                      .parent_names = (const char *[]){
--                              "nss_imem_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_imem_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3089,9 +3008,8 @@ static struct clk_branch gcc_nss_noc_clk
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_noc_clk",
--                      .parent_names = (const char *[]){
--                              "nss_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3106,9 +3024,8 @@ static struct clk_branch gcc_nss_ppe_btq
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ppe_btq_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3123,9 +3040,8 @@ static struct clk_branch gcc_nss_ppe_cfg
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ppe_cfg_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3140,9 +3056,8 @@ static struct clk_branch gcc_nss_ppe_clk
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ppe_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3157,9 +3072,8 @@ static struct clk_branch gcc_nss_ppe_ipe
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ppe_ipe_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3174,9 +3088,8 @@ static struct clk_branch gcc_nss_ptp_ref
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_ptp_ref_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_cdiv_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_cdiv_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3192,9 +3105,8 @@ static struct clk_branch gcc_crypto_ppe_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_crypto_ppe_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3209,9 +3121,8 @@ static struct clk_branch gcc_nssnoc_ce_a
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_ce_apb_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3226,9 +3137,8 @@ static struct clk_branch gcc_nssnoc_ce_a
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_ce_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3243,9 +3153,8 @@ static struct clk_branch gcc_nssnoc_cryp
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_crypto_clk",
--                      .parent_names = (const char *[]){
--                              "nss_crypto_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_crypto_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3260,9 +3169,8 @@ static struct clk_branch gcc_nssnoc_ppe_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_ppe_cfg_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3277,9 +3185,8 @@ static struct clk_branch gcc_nssnoc_ppe_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_ppe_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3294,9 +3201,8 @@ static struct clk_branch gcc_nssnoc_qosg
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_qosgen_ref_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_xo_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3311,9 +3217,8 @@ static struct clk_branch gcc_nssnoc_snoc
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_snoc_clk",
--                      .parent_names = (const char *[]){
--                              "system_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &system_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3328,9 +3233,8 @@ static struct clk_branch gcc_nssnoc_time
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_timeout_ref_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_xo_div4_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_div4_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3345,9 +3249,8 @@ static struct clk_branch gcc_nssnoc_ubi0
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_ubi0_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3362,9 +3265,8 @@ static struct clk_branch gcc_nssnoc_ubi1
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nssnoc_ubi1_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3380,9 +3282,8 @@ static struct clk_branch gcc_ubi0_ahb_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi0_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3398,9 +3299,8 @@ static struct clk_branch gcc_ubi0_axi_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi0_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3416,9 +3316,8 @@ static struct clk_branch gcc_ubi0_nc_axi
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi0_nc_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3434,9 +3333,8 @@ static struct clk_branch gcc_ubi0_core_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi0_core_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ubi0_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ubi0_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3452,9 +3350,8 @@ static struct clk_branch gcc_ubi0_mpt_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi0_mpt_clk",
--                      .parent_names = (const char *[]){
--                              "ubi_mpt_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &ubi_mpt_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3470,9 +3367,8 @@ static struct clk_branch gcc_ubi1_ahb_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi1_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ce_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ce_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3488,9 +3384,8 @@ static struct clk_branch gcc_ubi1_axi_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi1_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3506,9 +3401,8 @@ static struct clk_branch gcc_ubi1_nc_axi
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi1_nc_axi_clk",
--                      .parent_names = (const char *[]){
--                              "nss_noc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_noc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3524,9 +3418,8 @@ static struct clk_branch gcc_ubi1_core_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi1_core_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ubi1_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ubi1_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3542,9 +3435,8 @@ static struct clk_branch gcc_ubi1_mpt_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_ubi1_mpt_clk",
--                      .parent_names = (const char *[]){
--                              "ubi_mpt_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &ubi_mpt_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3559,9 +3451,8 @@ static struct clk_branch gcc_cmn_12gpll_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_cmn_12gpll_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3576,9 +3467,8 @@ static struct clk_branch gcc_cmn_12gpll_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_cmn_12gpll_sys_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_xo_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3593,9 +3483,8 @@ static struct clk_branch gcc_mdio_ahb_cl
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_mdio_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3610,9 +3499,8 @@ static struct clk_branch gcc_uniphy0_ahb
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3627,9 +3515,8 @@ static struct clk_branch gcc_uniphy0_sys
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_sys_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_xo_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3644,9 +3531,8 @@ static struct clk_branch gcc_uniphy1_ahb
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy1_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3661,9 +3547,8 @@ static struct clk_branch gcc_uniphy1_sys
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy1_sys_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_xo_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3678,9 +3563,8 @@ static struct clk_branch gcc_uniphy2_ahb
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy2_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3695,9 +3579,8 @@ static struct clk_branch gcc_uniphy2_sys
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy2_sys_clk",
--                      .parent_names = (const char *[]){
--                              "gcc_xo_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gcc_xo_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3712,9 +3595,8 @@ static struct clk_branch gcc_nss_port1_r
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port1_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port1_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port1_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3729,9 +3611,8 @@ static struct clk_branch gcc_nss_port1_t
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port1_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port1_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port1_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3746,9 +3627,8 @@ static struct clk_branch gcc_nss_port2_r
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port2_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port2_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port2_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3763,9 +3643,8 @@ static struct clk_branch gcc_nss_port2_t
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port2_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port2_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port2_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3780,9 +3659,8 @@ static struct clk_branch gcc_nss_port3_r
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port3_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port3_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port3_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3797,9 +3675,8 @@ static struct clk_branch gcc_nss_port3_t
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port3_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port3_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port3_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3814,9 +3691,8 @@ static struct clk_branch gcc_nss_port4_r
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port4_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port4_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port4_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3831,9 +3707,8 @@ static struct clk_branch gcc_nss_port4_t
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port4_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port4_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port4_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3848,9 +3723,8 @@ static struct clk_branch gcc_nss_port5_r
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port5_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port5_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3865,9 +3739,8 @@ static struct clk_branch gcc_nss_port5_t
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port5_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port5_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3882,9 +3755,8 @@ static struct clk_branch gcc_nss_port6_r
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port6_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port6_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port6_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3899,9 +3771,8 @@ static struct clk_branch gcc_nss_port6_t
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_nss_port6_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port6_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port6_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3916,9 +3787,8 @@ static struct clk_branch gcc_port1_mac_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_port1_mac_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3933,9 +3803,8 @@ static struct clk_branch gcc_port2_mac_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_port2_mac_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3950,9 +3819,8 @@ static struct clk_branch gcc_port3_mac_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_port3_mac_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3967,9 +3835,8 @@ static struct clk_branch gcc_port4_mac_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_port4_mac_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -3984,9 +3851,8 @@ static struct clk_branch gcc_port5_mac_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_port5_mac_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4001,9 +3867,8 @@ static struct clk_branch gcc_port6_mac_c
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_port6_mac_clk",
--                      .parent_names = (const char *[]){
--                              "nss_ppe_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_ppe_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4018,9 +3883,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port1_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port1_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port1_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4035,9 +3899,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port1_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port1_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port1_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4052,9 +3915,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port2_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port2_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port2_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4069,9 +3931,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port2_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port2_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port2_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4086,9 +3947,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port3_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port3_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port3_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4103,9 +3963,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port3_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port3_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port3_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4120,9 +3979,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port4_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port4_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port4_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4137,9 +3995,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port4_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port4_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port4_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4154,9 +4011,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port5_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port5_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4171,9 +4027,8 @@ static struct clk_branch gcc_uniphy0_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy0_port5_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port5_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4188,9 +4043,8 @@ static struct clk_branch gcc_uniphy1_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy1_port5_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port5_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4205,9 +4059,8 @@ static struct clk_branch gcc_uniphy1_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy1_port5_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port5_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port5_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4222,9 +4075,8 @@ static struct clk_branch gcc_uniphy2_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy2_port6_rx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port6_rx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port6_rx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4239,9 +4091,8 @@ static struct clk_branch gcc_uniphy2_por
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_uniphy2_port6_tx_clk",
--                      .parent_names = (const char *[]){
--                              "nss_port6_tx_div_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &nss_port6_tx_div_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4257,9 +4108,8 @@ static struct clk_branch gcc_crypto_ahb_
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_crypto_ahb_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4275,9 +4125,8 @@ static struct clk_branch gcc_crypto_axi_
-               .enable_mask = BIT(1),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_crypto_axi_clk",
--                      .parent_names = (const char *[]){
--                              "pcnoc_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &pcnoc_clk_src.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4293,9 +4142,8 @@ static struct clk_branch gcc_crypto_clk
-               .enable_mask = BIT(2),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_crypto_clk",
--                      .parent_names = (const char *[]){
--                              "crypto_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &crypto_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4310,9 +4158,8 @@ static struct clk_branch gcc_gp1_clk = {
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_gp1_clk",
--                      .parent_names = (const char *[]){
--                              "gp1_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gp1_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4327,9 +4174,8 @@ static struct clk_branch gcc_gp2_clk = {
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_gp2_clk",
--                      .parent_names = (const char *[]){
--                              "gp2_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gp2_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4344,9 +4190,8 @@ static struct clk_branch gcc_gp3_clk = {
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "gcc_gp3_clk",
--                      .parent_names = (const char *[]){
--                              "gp3_clk_src"
--                      },
-+                      .parent_hws = (const struct clk_hw *[]){
-+                              &gp3_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-@@ -4368,7 +4213,7 @@ static struct clk_rcg2 pcie0_rchng_clk_s
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "pcie0_rchng_clk_src",
-               .parent_data = gcc_xo_gpll0,
--              .num_parents = 2,
-+              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
- };
diff --git a/target/linux/ipq807x/patches-6.1/0008-v6.2-clk-qcom-reset-support-resetting-multiple-bits.patch b/target/linux/ipq807x/patches-6.1/0008-v6.2-clk-qcom-reset-support-resetting-multiple-bits.patch
deleted file mode 100644 (file)
index e0725a6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-From 813ba3e427671ba3ff35c825087b03f0ad91cf02 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 7 Nov 2022 14:28:59 +0100
-Subject: [PATCH] clk: qcom: reset: support resetting multiple bits
-
-This patch adds the support for giving the complete bitmask
-in reset structure and reset operation will use this bitmask
-for all reset operations.
-
-Currently, reset structure only takes a single bit for each reset
-and then calculates the bitmask by using the BIT() macro.
-
-However, this is not sufficient anymore for newer SoC-s like IPQ8074,
-IPQ6018 and more, since their networking resets require multiple bits
-to be asserted in order to properly reset the HW block completely.
-
-So, in order to allow asserting multiple bits add "bitmask" field to
-qcom_reset_map, and then use that bitmask value if its populated in the
-driver, if its not populated, then we just default to existing behaviour
-and calculate the bitmask on the fly.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221107132901.489240-1-robimarko@gmail.com
----
- drivers/clk/qcom/reset.c | 4 ++--
- drivers/clk/qcom/reset.h | 1 +
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/qcom/reset.c
-+++ b/drivers/clk/qcom/reset.c
-@@ -30,7 +30,7 @@ qcom_reset_assert(struct reset_controlle
-       rst = to_qcom_reset_controller(rcdev);
-       map = &rst->reset_map[id];
--      mask = BIT(map->bit);
-+      mask = map->bitmask ? map->bitmask : BIT(map->bit);
-       return regmap_update_bits(rst->regmap, map->reg, mask, mask);
- }
-@@ -44,7 +44,7 @@ qcom_reset_deassert(struct reset_control
-       rst = to_qcom_reset_controller(rcdev);
-       map = &rst->reset_map[id];
--      mask = BIT(map->bit);
-+      mask = map->bitmask ? map->bitmask : BIT(map->bit);
-       return regmap_update_bits(rst->regmap, map->reg, mask, 0);
- }
---- a/drivers/clk/qcom/reset.h
-+++ b/drivers/clk/qcom/reset.h
-@@ -12,6 +12,7 @@ struct qcom_reset_map {
-       unsigned int reg;
-       u8 bit;
-       u8 udelay;
-+      u32 bitmask;
- };
- struct regmap;
diff --git a/target/linux/ipq807x/patches-6.1/0009-v6.2-dt-bindings-clock-qcom-ipq8074-add-missing-networkin.patch b/target/linux/ipq807x/patches-6.1/0009-v6.2-dt-bindings-clock-qcom-ipq8074-add-missing-networkin.patch
deleted file mode 100644 (file)
index 75f16a1..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From e78a40eb24187a8b4f9b89e2181f674df39c2013 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 7 Nov 2022 14:29:00 +0100
-Subject: [PATCH] dt-bindings: clock: qcom: ipq8074: add missing networking
- resets
-
-Add bindings for the missing networking resets found in IPQ8074 GCC.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221107132901.489240-2-robimarko@gmail.com
----
- include/dt-bindings/clock/qcom,gcc-ipq8074.h | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
---- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h
-+++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h
-@@ -367,6 +367,20 @@
- #define GCC_PCIE1_AHB_ARES                    129
- #define GCC_PCIE1_AXI_MASTER_STICKY_ARES      130
- #define GCC_PCIE0_AXI_SLAVE_STICKY_ARES               131
-+#define GCC_PPE_FULL_RESET                    132
-+#define GCC_UNIPHY0_SOFT_RESET                        133
-+#define GCC_UNIPHY0_XPCS_RESET                        134
-+#define GCC_UNIPHY1_SOFT_RESET                        135
-+#define GCC_UNIPHY1_XPCS_RESET                        136
-+#define GCC_UNIPHY2_SOFT_RESET                        137
-+#define GCC_UNIPHY2_XPCS_RESET                        138
-+#define GCC_EDMA_HW_RESET                     139
-+#define GCC_NSSPORT1_RESET                    140
-+#define GCC_NSSPORT2_RESET                    141
-+#define GCC_NSSPORT3_RESET                    142
-+#define GCC_NSSPORT4_RESET                    143
-+#define GCC_NSSPORT5_RESET                    144
-+#define GCC_NSSPORT6_RESET                    145
- #define USB0_GDSC                             0
- #define USB1_GDSC                             1
diff --git a/target/linux/ipq807x/patches-6.1/0010-v6.2-clk-qcom-ipq8074-add-missing-networking-resets.patch b/target/linux/ipq807x/patches-6.1/0010-v6.2-clk-qcom-ipq8074-add-missing-networking-resets.patch
deleted file mode 100644 (file)
index 212fc84..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-From da76cb63d04dc22ed32123b8c1d084c006d67bfb Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 7 Nov 2022 14:29:01 +0100
-Subject: [PATCH] clk: qcom: ipq8074: add missing networking resets
-
-Downstream QCA 5.4 kernel defines networking resets which are not present
-in the mainline kernel but are required for the networking drivers.
-
-So, port the downstream resets and avoid using magic values for mask,
-construct mask for resets which require multiple bits to be set/cleared.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221107132901.489240-3-robimarko@gmail.com
----
- drivers/clk/qcom/gcc-ipq8074.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
---- a/drivers/clk/qcom/gcc-ipq8074.c
-+++ b/drivers/clk/qcom/gcc-ipq8074.c
-@@ -4671,6 +4671,20 @@ static const struct qcom_reset_map gcc_i
-       [GCC_PCIE1_AXI_SLAVE_ARES] = { 0x76040, 4 },
-       [GCC_PCIE1_AHB_ARES] = { 0x76040, 5 },
-       [GCC_PCIE1_AXI_MASTER_STICKY_ARES] = { 0x76040, 6 },
-+      [GCC_PPE_FULL_RESET] = { .reg = 0x68014, .bitmask = GENMASK(19, 16) },
-+      [GCC_UNIPHY0_SOFT_RESET] = { .reg = 0x56004, .bitmask = GENMASK(13, 4) | BIT(1) },
-+      [GCC_UNIPHY0_XPCS_RESET] = { 0x56004, 2 },
-+      [GCC_UNIPHY1_SOFT_RESET] = { .reg = 0x56104, .bitmask = GENMASK(5, 4) | BIT(1) },
-+      [GCC_UNIPHY1_XPCS_RESET] = { 0x56104, 2 },
-+      [GCC_UNIPHY2_SOFT_RESET] = { .reg = 0x56204, .bitmask = GENMASK(5, 4) | BIT(1) },
-+      [GCC_UNIPHY2_XPCS_RESET] = { 0x56204, 2 },
-+      [GCC_EDMA_HW_RESET] = { .reg = 0x68014, .bitmask = GENMASK(21, 20) },
-+      [GCC_NSSPORT1_RESET] = { .reg = 0x68014, .bitmask = BIT(24) | GENMASK(1, 0) },
-+      [GCC_NSSPORT2_RESET] = { .reg = 0x68014, .bitmask = BIT(25) | GENMASK(3, 2) },
-+      [GCC_NSSPORT3_RESET] = { .reg = 0x68014, .bitmask = BIT(26) | GENMASK(5, 4) },
-+      [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) },
- };
- static struct gdsc *gcc_ipq8074_gdscs[] = {
diff --git a/target/linux/ipq807x/patches-6.1/0011-v6.2-clk-qcom-ipq8074-populate-fw_name-for-all-parents.patch b/target/linux/ipq807x/patches-6.1/0011-v6.2-clk-qcom-ipq8074-populate-fw_name-for-all-parents.patch
deleted file mode 100644 (file)
index 7372b1d..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-From 78936d46470938caa9a7ea529deeb36777b4f98e Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 16 Nov 2022 22:46:55 +0100
-Subject: [PATCH] clk: qcom: ipq8074: populate fw_name for all parents
-
-It appears that having only .name populated in parent_data for clocks
-which are only globally searchable currently will not work as the clk core
-won't copy that name if there is no .fw_name present as well.
-
-So, populate .fw_name for all parent clocks in parent_data.
-
-Fixes: ae55ad32e273 ("clk: qcom: ipq8074: convert to parent data")
-
-Co-developed-by: Christian Marangi <ansuelsmth@gmail.com>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221116214655.1116467-1-robimarko@gmail.com
----
- drivers/clk/qcom/gcc-ipq8074.c | 52 +++++++++++++++++-----------------
- 1 file changed, 26 insertions(+), 26 deletions(-)
-
---- a/drivers/clk/qcom/gcc-ipq8074.c
-+++ b/drivers/clk/qcom/gcc-ipq8074.c
-@@ -680,7 +680,7 @@ static struct clk_rcg2 pcie0_aux_clk_src
- };
- static const struct clk_parent_data gcc_pcie20_phy0_pipe_clk_xo[] = {
--      { .name = "pcie20_phy0_pipe_clk" },
-+      { .fw_name = "pcie0_pipe", .name = "pcie20_phy0_pipe_clk" },
-       { .fw_name = "xo", .name = "xo" },
- };
-@@ -733,7 +733,7 @@ static struct clk_rcg2 pcie1_aux_clk_src
- };
- static const struct clk_parent_data gcc_pcie20_phy1_pipe_clk_xo[] = {
--      { .name = "pcie20_phy1_pipe_clk" },
-+      { .fw_name = "pcie1_pipe", .name = "pcie20_phy1_pipe_clk" },
-       { .fw_name = "xo", .name = "xo" },
- };
-@@ -1137,7 +1137,7 @@ static const struct freq_tbl ftbl_nss_no
- static const struct clk_parent_data gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = {
-       { .fw_name = "xo", .name = "xo" },
--      { .name = "bias_pll_nss_noc_clk" },
-+      { .fw_name = "bias_pll_nss_noc_clk", .name = "bias_pll_nss_noc_clk" },
-       { .hw = &gpll0.clkr.hw },
-       { .hw = &gpll2.clkr.hw },
- };
-@@ -1362,7 +1362,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", .name = "xo" },
--      { .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 },
-@@ -1413,10 +1413,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", .name = "xo" },
--      { .name = "uniphy0_gcc_rx_clk" },
--      { .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 },
--      { .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[] = {
-@@ -1465,10 +1465,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", .name = "xo" },
--      { .name = "uniphy0_gcc_tx_clk" },
--      { .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 },
--      { .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[] = {
-@@ -1696,12 +1696,12 @@ static const struct freq_tbl ftbl_nss_po
- static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
-       { .fw_name = "xo", .name = "xo" },
--      { .name = "uniphy0_gcc_rx_clk" },
--      { .name = "uniphy0_gcc_tx_clk" },
--      { .name = "uniphy1_gcc_rx_clk" },
--      { .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 },
--      { .name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map
-@@ -1758,12 +1758,12 @@ static const struct freq_tbl ftbl_nss_po
- static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
-       { .fw_name = "xo", .name = "xo" },
--      { .name = "uniphy0_gcc_tx_clk" },
--      { .name = "uniphy0_gcc_rx_clk" },
--      { .name = "uniphy1_gcc_tx_clk" },
--      { .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 },
--      { .name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map
-@@ -1820,10 +1820,10 @@ static const struct freq_tbl ftbl_nss_po
- static const struct clk_parent_data gcc_xo_uniphy2_rx_tx_ubi32_bias[] = {
-       { .fw_name = "xo", .name = "xo" },
--      { .name = "uniphy2_gcc_rx_clk" },
--      { .name = "uniphy2_gcc_tx_clk" },
-+      { .fw_name = "uniphy2_gcc_rx_clk", .name = "uniphy2_gcc_rx_clk" },
-+      { .fw_name = "uniphy2_gcc_tx_clk", .name = "uniphy2_gcc_tx_clk" },
-       { .hw = &ubi32_pll.clkr.hw },
--      { .name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
-@@ -1877,10 +1877,10 @@ static const struct freq_tbl ftbl_nss_po
- static const struct clk_parent_data gcc_xo_uniphy2_tx_rx_ubi32_bias[] = {
-       { .fw_name = "xo", .name = "xo" },
--      { .name = "uniphy2_gcc_tx_clk" },
--      { .name = "uniphy2_gcc_rx_clk" },
-+      { .fw_name = "uniphy2_gcc_tx_clk", .name = "uniphy2_gcc_tx_clk" },
-+      { .fw_name = "uniphy2_gcc_rx_clk", .name = "uniphy2_gcc_rx_clk" },
-       { .hw = &ubi32_pll.clkr.hw },
--      { .name = "bias_pll_cc_clk" },
-+      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
- };
- static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
diff --git a/target/linux/ipq807x/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch b/target/linux/ipq807x/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch
deleted file mode 100644 (file)
index 1f99de0..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 9033c3c86ea0dd35bd2ab957317573b755967298 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Sun, 30 Oct 2022 18:57:03 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: pass XO and sleep clocks to GCC
-
-Pass XO and sleep clocks to the GCC controller so it does not have to
-find them by matching globaly by name.
-
-If not passed directly, driver maintains backwards compatibility by then
-falling back to global lookup.
-
-Since we are here, set cell numbers in decimal instead of hex.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221030175703.1103224-3-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -361,9 +361,11 @@
-               gcc: gcc@1800000 {
-                       compatible = "qcom,gcc-ipq8074";
-                       reg = <0x01800000 0x80000>;
--                      #clock-cells = <0x1>;
-+                      clocks = <&xo>, <&sleep_clk>;
-+                      clock-names = "xo", "sleep_clk";
-+                      #clock-cells = <1>;
-                       #power-domain-cells = <1>;
--                      #reset-cells = <0x1>;
-+                      #reset-cells = <1>;
-               };
-               tcsr_mutex: hwlock@1905000 {
diff --git a/target/linux/ipq807x/patches-6.1/0013-v6.2-arm64-dts-qcom-add-PMP8074-DTSI.patch b/target/linux/ipq807x/patches-6.1/0013-v6.2-arm64-dts-qcom-add-PMP8074-DTSI.patch
deleted file mode 100644 (file)
index cd14642..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-From fb76b808f8628215afebaf0f8af0bde635302590 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:18:14 +0200
-Subject: [PATCH] arm64: dts: qcom: add PMP8074 DTSI
-
-PMP8074 is a companion PMIC to the Qualcomm IPQ8074 series that is
-controlled via SPMI.
-
-Add DTSI for it providing GPIO, regulator, RTC and VADC support.
-
-RTC is disabled by default as there is no built-in battery so it will
-loose time unless board vendor added a battery, so make it optional.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20220818221815.346233-4-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/pmp8074.dtsi | 125 ++++++++++++++++++++++++++
- 1 file changed, 125 insertions(+)
- create mode 100644 arch/arm64/boot/dts/qcom/pmp8074.dtsi
-
---- /dev/null
-+++ b/arch/arm64/boot/dts/qcom/pmp8074.dtsi
-@@ -0,0 +1,125 @@
-+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
-+
-+#include <dt-bindings/spmi/spmi.h>
-+#include <dt-bindings/iio/qcom,spmi-vadc.h>
-+
-+&spmi_bus {
-+      pmic@0 {
-+              compatible = "qcom,pmp8074", "qcom,spmi-pmic";
-+              reg = <0x0 SPMI_USID>;
-+              #address-cells = <1>;
-+              #size-cells = <0>;
-+
-+              pmp8074_adc: adc@3100 {
-+                      compatible = "qcom,spmi-adc-rev2";
-+                      reg = <0x3100>;
-+                      interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+                      #io-channel-cells = <1>;
-+
-+                      ref-gnd@0 {
-+                              reg = <ADC5_REF_GND>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      vref-1p25@1 {
-+                              reg = <ADC5_1P25VREF>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      vref-vadc@2 {
-+                              reg = <ADC5_VREF_VADC>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      pmic_die: die-temp@6 {
-+                              reg = <ADC5_DIE_TEMP>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      xo_therm: xo-temp@76 {
-+                              reg = <ADC5_XO_THERM_100K_PU>;
-+                              qcom,ratiometric;
-+                              qcom,hw-settle-time = <200>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      pa_therm1: thermistor1@77 {
-+                              reg = <ADC5_AMUX_THM1_100K_PU>;
-+                              qcom,ratiometric;
-+                              qcom,hw-settle-time = <200>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      pa_therm2: thermistor2@78 {
-+                              reg = <ADC5_AMUX_THM2_100K_PU>;
-+                              qcom,ratiometric;
-+                              qcom,hw-settle-time = <200>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      pa_therm3: thermistor3@79 {
-+                              reg = <ADC5_AMUX_THM3_100K_PU>;
-+                              qcom,ratiometric;
-+                              qcom,hw-settle-time = <200>;
-+                              qcom,pre-scaling = <1 1>;
-+                      };
-+
-+                      vph-pwr@131 {
-+                              reg = <ADC5_VPH_PWR>;
-+                              qcom,pre-scaling = <1 3>;
-+                      };
-+              };
-+
-+              pmp8074_rtc: rtc@6000 {
-+                      compatible = "qcom,pm8941-rtc";
-+                      reg = <0x6000>;
-+                      reg-names = "rtc", "alarm";
-+                      interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
-+                      allow-set-time;
-+                      status = "disabled";
-+              };
-+
-+              pmp8074_gpios: gpio@c000 {
-+                      compatible = "qcom,pmp8074-gpio", "qcom,spmi-gpio";
-+                      reg = <0xc000>;
-+                      gpio-controller;
-+                      #gpio-cells = <2>;
-+                      gpio-ranges = <&pmp8074_gpios 0 0 12>;
-+                      interrupt-controller;
-+                      #interrupt-cells = <2>;
-+              };
-+      };
-+
-+      pmic@1 {
-+              compatible = "qcom,pmp8074", "qcom,spmi-pmic";
-+              reg = <0x1 SPMI_USID>;
-+
-+              regulators {
-+                      compatible = "qcom,pmp8074-regulators";
-+
-+                      s3: s3 {
-+                              regulator-name = "vdd_s3";
-+                              regulator-min-microvolt = <592000>;
-+                              regulator-max-microvolt = <1064000>;
-+                              regulator-always-on;
-+                              regulator-boot-on;
-+                      };
-+
-+                      s4: s4 {
-+                              regulator-name = "vdd_s4";
-+                              regulator-min-microvolt = <712000>;
-+                              regulator-max-microvolt = <992000>;
-+                              regulator-always-on;
-+                              regulator-boot-on;
-+                      };
-+
-+                      l11: l11 {
-+                              regulator-name = "l11";
-+                              regulator-min-microvolt = <1800000>;
-+                              regulator-max-microvolt = <3300000>;
-+                      };
-+              };
-+      };
-+};
diff --git a/target/linux/ipq807x/patches-6.1/0014-v6.2-arm64-dts-qcom-ipq8074-hk01-add-VQMMC-supply.patch b/target/linux/ipq807x/patches-6.1/0014-v6.2-arm64-dts-qcom-ipq8074-hk01-add-VQMMC-supply.patch
deleted file mode 100644 (file)
index ebd3763..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From 2c394cfc1779886048feca7dc7f4075da5f6328c Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 19 Aug 2022 00:18:15 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq8074-hk01: add VQMMC supply
-
-Since now we have control over the PMP8074 PMIC providing various system
-voltages including L11 which provides the SDIO/eMMC I/O voltage set it as
-the SDHCI VQMMC supply.
-
-This allows SDHCI controller to switch to 1.8V I/O mode and support high
-speed modes like HS200 and HS400.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20220818221815.346233-5-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/ipq8074-hk01.dts | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
-+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
-@@ -3,6 +3,7 @@
- /* Copyright (c) 2017, The Linux Foundation. All rights reserved.
-  */
- #include "ipq8074.dtsi"
-+#include "pmp8074.dtsi"
- / {
-       model = "Qualcomm Technologies, Inc. IPQ8074-HK01";
-@@ -84,6 +85,7 @@
- &sdhc_1 {
-       status = "okay";
-+      vqmmc-supply = <&l11>;
- };
- &qusb_phy_0 {
diff --git a/target/linux/ipq807x/patches-6.1/0015-v6.2-arm64-dts-qcom-hk01-use-GPIO-flags-for-tlmm.patch b/target/linux/ipq807x/patches-6.1/0015-v6.2-arm64-dts-qcom-hk01-use-GPIO-flags-for-tlmm.patch
deleted file mode 100644 (file)
index e08f6d1..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-From 82ceb86227b1fc15c76d5fc691b2bf425f1a63b3 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 7 Nov 2022 10:29:30 +0100
-Subject: [PATCH] arm64: dts: qcom: hk01: use GPIO flags for tlmm
-
-Use respective GPIO_ACTIVE_LOW/HIGH flags for tlmm GPIOs instead of
-harcoding the cell value.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221107092930.33325-3-robimarko@gmail.com
----
- arch/arm64/boot/dts/qcom/ipq8074-hk01.dts | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
-+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
-@@ -4,6 +4,7 @@
-  */
- #include "ipq8074.dtsi"
- #include "pmp8074.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
- / {
-       model = "Qualcomm Technologies, Inc. IPQ8074-HK01";
-@@ -52,12 +53,12 @@
- &pcie0 {
-       status = "okay";
--      perst-gpios = <&tlmm 61 0x1>;
-+      perst-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
- };
- &pcie1 {
-       status = "okay";
--      perst-gpios = <&tlmm 58 0x1>;
-+      perst-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>;
- };
- &pcie_qmp0 {
diff --git a/target/linux/ipq807x/patches-6.1/0016-v6.2-arm64-dts-qcom-ipq8074-Fix-up-comments.patch b/target/linux/ipq807x/patches-6.1/0016-v6.2-arm64-dts-qcom-ipq8074-Fix-up-comments.patch
deleted file mode 100644 (file)
index a8bf249..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-From 1b1c1423ca3e740984aa883512a72c4ea08fbe28 Mon Sep 17 00:00:00 2001
-From: Konrad Dybcio <konrad.dybcio@linaro.org>
-Date: Mon, 7 Nov 2022 15:55:17 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074-*: Fix up comments
-
-Make sure all multiline C-style commends begin with just '/*' with
-the comment text starting on a new line.
-
-Also, fix up some whitespace within comments.
-
-Signed-off-by: Konrad Dybcio <konrad.dybcio@linaro.org>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221107145522.6706-8-konrad.dybcio@linaro.org
----
- arch/arm64/boot/dts/qcom/ipq8074-hk01.dts    |  3 ++-
- arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts |  3 ++-
- arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts |  3 ++-
- arch/arm64/boot/dts/qcom/ipq8074.dtsi        | 12 ++++++------
- 4 files changed, 12 insertions(+), 9 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
-+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0-only
- /dts-v1/;
--/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
-+/*
-+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
-  */
- #include "ipq8074.dtsi"
- #include "pmp8074.dtsi"
---- a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
-+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
-@@ -1,5 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0-only
--/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
-+/*
-+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
-  */
- /dts-v1/;
---- a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
-+++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0-only
- /dts-v1/;
--/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
-+/*
-+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
-  */
- #include "ipq8074-hk10.dtsi"
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -129,10 +129,10 @@
-                       status = "disabled";
-                       usb1_ssphy: phy@58200 {
--                              reg = <0x00058200 0x130>,       /* Tx */
-+                              reg = <0x00058200 0x130>,     /* Tx */
-                                     <0x00058400 0x200>,     /* Rx */
--                                    <0x00058800 0x1f8>,     /* PCS  */
--                                    <0x00058600 0x044>;     /* PCS misc*/
-+                                    <0x00058800 0x1f8>,     /* PCS */
-+                                    <0x00058600 0x044>;     /* PCS misc */
-                               #phy-cells = <0>;
-                               #clock-cells = <0>;
-                               clocks = <&gcc GCC_USB1_PIPE_CLK>;
-@@ -172,10 +172,10 @@
-                       status = "disabled";
-                       usb0_ssphy: phy@78200 {
--                              reg = <0x00078200 0x130>,       /* Tx */
-+                              reg = <0x00078200 0x130>,     /* Tx */
-                                     <0x00078400 0x200>,     /* Rx */
--                                    <0x00078800 0x1f8>,     /* PCS  */
--                                    <0x00078600 0x044>;     /* PCS misc*/
-+                                    <0x00078800 0x1f8>,     /* PCS */
-+                                    <0x00078600 0x044>;     /* PCS misc */
-                               #phy-cells = <0>;
-                               #clock-cells = <0>;
-                               clocks = <&gcc GCC_USB0_PIPE_CLK>;
diff --git a/target/linux/ipq807x/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch b/target/linux/ipq807x/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch
deleted file mode 100644 (file)
index 1ce1140..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-From 5f20690f77878b1ba24ec88df01b92d5131a6780 Mon Sep 17 00:00:00 2001
-From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Date: Tue, 8 Nov 2022 15:23:57 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: align TLMM pin configuration with
- DT schema
-
-DT schema expects TLMM pin configuration nodes to be named with
-'-state' suffix and their optional children with '-pins' suffix.
-
-Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
-Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-Link: https://lore.kernel.org/r/20221108142357.67202-2-krzysztof.kozlowski@linaro.org
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -318,35 +318,35 @@
-                       interrupt-controller;
-                       #interrupt-cells = <0x2>;
--                      serial_4_pins: serial4-pinmux {
-+                      serial_4_pins: serial4-state {
-                               pins = "gpio23", "gpio24";
-                               function = "blsp4_uart1";
-                               drive-strength = <8>;
-                               bias-disable;
-                       };
--                      i2c_0_pins: i2c-0-pinmux {
-+                      i2c_0_pins: i2c-0-state {
-                               pins = "gpio42", "gpio43";
-                               function = "blsp1_i2c";
-                               drive-strength = <8>;
-                               bias-disable;
-                       };
--                      spi_0_pins: spi-0-pins {
-+                      spi_0_pins: spi-0-state {
-                               pins = "gpio38", "gpio39", "gpio40", "gpio41";
-                               function = "blsp0_spi";
-                               drive-strength = <8>;
-                               bias-disable;
-                       };
--                      hsuart_pins: hsuart-pins {
-+                      hsuart_pins: hsuart-state {
-                               pins = "gpio46", "gpio47", "gpio48", "gpio49";
-                               function = "blsp2_uart";
-                               drive-strength = <8>;
-                               bias-disable;
-                       };
--                      qpic_pins: qpic-pins {
-+                      qpic_pins: qpic-state {
-                               pins = "gpio1", "gpio3", "gpio4",
-                                      "gpio5", "gpio6", "gpio7",
-                                      "gpio8", "gpio10", "gpio11",
diff --git a/target/linux/ipq807x/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch b/target/linux/ipq807x/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch
deleted file mode 100644 (file)
index 8719bf7..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From a4748d2850783d36f77ccf2b5fcc86ccf1800ef1 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 16 Nov 2022 22:48:36 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: set Gen2 PCIe pcie max-link-speed
-
-Add the generic 'max-link-speed' property to describe the Gen2 PCIe link
-generation limit.
-This allows the generic DWC code to configure the link speed correctly.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -766,6 +766,7 @@
-                       linux,pci-domain = <1>;
-                       bus-range = <0x00 0xff>;
-                       num-lanes = <1>;
-+                      max-link-speed = <2>;
-                       #address-cells = <3>;
-                       #size-cells = <2>;
diff --git a/target/linux/ipq807x/patches-6.1/0020-v6.3-PCI-qcom-Add-support-for-IPQ8074-Gen3-port.patch b/target/linux/ipq807x/patches-6.1/0020-v6.3-PCI-qcom-Add-support-for-IPQ8074-Gen3-port.patch
deleted file mode 100644 (file)
index 60caee4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From f356132229b18ceef5d5ef9103bbaa9bdeb84c8d Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Fri, 13 Jan 2023 17:44:47 +0100
-Subject: [PATCH] PCI: qcom: Add IPQ8074 Gen3 port support
-
-IPQ8074 has one Gen2 and one Gen3 port, with Gen2 port already supported.
-Add compatible for Gen3 port which uses the same controller as IPQ6018.
-
-Link: https://lore.kernel.org/r/20230113164449.906002-7-robimarko@gmail.com
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
-Signed-off-by: Bjorn Helgaas <bhelgaas@google.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
-@@ -1745,6 +1745,7 @@ static const struct of_device_id qcom_pc
-       { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
-       { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
-       { .compatible = "qcom,pcie-ipq8074", .data = &cfg_2_3_3 },
-+      { .compatible = "qcom,pcie-ipq8074-gen3", .data = &cfg_2_9_0 },
-       { .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 },
-       { .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 },
-       { .compatible = "qcom,pcie-sa8540p", .data = &cfg_1_9_0 },
diff --git a/target/linux/ipq807x/patches-6.1/0021-v6.3-clk-qcom-ipq8074-populate-fw_name-for-usb3phy-s.patch b/target/linux/ipq807x/patches-6.1/0021-v6.3-clk-qcom-ipq8074-populate-fw_name-for-usb3phy-s.patch
deleted file mode 100644 (file)
index eb772be..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 614d31c231c7707322b643f409eeb7e28adc7f8c Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Sun, 8 Jan 2023 13:36:28 +0100
-Subject: [PATCH] clk: qcom: ipq8074: populate fw_name for usb3phy-s
-
-Having only .name populated in parent_data for clocks which are only
-globally searchable currently will not work as the clk core won't copy
-that name if there is no .fw_name present as well.
-
-So, populate .fw_name for usb3phy clocks in parent_data as they were
-missed by me in ("clk: qcom: ipq8074: populate fw_name for all parents").
-
-Fixes: ae55ad32e273 ("clk: qcom: ipq8074: convert to parent data")
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/clk/qcom/gcc-ipq8074.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/qcom/gcc-ipq8074.c
-+++ b/drivers/clk/qcom/gcc-ipq8074.c
-@@ -934,7 +934,7 @@ static struct clk_rcg2 usb0_mock_utmi_cl
- };
- static const struct clk_parent_data gcc_usb3phy_0_cc_pipe_clk_xo[] = {
--      { .name = "usb3phy_0_cc_pipe_clk" },
-+      { .fw_name = "usb3phy_0_cc_pipe_clk", .name = "usb3phy_0_cc_pipe_clk" },
-       { .fw_name = "xo", .name = "xo" },
- };
-@@ -1002,7 +1002,7 @@ static struct clk_rcg2 usb1_mock_utmi_cl
- };
- static const struct clk_parent_data gcc_usb3phy_1_cc_pipe_clk_xo[] = {
--      { .name = "usb3phy_1_cc_pipe_clk" },
-+      { .fw_name = "usb3phy_1_cc_pipe_clk", .name = "usb3phy_1_cc_pipe_clk" },
-       { .fw_name = "xo", .name = "xo" },
- };
diff --git a/target/linux/ipq807x/patches-6.1/0022-v6.5-soc-qcom-mdt_loader-Fix-unconditional-call-to-scm_pa.patch b/target/linux/ipq807x/patches-6.1/0022-v6.5-soc-qcom-mdt_loader-Fix-unconditional-call-to-scm_pa.patch
deleted file mode 100644 (file)
index 72b3827..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-From b8295c6eb276b60f7b75c53a9703ca8fee01eba2 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <ansuelsmth@gmail.com>
-Date: Fri, 26 May 2023 13:09:17 +0200
-Subject: [PATCH] soc: qcom: mdt_loader: Fix unconditional call to
- scm_pas_mem_setup
-
-Commit ebeb20a9cd3f ("soc: qcom: mdt_loader: Always invoke PAS
-mem_setup") dropped the relocate check and made pas_mem_setup run
-unconditionally. The code was later moved with commit f4e526ff7e38
-("soc: qcom: mdt_loader: Extract PAS operations") to
-qcom_mdt_pas_init() effectively losing track of what was actually
-done.
-
-The assumption that PAS mem_setup can be done anytime was effectively
-wrong, with no good reason and this caused regression on some SoC
-that use remoteproc to bringup ath11k. One example is IPQ8074 SoC that
-effectively broke resulting in remoteproc silently die and ath11k not
-working.
-
-On this SoC FW relocate is not enabled and PAS mem_setup was correctly
-skipped in previous kernel version resulting in correct bringup and
-function of remoteproc and ath11k.
-
-To fix the regression, reintroduce the relocate check in
-qcom_mdt_pas_init() and correctly skip PAS mem_setup where relocate is
-not enabled.
-
-Fixes: ebeb20a9cd3f ("soc: qcom: mdt_loader: Always invoke PAS mem_setup")
-Reported-by: Robert Marko <robimarko@gmail.com>
-Tested-by: Robert Marko <robimarko@gmail.com>
-Co-developed-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
-Cc: stable@vger.kernel.org
----
- drivers/soc/qcom/mdt_loader.c | 16 +++++++++++-----
- 1 file changed, 11 insertions(+), 5 deletions(-)
-
---- a/drivers/soc/qcom/mdt_loader.c
-+++ b/drivers/soc/qcom/mdt_loader.c
-@@ -210,6 +210,7 @@ int qcom_mdt_pas_init(struct device *dev
-       const struct elf32_hdr *ehdr;
-       phys_addr_t min_addr = PHYS_ADDR_MAX;
-       phys_addr_t max_addr = 0;
-+      bool relocate = false;
-       size_t metadata_len;
-       void *metadata;
-       int ret;
-@@ -224,6 +225,9 @@ int qcom_mdt_pas_init(struct device *dev
-               if (!mdt_phdr_valid(phdr))
-                       continue;
-+              if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
-+                      relocate = true;
-+
-               if (phdr->p_paddr < min_addr)
-                       min_addr = phdr->p_paddr;
-@@ -246,11 +250,13 @@ int qcom_mdt_pas_init(struct device *dev
-               goto out;
-       }
--      ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
--      if (ret) {
--              /* Unable to set up relocation */
--              dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
--              goto out;
-+      if (relocate) {
-+              ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
-+              if (ret) {
-+                      /* Unable to set up relocation */
-+                      dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
-+                      goto out;
-+              }
-       }
- out:
diff --git a/target/linux/ipq807x/patches-6.1/0100-clk-qcom-clk-rcg2-introduce-support-for-multiple-con.patch b/target/linux/ipq807x/patches-6.1/0100-clk-qcom-clk-rcg2-introduce-support-for-multiple-con.patch
deleted file mode 100644 (file)
index 5713775..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-From 032be4f49dda786fea9e1501212f6cd09a7ded96 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <ansuelsmth@gmail.com>
-Date: Thu, 3 Nov 2022 14:49:43 +0100
-Subject: [PATCH] clk: qcom: clk-rcg2: introduce support for multiple conf for
- same freq
-
-Some RCG frequency can be reached by multiple configuration.
-
-We currently declare multiple configuration for the same frequency but
-that is not supported and always the first configuration will be taken.
-
-These multiple configuration are needed as based on the current parent
-configuration, it may be needed to use a different configuration to
-reach the same frequency.
-
-To handle this introduce 2 new macro, FM and C.
-
-- FM is used to declare an empty freq_tbl with just the frequency and an
-  array of confs to insert all the config for the provided frequency.
-
-- C is used to declare a fre_conf where src, pre_div, m and n are
-  provided.
-
-The driver is changed to handle this special freq_tbl and select the
-correct config by calculating the final rate and deciding based on the
-one that is less different than the requested one.
-
-Tested-by: Robert Marko <robimarko@gmail.com>
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
----
- drivers/clk/qcom/clk-rcg.h  | 14 ++++++-
- drivers/clk/qcom/clk-rcg2.c | 84 +++++++++++++++++++++++++++++++++----
- 2 files changed, 88 insertions(+), 10 deletions(-)
-
---- a/drivers/clk/qcom/clk-rcg.h
-+++ b/drivers/clk/qcom/clk-rcg.h
-@@ -7,7 +7,17 @@
- #include <linux/clk-provider.h>
- #include "clk-regmap.h"
--#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
-+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n), 0, NULL }
-+
-+#define FM(_f, _confs) { .freq = (_f), .confs_num = ARRAY_SIZE(_confs), .confs = (_confs) }
-+#define C(s, h, m, n) { (s), (2 * (h) - 1), (m), (n) }
-+
-+struct freq_conf {
-+      u8 src;
-+      u8 pre_div;
-+      u16 m;
-+      u16 n;
-+};
- struct freq_tbl {
-       unsigned long freq;
-@@ -15,6 +25,8 @@ struct freq_tbl {
-       u8 pre_div;
-       u16 m;
-       u16 n;
-+      int confs_num;
-+      const struct freq_conf *confs;
- };
- /**
---- a/drivers/clk/qcom/clk-rcg2.c
-+++ b/drivers/clk/qcom/clk-rcg2.c
-@@ -209,11 +209,60 @@ clk_rcg2_recalc_rate(struct clk_hw *hw,
-       return __clk_rcg2_recalc_rate(hw, parent_rate, cfg);
- }
-+static void
-+clk_rcg2_select_conf(struct clk_hw *hw, struct freq_tbl *f_tbl,
-+                   const struct freq_tbl *f, unsigned long req_rate)
-+{
-+      unsigned long best_rate = 0, parent_rate, rate;
-+      const struct freq_conf *conf, *best_conf;
-+      struct clk_rcg2 *rcg = to_clk_rcg2(hw);
-+      struct clk_hw *p;
-+      int index, i;
-+
-+      /* Search in each provided config the one that is near the wanted rate */
-+      for (i = 0, conf = f->confs; i < f->confs_num; i++, conf++) {
-+              index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
-+              if (index < 0)
-+                      continue;
-+
-+              p = clk_hw_get_parent_by_index(hw, index);
-+              if (!p)
-+                      continue;
-+
-+              parent_rate =  clk_hw_get_rate(p);
-+              rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div);
-+
-+              if (rate == req_rate) {
-+                      best_conf = conf;
-+                      break;
-+              }
-+
-+              if (abs(req_rate - rate) < abs(best_rate - rate)) {
-+                      best_rate = rate;
-+                      best_conf = conf;
-+              }
-+      }
-+
-+      /*
-+       * Very unlikely.
-+       * Force the first conf if we can't find a correct config.
-+       */
-+      if (unlikely(i == f->confs_num))
-+              best_conf = f->confs;
-+
-+      /* Apply the config */
-+      f_tbl->src = best_conf->src;
-+      f_tbl->pre_div = best_conf->pre_div;
-+      f_tbl->m = best_conf->m;
-+      f_tbl->n = best_conf->n;
-+}
-+
- static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
-                                   struct clk_rate_request *req,
-                                   enum freq_policy policy)
- {
-       unsigned long clk_flags, rate = req->rate;
-+      struct freq_tbl f_tbl;
-       struct clk_hw *p;
-       struct clk_rcg2 *rcg = to_clk_rcg2(hw);
-       int index;
-@@ -232,7 +281,15 @@ static int _freq_tbl_determine_rate(stru
-       if (!f)
-               return -EINVAL;
--      index = qcom_find_src_index(hw, rcg->parent_map, f->src);
-+      f_tbl = *f;
-+      /*
-+       * A single freq may be reached by multiple configuration.
-+       * Try to find the bast one if we have this kind of freq_table.
-+       */
-+      if (f->confs)
-+              clk_rcg2_select_conf(hw, &f_tbl, f, rate);
-+
-+      index = qcom_find_src_index(hw, rcg->parent_map, f_tbl.src);
-       if (index < 0)
-               return index;
-@@ -242,18 +299,18 @@ static int _freq_tbl_determine_rate(stru
-               return -EINVAL;
-       if (clk_flags & CLK_SET_RATE_PARENT) {
--              rate = f->freq;
--              if (f->pre_div) {
-+              rate = f_tbl.freq;
-+              if (f_tbl.pre_div) {
-                       if (!rate)
-                               rate = req->rate;
-                       rate /= 2;
--                      rate *= f->pre_div + 1;
-+                      rate *= f_tbl.pre_div + 1;
-               }
--              if (f->n) {
-+              if (f_tbl.n) {
-                       u64 tmp = rate;
--                      tmp = tmp * f->n;
--                      do_div(tmp, f->m);
-+                      tmp = tmp * f_tbl.n;
-+                      do_div(tmp, f_tbl.m);
-                       rate = tmp;
-               }
-       } else {
-@@ -261,7 +318,7 @@ static int _freq_tbl_determine_rate(stru
-       }
-       req->best_parent_hw = p;
-       req->best_parent_rate = rate;
--      req->rate = f->freq;
-+      req->rate = f_tbl.freq;
-       return 0;
- }
-@@ -357,6 +414,7 @@ static int __clk_rcg2_set_rate(struct cl
- {
-       struct clk_rcg2 *rcg = to_clk_rcg2(hw);
-       const struct freq_tbl *f;
-+      struct freq_tbl f_tbl;
-       switch (policy) {
-       case FLOOR:
-@@ -372,7 +430,15 @@ static int __clk_rcg2_set_rate(struct cl
-       if (!f)
-               return -EINVAL;
--      return clk_rcg2_configure(rcg, f);
-+      f_tbl = *f;
-+      /*
-+       * A single freq may be reached by multiple configuration.
-+       * Try to find the best one if we have this kind of freq_table.
-+       */
-+      if (f->confs)
-+              clk_rcg2_select_conf(hw, &f_tbl, f, rate);
-+
-+      return clk_rcg2_configure(rcg, &f_tbl);
- }
- static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/target/linux/ipq807x/patches-6.1/0101-clk-qcom-gcc-ipq8074-rework-nss_port5-6-clock-to-mul.patch b/target/linux/ipq807x/patches-6.1/0101-clk-qcom-gcc-ipq8074-rework-nss_port5-6-clock-to-mul.patch
deleted file mode 100644 (file)
index 32fb2d9..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-From f778553f296792f4d1e8b3552603ad6116ea3eb3 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <ansuelsmth@gmail.com>
-Date: Thu, 3 Nov 2022 14:49:44 +0100
-Subject: [PATCH] clk: qcom: gcc-ipq8074: rework nss_port5/6 clock to multiple
- conf
-
-Rework nss_port5/6 to use the new multiple configuration implementation
-and correctly fix the clocks for these port under some corner case.
-
-This is particularly relevant for device that have 2.5G or 10G port
-connected to port5 or port 6 on ipq8074. As the parent are shared
-across multiple port it may be required to select the correct
-configuration to accomplish the desired clock. Without this patch such
-port doesn't work in some specific ethernet speed as the clock will be
-set to the wrong frequency as we just select the first configuration for
-the related frequency instead of selecting the best one.
-
-Tested-by: Robert Marko <robimarko@gmail.com> # ipq8074 Qnap QHora-301W
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
----
- drivers/clk/qcom/gcc-ipq8074.c | 64 +++++++++++++++++++++++++---------
- 1 file changed, 48 insertions(+), 16 deletions(-)
-
---- a/drivers/clk/qcom/gcc-ipq8074.c
-+++ b/drivers/clk/qcom/gcc-ipq8074.c
-@@ -1682,13 +1682,21 @@ static struct clk_regmap_div nss_port4_t
-       },
- };
-+static const struct freq_conf ftbl_nss_port5_rx_clk_src_25[] = {
-+      C(P_UNIPHY1_RX, 12.5, 0, 0),
-+      C(P_UNIPHY0_RX, 5, 0, 0),
-+};
-+
-+static const struct freq_conf ftbl_nss_port5_rx_clk_src_125[] = {
-+      C(P_UNIPHY1_RX, 2.5, 0, 0),
-+      C(P_UNIPHY0_RX, 1, 0, 0),
-+};
-+
- static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = {
-       F(19200000, P_XO, 1, 0, 0),
--      F(25000000, P_UNIPHY1_RX, 12.5, 0, 0),
--      F(25000000, P_UNIPHY0_RX, 5, 0, 0),
-+      FM(25000000, ftbl_nss_port5_rx_clk_src_25),
-       F(78125000, P_UNIPHY1_RX, 4, 0, 0),
--      F(125000000, P_UNIPHY1_RX, 2.5, 0, 0),
--      F(125000000, P_UNIPHY0_RX, 1, 0, 0),
-+      FM(125000000, ftbl_nss_port5_rx_clk_src_125),
-       F(156250000, P_UNIPHY1_RX, 2, 0, 0),
-       F(312500000, P_UNIPHY1_RX, 1, 0, 0),
-       { }
-@@ -1744,13 +1752,21 @@ static struct clk_regmap_div nss_port5_r
-       },
- };
-+static struct freq_conf ftbl_nss_port5_tx_clk_src_25[] = {
-+      C(P_UNIPHY1_TX, 12.5, 0, 0),
-+      C(P_UNIPHY0_TX, 5, 0, 0),
-+};
-+
-+static struct freq_conf ftbl_nss_port5_tx_clk_src_125[] = {
-+      C(P_UNIPHY1_TX, 2.5, 0, 0),
-+      C(P_UNIPHY0_TX, 1, 0, 0),
-+};
-+
- static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = {
-       F(19200000, P_XO, 1, 0, 0),
--      F(25000000, P_UNIPHY1_TX, 12.5, 0, 0),
--      F(25000000, P_UNIPHY0_TX, 5, 0, 0),
-+      FM(25000000, ftbl_nss_port5_tx_clk_src_25),
-       F(78125000, P_UNIPHY1_TX, 4, 0, 0),
--      F(125000000, P_UNIPHY1_TX, 2.5, 0, 0),
--      F(125000000, P_UNIPHY0_TX, 1, 0, 0),
-+      FM(125000000, ftbl_nss_port5_tx_clk_src_125),
-       F(156250000, P_UNIPHY1_TX, 2, 0, 0),
-       F(312500000, P_UNIPHY1_TX, 1, 0, 0),
-       { }
-@@ -1806,13 +1822,21 @@ static struct clk_regmap_div nss_port5_t
-       },
- };
-+static struct freq_conf ftbl_nss_port6_rx_clk_src_25[] = {
-+      C(P_UNIPHY2_RX, 5, 0, 0),
-+      C(P_UNIPHY2_RX, 12.5, 0, 0),
-+};
-+
-+static struct freq_conf ftbl_nss_port6_rx_clk_src_125[] = {
-+      C(P_UNIPHY2_RX, 1, 0, 0),
-+      C(P_UNIPHY2_RX, 2.5, 0, 0),
-+};
-+
- static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = {
-       F(19200000, P_XO, 1, 0, 0),
--      F(25000000, P_UNIPHY2_RX, 5, 0, 0),
--      F(25000000, P_UNIPHY2_RX, 12.5, 0, 0),
-+      FM(25000000, ftbl_nss_port6_rx_clk_src_25),
-       F(78125000, P_UNIPHY2_RX, 4, 0, 0),
--      F(125000000, P_UNIPHY2_RX, 1, 0, 0),
--      F(125000000, P_UNIPHY2_RX, 2.5, 0, 0),
-+      FM(125000000, ftbl_nss_port6_rx_clk_src_125),
-       F(156250000, P_UNIPHY2_RX, 2, 0, 0),
-       F(312500000, P_UNIPHY2_RX, 1, 0, 0),
-       { }
-@@ -1863,13 +1887,21 @@ static struct clk_regmap_div nss_port6_r
-       },
- };
-+static struct freq_conf ftbl_nss_port6_tx_clk_src_25[] = {
-+      C(P_UNIPHY2_TX, 5, 0, 0),
-+      C(P_UNIPHY2_TX, 12.5, 0, 0),
-+};
-+
-+static struct freq_conf ftbl_nss_port6_tx_clk_src_125[] = {
-+      C(P_UNIPHY2_TX, 1, 0, 0),
-+      C(P_UNIPHY2_TX, 2.5, 0, 0),
-+};
-+
- static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = {
-       F(19200000, P_XO, 1, 0, 0),
--      F(25000000, P_UNIPHY2_TX, 5, 0, 0),
--      F(25000000, P_UNIPHY2_TX, 12.5, 0, 0),
-+      FM(25000000, ftbl_nss_port6_tx_clk_src_25),
-       F(78125000, P_UNIPHY2_TX, 4, 0, 0),
--      F(125000000, P_UNIPHY2_TX, 1, 0, 0),
--      F(125000000, P_UNIPHY2_TX, 2.5, 0, 0),
-+      FM(125000000, ftbl_nss_port6_tx_clk_src_125),
-       F(156250000, P_UNIPHY2_TX, 2, 0, 0),
-       F(312500000, P_UNIPHY2_TX, 1, 0, 0),
-       { }
diff --git a/target/linux/ipq807x/patches-6.1/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch b/target/linux/ipq807x/patches-6.1/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch
deleted file mode 100644 (file)
index af53c07..0000000
+++ /dev/null
@@ -1,70 +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
-@@ -85,6 +85,26 @@
-               #size-cells = <2>;
-               ranges;
-+              nss@40000000 {
-+                      no-map;
-+                      reg = <0x0 0x40000000 0x0 0x01000000>;
-+              };
-+
-+              tzapp_region: tzapp@4a400000 {
-+                      no-map;
-+                      reg = <0x0 0x4a400000 0x0 0x00200000>;
-+              };
-+
-+              uboot@4a600000 {
-+                      no-map;
-+                      reg = <0x0 0x4a600000 0x0 0x00400000>;
-+              };
-+
-+              sbl@4aa00000 {
-+                      no-map;
-+                      reg = <0x0 0x4aa00000 0x0 0x00100000>;
-+              };
-+
-               smem@4ab00000 {
-                       compatible = "qcom,smem";
-                       reg = <0x0 0x4ab00000 0x0 0x00100000>;
-@@ -97,6 +117,21 @@
-                       no-map;
-                       reg = <0x0 0x4ac00000 0x0 0x00400000>;
-               };
-+
-+              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/ipq807x/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch b/target/linux/ipq807x/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch
deleted file mode 100644 (file)
index 69d4126..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From 8a576b5bc9f0555d1d970cacabcaa24a3b74fa57 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 16 Nov 2022 22:15:01 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: pass QMP PCI PHY PIPE clocks to
- GCC
-
-Pass QMP PCI PHY PIPE clocks to the GCC controller so it does not have to
-find them by matching globaly by name.
-
-If not passed directly, driver maintains backwards compatibility by then
-falling back to global lookup.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -396,8 +396,8 @@
-               gcc: gcc@1800000 {
-                       compatible = "qcom,gcc-ipq8074";
-                       reg = <0x01800000 0x80000>;
--                      clocks = <&xo>, <&sleep_clk>;
--                      clock-names = "xo", "sleep_clk";
-+                      clocks = <&xo>, <&sleep_clk>, <&pcie_phy0>, <&pcie_phy1>;
-+                      clock-names = "xo", "sleep_clk", "pcie0_pipe", "pcie1_pipe";
-                       #clock-cells = <1>;
-                       #power-domain-cells = <1>;
-                       #reset-cells = <1>;
diff --git a/target/linux/ipq807x/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch b/target/linux/ipq807x/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch
deleted file mode 100644 (file)
index 9fefd88..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
-@@ -699,7 +699,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>;
-@@ -811,8 +811,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 142
-@@ -873,8 +872,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 75
diff --git a/target/linux/ipq807x/patches-6.1/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch b/target/linux/ipq807x/patches-6.1/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch
deleted file mode 100644 (file)
index 0a98494..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;
-@@ -151,6 +139,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;
-@@ -240,6 +243,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 */
-@@ -733,6 +742,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)
-               goto free_rproc;
--      if (wcss->version == WCSS_QCS404) {
--              ret = q6v5_wcss_init_clock(wcss);
-+      if (desc->init_clock) {
-+              ret = desc->init_clock(wcss);
-               if (ret)
-                       goto free_rproc;
-+      }
--              ret = q6v5_wcss_init_regulator(wcss);
-+      if (desc->init_regulator) {
-+              ret = desc->init_regulator(wcss);
-               if (ret)
-                       goto free_rproc;
-       }
-@@ -1087,6 +1113,7 @@ static int q6v5_wcss_remove(struct platf
- }
- 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,
-@@ -1096,6 +1123,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/ipq807x/patches-6.1/0113-remoteproc-qcom-Add-secure-PIL-support.patch b/target/linux/ipq807x/patches-6.1/0113-remoteproc-qcom-Add-secure-PIL-support.patch
deleted file mode 100644 (file)
index 0328efc..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/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          3
-+
-+#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_ssr ssr_subdev;
-@@ -152,6 +157,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)
-@@ -251,6 +257,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) {
-@@ -285,6 +300,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");
-@@ -718,6 +734,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);
-@@ -742,6 +767,7 @@ static int q6v5_wcss_stop(struct rproc *
-                       return ret;
-       }
-+pas_done:
-       clk_disable_unprepare(wcss->prng_clk);
-       qcom_q6v5_unprepare(&wcss->q6v5);
-@@ -765,9 +791,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 = 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)
-@@ -1120,6 +1156,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/ipq807x/patches-6.1/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch b/target/linux/ipq807x/patches-6.1/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch
deleted file mode 100644 (file)
index e5c9506..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_ssr ssr_subdev;
-@@ -147,7 +148,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;
-@@ -789,8 +791,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 = 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)
-@@ -1150,7 +1174,8 @@ static int q6v5_wcss_remove(struct platf
- 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,
-@@ -1163,7 +1188,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/ipq807x/patches-6.1/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch b/target/linux/ipq807x/patches-6.1/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch
deleted file mode 100644 (file)
index be63d46..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
-@@ -1179,6 +1179,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/ipq807x/patches-6.1/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch b/target/linux/ipq807x/patches-6.1/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch
deleted file mode 100644 (file)
index f0b7172..0000000
+++ /dev/null
@@ -1,79 +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
-@@ -86,7 +86,7 @@
- #define TCSR_WCSS_CLK_MASK    0x1F
- #define TCSR_WCSS_CLK_ENABLE  0x14
--#define MAX_HALT_REG          3
-+#define MAX_HALT_REG          4
- #define WCNSS_PAS_ID          6
-@@ -154,6 +154,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;
-@@ -875,10 +876,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;
-@@ -929,9 +933,9 @@ static int q6v5_wcss_init_mmio(struct q6
-               return -EINVAL;
-       }
--      wcss->halt_q6 = halt_reg[0];
--      wcss->halt_wcss = halt_reg[1];
--      wcss->halt_nc = halt_reg[2];
-+      wcss->halt_q6 = halt_reg[1];
-+      wcss->halt_wcss = halt_reg[2];
-+      wcss->halt_nc = halt_reg[3];
-       return 0;
- }
-@@ -1179,6 +1183,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,
-@@ -1193,6 +1198,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/ipq807x/patches-6.1/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch b/target/linux/ipq807x/patches-6.1/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/ipq807x/patches-6.1/0118-clk-qcom-Add-WCSSAON-reset.patch b/target/linux/ipq807x/patches-6.1/0118-clk-qcom-Add-WCSSAON-reset.patch
deleted file mode 100644 (file)
index 7915317..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
-@@ -4717,6 +4717,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/ipq807x/patches-6.1/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch b/target/linux/ipq807x/patches-6.1/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch
deleted file mode 100644 (file)
index 8674522..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
-@@ -161,6 +161,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)
-@@ -1150,6 +1151,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)
-               goto free_rproc;
-@@ -1188,6 +1190,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 = {
-@@ -1204,6 +1207,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/ipq807x/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch b/target/linux/ipq807x/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch
deleted file mode 100644 (file)
index e37ba37..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
-@@ -140,6 +140,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 {
-               #address-cells = <0x1>;
-               #size-cells = <0x1>;
-@@ -409,6 +435,11 @@
-                       #hwlock-cells = <1>;
-               };
-+              tcsr_q6: syscon@1945000 {
-+                      compatible = "syscon";
-+                      reg = <0x01945000 0xe000>;
-+              };
-+
-               spmi_bus: spmi@200f000 {
-                       compatible = "qcom,spmi-pmic-arb";
-                       reg = <0x0200f000 0x001000>,
-@@ -913,6 +944,56 @@
-                                     "axi_s_sticky";
-                       status = "disabled";
-               };
-+
-+              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/ipq807x/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch b/target/linux/ipq807x/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch
deleted file mode 100644 (file)
index bd5410c..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
-@@ -994,6 +994,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/ipq807x/patches-6.1/0122-arm64-dts-ipq8074-add-CPU-clock.patch b/target/linux/ipq807x/patches-6.1/0122-arm64-dts-ipq8074-add-CPU-clock.patch
deleted file mode 100644 (file)
index a3c5f34..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/ipq807x/patches-6.1/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch b/target/linux/ipq807x/patches-6.1/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch
deleted file mode 100644 (file)
index 3520b38..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/ipq807x/patches-6.1/0128-cpufreq-qcom-nvmem-add-support-for-IPQ8074.patch b/target/linux/ipq807x/patches-6.1/0128-cpufreq-qcom-nvmem-add-support-for-IPQ8074.patch
deleted file mode 100644 (file)
index 09abbfa..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-From 11592aa862e67f4477dee7e94d5c8244d893de1b Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Sat, 31 Dec 2022 13:03:41 +0100
-Subject: [PATCH] cpufreq: qcom-nvmem: add support for IPQ8074
-
-IPQ8074 comes in 2 families:
-* IPQ8070A/IPQ8071A (Acorn) up to 1.4GHz
-* IPQ8072A/IPQ8074A/IPQ8076A/IPQ8078A (Hawkeye) up to 2.2GHz
-
-So, in order to be able to share one OPP table lets add support for IPQ8074
-family based of SMEM SoC ID-s as speedbin fuse is always 0 on IPQ8074.
-
-IPQ8074 compatible is blacklisted from DT platdev as the cpufreq device
-will get created by NVMEM CPUFreq driver.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
-Changes in v2:
-* Print an error if SMEM ID is not part of the IPQ8074 family
-and restrict the speed to Acorn variant (1.4GHz)
----
- drivers/cpufreq/cpufreq-dt-platdev.c |  1 +
- drivers/cpufreq/qcom-cpufreq-nvmem.c | 43 ++++++++++++++++++++++++++++
- 2 files changed, 44 insertions(+)
-
---- a/drivers/cpufreq/cpufreq-dt-platdev.c
-+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
-@@ -164,6 +164,7 @@ static const struct of_device_id blockli
-       { .compatible = "ti,omap3", },
-       { .compatible = "qcom,ipq8064", },
-+      { .compatible = "qcom,ipq8074", },
-       { .compatible = "qcom,apq8064", },
-       { .compatible = "qcom,msm8974", },
-       { .compatible = "qcom,msm8960", },
---- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
-+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
-@@ -31,6 +31,9 @@
- #include <dt-bindings/arm/qcom,ids.h>
-+#define IPQ8074_HAWKEYE_VERSION               BIT(0)
-+#define IPQ8074_ACORN_VERSION         BIT(1)
-+
- struct qcom_cpufreq_drv;
- struct qcom_cpufreq_match_data {
-@@ -204,6 +207,41 @@ len_error:
-       return ret;
- }
-+static int qcom_cpufreq_ipq8074_name_version(struct device *cpu_dev,
-+                                           struct nvmem_cell *speedbin_nvmem,
-+                                           char **pvs_name,
-+                                           struct qcom_cpufreq_drv *drv)
-+{
-+      u32 msm_id;
-+      int ret;
-+      *pvs_name = NULL;
-+
-+      ret = qcom_smem_get_soc_id(&msm_id);
-+      if (ret)
-+              return ret;
-+
-+      switch (msm_id) {
-+      case QCOM_ID_IPQ8070A:
-+      case QCOM_ID_IPQ8071A:
-+              drv->versions = IPQ8074_ACORN_VERSION;
-+              break;
-+      case QCOM_ID_IPQ8072A:
-+      case QCOM_ID_IPQ8074A:
-+      case QCOM_ID_IPQ8076A:
-+      case QCOM_ID_IPQ8078A:
-+              drv->versions = IPQ8074_HAWKEYE_VERSION;
-+              break;
-+      default:
-+              dev_err(cpu_dev,
-+                      "SoC ID %u is not part of IPQ8074 family, limiting to 1.4GHz!\n",
-+                      msm_id);
-+              drv->versions = IPQ8074_ACORN_VERSION;
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
- static const struct qcom_cpufreq_match_data match_data_kryo = {
-       .get_version = qcom_cpufreq_kryo_name_version,
- };
-@@ -218,6 +256,10 @@ static const struct qcom_cpufreq_match_d
-       .genpd_names = qcs404_genpd_names,
- };
-+static const struct qcom_cpufreq_match_data match_data_ipq8074 = {
-+      .get_version = qcom_cpufreq_ipq8074_name_version,
-+};
-+
- static int qcom_cpufreq_probe(struct platform_device *pdev)
- {
-       struct qcom_cpufreq_drv *drv;
-@@ -363,6 +405,7 @@ static const struct of_device_id qcom_cp
-       { .compatible = "qcom,msm8996", .data = &match_data_kryo },
-       { .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
-       { .compatible = "qcom,ipq8064", .data = &match_data_krait },
-+      { .compatible = "qcom,ipq8074", .data = &match_data_ipq8074 },
-       { .compatible = "qcom,apq8064", .data = &match_data_krait },
-       { .compatible = "qcom,msm8974", .data = &match_data_krait },
-       { .compatible = "qcom,msm8960", .data = &match_data_krait },
diff --git a/target/linux/ipq807x/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch b/target/linux/ipq807x/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch
deleted file mode 100644 (file)
index 3a6f4e9..0000000
+++ /dev/null
@@ -1,128 +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
-@@ -340,6 +340,113 @@
-                       status = "disabled";
-               };
-+              qfprom: efuse@a4000 {
-+                      compatible = "qcom,ipq8074-qfprom", "qcom,qfprom";
-+                      reg = <0x000a4000 0x1000>;
-+                      #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 {
-                       compatible = "qcom,prng-ee";
-                       reg = <0x000e3000 0x1000>;
diff --git a/target/linux/ipq807x/patches-6.1/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch b/target/linux/ipq807x/patches-6.1/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch
deleted file mode 100644 (file)
index 9c1e7b9..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 {
-@@ -83,6 +87,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/ipq807x/patches-6.1/0132-mmc-core-disable-TRIM-on-Micron-MTFC4GACAJCN-1M.patch b/target/linux/ipq807x/patches-6.1/0132-mmc-core-disable-TRIM-on-Micron-MTFC4GACAJCN-1M.patch
deleted file mode 100644 (file)
index 8c2e59e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From f5aaf6669bd4f1f0218dd7fd5dc90941267ad860 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Tue, 30 May 2023 23:26:30 +0200
-Subject: [PATCH] mmc: core: disable TRIM on Micron MTFC4GACAJCN-1M
-
-It seems that Micron MTFC4GACAJCN-1M despite advertising TRIM support does
-not work when the core is trying to use REQ_OP_WRITE_ZEROES.
-
-We are seeing the following errors in OpenWrt under 6.1 on Qnap Qhora 301W
-that we did not previously have and tracked it down to REQ_OP_WRITE_ZEROES:
-[   18.085950] I/O error, dev loop0, sector 596 op 0x9:(WRITE_ZEROES) flags 0x800 phys_seg 0 prio class 2
-
-Disabling TRIM makes the error go away, so lets add a quirk for this eMMC
-to disable TRIM.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/mmc/core/quirks.h | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/mmc/core/quirks.h
-+++ b/drivers/mmc/core/quirks.h
-@@ -101,6 +101,13 @@ static const struct mmc_fixup __maybe_un
-                 MMC_QUIRK_TRIM_BROKEN),
-       /*
-+       * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
-+       * support being used to offload WRITE_ZEROES.
-+       */
-+      MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
-+                MMC_QUIRK_TRIM_BROKEN),
-+
-+      /*
-        * Some SD cards reports discard support while they don't
-        */
-       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
diff --git a/target/linux/ipq807x/patches-6.1/0133-mmc-core-disable-TRIM-on-Kingston-EMMC04G-M627.patch b/target/linux/ipq807x/patches-6.1/0133-mmc-core-disable-TRIM-on-Kingston-EMMC04G-M627.patch
deleted file mode 100644 (file)
index ac7af52..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 26c97b6fb7d291f55e0e4a410d266d1355118ed9 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 31 May 2023 20:21:26 +0200
-Subject: [PATCH] mmc: core: disable TRIM on Kingston EMMC04G-M627
-
-It seems that Kingston EMMC04G-M627 despite advertising TRIM support does
-not work when the core is trying to use REQ_OP_WRITE_ZEROES.
-
-We are seeing I/O errors in OpenWrt under 6.1 on Zyxel NBG7815 that we did
-not previously have and tracked it down to REQ_OP_WRITE_ZEROES.
-
-Trying to use fstrim seems to also throw errors like:
-[93010.835112] I/O error, dev loop0, sector 16902 op 0x3:(DISCARD) flags 0x800 phys_seg 1 prio class 2
-
-Disabling TRIM makes the error go away, so lets add a quirk for this eMMC
-to disable TRIM.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/mmc/core/quirks.h | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/mmc/core/quirks.h
-+++ b/drivers/mmc/core/quirks.h
-@@ -108,6 +108,13 @@ static const struct mmc_fixup __maybe_un
-                 MMC_QUIRK_TRIM_BROKEN),
-       /*
-+       * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
-+       * support being used to offload WRITE_ZEROES.
-+       */
-+      MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
-+                MMC_QUIRK_TRIM_BROKEN),
-+
-+      /*
-        * Some SD cards reports discard support while they don't
-        */
-       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
diff --git a/target/linux/ipq807x/patches-6.1/0134-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch b/target/linux/ipq807x/patches-6.1/0134-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch
deleted file mode 100644 (file)
index 6231d8a..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-From 145bbf2b88990ef3ff00ee541bb7662008683c16 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Wed, 7 Jun 2023 20:26:26 +0200
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add critical thermal trips
-
-According to bindings, thermal zones must have associated trips as well.
-Since we currently dont have CPUFreq support and thus no passive cooling
-lets start by defining critical trips to protect the devices against
-severe overheating.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 96 +++++++++++++++++++++++++++
- 1 file changed, 96 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -1293,6 +1293,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 4>;
-+
-+                      trips {
-+                              nss-top-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               nss0-thermal {
-@@ -1300,6 +1308,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 5>;
-+
-+                      trips {
-+                              nss-0-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               nss1-thermal {
-@@ -1307,6 +1323,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 6>;
-+
-+                      trips {
-+                              nss-1-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               wcss-phya0-thermal {
-@@ -1314,6 +1338,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 7>;
-+
-+                      trips {
-+                              wcss-phya0-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               wcss-phya1-thermal {
-@@ -1321,6 +1353,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 8>;
-+
-+                      trips {
-+                              wcss-phya1-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               cpu0_thermal: cpu0-thermal {
-@@ -1328,6 +1368,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 9>;
-+
-+                      trips {
-+                              cpu0-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               cpu1_thermal: cpu1-thermal {
-@@ -1335,6 +1383,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 10>;
-+
-+                      trips {
-+                              cpu1-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               cpu2_thermal: cpu2-thermal {
-@@ -1342,6 +1398,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 11>;
-+
-+                      trips {
-+                              cpu2-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               cpu3_thermal: cpu3-thermal {
-@@ -1349,6 +1413,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 12>;
-+
-+                      trips {
-+                              cpu3-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               cluster_thermal: cluster-thermal {
-@@ -1356,6 +1428,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 13>;
-+
-+                      trips {
-+                              cluster-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               wcss-phyb0-thermal {
-@@ -1363,6 +1443,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 14>;
-+
-+                      trips {
-+                              wcss-phyb0-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-               wcss-phyb1-thermal {
-@@ -1370,6 +1458,14 @@
-                       polling-delay = <1000>;
-                       thermal-sensors = <&tsens 15>;
-+
-+                      trips {
-+                              wcss-phyb1-crit {
-+                                      temperature = <110000>;
-+                                      hysteresis = <1000>;
-+                                      type = "critical";
-+                              };
-+                      };
-               };
-       };
- };
diff --git a/target/linux/ipq807x/patches-6.1/0900-power-Add-Qualcomm-APM.patch b/target/linux/ipq807x/patches-6.1/0900-power-Add-Qualcomm-APM.patch
deleted file mode 100644 (file)
index 2e5c72b..0000000
+++ /dev/null
@@ -1,1047 +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
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0-only
- source "drivers/power/reset/Kconfig"
- source "drivers/power/supply/Kconfig"
-+source "drivers/power/qcom/Kconfig"
---- a/drivers/power/Makefile
-+++ b/drivers/power/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0-only
- obj-$(CONFIG_POWER_RESET)     += reset/
- 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,944 @@
-+/*
-+ * 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_find_property(dev->of_node, "qcom,apm-post-halt-delay", NULL)) {
-+              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_find_property(dev->of_node, "qcom,apm-halt-clk-delay", NULL)) {
-+              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_find_property(dev->of_node, "qcom,apm-resume-clk-delay", NULL)) {
-+              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_find_property(dev->of_node, "qcom,apm-sel-switch-delay", NULL)) {
-+              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 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;
-+      const struct of_device_id *match;
-+      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;
-+      }
-+
-+      match = of_match_device(msm_apm_match_table, dev);
-+      if (!match)
-+              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)match->data;
-+      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 int 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);
-+      }
-+
-+      return 0;
-+}
-+
-+static struct platform_driver msm_apm_driver = {
-+      .driver         = {
-+              .name           = MSM_APM_DRIVER_NAME,
-+              .of_match_table = msm_apm_match_table,
-+              .owner          = THIS_MODULE,
-+      },
-+      .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/ipq807x/patches-6.1/0901-regulator-add-Qualcomm-CPR-regulators.patch b/target/linux/ipq807x/patches-6.1/0901-regulator-add-Qualcomm-CPR-regulators.patch
deleted file mode 100644 (file)
index 9b9f715..0000000
+++ /dev/null
@@ -1,12144 +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
-@@ -1524,4 +1524,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
-@@ -110,6 +110,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,695 @@
-+/*
-+ * 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 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 of_device_id *match;
-+      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;
-+
-+      match = of_match_device(cpr3_regulator_match_table, &pdev->dev);
-+      if (!match)
-+              return -ENODEV;
-+
-+      cpr_data = (struct cpr3_reg_data *)match->data;
-+      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 int cpr3_npu_regulator_remove(struct platform_device *pdev)
-+{
-+      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
-+
-+      return 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,
-+              .owner          = THIS_MODULE,
-+      },
-+      .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;
-+      struct cpr4_reg_data    *cpr4_regulator_data;
-+      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,2750 @@
-+/*
-+ * 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 <soc/qcom/socinfo.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
-+
-+/**
-+ * 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_find_property(vreg->of_node, "qcom,system-voltage", NULL)) {
-+              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_find_property(vreg->of_node,
-+                              "qcom,allow-aging-voltage-adjustment", NULL)) {
-+              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_find_property(vreg->of_node,
-+                     "qcom,allow-aging-open-loop-voltage-adjustment", NULL)) {
-+              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_find_property(vreg->of_node, "qcom,cpr-aging-derate",
-+                                      NULL)) {
-+                      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_find_property(node, "qcom,cpr-panic-reg-name-list", NULL)) {
-+              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_find_property(ctrl->dev->of_node, "clock-names", NULL)) {
-+              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_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
-+              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_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
-+              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_find_property(vreg->of_node, prop, NULL))
-+              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)
-+              strlcpy(prop_name, prop_name_v2, sizeof(prop_name_v2));
-+      else
-+              strlcpy(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 {
-+              strlcpy(prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
-+                      sizeof(prop_str));
-+      }
-+
-+      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
-+              /* 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)
-+              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
-+                      sizeof(prop_str));
-+      else
-+              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold",
-+                      sizeof(prop_str));
-+
-+      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
-+              /* 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 {
-+              strlcpy(req_prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
-+                      sizeof(req_prop_str));
-+      }
-+
-+      if (soc_version_major > 1)
-+              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
-+                      sizeof(prop_str));
-+      else
-+              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold",
-+                      sizeof(prop_str));
-+
-+      if (!of_find_property(vreg->of_node, req_prop_str, NULL)) {
-+              /* No adjustment required. */
-+              cpr3_info(vreg, "Cold temperature adjustment not required.\n");
-+              return 0;
-+      }
-+
-+      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
-+              /* 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 {
-+              strlcpy(prop_str, "qcom,cpr-open-loop-voltage-fuse-adjustment",
-+                      sizeof(prop_str));
-+      }
-+
-+      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
-+              /* 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_find_property(vreg->of_node,
-+                      "qcom,cpr-open-loop-voltage-adjustment", NULL)) {
-+              /* 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_find_property(vreg->of_node,
-+                      "qcom,cpr-open-loop-voltage-min-diff", NULL)) {
-+              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_find_property(vreg->of_node, volt_adj, NULL)
-+          && !of_find_property(vreg->of_node, volt_fuse_adj, NULL)
-+          && !vreg->aging_allowed) {
-+              /* No adjustment required. */
-+              return 0;
-+      } else if (!of_find_property(vreg->of_node, ro_scaling, NULL)) {
-+              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_find_property(vreg->of_node, volt_fuse_adj, NULL)) {
-+              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_find_property(vreg->of_node, volt_adj, NULL)) {
-+              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_find_property(node, "qcom,apm-ctrl", NULL)) {
-+              /* 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_find_property(node, use_corner_band ?
-+                           "qcom,corner-band-allow-temp-adjustment"
-+                           : "qcom,corner-allow-temp-adjustment", NULL)) {
-+              if (!ctrl->allow_temp_adj) {
-+                      cpr3_err(ctrl, "Temperature adjustment configurations missing\n");
-+                      return -EINVAL;
-+              }
-+
-+              vreg->allow_temp_adj = true;
-+      }
-+
-+      if (of_find_property(node, use_corner_band ?
-+                           "qcom,corner-band-allow-core-count-adjustment"
-+                           : "qcom,corner-allow-core-count-adjustment",
-+                           NULL)) {
-+              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_find_property(vreg->of_node,
-+              "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) {
-+              /* 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_find_property(vreg->of_node,
-+              "qcom,cpr-closed-loop-voltage-adjustment", NULL);
-+      fused_adjustment = of_find_property(vreg->of_node,
-+              "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL);
-+
-+      if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
-+              /* No adjustment required. */
-+              return 0;
-+      } else if (!of_find_property(vreg->of_node,
-+                      "qcom,cpr-ro-scaling-factor", NULL)) {
-+              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,1819 @@
-+/*
-+ * 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_find_property(node, "qcom,cpr-ro-sel", NULL)) {
-+              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_find_property(node,
-+                      "qcom,cpr-misc-fuse-voltage-adjustment",
-+                      NULL)) {
-+                      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_find_property(vreg->of_node,
-+              "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) {
-+              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_find_property(vreg->of_node, "qcom,allow-boost", NULL)) {
-+              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_find_property(vreg->of_node,
-+                      "qcom,cpr-boost-voltage-fuse-adjustment", NULL)) {
-+              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_find_property(vreg->of_node,
-+                              "qcom,cpr-boost-temp-adjustment", NULL)) {
-+              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_find_property(ctrl->dev->of_node, "vdd-limit-supply", NULL)) {
-+              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 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 of_device_id *match;
-+      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;
-+
-+      match = of_match_device(cpr4_regulator_match_table, &pdev->dev);
-+      if (!match)
-+              return -ENODEV;
-+
-+      cpr_data = (struct cpr4_reg_data *)match->data;
-+      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 int cpr4_apss_regulator_remove(struct platform_device *pdev)
-+{
-+      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
-+
-+      return 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,
-+              .owner          = THIS_MODULE,
-+      },
-+      .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);
---- /dev/null
-+++ b/include/soc/qcom/socinfo.h
-@@ -0,0 +1,463 @@
-+/* Copyright (c) 2009-2014, 2016, 2020, 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 _ARCH_ARM_MACH_MSM_SOCINFO_H_
-+#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
-+
-+#include <linux/of.h>
-+
-+#define CPU_IPQ8074 323
-+#define CPU_IPQ8072 342
-+#define CPU_IPQ8076 343
-+#define CPU_IPQ8078 344
-+#define CPU_IPQ8070 375
-+#define CPU_IPQ8071 376
-+
-+#define CPU_IPQ8072A 389
-+#define CPU_IPQ8074A 390
-+#define CPU_IPQ8076A 391
-+#define CPU_IPQ8078A 392
-+#define CPU_IPQ8070A 395
-+#define CPU_IPQ8071A 396
-+
-+#define CPU_IPQ8172  397
-+#define CPU_IPQ8173  398
-+#define CPU_IPQ8174  399
-+
-+#define CPU_IPQ6018 402
-+#define CPU_IPQ6028 403
-+#define CPU_IPQ6000 421
-+#define CPU_IPQ6010 422
-+#define CPU_IPQ6005 453
-+
-+#define CPU_IPQ5010 446
-+#define CPU_IPQ5018 447
-+#define CPU_IPQ5028 448
-+#define CPU_IPQ5000 503
-+#define CPU_IPQ0509 504
-+#define CPU_IPQ0518 505
-+
-+#define CPU_IPQ9514 510
-+#define CPU_IPQ9554 512
-+#define CPU_IPQ9570 513
-+#define CPU_IPQ9574 514
-+#define CPU_IPQ9550 511
-+#define CPU_IPQ9510 521
-+
-+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);
-+}
-+
-+static inline int read_ipq_cpu_type(void)
-+{
-+      const int *prop;
-+      prop = of_get_property(of_find_node_by_path("/"), "cpu_type", NULL);
-+      /*
-+       * Return Default CPU type if "cpu_type" property is not found in DTSI
-+       */
-+      if (!prop)
-+              return CPU_IPQ8074;
-+
-+      return le32_to_cpu(*prop);
-+}
-+
-+static inline int cpu_is_ipq8070(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8070;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8071(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8071;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8072(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8072;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8074(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8074;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8076(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8076;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8078(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8078;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8072a(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8072A;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8074a(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8074A;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8076a(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8076A;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8078a(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8078A;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8070a(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8070A;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8071a(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8071A;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8172(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8172;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8173(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8173;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq8174(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ8174;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq6018(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ6018;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq6028(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ6028;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq6000(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ6000;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq6010(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ6010;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq6005(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ6005;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq5010(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ5010;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq5018(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ5018;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq5028(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ5028;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq5000(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ5000;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq0509(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ0509;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq0518(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ0518;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq9514(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ9514;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq9554(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ9554;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq9570(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ9570;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq9574(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ9574;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq9550(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ9550;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq9510(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return read_ipq_cpu_type() == CPU_IPQ9510;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq807x(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq8072() || cpu_is_ipq8074() ||
-+              cpu_is_ipq8076() || cpu_is_ipq8078() ||
-+              cpu_is_ipq8070() || cpu_is_ipq8071() ||
-+              cpu_is_ipq8072a() || cpu_is_ipq8074a() ||
-+              cpu_is_ipq8076a() || cpu_is_ipq8078a() ||
-+              cpu_is_ipq8070a() || cpu_is_ipq8071a() ||
-+              cpu_is_ipq8172() || cpu_is_ipq8173() ||
-+              cpu_is_ipq8174();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq60xx(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq6018() || cpu_is_ipq6028() ||
-+              cpu_is_ipq6000() || cpu_is_ipq6010() ||
-+              cpu_is_ipq6005();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq50xx(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq5010() || cpu_is_ipq5018() ||
-+              cpu_is_ipq5028() || cpu_is_ipq5000() ||
-+              cpu_is_ipq0509() || cpu_is_ipq0518();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_ipq95xx(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq9514() || cpu_is_ipq9554() ||
-+              cpu_is_ipq9570() || cpu_is_ipq9574() ||
-+              cpu_is_ipq9550() || cpu_is_ipq9510();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_nss_crypto_enabled(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq807x() || cpu_is_ipq60xx() ||
-+              cpu_is_ipq50xx() || cpu_is_ipq9570() ||
-+              cpu_is_ipq9550() || cpu_is_ipq9574() ||
-+              cpu_is_ipq9554();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_internal_wifi_enabled(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq807x() || cpu_is_ipq60xx() ||
-+              cpu_is_ipq50xx() || cpu_is_ipq9514() ||
-+              cpu_is_ipq9554() || cpu_is_ipq9574();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_uniphy1_enabled(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq807x() || cpu_is_ipq60xx() ||
-+              cpu_is_ipq9554() || cpu_is_ipq9570() ||
-+              cpu_is_ipq9574() || cpu_is_ipq9550();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int cpu_is_uniphy2_enabled(void)
-+{
-+#ifdef CONFIG_ARCH_QCOM
-+      return  cpu_is_ipq807x() || cpu_is_ipq9570() ||
-+              cpu_is_ipq9574();
-+#else
-+      return 0;
-+#endif
-+}
-+
-+#endif /* _ARCH_ARM_MACH_MSM_SOCINFO_H_ */
diff --git a/target/linux/ipq807x/patches-6.1/0902-arm64-dts-ipq8074-add-label-to-clocks.patch b/target/linux/ipq807x/patches-6.1/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/Makefile b/target/linux/qualcommax/Makefile
new file mode 100644 (file)
index 0000000..c6b74e0
--- /dev/null
@@ -0,0 +1,22 @@
+include $(TOPDIR)/rules.mk
+
+ARCH:=aarch64
+BOARD:=qualcommax
+BOARDNAME:=Qualcomm Atheros 802.11ax WiSoC-s
+FEATURES:=squashfs ramdisk fpu nand rtc emmc
+KERNELNAME:=Image dtbs
+CPU_TYPE:=cortex-a53
+SUBTARGETS:=generic
+
+KERNEL_PATCHVER:=6.1
+
+include $(INCLUDE_DIR)/target.mk
+DEFAULT_PACKAGES += \
+       kmod-usb3 kmod-usb-dwc3 kmod-usb-dwc3-qcom \
+       kmod-leds-gpio kmod-gpio-button-hotplug \
+       kmod-phy-aquantia kmod-qca-nss-dp \
+       ath11k-firmware-ipq8074 kmod-ath11k-ahb \
+       wpad-basic-mbedtls uboot-envtools \
+       e2fsprogs kmod-fs-ext4 losetup
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/qualcommax/base-files/etc/board.d/01_leds b/target/linux/qualcommax/base-files/etc/board.d/01_leds
new file mode 100644 (file)
index 0000000..a89b4c1
--- /dev/null
@@ -0,0 +1,33 @@
+
+. /lib/functions/uci-defaults.sh
+
+board_config_update
+
+board=$(board_name)
+
+case "$board" in
+edgecore,eap102)
+       ucidef_set_led_netdev "wan" "WAN" "green:wanpoe" "wan"
+       ;;
+netgear,wax218)
+       ucidef_set_led_netdev "lan" "LAN" "blue:lan" "lan"
+       ucidef_set_led_wlan "wlan5g" "WIFI 5GHz" "blue:wlan5g" "phy0radio"
+       ucidef_set_led_wlan "wlan2g" "WIFI 2.4GHz" "blue:wlan2g" "phy1radio"
+       ;;
+redmi,ax6|\
+xiaomi,ax3600)
+       ucidef_set_led_netdev "wan" "WAN" "blue:network" "wan"
+       ;;
+qnap,301w)
+       ucidef_set_led_netdev "lan1" "LAN1" "green:lan1" "lan1"
+       ucidef_set_led_netdev "lan2" "LAN2" "green:lan2" "lan2"
+       ucidef_set_led_netdev "lan3" "LAN3" "green:lan3" "lan3"
+       ucidef_set_led_netdev "lan4" "LAN4" "green:lan4" "lan4"
+       ucidef_set_led_netdev "10G_1" "10G_1" "green:10g_1" "10g-1"
+       ucidef_set_led_netdev "10G_2" "10G_2" "green:10g_2" "10g-2"
+       ;;
+esac
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/qualcommax/base-files/etc/board.d/02_network b/target/linux/qualcommax/base-files/etc/board.d/02_network
new file mode 100644 (file)
index 0000000..8175a99
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2015 The Linux Foundation. All rights reserved.
+# Copyright (c) 2011-2015 OpenWrt.org
+#
+
+. /lib/functions/uci-defaults.sh
+. /lib/functions/system.sh
+
+ipq807x_setup_interfaces()
+{
+       local board="$1"
+
+       case "$board" in
+       buffalo,wxr-5950ax12|\
+       dynalink,dl-wrx36|\
+       xiaomi,ax9000)
+               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan"
+               ;;
+       edgecore,eap102)
+               ucidef_set_interfaces_lan_wan "lan" "wan"
+               ;;
+       edimax,cax1800)
+               ucidef_set_interfaces_lan_wan "lan"
+               ;;
+       netgear,wax218)
+               ucidef_set_interface_lan "lan" "dhcp"
+               ;;
+       prpl,haze)
+               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
+               ;;
+       qnap,301w)
+               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4 10g-2" "10g-1"
+               ;;
+       compex,wpq873|\
+       redmi,ax6|\
+       xiaomi,ax3600)
+               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
+               ;;
+       zyxel,nbg7815)
+               ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4 10g" "wan"
+               ;;
+       *)
+               echo "Unsupported hardware. Network interfaces not initialized"
+               ;;
+       esac
+}
+
+board_config_update
+board=$(board_name)
+ipq807x_setup_interfaces $board
+board_config_flush
+
+exit 0
diff --git a/target/linux/qualcommax/base-files/etc/hotplug.d/firmware/11-ath11k-caldata b/target/linux/qualcommax/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
new file mode 100644 (file)
index 0000000..f931557
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+[ -e /lib/firmware/$FIRMWARE ] && exit 0
+
+. /lib/functions/caldata.sh
+
+board=$(board_name)
+
+case "$FIRMWARE" in
+"ath11k/IPQ8074/hw2.0/cal-ahb-c000000.wifi.bin")
+       case "$board" in
+       buffalo,wxr-5950ax12|\
+       compex,wpq873|\
+       edgecore,eap102|\
+       edimax,cax1800|\
+       dynalink,dl-wrx36|\
+       netgear,wax218|\
+       qnap,301w|\
+       redmi,ax6|\
+       xiaomi,ax3600|\
+       xiaomi,ax9000|\
+       zyxel,nbg7815)
+               caldata_extract "0:art" 0x1000 0x20000
+               ;;
+       prpl,haze)
+                caldata_extract_mmc "0:ART" 0x1000 0x20000
+               ;;
+       esac
+       ;;
+"ath11k/QCN9074/hw1.0/cal-pci-0000:01:00.0.bin"|\
+"ath11k/QCN9074/hw1.0/cal-pci-0001:01:00.0.bin")
+       case "$board" in
+       prpl,haze)
+                caldata_extract_mmc "0:ART" 0x26800 0x20000
+               ;;
+       xiaomi,ax9000)
+               caldata_extract "0:art" 0x26800 0x20000
+               ;;
+       esac
+       ;;
+*)
+       exit 1
+       ;;
+esac
diff --git a/target/linux/qualcommax/base-files/etc/init.d/bootcount b/target/linux/qualcommax/base-files/etc/init.d/bootcount
new file mode 100755 (executable)
index 0000000..6917446
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh /etc/rc.common
+
+START=99
+
+boot() {
+       case $(board_name) in
+       edgecore,eap102)
+               fw_setenv upgrade_available 0
+               # Unset changed flag after sysupgrade complete
+               fw_setenv changed
+       ;;
+       esac
+}
diff --git a/target/linux/qualcommax/base-files/lib/upgrade/buffalo.sh b/target/linux/qualcommax/base-files/lib/upgrade/buffalo.sh
new file mode 100644 (file)
index 0000000..d0ed258
--- /dev/null
@@ -0,0 +1,55 @@
+. /lib/functions.sh
+
+# Prepare UBI devices for OpenWrt installation
+# - rootfs (mtd22)
+#   - remove "ubi_rootfs" volume (rootfs on stock)
+#   - remove "fw_hash" volume (firmware hash)
+# - user_property (mtd24)
+#   - remove "user_property_ubi" volume (user configuration)
+#   - remove "extra_property" volume (gzipped syslog)
+buffalo_upgrade_prepare() {
+       local ubi_rootdev ubi_propdev
+
+       if ! ubi_rootdev="$(nand_attach_ubi rootfs)" || \
+          ! ubi_propdev="$(nand_attach_ubi user_property)"; then
+               echo "failed to attach UBI volume \"rootfs\" or \"user_property\", rebooting..."
+               reboot -f
+       fi
+
+       ubirmvol /dev/$ubi_rootdev -N ubi_rootfs &> /dev/null || true
+       ubirmvol /dev/$ubi_rootdev -N fw_hash &> /dev/null || true
+
+       ubirmvol /dev/$ubi_propdev -N user_property_ubi &> /dev/null || true
+       ubirmvol /dev/$ubi_propdev -N extra_property &> /dev/null || true
+}
+
+# Re-create small dummy ubi_rootfs volume and update
+# fw_hash volume to pass the checking by U-Boot
+# - rootfs (mtd22)
+#   - re-create "ubi_rootfs" volume
+#   - re-create and update "fw_hash" volume
+# - rootfs_recover (mtd23)
+#   - update "fw_hash" volume
+buffalo_upgrade_optvol() {
+       local ubi_rootdev ubi_rcvrdev
+       local hashvol_root hashvol_rcvr
+
+       if ! ubi_rootdev="$(nand_attach_ubi rootfs)" || \
+          ! ubi_rcvrdev="$(nand_attach_ubi rootfs_recover)"; then
+               echo "failed to attach UBI volume \"rootfs\" or \"rootfs_recover\", rebooting..."
+               reboot -f
+       fi
+
+       ubimkvol /dev/$ubi_rootdev -N ubi_rootfs -S 1
+       ubimkvol /dev/$ubi_rootdev -N fw_hash -S 1 -t static
+
+       if ! hashvol_root="$(nand_find_volume $ubi_rootdev fw_hash)" || \
+          ! hashvol_rcvr="$(nand_find_volume $ubi_rcvrdev fw_hash)"; then
+               echo "\"fw_hash\" volume in \"rootfs\" or \"rootfs_recover\" not found, rebooting..."
+               reboot -f
+       fi
+
+       echo -n "00000000000000000000000000000000" > /tmp/dummyhash.txt
+       ubiupdatevol /dev/$hashvol_root /tmp/dummyhash.txt
+       ubiupdatevol /dev/$hashvol_rcvr /tmp/dummyhash.txt
+}
diff --git a/target/linux/qualcommax/base-files/lib/upgrade/mmc.sh b/target/linux/qualcommax/base-files/lib/upgrade/mmc.sh
new file mode 100644 (file)
index 0000000..dac9ddd
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# Copyright (C) 2016 lede-project.org
+#
+
+# this can be used as a generic mmc upgrade script
+# just add a device entry in platform.sh, 
+# define "kernelname" and "rootfsname" and call mmc_do_upgrade
+# after the kernel and rootfs flash a loopdev (as overlay) is 
+# setup on top of the rootfs partition
+# for the proper function a padded rootfs image is needed, basically 
+# append "pad-to 64k" to the image definition
+# this is based on the ipq806x zyxel.sh mmc upgrade
+
+. /lib/functions.sh
+
+mmc_do_upgrade() {
+       local tar_file="$1"
+       local rootfs=
+       local kernel=
+
+                       [ -z "$kernel" ] && kernel=$(find_mmc_part ${kernelname})
+                       [ -z "$rootfs" ] && rootfs=$(find_mmc_part ${rootfsname})
+
+                       [ -z "$kernel" ] && echo "Upgrade failed: kernel partition not found! Rebooting..." && reboot -f
+                       [ -z "$rootfs" ] && echo "Upgrade failed: rootfs partition not found! Rebooting..." && reboot -f
+
+       mmc_do_flash $tar_file $kernel $rootfs
+
+       return 0
+}
+
+mmc_do_flash() {
+       local tar_file=$1
+       local kernel=$2
+       local rootfs=$3
+       
+       # keep sure its unbound
+       losetup --detach-all || {
+               echo Failed to detach all loop devices. Skip this try.
+               reboot -f
+       }
+
+       # use the first found directory in the tar archive
+       local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
+       board_dir=${board_dir%/}
+
+       echo "flashing kernel to $kernel"
+       tar xf $tar_file ${board_dir}/kernel -O >$kernel
+
+       echo "flashing rootfs to ${rootfs}"
+       tar xf $tar_file ${board_dir}/root -O >"${rootfs}"
+
+       # a padded rootfs is needed for overlay fs creation
+       local offset=$(tar xf $tar_file ${board_dir}/root -O | wc -c)
+       [ $offset -lt 65536 ] && {
+               echo Wrong size for rootfs: $offset
+               sleep 10
+               reboot -f
+       }
+
+       # Mount loop for rootfs_data
+       local loopdev="$(losetup -f)"
+       losetup -o $offset $loopdev $rootfs || {
+               echo "Failed to mount looped rootfs_data."
+               sleep 10
+               reboot -f
+       }
+
+       echo "Format new rootfs_data at position ${offset}."
+       mkfs.ext4 -F -L rootfs_data $loopdev
+       mkdir /tmp/new_root
+       mount -t ext4 $loopdev /tmp/new_root && {
+               echo "Saving config to rootfs_data at position ${offset}."
+               cp -v "$UPGRADE_BACKUP" "/tmp/new_root/$BACKUP_FILE"
+               umount /tmp/new_root
+       }
+
+       # Cleanup
+       losetup -d $loopdev >/dev/null 2>&1
+       sync
+       umount -a
+       reboot -f
+}
diff --git a/target/linux/qualcommax/base-files/lib/upgrade/platform.sh b/target/linux/qualcommax/base-files/lib/upgrade/platform.sh
new file mode 100644 (file)
index 0000000..458eb16
--- /dev/null
@@ -0,0 +1,117 @@
+PART_NAME=firmware
+REQUIRE_IMAGE_METADATA=1
+
+RAMFS_COPY_BIN='fw_printenv fw_setenv head'
+RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
+
+xiaomi_initramfs_prepare() {
+       # Wipe UBI if running initramfs
+       [ "$(rootfs_type)" = "tmpfs" ] || return 0
+
+       local rootfs_mtdnum="$( find_mtd_index rootfs )"
+       if [ ! "$rootfs_mtdnum" ]; then
+               echo "unable to find mtd partition rootfs"
+               return 1
+       fi
+
+       local kern_mtdnum="$( find_mtd_index ubi_kernel )"
+       if [ ! "$kern_mtdnum" ]; then
+               echo "unable to find mtd partition ubi_kernel"
+               return 1
+       fi
+
+       ubidetach -m "$rootfs_mtdnum"
+       ubiformat /dev/mtd$rootfs_mtdnum -y
+
+       ubidetach -m "$kern_mtdnum"
+       ubiformat /dev/mtd$kern_mtdnum -y
+}
+
+platform_check_image() {
+       return 0;
+}
+
+platform_pre_upgrade() {
+       case "$(board_name)" in
+       redmi,ax6|\
+       xiaomi,ax3600|\
+       xiaomi,ax9000)
+               xiaomi_initramfs_prepare
+               ;;
+       esac
+}
+
+platform_do_upgrade() {
+       case "$(board_name)" in
+       buffalo,wxr-5950ax12)
+               CI_KERN_UBIPART="rootfs"
+               CI_ROOT_UBIPART="user_property"
+               buffalo_upgrade_prepare
+               nand_do_flash_file "$1" || nand_do_upgrade_failed
+               nand_do_restore_config || nand_do_upgrade_failed
+               buffalo_upgrade_optvol
+               ;;
+       dynalink,dl-wrx36)
+               nand_do_upgrade "$1"
+               ;;
+       edgecore,eap102)
+               active="$(fw_printenv -n active)"
+               if [ "$active" -eq "1" ]; then
+                       CI_UBIPART="rootfs2"
+               else
+                       CI_UBIPART="rootfs1"
+               fi
+               # force altbootcmd which handles partition change in u-boot
+               fw_setenv bootcount 3
+               fw_setenv upgrade_available 1
+               nand_do_upgrade "$1"
+               ;;
+       compex,wpq873|\
+       edimax,cax1800|\
+       netgear,wax218)
+               nand_do_upgrade "$1"
+               ;;
+       prpl,haze|\
+       qnap,301w)
+               kernelname="0:HLOS"
+               rootfsname="rootfs"
+               mmc_do_upgrade "$1"
+               ;;
+       zyxel,nbg7815)
+               local config_mtdnum="$(find_mtd_index 0:bootconfig)"
+               [ -z "$config_mtdnum" ] && reboot
+               part_num="$(hexdump -e '1/1 "%01x|"' -n 1 -s 168 -C /dev/mtd$config_mtdnum | cut -f 1 -d "|" | head -n1)"
+               if [ "$part_num" -eq "0" ]; then
+                       kernelname="0:HLOS"
+                       rootfsname="rootfs"
+                       mmc_do_upgrade "$1"
+               else
+                       kernelname="0:HLOS_1"
+                       rootfsname="rootfs_1"
+                       mmc_do_upgrade "$1"
+               fi
+               ;;
+       redmi,ax6|\
+       xiaomi,ax3600|\
+       xiaomi,ax9000)
+               # Make sure that UART is enabled
+               fw_setenv boot_wait on
+               fw_setenv uart_en 1
+
+               # Enforce single partition.
+               fw_setenv flag_boot_rootfs 0
+               fw_setenv flag_last_success 0
+               fw_setenv flag_boot_success 1
+               fw_setenv flag_try_sys1_failed 8
+               fw_setenv flag_try_sys2_failed 8
+
+               # Kernel and rootfs are placed in 2 different UBI
+               CI_KERN_UBIPART="ubi_kernel"
+               CI_ROOT_UBIPART="rootfs"
+               nand_do_upgrade "$1"
+               ;;
+       *)
+               default_do_upgrade "$1"
+               ;;
+       esac
+}
diff --git a/target/linux/qualcommax/config-6.1 b/target/linux/qualcommax/config-6.1
new file mode 100644 (file)
index 0000000..2fa4aa3
--- /dev/null
@@ -0,0 +1,560 @@
+CONFIG_64BIT=y
+# CONFIG_APQ_GCC_8084 is not set
+# CONFIG_APQ_MMCC_8084 is not set
+CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
+CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_FORCE_MAX_ORDER=11
+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_NR_GPIO=0
+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_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_PAGE_SHIFT=12
+CONFIG_ARM64_PA_BITS=48
+CONFIG_ARM64_PA_BITS_48=y
+CONFIG_ARM64_PTR_AUTH=y
+CONFIG_ARM64_PTR_AUTH_KERNEL=y
+CONFIG_ARM64_SME=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_GIC_V3_ITS_PCI=y
+# CONFIG_ARM_MHU_V2 is not set
+CONFIG_ARM_PSCI_CPUIDLE=y
+CONFIG_ARM_PSCI_CPUIDLE_DOMAIN=y
+CONFIG_ARM_PSCI_FW=y
+# CONFIG_ARM_QCOM_CPUFREQ_HW is not set
+CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y
+CONFIG_AUDIT_ARCH_COMPAT_GENERIC=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_CAVIUM_TX2_ERRATUM_219=y
+CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
+CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
+CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
+CONFIG_CC_NO_ARRAY_BOUNDS=y
+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_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_QCE=y
+CONFIG_CRYPTO_DEV_QCE_AEAD=y
+# CONFIG_CRYPTO_DEV_QCE_ENABLE_AEAD is not set
+CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL=y
+# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set
+# CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER is not set
+CONFIG_CRYPTO_DEV_QCE_SHA=y
+CONFIG_CRYPTO_DEV_QCE_SKCIPHER=y
+CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512
+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_SHA1=y
+CONFIG_CRYPTO_LIB_SHA256=y
+CONFIG_CRYPTO_LIB_UTILS=y
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
+# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_ZSTD=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEV_COREDUMP=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_DIRECT_REMAP=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DTC=y
+CONFIG_DT_IDLE_GENPD=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_FUJITSU_ERRATUM_010001=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_GCC11_NO_ARRAY_BOUNDS=y
+CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS=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_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_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=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_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HWSPINLOCK=y
+CONFIG_HWSPINLOCK_QCOM=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_IPQ_APSS_6018=y
+CONFIG_IPQ_APSS_PLL=y
+# CONFIG_IPQ_GCC_4019 is not set
+# CONFIG_IPQ_GCC_6018 is not set
+# CONFIG_IPQ_GCC_806X is not set
+CONFIG_IPQ_GCC_8074=y
+# CONFIG_IPQ_LCC_806X 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_WORK=y
+# CONFIG_KPSS_XCC is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=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_MDM_GCC_9615 is not set
+# CONFIG_MDM_LCC_9615 is not set
+CONFIG_MEMFD_CREATE=y
+# CONFIG_MFD_HI6421_SPMI is not set
+# CONFIG_MFD_QCOM_RPM is not set
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+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_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MODULES_USE_ELF_RELA=y
+# CONFIG_MSM_GCC_8660 is not set
+# CONFIG_MSM_GCC_8909 is not set
+# CONFIG_MSM_GCC_8916 is not set
+# CONFIG_MSM_GCC_8939 is not set
+# CONFIG_MSM_GCC_8960 is not set
+# CONFIG_MSM_GCC_8974 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_LCC_8960 is not set
+# CONFIG_MSM_MMCC_8960 is not set
+# CONFIG_MSM_MMCC_8974 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_FLOW_LIMIT=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NLS=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_NVIDIA_CARMEL_CNP_ERRATUM=y
+CONFIG_NVMEM=y
+CONFIG_NVMEM_QCOM_QFPROM=y
+# CONFIG_NVMEM_SPMI_SDAM is not set
+CONFIG_NVMEM_SYSFS=y
+CONFIG_NVMEM_U_BOOT_ENV=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_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=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_IPQ4019_USB is not set
+# CONFIG_PHY_QCOM_IPQ806X_SATA is not set
+# CONFIG_PHY_QCOM_IPQ806X_USB is not set
+# CONFIG_PHY_QCOM_PCIE2 is not set
+CONFIG_PHY_QCOM_QMP=y
+CONFIG_PHY_QCOM_QUSB2=y
+# 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_IPQ6018 is not set
+CONFIG_PINCTRL_IPQ8074=y
+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_SPMI_PMIC=y
+# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
+# CONFIG_PINCTRL_QCS404 is not set
+# CONFIG_PINCTRL_SC7180 is not set
+# CONFIG_PINCTRL_SC8280XP is not set
+# CONFIG_PINCTRL_SDM660 is not set
+# CONFIG_PINCTRL_SDM845 is not set
+# CONFIG_PINCTRL_SM6350 is not set
+# CONFIG_PINCTRL_SM6375 is not set
+# CONFIG_PINCTRL_SM8150 is not set
+# CONFIG_PINCTRL_SM8250 is not set
+# CONFIG_PINCTRL_SM8450 is not set
+CONFIG_PM=y
+# CONFIG_PM8916_WATCHDOG is not set
+CONFIG_PM_CLK=y
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_OPP=y
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_MSM is not set
+# CONFIG_POWER_RESET_QCOM_PON is not set
+CONFIG_POWER_SUPPLY=y
+CONFIG_PREEMPT_NONE_BUILD=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+# CONFIG_QCM_DISPCC_2290 is not set
+# CONFIG_QCM_GCC_2290 is not set
+# CONFIG_QCOM_A53PLL is not set
+# CONFIG_QCOM_AOSS_QMP is not set
+CONFIG_QCOM_APCS_IPC=y
+CONFIG_QCOM_APM=y
+# 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_CLK_APCS_SDX55 is not set
+# CONFIG_QCOM_COINCELL is not set
+# CONFIG_QCOM_COMMAND_DB is not set
+# CONFIG_QCOM_CPR is not set
+# CONFIG_QCOM_EBI2 is not set
+# CONFIG_QCOM_FASTRPC is not set
+CONFIG_QCOM_GDSC=y
+# 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_IPCC is not set
+# CONFIG_QCOM_LLCC is not set
+CONFIG_QCOM_MDT_LOADER=y
+# CONFIG_QCOM_MPM is not set
+# 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_MSS is not set
+# CONFIG_QCOM_Q6V5_PAS is not set
+CONFIG_QCOM_Q6V5_WCSS=y
+# CONFIG_QCOM_RMTFS_MEM is not set
+# CONFIG_QCOM_RPMH is not set
+CONFIG_QCOM_RPROC_COMMON=y
+CONFIG_QCOM_SCM=y
+# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set
+# 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_SPMI_ADC5=y
+# CONFIG_QCOM_SPMI_RRADC is not set
+# CONFIG_QCOM_STATS is not set
+# CONFIG_QCOM_SYSMON is not set
+CONFIG_QCOM_TSENS=y
+CONFIG_QCOM_VADC_COMMON=y
+# 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_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_SPMI=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_CPR3=y
+# CONFIG_REGULATOR_CPR3_NPU is not set
+CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_QCOM_LABIBB is not set
+CONFIG_REGULATOR_QCOM_SPMI=y
+# CONFIG_REGULATOR_QCOM_USB_VBUS is not set
+# 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_DRV_PM8XXX=y
+CONFIG_RTC_I2C_AND_SPI=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+# CONFIG_SCHED_CORE is not set
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_THERMAL_PRESSURE=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_DISPCC_7180 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_LPASS_CORECC_7180 is not set
+# CONFIG_SC_LPASS_CORECC_7280 is not set
+# CONFIG_SC_MSS_7180 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_65 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_SMP=y
+# CONFIG_SM_CAMCC_8450 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_GPUCC_6350 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_VIDEOCC_8150 is not set
+# CONFIG_SM_VIDEOCC_8250 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_QUP=y
+CONFIG_SPMI=y
+# CONFIG_SPMI_HISI3670 is not set
+CONFIG_SPMI_MSM_PMIC_ARB=y
+# CONFIG_SPMI_PMIC_CLKDIV is not set
+CONFIG_SRCU=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_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_VIRTIO=y
+CONFIG_VIRTIO_ANCHOR=y
+# CONFIG_VIRTIO_BLK 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/files/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts
new file mode 100644 (file)
index 0000000..2c9cbd5
--- /dev/null
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2021, Dirk Buchwalder <buchwalder@posteo.de> */
+
+/dts-v1/;
+
+#include "ipq8074-512m.dtsi"
+#include "ipq8074-ac-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "Edimax CAX1800";
+       compatible = "edimax,cax1800", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               led-boot = &led_system_red;
+               led-failsafe = &led_system_red;
+               led-running = &led_system_green;
+               led-upgrade = &led_system_red;
+               /* Aliases as required by u-boot to patch MAC addresses */
+               ethernet0 = &dp5;
+               label-mac-device = &dp5;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " root=/dev/ubiblock0_1";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 32 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_system_red: system-red {
+                       label = "red:system";
+                       gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_system_green: system-green {
+                       label = "green:system";
+                       gpios = <&tlmm 26 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_system_blue: system-blue {
+                       label = "blue:system";
+                       gpios = <&tlmm 27 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "rootfs";
+                               reg = <0x0000000 0x3400000>;
+                       };
+               };
+       };
+};
+
+&blsp1_spi1 {
+       pinctrl-0 = <&spi_0_pins>;
+       pinctrl-names = "default";
+       cs-select = <0>;
+       status = "ok";
+
+       m25p80@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+               use-default-sizes;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "0:sbl1";
+                               reg = <0x0 0x50000>;
+                               read-only;
+                       };
+
+                       partition@50000 {
+                               label = "0:mibib";
+                               reg = <0x50000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@60000 {
+                               label = "0:bootconfig";
+                               reg = <0x60000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@80000 {
+                               label = "0:bootconfig1";
+                               reg = <0x80000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@a0000 {
+                               label = "0:qsee";
+                               reg = <0xa0000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@220000 {
+                               label = "0:qsee_1";
+                               reg = <0x220000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@3a0000 {
+                               label = "0:devcfg";
+                               reg = <0x3a0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3b0000 {
+                               label = "0:devcfg_1";
+                               reg = <0x3b0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3c0000 {
+                               label = "0:apdp";
+                               reg = <0x3c0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3d0000 {
+                               label = "0:apdp_1";
+                               reg = <0x3d0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3e0000 {
+                               label = "0:rpm";
+                               reg = <0x3e0000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@420000 {
+                               label = "0:rpm_1";
+                               reg = <0x420000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@460000 {
+                               label = "0:cdt";
+                               reg = <0x460000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@470000 {
+                               label = "0:cdt_1";
+                               reg = <0x470000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@480000 {
+                               label = "0:appsblenv";
+                               reg = <0x480000 0x10000>;
+                       };
+
+                       partition@490000 {
+                               label = "0:appsbl";
+                               reg = <0x490000 0xa0000>;
+                               read-only;
+                       };
+
+                       partition@530000 {
+                               label = "0:appsbl_1";
+                               reg = <0x530000 0xa0000>;
+                               read-only;
+                       };
+
+                       partition@5d0000 {
+                               label = "0:art";
+                               reg = <0x5d0000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@610000 {
+                               label = "0:ethphyfw";
+                               reg = <0x610000 0x80000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       qca8075: ethernet-phy@4 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <4>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x1e>; /* lan port bitmap */
+       switch_wan_bmp = <0x20>; /* wan port bitmap */
+       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0>;
+               };
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+               port@4 {
+                       port_id = <5>;
+                       phy_address = <4>;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp5 {
+       status = "okay";
+       phy-handle = <&qca8075>;
+       label = "lan";
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Edimax-CAX1800";
+       qcom,ath11k-fw-memory-mode = <1>;
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dts
new file mode 100644 (file)
index 0000000..f3e82e2
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2021, Robert Marko <robimarko@gmail.com> */
+
+/dts-v1/;
+
+#include "ipq8071-ax3600.dtsi"
+
+/ {
+       model = "Xiaomi AX3600";
+       compatible = "xiaomi,ax3600", "qcom,ipq8074";
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_system_blue: system-blue {
+                       label = "blue:system";
+                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_system_yellow: system-yellow {
+                       label = "yellow:system";
+                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
+               };
+
+               network-yellow {
+                       label = "yellow:network";
+                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
+               };
+
+               network-blue {
+                       label = "blue:network";
+                       gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+               };
+
+               aiot {
+                       label = "blue:aiot";
+                       gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy0tpt";
+               };
+       };
+};
+
+&pcie_qmp0 {
+       status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 52 GPIO_ACTIVE_HIGH>;
+
+       bridge@0,0 {
+               reg = <0x00000000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+
+               wifi0: wifi@1,0 {
+                       status = "okay";
+
+                       compatible = "qcom,ath10k";
+                       reg = <0x00010000 0 0 0 0>;
+
+                       qcom,ath10k-calibration-variant = "Xiaomi-AX3600";
+                       nvmem-cell-names = "calibration";
+                       nvmem-cells = <&caldata_qca9889>;
+               };
+       };
+};
+
+&wifi {
+       qcom,ath11k-calibration-variant = "Xiaomi-AX3600";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi
new file mode 100644 (file)
index 0000000..c18cef5
--- /dev/null
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2021, Robert Marko <robimarko@gmail.com> */
+
+#include "ipq8074-512m.dtsi"
+#include "ipq8074-ac-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       aliases {
+               serial0 = &blsp1_uart5;
+               led-boot = &led_system_yellow;
+               led-failsafe = &led_system_yellow;
+               led-running = &led_system_blue;
+               led-upgrade = &led_system_yellow;
+               label-mac-device = &dp2;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " root=/dev/ubiblock0_0";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       /*
+        * Bootloader will find the NAND DT node by the compatible and
+        * then "fixup" it by adding the partitions from the SMEM table
+        * using the legacy bindings thus making it impossible for us
+        * to change the partition table or utilize NVMEM for calibration.
+        * So add a dummy partitions node that bootloader will populate
+        * and set it as disabled so the kernel ignores it instead of
+        * printing warnings due to the broken way bootloader adds the
+        * partitions.
+        */
+       partitions {
+               status = "disabled";
+       };
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "0:sbl1";
+                               reg = <0x0 0x100000>;
+                               read-only;
+                       };
+
+                       partition@100000 {
+                               label = "0:mibib";
+                               reg = <0x100000 0x100000>;
+                               read-only;
+                       };
+
+                       partition@200000 {
+                               label = "0:qsee";
+                               reg = <0x200000 0x300000>;
+                               read-only;
+                       };
+
+                       partition@500000 {
+                               label = "0:devcfg";
+                               reg = <0x500000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@580000 {
+                               label = "0:rpm";
+                               reg = <0x580000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@600000 {
+                               label = "0:cdt";
+                               reg = <0x600000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@680000 {
+                               label = "0:appsblenv";
+                               reg = <0x680000 0x80000>;
+                       };
+
+                       partition@700000 {
+                               label = "0:appsbl";
+                               reg = <0x700000 0x100000>;
+                               read-only;
+                       };
+
+                       partition@800000 {
+                               label = "0:art";
+                               reg = <0x800000 0x80000>;
+                               read-only;
+
+                               compatible = "nvmem-cells";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               macaddr_dp2: macaddr@6 {
+                                       reg = <0x6 0x6>;
+                               };
+
+                               macaddr_dp3: macaddr@c {
+                                       reg = <0xc 0x6>;
+                               };
+
+                               macaddr_dp4: macaddr@12 {
+                                       reg = <0x12 0x6>;
+                               };
+
+                               macaddr_dp5: macaddr@18 {
+                                       reg = <0x18 0x6>;
+                               };
+
+                               caldata_qca9889: caldata@4d000 {
+                                       reg = <0x33000 0x844>;
+                               };
+                       };
+
+                       partition@880000 {
+                               label = "bdata";
+                               reg = <0x880000 0x80000>;
+                       };
+
+                       partition@900000 {
+                               /* This is crash + crash_syslog parts combined */
+                               label = "pstore";
+                               reg = <0x900000 0x100000>;
+                       };
+
+                       /* Make the first rootfs a dedicated ubi partition for kernel */
+                       partition@a00000 {
+                               label = "ubi_kernel";
+                               reg = <0xa00000 0x23c0000>;
+                       };
+
+                       /* Place the real rootfs in the original second rootfs and
+                        * expand it to the end of the nand
+                        */
+                       rootfs: partition@2dc0000 {
+                               label = "rootfs";
+                               reg = <0x2dc0000 0xd240000>;
+                       };
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       qca8075_1: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+
+       qca8075_2: ethernet-phy@2 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <2>;
+       };
+
+       qca8075_3: ethernet-phy@3 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <3>;
+       };
+
+       qca8075_4: ethernet-phy@4 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <4>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x1e>; /* lan port bitmap */
+       switch_wan_bmp = <0x20>; /* wan port bitmap */
+       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0>;
+               };
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+               port@4 {
+                       port_id = <5>;
+                       phy_address = <4>;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_1>;
+       label = "wan";
+       nvmem-cells = <&macaddr_dp2>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_2>;
+       label = "lan1";
+       nvmem-cells = <&macaddr_dp3>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_3>;
+       label = "lan2";
+       nvmem-cells = <&macaddr_dp4>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp5 {
+       status = "okay";
+       phy-handle = <&qca8075_4>;
+       label = "lan3";
+       nvmem-cells = <&macaddr_dp5>;
+       nvmem-cell-names = "mac-address";
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-fw-memory-mode = <1>;
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax6.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-ax6.dts
new file mode 100644 (file)
index 0000000..6611a8f
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2021, Zhijun You <hujy652@gmail.com> */
+
+/dts-v1/;
+
+#include "ipq8071-ax3600.dtsi"
+
+/ {
+       model = "Redmi AX6";
+       compatible = "redmi,ax6", "qcom,ipq8074";
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_system_blue: system-blue {
+                       label = "blue:system";
+                       gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_system_yellow: system-yellow {
+                       label = "yellow:system";
+                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
+               };
+
+               network-blue {
+                       label = "blue:network";
+                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
+               };
+
+               network-yellow {
+                       label = "yellow:network";
+                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+/* AX6 can both have NAND of 256MiB or 128MiB.
+ * To be on the safe side, assume 128MiB of NAND.
+ */
+&rootfs {
+       reg = <0x2dc0000 0x5220000>;
+};
+
+&wifi {
+       qcom,ath11k-calibration-variant = "Redmi-AX6";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-eap102.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8071-eap102.dts
new file mode 100644 (file)
index 0000000..357b636
--- /dev/null
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2022, Matthew Hagan <mnhagan88@gmail.com> */
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-ac-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "Edgecore EAP102";
+       compatible = "edgecore,eap102", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               serial1 = &blsp1_uart3;
+               led-boot = &led_system_green;
+               led-failsafe = &led_system_green;
+               led-running = &led_system_green;
+               led-upgrade = &led_system_green;
+               /* Aliases as required by u-boot to patch MAC addresses */
+               ethernet0 = &dp5;
+               ethernet1 = &dp6;
+               label-mac-device = &dp5;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " root=/dev/ubiblock0_1";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+               pinctrl-0 = <&button_pins>;
+               pinctrl-names = "default";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 66 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_wanpoe {
+                       label = "green:wanpoe";
+                       gpios = <&tlmm 46 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_wlan2g {
+                       label = "green:wlan2g";
+                       gpio = <&tlmm 47 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy1radio";
+               };
+
+               led_wlan5g {
+                       label = "green:wlan5g";
+                       gpio = <&tlmm 48 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy0radio";
+               };
+
+               led_system_green: led_system {
+                       label = "green:power";
+                       gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       button_pins: button_pins {
+               reset_button {
+                       pins = "gpio66";
+                       function = "gpio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_spi1 {
+       status = "okay";
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "0:sbl1";
+                               reg = <0x0 0x50000>;
+                               read-only;
+                       };
+
+                       partition@50000 {
+                               label = "0:mibib";
+                               reg = <0x50000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@60000 {
+                               label = "0:bootconfig";
+                               reg = <0x60000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@80000 {
+                               label = "0:bootconfig1";
+                               reg = <0x80000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@a0000 {
+                               label = "0:qsee";
+                               reg = <0xa0000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@220000 {
+                               label = "0:qsee_1";
+                               reg = <0x220000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@3a0000 {
+                               label = "0:devcfg";
+                               reg = <0x3a0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3b0000 {
+                               label = "0:devcfg_1";
+                               reg = <0x3b0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3c0000 {
+                               label = "0:apdp";
+                               reg = <0x3c0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3d0000 {
+                               label = "0:apdp_1";
+                               reg = <0x3d0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3e0000 {
+                               label = "0:rpm";
+                               reg = <0x3e0000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@420000 {
+                               label = "0:rpm_1";
+                               reg = <0x420000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@460000 {
+                               label = "0:cdt";
+                               reg = <0x460000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@470000 {
+                               label = "0:cdt_1";
+                               reg = <0x470000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@480000 {
+                               label = "0:appsblenv";
+                               reg = <0x480000 0x10000>;
+                       };
+
+                       partition@490000 {
+                               label = "0:appsbl";
+                               reg = <0x490000 0xc0000>;
+                               read-only;
+                       };
+
+                       partition@550000 {
+                               label = "0:appsbl_1";
+                               reg = <0x530000 0xc0000>;
+                               read-only;
+                       };
+
+                       partition@610000 {
+                               label = "0:art";
+                               reg = <0x610000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@650000 {
+                               label = "0:ethphyfw";
+                               reg = <0x650000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@6d0000 {
+                               label = "0:product_info";
+                               reg = <0x6d0000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@750000 {
+                               label = "priv_data1";
+                               reg = <0x750000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@760000 {
+                               label = "priv_data2";
+                               reg = <0x760000 0x10000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&blsp1_uart3 {
+       status = "okay";
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <8>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "rootfs1";
+                               reg = <0x0000000 0x3400000>;
+                       };
+
+                       partition@3400000 {
+                               label = "0:wififw";
+                               reg = <0x3400000 0x800000>;
+                               read-only;
+                       };
+
+                       partition@3c00000 {
+                               label = "rootfs2";
+                               reg = <0x3c00000 0x3400000>;
+                       };
+
+                       partition@7000000 {
+                               label = "0:wififw_1";
+                               reg = <0x7000000 0x800000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+
+       qca8081_24: ethernet-phy@24 {
+               compatible = "ethernet-phy-id004d.d101";
+               reg = <24>;
+               reset-gpios = <&tlmm 33 GPIO_ACTIVE_LOW>;
+       };
+
+       qca8081_28: ethernet-phy@28 {
+               compatible = "ethernet-phy-id004d.d101";
+               reg = <28>;
+               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x3e>; /* lan port bitmap */
+       switch_wan_bmp = <0x40>; /* wan port bitmap */
+       switch_mac_mode = <0xff>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xf>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xf>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@4 {
+                       port_id = <5>;
+                       phy_address = <24>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+               port@5 {
+                       port_id = <6>;
+                       phy_address = <28>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp5 {
+       status = "okay";
+       phy-handle = <&qca8081_28>;
+       label = "wan";
+};
+
+&dp6 {
+       status = "okay";
+       phy-handle = <&qca8081_24>;
+       label = "lan";
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Edgecore-EAP102";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-301w.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-301w.dts
new file mode 100644 (file)
index 0000000..5521a48
--- /dev/null
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2021, Dirk Buchwalder <buchwalder@posteo.de> */
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "QNAP 301w";
+       compatible = "qnap,301w", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               /*
+                * Aliases as required by u-boot
+                * to patch MAC addresses
+                */
+               led-boot = &led_system_red;
+               led-failsafe = &led_system_red;
+               led-running = &led_pwr_green;
+               led-upgrade = &led_system_red;
+               ethernet0 = &dp1;
+               ethernet1 = &dp2;
+               ethernet2 = &dp3;
+               ethernet3 = &dp4;
+               ethernet4 = &dp5;
+               ethernet5 = &dp6_syn;
+               label-mac-device = &dp1;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+               pinctrl-0 = <&button_pins>;
+               pinctrl-names = "default";
+
+               wps-button {
+                       label = "wps";
+                       gpios = <&tlmm 57 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+               };
+
+               reset-button {
+                       label = "reset";
+                       gpios = <&tlmm 67 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-0 = <&leds_pins>;
+               pinctrl-names = "default";
+
+               led_system_green: led-system-green {
+                       label = "green:system";
+                       gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led_system_red: led-system-red {
+                       label = "red:system";
+                       gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led_pwr_green: led-pwr-green {
+                       label = "green:pwr";
+                       gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-wifi-green {
+                       label = "green:wifi";
+                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-lan4-green {
+                       label = "green:lan4";
+                       gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-lan4-amber {
+                       label = "amber:lan4";
+                       gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+
+               led-lan3-green {
+                       label = "green:lan3";
+                       gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-lan3-amber {
+                       label = "amber:lan3";
+                       gpios = <&tlmm 11 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+
+               led-lan2-green {
+                       label = "green:lan2";
+                       gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-lan2-amber {
+                       label = "amber:lan2";
+                       gpios = <&tlmm 13 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+
+               led-lan1-green {
+                       label = "green:lan1";
+                       gpios = <&tlmm 14 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-lan1-amber {
+                       label = "amber:lan1";
+                       gpios = <&tlmm 15 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+
+               led-10g-1-green {
+                       label = "green:10g_1";
+                       gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-10g-1-amber {
+                       label = "amber:10g_1";
+                       gpios = <&tlmm 56 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+
+               led-10g-2-green {
+                       label = "green:10g_2";
+                       gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-10g-2-amber {
+                       label = "amber:10g_2";
+                       gpios = <&tlmm 52 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+       };
+};
+
+&tlmm {
+
+       mdio_pins: mdio-state {
+               mdc-pins {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio-pins {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       button_pins: button-state {
+               wps-pins {
+                       pins = "gpio57";
+                       function = "gpio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               rst-pins {
+                       pins = "gpio67";
+                       function = "gpio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       leds_pins: leds-state {
+               pins = "gpio1", "gpio3", "gpio4", "gpio6", "gpio7", "gpio8",
+                      "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio42",
+                      "gpio51", "gpio52", "gpio54", "gpio56";
+               function = "gpio";
+               drive-strength = <8>;
+               bias-pull-down;
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&ssphy_1 {
+       status = "okay";
+};
+
+&qusb_phy_1 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&blsp1_spi1 { /* BLSP1 QUP1 */
+       pinctrl-0 = <&spi_0_pins>;
+       pinctrl-names = "default";
+       cs-gpios = <0>;
+       status = "okay";
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+
+               partitions {
+                       compatible = "qcom,smem-part";
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       aqr113c_0: ethernet-phy@0 {
+               compatible ="ethernet-phy-ieee802.3-c45";
+               reg = <0>;
+               reset-gpios = <&tlmm 59 GPIO_ACTIVE_LOW>;
+       };
+
+       aqr113c_8: ethernet-phy@8 {
+               compatible ="ethernet-phy-ieee802.3-c45";
+               reg = <8>;
+               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+       };
+
+       qca8075_16: ethernet-phy@16 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <16>;
+       };
+
+       qca8075_17: ethernet-phy@17 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <17>;
+       };
+
+       qca8075_18: ethernet-phy@18 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <18>;
+       };
+
+       qca8075_19: ethernet-phy@19 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <19>;
+       };
+};
+
+&sdhc_1 {
+       status = "okay";
+
+       /* According to the stock dts from the QNAP gpl drop
+        * the emmc has a problem with the hs400 > hs200 speed switch.
+        * Therefore remove the mmc-hs400-1_8v property
+       */
+       /delete-property/ mmc-hs400-1_8v;
+       mmc-hs200-1_8v;
+       mmc-ddr-1_8v;
+       vqmmc-supply = <&l11>;
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x3e>; /* lan port bitmap */
+       switch_wan_bmp = <0xc0>; /* wan port bitmap */
+       switch_mac_mode = <0xb>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xd>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xd>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <16>;
+               };
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <17>;
+               };
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <18>;
+               };
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <19>;
+               };
+               port@4 {
+                       port_id = <5>;
+                       phy_address = <8>;
+                       compatible = "ethernet-phy-ieee802.3-c45";
+                       ethernet-phy-ieee802.3-c45;
+               };
+               port@5 {
+                       port_id = <6>;
+                       phy_address = <0>;
+                       compatible = "ethernet-phy-ieee802.3-c45";
+                       ethernet-phy-ieee802.3-c45;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp1 {
+       status = "okay";
+       phy-handle = <&qca8075_16>;
+       label = "lan4";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_17>;
+       label = "lan3";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_18>;
+       label = "lan2";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_19>;
+       label = "lan1";
+};
+
+&dp5 {
+       status = "okay";
+       qcom,mactype = <1>;
+       phy-handle = <&aqr113c_8>;
+       label = "10g-1";
+};
+
+&dp6_syn {
+       status = "okay";
+       phy-handle = <&aqr113c_0>;
+       label = "10g-2";
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "QNAP-301w";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-ax9000.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-ax9000.dts
new file mode 100644 (file)
index 0000000..801aa05
--- /dev/null
@@ -0,0 +1,522 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2021, Robert Marko <robimarko@gmail.com> */
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "Xiaomi AX9000";
+       compatible = "xiaomi,ax9000", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               led-boot = &led_system_yellow;
+               led-failsafe = &led_system_yellow;
+               led-running = &led_system_blue;
+               led-upgrade = &led_system_yellow;
+               label-mac-device = &dp5;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " root=/dev/ubiblock0_0";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+
+               wps {
+                       label = "wps"; /* Labeled Mesh on the device */
+                       gpios = <&tlmm 46 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_system_blue: system-blue {
+                       label = "blue:system";
+                       gpios = <&tlmm 48 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               led_system_yellow: system-yellow {
+                       label = "yellow:system";
+                       gpios = <&tlmm 52 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_YELLOW>;
+               };
+
+               network-yellow {
+                       label = "yellow:network";
+                       gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_YELLOW>;
+               };
+
+               network-blue {
+                       label = "blue:network";
+                       gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               top-red {
+                       label = "red:top";
+                       gpios = <&tlmm 63 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+                       default-state = "keep";
+               };
+
+               top-green {
+                       label = "green:top";
+                       gpios = <&tlmm 64 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+                       default-state = "keep";
+               };
+
+               top-blue {
+                       label = "blue:top";
+                       gpios = <&tlmm 66 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_BLUE>;
+                       default-state = "keep";
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       i2c_pins: i2c-pins {
+               pins = "gpio0", "gpio2";
+               function = "blsp5_i2c";
+               drive-strength = <8>;
+               bias-disable;
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&blsp1_i2c6 {
+       status = "okay";
+
+       pinctrl-0 = <&i2c_pins>;
+       pinctrl-names = "default";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       /*
+        * Bootloader will find the NAND DT node by the compatible and
+        * then "fixup" it by adding the partitions from the SMEM table
+        * using the legacy bindings thus making it impossible for us
+        * to change the partition table or utilize NVMEM for calibration.
+        * So add a dummy partitions node that bootloader will populate
+        * and set it as disabled so the kernel ignores it instead of
+        * printing warnings due to the broken way bootloader adds the
+        * partitions.
+        */
+       partitions {
+               status = "disabled";
+       };
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "0:sbl1";
+                               reg = <0x0 0x100000>;
+                               read-only;
+                       };
+
+                       partition@100000 {
+                               label = "0:mibib";
+                               reg = <0x100000 0x100000>;
+                               read-only;
+                       };
+
+                       partition@200000 {
+                               label = "0:bootconfig";
+                               reg = <0x200000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@280000 {
+                               label = "0:bootconfig1";
+                               reg = <0x280000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@300000 {
+                               label = "0:qsee";
+                               reg = <0x300000 0x300000>;
+                               read-only;
+                       };
+
+                       partition@600000 {
+                               label = "0:qsee_1";
+                               reg = <0x600000 0x300000>;
+                               read-only;
+                       };
+
+                       partition@900000 {
+                               label = "0:devcfg";
+                               reg = <0x900000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@980000 {
+                               label = "0:devcfg_1";
+                               reg = <0x980000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@a00000 {
+                               label = "0:apdp";
+                               reg = <0xa00000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@a80000 {
+                               label = "0:apdp_1";
+                               reg = <0xa80000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@b00000 {
+                               label = "0:rpm";
+                               reg = <0xb00000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@b80000 {
+                               label = "0:rpm_1";
+                               reg = <0xb80000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@c00000 {
+                               label = "0:cdt";
+                               reg = <0xc00000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@c80000 {
+                               label = "0:cdt_1";
+                               reg = <0xc80000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@d00000 {
+                               label = "0:appsblenv";
+                               reg = <0xd00000 0x80000>;
+                       };
+
+                       partition@d80000 {
+                               label = "0:appsbl";
+                               reg = <0xd80000 0x100000>;
+                               read-only;
+                       };
+
+                       partition@e80000 {
+                               label = "0:appsbl_1";
+                               reg = <0xe80000 0x100000>;
+                               read-only;
+                       };
+
+                       partition@f80000 {
+                               label = "0:art";
+                               reg = <0xf80000 0x80000>;
+                               read-only;
+
+                               compatible = "nvmem-cells";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               macaddr_dp1: macaddr@0 {
+                                       reg = <0x0 0x6>;
+                               };
+
+                               macaddr_dp2: macaddr@6 {
+                                       reg = <0x6 0x6>;
+                               };
+
+                               macaddr_dp3: macaddr@c {
+                                       reg = <0xc 0x6>;
+                               };
+
+                               macaddr_dp4: macaddr@12 {
+                                       reg = <0x12 0x6>;
+                               };
+
+                               macaddr_dp5: macaddr@18 {
+                                       reg = <0x18 0x6>;
+                               };
+
+                               caldata_qca9889: caldata@4d000 {
+                                       reg = <0x4d000 0x844>;
+                               };
+                       };
+
+                       partition@1000000 {
+                               label = "bdata";
+                               reg = <0x1000000 0x80000>;
+                       };
+
+                       partition@1080000 {
+                               /* This is crash + crash_syslog parts combined */
+                               label = "pstore";
+                               reg = <0x1080000 0x100000>;
+                       };
+
+                       partition@1180000 {
+                               label = "ubi_kernel";
+                               reg = <0x1180000 0x3800000>;
+                       };
+
+                       partition@4980000 {
+                               label = "rootfs";
+                               reg = <0x4980000 0xb680000>;
+                       };
+               };
+       };
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       qca8075_0: ethernet-phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+
+       qca8075_1: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+
+       qca8075_2: ethernet-phy@2 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <2>;
+       };
+
+       qca8075_3: ethernet-phy@3 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <3>;
+       };
+
+       qca8081: ethernet-phy@24 {
+               compatible = "ethernet-phy-id004d.d101";
+               reg = <24>;
+               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x1e>; /* lan port bitmap */
+       switch_wan_bmp = <0x20>; /* wan port bitmap */
+       switch_mac_mode = <0xb>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xc>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0>;
+               };
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+               port@4 {
+                       port_id = <5>;
+                       phy_address = <24>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp1 {
+       status = "okay";
+       phy-handle = <&qca8075_0>;
+       label = "lan4";
+       nvmem-cells = <&macaddr_dp1>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_1>;
+       label = "lan3";
+       nvmem-cells = <&macaddr_dp2>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_2>;
+       label = "lan2";
+       nvmem-cells = <&macaddr_dp3>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_3>;
+       label = "lan1";
+       nvmem-cells = <&macaddr_dp4>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp5 {
+       status = "okay";
+       phy-handle = <&qca8081>;
+       label = "wan";
+       nvmem-cells = <&macaddr_dp5>;
+       nvmem-cell-names = "mac-address";
+};
+
+&pcie_qmp0 {
+       status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 58 GPIO_ACTIVE_LOW>;
+
+       bridge@0,0 {
+               reg = <0x00000000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+
+               wifi@1,0 {
+                       status = "okay";
+
+                       /* ath11k has no DT compatible for PCI cards */
+                       compatible = "pci17cb,1104";
+                       reg = <0x00010000 0 0 0 0>;
+
+                       qcom,ath11k-calibration-variant = "Xiaomi-AX9000";
+               };
+       };
+};
+
+&pcie_qmp1 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 62 GPIO_ACTIVE_HIGH>;
+
+       bridge@1,0 {
+               reg = <0x00010000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+
+               wifi@1,0 {
+                       status = "okay";
+
+                       compatible = "qcom,ath10k";
+                       reg = <0x00010000 0 0 0 0>;
+
+                       qcom,ath10k-calibration-variant = "Xiaomi-AX9000";
+                       nvmem-cell-names = "calibration";
+                       nvmem-cells = <&caldata_qca9889>;
+               };
+       };
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Xiaomi-AX9000";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-dl-wrx36.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-dl-wrx36.dts
new file mode 100644 (file)
index 0000000..5468e9e
--- /dev/null
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright (c) 2022, Robert Marko <robimarko@gmail.com> */
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "Dynalink DL-WRX36";
+       compatible = "dynalink,dl-wrx36", "qcom,ipq8074";
+
+       aliases {
+               led-boot = &led_system_red;
+               led-failsafe = &led_system_red;
+               led-running = &led_system_blue;
+               led-upgrade = &led_system_red;
+               serial0 = &blsp1_uart5;
+               /* Aliases as required by u-boot to patch MAC addresses */
+               ethernet0 = &dp6_syn;
+               ethernet1 = &dp4;
+               ethernet2 = &dp3;
+               ethernet3 = &dp2;
+               ethernet4 = &dp1;
+               label-mac-device = &dp6_syn;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " root=/dev/ubiblock0_1";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+
+               wps {
+                       label = "wps";
+                       gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_system_blue: system-blue {
+                       label = "blue:system";
+                       gpios = <&tlmm 26 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               led_system_red: system-red {
+                       label = "red:system";
+                       gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <8>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "qcom,smem-part";
+               };
+       };
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       qca8075_0: ethernet-phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+
+       qca8075_1: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+
+       qca8075_2: ethernet-phy@2 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <2>;
+       };
+
+       qca8075_3: ethernet-phy@3 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <3>;
+       };
+
+       qca8081: ethernet-phy@28 {
+               compatible = "ethernet-phy-id004d.d101";
+               reg = <28>;
+               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x3e>; /* lan port bitmap */
+       switch_wan_bmp = <0x40>; /* wan port bitmap */
+       switch_mac_mode = <0xb>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xc>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0>;
+               };
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+               port@5 {
+                       port_id = <6>;
+                       phy_address = <28>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp1 {
+       status = "okay";
+       phy-handle = <&qca8075_0>;
+       label = "lan4";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_1>;
+       label = "lan3";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_2>;
+       label = "lan2";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_3>;
+       label = "lan1";
+};
+
+&dp6_syn {
+       status = "okay";
+       phy-handle = <&qca8081>;
+       label = "wan";
+};
+
+&wifi {
+       status = "okay";
+       qcom,ath11k-calibration-variant = "Dynalink-DL-WRX36";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-haze.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-haze.dts
new file mode 100644 (file)
index 0000000..8a5200b
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "prpl Foundation Haze";
+       compatible = "prpl,haze", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               /* Aliases are required by U-Boot to patch MAC addresses */
+               ethernet0 = &dp6_syn;
+               ethernet1 = &dp4;
+               ethernet2 = &dp3;
+               ethernet3 = &dp2;
+               label-mac-device = &dp6_syn;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+               pinctrl-0 = <&button_pins>;
+               pinctrl-names = "default";
+
+               wps-button {
+                       label = "wps";
+                       gpios = <&tlmm 42 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+               };
+
+               reset-button {
+                       label = "reset";
+                       gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-state {
+               mdc-pins {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio-pins {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       button_pins: button-state {
+               wps-pins {
+                       pins = "gpio42";
+                       function = "gpio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               rst-pins {
+                       pins = "gpio44";
+                       function = "gpio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&ssphy_1 {
+       status = "okay";
+};
+
+&qusb_phy_1 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&blsp1_spi1 { /* BLSP1 QUP1 */
+       pinctrl-0 = <&spi_0_pins>;
+       pinctrl-names = "default";
+       cs-gpios = <0>;
+       status = "okay";
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+
+               partitions {
+                       compatible = "qcom,smem-part";
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 22 GPIO_ACTIVE_LOW>;
+
+       qca8075_1: ethernet-phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+
+       qca8075_2: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+
+       qca8075_3: ethernet-phy@2 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <2>;
+       };
+
+       qca8075_4: ethernet-phy@3 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <3>;
+       };
+
+       aqr113c: ethernet-phy@5 {
+               compatible ="ethernet-phy-ieee802.3-c45";
+               reg = <8>;
+               reset-gpios = <&tlmm 43 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&sdhc_1 {
+       status = "okay";
+
+       vqmmc-supply = <&l11>;
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x1e>; /* lan port bitmap */
+       switch_wan_bmp = <0x60>; /* wan port bitmap */
+       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0xe>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0xd>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0>;
+               };
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+               port@4 {
+                       port_id = <6>;
+                       phy_address = <8>;
+                       compatible = "ethernet-phy-ieee802.3-c45";
+                       ethernet-phy-ieee802.3-c45;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+/* Dummy LAN port */
+&dp1 {
+       status = "disabled";
+       phy-handle = <&qca8075_1>;
+       label = "lan4";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_2>;
+       label = "lan3";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_3>;
+       label = "lan2";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_4>;
+       label = "lan1";
+};
+
+&dp6_syn {
+       status = "okay";
+       qcom,mactype = <1>;
+       phy-handle = <&aqr113c>;
+       label = "wan";
+};
+
+&pcie_qmp0 {
+       status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 58 GPIO_ACTIVE_LOW>;
+
+       bridge@0,0 {
+               reg = <0x00020000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+       };
+};
+
+&pcie_qmp1 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 61 GPIO_ACTIVE_LOW>;
+
+       bridge@1,0 {
+               reg = <0x00010000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+
+               wifi@1,0 {
+                       status = "okay";
+
+                       /* ath11k has no DT compatible for PCI cards */
+                       compatible = "pci17cb,1104";
+                       reg = <0x00010000 0 0 0 0>;
+
+                       qcom,ath11k-calibration-variant = "prpl-Haze";
+               };
+       };
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "prpl-Haze";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts
new file mode 100644 (file)
index 0000000..5bfcdcc
--- /dev/null
@@ -0,0 +1,191 @@
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Netgear WAX218";
+       compatible = "netgear,wax218", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               led-boot = &led_power_amber;
+               led-failsafe = &led_power_amber;
+               led-running = &led_power_amber;
+               led-upgrade = &led_power_amber;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               /*
+                * Netgear's U-Boot adds "ubi.mtd=rootfs root=mtd:ubi_rootfs"
+                * That fails to create a UBI block device, so add it here.
+               */
+               bootargs-append = " ubi.block=0,rootfs root=/dev/ubiblock0_1";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 52 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       led_spi {
+               compatible = "spi-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               sck-gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>;
+               mosi-gpios = <&tlmm 19 GPIO_ACTIVE_HIGH>;
+
+               led_gpio: led_gpio@0 {
+                       compatible = "fairchild,74hc595";
+                       reg = <0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       registers-number = <1>;
+                       enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+                       spi-max-frequency = <1000000>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_power_amber: led_power {
+                       label = "amber:power";
+                       gpios = <&led_gpio 1 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_lan {
+                       label = "blue:lan";
+                       gpios = <&led_gpio 2 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_wlan_2g {
+                       label = "blue:wlan2g";
+                       gpios = <&led_gpio 3 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_wlan_5g {
+                       label = "blue:wlan5g";
+                       gpios = <&led_gpio 4 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;
+       switch_lan_bmp = <0x3e>;
+       switch_wan_bmp = <0x40>;
+       switch_mac_mode = <0x00>;
+       switch_mac_mode1 = <0xff>;
+       switch_mac_mode2 = <0x0f>;
+       bm_tick_mode = <0>;
+       tm_tick_mode = <0>;
+
+       qcom,port_phyinfo {
+               port@5 {
+                       port_id = <6>;
+                       phy_address = <28>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+
+       qca8081_28: ethernet-phy@28 {
+               reg = <28>;
+       };
+};
+
+&dp6_syn {
+       status = "okay";
+       phy-handle = <&qca8081_28>;
+       label = "lan";
+       nvmem-cells = <&macaddr_ubootenv_ethaddr>;
+       nvmem-cell-names = "mac-address";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "qcom,smem-part";
+
+                       partition-0-appsblenv {
+                               compatible = "fixed-partitions";
+                               label = "0:appsblenv";
+                               read-only;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               partition@0 {
+                                       compatible = "u-boot,env";
+                                       label = "env-data";
+                                       reg = <0x0 0x40000>;
+
+                                       macaddr_ubootenv_ethaddr: ethaddr {};
+                               };
+                       };
+               };
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Netgear-WAX218";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts
new file mode 100644 (file)
index 0000000..9779070
--- /dev/null
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/* Copyright 2023 Nokia */
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "Compex WPQ873";
+       compatible = "compex,wpq873", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               led-boot = &led_power_blue;
+               led-failsafe = &led_power_red;
+               led-running = &led_system_green;
+               led-upgrade = &led_system_blue;
+               /* Aliases as required by u-boot to patch MAC addresses */
+               ethernet0 = &dp6;
+               ethernet1 = &dp2;
+               ethernet2 = &dp3;
+               ethernet3 = &dp4;
+               label-mac-device = &dp6;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " root=/dev/ubiblock0_1";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 21 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_power_red: power-red {
+                       label = "red:power";
+                       gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led_power_blue: power-blue {
+                       label = "blue:power";
+                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               led_system_red: system-red {
+                       label = "red:system";
+                       gpios = <&tlmm 28 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led_system_green: system-green {
+                       label = "green:system";
+                       gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led_system_blue: system-blue {
+                       label = "blue:system";
+                       gpios = <&tlmm 19 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       i2c_pins: i2c-pins {
+               pins = "gpio0", "gpio2";
+               function = "blsp5_i2c";
+               drive-strength = <8>;
+               bias-disable;
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&blsp1_i2c6 {
+       status = "okay";
+
+       pinctrl-0 = <&i2c_pins>;
+       pinctrl-names = "default";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&blsp1_spi1 {
+       status = "okay";
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+
+       button_pins: button_pins {
+               reset_button {
+                       pins = "gpio66";
+                       function = "gpio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_spi1 {
+       status = "okay";
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "0:sbl1";
+                               reg = <0x0 0x50000>;
+                               read-only;
+                       };
+
+                       partition@50000 {
+                               label = "0:mibib";
+                               reg = <0x50000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@60000 {
+                               label = "0:bootconfig";
+                               reg = <0x60000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@80000 {
+                               label = "0:bootconfig1";
+                               reg = <0x80000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@a0000 {
+                               label = "0:qsee";
+                               reg = <0xa0000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@220000 {
+                               label = "0:qsee_1";
+                               reg = <0x220000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@3a0000 {
+                               label = "0:devcfg";
+                               reg = <0x3a0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3b0000 {
+                               label = "0:devcfg_1";
+                               reg = <0x3b0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3c0000 {
+                               label = "0:apdp";
+                               reg = <0x3c0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3d0000 {
+                               label = "0:apdp_1";
+                               reg = <0x3d0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3e0000 {
+                               label = "0:rpm";
+                               reg = <0x3e0000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@420000 {
+                               label = "0:rpm_1";
+                               reg = <0x420000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@460000 {
+                               label = "0:cdt";
+                               reg = <0x460000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@470000 {
+                               label = "0:cdt_1";
+                               reg = <0x470000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@480000 {
+                               label = "0:appsblenv";
+                               reg = <0x480000 0x10000>;
+                       };
+
+                       partition@490000 {
+                               label = "0:appsbl";
+                               reg = <0x490000 0xa0000>;
+                               read-only;
+                       };
+
+                       partition@550000 {
+                               label = "0:appsbl_1";
+                               reg = <0x530000 0xa0000>;
+                               read-only;
+                       };
+
+                       partition@610000 {
+                               label = "0:art";
+                               reg = <0x5d0000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@650000 {
+                               label = "0:ethphyfw";
+                               reg = <0x610000 0x80000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <8>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "rootfs";
+                               reg = <0x0000000 0x3400000>;
+                       };
+
+                       partition@3400000 {
+                               label = "0:wififw";
+                               reg = <0x3400000 0x800000>;
+                               read-only;
+                       };
+
+                       partition@3c00000 {
+                               label = "rootfs_1";
+                               reg = <0x3c00000 0x3400000>;
+                       };
+
+                       partition@7000000 {
+                               label = "0:wififw_1";
+                               reg = <0x7000000 0x800000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&qusb_phy_1 {
+       status = "okay";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&ssphy_1 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+
+&mdio {
+       status = "okay";
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       qca8075_1: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+
+       qca8075_2: ethernet-phy@2 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <2>;
+       };
+
+       qca8075_3: ethernet-phy@3 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <3>;
+       };
+
+       qca8081: ethernet-phy@28 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <28>;
+               reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+       };
+
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+       switch_lan_bmp = <0x3e>; /* lan port bitmap */
+       switch_wan_bmp = <0x40>; /* wan port bitmap */
+       switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
+       switch_mac_mode1 = <0x0f>; /* mac mode for uniphy instance1*/
+       switch_mac_mode2 = <0x0f>; /* mac mode for uniphy instance2*/
+       bm_tick_mode = <0>; /* bm tick mode */
+       tm_tick_mode = <0>; /* tm tick mode */
+
+       qcom,port_phyinfo {
+               port@2 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+               port@3 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+               port@4 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+               port@5 {
+                       port_id = <6>;
+                       phy_address = <28>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp2 {
+        status = "okay";
+        phy-handle = <&qca8075_1>;
+        label = "lan1";
+};
+
+&dp3 {
+        status = "okay";
+        phy-handle = <&qca8075_2>;
+        label = "lan2";
+};
+
+&dp4 {
+        status = "okay";
+        phy-handle = <&qca8075_3>;
+        label = "lan3";
+};
+
+&dp6 {
+        status = "okay";
+        phy-handle = <&qca8081>;
+        label = "wan";
+};
+
+&pcie_qmp0 {
+       status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 58 GPIO_ACTIVE_LOW>;
+
+       bridge@0,0 {
+               reg = <0x00020000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+       };
+};
+
+&pcie_qmp1 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+
+       perst-gpio = <&tlmm 62 GPIO_ACTIVE_HIGH>;
+
+       bridge@1,0 {
+               reg = <0x00010000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+       };
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Compex-WPQ873";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-512m.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-512m.dtsi
new file mode 100644 (file)
index 0000000..dace400
--- /dev/null
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "ipq8074.dtsi"
+
+&tzapp_region {
+       reg = <0x0 0x4a400000 0x0 0x100000>;
+};
+
+&q6_region {
+       reg = <0x0 0x4b000000 0x0 0x3700000>;
+};
+
+&q6_etr_region {
+       reg = <0x0 0x4e700000 0x0 0x100000>;
+};
+
+&m3_dump_region {
+       reg = <0x0 0x4e800000 0x0 0x100000>;
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-ac-cpu.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-ac-cpu.dtsi
new file mode 100644 (file)
index 0000000..057d592
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <dt-bindings/thermal/thermal.h>
+#include "ipq8074-cpr-regulator.dtsi"
+
+&CPU0 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+
+&CPU1 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+
+&CPU2 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+
+&CPU3 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+&cpu0_thermal {
+       trips {
+               cpu0_passive: cpu-passive {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu0_passive>;
+                       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>;
+               };
+       };
+};
+
+&cpu1_thermal {
+       trips {
+               cpu1_passive: cpu-passive {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu1_passive>;
+                       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>;
+               };
+       };
+};
+
+&cpu2_thermal {
+       trips {
+               cpu2_passive: cpu-passive {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu2_passive>;
+                       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>;
+               };
+       };
+};
+
+&cpu3_thermal {
+       trips {
+               cpu3_passive: cpu-passive {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu3_passive>;
+                       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>;
+               };
+       };
+};
+
+&cluster_thermal {
+       trips {
+               cluster_passive: cluster-passive {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cluster_passive>;
+                       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/files/arch/arm64/boot/dts/qcom/ipq8074-cpr-regulator.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-cpr-regulator.dtsi
new file mode 100644 (file)
index 0000000..e351a2e
--- /dev/null
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "pmp8074.dtsi"
+
+&soc {
+       apc_apm: apm@b111000 {
+               compatible = "qcom,ipq807x-apm";
+               reg = <0xb111000 0x1000>;
+               reg-names = "pm-apcc-glb";
+               qcom,apm-post-halt-delay = <0x2>;
+               qcom,apm-halt-clk-delay = <0x11>;
+               qcom,apm-resume-clk-delay = <0x10>;
+               qcom,apm-sel-switch-delay = <0x01>;
+       };
+
+       apc_cpr: cpr4-ctrl@b018000 {
+               compatible = "qcom,cpr4-ipq807x-apss-regulator";
+               reg = <0xb018000 0x4000>, <0xa4000 0x1000>, <0x0193d008 0x4>;
+               reg-names = "cpr_ctrl", "fuse_base", "cpr_tcsr_reg";
+               interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "cpr";
+               qcom,cpr-ctrl-name = "apc";
+               qcom,cpr-sensor-time = <1000>;
+               qcom,cpr-loop-time = <5000000>;
+               qcom,cpr-idle-cycles = <15>;
+               qcom,cpr-step-quot-init-min = <12>;
+               qcom,cpr-step-quot-init-max = <14>;
+               qcom,cpr-count-mode = <0>;              /* All-at-once */
+               qcom,cpr-count-repeat = <14>;
+               qcom,cpr-down-error-step-limit = <1>;
+               qcom,cpr-up-error-step-limit = <1>;
+               qcom,apm-ctrl = <&apc_apm>;
+               qcom,apm-threshold-voltage = <848000>;
+               vdd-supply = <&s3>;
+               qcom,voltage-step = <8000>;
+
+               thread@0 {
+                       qcom,cpr-thread-id = <0>;
+                       qcom,cpr-consecutive-up = <0>;
+                       qcom,cpr-consecutive-down = <0>;
+                       qcom,cpr-up-threshold = <4>;
+                       qcom,cpr-down-threshold = <1>;
+
+                       apc_vreg: regulator {
+                               regulator-name = "apc_corner";
+                               regulator-min-microvolt = <1>;
+                               regulator-max-microvolt = <6>;
+                               qcom,cpr-part-types = <2>;
+                               qcom,cpr-parts-voltage = <1048000>;
+                               qcom,cpr-parts-voltage-v2 = <992000>;
+                               qcom,cpr-fuse-corners = <4>;
+                               qcom,cpr-fuse-combos = <8>;
+                               qcom,cpr-corners = <6>;
+                               qcom,cpr-speed-bins = <1>;
+                               qcom,cpr-speed-bin-corners = <6>;
+                               qcom,cpr-corner-fmax-map = <1 3 5 6>;
+                               qcom,allow-voltage-interpolation;
+                               qcom,allow-quotient-interpolation;
+                               qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+                               qcom,cpr-voltage-ceiling =
+                                       <840000 904000 944000
+                                        984000 992000 1064000>;
+                               qcom,cpr-voltage-floor =
+                                       <592000 648000 712000
+                                        744000 784000 848000>;
+                               qcom,corner-frequencies =
+                                       <1017600000 1382400000 1651200000
+                                       1843200000 1920000000 2208000000>;
+
+                               /* TT/FF parts i.e. turbo L1 OL voltage < 1048 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-0 =
+                                       /* Speed bin 0; CPR rev 0..7 */
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0 12000>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>;
+
+                               /* SS parts i.e turbo L1 OL voltage >= 1048 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-1 =
+                                       /* Speed bin 0; CPR rev 0..7 */
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       < 20000  26000      0 20000>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>;
+
+                               /* v2 - FF parts i.e. turbo L1 OL voltage < 992 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-0 =
+                                        /* Speed bin 0; CPR rev 0..7 */
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>;
+
+                               /* v2 - SS/TT parts i.e turbo L1 OL voltage >= 992 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-1 =
+                                       /* Speed bin 0; CPR rev 0..7 */
+                                       <     0      0      0     0>,
+                                       <     0   7000  36000  4000>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>;
+
+                               /* v2 - FF parts i.e. turbo L1 OL voltage < 992 mV */
+                               qcom,cpr-closed-loop-voltage-adjustment-v2-0 =
+                                       /* Speed bin 0; CPR rev 0..7 */
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>;
+
+                               /* v2 - SS/TT parts i.e turbo L1 OL voltage >= 992 mV */
+                               qcom,cpr-closed-loop-voltage-adjustment-v2-1 =
+                                       /* Speed bin 0; CPR rev 0..7 */
+                                       <     0      0      0     0>,
+                                       <     0      0      19000 0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>,
+                                       <     0      0      0     0>;
+
+                               qcom,cpr-ro-scaling-factor =
+                                       < 3970 4150 0    2280 2520 2470 2250 2280
+                                         2390 2330 2530 2500  850 2900 2510 2170 >,
+                                       < 3970 4150 0    2280 2520 2470 2250 2280
+                                         2390 2330 2530 2500  850 2900 2510 2170 >,
+                                       < 3970 4150 0    2280 2520 2470 2250 2280
+                                         2390 2330 2530 2500  850 2900 2510 2170 >,
+                                       < 3970 4150 0    2280 2520 2470 2250 2280
+                                         2390 2330 2530 2500  850 2900 2510 2170 >;
+
+                               qcom,cpr-floor-to-ceiling-max-range =
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>,
+                                       < 40000 40000 40000 40000 40000 40000>;
+                               regulator-always-on;
+                       };
+               };
+       };
+
+       npu_cpr: npu-cpr {
+               compatible = "qcom,cpr3-ipq807x-npu-regulator";
+               reg = <0xa4000 0x1000>, <0x0193d008 0x4>;
+               reg-names = "fuse_base", "cpr_tcsr_reg";
+               qcom,cpr-ctrl-name = "npu";
+               vdd-supply = <&s4>;
+               qcom,voltage-step = <8000>;
+               thread@0 {
+                       qcom,cpr-thread-id = <0>;
+                       qcom,cpr-consecutive-up = <0>;
+                       qcom,cpr-consecutive-down = <2>;
+                       qcom,cpr-up-threshold = <2>;
+                       qcom,cpr-down-threshold = <1>;
+
+                       npu_vreg: regulator {
+                               regulator-name = "npu_corner";
+                               regulator-min-microvolt = <1>;
+                               regulator-max-microvolt = <3>;
+                               qcom,cpr-part-types = <2>;
+                               qcom,cpr-parts-voltage = <968000>;
+                               qcom,cpr-parts-voltage-v2 = <832001>;
+                               qcom,cpr-cold-temp-threshold-v2 = <30>;
+                               qcom,cpr-fuse-corners = <2>;
+                               qcom,cpr-fuse-combos = <1>;
+                               qcom,cpr-corners = <2>;
+                               qcom,cpr-speed-bins = <1>;
+                               qcom,cpr-speed-bin-corners = <2>;
+                               qcom,allow-voltage-interpolation;
+                               qcom,cpr-corner-fmax-map = <1 2>;
+                               qcom,cpr-voltage-ceiling =
+                                       <912000 992000>;
+                               qcom,cpr-voltage-floor =
+                                       <752000 792000>;
+                               qcom,corner-frequencies =
+                                       <1497600000 1689600000>;
+
+                               /* TT/FF parts i.e. turbo OL voltage < 968 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-0 =
+                                       < 40000   40000>;
+
+                               /* SS parts i.e turbo OL voltage >= 968 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-1 =
+                                       < 24000   24000>;
+
+                               /* FF parts i.e. turbo OL voltage <= 832 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-0=
+                                       <40000   40000>;
+
+                                /* TT/SS parts i.e turbo OL voltage > 832 mV */
+                               qcom,cpr-open-loop-voltage-fuse-adjustment-v2-1=
+                                       <40000   40000>;
+
+                               /* FF parts i.e. turbo OL voltage <= 832 mV */
+                               qcom,cpr-cold-temp-voltage-adjustment-v2-0 =
+                                       <0   0>;
+
+                               /* TT/SS parts i.e turbo OL voltage > 832 mV */
+                               qcom,cpr-cold-temp-voltage-adjustment-v2-1 =
+                                       <35000   27000>;
+                       };
+               };
+       };
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-ess.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-ess.dtsi
new file mode 100644 (file)
index 0000000..129266c
--- /dev/null
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+&clocks {
+       bias_pll_cc_clk {
+               compatible = "fixed-clock";
+               clock-frequency = <300000000>;
+               #clock-cells = <0>;
+       };
+
+       bias_pll_nss_noc_clk {
+               compatible = "fixed-clock";
+               clock-frequency = <416500000>;
+               #clock-cells = <0>;
+       };
+};
+
+&soc {
+       switch: ess-switch@3a000000 {
+               compatible = "qcom,ess-switch-ipq807x";
+               reg = <0x3a000000 0x1000000>;
+               switch_access_mode = "local bus";
+               switch_cpu_bmp = <0x1>;  /* cpu port bitmap */
+               switch_inner_bmp = <0x80>; /*inner port bitmap*/
+               clocks = <&gcc GCC_CMN_12GPLL_AHB_CLK>,
+                        <&gcc GCC_CMN_12GPLL_SYS_CLK>,
+                        <&gcc GCC_UNIPHY0_AHB_CLK>,
+                        <&gcc GCC_UNIPHY0_SYS_CLK>,
+                        <&gcc GCC_UNIPHY1_AHB_CLK>,
+                        <&gcc GCC_UNIPHY1_SYS_CLK>,
+                        <&gcc GCC_UNIPHY2_AHB_CLK>,
+                        <&gcc GCC_UNIPHY2_SYS_CLK>,
+                        <&gcc GCC_PORT1_MAC_CLK>,
+                        <&gcc GCC_PORT2_MAC_CLK>,
+                        <&gcc GCC_PORT3_MAC_CLK>,
+                        <&gcc GCC_PORT4_MAC_CLK>,
+                        <&gcc GCC_PORT5_MAC_CLK>,
+                        <&gcc GCC_PORT6_MAC_CLK>,
+                        <&gcc GCC_NSS_PPE_CLK>,
+                        <&gcc GCC_NSS_PPE_CFG_CLK>,
+                        <&gcc GCC_NSSNOC_PPE_CLK>,
+                        <&gcc GCC_NSSNOC_PPE_CFG_CLK>,
+                        <&gcc GCC_NSS_EDMA_CLK>,
+                        <&gcc GCC_NSS_EDMA_CFG_CLK>,
+                        <&gcc GCC_NSS_PPE_IPE_CLK>,
+                        <&gcc GCC_NSS_PPE_BTQ_CLK>,
+                        <&gcc GCC_MDIO_AHB_CLK>,
+                        <&gcc GCC_NSS_NOC_CLK>,
+                        <&gcc GCC_NSSNOC_SNOC_CLK>,
+                        <&gcc GCC_MEM_NOC_NSS_AXI_CLK>,
+                        <&gcc GCC_NSS_CRYPTO_CLK>,
+                        <&gcc GCC_NSS_IMEM_CLK>,
+                        <&gcc GCC_NSS_PTP_REF_CLK>,
+                        <&gcc GCC_NSS_PORT1_RX_CLK>,
+                        <&gcc GCC_NSS_PORT1_TX_CLK>,
+                        <&gcc GCC_NSS_PORT2_RX_CLK>,
+                        <&gcc GCC_NSS_PORT2_TX_CLK>,
+                        <&gcc GCC_NSS_PORT3_RX_CLK>,
+                        <&gcc GCC_NSS_PORT3_TX_CLK>,
+                        <&gcc GCC_NSS_PORT4_RX_CLK>,
+                        <&gcc GCC_NSS_PORT4_TX_CLK>,
+                        <&gcc GCC_NSS_PORT5_RX_CLK>,
+                        <&gcc GCC_NSS_PORT5_TX_CLK>,
+                        <&gcc GCC_NSS_PORT6_RX_CLK>,
+                        <&gcc GCC_NSS_PORT6_TX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT1_RX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT1_TX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT2_RX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT2_TX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT3_RX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT3_TX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT4_RX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT4_TX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT5_RX_CLK>,
+                        <&gcc GCC_UNIPHY0_PORT5_TX_CLK>,
+                        <&gcc GCC_UNIPHY1_PORT5_RX_CLK>,
+                        <&gcc GCC_UNIPHY1_PORT5_TX_CLK>,
+                        <&gcc GCC_UNIPHY2_PORT6_RX_CLK>,
+                        <&gcc GCC_UNIPHY2_PORT6_TX_CLK>,
+                        <&gcc NSS_PORT5_RX_CLK_SRC>,
+                        <&gcc NSS_PORT5_TX_CLK_SRC>;
+               clock-names = "cmn_ahb_clk", "cmn_sys_clk",
+                             "uniphy0_ahb_clk", "uniphy0_sys_clk",
+                             "uniphy1_ahb_clk", "uniphy1_sys_clk",
+                             "uniphy2_ahb_clk", "uniphy2_sys_clk",
+                             "port1_mac_clk", "port2_mac_clk",
+                             "port3_mac_clk", "port4_mac_clk",
+                             "port5_mac_clk", "port6_mac_clk",
+                             "nss_ppe_clk", "nss_ppe_cfg_clk",
+                             "nssnoc_ppe_clk", "nssnoc_ppe_cfg_clk",
+                             "nss_edma_clk", "nss_edma_cfg_clk",
+                             "nss_ppe_ipe_clk", "nss_ppe_btq_clk",
+                             "gcc_mdio_ahb_clk", "gcc_nss_noc_clk",
+                             "gcc_nssnoc_snoc_clk",
+                             "gcc_mem_noc_nss_axi_clk",
+                             "gcc_nss_crypto_clk",
+                             "gcc_nss_imem_clk",
+                             "gcc_nss_ptp_ref_clk",
+                             "nss_port1_rx_clk", "nss_port1_tx_clk",
+                             "nss_port2_rx_clk", "nss_port2_tx_clk",
+                             "nss_port3_rx_clk", "nss_port3_tx_clk",
+                             "nss_port4_rx_clk", "nss_port4_tx_clk",
+                             "nss_port5_rx_clk", "nss_port5_tx_clk",
+                             "nss_port6_rx_clk", "nss_port6_tx_clk",
+                             "uniphy0_port1_rx_clk",
+                             "uniphy0_port1_tx_clk",
+                             "uniphy0_port2_rx_clk",
+                             "uniphy0_port2_tx_clk",
+                             "uniphy0_port3_rx_clk",
+                             "uniphy0_port3_tx_clk",
+                             "uniphy0_port4_rx_clk",
+                             "uniphy0_port4_tx_clk",
+                             "uniphy0_port5_rx_clk",
+                             "uniphy0_port5_tx_clk",
+                             "uniphy1_port5_rx_clk",
+                             "uniphy1_port5_tx_clk",
+                             "uniphy2_port6_rx_clk",
+                             "uniphy2_port6_tx_clk",
+                             "nss_port5_rx_clk_src",
+                             "nss_port5_tx_clk_src";
+               resets = <&gcc GCC_PPE_FULL_RESET>,
+                        <&gcc GCC_UNIPHY0_SOFT_RESET>,
+                        <&gcc GCC_UNIPHY0_XPCS_RESET>,
+                        <&gcc GCC_UNIPHY1_SOFT_RESET>,
+                        <&gcc GCC_UNIPHY1_XPCS_RESET>,
+                        <&gcc GCC_UNIPHY2_SOFT_RESET>,
+                        <&gcc GCC_UNIPHY2_XPCS_RESET>,
+                        <&gcc GCC_NSSPORT1_RESET>,
+                        <&gcc GCC_NSSPORT2_RESET>,
+                        <&gcc GCC_NSSPORT3_RESET>,
+                        <&gcc GCC_NSSPORT4_RESET>,
+                        <&gcc GCC_NSSPORT5_RESET>,
+                        <&gcc GCC_NSSPORT6_RESET>;
+               reset-names = "ppe_rst", "uniphy0_soft_rst",
+                             "uniphy0_xpcs_rst", "uniphy1_soft_rst",
+                             "uniphy1_xpcs_rst", "uniphy2_soft_rst",
+                             "uniphy2_xpcs_rst", "nss_port1_rst",
+                             "nss_port2_rst", "nss_port3_rst",
+                             "nss_port4_rst", "nss_port5_rst",
+                             "nss_port6_rst";
+               mdio-bus = <&mdio>;
+               status = "disabled";
+
+               port_scheduler_resource {
+                       port@0 {
+                               port_id = <0>;
+                               ucast_queue = <0 143>;
+                               mcast_queue = <256 271>;
+                               l0sp = <0 35>;
+                               l0cdrr = <0 47>;
+                               l0edrr = <0 47>;
+                               l1cdrr = <0 7>;
+                               l1edrr = <0 7>;
+                       };
+                       port@1 {
+                               port_id = <1>;
+                               ucast_queue = <144 159>;
+                               mcast_queue = <272 275>;
+                               l0sp = <36 39>;
+                               l0cdrr = <48 63>;
+                               l0edrr = <48 63>;
+                               l1cdrr = <8 11>;
+                               l1edrr = <8 11>;
+                       };
+                       port@2 {
+                               port_id = <2>;
+                               ucast_queue = <160 175>;
+                               mcast_queue = <276 279>;
+                               l0sp = <40 43>;
+                               l0cdrr = <64 79>;
+                               l0edrr = <64 79>;
+                               l1cdrr = <12 15>;
+                               l1edrr = <12 15>;
+                       };
+                       port@3 {
+                               port_id = <3>;
+                               ucast_queue = <176 191>;
+                               mcast_queue = <280 283>;
+                               l0sp = <44 47>;
+                               l0cdrr = <80 95>;
+                               l0edrr = <80 95>;
+                               l1cdrr = <16 19>;
+                               l1edrr = <16 19>;
+                       };
+                       port@4 {
+                               port_id = <4>;
+                               ucast_queue = <192 207>;
+                               mcast_queue = <284 287>;
+                               l0sp = <48 51>;
+                               l0cdrr = <96 111>;
+                               l0edrr = <96 111>;
+                               l1cdrr = <20 23>;
+                               l1edrr = <20 23>;
+                       };
+                       port@5 {
+                               port_id = <5>;
+                               ucast_queue = <208 223>;
+                               mcast_queue = <288 291>;
+                               l0sp = <52 55>;
+                               l0cdrr = <112 127>;
+                               l0edrr = <112 127>;
+                               l1cdrr = <24 27>;
+                               l1edrr = <24 27>;
+                       };
+                       port@6 {
+                               port_id = <6>;
+                               ucast_queue = <224 239>;
+                               mcast_queue = <292 295>;
+                               l0sp = <56 59>;
+                               l0cdrr = <128 143>;
+                               l0edrr = <128 143>;
+                               l1cdrr = <28 31>;
+                               l1edrr = <28 31>;
+                       };
+                       port@7 {
+                               port_id = <7>;
+                               ucast_queue = <240 255>;
+                               mcast_queue = <296 299>;
+                               l0sp = <60 63>;
+                               l0cdrr = <144 159>;
+                               l0edrr = <144 159>;
+                               l1cdrr = <32 35>;
+                               l1edrr = <32 35>;
+                       };
+               };
+               port_scheduler_config {
+                       port@0 {
+                               port_id = <0>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <0 1>; /*L0 SPs*/
+                                               /*cpri cdrr epri edrr*/
+                                               cfg = <0 0 0 0>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               /*unicast queues*/
+                                               ucast_queue = <0 4 8>;
+                                               /*multicast queues*/
+                                               mcast_queue = <256 260>;
+                                               /*sp cpri cdrr epri edrr*/
+                                               cfg = <0 0 0 0 0>;
+                                       };
+                                       group@1 {
+                                               ucast_queue = <1 5 9>;
+                                               mcast_queue = <257 261>;
+                                               cfg = <0 1 1 1 1>;
+                                       };
+                                       group@2 {
+                                               ucast_queue = <2 6 10>;
+                                               mcast_queue = <258 262>;
+                                               cfg = <0 2 2 2 2>;
+                                       };
+                                       group@3 {
+                                               ucast_queue = <3 7 11>;
+                                               mcast_queue = <259 263>;
+                                               cfg = <0 3 3 3 3>;
+                                       };
+                               };
+                       };
+                       port@1 {
+                               port_id = <1>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <36>;
+                                               cfg = <0 8 0 8>;
+                                       };
+                                       group@1 {
+                                               sp = <37>;
+                                               cfg = <1 9 1 9>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <144>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <272>;
+                                               mcast_loop_pri = <4>;
+                                               cfg = <36 0 48 0 48>;
+                                       };
+                               };
+                       };
+                       port@2 {
+                               port_id = <2>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <40>;
+                                               cfg = <0 12 0 12>;
+                                       };
+                                       group@1 {
+                                               sp = <41>;
+                                               cfg = <1 13 1 13>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <160>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <276>;
+                                               mcast_loop_pri = <4>;
+                                               cfg = <40 0 64 0 64>;
+                                       };
+                               };
+                       };
+                       port@3 {
+                               port_id = <3>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <44>;
+                                               cfg = <0 16 0 16>;
+                                       };
+                                       group@1 {
+                                               sp = <45>;
+                                               cfg = <1 17 1 17>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <176>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <280>;
+                                               mcast_loop_pri = <4>;
+                                               cfg = <44 0 80 0 80>;
+                                       };
+                               };
+                       };
+                       port@4 {
+                               port_id = <4>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <48>;
+                                               cfg = <0 20 0 20>;
+                                       };
+                                       group@1 {
+                                               sp = <49>;
+                                               cfg = <1 21 1 21>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <192>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <284>;
+                                               mcast_loop_pri = <4>;
+                                               cfg = <48 0 96 0 96>;
+                                       };
+                               };
+                       };
+                       port@5 {
+                               port_id = <5>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <52>;
+                                               cfg = <0 24 0 24>;
+                                       };
+                                       group@1 {
+                                               sp = <53>;
+                                               cfg = <1 25 1 25>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <208>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <288>;
+                                               mcast_loop_pri = <4>;
+                                               cfg = <52 0 112 0 112>;
+                                       };
+                               };
+                       };
+                       port@6 {
+                               port_id = <6>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <56>;
+                                               cfg = <0 28 0 28>;
+                                       };
+                                       group@1 {
+                                               sp = <57>;
+                                               cfg = <1 29 1 29>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <224>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <292>;
+                                               mcast_loop_pri = <4>;
+                                               cfg = <56 0 128 0 128>;
+                                       };
+                               };
+                       };
+                       port@7 {
+                               port_id = <7>;
+                               l1scheduler {
+                                       group@0 {
+                                               sp = <60>;
+                                               cfg = <0 32 0 32>;
+                                       };
+                                       group@1 {
+                                               sp = <61>;
+                                               cfg = <1 33 1 33>;
+                                       };
+                               };
+                               l0scheduler {
+                                       group@0 {
+                                               ucast_queue = <240>;
+                                               ucast_loop_pri = <16>;
+                                               mcast_queue = <296>;
+                                               cfg = <60 0 144 0 144>;
+                                       };
+                               };
+                       };
+               };
+       };
+
+       ess-uniphy@7a00000 {
+               compatible = "qcom,ess-uniphy";
+               reg = <0x7a00000 0x30000>;
+               uniphy_access_mode = "local bus";
+       };
+
+       edma: edma@3ab00000 {
+               compatible = "qcom,edma";
+               reg = <0x3ab00000 0x76900>;
+               reg-names = "edma-reg-base";
+               qcom,txdesc-ring-start = <23>;
+               qcom,txdesc-rings = <1>;
+               qcom,txcmpl-ring-start = <7>;
+               qcom,txcmpl-rings = <1>;
+               qcom,rxfill-ring-start = <7>;
+               qcom,rxfill-rings = <1>;
+               qcom,rxdesc-ring-start = <15>;
+               qcom,rxdesc-rings = <1>;
+               interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
+               resets = <&gcc GCC_EDMA_HW_RESET>;
+               reset-names = "edma_rst";
+               status = "disabled";
+       };
+
+       dp1: dp1 {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <1>;
+               reg = <0x3a001000 0x200>;
+               qcom,mactype = <0>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp2: dp2 {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <2>;
+               reg = <0x3a001200 0x200>;
+               qcom,mactype = <0>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp3: dp3 {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <3>;
+               reg = <0x3a001400 0x200>;
+               qcom,mactype = <0>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp4: dp4 {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <4>;
+               reg = <0x3a001600 0x200>;
+               qcom,mactype = <0>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp5: dp5 {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <5>;
+               reg = <0x3a001800 0x200>;
+               qcom,mactype = <0>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp6: dp6 {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <6>;
+               reg = <0x3a001a00 0x200>;
+               qcom,mactype = <0>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp5_syn: dp5-syn {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <5>;
+               reg = <0x3a003000 0x3fff>;
+               qcom,mactype = <1>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+
+       dp6_syn: dp6-syn {
+               device_type = "network";
+               compatible = "qcom,nss-dp";
+               qcom,id = <6>;
+               reg = <0x3a007000 0x3fff>;
+               qcom,mactype = <1>;
+               local-mac-address = [000000000000];
+               phy-mode = "sgmii";
+               status = "disabled";
+       };
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-hk-cpu.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-hk-cpu.dtsi
new file mode 100644 (file)
index 0000000..37af7bb
--- /dev/null
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <dt-bindings/thermal/thermal.h>
+#include "ipq8074-cpr-regulator.dtsi"
+
+&CPU0 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+
+&CPU1 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+
+&CPU2 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+
+&CPU3 {
+       cpu-supply = <&apc_vreg>;
+       voltage-tolerance = <1>;
+};
+&cpu0_thermal {
+       trips {
+               cpu0_passive_low: cpu-passive-low {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+
+               cpu0_passive_high: cpu-passive-high {
+                       temperature = <100000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu0_passive_low>;
+                       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>;
+               };
+               map1 {
+                       trip = <&cpu0_passive_high>;
+                       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>;
+               };
+       };
+};
+
+&cpu1_thermal {
+       trips {
+               cpu1_passive_low: cpu-passive-low {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+
+               cpu1_passive_high: cpu-passive-high {
+                       temperature = <100000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu1_passive_low>;
+                       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>;
+               };
+               map1 {
+                       trip = <&cpu1_passive_high>;
+                       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>;
+               };
+       };
+};
+
+&cpu2_thermal {
+       trips {
+               cpu2_passive_low: cpu-passive-low {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+
+               cpu2_passive_high: cpu-passive-high {
+                       temperature = <100000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu2_passive_low>;
+                       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>;
+               };
+               map1 {
+                       trip = <&cpu2_passive_high>;
+                       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>;
+               };
+       };
+};
+
+&cpu3_thermal {
+       trips {
+               cpu3_passive_low: cpu-passive-low {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+
+               cpu3_passive_high: cpu-passive-high {
+                       temperature = <100000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu3_passive_low>;
+                       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>;
+               };
+               map1 {
+                       trip = <&cpu3_passive_high>;
+                       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>;
+               };
+       };
+};
+
+&cluster_thermal {
+       trips {
+               cluster_passive_low: cluster-passive {
+                       temperature = <95000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+
+               cluster_passive_high: cluster-passive-high {
+                       temperature = <100000>;
+                       hysteresis = <2000>;
+                       type = "passive";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cluster_passive_low>;
+                       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>;
+               };
+               map1 {
+                       trip = <&cluster_passive_high>;
+                       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/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts
new file mode 100644 (file)
index 0000000..d113b23
--- /dev/null
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) 2022, Karol Przybylski <itor@o2.pl>
+ * Copyright (c) 2023, Andre Valentin <avalentin@marcant.net>
+ */
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/input/input.h>
+
+
+/ {
+       model = "Zyxel NBG7815";
+       compatible = "zyxel,nbg7815", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               serial1 = &blsp1_uart3;
+               /* Alias as required by u-boot to patch MAC addresses */
+               ethernet0 = &dp1;
+               label-mac-device = &dp1;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       linux,code = <KEY_RESTART>;
+                       gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+
+&blsp1_uart3 {
+       status = "okay";
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+
+&blsp1_spi1 {
+       pinctrl-0 = <&spi_0_pins>;
+       pinctrl-names = "default";
+       cs-gpios = <0>;
+       status = "okay";
+
+       /*
+        * Bootloader will find the NAND DT node by the compatible and
+        * then "fixup" it by adding the partitions from the SMEM table
+        * using the legacy bindings thus making it impossible for us
+        * to change the partition table or utilize NVMEM for calibration.
+        * So add a dummy partitions node that bootloader will populate
+        * and set it as disabled so the kernel ignores it instead of
+        * printing warnings due to the broken way bootloader adds the
+        * partitions.
+        */
+       partitions {
+               status = "disabled";
+       };
+
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "0:sbl1";
+                               reg = <0x0 0x50000>;
+                               read-only;
+                       };
+
+                       partition@50000 {
+                               label = "0:mibib";
+                               reg = <0x50000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@60000 {
+                               label = "0:bootconfig";
+                               reg = <0x60000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@80000 {
+                               label = "0:bootconfig1";
+                               reg = <0x80000 0x20000>;
+                               read-only;
+                       };
+
+                       partition@a0000 {
+                               label = "0:qsee";
+                               reg = <0xa0000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@220000 {
+                               label = "0:qsee_1";
+                               reg = <0x220000 0x180000>;
+                               read-only;
+                       };
+
+                       partition@3a0000 {
+                               label = "0:devcfg";
+                               reg = <0x3a0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3b0000 {
+                               label = "0:devcfg_1";
+                               reg = <0x3b0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3c0000 {
+                               label = "0:apdp";
+                               reg = <0x3c0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3d0000 {
+                               label = "0:apdp_1";
+                               reg = <0x3d0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@3e0000 {
+                               label = "0:rpm";
+                               reg = <0x3e0000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@420000 {
+                               label = "0:rpm_1";
+                               reg = <0x420000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@460000 {
+                               label = "0:cdt";
+                               reg = <0x460000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@470000 {
+                               label = "0:cdt_1";
+                               reg = <0x470000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@480000 {
+                               label = "0:appsbl";
+                               reg = <0x480000 0xc0000>;
+                               read-only;
+                       };
+
+                       partition@540000 {
+                               label = "0:appsbl_1";
+                               reg = <0x540000 0xc0000>;
+                               read-only;
+                       };
+
+                       partition@600000 {
+                               compatible = "u-boot,env";
+                               label = "0:appsblenv";
+                               reg = <0x600000 0x10000>;
+
+                               macaddr_lan: ethaddr {
+                                       #nvmem-cell-cells = <1>;
+                               };
+                       };
+
+                       partition@610000 {
+                               label = "0:art";
+                               reg = <0x610000 0x40000>;
+                               read-only;
+                       };
+
+                       partition@650000 {
+                               label = "0:ethphyfw";
+                               reg = <0x650000 0x80000>;
+                               read-only;
+                       };
+
+                       partition@6d0000 {
+                               label = "0:crt";
+                               reg = <0x6d0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@6e0000 {
+                               label = "dual_flag";
+                               reg = <0x6e0000 0x10000>;
+                       };
+
+                       partition@6f0000 {
+                               label = "reserved";
+                               reg = <0x6f0000 0x110000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
+
+       qca8075_1: ethernet-phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+
+       qca8075_2: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+
+       qca8075_3: ethernet-phy@2 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <2>;
+       };
+
+       qca8075_4: ethernet-phy@3 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <3>;
+       };
+
+       qca8081: ethernet-phy@4{
+               compatible = "ethernet-phy-id004d.d101";
+               reg = <28>;
+               reset-gpios = <&tlmm 31 GPIO_ACTIVE_LOW>;
+       };
+
+       aqr113c: ethernet-phy@5 {
+               compatible = "ethernet-phy-ieee802.3-c45";
+               reg = <8>;
+               reset-gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;
+       switch_lan_bmp = <0x3e>;
+       switch_wan_bmp = <0x40>;
+       switch_mac_mode = <0x0>;
+       switch_mac_mode1 = <0xf>;
+       switch_mac_mode2 = <0xd>;
+       bm_tick_mode = <0>;
+       tm_tick_mode = <0>;
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0>;
+               };
+
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <1>;
+               };
+
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <2>;
+               };
+
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <3>;
+               };
+
+               port@4 {
+                       port_id = <5>;
+                       phy_address = <28>;
+                       port_mac_sel = "QGMAC_PORT";
+               };
+
+               port@5 {
+                       port_id = <6>;
+                       ethernet-phy-ieee802.3-c45;
+                       phy_address = <8>;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp1 {
+       status = "okay";
+       phy-handle = <&qca8075_1>;
+       label = "lan1";
+       nvmem-cells = <&macaddr_lan 0>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_2>;
+       label = "lan2";
+       nvmem-cells = <&macaddr_lan 0>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_3>;
+       label = "lan3";
+       nvmem-cells = <&macaddr_lan 0>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_4>;
+       label = "lan4";
+       nvmem-cells = <&macaddr_lan 0>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp5 {
+       status = "okay";
+       phy-handle = <&qca8081>;
+       label = "wan";
+       nvmem-cells = <&macaddr_lan 1>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp6_syn {
+       status = "okay";
+       phy-handle = <&aqr113c>;
+       label = "10g";
+       nvmem-cells = <&macaddr_lan 0>;
+       nvmem-cell-names = "mac-address";
+};
+
+&blsp1_i2c2 {
+       pinctrl-0 = <&i2c_0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       tmp103@70 {
+               compatible = "ti,tmp103";
+               reg = <0x70>;
+       };
+};
+
+&sdhc_1 {
+       status = "okay";
+       /* unstable, problem with the hs400 > h200 speed switch */
+       /delete-property/ mmc-hs400-1_8v;
+       mmc-hs200-1_8v;
+       mmc-ddr-1_8v;
+       vqmmc-supply = <&l11>;
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&ssphy_1 {
+       status = "okay";
+};
+
+&qusb_phy_1 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Zyxel-NBG7815";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-wxr-5950ax12.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-wxr-5950ax12.dts
new file mode 100644 (file)
index 0000000..32386dc
--- /dev/null
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+/dts-v1/;
+
+#include "ipq8074.dtsi"
+#include "ipq8074-hk-cpu.dtsi"
+#include "ipq8074-ess.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "Buffalo WXR-5950AX12";
+       compatible = "buffalo,wxr-5950ax12", "qcom,ipq8074";
+
+       aliases {
+               serial0 = &blsp1_uart5;
+               led-boot = &led_power_white;
+               led-failsafe = &led_power_red;
+               led-running = &led_power_white;
+               led-upgrade = &led_power_white;
+               label-mac-device = &dp5_syn;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               bootargs-append = " ubi.mtd=user_property root=/dev/ubiblock1_0";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       label = "white:router";
+                       gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_WHITE>;
+               };
+
+               led-1 {
+                       label = "red:router";
+                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led_power_red: led-2 {
+                       label = "red:power";
+                       gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_POWER;
+               };
+
+               led_power_white: led-3 {
+                       label = "white:power";
+                       gpios = <&tlmm 34 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_WHITE>;
+                       function = LED_FUNCTION_POWER;
+               };
+
+               led-4 {
+                       label = "white:internet";
+                       gpios = <&tlmm 43 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_WHITE>;
+               };
+
+               led-5 {
+                       label = "red:internet";
+                       gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led-6 {
+                       label = "red:wireless";
+                       gpios = <&tlmm 55 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_WLAN;
+               };
+
+               led-7 {
+                       label = "white:wireless";
+                       gpios = <&tlmm 56 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_WHITE>;
+                       function = LED_FUNCTION_WLAN;
+               };
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               /*
+                * mode: 3x position switch
+                *
+                * - ROUTER
+                * - AP
+                * - WB (Wireless Bridge)
+                */
+               ap {
+                       label = "mode-ap";
+                       gpios = <&tlmm 29 GPIO_ACTIVE_LOW>;
+                       linux,code = <BTN_0>;
+               };
+
+               bridge {
+                       label = "mode-wb";
+                       gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
+                       linux,code = <BTN_1>;
+               };
+
+               /*
+                * op: 2x position switch
+                *
+                * - AUTO
+                * - MANUAL (select Router/AP/WB manually)
+                */
+               manual {
+                       label = "op-manual";
+                       gpios = <&tlmm 52 GPIO_ACTIVE_LOW>;
+                       linux,code = <BTN_2>;
+               };
+
+               wps {
+                       label = "wps";
+                       gpios = <&tlmm 51 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+               };
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       reg_usb_vbus: regulator-5v-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&tlmm 64 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+};
+
+&tlmm {
+       mdio_pins: mdio-pins {
+               mdc {
+                       pins = "gpio68";
+                       function = "mdc";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+
+               mdio {
+                       pins = "gpio69";
+                       function = "mdio";
+                       drive-strength = <8>;
+                       bias-pull-up;
+               };
+       };
+};
+
+&blsp1_uart5 {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+
+               partitions {
+                       compatible = "qcom,smem-part";
+
+                       partition-0-appsblenv {
+                               compatible = "fixed-partitions";
+                               label = "0:appsblenv";
+                               read-only;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               partition@0 {
+                                       compatible = "u-boot,env";
+                                       label = "env-data";
+                                       reg = <0x0 0x40000>;
+
+                                       macaddr_appsblenv_ethaddr: ethaddr {
+                                       };
+                               };
+                       };
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       /*
+        * RESET pins of phy chips
+        *
+        * WXR-5950AX12 has 2x RESET pins for QCA8075 and AQR113C.
+        * The pin of QCA8075 is for the chip and not phys in the chip, the
+        * pin of AQR113C is for 2x chips. So both pins are not appropriate
+        * to declare them as reset-gpios in phy nodes.
+        * Multiple entries in reset-gpios of mdio may not be supported, but
+        * leave the following as-is to show that the those reset pin exists.
+        */
+       reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>, /* QCA8075 RESET */
+                     <&tlmm 63 GPIO_ACTIVE_LOW>; /* AQR113C RESET (2x) */
+
+       aqr113c_1: ethernet-phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c45";
+               reg = <0x0>;
+       };
+
+       aqr113c_2: ethernet-phy@8 {
+               compatible = "ethernet-phy-ieee802.3-c45";
+               reg = <0x8>;
+       };
+
+       qca8075_1: ethernet-phy@18 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x18>;
+       };
+
+       qca8075_2: ethernet-phy@19 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x19>;
+       };
+
+       qca8075_3: ethernet-phy@1a {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x1a>;
+       };
+
+       qca8075_4: ethernet-phy@1b {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x1b>;
+       };
+
+       qca8075_5: ethernet-phy@1c {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x1c>;
+       };
+};
+
+&switch {
+       status = "okay";
+
+       switch_cpu_bmp = <0x1>;
+       switch_lan_bmp = <0x3e>;
+       switch_wan_bmp = <0x40>;
+       switch_mac_mode = <0xb>;
+       switch_mac_mode1 = <0xd>;
+       switch_mac_mode2 = <0xd>;
+       bm_tick_mode = <0>;
+       tm_tick_mode = <0>;
+
+       qcom,port_phyinfo {
+               port@0 {
+                       port_id = <1>;
+                       phy_address = <0x18>;
+               };
+
+               port@1 {
+                       port_id = <2>;
+                       phy_address = <0x19>;
+               };
+
+               port@2 {
+                       port_id = <3>;
+                       phy_address = <0x1a>;
+               };
+
+               port@3 {
+                       port_id = <4>;
+                       phy_address = <0x1b>;
+               };
+
+               port@4 {
+                       port_id = <5>;
+                       ethernet-phy-ieee802.3-c45;
+                       phy_address = <0x0>;
+               };
+
+               port@5 {
+                       port_id = <6>;
+                       ethernet-phy-ieee802.3-c45;
+                       phy_address = <0x8>;
+               };
+       };
+};
+
+&edma {
+       status = "okay";
+};
+
+&dp2 {
+       status = "okay";
+       phy-handle = <&qca8075_2>;
+       label = "lan4";
+       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp3 {
+       status = "okay";
+       phy-handle = <&qca8075_3>;
+       label = "lan3";
+       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp4 {
+       status = "okay";
+       phy-handle = <&qca8075_4>;
+       label = "lan2";
+       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp5_syn {
+       status = "okay";
+       phy-handle = <&aqr113c_1>;
+       label = "wan";
+       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
+       nvmem-cell-names = "mac-address";
+};
+
+&dp6_syn {
+       status = "okay";
+       phy-handle = <&aqr113c_2>;
+       label = "lan1";
+       nvmem-cells = <&macaddr_appsblenv_ethaddr>;
+       nvmem-cell-names = "mac-address";
+};
+
+&ssphy_0 {
+       status = "okay";
+};
+
+&qusb_phy_0 {
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+
+       vbus-supply = <&reg_usb_vbus>;
+};
+
+&wifi {
+       status = "okay";
+
+       qcom,ath11k-calibration-variant = "Buffalo-WXR-5950AX12";
+};
diff --git a/target/linux/qualcommax/generic/target.mk b/target/linux/qualcommax/generic/target.mk
new file mode 100644 (file)
index 0000000..f5cb1fb
--- /dev/null
@@ -0,0 +1 @@
+BOARDNAME:=Generic
diff --git a/target/linux/qualcommax/image/Makefile b/target/linux/qualcommax/image/Makefile
new file mode 100644 (file)
index 0000000..f59ad0c
--- /dev/null
@@ -0,0 +1,17 @@
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Device/Default
+       PROFILES := Default
+       KERNEL_LOADADDR := 0x41000000
+       DEVICE_DTS = $$(SOC)-$(lastword $(subst _, ,$(1)))
+       DEVICE_DTS_CONFIG := config@1
+       DEVICE_DTS_DIR := $(DTS_DIR)/qcom
+       IMAGES := sysupgrade.bin
+       IMAGE/sysupgrade.bin = sysupgrade-tar | append-metadata
+       IMAGE/sysupgrade.bin/squashfs :=
+endef
+
+include $(SUBTARGET).mk
+
+$(eval $(call BuildImage))
diff --git a/target/linux/qualcommax/image/generic.mk b/target/linux/qualcommax/image/generic.mk
new file mode 100644 (file)
index 0000000..6003f2a
--- /dev/null
@@ -0,0 +1,188 @@
+define Device/FitImage
+       KERNEL_SUFFIX := -uImage.itb
+       KERNEL = kernel-bin | libdeflate-gzip | fit gzip $$(KDIR)/image-$$(DEVICE_DTS).dtb
+       KERNEL_NAME := Image
+endef
+
+define Device/FitImageLzma
+       KERNEL_SUFFIX := -uImage.itb
+       KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
+       KERNEL_NAME := Image
+endef
+
+define Device/EmmcImage
+       IMAGES += factory.bin sysupgrade.bin
+       IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to 64k
+       IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-to 64k | sysupgrade-tar rootfs=$$$$@ | append-metadata
+endef
+
+define Device/UbiFit
+       KERNEL_IN_UBI := 1
+       IMAGES := factory.ubi sysupgrade.bin
+       IMAGE/factory.ubi := append-ubi
+       IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+endef
+
+define Device/buffalo_wxr-5950ax12
+       $(call Device/FitImage)
+       DEVICE_VENDOR := Buffalo
+       DEVICE_MODEL := WXR-5950AX12
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@hk01
+       SOC := ipq8074
+       IMAGES := sysupgrade.bin
+       IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+       DEVICE_PACKAGES := ipq-wifi-buffalo_wxr-5950ax12
+endef
+TARGET_DEVICES += buffalo_wxr-5950ax12
+
+define Device/compex_wpq873
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_VENDOR := Compex
+       DEVICE_MODEL := WPQ873
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@hk09.wpq873
+       SOC := ipq8072
+       IMAGE/factory.ubi := append-ubi | qsdk-ipq-factory-nand
+endef
+TARGET_DEVICES += compex_wpq873
+
+define Device/dynalink_dl-wrx36
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_VENDOR := Dynalink
+       DEVICE_MODEL := DL-WRX36
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@rt5010w-d350-rev0
+       SOC := ipq8072
+       DEVICE_PACKAGES := ipq-wifi-dynalink_dl-wrx36
+endef
+TARGET_DEVICES += dynalink_dl-wrx36
+
+define Device/edgecore_eap102
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_VENDOR := Edgecore
+       DEVICE_MODEL := EAP102
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@ac02
+       SOC := ipq8071
+       DEVICE_PACKAGES := ipq-wifi-edgecore_eap102
+       IMAGE/factory.ubi := append-ubi | qsdk-ipq-factory-nand
+endef
+TARGET_DEVICES += edgecore_eap102
+
+define Device/edimax_cax1800
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_VENDOR := Edimax
+       DEVICE_MODEL := CAX1800
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@ac03
+       SOC := ipq8070
+       DEVICE_PACKAGES := ipq-wifi-edimax_cax1800
+endef
+TARGET_DEVICES += edimax_cax1800
+
+define Device/netgear_wax218
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       ARTIFACTS := web-ui-factory.fit
+       DEVICE_VENDOR := Netgear
+       DEVICE_MODEL := WAX218
+       DEVICE_DTS_CONFIG := config@hk07
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       SOC := ipq8072
+       ARTIFACT/web-ui-factory.fit := append-image initramfs-uImage.itb | \
+               ubinize-kernel | qsdk-ipq-factory-nand
+       DEVICE_PACKAGES := kmod-spi-gpio kmod-spi-bitbang kmod-gpio-nxp-74hc164 \
+               ipq-wifi-netgear_wax218
+endef
+TARGET_DEVICES += netgear_wax218
+
+define Device/prpl_haze
+       $(call Device/FitImage)
+       $(call Device/EmmcImage)
+       DEVICE_VENDOR := prpl Foundation
+       DEVICE_MODEL := Haze
+       DEVICE_DTS_CONFIG := config@hk09
+       SOC := ipq8072
+       DEVICE_PACKAGES += ath11k-firmware-qcn9074 ipq-wifi-prpl_haze kmod-ath11k-pci
+endef
+TARGET_DEVICES += prpl_haze
+
+define Device/qnap_301w
+       $(call Device/FitImage)
+       $(call Device/EmmcImage)
+       DEVICE_VENDOR := QNAP
+       DEVICE_MODEL := 301w
+       DEVICE_DTS_CONFIG := config@hk01
+       KERNEL_SIZE := 16384k
+       SOC := ipq8072
+       DEVICE_PACKAGES += ipq-wifi-qnap_301w
+endef
+TARGET_DEVICES += qnap_301w
+
+define Device/redmi_ax6
+       $(call Device/xiaomi_ax3600)
+       DEVICE_VENDOR := Redmi
+       DEVICE_MODEL := AX6
+       DEVICE_PACKAGES := ipq-wifi-redmi_ax6
+endef
+TARGET_DEVICES += redmi_ax6
+
+define Device/xiaomi_ax3600
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_VENDOR := Xiaomi
+       DEVICE_MODEL := AX3600
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@ac04
+       SOC := ipq8071
+       KERNEL_SIZE := 36608k
+       DEVICE_PACKAGES := ipq-wifi-xiaomi_ax3600 kmod-ath10k-ct-smallbuffers ath10k-firmware-qca9887-ct
+ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+       ARTIFACTS := initramfs-factory.ubi
+       ARTIFACT/initramfs-factory.ubi := append-image-stage initramfs-uImage.itb | ubinize-kernel
+endif
+endef
+TARGET_DEVICES += xiaomi_ax3600
+
+define Device/xiaomi_ax9000
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_VENDOR := Xiaomi
+       DEVICE_MODEL := AX9000
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_DTS_CONFIG := config@hk14
+       SOC := ipq8072
+       KERNEL_SIZE := 57344k
+       DEVICE_PACKAGES := ipq-wifi-xiaomi_ax9000 kmod-ath11k-pci ath11k-firmware-qcn9074 \
+       kmod-ath10k-ct ath10k-firmware-qca9887-ct
+ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+       ARTIFACTS := initramfs-factory.ubi
+       ARTIFACT/initramfs-factory.ubi := append-image-stage initramfs-uImage.itb | ubinize-kernel
+endif
+endef
+TARGET_DEVICES += xiaomi_ax9000
+
+define Device/zyxel_nbg7815
+       $(call Device/FitImage)
+       $(call Device/EmmcImage)
+       DEVICE_VENDOR := ZYXEL
+       DEVICE_MODEL := NBG7815
+       DEVICE_DTS_CONFIG := config@nbg7815
+       SOC := ipq8074
+       DEVICE_PACKAGES += ipq-wifi-zyxel_nbg7815 kmod-ath11k-pci kmod-hwmon-tmp103 \
+               kmod-bluetooth
+endef
+TARGET_DEVICES += zyxel_nbg7815
diff --git a/target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch b/target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch
new file mode 100644 (file)
index 0000000..dd57eae
--- /dev/null
@@ -0,0 +1,32 @@
+From 6463c10bfdbd684ec7ecfd408ea541283215a088 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:06:28 +0200
+Subject: [PATCH] arm64: dts: qcom: ipq8074: add A53 PLL node
+
+Add the required node for A53 PLL which will be used to provide the CPU
+clock via APCS for APSS scaling.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220818220628.339366-9-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -675,6 +675,14 @@
+                       #mbox-cells = <1>;
+               };
++              a53pll: clock@b116000 {
++                      compatible = "qcom,ipq8074-a53pll";
++                      reg = <0x0b116000 0x40>;
++                      #clock-cells = <0>;
++                      clocks = <&xo>;
++                      clock-names = "xo";
++              };
++
+               timer@b120000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
diff --git a/target/linux/qualcommax/patches-6.1/0002-v6.2-thermal-drivers-tsens-Add-support-for-combined-inter.patch b/target/linux/qualcommax/patches-6.1/0002-v6.2-thermal-drivers-tsens-Add-support-for-combined-inter.patch
new file mode 100644 (file)
index 0000000..0320725
--- /dev/null
@@ -0,0 +1,134 @@
+From e593e834fe8ba9bf314d8215ac05d8787f81efda Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:02:42 +0200
+Subject: [PATCH] thermal/drivers/tsens: Add support for combined interrupt
+
+Despite using tsens v2.3 IP, IPQ8074 and IPQ6018 only have one IRQ for
+signaling both up/low and critical trips.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220818220245.338396-2-robimarko@gmail.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/qcom/tsens-8960.c |  1 +
+ drivers/thermal/qcom/tsens-v0_1.c |  1 +
+ drivers/thermal/qcom/tsens-v1.c   |  1 +
+ drivers/thermal/qcom/tsens-v2.c   |  1 +
+ drivers/thermal/qcom/tsens.c      | 38 ++++++++++++++++++++++++++-----
+ drivers/thermal/qcom/tsens.h      |  2 ++
+ 6 files changed, 38 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/qcom/tsens-8960.c
++++ b/drivers/thermal/qcom/tsens-8960.c
+@@ -269,6 +269,7 @@ static const struct tsens_ops ops_8960 =
+ static struct tsens_features tsens_8960_feat = {
+       .ver_major      = VER_0,
+       .crit_int       = 0,
++      .combo_int      = 0,
+       .adc            = 1,
+       .srot_split     = 0,
+       .max_sensors    = 11,
+--- a/drivers/thermal/qcom/tsens-v0_1.c
++++ b/drivers/thermal/qcom/tsens-v0_1.c
+@@ -549,6 +549,7 @@ static int __init init_8939(struct tsens
+ static struct tsens_features tsens_v0_1_feat = {
+       .ver_major      = VER_0_1,
+       .crit_int       = 0,
++      .combo_int      = 0,
+       .adc            = 1,
+       .srot_split     = 1,
+       .max_sensors    = 11,
+--- a/drivers/thermal/qcom/tsens-v1.c
++++ b/drivers/thermal/qcom/tsens-v1.c
+@@ -273,6 +273,7 @@ static int calibrate_8976(struct tsens_p
+ static struct tsens_features tsens_v1_feat = {
+       .ver_major      = VER_1_X,
+       .crit_int       = 0,
++      .combo_int      = 0,
+       .adc            = 1,
+       .srot_split     = 1,
+       .max_sensors    = 11,
+--- a/drivers/thermal/qcom/tsens-v2.c
++++ b/drivers/thermal/qcom/tsens-v2.c
+@@ -31,6 +31,7 @@
+ static struct tsens_features tsens_v2_feat = {
+       .ver_major      = VER_2_X,
+       .crit_int       = 1,
++      .combo_int      = 0,
+       .adc            = 0,
+       .srot_split     = 1,
+       .max_sensors    = 16,
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -532,6 +532,27 @@ static irqreturn_t tsens_irq_thread(int
+       return IRQ_HANDLED;
+ }
++/**
++ * tsens_combined_irq_thread() - Threaded interrupt handler for combined interrupts
++ * @irq: irq number
++ * @data: tsens controller private data
++ *
++ * Handle the combined interrupt as if it were 2 separate interrupts, so call the
++ * critical handler first and then the up/low one.
++ *
++ * Return: IRQ_HANDLED
++ */
++static irqreturn_t tsens_combined_irq_thread(int irq, void *data)
++{
++      irqreturn_t ret;
++
++      ret = tsens_critical_irq_thread(irq, data);
++      if (ret != IRQ_HANDLED)
++              return ret;
++
++      return tsens_irq_thread(irq, data);
++}
++
+ static int tsens_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+       struct tsens_sensor *s = tz->devdata;
+@@ -1074,13 +1095,18 @@ static int tsens_register(struct tsens_p
+                                  tsens_mC_to_hw(priv->sensor, 0));
+       }
+-      ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
+-      if (ret < 0)
+-              return ret;
++      if (priv->feat->combo_int) {
++              ret = tsens_register_irq(priv, "combined",
++                                       tsens_combined_irq_thread);
++      } else {
++              ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
++              if (ret < 0)
++                      return ret;
+-      if (priv->feat->crit_int)
+-              ret = tsens_register_irq(priv, "critical",
+-                                       tsens_critical_irq_thread);
++              if (priv->feat->crit_int)
++                      ret = tsens_register_irq(priv, "critical",
++                                               tsens_critical_irq_thread);
++      }
+       return ret;
+ }
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -493,6 +493,7 @@ enum regfield_ids {
+  * struct tsens_features - Features supported by the IP
+  * @ver_major: Major number of IP version
+  * @crit_int: does the IP support critical interrupts?
++ * @combo_int: does the IP use one IRQ for up, low and critical thresholds?
+  * @adc:      do the sensors only output adc code (instead of temperature)?
+  * @srot_split: does the IP neatly splits the register space into SROT and TM,
+  *              with SROT only being available to secure boot firmware?
+@@ -502,6 +503,7 @@ enum regfield_ids {
+ struct tsens_features {
+       unsigned int ver_major;
+       unsigned int crit_int:1;
++      unsigned int combo_int:1;
+       unsigned int adc:1;
+       unsigned int srot_split:1;
+       unsigned int has_watchdog:1;
diff --git a/target/linux/qualcommax/patches-6.1/0003-v6.2-thermal-drivers-tsens-Allow-configuring-min-and-max-.patch b/target/linux/qualcommax/patches-6.1/0003-v6.2-thermal-drivers-tsens-Allow-configuring-min-and-max-.patch
new file mode 100644 (file)
index 0000000..3630618
--- /dev/null
@@ -0,0 +1,101 @@
+From 7805365fee582056b32c69cf35aafbb94b14a8ca Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:02:43 +0200
+Subject: [PATCH] thermal/drivers/tsens: Allow configuring min and max trips
+
+IPQ8074 and IPQ6018 dont support negative trip temperatures and support
+up to 204 degrees C as the max trip temperature.
+
+So, instead of always setting the -40 as min and 120 degrees C as max
+allow it to be configured as part of the features.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Link: https://lore.kernel.org/r/20220818220245.338396-3-robimarko@gmail.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/qcom/tsens-8960.c | 2 ++
+ drivers/thermal/qcom/tsens-v0_1.c | 2 ++
+ drivers/thermal/qcom/tsens-v1.c   | 2 ++
+ drivers/thermal/qcom/tsens-v2.c   | 2 ++
+ drivers/thermal/qcom/tsens.c      | 4 ++--
+ drivers/thermal/qcom/tsens.h      | 4 ++++
+ 6 files changed, 14 insertions(+), 2 deletions(-)
+
+--- a/drivers/thermal/qcom/tsens-8960.c
++++ b/drivers/thermal/qcom/tsens-8960.c
+@@ -273,6 +273,8 @@ static struct tsens_features tsens_8960_
+       .adc            = 1,
+       .srot_split     = 0,
+       .max_sensors    = 11,
++      .trip_min_temp  = -40000,
++      .trip_max_temp  = 120000,
+ };
+ struct tsens_plat_data data_8960 = {
+--- a/drivers/thermal/qcom/tsens-v0_1.c
++++ b/drivers/thermal/qcom/tsens-v0_1.c
+@@ -553,6 +553,8 @@ static struct tsens_features tsens_v0_1_
+       .adc            = 1,
+       .srot_split     = 1,
+       .max_sensors    = 11,
++      .trip_min_temp  = -40000,
++      .trip_max_temp  = 120000,
+ };
+ static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
+--- a/drivers/thermal/qcom/tsens-v1.c
++++ b/drivers/thermal/qcom/tsens-v1.c
+@@ -277,6 +277,8 @@ static struct tsens_features tsens_v1_fe
+       .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] = {
+--- a/drivers/thermal/qcom/tsens-v2.c
++++ b/drivers/thermal/qcom/tsens-v2.c
+@@ -35,6 +35,8 @@ static struct tsens_features tsens_v2_fe
+       .adc            = 0,
+       .srot_split     = 1,
+       .max_sensors    = 16,
++      .trip_min_temp  = -40000,
++      .trip_max_temp  = 120000,
+ };
+ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -573,8 +573,8 @@ static int tsens_set_trips(struct therma
+       dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
+               hw_id, __func__, low, high);
+-      cl_high = clamp_val(high, -40000, 120000);
+-      cl_low  = clamp_val(low, -40000, 120000);
++      cl_high = clamp_val(high, priv->feat->trip_min_temp, priv->feat->trip_max_temp);
++      cl_low  = clamp_val(low, priv->feat->trip_min_temp, priv->feat->trip_max_temp);
+       high_val = tsens_mC_to_hw(s, cl_high);
+       low_val  = tsens_mC_to_hw(s, cl_low);
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -499,6 +499,8 @@ enum regfield_ids {
+  *              with SROT only being available to secure boot firmware?
+  * @has_watchdog: does this IP support watchdog functionality?
+  * @max_sensors: maximum sensors supported by this version of the IP
++ * @trip_min_temp: minimum trip temperature supported by this version of the IP
++ * @trip_max_temp: maximum trip temperature supported by this version of the IP
+  */
+ struct tsens_features {
+       unsigned int ver_major;
+@@ -508,6 +510,8 @@ struct tsens_features {
+       unsigned int srot_split:1;
+       unsigned int has_watchdog:1;
+       unsigned int max_sensors;
++      int trip_min_temp;
++      int trip_max_temp;
+ };
+ /**
diff --git a/target/linux/qualcommax/patches-6.1/0004-v6.2-thermal-drivers-tsens-Add-IPQ8074-support.patch b/target/linux/qualcommax/patches-6.1/0004-v6.2-thermal-drivers-tsens-Add-IPQ8074-support.patch
new file mode 100644 (file)
index 0000000..eaea693
--- /dev/null
@@ -0,0 +1,74 @@
+From 0164d794cbc58488a7321272e95958d10cf103a4 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:02:44 +0200
+Subject: [PATCH] thermal/drivers/tsens: Add IPQ8074 support
+
+Qualcomm IPQ8074 uses tsens v2.3 IP, however unlike other tsens v2 IP
+it only has one IRQ, that is used for up/low as well as critical.
+It also does not support negative trip temperatures.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Link: https://lore.kernel.org/r/20220818220245.338396-4-robimarko@gmail.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/qcom/tsens-v2.c | 17 +++++++++++++++++
+ drivers/thermal/qcom/tsens.c    |  3 +++
+ drivers/thermal/qcom/tsens.h    |  2 +-
+ 3 files changed, 21 insertions(+), 1 deletion(-)
+
+--- a/drivers/thermal/qcom/tsens-v2.c
++++ b/drivers/thermal/qcom/tsens-v2.c
+@@ -39,6 +39,17 @@ static struct tsens_features tsens_v2_fe
+       .trip_max_temp  = 120000,
+ };
++static struct tsens_features ipq8074_feat = {
++      .ver_major      = VER_2_X,
++      .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 */
+@@ -104,6 +115,12 @@ struct tsens_plat_data data_tsens_v2 = {
+       .fields = tsens_v2_regfields,
+ };
++struct tsens_plat_data data_ipq8074 = {
++      .ops            = &ops_generic_v2,
++      .feat           = &ipq8074_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
+@@ -981,6 +981,9 @@ static const struct of_device_id tsens_t
+               .compatible = "qcom,ipq8064-tsens",
+               .data = &data_8960,
+       }, {
++              .compatible = "qcom,ipq8074-tsens",
++              .data = &data_ipq8074,
++      }, {
+               .compatible = "qcom,mdm9607-tsens",
+               .data = &data_9607,
+       }, {
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -597,6 +597,6 @@ extern struct tsens_plat_data data_8916,
+ extern struct tsens_plat_data data_tsens_v1, data_8976, data_8956;
+ /* TSENS v2 targets */
+-extern struct tsens_plat_data data_8996, data_tsens_v2;
++extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
+ #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch b/target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch
new file mode 100644 (file)
index 0000000..bad75e4
--- /dev/null
@@ -0,0 +1,130 @@
+From c3cc0c2a17f552be2426200e47a9e2c62cf449ce Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:02:45 +0200
+Subject: [PATCH] arm64: dts: qcom: ipq8074: add thermal nodes
+
+IPQ8074 has a tsens v2.3.0 peripheral which monitors
+temperatures around the various subsystems on the
+die.
+
+So lets add the tsens and thermal zone nodes, passive
+CPU cooling will come in later patches after CPU frequency
+scaling is supported.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220818220245.338396-5-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 96 +++++++++++++++++++++++++++
+ 1 file changed, 96 insertions(+)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -274,6 +274,16 @@
+                       status = "disabled";
+               };
++              tsens: thermal-sensor@4a9000 {
++                      compatible = "qcom,ipq8074-tsens";
++                      reg = <0x4a9000 0x1000>, /* TM */
++                            <0x4a8000 0x1000>; /* SROT */
++                      interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "combined";
++                      #qcom,sensors = <16>;
++                      #thermal-sensor-cells = <1>;
++              };
++
+               cryptobam: dma-controller@704000 {
+                       compatible = "qcom,bam-v1.7.0";
+                       reg = <0x00704000 0x20000>;
+@@ -874,4 +884,90 @@
+                            <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+       };
++
++      thermal-zones {
++              nss-top-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 4>;
++              };
++
++              nss0-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 5>;
++              };
++
++              nss1-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 6>;
++              };
++
++              wcss-phya0-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 7>;
++              };
++
++              wcss-phya1-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 8>;
++              };
++
++              cpu0_thermal: cpu0-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 9>;
++              };
++
++              cpu1_thermal: cpu1-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 10>;
++              };
++
++              cpu2_thermal: cpu2-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 11>;
++              };
++
++              cpu3_thermal: cpu3-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 12>;
++              };
++
++              cluster_thermal: cluster-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 13>;
++              };
++
++              wcss-phyb0-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 14>;
++              };
++
++              wcss-phyb1-thermal {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&tsens 15>;
++              };
++      };
+ };
diff --git a/target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch b/target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch
new file mode 100644 (file)
index 0000000..e229851
--- /dev/null
@@ -0,0 +1,29 @@
+From 0df592a0a1a3fff9133977192677aa915afc174f Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:08:49 +0200
+Subject: [PATCH] arm64: dts: qcom: ipq8074: add clocks to APCS
+
+APCS now has support for providing the APSS clocks as the child device
+for IPQ8074.
+
+So, add the A53 PLL and XO clocks in order to use APCS as the CPU
+clocksource for APSS scaling.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220818220849.339732-4-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -680,6 +680,8 @@
+               apcs_glb: mailbox@b111000 {
+                       compatible = "qcom,ipq8074-apcs-apps-global";
+                       reg = <0x0b111000 0x1000>;
++                      clocks = <&a53pll>, <&xo>;
++                      clock-names = "pll", "xo";
+                       #clock-cells = <1>;
+                       #mbox-cells = <1>;
diff --git a/target/linux/qualcommax/patches-6.1/0007-v6.2-clk-qcom-ipq8074-convert-to-parent-data.patch b/target/linux/qualcommax/patches-6.1/0007-v6.2-clk-qcom-ipq8074-convert-to-parent-data.patch
new file mode 100644 (file)
index 0000000..9162ea5
--- /dev/null
@@ -0,0 +1,3601 @@
+From e6c5115d6845f25eda7e162dcd783a2044215867 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Sun, 30 Oct 2022 18:57:01 +0100
+Subject: [PATCH] clk: qcom: ipq8074: convert to parent data
+
+Convert the IPQ8074 GCC driver to use parent data instead of global
+name matching.
+
+Utilize ARRAY_SIZE for num_parents instead of hardcoding the value.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221030175703.1103224-1-robimarko@gmail.com
+---
+ drivers/clk/qcom/gcc-ipq8074.c | 1781 +++++++++++++++-----------------
+ 1 file changed, 813 insertions(+), 968 deletions(-)
+
+--- a/drivers/clk/qcom/gcc-ipq8074.c
++++ b/drivers/clk/qcom/gcc-ipq8074.c
+@@ -49,349 +49,6 @@ enum {
+       P_UNIPHY2_TX,
+ };
+-static const char * const gcc_xo_gpll0_gpll0_out_main_div2[] = {
+-      "xo",
+-      "gpll0",
+-      "gpll0_out_main_div2",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-      { P_GPLL0_DIV2, 4 },
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-};
+-
+-static const char * const gcc_xo_gpll0_gpll2_gpll0_out_main_div2[] = {
+-      "xo",
+-      "gpll0",
+-      "gpll2",
+-      "gpll0_out_main_div2",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-      { P_GPLL2, 2 },
+-      { P_GPLL0_DIV2, 4 },
+-};
+-
+-static const char * const gcc_xo_gpll0_sleep_clk[] = {
+-      "xo",
+-      "gpll0",
+-      "sleep_clk",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_sleep_clk_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 2 },
+-      { P_SLEEP_CLK, 6 },
+-};
+-
+-static const char * const gcc_xo_gpll6_gpll0_gpll0_out_main_div2[] = {
+-      "xo",
+-      "gpll6",
+-      "gpll0",
+-      "gpll0_out_main_div2",
+-};
+-
+-static const struct parent_map gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL6, 1 },
+-      { P_GPLL0, 3 },
+-      { P_GPLL0_DIV2, 4 },
+-};
+-
+-static const char * const gcc_xo_gpll0_out_main_div2_gpll0[] = {
+-      "xo",
+-      "gpll0_out_main_div2",
+-      "gpll0",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_out_main_div2_gpll0_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0_DIV2, 2 },
+-      { P_GPLL0, 1 },
+-};
+-
+-static const char * const gcc_usb3phy_0_cc_pipe_clk_xo[] = {
+-      "usb3phy_0_cc_pipe_clk",
+-      "xo",
+-};
+-
+-static const struct parent_map gcc_usb3phy_0_cc_pipe_clk_xo_map[] = {
+-      { P_USB3PHY_0_PIPE, 0 },
+-      { P_XO, 2 },
+-};
+-
+-static const char * const gcc_usb3phy_1_cc_pipe_clk_xo[] = {
+-      "usb3phy_1_cc_pipe_clk",
+-      "xo",
+-};
+-
+-static const struct parent_map gcc_usb3phy_1_cc_pipe_clk_xo_map[] = {
+-      { P_USB3PHY_1_PIPE, 0 },
+-      { P_XO, 2 },
+-};
+-
+-static const char * const gcc_pcie20_phy0_pipe_clk_xo[] = {
+-      "pcie20_phy0_pipe_clk",
+-      "xo",
+-};
+-
+-static const struct parent_map gcc_pcie20_phy0_pipe_clk_xo_map[] = {
+-      { P_PCIE20_PHY0_PIPE, 0 },
+-      { P_XO, 2 },
+-};
+-
+-static const char * const gcc_pcie20_phy1_pipe_clk_xo[] = {
+-      "pcie20_phy1_pipe_clk",
+-      "xo",
+-};
+-
+-static const struct parent_map gcc_pcie20_phy1_pipe_clk_xo_map[] = {
+-      { P_PCIE20_PHY1_PIPE, 0 },
+-      { P_XO, 2 },
+-};
+-
+-static const char * const gcc_xo_gpll0_gpll6_gpll0_div2[] = {
+-      "xo",
+-      "gpll0",
+-      "gpll6",
+-      "gpll0_out_main_div2",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_div2_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-      { P_GPLL6, 2 },
+-      { P_GPLL0_DIV2, 4 },
+-};
+-
+-static const char * const gcc_xo_gpll0_gpll6_gpll0_out_main_div2[] = {
+-      "xo",
+-      "gpll0",
+-      "gpll6",
+-      "gpll0_out_main_div2",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-      { P_GPLL6, 2 },
+-      { P_GPLL0_DIV2, 3 },
+-};
+-
+-static const char * const gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = {
+-      "xo",
+-      "bias_pll_nss_noc_clk",
+-      "gpll0",
+-      "gpll2",
+-};
+-
+-static const struct parent_map gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map[] = {
+-      { P_XO, 0 },
+-      { P_BIAS_PLL_NSS_NOC, 1 },
+-      { P_GPLL0, 2 },
+-      { P_GPLL2, 3 },
+-};
+-
+-static const char * const gcc_xo_nss_crypto_pll_gpll0[] = {
+-      "xo",
+-      "nss_crypto_pll",
+-      "gpll0",
+-};
+-
+-static const struct parent_map gcc_xo_nss_crypto_pll_gpll0_map[] = {
+-      { P_XO, 0 },
+-      { P_NSS_CRYPTO_PLL, 1 },
+-      { P_GPLL0, 2 },
+-};
+-
+-static const char * const gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6[] = {
+-      "xo",
+-      "ubi32_pll",
+-      "gpll0",
+-      "gpll2",
+-      "gpll4",
+-      "gpll6",
+-};
+-
+-static const struct parent_map gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map[] = {
+-      { P_XO, 0 },
+-      { P_UBI32_PLL, 1 },
+-      { P_GPLL0, 2 },
+-      { P_GPLL2, 3 },
+-      { P_GPLL4, 4 },
+-      { P_GPLL6, 5 },
+-};
+-
+-static const char * const gcc_xo_gpll0_out_main_div2[] = {
+-      "xo",
+-      "gpll0_out_main_div2",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_out_main_div2_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0_DIV2, 1 },
+-};
+-
+-static const char * const gcc_xo_bias_gpll0_gpll4_nss_ubi32[] = {
+-      "xo",
+-      "bias_pll_cc_clk",
+-      "gpll0",
+-      "gpll4",
+-      "nss_crypto_pll",
+-      "ubi32_pll",
+-};
+-
+-static const struct parent_map gcc_xo_bias_gpll0_gpll4_nss_ubi32_map[] = {
+-      { P_XO, 0 },
+-      { P_BIAS_PLL, 1 },
+-      { P_GPLL0, 2 },
+-      { P_GPLL4, 3 },
+-      { P_NSS_CRYPTO_PLL, 4 },
+-      { P_UBI32_PLL, 5 },
+-};
+-
+-static const char * const gcc_xo_gpll0_gpll4[] = {
+-      "xo",
+-      "gpll0",
+-      "gpll4",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-      { P_GPLL4, 2 },
+-};
+-
+-static const char * const gcc_xo_uniphy0_rx_tx_ubi32_bias[] = {
+-      "xo",
+-      "uniphy0_gcc_rx_clk",
+-      "uniphy0_gcc_tx_clk",
+-      "ubi32_pll",
+-      "bias_pll_cc_clk",
+-};
+-
+-static const struct parent_map gcc_xo_uniphy0_rx_tx_ubi32_bias_map[] = {
+-      { P_XO, 0 },
+-      { P_UNIPHY0_RX, 1 },
+-      { P_UNIPHY0_TX, 2 },
+-      { P_UBI32_PLL, 5 },
+-      { P_BIAS_PLL, 6 },
+-};
+-
+-static const char * const gcc_xo_uniphy0_tx_rx_ubi32_bias[] = {
+-      "xo",
+-      "uniphy0_gcc_tx_clk",
+-      "uniphy0_gcc_rx_clk",
+-      "ubi32_pll",
+-      "bias_pll_cc_clk",
+-};
+-
+-static const struct parent_map gcc_xo_uniphy0_tx_rx_ubi32_bias_map[] = {
+-      { P_XO, 0 },
+-      { P_UNIPHY0_TX, 1 },
+-      { P_UNIPHY0_RX, 2 },
+-      { P_UBI32_PLL, 5 },
+-      { P_BIAS_PLL, 6 },
+-};
+-
+-static const char * const gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
+-      "xo",
+-      "uniphy0_gcc_rx_clk",
+-      "uniphy0_gcc_tx_clk",
+-      "uniphy1_gcc_rx_clk",
+-      "uniphy1_gcc_tx_clk",
+-      "ubi32_pll",
+-      "bias_pll_cc_clk",
+-};
+-
+-static const struct parent_map
+-gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = {
+-      { P_XO, 0 },
+-      { P_UNIPHY0_RX, 1 },
+-      { P_UNIPHY0_TX, 2 },
+-      { P_UNIPHY1_RX, 3 },
+-      { P_UNIPHY1_TX, 4 },
+-      { P_UBI32_PLL, 5 },
+-      { P_BIAS_PLL, 6 },
+-};
+-
+-static const char * const gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
+-      "xo",
+-      "uniphy0_gcc_tx_clk",
+-      "uniphy0_gcc_rx_clk",
+-      "uniphy1_gcc_tx_clk",
+-      "uniphy1_gcc_rx_clk",
+-      "ubi32_pll",
+-      "bias_pll_cc_clk",
+-};
+-
+-static const struct parent_map
+-gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = {
+-      { P_XO, 0 },
+-      { P_UNIPHY0_TX, 1 },
+-      { P_UNIPHY0_RX, 2 },
+-      { P_UNIPHY1_TX, 3 },
+-      { P_UNIPHY1_RX, 4 },
+-      { P_UBI32_PLL, 5 },
+-      { P_BIAS_PLL, 6 },
+-};
+-
+-static const char * const gcc_xo_uniphy2_rx_tx_ubi32_bias[] = {
+-      "xo",
+-      "uniphy2_gcc_rx_clk",
+-      "uniphy2_gcc_tx_clk",
+-      "ubi32_pll",
+-      "bias_pll_cc_clk",
+-};
+-
+-static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
+-      { P_XO, 0 },
+-      { P_UNIPHY2_RX, 1 },
+-      { P_UNIPHY2_TX, 2 },
+-      { P_UBI32_PLL, 5 },
+-      { P_BIAS_PLL, 6 },
+-};
+-
+-static const char * const gcc_xo_uniphy2_tx_rx_ubi32_bias[] = {
+-      "xo",
+-      "uniphy2_gcc_tx_clk",
+-      "uniphy2_gcc_rx_clk",
+-      "ubi32_pll",
+-      "bias_pll_cc_clk",
+-};
+-
+-static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
+-      { P_XO, 0 },
+-      { P_UNIPHY2_TX, 1 },
+-      { P_UNIPHY2_RX, 2 },
+-      { P_UBI32_PLL, 5 },
+-      { P_BIAS_PLL, 6 },
+-};
+-
+-static const char * const gcc_xo_gpll0_gpll6_gpll0_sleep_clk[] = {
+-      "xo",
+-      "gpll0",
+-      "gpll6",
+-      "gpll0_out_main_div2",
+-      "sleep_clk",
+-};
+-
+-static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map[] = {
+-      { P_XO, 0 },
+-      { P_GPLL0, 1 },
+-      { P_GPLL6, 2 },
+-      { P_GPLL0_DIV2, 4 },
+-      { P_SLEEP_CLK, 6 },
+-};
+-
+ static struct clk_alpha_pll gpll0_main = {
+       .offset = 0x21000,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+@@ -400,8 +57,9 @@ static struct clk_alpha_pll gpll0_main =
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll0_main",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_ops,
+@@ -414,9 +72,8 @@ static struct clk_fixed_factor gpll0_out
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "gpll0_out_main_div2",
+-              .parent_names = (const char *[]){
+-                      "gpll0_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gpll0_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -429,9 +86,8 @@ static struct clk_alpha_pll_postdiv gpll
+       .width = 4,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpll0",
+-              .parent_names = (const char *[]){
+-                      "gpll0_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gpll0_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_ro_ops,
+       },
+@@ -445,8 +101,9 @@ static struct clk_alpha_pll gpll2_main =
+               .enable_mask = BIT(2),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll2_main",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_ops,
+@@ -461,9 +118,8 @@ static struct clk_alpha_pll_postdiv gpll
+       .width = 4,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpll2",
+-              .parent_names = (const char *[]){
+-                      "gpll2_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gpll2_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_ro_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -478,8 +134,9 @@ static struct clk_alpha_pll gpll4_main =
+               .enable_mask = BIT(5),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll4_main",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_ops,
+@@ -494,9 +151,8 @@ static struct clk_alpha_pll_postdiv gpll
+       .width = 4,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpll4",
+-              .parent_names = (const char *[]){
+-                      "gpll4_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gpll4_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_ro_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -512,8 +168,9 @@ static struct clk_alpha_pll gpll6_main =
+               .enable_mask = BIT(7),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll6_main",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_ops,
+@@ -528,9 +185,8 @@ static struct clk_alpha_pll_postdiv gpll
+       .width = 2,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpll6",
+-              .parent_names = (const char *[]){
+-                      "gpll6_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gpll6_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_ro_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -542,9 +198,8 @@ static struct clk_fixed_factor gpll6_out
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "gpll6_out_main_div2",
+-              .parent_names = (const char *[]){
+-                      "gpll6_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gpll6_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -560,8 +215,9 @@ static struct clk_alpha_pll ubi32_pll_ma
+               .enable_mask = BIT(6),
+               .hw.init = &(struct clk_init_data){
+                       .name = "ubi32_pll_main",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_huayra_ops,
+@@ -575,9 +231,8 @@ static struct clk_alpha_pll_postdiv ubi3
+       .width = 2,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "ubi32_pll",
+-              .parent_names = (const char *[]){
+-                      "ubi32_pll_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &ubi32_pll_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_ro_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -592,8 +247,9 @@ static struct clk_alpha_pll nss_crypto_p
+               .enable_mask = BIT(4),
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_crypto_pll_main",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_ops,
+@@ -607,9 +263,8 @@ static struct clk_alpha_pll_postdiv nss_
+       .width = 4,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_crypto_pll",
+-              .parent_names = (const char *[]){
+-                      "nss_crypto_pll_main"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &nss_crypto_pll_main.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_ro_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -623,6 +278,18 @@ static const struct freq_tbl ftbl_pcnoc_
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_gpll0_out_main_div2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw},
++      { .hw = &gpll0_out_main_div2.hw},
++};
++
++static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++      { P_GPLL0_DIV2, 4 },
++};
++
+ static struct clk_rcg2 pcnoc_bfdcd_clk_src = {
+       .cmd_rcgr = 0x27000,
+       .freq_tbl = ftbl_pcnoc_bfdcd_clk_src,
+@@ -630,8 +297,8 @@ static struct clk_rcg2 pcnoc_bfdcd_clk_s
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pcnoc_bfdcd_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+               .flags = CLK_IS_CRITICAL,
+       },
+@@ -642,9 +309,8 @@ static struct clk_fixed_factor pcnoc_clk
+       .div = 1,
+       .hw.init = &(struct clk_init_data){
+               .name = "pcnoc_clk_src",
+-              .parent_names = (const char *[]){
+-                      "pcnoc_bfdcd_clk_src"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_bfdcd_clk_src.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -658,8 +324,9 @@ static struct clk_branch gcc_sleep_clk_s
+               .enable_mask = BIT(1),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sleep_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "sleep_clk"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "sleep_clk",
++                              .name = "sleep_clk",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_branch2_ops,
+@@ -682,8 +349,8 @@ static struct clk_rcg2 blsp1_qup1_i2c_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup1_i2c_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -708,8 +375,8 @@ static struct clk_rcg2 blsp1_qup1_spi_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup1_spi_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -721,8 +388,8 @@ static struct clk_rcg2 blsp1_qup2_i2c_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup2_i2c_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -735,8 +402,8 @@ static struct clk_rcg2 blsp1_qup2_spi_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup2_spi_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -748,8 +415,8 @@ static struct clk_rcg2 blsp1_qup3_i2c_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup3_i2c_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -762,8 +429,8 @@ static struct clk_rcg2 blsp1_qup3_spi_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup3_spi_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -775,8 +442,8 @@ static struct clk_rcg2 blsp1_qup4_i2c_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup4_i2c_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -789,8 +456,8 @@ static struct clk_rcg2 blsp1_qup4_spi_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup4_spi_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -802,8 +469,8 @@ static struct clk_rcg2 blsp1_qup5_i2c_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup5_i2c_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -816,8 +483,8 @@ static struct clk_rcg2 blsp1_qup5_spi_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup5_spi_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -829,8 +496,8 @@ static struct clk_rcg2 blsp1_qup6_i2c_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup6_i2c_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -843,8 +510,8 @@ static struct clk_rcg2 blsp1_qup6_spi_ap
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_qup6_spi_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -877,8 +544,8 @@ static struct clk_rcg2 blsp1_uart1_apps_
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_uart1_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -891,8 +558,8 @@ static struct clk_rcg2 blsp1_uart2_apps_
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_uart2_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -905,8 +572,8 @@ static struct clk_rcg2 blsp1_uart3_apps_
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_uart3_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -919,8 +586,8 @@ static struct clk_rcg2 blsp1_uart4_apps_
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_uart4_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -933,8 +600,8 @@ static struct clk_rcg2 blsp1_uart5_apps_
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_uart5_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -947,8 +614,8 @@ static struct clk_rcg2 blsp1_uart6_apps_
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "blsp1_uart6_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -958,6 +625,11 @@ static const struct clk_parent_data gcc_
+       { .hw = &gpll0.clkr.hw },
+ };
++static const struct parent_map gcc_xo_gpll0_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++};
++
+ static const struct freq_tbl ftbl_pcie_axi_clk_src[] = {
+       F(19200000, P_XO, 1, 0, 0),
+       F(200000000, P_GPLL0, 4, 0, 0),
+@@ -972,7 +644,7 @@ static struct clk_rcg2 pcie0_axi_clk_src
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pcie0_axi_clk_src",
+               .parent_data = gcc_xo_gpll0,
+-              .num_parents = 2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -981,6 +653,18 @@ static const struct freq_tbl ftbl_pcie_a
+       F(19200000, P_XO, 1, 0, 0),
+ };
++static const struct clk_parent_data gcc_xo_gpll0_sleep_clk[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw },
++      { .fw_name = "sleep_clk", .name = "sleep_clk" },
++};
++
++static const struct parent_map gcc_xo_gpll0_sleep_clk_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 2 },
++      { P_SLEEP_CLK, 6 },
++};
++
+ static struct clk_rcg2 pcie0_aux_clk_src = {
+       .cmd_rcgr = 0x75024,
+       .freq_tbl = ftbl_pcie_aux_clk_src,
+@@ -989,12 +673,22 @@ static struct clk_rcg2 pcie0_aux_clk_src
+       .parent_map = gcc_xo_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pcie0_aux_clk_src",
+-              .parent_names = gcc_xo_gpll0_sleep_clk,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
++static const struct clk_parent_data gcc_pcie20_phy0_pipe_clk_xo[] = {
++      { .name = "pcie20_phy0_pipe_clk" },
++      { .fw_name = "xo", .name = "xo" },
++};
++
++static const struct parent_map gcc_pcie20_phy0_pipe_clk_xo_map[] = {
++      { P_PCIE20_PHY0_PIPE, 0 },
++      { P_XO, 2 },
++};
++
+ static struct clk_regmap_mux pcie0_pipe_clk_src = {
+       .reg = 0x7501c,
+       .shift = 8,
+@@ -1003,8 +697,8 @@ static struct clk_regmap_mux pcie0_pipe_
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcie0_pipe_clk_src",
+-                      .parent_names = gcc_pcie20_phy0_pipe_clk_xo,
+-                      .num_parents = 2,
++                      .parent_data = gcc_pcie20_phy0_pipe_clk_xo,
++                      .num_parents = ARRAY_SIZE(gcc_pcie20_phy0_pipe_clk_xo),
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+@@ -1019,7 +713,7 @@ static struct clk_rcg2 pcie1_axi_clk_src
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pcie1_axi_clk_src",
+               .parent_data = gcc_xo_gpll0,
+-              .num_parents = 2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1032,12 +726,22 @@ static struct clk_rcg2 pcie1_aux_clk_src
+       .parent_map = gcc_xo_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pcie1_aux_clk_src",
+-              .parent_names = gcc_xo_gpll0_sleep_clk,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
++static const struct clk_parent_data gcc_pcie20_phy1_pipe_clk_xo[] = {
++      { .name = "pcie20_phy1_pipe_clk" },
++      { .fw_name = "xo", .name = "xo" },
++};
++
++static const struct parent_map gcc_pcie20_phy1_pipe_clk_xo_map[] = {
++      { P_PCIE20_PHY1_PIPE, 0 },
++      { P_XO, 2 },
++};
++
+ static struct clk_regmap_mux pcie1_pipe_clk_src = {
+       .reg = 0x7601c,
+       .shift = 8,
+@@ -1046,8 +750,8 @@ static struct clk_regmap_mux pcie1_pipe_
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcie1_pipe_clk_src",
+-                      .parent_names = gcc_pcie20_phy1_pipe_clk_xo,
+-                      .num_parents = 2,
++                      .parent_data = gcc_pcie20_phy1_pipe_clk_xo,
++                      .num_parents = ARRAY_SIZE(gcc_pcie20_phy1_pipe_clk_xo),
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+@@ -1066,6 +770,20 @@ static const struct freq_tbl ftbl_sdcc_a
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_gpll2_gpll0_out_main_div2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll2.clkr.hw },
++      { .hw = &gpll0_out_main_div2.hw },
++};
++
++static const struct parent_map gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++      { P_GPLL2, 2 },
++      { P_GPLL0_DIV2, 4 },
++};
++
+ static struct clk_rcg2 sdcc1_apps_clk_src = {
+       .cmd_rcgr = 0x42004,
+       .freq_tbl = ftbl_sdcc_apps_clk_src,
+@@ -1074,8 +792,8 @@ static struct clk_rcg2 sdcc1_apps_clk_sr
+       .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "sdcc1_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2_gpll0_out_main_div2),
+               .ops = &clk_rcg2_floor_ops,
+       },
+ };
+@@ -1086,6 +804,20 @@ static const struct freq_tbl ftbl_sdcc_i
+       F(308570000, P_GPLL6, 3.5, 0, 0),
+ };
++static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_div2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll6.clkr.hw },
++      { .hw = &gpll0_out_main_div2.hw },
++};
++
++static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_div2_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++      { P_GPLL6, 2 },
++      { P_GPLL0_DIV2, 4 },
++};
++
+ static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+       .cmd_rcgr = 0x5d000,
+       .freq_tbl = ftbl_sdcc_ice_core_clk_src,
+@@ -1094,8 +826,8 @@ static struct clk_rcg2 sdcc1_ice_core_cl
+       .parent_map = gcc_xo_gpll0_gpll6_gpll0_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "sdcc1_ice_core_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll6_gpll0_div2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_gpll0_gpll6_gpll0_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1108,8 +840,8 @@ static struct clk_rcg2 sdcc2_apps_clk_sr
+       .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "sdcc2_apps_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2_gpll0_out_main_div2),
+               .ops = &clk_rcg2_floor_ops,
+       },
+ };
+@@ -1121,6 +853,18 @@ static const struct freq_tbl ftbl_usb_ma
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_out_main_div2_gpll0[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0_out_main_div2.hw },
++      { .hw = &gpll0.clkr.hw },
++};
++
++static const struct parent_map gcc_xo_gpll0_out_main_div2_gpll0_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0_DIV2, 2 },
++      { P_GPLL0, 1 },
++};
++
+ static struct clk_rcg2 usb0_master_clk_src = {
+       .cmd_rcgr = 0x3e00c,
+       .freq_tbl = ftbl_usb_master_clk_src,
+@@ -1129,8 +873,8 @@ static struct clk_rcg2 usb0_master_clk_s
+       .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "usb0_master_clk_src",
+-              .parent_names = gcc_xo_gpll0_out_main_div2_gpll0,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_out_main_div2_gpll0,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1148,8 +892,8 @@ static struct clk_rcg2 usb0_aux_clk_src
+       .parent_map = gcc_xo_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "usb0_aux_clk_src",
+-              .parent_names = gcc_xo_gpll0_sleep_clk,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1161,6 +905,20 @@ static const struct freq_tbl ftbl_usb_mo
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll6_gpll0_gpll0_out_main_div2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll6.clkr.hw },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll0_out_main_div2.hw },
++};
++
++static const struct parent_map gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map[] = {
++      { P_XO, 0 },
++      { P_GPLL6, 1 },
++      { P_GPLL0, 3 },
++      { P_GPLL0_DIV2, 4 },
++};
++
+ static struct clk_rcg2 usb0_mock_utmi_clk_src = {
+       .cmd_rcgr = 0x3e020,
+       .freq_tbl = ftbl_usb_mock_utmi_clk_src,
+@@ -1169,12 +927,22 @@ static struct clk_rcg2 usb0_mock_utmi_cl
+       .parent_map = gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "usb0_mock_utmi_clk_src",
+-              .parent_names = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll6_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
++static const struct clk_parent_data gcc_usb3phy_0_cc_pipe_clk_xo[] = {
++      { .name = "usb3phy_0_cc_pipe_clk" },
++      { .fw_name = "xo", .name = "xo" },
++};
++
++static const struct parent_map gcc_usb3phy_0_cc_pipe_clk_xo_map[] = {
++      { P_USB3PHY_0_PIPE, 0 },
++      { P_XO, 2 },
++};
++
+ static struct clk_regmap_mux usb0_pipe_clk_src = {
+       .reg = 0x3e048,
+       .shift = 8,
+@@ -1183,8 +951,8 @@ static struct clk_regmap_mux usb0_pipe_c
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "usb0_pipe_clk_src",
+-                      .parent_names = gcc_usb3phy_0_cc_pipe_clk_xo,
+-                      .num_parents = 2,
++                      .parent_data = gcc_usb3phy_0_cc_pipe_clk_xo,
++                      .num_parents = ARRAY_SIZE(gcc_usb3phy_0_cc_pipe_clk_xo),
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+@@ -1199,8 +967,8 @@ static struct clk_rcg2 usb1_master_clk_s
+       .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "usb1_master_clk_src",
+-              .parent_names = gcc_xo_gpll0_out_main_div2_gpll0,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_out_main_div2_gpll0,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1213,8 +981,8 @@ static struct clk_rcg2 usb1_aux_clk_src
+       .parent_map = gcc_xo_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "usb1_aux_clk_src",
+-              .parent_names = gcc_xo_gpll0_sleep_clk,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1227,12 +995,22 @@ static struct clk_rcg2 usb1_mock_utmi_cl
+       .parent_map = gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "usb1_mock_utmi_clk_src",
+-              .parent_names = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_gpll6_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll6_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
++static const struct clk_parent_data gcc_usb3phy_1_cc_pipe_clk_xo[] = {
++      { .name = "usb3phy_1_cc_pipe_clk" },
++      { .fw_name = "xo", .name = "xo" },
++};
++
++static const struct parent_map gcc_usb3phy_1_cc_pipe_clk_xo_map[] = {
++      { P_USB3PHY_1_PIPE, 0 },
++      { P_XO, 2 },
++};
++
+ static struct clk_regmap_mux usb1_pipe_clk_src = {
+       .reg = 0x3f048,
+       .shift = 8,
+@@ -1241,8 +1019,8 @@ static struct clk_regmap_mux usb1_pipe_c
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "usb1_pipe_clk_src",
+-                      .parent_names = gcc_usb3phy_1_cc_pipe_clk_xo,
+-                      .num_parents = 2,
++                      .parent_data = gcc_usb3phy_1_cc_pipe_clk_xo,
++                      .num_parents = ARRAY_SIZE(gcc_usb3phy_1_cc_pipe_clk_xo),
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+@@ -1256,8 +1034,9 @@ static struct clk_branch gcc_xo_clk_src
+               .enable_mask = BIT(1),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_xo_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "xo"
++                      .parent_data = &(const struct clk_parent_data){
++                              .fw_name = "xo",
++                              .name = "xo",
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+@@ -1271,9 +1050,8 @@ static struct clk_fixed_factor gcc_xo_di
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "gcc_xo_div4_clk_src",
+-              .parent_names = (const char *[]){
+-                      "gcc_xo_clk_src"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_clk_src.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -1291,6 +1069,20 @@ static const struct freq_tbl ftbl_system
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_out_main_div2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll6.clkr.hw },
++      { .hw = &gpll0_out_main_div2.hw },
++};
++
++static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++      { P_GPLL6, 2 },
++      { P_GPLL0_DIV2, 3 },
++};
++
+ static struct clk_rcg2 system_noc_bfdcd_clk_src = {
+       .cmd_rcgr = 0x26004,
+       .freq_tbl = ftbl_system_noc_bfdcd_clk_src,
+@@ -1298,8 +1090,8 @@ static struct clk_rcg2 system_noc_bfdcd_
+       .parent_map = gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "system_noc_bfdcd_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll6_gpll0_out_main_div2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_gpll0_gpll6_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+               .flags = CLK_IS_CRITICAL,
+       },
+@@ -1310,9 +1102,8 @@ static struct clk_fixed_factor system_no
+       .div = 1,
+       .hw.init = &(struct clk_init_data){
+               .name = "system_noc_clk_src",
+-              .parent_names = (const char *[]){
+-                      "system_noc_bfdcd_clk_src"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &system_noc_bfdcd_clk_src.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -1333,7 +1124,7 @@ static struct clk_rcg2 nss_ce_clk_src =
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_ce_clk_src",
+               .parent_data = gcc_xo_gpll0,
+-              .num_parents = 2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1344,6 +1135,20 @@ static const struct freq_tbl ftbl_nss_no
+       { }
+ };
++static const struct clk_parent_data gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "bias_pll_nss_noc_clk" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll2.clkr.hw },
++};
++
++static const struct parent_map gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map[] = {
++      { P_XO, 0 },
++      { P_BIAS_PLL_NSS_NOC, 1 },
++      { P_GPLL0, 2 },
++      { P_GPLL2, 3 },
++};
++
+ static struct clk_rcg2 nss_noc_bfdcd_clk_src = {
+       .cmd_rcgr = 0x68088,
+       .freq_tbl = ftbl_nss_noc_bfdcd_clk_src,
+@@ -1351,8 +1156,8 @@ static struct clk_rcg2 nss_noc_bfdcd_clk
+       .parent_map = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_noc_bfdcd_clk_src",
+-              .parent_names = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2,
+-              .num_parents = 4,
++              .parent_data = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2,
++              .num_parents = ARRAY_SIZE(gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1362,9 +1167,8 @@ static struct clk_fixed_factor nss_noc_c
+       .div = 1,
+       .hw.init = &(struct clk_init_data){
+               .name = "nss_noc_clk_src",
+-              .parent_names = (const char *[]){
+-                      "nss_noc_bfdcd_clk_src"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_bfdcd_clk_src.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -1377,6 +1181,18 @@ static const struct freq_tbl ftbl_nss_cr
+       { }
+ };
++static const struct clk_parent_data gcc_xo_nss_crypto_pll_gpll0[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &nss_crypto_pll.clkr.hw },
++      { .hw = &gpll0.clkr.hw },
++};
++
++static const struct parent_map gcc_xo_nss_crypto_pll_gpll0_map[] = {
++      { P_XO, 0 },
++      { P_NSS_CRYPTO_PLL, 1 },
++      { P_GPLL0, 2 },
++};
++
+ static struct clk_rcg2 nss_crypto_clk_src = {
+       .cmd_rcgr = 0x68144,
+       .freq_tbl = ftbl_nss_crypto_clk_src,
+@@ -1385,8 +1201,8 @@ static struct clk_rcg2 nss_crypto_clk_sr
+       .parent_map = gcc_xo_nss_crypto_pll_gpll0_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_crypto_clk_src",
+-              .parent_names = gcc_xo_nss_crypto_pll_gpll0,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_nss_crypto_pll_gpll0,
++              .num_parents = ARRAY_SIZE(gcc_xo_nss_crypto_pll_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1400,6 +1216,24 @@ static const struct freq_tbl ftbl_nss_ub
+       { }
+ };
++static const struct clk_parent_data gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll2.clkr.hw },
++      { .hw = &gpll4.clkr.hw },
++      { .hw = &gpll6.clkr.hw },
++};
++
++static const struct parent_map gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map[] = {
++      { P_XO, 0 },
++      { P_UBI32_PLL, 1 },
++      { P_GPLL0, 2 },
++      { P_GPLL2, 3 },
++      { P_GPLL4, 4 },
++      { P_GPLL6, 5 },
++};
++
+ static struct clk_rcg2 nss_ubi0_clk_src = {
+       .cmd_rcgr = 0x68104,
+       .freq_tbl = ftbl_nss_ubi_clk_src,
+@@ -1407,8 +1241,8 @@ static struct clk_rcg2 nss_ubi0_clk_src
+       .parent_map = gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_ubi0_clk_src",
+-              .parent_names = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
+-              .num_parents = 6,
++              .parent_data = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
++              .num_parents = ARRAY_SIZE(gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6),
+               .ops = &clk_rcg2_ops,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+@@ -1421,9 +1255,8 @@ static struct clk_regmap_div nss_ubi0_di
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_ubi0_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_ubi0_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ubi0_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ro_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1438,8 +1271,8 @@ static struct clk_rcg2 nss_ubi1_clk_src
+       .parent_map = gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_ubi1_clk_src",
+-              .parent_names = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
+-              .num_parents = 6,
++              .parent_data = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6,
++              .num_parents = ARRAY_SIZE(gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6),
+               .ops = &clk_rcg2_ops,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+@@ -1452,9 +1285,8 @@ static struct clk_regmap_div nss_ubi1_di
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_ubi1_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_ubi1_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ubi1_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ro_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1468,6 +1300,16 @@ static const struct freq_tbl ftbl_ubi_mp
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_out_main_div2[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0_out_main_div2.hw },
++};
++
++static const struct parent_map gcc_xo_gpll0_out_main_div2_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0_DIV2, 1 },
++};
++
+ static struct clk_rcg2 ubi_mpt_clk_src = {
+       .cmd_rcgr = 0x68090,
+       .freq_tbl = ftbl_ubi_mpt_clk_src,
+@@ -1475,8 +1317,8 @@ static struct clk_rcg2 ubi_mpt_clk_src =
+       .parent_map = gcc_xo_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "ubi_mpt_clk_src",
+-              .parent_names = gcc_xo_gpll0_out_main_div2,
+-              .num_parents = 2,
++              .parent_data = gcc_xo_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1487,6 +1329,18 @@ static const struct freq_tbl ftbl_nss_im
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_gpll4[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll4.clkr.hw },
++};
++
++static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++      { P_GPLL4, 2 },
++};
++
+ static struct clk_rcg2 nss_imem_clk_src = {
+       .cmd_rcgr = 0x68158,
+       .freq_tbl = ftbl_nss_imem_clk_src,
+@@ -1494,8 +1348,8 @@ static struct clk_rcg2 nss_imem_clk_src
+       .parent_map = gcc_xo_gpll0_gpll4_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_imem_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll4,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll4,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1506,6 +1360,24 @@ static const struct freq_tbl ftbl_nss_pp
+       { }
+ };
++static const struct clk_parent_data gcc_xo_bias_gpll0_gpll4_nss_ubi32[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "bias_pll_cc_clk" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll4.clkr.hw },
++      { .hw = &nss_crypto_pll.clkr.hw },
++      { .hw = &ubi32_pll.clkr.hw },
++};
++
++static const struct parent_map gcc_xo_bias_gpll0_gpll4_nss_ubi32_map[] = {
++      { P_XO, 0 },
++      { P_BIAS_PLL, 1 },
++      { P_GPLL0, 2 },
++      { P_GPLL4, 3 },
++      { P_NSS_CRYPTO_PLL, 4 },
++      { P_UBI32_PLL, 5 },
++};
++
+ static struct clk_rcg2 nss_ppe_clk_src = {
+       .cmd_rcgr = 0x68080,
+       .freq_tbl = ftbl_nss_ppe_clk_src,
+@@ -1513,8 +1385,8 @@ static struct clk_rcg2 nss_ppe_clk_src =
+       .parent_map = gcc_xo_bias_gpll0_gpll4_nss_ubi32_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_ppe_clk_src",
+-              .parent_names = gcc_xo_bias_gpll0_gpll4_nss_ubi32,
+-              .num_parents = 6,
++              .parent_data = gcc_xo_bias_gpll0_gpll4_nss_ubi32,
++              .num_parents = ARRAY_SIZE(gcc_xo_bias_gpll0_gpll4_nss_ubi32),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1524,9 +1396,8 @@ static struct clk_fixed_factor nss_ppe_c
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "nss_ppe_cdiv_clk_src",
+-              .parent_names = (const char *[]){
+-                      "nss_ppe_clk_src"
+-              },
++              .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+               .flags = CLK_SET_RATE_PARENT,
+@@ -1540,6 +1411,22 @@ static const struct freq_tbl ftbl_nss_po
+       { }
+ };
++static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_ubi32_bias[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "uniphy0_gcc_rx_clk" },
++      { .name = "uniphy0_gcc_tx_clk" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .name = "bias_pll_cc_clk" },
++};
++
++static const struct parent_map gcc_xo_uniphy0_rx_tx_ubi32_bias_map[] = {
++      { P_XO, 0 },
++      { P_UNIPHY0_RX, 1 },
++      { P_UNIPHY0_TX, 2 },
++      { P_UBI32_PLL, 5 },
++      { P_BIAS_PLL, 6 },
++};
++
+ static struct clk_rcg2 nss_port1_rx_clk_src = {
+       .cmd_rcgr = 0x68020,
+       .freq_tbl = ftbl_nss_port1_rx_clk_src,
+@@ -1547,8 +1434,8 @@ static struct clk_rcg2 nss_port1_rx_clk_
+       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port1_rx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1560,9 +1447,8 @@ static struct clk_regmap_div nss_port1_r
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port1_rx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port1_rx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port1_rx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1577,6 +1463,22 @@ static const struct freq_tbl ftbl_nss_po
+       { }
+ };
++static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_ubi32_bias[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "uniphy0_gcc_tx_clk" },
++      { .name = "uniphy0_gcc_rx_clk" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .name = "bias_pll_cc_clk" },
++};
++
++static const struct parent_map gcc_xo_uniphy0_tx_rx_ubi32_bias_map[] = {
++      { P_XO, 0 },
++      { P_UNIPHY0_TX, 1 },
++      { P_UNIPHY0_RX, 2 },
++      { P_UBI32_PLL, 5 },
++      { P_BIAS_PLL, 6 },
++};
++
+ static struct clk_rcg2 nss_port1_tx_clk_src = {
+       .cmd_rcgr = 0x68028,
+       .freq_tbl = ftbl_nss_port1_tx_clk_src,
+@@ -1584,8 +1486,8 @@ static struct clk_rcg2 nss_port1_tx_clk_
+       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port1_tx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1597,9 +1499,8 @@ static struct clk_regmap_div nss_port1_t
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port1_tx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port1_tx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port1_tx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1614,8 +1515,8 @@ static struct clk_rcg2 nss_port2_rx_clk_
+       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port2_rx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1627,9 +1528,8 @@ static struct clk_regmap_div nss_port2_r
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port2_rx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port2_rx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port2_rx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1644,8 +1544,8 @@ static struct clk_rcg2 nss_port2_tx_clk_
+       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port2_tx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1657,9 +1557,8 @@ static struct clk_regmap_div nss_port2_t
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port2_tx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port2_tx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port2_tx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1674,8 +1573,8 @@ static struct clk_rcg2 nss_port3_rx_clk_
+       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port3_rx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1687,9 +1586,8 @@ static struct clk_regmap_div nss_port3_r
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port3_rx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port3_rx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port3_rx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1704,8 +1602,8 @@ static struct clk_rcg2 nss_port3_tx_clk_
+       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port3_tx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1717,9 +1615,8 @@ static struct clk_regmap_div nss_port3_t
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port3_tx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port3_tx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port3_tx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1734,8 +1631,8 @@ static struct clk_rcg2 nss_port4_rx_clk_
+       .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port4_rx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_rx_tx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1747,9 +1644,8 @@ static struct clk_regmap_div nss_port4_r
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port4_rx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port4_rx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port4_rx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1764,8 +1660,8 @@ static struct clk_rcg2 nss_port4_tx_clk_
+       .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port4_tx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy0_tx_rx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1777,9 +1673,8 @@ static struct clk_regmap_div nss_port4_t
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port4_tx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port4_tx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port4_tx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1799,6 +1694,27 @@ static const struct freq_tbl ftbl_nss_po
+       { }
+ };
++static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "uniphy0_gcc_rx_clk" },
++      { .name = "uniphy0_gcc_tx_clk" },
++      { .name = "uniphy1_gcc_rx_clk" },
++      { .name = "uniphy1_gcc_tx_clk" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .name = "bias_pll_cc_clk" },
++};
++
++static const struct parent_map
++gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = {
++      { P_XO, 0 },
++      { P_UNIPHY0_RX, 1 },
++      { P_UNIPHY0_TX, 2 },
++      { P_UNIPHY1_RX, 3 },
++      { P_UNIPHY1_TX, 4 },
++      { P_UBI32_PLL, 5 },
++      { P_BIAS_PLL, 6 },
++};
++
+ static struct clk_rcg2 nss_port5_rx_clk_src = {
+       .cmd_rcgr = 0x68060,
+       .freq_tbl = ftbl_nss_port5_rx_clk_src,
+@@ -1806,8 +1722,8 @@ static struct clk_rcg2 nss_port5_rx_clk_
+       .parent_map = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port5_rx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias,
+-              .num_parents = 7,
++              .parent_data = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1819,9 +1735,8 @@ static struct clk_regmap_div nss_port5_r
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port5_rx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_rx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_rx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1841,6 +1756,27 @@ static const struct freq_tbl ftbl_nss_po
+       { }
+ };
++static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "uniphy0_gcc_tx_clk" },
++      { .name = "uniphy0_gcc_rx_clk" },
++      { .name = "uniphy1_gcc_tx_clk" },
++      { .name = "uniphy1_gcc_rx_clk" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .name = "bias_pll_cc_clk" },
++};
++
++static const struct parent_map
++gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = {
++      { P_XO, 0 },
++      { P_UNIPHY0_TX, 1 },
++      { P_UNIPHY0_RX, 2 },
++      { P_UNIPHY1_TX, 3 },
++      { P_UNIPHY1_RX, 4 },
++      { P_UBI32_PLL, 5 },
++      { P_BIAS_PLL, 6 },
++};
++
+ static struct clk_rcg2 nss_port5_tx_clk_src = {
+       .cmd_rcgr = 0x68068,
+       .freq_tbl = ftbl_nss_port5_tx_clk_src,
+@@ -1848,8 +1784,8 @@ static struct clk_rcg2 nss_port5_tx_clk_
+       .parent_map = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port5_tx_clk_src",
+-              .parent_names = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias,
+-              .num_parents = 7,
++              .parent_data = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1861,9 +1797,8 @@ static struct clk_regmap_div nss_port5_t
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port5_tx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_tx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_tx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1883,6 +1818,22 @@ static const struct freq_tbl ftbl_nss_po
+       { }
+ };
++static const struct clk_parent_data gcc_xo_uniphy2_rx_tx_ubi32_bias[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "uniphy2_gcc_rx_clk" },
++      { .name = "uniphy2_gcc_tx_clk" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .name = "bias_pll_cc_clk" },
++};
++
++static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
++      { P_XO, 0 },
++      { P_UNIPHY2_RX, 1 },
++      { P_UNIPHY2_TX, 2 },
++      { P_UBI32_PLL, 5 },
++      { P_BIAS_PLL, 6 },
++};
++
+ static struct clk_rcg2 nss_port6_rx_clk_src = {
+       .cmd_rcgr = 0x68070,
+       .freq_tbl = ftbl_nss_port6_rx_clk_src,
+@@ -1890,8 +1841,8 @@ static struct clk_rcg2 nss_port6_rx_clk_
+       .parent_map = gcc_xo_uniphy2_rx_tx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port6_rx_clk_src",
+-              .parent_names = gcc_xo_uniphy2_rx_tx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy2_rx_tx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy2_rx_tx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1903,9 +1854,8 @@ static struct clk_regmap_div nss_port6_r
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port6_rx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port6_rx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port6_rx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1925,6 +1875,22 @@ static const struct freq_tbl ftbl_nss_po
+       { }
+ };
++static const struct clk_parent_data gcc_xo_uniphy2_tx_rx_ubi32_bias[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .name = "uniphy2_gcc_tx_clk" },
++      { .name = "uniphy2_gcc_rx_clk" },
++      { .hw = &ubi32_pll.clkr.hw },
++      { .name = "bias_pll_cc_clk" },
++};
++
++static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
++      { P_XO, 0 },
++      { P_UNIPHY2_TX, 1 },
++      { P_UNIPHY2_RX, 2 },
++      { P_UBI32_PLL, 5 },
++      { P_BIAS_PLL, 6 },
++};
++
+ static struct clk_rcg2 nss_port6_tx_clk_src = {
+       .cmd_rcgr = 0x68078,
+       .freq_tbl = ftbl_nss_port6_tx_clk_src,
+@@ -1932,8 +1898,8 @@ static struct clk_rcg2 nss_port6_tx_clk_
+       .parent_map = gcc_xo_uniphy2_tx_rx_ubi32_bias_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "nss_port6_tx_clk_src",
+-              .parent_names = gcc_xo_uniphy2_tx_rx_ubi32_bias,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_uniphy2_tx_rx_ubi32_bias,
++              .num_parents = ARRAY_SIZE(gcc_xo_uniphy2_tx_rx_ubi32_bias),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1945,9 +1911,8 @@ static struct clk_regmap_div nss_port6_t
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "nss_port6_tx_div_clk_src",
+-                      .parent_names = (const char *[]){
+-                              "nss_port6_tx_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port6_tx_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+@@ -1970,8 +1935,8 @@ static struct clk_rcg2 crypto_clk_src =
+       .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "crypto_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll0_out_main_div2,
+-              .num_parents = 3,
++              .parent_data = gcc_xo_gpll0_gpll0_out_main_div2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -1981,6 +1946,22 @@ static struct freq_tbl ftbl_gp_clk_src[]
+       { }
+ };
++static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_sleep_clk[] = {
++      { .fw_name = "xo", .name = "xo" },
++      { .hw = &gpll0.clkr.hw },
++      { .hw = &gpll6.clkr.hw },
++      { .hw = &gpll0_out_main_div2.hw },
++      { .fw_name = "sleep_clk", .name = "sleep_clk" },
++};
++
++static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map[] = {
++      { P_XO, 0 },
++      { P_GPLL0, 1 },
++      { P_GPLL6, 2 },
++      { P_GPLL0_DIV2, 4 },
++      { P_SLEEP_CLK, 6 },
++};
++
+ static struct clk_rcg2 gp1_clk_src = {
+       .cmd_rcgr = 0x08004,
+       .freq_tbl = ftbl_gp_clk_src,
+@@ -1989,8 +1970,8 @@ static struct clk_rcg2 gp1_clk_src = {
+       .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gp1_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -2003,8 +1984,8 @@ static struct clk_rcg2 gp2_clk_src = {
+       .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gp2_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -2017,8 +1998,8 @@ static struct clk_rcg2 gp3_clk_src = {
+       .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gp3_clk_src",
+-              .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
+-              .num_parents = 5,
++              .parent_data = gcc_xo_gpll0_gpll6_gpll0_sleep_clk,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll0_sleep_clk),
+               .ops = &clk_rcg2_ops,
+       },
+ };
+@@ -2030,9 +2011,8 @@ static struct clk_branch gcc_blsp1_ahb_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2047,9 +2027,8 @@ static struct clk_branch gcc_blsp1_qup1_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup1_i2c_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup1_i2c_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup1_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2064,9 +2043,8 @@ static struct clk_branch gcc_blsp1_qup1_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup1_spi_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup1_spi_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup1_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2081,9 +2059,8 @@ static struct clk_branch gcc_blsp1_qup2_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup2_i2c_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup2_i2c_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup2_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2098,9 +2075,8 @@ static struct clk_branch gcc_blsp1_qup2_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup2_spi_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup2_spi_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup2_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2115,9 +2091,8 @@ static struct clk_branch gcc_blsp1_qup3_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup3_i2c_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup3_i2c_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup3_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2132,9 +2107,8 @@ static struct clk_branch gcc_blsp1_qup3_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup3_spi_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup3_spi_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup3_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2149,9 +2123,8 @@ static struct clk_branch gcc_blsp1_qup4_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup4_i2c_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup4_i2c_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup4_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2166,9 +2139,8 @@ static struct clk_branch gcc_blsp1_qup4_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup4_spi_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup4_spi_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup4_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2183,9 +2155,8 @@ static struct clk_branch gcc_blsp1_qup5_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup5_i2c_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup5_i2c_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup5_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2200,9 +2171,8 @@ static struct clk_branch gcc_blsp1_qup5_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup5_spi_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup5_spi_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup5_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2217,9 +2187,8 @@ static struct clk_branch gcc_blsp1_qup6_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup6_i2c_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup6_i2c_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup6_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2234,9 +2203,8 @@ static struct clk_branch gcc_blsp1_qup6_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup6_spi_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_qup6_spi_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_qup6_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2251,9 +2219,8 @@ static struct clk_branch gcc_blsp1_uart1
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart1_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_uart1_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_uart1_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2268,9 +2235,8 @@ static struct clk_branch gcc_blsp1_uart2
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart2_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_uart2_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_uart2_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2285,9 +2251,8 @@ static struct clk_branch gcc_blsp1_uart3
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart3_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_uart3_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_uart3_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2302,9 +2267,8 @@ static struct clk_branch gcc_blsp1_uart4
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart4_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_uart4_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_uart4_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2319,9 +2283,8 @@ static struct clk_branch gcc_blsp1_uart5
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart5_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_uart5_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_uart5_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2336,9 +2299,8 @@ static struct clk_branch gcc_blsp1_uart6
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart6_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "blsp1_uart6_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &blsp1_uart6_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2354,9 +2316,8 @@ static struct clk_branch gcc_prng_ahb_cl
+               .enable_mask = BIT(8),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_prng_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2371,9 +2332,8 @@ static struct clk_branch gcc_qpic_ahb_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_qpic_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2388,9 +2348,8 @@ static struct clk_branch gcc_qpic_clk =
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_qpic_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2405,9 +2364,8 @@ static struct clk_branch gcc_pcie0_ahb_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie0_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2422,9 +2380,8 @@ static struct clk_branch gcc_pcie0_aux_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie0_aux_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie0_aux_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie0_aux_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2439,9 +2396,8 @@ static struct clk_branch gcc_pcie0_axi_m
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie0_axi_m_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie0_axi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie0_axi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2456,9 +2412,8 @@ static struct clk_branch gcc_pcie0_axi_s
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie0_axi_s_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie0_axi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie0_axi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2474,9 +2429,8 @@ static struct clk_branch gcc_pcie0_pipe_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie0_pipe_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie0_pipe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie0_pipe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2491,9 +2445,8 @@ static struct clk_branch gcc_sys_noc_pci
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sys_noc_pcie0_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie0_axi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie0_axi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2508,9 +2461,8 @@ static struct clk_branch gcc_pcie1_ahb_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie1_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2525,9 +2477,8 @@ static struct clk_branch gcc_pcie1_aux_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie1_aux_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie1_aux_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie1_aux_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2542,9 +2493,8 @@ static struct clk_branch gcc_pcie1_axi_m
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie1_axi_m_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie1_axi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie1_axi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2559,9 +2509,8 @@ static struct clk_branch gcc_pcie1_axi_s
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie1_axi_s_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie1_axi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie1_axi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2577,9 +2526,8 @@ static struct clk_branch gcc_pcie1_pipe_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie1_pipe_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie1_pipe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie1_pipe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2594,9 +2542,8 @@ static struct clk_branch gcc_sys_noc_pci
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sys_noc_pcie1_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcie1_axi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcie1_axi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2611,9 +2558,8 @@ static struct clk_branch gcc_usb0_aux_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb0_aux_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb0_aux_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb0_aux_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2628,9 +2574,8 @@ static struct clk_branch gcc_sys_noc_usb
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sys_noc_usb0_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb0_master_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb0_master_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2645,9 +2590,8 @@ static struct clk_branch gcc_usb0_master
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb0_master_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb0_master_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb0_master_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2662,9 +2606,8 @@ static struct clk_branch gcc_usb0_mock_u
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb0_mock_utmi_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb0_mock_utmi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb0_mock_utmi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2679,9 +2622,8 @@ static struct clk_branch gcc_usb0_phy_cf
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb0_phy_cfg_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2697,9 +2639,8 @@ static struct clk_branch gcc_usb0_pipe_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb0_pipe_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb0_pipe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb0_pipe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2714,9 +2655,8 @@ static struct clk_branch gcc_usb0_sleep_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb0_sleep_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_sleep_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_sleep_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2731,9 +2671,8 @@ static struct clk_branch gcc_usb1_aux_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb1_aux_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb1_aux_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb1_aux_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2748,9 +2687,8 @@ static struct clk_branch gcc_sys_noc_usb
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sys_noc_usb1_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb1_master_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb1_master_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2765,9 +2703,8 @@ static struct clk_branch gcc_usb1_master
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb1_master_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb1_master_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb1_master_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2782,9 +2719,8 @@ static struct clk_branch gcc_usb1_mock_u
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb1_mock_utmi_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb1_mock_utmi_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb1_mock_utmi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2799,9 +2735,8 @@ static struct clk_branch gcc_usb1_phy_cf
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb1_phy_cfg_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2817,9 +2752,8 @@ static struct clk_branch gcc_usb1_pipe_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb1_pipe_clk",
+-                      .parent_names = (const char *[]){
+-                              "usb1_pipe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &usb1_pipe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2834,9 +2768,8 @@ static struct clk_branch gcc_usb1_sleep_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb1_sleep_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_sleep_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_sleep_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2851,9 +2784,8 @@ static struct clk_branch gcc_sdcc1_ahb_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc1_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2868,9 +2800,8 @@ static struct clk_branch gcc_sdcc1_apps_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc1_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "sdcc1_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &sdcc1_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2885,9 +2816,8 @@ static struct clk_branch gcc_sdcc1_ice_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc1_ice_core_clk",
+-                      .parent_names = (const char *[]){
+-                              "sdcc1_ice_core_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &sdcc1_ice_core_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2902,9 +2832,8 @@ static struct clk_branch gcc_sdcc2_ahb_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc2_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2919,9 +2848,8 @@ static struct clk_branch gcc_sdcc2_apps_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc2_apps_clk",
+-                      .parent_names = (const char *[]){
+-                              "sdcc2_apps_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &sdcc2_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2936,9 +2864,8 @@ static struct clk_branch gcc_mem_noc_nss
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_mem_noc_nss_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2953,9 +2880,8 @@ static struct clk_branch gcc_nss_ce_apb_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ce_apb_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2970,9 +2896,8 @@ static struct clk_branch gcc_nss_ce_axi_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ce_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -2987,9 +2912,8 @@ static struct clk_branch gcc_nss_cfg_clk
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_cfg_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3004,9 +2928,8 @@ static struct clk_branch gcc_nss_crypto_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_crypto_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_crypto_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_crypto_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3021,9 +2944,8 @@ static struct clk_branch gcc_nss_csr_clk
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_csr_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3038,9 +2960,8 @@ static struct clk_branch gcc_nss_edma_cf
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_edma_cfg_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3055,9 +2976,8 @@ static struct clk_branch gcc_nss_edma_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_edma_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3072,9 +2992,8 @@ static struct clk_branch gcc_nss_imem_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_imem_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_imem_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_imem_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3089,9 +3008,8 @@ static struct clk_branch gcc_nss_noc_clk
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_noc_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3106,9 +3024,8 @@ static struct clk_branch gcc_nss_ppe_btq
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ppe_btq_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3123,9 +3040,8 @@ static struct clk_branch gcc_nss_ppe_cfg
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ppe_cfg_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3140,9 +3056,8 @@ static struct clk_branch gcc_nss_ppe_clk
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ppe_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3157,9 +3072,8 @@ static struct clk_branch gcc_nss_ppe_ipe
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ppe_ipe_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3174,9 +3088,8 @@ static struct clk_branch gcc_nss_ptp_ref
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_ptp_ref_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_cdiv_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_cdiv_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3192,9 +3105,8 @@ static struct clk_branch gcc_crypto_ppe_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_crypto_ppe_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3209,9 +3121,8 @@ static struct clk_branch gcc_nssnoc_ce_a
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_ce_apb_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3226,9 +3137,8 @@ static struct clk_branch gcc_nssnoc_ce_a
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_ce_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3243,9 +3153,8 @@ static struct clk_branch gcc_nssnoc_cryp
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_crypto_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_crypto_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_crypto_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3260,9 +3169,8 @@ static struct clk_branch gcc_nssnoc_ppe_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_ppe_cfg_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3277,9 +3185,8 @@ static struct clk_branch gcc_nssnoc_ppe_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_ppe_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3294,9 +3201,8 @@ static struct clk_branch gcc_nssnoc_qosg
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_qosgen_ref_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_xo_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3311,9 +3217,8 @@ static struct clk_branch gcc_nssnoc_snoc
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_snoc_clk",
+-                      .parent_names = (const char *[]){
+-                              "system_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &system_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3328,9 +3233,8 @@ static struct clk_branch gcc_nssnoc_time
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_timeout_ref_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_xo_div4_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_div4_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3345,9 +3249,8 @@ static struct clk_branch gcc_nssnoc_ubi0
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_ubi0_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3362,9 +3265,8 @@ static struct clk_branch gcc_nssnoc_ubi1
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nssnoc_ubi1_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3380,9 +3282,8 @@ static struct clk_branch gcc_ubi0_ahb_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi0_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3398,9 +3299,8 @@ static struct clk_branch gcc_ubi0_axi_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi0_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3416,9 +3316,8 @@ static struct clk_branch gcc_ubi0_nc_axi
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi0_nc_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3434,9 +3333,8 @@ static struct clk_branch gcc_ubi0_core_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi0_core_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ubi0_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ubi0_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3452,9 +3350,8 @@ static struct clk_branch gcc_ubi0_mpt_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi0_mpt_clk",
+-                      .parent_names = (const char *[]){
+-                              "ubi_mpt_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &ubi_mpt_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3470,9 +3367,8 @@ static struct clk_branch gcc_ubi1_ahb_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi1_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ce_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ce_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3488,9 +3384,8 @@ static struct clk_branch gcc_ubi1_axi_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi1_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3506,9 +3401,8 @@ static struct clk_branch gcc_ubi1_nc_axi
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi1_nc_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_noc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_noc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3524,9 +3418,8 @@ static struct clk_branch gcc_ubi1_core_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi1_core_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ubi1_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ubi1_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3542,9 +3435,8 @@ static struct clk_branch gcc_ubi1_mpt_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ubi1_mpt_clk",
+-                      .parent_names = (const char *[]){
+-                              "ubi_mpt_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &ubi_mpt_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3559,9 +3451,8 @@ static struct clk_branch gcc_cmn_12gpll_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_cmn_12gpll_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3576,9 +3467,8 @@ static struct clk_branch gcc_cmn_12gpll_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_cmn_12gpll_sys_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_xo_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3593,9 +3483,8 @@ static struct clk_branch gcc_mdio_ahb_cl
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_mdio_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3610,9 +3499,8 @@ static struct clk_branch gcc_uniphy0_ahb
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3627,9 +3515,8 @@ static struct clk_branch gcc_uniphy0_sys
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_sys_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_xo_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3644,9 +3531,8 @@ static struct clk_branch gcc_uniphy1_ahb
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy1_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3661,9 +3547,8 @@ static struct clk_branch gcc_uniphy1_sys
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy1_sys_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_xo_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3678,9 +3563,8 @@ static struct clk_branch gcc_uniphy2_ahb
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy2_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3695,9 +3579,8 @@ static struct clk_branch gcc_uniphy2_sys
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy2_sys_clk",
+-                      .parent_names = (const char *[]){
+-                              "gcc_xo_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gcc_xo_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3712,9 +3595,8 @@ static struct clk_branch gcc_nss_port1_r
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port1_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port1_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port1_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3729,9 +3611,8 @@ static struct clk_branch gcc_nss_port1_t
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port1_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port1_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port1_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3746,9 +3627,8 @@ static struct clk_branch gcc_nss_port2_r
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port2_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port2_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port2_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3763,9 +3643,8 @@ static struct clk_branch gcc_nss_port2_t
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port2_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port2_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port2_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3780,9 +3659,8 @@ static struct clk_branch gcc_nss_port3_r
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port3_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port3_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port3_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3797,9 +3675,8 @@ static struct clk_branch gcc_nss_port3_t
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port3_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port3_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port3_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3814,9 +3691,8 @@ static struct clk_branch gcc_nss_port4_r
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port4_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port4_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port4_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3831,9 +3707,8 @@ static struct clk_branch gcc_nss_port4_t
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port4_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port4_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port4_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3848,9 +3723,8 @@ static struct clk_branch gcc_nss_port5_r
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port5_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3865,9 +3739,8 @@ static struct clk_branch gcc_nss_port5_t
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port5_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3882,9 +3755,8 @@ static struct clk_branch gcc_nss_port6_r
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port6_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port6_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port6_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3899,9 +3771,8 @@ static struct clk_branch gcc_nss_port6_t
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_nss_port6_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port6_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port6_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3916,9 +3787,8 @@ static struct clk_branch gcc_port1_mac_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_port1_mac_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3933,9 +3803,8 @@ static struct clk_branch gcc_port2_mac_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_port2_mac_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3950,9 +3819,8 @@ static struct clk_branch gcc_port3_mac_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_port3_mac_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3967,9 +3835,8 @@ static struct clk_branch gcc_port4_mac_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_port4_mac_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -3984,9 +3851,8 @@ static struct clk_branch gcc_port5_mac_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_port5_mac_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4001,9 +3867,8 @@ static struct clk_branch gcc_port6_mac_c
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_port6_mac_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_ppe_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_ppe_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4018,9 +3883,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port1_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port1_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port1_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4035,9 +3899,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port1_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port1_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port1_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4052,9 +3915,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port2_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port2_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port2_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4069,9 +3931,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port2_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port2_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port2_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4086,9 +3947,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port3_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port3_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port3_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4103,9 +3963,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port3_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port3_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port3_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4120,9 +3979,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port4_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port4_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port4_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4137,9 +3995,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port4_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port4_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port4_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4154,9 +4011,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port5_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4171,9 +4027,8 @@ static struct clk_branch gcc_uniphy0_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy0_port5_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4188,9 +4043,8 @@ static struct clk_branch gcc_uniphy1_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy1_port5_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4205,9 +4059,8 @@ static struct clk_branch gcc_uniphy1_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy1_port5_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port5_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port5_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4222,9 +4075,8 @@ static struct clk_branch gcc_uniphy2_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy2_port6_rx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port6_rx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port6_rx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4239,9 +4091,8 @@ static struct clk_branch gcc_uniphy2_por
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_uniphy2_port6_tx_clk",
+-                      .parent_names = (const char *[]){
+-                              "nss_port6_tx_div_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &nss_port6_tx_div_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4257,9 +4108,8 @@ static struct clk_branch gcc_crypto_ahb_
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_crypto_ahb_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4275,9 +4125,8 @@ static struct clk_branch gcc_crypto_axi_
+               .enable_mask = BIT(1),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_crypto_axi_clk",
+-                      .parent_names = (const char *[]){
+-                              "pcnoc_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &pcnoc_clk_src.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4293,9 +4142,8 @@ static struct clk_branch gcc_crypto_clk
+               .enable_mask = BIT(2),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_crypto_clk",
+-                      .parent_names = (const char *[]){
+-                              "crypto_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &crypto_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4310,9 +4158,8 @@ static struct clk_branch gcc_gp1_clk = {
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_gp1_clk",
+-                      .parent_names = (const char *[]){
+-                              "gp1_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gp1_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4327,9 +4174,8 @@ static struct clk_branch gcc_gp2_clk = {
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_gp2_clk",
+-                      .parent_names = (const char *[]){
+-                              "gp2_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gp2_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4344,9 +4190,8 @@ static struct clk_branch gcc_gp3_clk = {
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_gp3_clk",
+-                      .parent_names = (const char *[]){
+-                              "gp3_clk_src"
+-                      },
++                      .parent_hws = (const struct clk_hw *[]){
++                              &gp3_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+@@ -4368,7 +4213,7 @@ static struct clk_rcg2 pcie0_rchng_clk_s
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pcie0_rchng_clk_src",
+               .parent_data = gcc_xo_gpll0,
+-              .num_parents = 2,
++              .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+               .ops = &clk_rcg2_ops,
+       },
+ };
diff --git a/target/linux/qualcommax/patches-6.1/0008-v6.2-clk-qcom-reset-support-resetting-multiple-bits.patch b/target/linux/qualcommax/patches-6.1/0008-v6.2-clk-qcom-reset-support-resetting-multiple-bits.patch
new file mode 100644 (file)
index 0000000..e0725a6
--- /dev/null
@@ -0,0 +1,59 @@
+From 813ba3e427671ba3ff35c825087b03f0ad91cf02 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Mon, 7 Nov 2022 14:28:59 +0100
+Subject: [PATCH] clk: qcom: reset: support resetting multiple bits
+
+This patch adds the support for giving the complete bitmask
+in reset structure and reset operation will use this bitmask
+for all reset operations.
+
+Currently, reset structure only takes a single bit for each reset
+and then calculates the bitmask by using the BIT() macro.
+
+However, this is not sufficient anymore for newer SoC-s like IPQ8074,
+IPQ6018 and more, since their networking resets require multiple bits
+to be asserted in order to properly reset the HW block completely.
+
+So, in order to allow asserting multiple bits add "bitmask" field to
+qcom_reset_map, and then use that bitmask value if its populated in the
+driver, if its not populated, then we just default to existing behaviour
+and calculate the bitmask on the fly.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221107132901.489240-1-robimarko@gmail.com
+---
+ drivers/clk/qcom/reset.c | 4 ++--
+ drivers/clk/qcom/reset.h | 1 +
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/qcom/reset.c
++++ b/drivers/clk/qcom/reset.c
+@@ -30,7 +30,7 @@ qcom_reset_assert(struct reset_controlle
+       rst = to_qcom_reset_controller(rcdev);
+       map = &rst->reset_map[id];
+-      mask = BIT(map->bit);
++      mask = map->bitmask ? map->bitmask : BIT(map->bit);
+       return regmap_update_bits(rst->regmap, map->reg, mask, mask);
+ }
+@@ -44,7 +44,7 @@ qcom_reset_deassert(struct reset_control
+       rst = to_qcom_reset_controller(rcdev);
+       map = &rst->reset_map[id];
+-      mask = BIT(map->bit);
++      mask = map->bitmask ? map->bitmask : BIT(map->bit);
+       return regmap_update_bits(rst->regmap, map->reg, mask, 0);
+ }
+--- a/drivers/clk/qcom/reset.h
++++ b/drivers/clk/qcom/reset.h
+@@ -12,6 +12,7 @@ struct qcom_reset_map {
+       unsigned int reg;
+       u8 bit;
+       u8 udelay;
++      u32 bitmask;
+ };
+ struct regmap;
diff --git a/target/linux/qualcommax/patches-6.1/0009-v6.2-dt-bindings-clock-qcom-ipq8074-add-missing-networkin.patch b/target/linux/qualcommax/patches-6.1/0009-v6.2-dt-bindings-clock-qcom-ipq8074-add-missing-networkin.patch
new file mode 100644 (file)
index 0000000..75f16a1
--- /dev/null
@@ -0,0 +1,39 @@
+From e78a40eb24187a8b4f9b89e2181f674df39c2013 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Mon, 7 Nov 2022 14:29:00 +0100
+Subject: [PATCH] dt-bindings: clock: qcom: ipq8074: add missing networking
+ resets
+
+Add bindings for the missing networking resets found in IPQ8074 GCC.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221107132901.489240-2-robimarko@gmail.com
+---
+ include/dt-bindings/clock/qcom,gcc-ipq8074.h | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h
++++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h
+@@ -367,6 +367,20 @@
+ #define GCC_PCIE1_AHB_ARES                    129
+ #define GCC_PCIE1_AXI_MASTER_STICKY_ARES      130
+ #define GCC_PCIE0_AXI_SLAVE_STICKY_ARES               131
++#define GCC_PPE_FULL_RESET                    132
++#define GCC_UNIPHY0_SOFT_RESET                        133
++#define GCC_UNIPHY0_XPCS_RESET                        134
++#define GCC_UNIPHY1_SOFT_RESET                        135
++#define GCC_UNIPHY1_XPCS_RESET                        136
++#define GCC_UNIPHY2_SOFT_RESET                        137
++#define GCC_UNIPHY2_XPCS_RESET                        138
++#define GCC_EDMA_HW_RESET                     139
++#define GCC_NSSPORT1_RESET                    140
++#define GCC_NSSPORT2_RESET                    141
++#define GCC_NSSPORT3_RESET                    142
++#define GCC_NSSPORT4_RESET                    143
++#define GCC_NSSPORT5_RESET                    144
++#define GCC_NSSPORT6_RESET                    145
+ #define USB0_GDSC                             0
+ #define USB1_GDSC                             1
diff --git a/target/linux/qualcommax/patches-6.1/0010-v6.2-clk-qcom-ipq8074-add-missing-networking-resets.patch b/target/linux/qualcommax/patches-6.1/0010-v6.2-clk-qcom-ipq8074-add-missing-networking-resets.patch
new file mode 100644 (file)
index 0000000..212fc84
--- /dev/null
@@ -0,0 +1,41 @@
+From da76cb63d04dc22ed32123b8c1d084c006d67bfb Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Mon, 7 Nov 2022 14:29:01 +0100
+Subject: [PATCH] clk: qcom: ipq8074: add missing networking resets
+
+Downstream QCA 5.4 kernel defines networking resets which are not present
+in the mainline kernel but are required for the networking drivers.
+
+So, port the downstream resets and avoid using magic values for mask,
+construct mask for resets which require multiple bits to be set/cleared.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221107132901.489240-3-robimarko@gmail.com
+---
+ drivers/clk/qcom/gcc-ipq8074.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/clk/qcom/gcc-ipq8074.c
++++ b/drivers/clk/qcom/gcc-ipq8074.c
+@@ -4671,6 +4671,20 @@ static const struct qcom_reset_map gcc_i
+       [GCC_PCIE1_AXI_SLAVE_ARES] = { 0x76040, 4 },
+       [GCC_PCIE1_AHB_ARES] = { 0x76040, 5 },
+       [GCC_PCIE1_AXI_MASTER_STICKY_ARES] = { 0x76040, 6 },
++      [GCC_PPE_FULL_RESET] = { .reg = 0x68014, .bitmask = GENMASK(19, 16) },
++      [GCC_UNIPHY0_SOFT_RESET] = { .reg = 0x56004, .bitmask = GENMASK(13, 4) | BIT(1) },
++      [GCC_UNIPHY0_XPCS_RESET] = { 0x56004, 2 },
++      [GCC_UNIPHY1_SOFT_RESET] = { .reg = 0x56104, .bitmask = GENMASK(5, 4) | BIT(1) },
++      [GCC_UNIPHY1_XPCS_RESET] = { 0x56104, 2 },
++      [GCC_UNIPHY2_SOFT_RESET] = { .reg = 0x56204, .bitmask = GENMASK(5, 4) | BIT(1) },
++      [GCC_UNIPHY2_XPCS_RESET] = { 0x56204, 2 },
++      [GCC_EDMA_HW_RESET] = { .reg = 0x68014, .bitmask = GENMASK(21, 20) },
++      [GCC_NSSPORT1_RESET] = { .reg = 0x68014, .bitmask = BIT(24) | GENMASK(1, 0) },
++      [GCC_NSSPORT2_RESET] = { .reg = 0x68014, .bitmask = BIT(25) | GENMASK(3, 2) },
++      [GCC_NSSPORT3_RESET] = { .reg = 0x68014, .bitmask = BIT(26) | GENMASK(5, 4) },
++      [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) },
+ };
+ static struct gdsc *gcc_ipq8074_gdscs[] = {
diff --git a/target/linux/qualcommax/patches-6.1/0011-v6.2-clk-qcom-ipq8074-populate-fw_name-for-all-parents.patch b/target/linux/qualcommax/patches-6.1/0011-v6.2-clk-qcom-ipq8074-populate-fw_name-for-all-parents.patch
new file mode 100644 (file)
index 0000000..7372b1d
--- /dev/null
@@ -0,0 +1,152 @@
+From 78936d46470938caa9a7ea529deeb36777b4f98e Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 16 Nov 2022 22:46:55 +0100
+Subject: [PATCH] clk: qcom: ipq8074: populate fw_name for all parents
+
+It appears that having only .name populated in parent_data for clocks
+which are only globally searchable currently will not work as the clk core
+won't copy that name if there is no .fw_name present as well.
+
+So, populate .fw_name for all parent clocks in parent_data.
+
+Fixes: ae55ad32e273 ("clk: qcom: ipq8074: convert to parent data")
+
+Co-developed-by: Christian Marangi <ansuelsmth@gmail.com>
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221116214655.1116467-1-robimarko@gmail.com
+---
+ drivers/clk/qcom/gcc-ipq8074.c | 52 +++++++++++++++++-----------------
+ 1 file changed, 26 insertions(+), 26 deletions(-)
+
+--- a/drivers/clk/qcom/gcc-ipq8074.c
++++ b/drivers/clk/qcom/gcc-ipq8074.c
+@@ -680,7 +680,7 @@ static struct clk_rcg2 pcie0_aux_clk_src
+ };
+ static const struct clk_parent_data gcc_pcie20_phy0_pipe_clk_xo[] = {
+-      { .name = "pcie20_phy0_pipe_clk" },
++      { .fw_name = "pcie0_pipe", .name = "pcie20_phy0_pipe_clk" },
+       { .fw_name = "xo", .name = "xo" },
+ };
+@@ -733,7 +733,7 @@ static struct clk_rcg2 pcie1_aux_clk_src
+ };
+ static const struct clk_parent_data gcc_pcie20_phy1_pipe_clk_xo[] = {
+-      { .name = "pcie20_phy1_pipe_clk" },
++      { .fw_name = "pcie1_pipe", .name = "pcie20_phy1_pipe_clk" },
+       { .fw_name = "xo", .name = "xo" },
+ };
+@@ -1137,7 +1137,7 @@ static const struct freq_tbl ftbl_nss_no
+ static const struct clk_parent_data gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = {
+       { .fw_name = "xo", .name = "xo" },
+-      { .name = "bias_pll_nss_noc_clk" },
++      { .fw_name = "bias_pll_nss_noc_clk", .name = "bias_pll_nss_noc_clk" },
+       { .hw = &gpll0.clkr.hw },
+       { .hw = &gpll2.clkr.hw },
+ };
+@@ -1362,7 +1362,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", .name = "xo" },
+-      { .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 },
+@@ -1413,10 +1413,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", .name = "xo" },
+-      { .name = "uniphy0_gcc_rx_clk" },
+-      { .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 },
+-      { .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[] = {
+@@ -1465,10 +1465,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", .name = "xo" },
+-      { .name = "uniphy0_gcc_tx_clk" },
+-      { .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 },
+-      { .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[] = {
+@@ -1696,12 +1696,12 @@ static const struct freq_tbl ftbl_nss_po
+ static const struct clk_parent_data gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = {
+       { .fw_name = "xo", .name = "xo" },
+-      { .name = "uniphy0_gcc_rx_clk" },
+-      { .name = "uniphy0_gcc_tx_clk" },
+-      { .name = "uniphy1_gcc_rx_clk" },
+-      { .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 },
+-      { .name = "bias_pll_cc_clk" },
++      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
+ };
+ static const struct parent_map
+@@ -1758,12 +1758,12 @@ static const struct freq_tbl ftbl_nss_po
+ static const struct clk_parent_data gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = {
+       { .fw_name = "xo", .name = "xo" },
+-      { .name = "uniphy0_gcc_tx_clk" },
+-      { .name = "uniphy0_gcc_rx_clk" },
+-      { .name = "uniphy1_gcc_tx_clk" },
+-      { .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 },
+-      { .name = "bias_pll_cc_clk" },
++      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
+ };
+ static const struct parent_map
+@@ -1820,10 +1820,10 @@ static const struct freq_tbl ftbl_nss_po
+ static const struct clk_parent_data gcc_xo_uniphy2_rx_tx_ubi32_bias[] = {
+       { .fw_name = "xo", .name = "xo" },
+-      { .name = "uniphy2_gcc_rx_clk" },
+-      { .name = "uniphy2_gcc_tx_clk" },
++      { .fw_name = "uniphy2_gcc_rx_clk", .name = "uniphy2_gcc_rx_clk" },
++      { .fw_name = "uniphy2_gcc_tx_clk", .name = "uniphy2_gcc_tx_clk" },
+       { .hw = &ubi32_pll.clkr.hw },
+-      { .name = "bias_pll_cc_clk" },
++      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
+ };
+ static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
+@@ -1877,10 +1877,10 @@ static const struct freq_tbl ftbl_nss_po
+ static const struct clk_parent_data gcc_xo_uniphy2_tx_rx_ubi32_bias[] = {
+       { .fw_name = "xo", .name = "xo" },
+-      { .name = "uniphy2_gcc_tx_clk" },
+-      { .name = "uniphy2_gcc_rx_clk" },
++      { .fw_name = "uniphy2_gcc_tx_clk", .name = "uniphy2_gcc_tx_clk" },
++      { .fw_name = "uniphy2_gcc_rx_clk", .name = "uniphy2_gcc_rx_clk" },
+       { .hw = &ubi32_pll.clkr.hw },
+-      { .name = "bias_pll_cc_clk" },
++      { .fw_name = "bias_pll_cc_clk", .name = "bias_pll_cc_clk" },
+ };
+ static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
diff --git a/target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch b/target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch
new file mode 100644 (file)
index 0000000..1f99de0
--- /dev/null
@@ -0,0 +1,36 @@
+From 9033c3c86ea0dd35bd2ab957317573b755967298 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Sun, 30 Oct 2022 18:57:03 +0100
+Subject: [PATCH] arm64: dts: qcom: ipq8074: pass XO and sleep clocks to GCC
+
+Pass XO and sleep clocks to the GCC controller so it does not have to
+find them by matching globaly by name.
+
+If not passed directly, driver maintains backwards compatibility by then
+falling back to global lookup.
+
+Since we are here, set cell numbers in decimal instead of hex.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221030175703.1103224-3-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -361,9 +361,11 @@
+               gcc: gcc@1800000 {
+                       compatible = "qcom,gcc-ipq8074";
+                       reg = <0x01800000 0x80000>;
+-                      #clock-cells = <0x1>;
++                      clocks = <&xo>, <&sleep_clk>;
++                      clock-names = "xo", "sleep_clk";
++                      #clock-cells = <1>;
+                       #power-domain-cells = <1>;
+-                      #reset-cells = <0x1>;
++                      #reset-cells = <1>;
+               };
+               tcsr_mutex: hwlock@1905000 {
diff --git a/target/linux/qualcommax/patches-6.1/0013-v6.2-arm64-dts-qcom-add-PMP8074-DTSI.patch b/target/linux/qualcommax/patches-6.1/0013-v6.2-arm64-dts-qcom-add-PMP8074-DTSI.patch
new file mode 100644 (file)
index 0000000..cd14642
--- /dev/null
@@ -0,0 +1,149 @@
+From fb76b808f8628215afebaf0f8af0bde635302590 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:18:14 +0200
+Subject: [PATCH] arm64: dts: qcom: add PMP8074 DTSI
+
+PMP8074 is a companion PMIC to the Qualcomm IPQ8074 series that is
+controlled via SPMI.
+
+Add DTSI for it providing GPIO, regulator, RTC and VADC support.
+
+RTC is disabled by default as there is no built-in battery so it will
+loose time unless board vendor added a battery, so make it optional.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220818221815.346233-4-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/pmp8074.dtsi | 125 ++++++++++++++++++++++++++
+ 1 file changed, 125 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/qcom/pmp8074.dtsi
+
+--- /dev/null
++++ b/arch/arm64/boot/dts/qcom/pmp8074.dtsi
+@@ -0,0 +1,125 @@
++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
++
++#include <dt-bindings/spmi/spmi.h>
++#include <dt-bindings/iio/qcom,spmi-vadc.h>
++
++&spmi_bus {
++      pmic@0 {
++              compatible = "qcom,pmp8074", "qcom,spmi-pmic";
++              reg = <0x0 SPMI_USID>;
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              pmp8074_adc: adc@3100 {
++                      compatible = "qcom,spmi-adc-rev2";
++                      reg = <0x3100>;
++                      interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      #io-channel-cells = <1>;
++
++                      ref-gnd@0 {
++                              reg = <ADC5_REF_GND>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      vref-1p25@1 {
++                              reg = <ADC5_1P25VREF>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      vref-vadc@2 {
++                              reg = <ADC5_VREF_VADC>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      pmic_die: die-temp@6 {
++                              reg = <ADC5_DIE_TEMP>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      xo_therm: xo-temp@76 {
++                              reg = <ADC5_XO_THERM_100K_PU>;
++                              qcom,ratiometric;
++                              qcom,hw-settle-time = <200>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      pa_therm1: thermistor1@77 {
++                              reg = <ADC5_AMUX_THM1_100K_PU>;
++                              qcom,ratiometric;
++                              qcom,hw-settle-time = <200>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      pa_therm2: thermistor2@78 {
++                              reg = <ADC5_AMUX_THM2_100K_PU>;
++                              qcom,ratiometric;
++                              qcom,hw-settle-time = <200>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      pa_therm3: thermistor3@79 {
++                              reg = <ADC5_AMUX_THM3_100K_PU>;
++                              qcom,ratiometric;
++                              qcom,hw-settle-time = <200>;
++                              qcom,pre-scaling = <1 1>;
++                      };
++
++                      vph-pwr@131 {
++                              reg = <ADC5_VPH_PWR>;
++                              qcom,pre-scaling = <1 3>;
++                      };
++              };
++
++              pmp8074_rtc: rtc@6000 {
++                      compatible = "qcom,pm8941-rtc";
++                      reg = <0x6000>;
++                      reg-names = "rtc", "alarm";
++                      interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
++                      allow-set-time;
++                      status = "disabled";
++              };
++
++              pmp8074_gpios: gpio@c000 {
++                      compatible = "qcom,pmp8074-gpio", "qcom,spmi-gpio";
++                      reg = <0xc000>;
++                      gpio-controller;
++                      #gpio-cells = <2>;
++                      gpio-ranges = <&pmp8074_gpios 0 0 12>;
++                      interrupt-controller;
++                      #interrupt-cells = <2>;
++              };
++      };
++
++      pmic@1 {
++              compatible = "qcom,pmp8074", "qcom,spmi-pmic";
++              reg = <0x1 SPMI_USID>;
++
++              regulators {
++                      compatible = "qcom,pmp8074-regulators";
++
++                      s3: s3 {
++                              regulator-name = "vdd_s3";
++                              regulator-min-microvolt = <592000>;
++                              regulator-max-microvolt = <1064000>;
++                              regulator-always-on;
++                              regulator-boot-on;
++                      };
++
++                      s4: s4 {
++                              regulator-name = "vdd_s4";
++                              regulator-min-microvolt = <712000>;
++                              regulator-max-microvolt = <992000>;
++                              regulator-always-on;
++                              regulator-boot-on;
++                      };
++
++                      l11: l11 {
++                              regulator-name = "l11";
++                              regulator-min-microvolt = <1800000>;
++                              regulator-max-microvolt = <3300000>;
++                      };
++              };
++      };
++};
diff --git a/target/linux/qualcommax/patches-6.1/0014-v6.2-arm64-dts-qcom-ipq8074-hk01-add-VQMMC-supply.patch b/target/linux/qualcommax/patches-6.1/0014-v6.2-arm64-dts-qcom-ipq8074-hk01-add-VQMMC-supply.patch
new file mode 100644 (file)
index 0000000..ebd3763
--- /dev/null
@@ -0,0 +1,37 @@
+From 2c394cfc1779886048feca7dc7f4075da5f6328c Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 19 Aug 2022 00:18:15 +0200
+Subject: [PATCH] arm64: dts: qcom: ipq8074-hk01: add VQMMC supply
+
+Since now we have control over the PMP8074 PMIC providing various system
+voltages including L11 which provides the SDIO/eMMC I/O voltage set it as
+the SDHCI VQMMC supply.
+
+This allows SDHCI controller to switch to 1.8V I/O mode and support high
+speed modes like HS200 and HS400.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220818221815.346233-5-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/ipq8074-hk01.dts | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
++++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
+@@ -3,6 +3,7 @@
+ /* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+  */
+ #include "ipq8074.dtsi"
++#include "pmp8074.dtsi"
+ / {
+       model = "Qualcomm Technologies, Inc. IPQ8074-HK01";
+@@ -84,6 +85,7 @@
+ &sdhc_1 {
+       status = "okay";
++      vqmmc-supply = <&l11>;
+ };
+ &qusb_phy_0 {
diff --git a/target/linux/qualcommax/patches-6.1/0015-v6.2-arm64-dts-qcom-hk01-use-GPIO-flags-for-tlmm.patch b/target/linux/qualcommax/patches-6.1/0015-v6.2-arm64-dts-qcom-hk01-use-GPIO-flags-for-tlmm.patch
new file mode 100644 (file)
index 0000000..e08f6d1
--- /dev/null
@@ -0,0 +1,42 @@
+From 82ceb86227b1fc15c76d5fc691b2bf425f1a63b3 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Mon, 7 Nov 2022 10:29:30 +0100
+Subject: [PATCH] arm64: dts: qcom: hk01: use GPIO flags for tlmm
+
+Use respective GPIO_ACTIVE_LOW/HIGH flags for tlmm GPIOs instead of
+harcoding the cell value.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221107092930.33325-3-robimarko@gmail.com
+---
+ arch/arm64/boot/dts/qcom/ipq8074-hk01.dts | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
++++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
+@@ -4,6 +4,7 @@
+  */
+ #include "ipq8074.dtsi"
+ #include "pmp8074.dtsi"
++#include <dt-bindings/gpio/gpio.h>
+ / {
+       model = "Qualcomm Technologies, Inc. IPQ8074-HK01";
+@@ -52,12 +53,12 @@
+ &pcie0 {
+       status = "okay";
+-      perst-gpios = <&tlmm 61 0x1>;
++      perst-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
+ };
+ &pcie1 {
+       status = "okay";
+-      perst-gpios = <&tlmm 58 0x1>;
++      perst-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>;
+ };
+ &pcie_qmp0 {
diff --git a/target/linux/qualcommax/patches-6.1/0016-v6.2-arm64-dts-qcom-ipq8074-Fix-up-comments.patch b/target/linux/qualcommax/patches-6.1/0016-v6.2-arm64-dts-qcom-ipq8074-Fix-up-comments.patch
new file mode 100644 (file)
index 0000000..a8bf249
--- /dev/null
@@ -0,0 +1,82 @@
+From 1b1c1423ca3e740984aa883512a72c4ea08fbe28 Mon Sep 17 00:00:00 2001
+From: Konrad Dybcio <konrad.dybcio@linaro.org>
+Date: Mon, 7 Nov 2022 15:55:17 +0100
+Subject: [PATCH] arm64: dts: qcom: ipq8074-*: Fix up comments
+
+Make sure all multiline C-style commends begin with just '/*' with
+the comment text starting on a new line.
+
+Also, fix up some whitespace within comments.
+
+Signed-off-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221107145522.6706-8-konrad.dybcio@linaro.org
+---
+ arch/arm64/boot/dts/qcom/ipq8074-hk01.dts    |  3 ++-
+ arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts |  3 ++-
+ arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts |  3 ++-
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi        | 12 ++++++------
+ 4 files changed, 12 insertions(+), 9 deletions(-)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
++++ b/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ /dts-v1/;
+-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
++/*
++ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+  */
+ #include "ipq8074.dtsi"
+ #include "pmp8074.dtsi"
+--- a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
++++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts
+@@ -1,5 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+-/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
++/*
++ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+  */
+ /dts-v1/;
+--- a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
++++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ /dts-v1/;
+-/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
++/*
++ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+  */
+ #include "ipq8074-hk10.dtsi"
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -129,10 +129,10 @@
+                       status = "disabled";
+                       usb1_ssphy: phy@58200 {
+-                              reg = <0x00058200 0x130>,       /* Tx */
++                              reg = <0x00058200 0x130>,     /* Tx */
+                                     <0x00058400 0x200>,     /* Rx */
+-                                    <0x00058800 0x1f8>,     /* PCS  */
+-                                    <0x00058600 0x044>;     /* PCS misc*/
++                                    <0x00058800 0x1f8>,     /* PCS */
++                                    <0x00058600 0x044>;     /* PCS misc */
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB1_PIPE_CLK>;
+@@ -172,10 +172,10 @@
+                       status = "disabled";
+                       usb0_ssphy: phy@78200 {
+-                              reg = <0x00078200 0x130>,       /* Tx */
++                              reg = <0x00078200 0x130>,     /* Tx */
+                                     <0x00078400 0x200>,     /* Rx */
+-                                    <0x00078800 0x1f8>,     /* PCS  */
+-                                    <0x00078600 0x044>;     /* PCS misc*/
++                                    <0x00078800 0x1f8>,     /* PCS */
++                                    <0x00078600 0x044>;     /* PCS misc */
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB0_PIPE_CLK>;
diff --git a/target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch b/target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch
new file mode 100644 (file)
index 0000000..1ce1140
--- /dev/null
@@ -0,0 +1,60 @@
+From 5f20690f77878b1ba24ec88df01b92d5131a6780 Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Date: Tue, 8 Nov 2022 15:23:57 +0100
+Subject: [PATCH] arm64: dts: qcom: ipq8074: align TLMM pin configuration with
+ DT schema
+
+DT schema expects TLMM pin configuration nodes to be named with
+'-state' suffix and their optional children with '-pins' suffix.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20221108142357.67202-2-krzysztof.kozlowski@linaro.org
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -318,35 +318,35 @@
+                       interrupt-controller;
+                       #interrupt-cells = <0x2>;
+-                      serial_4_pins: serial4-pinmux {
++                      serial_4_pins: serial4-state {
+                               pins = "gpio23", "gpio24";
+                               function = "blsp4_uart1";
+                               drive-strength = <8>;
+                               bias-disable;
+                       };
+-                      i2c_0_pins: i2c-0-pinmux {
++                      i2c_0_pins: i2c-0-state {
+                               pins = "gpio42", "gpio43";
+                               function = "blsp1_i2c";
+                               drive-strength = <8>;
+                               bias-disable;
+                       };
+-                      spi_0_pins: spi-0-pins {
++                      spi_0_pins: spi-0-state {
+                               pins = "gpio38", "gpio39", "gpio40", "gpio41";
+                               function = "blsp0_spi";
+                               drive-strength = <8>;
+                               bias-disable;
+                       };
+-                      hsuart_pins: hsuart-pins {
++                      hsuart_pins: hsuart-state {
+                               pins = "gpio46", "gpio47", "gpio48", "gpio49";
+                               function = "blsp2_uart";
+                               drive-strength = <8>;
+                               bias-disable;
+                       };
+-                      qpic_pins: qpic-pins {
++                      qpic_pins: qpic-state {
+                               pins = "gpio1", "gpio3", "gpio4",
+                                      "gpio5", "gpio6", "gpio7",
+                                      "gpio8", "gpio10", "gpio11",
diff --git a/target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch b/target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch
new file mode 100644 (file)
index 0000000..8719bf7
--- /dev/null
@@ -0,0 +1,24 @@
+From a4748d2850783d36f77ccf2b5fcc86ccf1800ef1 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 16 Nov 2022 22:48:36 +0100
+Subject: [PATCH] arm64: dts: qcom: ipq8074: set Gen2 PCIe pcie max-link-speed
+
+Add the generic 'max-link-speed' property to describe the Gen2 PCIe link
+generation limit.
+This allows the generic DWC code to configure the link speed correctly.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -766,6 +766,7 @@
+                       linux,pci-domain = <1>;
+                       bus-range = <0x00 0xff>;
+                       num-lanes = <1>;
++                      max-link-speed = <2>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
diff --git a/target/linux/qualcommax/patches-6.1/0020-v6.3-PCI-qcom-Add-support-for-IPQ8074-Gen3-port.patch b/target/linux/qualcommax/patches-6.1/0020-v6.3-PCI-qcom-Add-support-for-IPQ8074-Gen3-port.patch
new file mode 100644 (file)
index 0000000..60caee4
--- /dev/null
@@ -0,0 +1,26 @@
+From f356132229b18ceef5d5ef9103bbaa9bdeb84c8d Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Fri, 13 Jan 2023 17:44:47 +0100
+Subject: [PATCH] PCI: qcom: Add IPQ8074 Gen3 port support
+
+IPQ8074 has one Gen2 and one Gen3 port, with Gen2 port already supported.
+Add compatible for Gen3 port which uses the same controller as IPQ6018.
+
+Link: https://lore.kernel.org/r/20230113164449.906002-7-robimarko@gmail.com
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.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
+@@ -1745,6 +1745,7 @@ static const struct of_device_id qcom_pc
+       { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
+       { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
+       { .compatible = "qcom,pcie-ipq8074", .data = &cfg_2_3_3 },
++      { .compatible = "qcom,pcie-ipq8074-gen3", .data = &cfg_2_9_0 },
+       { .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 },
+       { .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 },
+       { .compatible = "qcom,pcie-sa8540p", .data = &cfg_1_9_0 },
diff --git a/target/linux/qualcommax/patches-6.1/0021-v6.3-clk-qcom-ipq8074-populate-fw_name-for-usb3phy-s.patch b/target/linux/qualcommax/patches-6.1/0021-v6.3-clk-qcom-ipq8074-populate-fw_name-for-usb3phy-s.patch
new file mode 100644 (file)
index 0000000..eb772be
--- /dev/null
@@ -0,0 +1,38 @@
+From 614d31c231c7707322b643f409eeb7e28adc7f8c Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Sun, 8 Jan 2023 13:36:28 +0100
+Subject: [PATCH] clk: qcom: ipq8074: populate fw_name for usb3phy-s
+
+Having only .name populated in parent_data for clocks which are only
+globally searchable currently will not work as the clk core won't copy
+that name if there is no .fw_name present as well.
+
+So, populate .fw_name for usb3phy clocks in parent_data as they were
+missed by me in ("clk: qcom: ipq8074: populate fw_name for all parents").
+
+Fixes: ae55ad32e273 ("clk: qcom: ipq8074: convert to parent data")
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ drivers/clk/qcom/gcc-ipq8074.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/qcom/gcc-ipq8074.c
++++ b/drivers/clk/qcom/gcc-ipq8074.c
+@@ -934,7 +934,7 @@ static struct clk_rcg2 usb0_mock_utmi_cl
+ };
+ static const struct clk_parent_data gcc_usb3phy_0_cc_pipe_clk_xo[] = {
+-      { .name = "usb3phy_0_cc_pipe_clk" },
++      { .fw_name = "usb3phy_0_cc_pipe_clk", .name = "usb3phy_0_cc_pipe_clk" },
+       { .fw_name = "xo", .name = "xo" },
+ };
+@@ -1002,7 +1002,7 @@ static struct clk_rcg2 usb1_mock_utmi_cl
+ };
+ static const struct clk_parent_data gcc_usb3phy_1_cc_pipe_clk_xo[] = {
+-      { .name = "usb3phy_1_cc_pipe_clk" },
++      { .fw_name = "usb3phy_1_cc_pipe_clk", .name = "usb3phy_1_cc_pipe_clk" },
+       { .fw_name = "xo", .name = "xo" },
+ };
diff --git a/target/linux/qualcommax/patches-6.1/0022-v6.5-soc-qcom-mdt_loader-Fix-unconditional-call-to-scm_pa.patch b/target/linux/qualcommax/patches-6.1/0022-v6.5-soc-qcom-mdt_loader-Fix-unconditional-call-to-scm_pa.patch
new file mode 100644 (file)
index 0000000..72b3827
--- /dev/null
@@ -0,0 +1,77 @@
+From b8295c6eb276b60f7b75c53a9703ca8fee01eba2 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Fri, 26 May 2023 13:09:17 +0200
+Subject: [PATCH] soc: qcom: mdt_loader: Fix unconditional call to
+ scm_pas_mem_setup
+
+Commit ebeb20a9cd3f ("soc: qcom: mdt_loader: Always invoke PAS
+mem_setup") dropped the relocate check and made pas_mem_setup run
+unconditionally. The code was later moved with commit f4e526ff7e38
+("soc: qcom: mdt_loader: Extract PAS operations") to
+qcom_mdt_pas_init() effectively losing track of what was actually
+done.
+
+The assumption that PAS mem_setup can be done anytime was effectively
+wrong, with no good reason and this caused regression on some SoC
+that use remoteproc to bringup ath11k. One example is IPQ8074 SoC that
+effectively broke resulting in remoteproc silently die and ath11k not
+working.
+
+On this SoC FW relocate is not enabled and PAS mem_setup was correctly
+skipped in previous kernel version resulting in correct bringup and
+function of remoteproc and ath11k.
+
+To fix the regression, reintroduce the relocate check in
+qcom_mdt_pas_init() and correctly skip PAS mem_setup where relocate is
+not enabled.
+
+Fixes: ebeb20a9cd3f ("soc: qcom: mdt_loader: Always invoke PAS mem_setup")
+Reported-by: Robert Marko <robimarko@gmail.com>
+Tested-by: Robert Marko <robimarko@gmail.com>
+Co-developed-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Cc: stable@vger.kernel.org
+---
+ drivers/soc/qcom/mdt_loader.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/soc/qcom/mdt_loader.c
++++ b/drivers/soc/qcom/mdt_loader.c
+@@ -210,6 +210,7 @@ int qcom_mdt_pas_init(struct device *dev
+       const struct elf32_hdr *ehdr;
+       phys_addr_t min_addr = PHYS_ADDR_MAX;
+       phys_addr_t max_addr = 0;
++      bool relocate = false;
+       size_t metadata_len;
+       void *metadata;
+       int ret;
+@@ -224,6 +225,9 @@ int qcom_mdt_pas_init(struct device *dev
+               if (!mdt_phdr_valid(phdr))
+                       continue;
++              if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
++                      relocate = true;
++
+               if (phdr->p_paddr < min_addr)
+                       min_addr = phdr->p_paddr;
+@@ -246,11 +250,13 @@ int qcom_mdt_pas_init(struct device *dev
+               goto out;
+       }
+-      ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
+-      if (ret) {
+-              /* Unable to set up relocation */
+-              dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
+-              goto out;
++      if (relocate) {
++              ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
++              if (ret) {
++                      /* Unable to set up relocation */
++                      dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
++                      goto out;
++              }
+       }
+ out:
diff --git a/target/linux/qualcommax/patches-6.1/0100-clk-qcom-clk-rcg2-introduce-support-for-multiple-con.patch b/target/linux/qualcommax/patches-6.1/0100-clk-qcom-clk-rcg2-introduce-support-for-multiple-con.patch
new file mode 100644 (file)
index 0000000..5713775
--- /dev/null
@@ -0,0 +1,203 @@
+From 032be4f49dda786fea9e1501212f6cd09a7ded96 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Thu, 3 Nov 2022 14:49:43 +0100
+Subject: [PATCH] clk: qcom: clk-rcg2: introduce support for multiple conf for
+ same freq
+
+Some RCG frequency can be reached by multiple configuration.
+
+We currently declare multiple configuration for the same frequency but
+that is not supported and always the first configuration will be taken.
+
+These multiple configuration are needed as based on the current parent
+configuration, it may be needed to use a different configuration to
+reach the same frequency.
+
+To handle this introduce 2 new macro, FM and C.
+
+- FM is used to declare an empty freq_tbl with just the frequency and an
+  array of confs to insert all the config for the provided frequency.
+
+- C is used to declare a fre_conf where src, pre_div, m and n are
+  provided.
+
+The driver is changed to handle this special freq_tbl and select the
+correct config by calculating the final rate and deciding based on the
+one that is less different than the requested one.
+
+Tested-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+---
+ drivers/clk/qcom/clk-rcg.h  | 14 ++++++-
+ drivers/clk/qcom/clk-rcg2.c | 84 +++++++++++++++++++++++++++++++++----
+ 2 files changed, 88 insertions(+), 10 deletions(-)
+
+--- a/drivers/clk/qcom/clk-rcg.h
++++ b/drivers/clk/qcom/clk-rcg.h
+@@ -7,7 +7,17 @@
+ #include <linux/clk-provider.h>
+ #include "clk-regmap.h"
+-#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
++#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n), 0, NULL }
++
++#define FM(_f, _confs) { .freq = (_f), .confs_num = ARRAY_SIZE(_confs), .confs = (_confs) }
++#define C(s, h, m, n) { (s), (2 * (h) - 1), (m), (n) }
++
++struct freq_conf {
++      u8 src;
++      u8 pre_div;
++      u16 m;
++      u16 n;
++};
+ struct freq_tbl {
+       unsigned long freq;
+@@ -15,6 +25,8 @@ struct freq_tbl {
+       u8 pre_div;
+       u16 m;
+       u16 n;
++      int confs_num;
++      const struct freq_conf *confs;
+ };
+ /**
+--- a/drivers/clk/qcom/clk-rcg2.c
++++ b/drivers/clk/qcom/clk-rcg2.c
+@@ -209,11 +209,60 @@ clk_rcg2_recalc_rate(struct clk_hw *hw,
+       return __clk_rcg2_recalc_rate(hw, parent_rate, cfg);
+ }
++static void
++clk_rcg2_select_conf(struct clk_hw *hw, struct freq_tbl *f_tbl,
++                   const struct freq_tbl *f, unsigned long req_rate)
++{
++      unsigned long best_rate = 0, parent_rate, rate;
++      const struct freq_conf *conf, *best_conf;
++      struct clk_rcg2 *rcg = to_clk_rcg2(hw);
++      struct clk_hw *p;
++      int index, i;
++
++      /* Search in each provided config the one that is near the wanted rate */
++      for (i = 0, conf = f->confs; i < f->confs_num; i++, conf++) {
++              index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
++              if (index < 0)
++                      continue;
++
++              p = clk_hw_get_parent_by_index(hw, index);
++              if (!p)
++                      continue;
++
++              parent_rate =  clk_hw_get_rate(p);
++              rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div);
++
++              if (rate == req_rate) {
++                      best_conf = conf;
++                      break;
++              }
++
++              if (abs(req_rate - rate) < abs(best_rate - rate)) {
++                      best_rate = rate;
++                      best_conf = conf;
++              }
++      }
++
++      /*
++       * Very unlikely.
++       * Force the first conf if we can't find a correct config.
++       */
++      if (unlikely(i == f->confs_num))
++              best_conf = f->confs;
++
++      /* Apply the config */
++      f_tbl->src = best_conf->src;
++      f_tbl->pre_div = best_conf->pre_div;
++      f_tbl->m = best_conf->m;
++      f_tbl->n = best_conf->n;
++}
++
+ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
+                                   struct clk_rate_request *req,
+                                   enum freq_policy policy)
+ {
+       unsigned long clk_flags, rate = req->rate;
++      struct freq_tbl f_tbl;
+       struct clk_hw *p;
+       struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+       int index;
+@@ -232,7 +281,15 @@ static int _freq_tbl_determine_rate(stru
+       if (!f)
+               return -EINVAL;
+-      index = qcom_find_src_index(hw, rcg->parent_map, f->src);
++      f_tbl = *f;
++      /*
++       * A single freq may be reached by multiple configuration.
++       * Try to find the bast one if we have this kind of freq_table.
++       */
++      if (f->confs)
++              clk_rcg2_select_conf(hw, &f_tbl, f, rate);
++
++      index = qcom_find_src_index(hw, rcg->parent_map, f_tbl.src);
+       if (index < 0)
+               return index;
+@@ -242,18 +299,18 @@ static int _freq_tbl_determine_rate(stru
+               return -EINVAL;
+       if (clk_flags & CLK_SET_RATE_PARENT) {
+-              rate = f->freq;
+-              if (f->pre_div) {
++              rate = f_tbl.freq;
++              if (f_tbl.pre_div) {
+                       if (!rate)
+                               rate = req->rate;
+                       rate /= 2;
+-                      rate *= f->pre_div + 1;
++                      rate *= f_tbl.pre_div + 1;
+               }
+-              if (f->n) {
++              if (f_tbl.n) {
+                       u64 tmp = rate;
+-                      tmp = tmp * f->n;
+-                      do_div(tmp, f->m);
++                      tmp = tmp * f_tbl.n;
++                      do_div(tmp, f_tbl.m);
+                       rate = tmp;
+               }
+       } else {
+@@ -261,7 +318,7 @@ static int _freq_tbl_determine_rate(stru
+       }
+       req->best_parent_hw = p;
+       req->best_parent_rate = rate;
+-      req->rate = f->freq;
++      req->rate = f_tbl.freq;
+       return 0;
+ }
+@@ -357,6 +414,7 @@ static int __clk_rcg2_set_rate(struct cl
+ {
+       struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+       const struct freq_tbl *f;
++      struct freq_tbl f_tbl;
+       switch (policy) {
+       case FLOOR:
+@@ -372,7 +430,15 @@ static int __clk_rcg2_set_rate(struct cl
+       if (!f)
+               return -EINVAL;
+-      return clk_rcg2_configure(rcg, f);
++      f_tbl = *f;
++      /*
++       * A single freq may be reached by multiple configuration.
++       * Try to find the best one if we have this kind of freq_table.
++       */
++      if (f->confs)
++              clk_rcg2_select_conf(hw, &f_tbl, f, rate);
++
++      return clk_rcg2_configure(rcg, &f_tbl);
+ }
+ static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/target/linux/qualcommax/patches-6.1/0101-clk-qcom-gcc-ipq8074-rework-nss_port5-6-clock-to-mul.patch b/target/linux/qualcommax/patches-6.1/0101-clk-qcom-gcc-ipq8074-rework-nss_port5-6-clock-to-mul.patch
new file mode 100644 (file)
index 0000000..32fb2d9
--- /dev/null
@@ -0,0 +1,129 @@
+From f778553f296792f4d1e8b3552603ad6116ea3eb3 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Thu, 3 Nov 2022 14:49:44 +0100
+Subject: [PATCH] clk: qcom: gcc-ipq8074: rework nss_port5/6 clock to multiple
+ conf
+
+Rework nss_port5/6 to use the new multiple configuration implementation
+and correctly fix the clocks for these port under some corner case.
+
+This is particularly relevant for device that have 2.5G or 10G port
+connected to port5 or port 6 on ipq8074. As the parent are shared
+across multiple port it may be required to select the correct
+configuration to accomplish the desired clock. Without this patch such
+port doesn't work in some specific ethernet speed as the clock will be
+set to the wrong frequency as we just select the first configuration for
+the related frequency instead of selecting the best one.
+
+Tested-by: Robert Marko <robimarko@gmail.com> # ipq8074 Qnap QHora-301W
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+---
+ drivers/clk/qcom/gcc-ipq8074.c | 64 +++++++++++++++++++++++++---------
+ 1 file changed, 48 insertions(+), 16 deletions(-)
+
+--- a/drivers/clk/qcom/gcc-ipq8074.c
++++ b/drivers/clk/qcom/gcc-ipq8074.c
+@@ -1682,13 +1682,21 @@ static struct clk_regmap_div nss_port4_t
+       },
+ };
++static const struct freq_conf ftbl_nss_port5_rx_clk_src_25[] = {
++      C(P_UNIPHY1_RX, 12.5, 0, 0),
++      C(P_UNIPHY0_RX, 5, 0, 0),
++};
++
++static const struct freq_conf ftbl_nss_port5_rx_clk_src_125[] = {
++      C(P_UNIPHY1_RX, 2.5, 0, 0),
++      C(P_UNIPHY0_RX, 1, 0, 0),
++};
++
+ static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = {
+       F(19200000, P_XO, 1, 0, 0),
+-      F(25000000, P_UNIPHY1_RX, 12.5, 0, 0),
+-      F(25000000, P_UNIPHY0_RX, 5, 0, 0),
++      FM(25000000, ftbl_nss_port5_rx_clk_src_25),
+       F(78125000, P_UNIPHY1_RX, 4, 0, 0),
+-      F(125000000, P_UNIPHY1_RX, 2.5, 0, 0),
+-      F(125000000, P_UNIPHY0_RX, 1, 0, 0),
++      FM(125000000, ftbl_nss_port5_rx_clk_src_125),
+       F(156250000, P_UNIPHY1_RX, 2, 0, 0),
+       F(312500000, P_UNIPHY1_RX, 1, 0, 0),
+       { }
+@@ -1744,13 +1752,21 @@ static struct clk_regmap_div nss_port5_r
+       },
+ };
++static struct freq_conf ftbl_nss_port5_tx_clk_src_25[] = {
++      C(P_UNIPHY1_TX, 12.5, 0, 0),
++      C(P_UNIPHY0_TX, 5, 0, 0),
++};
++
++static struct freq_conf ftbl_nss_port5_tx_clk_src_125[] = {
++      C(P_UNIPHY1_TX, 2.5, 0, 0),
++      C(P_UNIPHY0_TX, 1, 0, 0),
++};
++
+ static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = {
+       F(19200000, P_XO, 1, 0, 0),
+-      F(25000000, P_UNIPHY1_TX, 12.5, 0, 0),
+-      F(25000000, P_UNIPHY0_TX, 5, 0, 0),
++      FM(25000000, ftbl_nss_port5_tx_clk_src_25),
+       F(78125000, P_UNIPHY1_TX, 4, 0, 0),
+-      F(125000000, P_UNIPHY1_TX, 2.5, 0, 0),
+-      F(125000000, P_UNIPHY0_TX, 1, 0, 0),
++      FM(125000000, ftbl_nss_port5_tx_clk_src_125),
+       F(156250000, P_UNIPHY1_TX, 2, 0, 0),
+       F(312500000, P_UNIPHY1_TX, 1, 0, 0),
+       { }
+@@ -1806,13 +1822,21 @@ static struct clk_regmap_div nss_port5_t
+       },
+ };
++static struct freq_conf ftbl_nss_port6_rx_clk_src_25[] = {
++      C(P_UNIPHY2_RX, 5, 0, 0),
++      C(P_UNIPHY2_RX, 12.5, 0, 0),
++};
++
++static struct freq_conf ftbl_nss_port6_rx_clk_src_125[] = {
++      C(P_UNIPHY2_RX, 1, 0, 0),
++      C(P_UNIPHY2_RX, 2.5, 0, 0),
++};
++
+ static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = {
+       F(19200000, P_XO, 1, 0, 0),
+-      F(25000000, P_UNIPHY2_RX, 5, 0, 0),
+-      F(25000000, P_UNIPHY2_RX, 12.5, 0, 0),
++      FM(25000000, ftbl_nss_port6_rx_clk_src_25),
+       F(78125000, P_UNIPHY2_RX, 4, 0, 0),
+-      F(125000000, P_UNIPHY2_RX, 1, 0, 0),
+-      F(125000000, P_UNIPHY2_RX, 2.5, 0, 0),
++      FM(125000000, ftbl_nss_port6_rx_clk_src_125),
+       F(156250000, P_UNIPHY2_RX, 2, 0, 0),
+       F(312500000, P_UNIPHY2_RX, 1, 0, 0),
+       { }
+@@ -1863,13 +1887,21 @@ static struct clk_regmap_div nss_port6_r
+       },
+ };
++static struct freq_conf ftbl_nss_port6_tx_clk_src_25[] = {
++      C(P_UNIPHY2_TX, 5, 0, 0),
++      C(P_UNIPHY2_TX, 12.5, 0, 0),
++};
++
++static struct freq_conf ftbl_nss_port6_tx_clk_src_125[] = {
++      C(P_UNIPHY2_TX, 1, 0, 0),
++      C(P_UNIPHY2_TX, 2.5, 0, 0),
++};
++
+ static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = {
+       F(19200000, P_XO, 1, 0, 0),
+-      F(25000000, P_UNIPHY2_TX, 5, 0, 0),
+-      F(25000000, P_UNIPHY2_TX, 12.5, 0, 0),
++      FM(25000000, ftbl_nss_port6_tx_clk_src_25),
+       F(78125000, P_UNIPHY2_TX, 4, 0, 0),
+-      F(125000000, P_UNIPHY2_TX, 1, 0, 0),
+-      F(125000000, P_UNIPHY2_TX, 2.5, 0, 0),
++      FM(125000000, ftbl_nss_port6_tx_clk_src_125),
+       F(156250000, P_UNIPHY2_TX, 2, 0, 0),
+       F(312500000, P_UNIPHY2_TX, 1, 0, 0),
+       { }
diff --git a/target/linux/qualcommax/patches-6.1/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch b/target/linux/qualcommax/patches-6.1/0102-arm64-dts-ipq8074-add-reserved-memory-nodes.patch
new file mode 100644 (file)
index 0000000..af53c07
--- /dev/null
@@ -0,0 +1,70 @@
+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
+@@ -85,6 +85,26 @@
+               #size-cells = <2>;
+               ranges;
++              nss@40000000 {
++                      no-map;
++                      reg = <0x0 0x40000000 0x0 0x01000000>;
++              };
++
++              tzapp_region: tzapp@4a400000 {
++                      no-map;
++                      reg = <0x0 0x4a400000 0x0 0x00200000>;
++              };
++
++              uboot@4a600000 {
++                      no-map;
++                      reg = <0x0 0x4a600000 0x0 0x00400000>;
++              };
++
++              sbl@4aa00000 {
++                      no-map;
++                      reg = <0x0 0x4aa00000 0x0 0x00100000>;
++              };
++
+               smem@4ab00000 {
+                       compatible = "qcom,smem";
+                       reg = <0x0 0x4ab00000 0x0 0x00100000>;
+@@ -97,6 +117,21 @@
+                       no-map;
+                       reg = <0x0 0x4ac00000 0x0 0x00400000>;
+               };
++
++              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.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch b/target/linux/qualcommax/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch
new file mode 100644 (file)
index 0000000..69d4126
--- /dev/null
@@ -0,0 +1,30 @@
+From 8a576b5bc9f0555d1d970cacabcaa24a3b74fa57 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 16 Nov 2022 22:15:01 +0100
+Subject: [PATCH] arm64: dts: qcom: ipq8074: pass QMP PCI PHY PIPE clocks to
+ GCC
+
+Pass QMP PCI PHY PIPE clocks to the GCC controller so it does not have to
+find them by matching globaly by name.
+
+If not passed directly, driver maintains backwards compatibility by then
+falling back to global lookup.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -396,8 +396,8 @@
+               gcc: gcc@1800000 {
+                       compatible = "qcom,gcc-ipq8074";
+                       reg = <0x01800000 0x80000>;
+-                      clocks = <&xo>, <&sleep_clk>;
+-                      clock-names = "xo", "sleep_clk";
++                      clocks = <&xo>, <&sleep_clk>, <&pcie_phy0>, <&pcie_phy1>;
++                      clock-names = "xo", "sleep_clk", "pcie0_pipe", "pcie1_pipe";
+                       #clock-cells = <1>;
+                       #power-domain-cells = <1>;
+                       #reset-cells = <1>;
diff --git a/target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch b/target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch
new file mode 100644 (file)
index 0000000..9fefd88
--- /dev/null
@@ -0,0 +1,43 @@
+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
+@@ -699,7 +699,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>;
+@@ -811,8 +811,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 142
+@@ -873,8 +872,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 75
diff --git a/target/linux/qualcommax/patches-6.1/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch b/target/linux/qualcommax/patches-6.1/0112-remoteproc-qcom-Add-PRNG-proxy-clock.patch
new file mode 100644 (file)
index 0000000..0a98494
--- /dev/null
@@ -0,0 +1,155 @@
+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;
+@@ -151,6 +139,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;
+@@ -240,6 +243,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 */
+@@ -733,6 +742,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)
+               goto free_rproc;
+-      if (wcss->version == WCSS_QCS404) {
+-              ret = q6v5_wcss_init_clock(wcss);
++      if (desc->init_clock) {
++              ret = desc->init_clock(wcss);
+               if (ret)
+                       goto free_rproc;
++      }
+-              ret = q6v5_wcss_init_regulator(wcss);
++      if (desc->init_regulator) {
++              ret = desc->init_regulator(wcss);
+               if (ret)
+                       goto free_rproc;
+       }
+@@ -1087,6 +1113,7 @@ static int q6v5_wcss_remove(struct platf
+ }
+ 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,
+@@ -1096,6 +1123,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.1/0113-remoteproc-qcom-Add-secure-PIL-support.patch b/target/linux/qualcommax/patches-6.1/0113-remoteproc-qcom-Add-secure-PIL-support.patch
new file mode 100644 (file)
index 0000000..0328efc
--- /dev/null
@@ -0,0 +1,143 @@
+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/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          3
++
++#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_ssr ssr_subdev;
+@@ -152,6 +157,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)
+@@ -251,6 +257,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) {
+@@ -285,6 +300,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");
+@@ -718,6 +734,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);
+@@ -742,6 +767,7 @@ static int q6v5_wcss_stop(struct rproc *
+                       return ret;
+       }
++pas_done:
+       clk_disable_unprepare(wcss->prng_clk);
+       qcom_q6v5_unprepare(&wcss->q6v5);
+@@ -765,9 +791,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 = 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)
+@@ -1120,6 +1156,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.1/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch b/target/linux/qualcommax/patches-6.1/0114-remoteproc-qcom-Add-support-for-split-q6-m3-wlan-fir.patch
new file mode 100644 (file)
index 0000000..e5c9506
--- /dev/null
@@ -0,0 +1,103 @@
+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_ssr ssr_subdev;
+@@ -147,7 +148,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;
+@@ -789,8 +791,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 = 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)
+@@ -1150,7 +1174,8 @@ static int q6v5_wcss_remove(struct platf
+ 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,
+@@ -1163,7 +1188,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.1/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch b/target/linux/qualcommax/patches-6.1/0115-remoteproc-qcom-Add-ssr-subdevice-identifier.patch
new file mode 100644 (file)
index 0000000..be63d46
--- /dev/null
@@ -0,0 +1,24 @@
+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
+@@ -1179,6 +1179,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.1/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch b/target/linux/qualcommax/patches-6.1/0116-remoteproc-qcom-Update-regmap-offsets-for-halt-regis.patch
new file mode 100644 (file)
index 0000000..f0b7172
--- /dev/null
@@ -0,0 +1,79 @@
+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
+@@ -86,7 +86,7 @@
+ #define TCSR_WCSS_CLK_MASK    0x1F
+ #define TCSR_WCSS_CLK_ENABLE  0x14
+-#define MAX_HALT_REG          3
++#define MAX_HALT_REG          4
+ #define WCNSS_PAS_ID          6
+@@ -154,6 +154,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;
+@@ -875,10 +876,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;
+@@ -929,9 +933,9 @@ static int q6v5_wcss_init_mmio(struct q6
+               return -EINVAL;
+       }
+-      wcss->halt_q6 = halt_reg[0];
+-      wcss->halt_wcss = halt_reg[1];
+-      wcss->halt_nc = halt_reg[2];
++      wcss->halt_q6 = halt_reg[1];
++      wcss->halt_wcss = halt_reg[2];
++      wcss->halt_nc = halt_reg[3];
+       return 0;
+ }
+@@ -1179,6 +1183,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,
+@@ -1193,6 +1198,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.1/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch b/target/linux/qualcommax/patches-6.1/0117-dt-bindings-clock-qcom-Add-reset-for-WCSSAON.patch
new file mode 100644 (file)
index 0000000..fe0e0f9
--- /dev/null
@@ -0,0 +1,26 @@
+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.1/0118-clk-qcom-Add-WCSSAON-reset.patch b/target/linux/qualcommax/patches-6.1/0118-clk-qcom-Add-WCSSAON-reset.patch
new file mode 100644 (file)
index 0000000..7915317
--- /dev/null
@@ -0,0 +1,25 @@
+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
+@@ -4717,6 +4717,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.1/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch b/target/linux/qualcommax/patches-6.1/0119-remoteproc-wcss-disable-auto-boot-for-IPQ8074.patch
new file mode 100644 (file)
index 0000000..8674522
--- /dev/null
@@ -0,0 +1,48 @@
+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
+@@ -161,6 +161,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)
+@@ -1150,6 +1151,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)
+               goto free_rproc;
+@@ -1188,6 +1190,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 = {
+@@ -1204,6 +1207,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.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch b/target/linux/qualcommax/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch
new file mode 100644 (file)
index 0000000..e37ba37
--- /dev/null
@@ -0,0 +1,120 @@
+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
+@@ -140,6 +140,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 {
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+@@ -409,6 +435,11 @@
+                       #hwlock-cells = <1>;
+               };
++              tcsr_q6: syscon@1945000 {
++                      compatible = "syscon";
++                      reg = <0x01945000 0xe000>;
++              };
++
+               spmi_bus: spmi@200f000 {
+                       compatible = "qcom,spmi-pmic-arb";
+                       reg = <0x0200f000 0x001000>,
+@@ -913,6 +944,56 @@
+                                     "axi_s_sticky";
+                       status = "disabled";
+               };
++
++              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.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch b/target/linux/qualcommax/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch
new file mode 100644 (file)
index 0000000..bd5410c
--- /dev/null
@@ -0,0 +1,135 @@
+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
+@@ -994,6 +994,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.1/0122-arm64-dts-ipq8074-add-CPU-clock.patch b/target/linux/qualcommax/patches-6.1/0122-arm64-dts-ipq8074-add-CPU-clock.patch
new file mode 100644 (file)
index 0000000..a3c5f34
--- /dev/null
@@ -0,0 +1,59 @@
+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.1/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch b/target/linux/qualcommax/patches-6.1/0123-arm64-dts-ipq8074-add-cooling-cells-to-CPU-nodes.patch
new file mode 100644 (file)
index 0000000..3520b38
--- /dev/null
@@ -0,0 +1,48 @@
+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.1/0128-cpufreq-qcom-nvmem-add-support-for-IPQ8074.patch b/target/linux/qualcommax/patches-6.1/0128-cpufreq-qcom-nvmem-add-support-for-IPQ8074.patch
new file mode 100644 (file)
index 0000000..09abbfa
--- /dev/null
@@ -0,0 +1,108 @@
+From 11592aa862e67f4477dee7e94d5c8244d893de1b Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Sat, 31 Dec 2022 13:03:41 +0100
+Subject: [PATCH] cpufreq: qcom-nvmem: add support for IPQ8074
+
+IPQ8074 comes in 2 families:
+* IPQ8070A/IPQ8071A (Acorn) up to 1.4GHz
+* IPQ8072A/IPQ8074A/IPQ8076A/IPQ8078A (Hawkeye) up to 2.2GHz
+
+So, in order to be able to share one OPP table lets add support for IPQ8074
+family based of SMEM SoC ID-s as speedbin fuse is always 0 on IPQ8074.
+
+IPQ8074 compatible is blacklisted from DT platdev as the cpufreq device
+will get created by NVMEM CPUFreq driver.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+Changes in v2:
+* Print an error if SMEM ID is not part of the IPQ8074 family
+and restrict the speed to Acorn variant (1.4GHz)
+---
+ drivers/cpufreq/cpufreq-dt-platdev.c |  1 +
+ drivers/cpufreq/qcom-cpufreq-nvmem.c | 43 ++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+)
+
+--- a/drivers/cpufreq/cpufreq-dt-platdev.c
++++ b/drivers/cpufreq/cpufreq-dt-platdev.c
+@@ -164,6 +164,7 @@ static const struct of_device_id blockli
+       { .compatible = "ti,omap3", },
+       { .compatible = "qcom,ipq8064", },
++      { .compatible = "qcom,ipq8074", },
+       { .compatible = "qcom,apq8064", },
+       { .compatible = "qcom,msm8974", },
+       { .compatible = "qcom,msm8960", },
+--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
+@@ -31,6 +31,9 @@
+ #include <dt-bindings/arm/qcom,ids.h>
++#define IPQ8074_HAWKEYE_VERSION               BIT(0)
++#define IPQ8074_ACORN_VERSION         BIT(1)
++
+ struct qcom_cpufreq_drv;
+ struct qcom_cpufreq_match_data {
+@@ -204,6 +207,41 @@ len_error:
+       return ret;
+ }
++static int qcom_cpufreq_ipq8074_name_version(struct device *cpu_dev,
++                                           struct nvmem_cell *speedbin_nvmem,
++                                           char **pvs_name,
++                                           struct qcom_cpufreq_drv *drv)
++{
++      u32 msm_id;
++      int ret;
++      *pvs_name = NULL;
++
++      ret = qcom_smem_get_soc_id(&msm_id);
++      if (ret)
++              return ret;
++
++      switch (msm_id) {
++      case QCOM_ID_IPQ8070A:
++      case QCOM_ID_IPQ8071A:
++              drv->versions = IPQ8074_ACORN_VERSION;
++              break;
++      case QCOM_ID_IPQ8072A:
++      case QCOM_ID_IPQ8074A:
++      case QCOM_ID_IPQ8076A:
++      case QCOM_ID_IPQ8078A:
++              drv->versions = IPQ8074_HAWKEYE_VERSION;
++              break;
++      default:
++              dev_err(cpu_dev,
++                      "SoC ID %u is not part of IPQ8074 family, limiting to 1.4GHz!\n",
++                      msm_id);
++              drv->versions = IPQ8074_ACORN_VERSION;
++              break;
++      }
++
++      return 0;
++}
++
+ static const struct qcom_cpufreq_match_data match_data_kryo = {
+       .get_version = qcom_cpufreq_kryo_name_version,
+ };
+@@ -218,6 +256,10 @@ static const struct qcom_cpufreq_match_d
+       .genpd_names = qcs404_genpd_names,
+ };
++static const struct qcom_cpufreq_match_data match_data_ipq8074 = {
++      .get_version = qcom_cpufreq_ipq8074_name_version,
++};
++
+ static int qcom_cpufreq_probe(struct platform_device *pdev)
+ {
+       struct qcom_cpufreq_drv *drv;
+@@ -363,6 +405,7 @@ static const struct of_device_id qcom_cp
+       { .compatible = "qcom,msm8996", .data = &match_data_kryo },
+       { .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
+       { .compatible = "qcom,ipq8064", .data = &match_data_krait },
++      { .compatible = "qcom,ipq8074", .data = &match_data_ipq8074 },
+       { .compatible = "qcom,apq8064", .data = &match_data_krait },
+       { .compatible = "qcom,msm8974", .data = &match_data_krait },
+       { .compatible = "qcom,msm8960", .data = &match_data_krait },
diff --git a/target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch b/target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch
new file mode 100644 (file)
index 0000000..3a6f4e9
--- /dev/null
@@ -0,0 +1,128 @@
+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
+@@ -340,6 +340,113 @@
+                       status = "disabled";
+               };
++              qfprom: efuse@a4000 {
++                      compatible = "qcom,ipq8074-qfprom", "qcom,qfprom";
++                      reg = <0x000a4000 0x1000>;
++                      #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 {
+                       compatible = "qcom,prng-ee";
+                       reg = <0x000e3000 0x1000>;
diff --git a/target/linux/qualcommax/patches-6.1/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch b/target/linux/qualcommax/patches-6.1/0130-arm64-dts-qcom-ipq8074-add-CPU-OPP-table.patch
new file mode 100644 (file)
index 0000000..9c1e7b9
--- /dev/null
@@ -0,0 +1,102 @@
+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 {
+@@ -83,6 +87,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.1/0132-mmc-core-disable-TRIM-on-Micron-MTFC4GACAJCN-1M.patch b/target/linux/qualcommax/patches-6.1/0132-mmc-core-disable-TRIM-on-Micron-MTFC4GACAJCN-1M.patch
new file mode 100644 (file)
index 0000000..8c2e59e
--- /dev/null
@@ -0,0 +1,36 @@
+From f5aaf6669bd4f1f0218dd7fd5dc90941267ad860 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Tue, 30 May 2023 23:26:30 +0200
+Subject: [PATCH] mmc: core: disable TRIM on Micron MTFC4GACAJCN-1M
+
+It seems that Micron MTFC4GACAJCN-1M despite advertising TRIM support does
+not work when the core is trying to use REQ_OP_WRITE_ZEROES.
+
+We are seeing the following errors in OpenWrt under 6.1 on Qnap Qhora 301W
+that we did not previously have and tracked it down to REQ_OP_WRITE_ZEROES:
+[   18.085950] I/O error, dev loop0, sector 596 op 0x9:(WRITE_ZEROES) flags 0x800 phys_seg 0 prio class 2
+
+Disabling TRIM makes the error go away, so lets add a quirk for this eMMC
+to disable TRIM.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ drivers/mmc/core/quirks.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/mmc/core/quirks.h
++++ b/drivers/mmc/core/quirks.h
+@@ -101,6 +101,13 @@ static const struct mmc_fixup __maybe_un
+                 MMC_QUIRK_TRIM_BROKEN),
+       /*
++       * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
++       * support being used to offload WRITE_ZEROES.
++       */
++      MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
++                MMC_QUIRK_TRIM_BROKEN),
++
++      /*
+        * Some SD cards reports discard support while they don't
+        */
+       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
diff --git a/target/linux/qualcommax/patches-6.1/0133-mmc-core-disable-TRIM-on-Kingston-EMMC04G-M627.patch b/target/linux/qualcommax/patches-6.1/0133-mmc-core-disable-TRIM-on-Kingston-EMMC04G-M627.patch
new file mode 100644 (file)
index 0000000..ac7af52
--- /dev/null
@@ -0,0 +1,38 @@
+From 26c97b6fb7d291f55e0e4a410d266d1355118ed9 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 31 May 2023 20:21:26 +0200
+Subject: [PATCH] mmc: core: disable TRIM on Kingston EMMC04G-M627
+
+It seems that Kingston EMMC04G-M627 despite advertising TRIM support does
+not work when the core is trying to use REQ_OP_WRITE_ZEROES.
+
+We are seeing I/O errors in OpenWrt under 6.1 on Zyxel NBG7815 that we did
+not previously have and tracked it down to REQ_OP_WRITE_ZEROES.
+
+Trying to use fstrim seems to also throw errors like:
+[93010.835112] I/O error, dev loop0, sector 16902 op 0x3:(DISCARD) flags 0x800 phys_seg 1 prio class 2
+
+Disabling TRIM makes the error go away, so lets add a quirk for this eMMC
+to disable TRIM.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ drivers/mmc/core/quirks.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/mmc/core/quirks.h
++++ b/drivers/mmc/core/quirks.h
+@@ -108,6 +108,13 @@ static const struct mmc_fixup __maybe_un
+                 MMC_QUIRK_TRIM_BROKEN),
+       /*
++       * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
++       * support being used to offload WRITE_ZEROES.
++       */
++      MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
++                MMC_QUIRK_TRIM_BROKEN),
++
++      /*
+        * Some SD cards reports discard support while they don't
+        */
+       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
diff --git a/target/linux/qualcommax/patches-6.1/0134-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch b/target/linux/qualcommax/patches-6.1/0134-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch
new file mode 100644 (file)
index 0000000..6231d8a
--- /dev/null
@@ -0,0 +1,197 @@
+From 145bbf2b88990ef3ff00ee541bb7662008683c16 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 7 Jun 2023 20:26:26 +0200
+Subject: [PATCH] arm64: dts: qcom: ipq8074: add critical thermal trips
+
+According to bindings, thermal zones must have associated trips as well.
+Since we currently dont have CPUFreq support and thus no passive cooling
+lets start by defining critical trips to protect the devices against
+severe overheating.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ arch/arm64/boot/dts/qcom/ipq8074.dtsi | 96 +++++++++++++++++++++++++++
+ 1 file changed, 96 insertions(+)
+
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -1293,6 +1293,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 4>;
++
++                      trips {
++                              nss-top-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               nss0-thermal {
+@@ -1300,6 +1308,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 5>;
++
++                      trips {
++                              nss-0-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               nss1-thermal {
+@@ -1307,6 +1323,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 6>;
++
++                      trips {
++                              nss-1-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               wcss-phya0-thermal {
+@@ -1314,6 +1338,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 7>;
++
++                      trips {
++                              wcss-phya0-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               wcss-phya1-thermal {
+@@ -1321,6 +1353,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 8>;
++
++                      trips {
++                              wcss-phya1-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               cpu0_thermal: cpu0-thermal {
+@@ -1328,6 +1368,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 9>;
++
++                      trips {
++                              cpu0-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               cpu1_thermal: cpu1-thermal {
+@@ -1335,6 +1383,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 10>;
++
++                      trips {
++                              cpu1-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               cpu2_thermal: cpu2-thermal {
+@@ -1342,6 +1398,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 11>;
++
++                      trips {
++                              cpu2-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               cpu3_thermal: cpu3-thermal {
+@@ -1349,6 +1413,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 12>;
++
++                      trips {
++                              cpu3-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               cluster_thermal: cluster-thermal {
+@@ -1356,6 +1428,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 13>;
++
++                      trips {
++                              cluster-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               wcss-phyb0-thermal {
+@@ -1363,6 +1443,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 14>;
++
++                      trips {
++                              wcss-phyb0-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+               wcss-phyb1-thermal {
+@@ -1370,6 +1458,14 @@
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 15>;
++
++                      trips {
++                              wcss-phyb1-crit {
++                                      temperature = <110000>;
++                                      hysteresis = <1000>;
++                                      type = "critical";
++                              };
++                      };
+               };
+       };
+ };
diff --git a/target/linux/qualcommax/patches-6.1/0900-power-Add-Qualcomm-APM.patch b/target/linux/qualcommax/patches-6.1/0900-power-Add-Qualcomm-APM.patch
new file mode 100644 (file)
index 0000000..2e5c72b
--- /dev/null
@@ -0,0 +1,1047 @@
+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
+@@ -1,3 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ source "drivers/power/reset/Kconfig"
+ source "drivers/power/supply/Kconfig"
++source "drivers/power/qcom/Kconfig"
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -1,3 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_POWER_RESET)     += reset/
+ 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,944 @@
++/*
++ * 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_find_property(dev->of_node, "qcom,apm-post-halt-delay", NULL)) {
++              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_find_property(dev->of_node, "qcom,apm-halt-clk-delay", NULL)) {
++              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_find_property(dev->of_node, "qcom,apm-resume-clk-delay", NULL)) {
++              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_find_property(dev->of_node, "qcom,apm-sel-switch-delay", NULL)) {
++              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 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;
++      const struct of_device_id *match;
++      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;
++      }
++
++      match = of_match_device(msm_apm_match_table, dev);
++      if (!match)
++              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)match->data;
++      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 int 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);
++      }
++
++      return 0;
++}
++
++static struct platform_driver msm_apm_driver = {
++      .driver         = {
++              .name           = MSM_APM_DRIVER_NAME,
++              .of_match_table = msm_apm_match_table,
++              .owner          = THIS_MODULE,
++      },
++      .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.1/0901-regulator-add-Qualcomm-CPR-regulators.patch b/target/linux/qualcommax/patches-6.1/0901-regulator-add-Qualcomm-CPR-regulators.patch
new file mode 100644 (file)
index 0000000..9b9f715
--- /dev/null
@@ -0,0 +1,12144 @@
+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
+@@ -1524,4 +1524,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
+@@ -110,6 +110,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,695 @@
++/*
++ * 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 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 of_device_id *match;
++      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;
++
++      match = of_match_device(cpr3_regulator_match_table, &pdev->dev);
++      if (!match)
++              return -ENODEV;
++
++      cpr_data = (struct cpr3_reg_data *)match->data;
++      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 int cpr3_npu_regulator_remove(struct platform_device *pdev)
++{
++      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
++
++      return 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,
++              .owner          = THIS_MODULE,
++      },
++      .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;
++      struct cpr4_reg_data    *cpr4_regulator_data;
++      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,2750 @@
++/*
++ * 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 <soc/qcom/socinfo.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
++
++/**
++ * 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_find_property(vreg->of_node, "qcom,system-voltage", NULL)) {
++              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_find_property(vreg->of_node,
++                              "qcom,allow-aging-voltage-adjustment", NULL)) {
++              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_find_property(vreg->of_node,
++                     "qcom,allow-aging-open-loop-voltage-adjustment", NULL)) {
++              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_find_property(vreg->of_node, "qcom,cpr-aging-derate",
++                                      NULL)) {
++                      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_find_property(node, "qcom,cpr-panic-reg-name-list", NULL)) {
++              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_find_property(ctrl->dev->of_node, "clock-names", NULL)) {
++              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_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
++              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_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
++              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_find_property(vreg->of_node, prop, NULL))
++              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)
++              strlcpy(prop_name, prop_name_v2, sizeof(prop_name_v2));
++      else
++              strlcpy(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 {
++              strlcpy(prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
++                      sizeof(prop_str));
++      }
++
++      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
++              /* 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)
++              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
++                      sizeof(prop_str));
++      else
++              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold",
++                      sizeof(prop_str));
++
++      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
++              /* 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 {
++              strlcpy(req_prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
++                      sizeof(req_prop_str));
++      }
++
++      if (soc_version_major > 1)
++              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
++                      sizeof(prop_str));
++      else
++              strlcpy(prop_str, "qcom,cpr-cold-temp-threshold",
++                      sizeof(prop_str));
++
++      if (!of_find_property(vreg->of_node, req_prop_str, NULL)) {
++              /* No adjustment required. */
++              cpr3_info(vreg, "Cold temperature adjustment not required.\n");
++              return 0;
++      }
++
++      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
++              /* 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 {
++              strlcpy(prop_str, "qcom,cpr-open-loop-voltage-fuse-adjustment",
++                      sizeof(prop_str));
++      }
++
++      if (!of_find_property(vreg->of_node, prop_str, NULL)) {
++              /* 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_find_property(vreg->of_node,
++                      "qcom,cpr-open-loop-voltage-adjustment", NULL)) {
++              /* 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_find_property(vreg->of_node,
++                      "qcom,cpr-open-loop-voltage-min-diff", NULL)) {
++              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_find_property(vreg->of_node, volt_adj, NULL)
++          && !of_find_property(vreg->of_node, volt_fuse_adj, NULL)
++          && !vreg->aging_allowed) {
++              /* No adjustment required. */
++              return 0;
++      } else if (!of_find_property(vreg->of_node, ro_scaling, NULL)) {
++              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_find_property(vreg->of_node, volt_fuse_adj, NULL)) {
++              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_find_property(vreg->of_node, volt_adj, NULL)) {
++              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_find_property(node, "qcom,apm-ctrl", NULL)) {
++              /* 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_find_property(node, use_corner_band ?
++                           "qcom,corner-band-allow-temp-adjustment"
++                           : "qcom,corner-allow-temp-adjustment", NULL)) {
++              if (!ctrl->allow_temp_adj) {
++                      cpr3_err(ctrl, "Temperature adjustment configurations missing\n");
++                      return -EINVAL;
++              }
++
++              vreg->allow_temp_adj = true;
++      }
++
++      if (of_find_property(node, use_corner_band ?
++                           "qcom,corner-band-allow-core-count-adjustment"
++                           : "qcom,corner-allow-core-count-adjustment",
++                           NULL)) {
++              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_find_property(vreg->of_node,
++              "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) {
++              /* 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_find_property(vreg->of_node,
++              "qcom,cpr-closed-loop-voltage-adjustment", NULL);
++      fused_adjustment = of_find_property(vreg->of_node,
++              "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL);
++
++      if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
++              /* No adjustment required. */
++              return 0;
++      } else if (!of_find_property(vreg->of_node,
++                      "qcom,cpr-ro-scaling-factor", NULL)) {
++              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,1819 @@
++/*
++ * 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_find_property(node, "qcom,cpr-ro-sel", NULL)) {
++              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_find_property(node,
++                      "qcom,cpr-misc-fuse-voltage-adjustment",
++                      NULL)) {
++                      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_find_property(vreg->of_node,
++              "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) {
++              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_find_property(vreg->of_node, "qcom,allow-boost", NULL)) {
++              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_find_property(vreg->of_node,
++                      "qcom,cpr-boost-voltage-fuse-adjustment", NULL)) {
++              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_find_property(vreg->of_node,
++                              "qcom,cpr-boost-temp-adjustment", NULL)) {
++              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_find_property(ctrl->dev->of_node, "vdd-limit-supply", NULL)) {
++              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 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 of_device_id *match;
++      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;
++
++      match = of_match_device(cpr4_regulator_match_table, &pdev->dev);
++      if (!match)
++              return -ENODEV;
++
++      cpr_data = (struct cpr4_reg_data *)match->data;
++      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 int cpr4_apss_regulator_remove(struct platform_device *pdev)
++{
++      struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
++
++      return 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,
++              .owner          = THIS_MODULE,
++      },
++      .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);
+--- /dev/null
++++ b/include/soc/qcom/socinfo.h
+@@ -0,0 +1,463 @@
++/* Copyright (c) 2009-2014, 2016, 2020, 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 _ARCH_ARM_MACH_MSM_SOCINFO_H_
++#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
++
++#include <linux/of.h>
++
++#define CPU_IPQ8074 323
++#define CPU_IPQ8072 342
++#define CPU_IPQ8076 343
++#define CPU_IPQ8078 344
++#define CPU_IPQ8070 375
++#define CPU_IPQ8071 376
++
++#define CPU_IPQ8072A 389
++#define CPU_IPQ8074A 390
++#define CPU_IPQ8076A 391
++#define CPU_IPQ8078A 392
++#define CPU_IPQ8070A 395
++#define CPU_IPQ8071A 396
++
++#define CPU_IPQ8172  397
++#define CPU_IPQ8173  398
++#define CPU_IPQ8174  399
++
++#define CPU_IPQ6018 402
++#define CPU_IPQ6028 403
++#define CPU_IPQ6000 421
++#define CPU_IPQ6010 422
++#define CPU_IPQ6005 453
++
++#define CPU_IPQ5010 446
++#define CPU_IPQ5018 447
++#define CPU_IPQ5028 448
++#define CPU_IPQ5000 503
++#define CPU_IPQ0509 504
++#define CPU_IPQ0518 505
++
++#define CPU_IPQ9514 510
++#define CPU_IPQ9554 512
++#define CPU_IPQ9570 513
++#define CPU_IPQ9574 514
++#define CPU_IPQ9550 511
++#define CPU_IPQ9510 521
++
++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);
++}
++
++static inline int read_ipq_cpu_type(void)
++{
++      const int *prop;
++      prop = of_get_property(of_find_node_by_path("/"), "cpu_type", NULL);
++      /*
++       * Return Default CPU type if "cpu_type" property is not found in DTSI
++       */
++      if (!prop)
++              return CPU_IPQ8074;
++
++      return le32_to_cpu(*prop);
++}
++
++static inline int cpu_is_ipq8070(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8070;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8071(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8071;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8072(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8072;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8074(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8074;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8076(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8076;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8078(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8078;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8072a(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8072A;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8074a(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8074A;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8076a(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8076A;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8078a(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8078A;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8070a(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8070A;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8071a(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8071A;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8172(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8172;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8173(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8173;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq8174(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ8174;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq6018(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ6018;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq6028(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ6028;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq6000(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ6000;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq6010(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ6010;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq6005(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ6005;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq5010(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ5010;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq5018(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ5018;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq5028(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ5028;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq5000(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ5000;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq0509(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ0509;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq0518(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ0518;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq9514(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ9514;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq9554(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ9554;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq9570(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ9570;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq9574(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ9574;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq9550(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ9550;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq9510(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return read_ipq_cpu_type() == CPU_IPQ9510;
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq807x(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq8072() || cpu_is_ipq8074() ||
++              cpu_is_ipq8076() || cpu_is_ipq8078() ||
++              cpu_is_ipq8070() || cpu_is_ipq8071() ||
++              cpu_is_ipq8072a() || cpu_is_ipq8074a() ||
++              cpu_is_ipq8076a() || cpu_is_ipq8078a() ||
++              cpu_is_ipq8070a() || cpu_is_ipq8071a() ||
++              cpu_is_ipq8172() || cpu_is_ipq8173() ||
++              cpu_is_ipq8174();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq60xx(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq6018() || cpu_is_ipq6028() ||
++              cpu_is_ipq6000() || cpu_is_ipq6010() ||
++              cpu_is_ipq6005();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq50xx(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq5010() || cpu_is_ipq5018() ||
++              cpu_is_ipq5028() || cpu_is_ipq5000() ||
++              cpu_is_ipq0509() || cpu_is_ipq0518();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_ipq95xx(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq9514() || cpu_is_ipq9554() ||
++              cpu_is_ipq9570() || cpu_is_ipq9574() ||
++              cpu_is_ipq9550() || cpu_is_ipq9510();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_nss_crypto_enabled(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq807x() || cpu_is_ipq60xx() ||
++              cpu_is_ipq50xx() || cpu_is_ipq9570() ||
++              cpu_is_ipq9550() || cpu_is_ipq9574() ||
++              cpu_is_ipq9554();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_internal_wifi_enabled(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq807x() || cpu_is_ipq60xx() ||
++              cpu_is_ipq50xx() || cpu_is_ipq9514() ||
++              cpu_is_ipq9554() || cpu_is_ipq9574();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_uniphy1_enabled(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq807x() || cpu_is_ipq60xx() ||
++              cpu_is_ipq9554() || cpu_is_ipq9570() ||
++              cpu_is_ipq9574() || cpu_is_ipq9550();
++#else
++      return 0;
++#endif
++}
++
++static inline int cpu_is_uniphy2_enabled(void)
++{
++#ifdef CONFIG_ARCH_QCOM
++      return  cpu_is_ipq807x() || cpu_is_ipq9570() ||
++              cpu_is_ipq9574();
++#else
++      return 0;
++#endif
++}
++
++#endif /* _ARCH_ARM_MACH_MSM_SOCINFO_H_ */
diff --git a/target/linux/qualcommax/patches-6.1/0902-arm64-dts-ipq8074-add-label-to-clocks.patch b/target/linux/qualcommax/patches-6.1/0902-arm64-dts-ipq8074-add-label-to-clocks.patch
new file mode 100644 (file)
index 0000000..9b8b4df
--- /dev/null
@@ -0,0 +1,24 @@
+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>;