sunxid1: add new target
authorZoltan HERPAI <wigyori@uid0.hu>
Tue, 16 Nov 2021 15:44:56 +0000 (16:44 +0100)
committerZoltan HERPAI <zoltan.herpai@kaonmedia.com>
Tue, 21 Dec 2021 09:56:58 +0000 (10:56 +0100)
Add new target for the Allwinner D1 RISC-V SoCs. The target includes
a number of backported patches, as well as a new SD-card format including
the sun20spl image. The board's bootrom will detect if an SD-card is inserted
and will try to init from there.

The installation instruction is the usual SD-card install method.

Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
134 files changed:
target/linux/sunxid1/Makefile [new file with mode: 0644]
target/linux/sunxid1/base-files/etc/board.d/02_network [new file with mode: 0644]
target/linux/sunxid1/base-files/etc/inittab [new file with mode: 0644]
target/linux/sunxid1/base-files/lib/preinit/80_debug [new file with mode: 0644]
target/linux/sunxid1/config-5.15 [new file with mode: 0644]
target/linux/sunxid1/image/Config.in [new file with mode: 0644]
target/linux/sunxid1/image/Makefile [new file with mode: 0644]
target/linux/sunxid1/image/gen_sunxi_sdcard_img.sh [new file with mode: 0755]
target/linux/sunxid1/patches-5.15/0001-5.16-clk-sunxi-ng-Unregister-clocks-resets-when-unbinding.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0002-5.16-clk-sunxi-ng-Prevent-unbinding-CCUs-via-sysfs.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0003-5.16-clk-sunxi-ng-Use-a-separate-lock-for-each-CCU-instan.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0004-5.16-rtc-sun6i-Allow-probing-without-an-early-clock-provi.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0005-5.16-riscv-remove-.text-section-size-limitation-for-XIP.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0006-5.16-irq-simplify-handle_domain_-irq-nmi.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0007-5.16-irq-unexport-handle_irq_desc.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0008-5.16-irq-add-a-temporary-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTR.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0009-5.16-irq-remove-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0010-5.16-irq-add-generic_handle_arch_irq.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0011-5.16-irq-riscv-perform-irqentry-in-entry-code.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0012-5.16-irq-remove-handle_domain_-irq-nmi.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0013-5.16-soc-sunxi_sram-Make-use-of-the-helper-function-devm_.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0014-input-sun4i-lradc-keys-Add-wakup-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0015-thermal-sun8i-Document-the-unknown-field.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0016-thermal-sun8i-Set-the-event-type-for-new-samples.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0017-thermal-sun8i-Use-optional-clock-reset-getters.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0018-thermal-sun8i-Ensure-vref-is-powered.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0019-thermal-sun8i-Add-support-for-the-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0020-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0021-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0022-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0023-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0024-nvmem-sunxi_sid-Add-support-for-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0025-Input-sun4i-lradc-keys-Add-optional-clock-reset-supp.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0026-Input-sun4i-lradc-keys-Add-support-for-R329-and-D1.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0027-leds-sunxi-New-driver-for-the-R329-D1-LED-controller.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0028-ASoC-sun4i-i2s-Update-registers-for-more-channels.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0029-ASoC-sun4i-i2s-Add-support-for-the-R329-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0030-hwspinlock-sun6i-Clarify-bank-counting-logic.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0031-hwspinlock-sun6i-Fix-driver-to-match-binding.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0032-dmaengine-sun6i-Do-not-use-virt_to_phys.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0033-dmaengine-sun6i-Add-support-for-34-bit-physical-addr.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0034-crypto-sun8i-ce-Add-support-for-the-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0035-bus-sun50i-de2-Prevent-driver-from-being-unbound.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0036-clk-sunxi-ng-Export-symbols-used-by-CCU-drivers.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0037-clk-sunxi-ng-Allow-drivers-to-be-built-as-modules.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0038-clk-sunxi-ng-Convert-early-providers-to-platform-dri.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0039-clk-sunxi-ng-Allow-the-CCU-core-to-be-built-as-a-mod.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0040-clk-sunxi-ng-mux-Allow-muxes-to-have-keys.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0041-of-irq-Use-interrupts-extended-to-find-parent.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0042-RISC-V-Use-SBI-SRST-extension-when-available.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0043-RISC-V-Enable-CPU_IDLE-drivers.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0044-RISC-V-Rename-relocate-and-make-it-global.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0045-RISC-V-Add-arch-functions-for-non-retentive-suspend-.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0046-RISC-V-Add-SBI-HSM-suspend-related-defines.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0047-cpuidle-Factor-out-power-domain-related-code-from-PS.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0048-cpuidle-Add-RISC-V-SBI-CPU-idle-driver.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0049-RISC-V-Enable-RISC-V-SBI-CPU-Idle-driver-for-QEMU-vi.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0050-RISC-V-Clear-SIP-bit-only-when-using-SBI-IPI-operati.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0051-RISC-V-Treat-IPIs-as-normal-Linux-IRQs.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0052-clocksource-clint-Add-support-for-ACLINT-MTIMER-devi.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0053-irqchip-sun20i-Add-Allwinner-D1-stacked-INTC-driver.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0054-clk-sunxi-ng-div-Add-macros-using-clk_parent_data-an.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0055-clk-sunxi-ng-mp-Add-macros-using-clk_parent_data-and.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0056-clk-sunxi-ng-mux-Add-macros-using-clk_parent_data-an.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0057-clk-sunxi-ng-gate-Add-macros-for-gates-with-fixed-di.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0058-clk-sunxi-ng-Add-support-for-the-D1-SoC-clocks.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0059-clk-sunxi-ng-Add-support-for-the-sun6i-RTC-clocks.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0060-clk-sunxi-ng-sun6i-rtc-Add-support-for-H6.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0061-dmaengine-sun6i-Add-support-for-the-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0062-riscv-pgtable-Fixup-_PAGE_CHG_MASK-usage.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0063-riscv-pgtable-Add-custom-protection_map-init.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0064-riscv-pgtable-Add-DMA_COHERENT-with-custom-PTE-attri.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0065-riscv-fixup-PAGE_NONE.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0066-riscv-cmo-Add-dma-noncoherency-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0067-riscv-cmo-Add-vendor-custom-icache-sync.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0068-fixed-UB-which-lead-to-cache-coherence-bug.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0069-Enable-T-HEAD-MMU-extensions-unconditionally.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0070-riscv-Allow-suspend.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0071-riscv-cacheinfo-Remind-myself-to-fix-this.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0072-clocksource-riscv-Prefer-it-over-MMIO-clocksources.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0073-riscv-Enable-cpufreq.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0074-cpufreq-sun50i-add-efuse_xlate-to-get-efuse-version.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0075-cpufreq-sun50i-add-A100-cpufreq-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0076-cpufreq-sun50i-Move-out-of-ARM-specific-section.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0077-cpufreq-sun50i-Add-D1-cpufreq-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0078-dmaengine-sun6i-Changes-from-BSP.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0079-iommu-sun50i-Add-support-for-D1-IOMMU.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0080-irqchip-sifive-plic-Add-T-HEAD-PLIC-compatible.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0081-mailbox-Add-v2-mailbox.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0082-media-cedrus-Add-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0083-mmc-sunxi-mmc-Correct-the-maximum-transfer-size.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0084-mmc-sunxi-mmc-Fix-DMA-descriptors-above-32-bits.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0085-mmc-sunxi-mmc-Add-D1-MMC-compatible.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0086-mmc-sunxi-mmc-Add-more-registers.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0087-phy-sun4i-usb-Rework-HCI-PHY-aka.-pmu_unk1-handling.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0088-phy-sun4i-usb-Remove-disc_thresh-where-not-applicabl.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0089-phy-sun4i-usb-Add-D1-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0090-pinctrl-sunxi-Support-new-2.5V-I-O-bias-mode.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0091-pinctrl-sunxi-Adapt-for-D1-register-layout.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0092-pinctrl-sunxi-Add-support-for-Allwinner-D1-SoC.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0093-pwm-sun8i-v536-document-device-tree-bindings.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0094-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0095-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0096-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0097-remoteproc-sun8i-dsp-Add-a-driver-for-the-DSPs-in-su.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0098-rtc-sun6i-Add-support-for-linear-day-storage.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0099-rtc-sun6i-Add-Allwinner-H616-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0100-rtc-sun6i-Add-Allwinner-D1-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0101-soc-sunxi-sram-Actually-marked-claimed-regions-as-cl.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0102-soc-sunxi-sram-Map-SRAM-back-to-CPU-on-release.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0103-soc-sunxi-sram-Fix-debugfs-file-leak.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0104-soc-sunxi-sram-Use-devm_of_platform_populate.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0105-soc-sunxi-sram-Add-support-for-D1-LDOs.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0106-soc-sunxi-sram-Fix-debugfs-for-A64-SRAM-C.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0107-soc-sunxi-sram-Add-D1-DSP-SRAM.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0108-soc-sunxi-sram-Add-D1-syscon-variant.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0109-spi-spi-sun6i-Use-a-struct-for-quirks.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0110-spi-spi-sun6i-Add-Allwinner-R329-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0111-spi-spi-sun6i-Dual-Quad-RX-Support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0112-thermal-of-Remove-duplicate-null-check.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0113-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0114-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0115-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0116-ASoC-sun20i-codec-What-is-this-ramp-thing.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0117-Disable-broken-ARCH_SUNXI-drivers.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0118-riscv-Add-Allwinner-D1-SoC-support.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0119-riscv-Add-Allwinner-D1-SoC-device-tree.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0120-riscv-Add-D1-Nezha-board-device-tree.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0121-misc-changes.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0122-pinctrl-sunxi-sunxi_pinctrl_irq_ack-avoid-build-warn.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0123-Add-a-defconfig-for-the-Nezha.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0124-watchdog-sunxi_wdt-Add-support-for-D1.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0125-dt-bindings-clk-Add-compatibles-for-D1-CCUs.patch [new file with mode: 0644]
target/linux/sunxid1/patches-5.15/0126-dt-bindings-rtc-sun6i-Add-H616-R329-and-D1-support.patch [new file with mode: 0644]

diff --git a/target/linux/sunxid1/Makefile b/target/linux/sunxid1/Makefile
new file mode 100644 (file)
index 0000000..7d80107
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2021 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=riscv64
+BOARD:=sunxid1
+BOARDNAME:=AllWinner D1-based boards
+FEATURES:=ext4
+KERNELNAME:=Image dtbs
+MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>
+
+KERNEL_PATCHVER:=5.15
+
+include $(INCLUDE_DIR)/target.mk
+
+define Target/Description
+       Build firmware images for AllWinner D1-based boards
+endef
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/sunxid1/base-files/etc/board.d/02_network b/target/linux/sunxid1/base-files/etc/board.d/02_network
new file mode 100644 (file)
index 0000000..df48b43
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2015 OpenWrt.org
+#
+
+. /lib/functions/uci-defaults.sh
+
+board_config_update
+
+case "$(board_name)" in
+*)
+       ucidef_set_interface_lan 'eth0'
+       ;;
+esac
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/sunxid1/base-files/etc/inittab b/target/linux/sunxid1/base-files/etc/inittab
new file mode 100644 (file)
index 0000000..93cb948
--- /dev/null
@@ -0,0 +1,6 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+tts/0::askfirst:/usr/libexec/login.sh
+ttyS0::askfirst:/usr/libexec/login.sh
+ttySIF0::askfirst:/usr/libexec/login.sh
+tty1::askfirst:/usr/libexec/login.sh
diff --git a/target/linux/sunxid1/base-files/lib/preinit/80_debug b/target/linux/sunxid1/base-files/lib/preinit/80_debug
new file mode 100644 (file)
index 0000000..087e86e
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Copyright (C) 2012-2015 OpenWrt.org
+
+riscv_debug() {
+       cat /proc/cpuinfo
+}
+
+boot_hook_add preinit_main riscv_debug
+
diff --git a/target/linux/sunxid1/config-5.15 b/target/linux/sunxid1/config-5.15
new file mode 100644 (file)
index 0000000..91bf02c
--- /dev/null
@@ -0,0 +1,441 @@
+CONFIG_64BIT=y
+CONFIG_AF_UNIX_OOB=y
+# CONFIG_AHCI_SUNXI is not set
+CONFIG_ARCH_CLOCKSOURCE_INIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=24
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
+# CONFIG_ARCH_RV32I is not set
+CONFIG_ARCH_RV64I=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_STACKWALK=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ASN1=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_ATA=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_BINARY_PRINTF=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CAVIUM_PTP=y
+CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y
+CONFIG_CLKSRC_MMIO=y
+# CONFIG_CLK_SIFIVE is not set
+CONFIG_CLK_SUNXI=y
+CONFIG_CLK_SUNXI_CLOCKS=y
+CONFIG_CLK_SUNXI_PRCM_SUN6I=y
+CONFIG_CLK_SUNXI_PRCM_SUN8I=y
+CONFIG_CLK_SUNXI_PRCM_SUN9I=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CLZ_TAB=y
+CONFIG_CMODEL_MEDANY=y
+# CONFIG_CMODEL_MEDLOW is not set
+CONFIG_COMMON_CLK=y
+# CONFIG_COMPAT_32BIT_TIME is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_COREDUMP=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_CPU_ISOLATION=y
+CONFIG_CPU_RMAP=y
+CONFIG_CRC16=y
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CRC7=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_DEV_ALLWINNER=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
+CONFIG_CRYPTO_LIB_SHA256=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEVMEM=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_DIRECT_REMAP=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_REMAP=y
+CONFIG_DMA_SUN6I=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DWMAC_GENERIC=y
+CONFIG_DWMAC_SUN8I=y
+CONFIG_DWMAC_SUNXI=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ELF_CORE=y
+CONFIG_EXT4_FS=y
+CONFIG_EXTCON=y
+# CONFIG_EXTCON_USBC_TUSB320 is not set
+CONFIG_FAILOVER=y
+CONFIG_FHANDLE=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FPU=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FRAME_WARN=2048
+CONFIG_FS_IOMAP=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=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_CSUM=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IOREMAP=y
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=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=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_PCF857X=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HID=y
+CONFIG_HID_GENERIC=y
+# CONFIG_HID_PLAYSTATION is not set
+# CONFIG_HID_SEMITEK is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_RISCV_SBI=y
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_HELPER_AUTO=y
+# CONFIG_I2C_HID_OF is not set
+# CONFIG_I2C_HID_OF_GOODIX is not set
+CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_OCORES=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+# CONFIG_INPUT_DA7280_HAPTICS is not set
+# CONFIG_INPUT_IQS626A is not set
+CONFIG_IO_URING=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+CONFIG_KEYS=y
+# CONFIG_KFENCE is not set
+CONFIG_LEDS_SUN50I_R329=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LTO_NONE=y
+CONFIG_MACB=y
+# CONFIG_MACB_PCI is not set
+CONFIG_MACB_USE_HWSTAMP=y
+CONFIG_MAILBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_MAXPHYSMEM_128GB=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_BUS_MUX=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+# CONFIG_MDIO_SUN4I is not set
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_AXP20X=y
+CONFIG_MFD_AXP20X_I2C=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_SUN4I_GPADC is not set
+CONFIG_MFD_SUN6I_PRCM=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_SUNXI=y
+CONFIG_MMIOWB=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MODULE_SECTIONS=y
+CONFIG_MPILIB=y
+CONFIG_MQ_IOSCHED_DEADLINE=y
+CONFIG_MQ_IOSCHED_KYBER=y
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SW_HAMMING is not set
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NAMESPACES=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FAILOVER=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_NS=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_SOCK_MSG=y
+CONFIG_NET_VENDOR_ALLWINNER=y
+CONFIG_NET_VENDOR_MICROSOFT=y
+CONFIG_NLS=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_NR_CPUS=8
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SUNXI_SID=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OID_REGISTRY=y
+CONFIG_PADATA=y
+CONFIG_PAGE_OFFSET=0xffffffe000000000
+CONFIG_PAGE_POOL=y
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PA_BITS=56
+CONFIG_PCI=y
+CONFIG_PCI_DEBUG=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_ECAM=y
+CONFIG_PCI_HOST_COMMON=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PCI_SW_SWITCHTEC=y
+CONFIG_PCPU_DEV_REFCNT=y
+CONFIG_PCS_XPCS=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=y
+CONFIG_PHYLINK=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PHYS_RAM_BASE=0x40000000
+CONFIG_PHYS_RAM_BASE_FIXED=y
+CONFIG_PHY_SUN4I_USB=y
+# CONFIG_PHY_SUN50I_USB3 is not set
+# CONFIG_PHY_SUN6I_MIPI_DPHY is not set
+# CONFIG_PHY_SUN9I_USB is not set
+CONFIG_PID_NS=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SUN20I_D1=y
+# CONFIG_PINCTRL_SUN4I_A10 is not set
+# CONFIG_PINCTRL_SUN50I_A100 is not set
+# CONFIG_PINCTRL_SUN50I_A100_R is not set
+# CONFIG_PINCTRL_SUN50I_A64 is not set
+# CONFIG_PINCTRL_SUN50I_A64_R is not set
+# CONFIG_PINCTRL_SUN50I_H5 is not set
+# CONFIG_PINCTRL_SUN50I_H6 is not set
+# CONFIG_PINCTRL_SUN50I_H616 is not set
+# CONFIG_PINCTRL_SUN50I_H616_R is not set
+# CONFIG_PINCTRL_SUN50I_H6_R is not set
+# CONFIG_PINCTRL_SUN5I is not set
+# CONFIG_PINCTRL_SUN6I_A31 is not set
+# CONFIG_PINCTRL_SUN6I_A31_R is not set
+# CONFIG_PINCTRL_SUN8I_A23 is not set
+# CONFIG_PINCTRL_SUN8I_A23_R is not set
+# CONFIG_PINCTRL_SUN8I_A33 is not set
+# CONFIG_PINCTRL_SUN8I_A83T is not set
+# CONFIG_PINCTRL_SUN8I_A83T_R is not set
+# CONFIG_PINCTRL_SUN8I_H3 is not set
+# CONFIG_PINCTRL_SUN8I_H3_R is not set
+# CONFIG_PINCTRL_SUN8I_V3S is not set
+# CONFIG_PINCTRL_SUN9I_A80 is not set
+# CONFIG_PINCTRL_SUN9I_A80_R is not set
+CONFIG_PINCTRL_SUNXI=y
+CONFIG_PKCS7_MESSAGE_PARSER=y
+# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_PWM=y
+# CONFIG_PWM_ATMEL_TCB is not set
+# CONFIG_PWM_DWC is not set
+# CONFIG_PWM_SIFIVE is not set
+# CONFIG_PWM_SUN4I is not set
+CONFIG_PWM_SUN8I_V536=y
+CONFIG_PWM_SYSFS=y
+CONFIG_R8169=y
+CONFIG_RATIONAL=y
+CONFIG_RCU_TRACE=y
+CONFIG_RD_GZIP=y
+CONFIG_REALTEK_PHY=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_AXP20X is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESET_SIMPLE=y
+CONFIG_RESET_SUNXI=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RISCV=y
+# CONFIG_RISCV_ERRATA_ALTERNATIVE is not set
+CONFIG_RISCV_INTC=y
+CONFIG_RISCV_ISA_C=y
+CONFIG_RISCV_SBI=y
+CONFIG_RISCV_SBI_V01=y
+CONFIG_RISCV_TIMER=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+CONFIG_RTC_DRV_SUN6I=y
+CONFIG_RTC_I2C_AND_SPI=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_HOST=y
+CONFIG_SATA_PMP=y
+CONFIG_SATA_SIL24=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCSI=y
+CONFIG_SCSI_COMMON=y
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_DWLIB=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SG_POOL=y
+CONFIG_SIFIVE_PLIC=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_SMP=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+# CONFIG_SOC_MICROCHIP_POLARFIRE is not set
+# CONFIG_SOC_SIFIVE is not set
+# CONFIG_SOC_VIRT is not set
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_SUN4I is not set
+CONFIG_SPI_SUN6I=y
+CONFIG_SRCU=y
+CONFIG_STACKTRACE=y
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+# CONFIG_STMMAC_SELFTESTS is not set
+CONFIG_SUN20I_D1_CCU=y
+CONFIG_SUN20I_D1_R_CCU=y
+CONFIG_SUN20I_INTC=y
+# CONFIG_SUN4I_EMAC is not set
+CONFIG_SUN4I_TIMER=y
+CONFIG_SUN5I_HSTIMER=y
+CONFIG_SUN6I_MSGBOX=y
+CONFIG_SUN6I_RTC_CCU=y
+# CONFIG_SUN8I_A83T_CCU is not set
+CONFIG_SUN8I_DE2_CCU=y
+CONFIG_SUN8I_MSGBOX=y
+# CONFIG_SUN8I_R_CCU is not set
+CONFIG_SUNXI_CCU=y
+# CONFIG_SUNXI_RSB is not set
+CONFIG_SUNXI_SRAM=y
+CONFIG_SUNXI_WATCHDOG=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_TUNE_GENERIC=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_HID=y
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_HOST=y
+CONFIG_USB_MUSB_SUNXI=y
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_PCI=y
+CONFIG_USB_PHY=y
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_UHCI_HCD is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PCI=y
+# CONFIG_USB_XHCI_PLATFORM is not set
+# CONFIG_USER_NS is not set
+CONFIG_UTS_NS=y
+CONFIG_VA_BITS=39
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_VHOST_MENU is not set
+# CONFIG_VIRTIO_MENU is not set
+CONFIG_VMAP_STACK=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_X509_CERTIFICATE_PARSER=y
+CONFIG_XPS=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA32=y
diff --git a/target/linux/sunxid1/image/Config.in b/target/linux/sunxid1/image/Config.in
new file mode 100644 (file)
index 0000000..6d54195
--- /dev/null
@@ -0,0 +1,5 @@
+config SUNXID1_SD_BOOT_PARTSIZE
+       int "Boot (SD Card) filesystem partition size (in MB)"
+       depends on TARGET_sunxid1
+       default 32
+
diff --git a/target/linux/sunxid1/image/Makefile b/target/linux/sunxid1/image/Makefile
new file mode 100644 (file)
index 0000000..75d4e5e
--- /dev/null
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2021 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+FAT32_BLOCK_SIZE=1024
+FAT32_BLOCKS=$(shell echo $$(($(CONFIG_SUNXID1_SD_BOOT_PARTSIZE)*1024*1024/$(FAT32_BLOCK_SIZE))))
+
+KERNEL_LOADADDR:=0x40200000
+#KERNEL_LOADADDR:=0x40200000
+
+define Build/riscv-sdcard
+       rm -f $@.boot #$(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img
+       mkfs.fat $@.boot  -C $(FAT32_BLOCKS)
+
+       mcopy -i $@.boot $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-boot.scr ::boot.scr
+       mcopy -i $@.boot $(DTS_DIR)/$(DEVICE_DTS).dtb ::dtb
+       mcopy -i $@.boot $(IMAGE_KERNEL) ::uImage
+
+       ./gen_sunxi_sdcard_img.sh \
+               $@ \
+               $@.boot \
+               $(IMAGE_ROOTFS) \
+               $(CONFIG_SUNXID1_SD_BOOT_PARTSIZE) \
+               $(CONFIG_TARGET_ROOTFS_PARTSIZE) \
+               $(STAGING_DIR_IMAGE)/nezha-u-boot.toc1 \
+               $(STAGING_DIR_IMAGE)/boot0_sdcard_sun20iw1p1.bin
+endef
+
+define Device/Default
+  PROFILES := Default
+  KERNEL_NAME := Image
+#  KERNEL := kernel-bin | uImage gzip -a $(KERNEL_LOADADDR)
+  KERNEL := kernel-bin | uImage
+  IMAGES := sdcard.img.gz
+  IMAGE/sdcard.img.gz := riscv-sdcard | append-metadata | gzip
+endef
+
+define Device/FitImageGzip
+       KERNEL_SUFFIX := -fit-uImage.itb
+       KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb
+       KERNEL_NAME := Image
+endef
+
+define Device/FitImage
+       KERNEL_SUFFIX := -fit-uImage.itb
+       KERNEL = kernel-bin | fit none $$(DTS_DIR)/$$(DEVICE_DTS).dtb
+       KERNEL_NAME := Image
+endef
+
+define Device/nezha
+#  $(call Device/FitImage)
+  DEVICE_VENDOR := Nezha
+  DEVICE_MODEL := D1
+  DEVICE_DTS := allwinner/sun20i-d1-nezha
+  UBOOT := nezha
+endef
+
+define Image/Build
+       $(call Image/Build/$(1),$(1))
+endef
+
+TARGET_DEVICES += nezha
+
+$(eval $(call BuildImage))
diff --git a/target/linux/sunxid1/image/gen_sunxi_sdcard_img.sh b/target/linux/sunxid1/image/gen_sunxi_sdcard_img.sh
new file mode 100755 (executable)
index 0000000..08cecc0
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2013 OpenWrt.org
+
+set -ex
+[ $# -eq 7 ] || {
+    echo "SYNTAX: $0 <file> <bootfs image> <rootfs image> <bootfs size> <rootfs size> <u-boot image> <d1 spl>"
+    exit 1
+}
+
+OUTPUT="$1"
+BOOTFS="$2"
+ROOTFS="$3"
+BOOTFSSIZE="$4"
+ROOTFSSIZE="$5"
+UBOOT="$6"
+UBOOT_SPL="$7"
+
+ROOTFSPTOFFSET=$(($BOOTFSSIZE + 20 + 1))
+
+head=4
+sect=63
+
+set $(ptgen -o $OUTPUT -h $head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M@20M -t 83 -p ${ROOTFSSIZE}M@${ROOTFSPTOFFSET}M)
+
+BOOTOFFSET="$(($1 / 512))"
+BOOTSIZE="$(($2 / 512))"
+ROOTFSOFFSET="$(($3 / 512))"
+ROOTFSSIZE="$(($4 / 512))"
+
+dd bs=512 if="$UBOOT_SPL" of="$OUTPUT" seek=256 conv=notrunc
+dd bs=512 if="$UBOOT" of="$OUTPUT" seek=32800 conv=notrunc
+dd bs=512 if="$BOOTFS" of="$OUTPUT" seek="$BOOTOFFSET" conv=notrunc
+dd bs=512 if="$ROOTFS" of="$OUTPUT" seek="$ROOTFSOFFSET" conv=notrunc
+
+
+
+#dd bs=512 if="$UBOOT_SPL" of="$OUTPUT" seek=256 conv=notrunc
+#dd bs=512 if="$UBOOT" of="$OUTPUT" seek=2082 conv=notrunc
+#16M + 34
+#dd bs=512 if="$BOOTFS" of="$OUTPUT" seek=32802 conv=notrunc
+#dd bs=512 if="$ROOTFS" of="$OUTPUT" seek=${ROOTFSOFFSET} conv=notrunc
diff --git a/target/linux/sunxid1/patches-5.15/0001-5.16-clk-sunxi-ng-Unregister-clocks-resets-when-unbinding.patch b/target/linux/sunxid1/patches-5.15/0001-5.16-clk-sunxi-ng-Unregister-clocks-resets-when-unbinding.patch
new file mode 100644 (file)
index 0000000..c785711
--- /dev/null
@@ -0,0 +1,492 @@
+From 7599e32a45d303268886ba6b4a08c37e877e42a2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 1 Sep 2021 00:05:19 -0500
+Subject: [PATCH 001/124] clk: sunxi-ng: Unregister clocks/resets when
+ unbinding
+
+Currently, unbinding a CCU driver unmaps the device's MMIO region, while
+leaving its clocks/resets and their providers registered. This can cause
+a page fault later when some clock operation tries to perform MMIO. Fix
+this by separating the CCU initialization from the memory allocation,
+and then using a devres callback to unregister the clocks and resets.
+
+This also fixes a memory leak of the `struct ccu_reset`, and uses the
+correct owner (the specific platform driver) for the clocks and resets.
+
+Early OF clock providers are never unregistered, and limited error
+handling is possible, so they are mostly unchanged. The error reporting
+is made more consistent by moving the message inside of_sunxi_ccu_probe.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+Link: https://lore.kernel.org/r/20210901050526.45673-2-samuel@sholland.org
+---
+ drivers/clk/sunxi-ng/ccu-sun4i-a10.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-a100.c   |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-a64.c    |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c   |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-h6.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-h616.c   |  4 +-
+ drivers/clk/sunxi-ng/ccu-sun5i.c         |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun6i-a31.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-a23.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-a33.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-a83t.c    |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-de2.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-h3.c      |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-r.c       |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-r40.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun8i-v3s.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c  |  3 +-
+ drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c |  3 +-
+ drivers/clk/sunxi-ng/ccu-sun9i-a80.c     |  2 +-
+ drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c |  2 +-
+ drivers/clk/sunxi-ng/ccu_common.c        | 89 ++++++++++++++++++++----
+ drivers/clk/sunxi-ng/ccu_common.h        |  6 +-
+ 23 files changed, 100 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+index f32366d9336e..bd9a8782fec3 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
++++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+@@ -1464,7 +1464,7 @@ static void __init sun4i_ccu_init(struct device_node *node,
+       val &= ~GENMASK(7, 6);
+       writel(val | (2 << 6), reg + SUN4I_AHB_REG);
+-      sunxi_ccu_probe(node, reg, desc);
++      of_sunxi_ccu_probe(node, reg, desc);
+ }
+ static void __init sun4i_a10_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+index a56142b90993..6f2a58970556 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+@@ -196,7 +196,7 @@ static int sun50i_a100_r_ccu_probe(struct platform_device *pdev)
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+-      return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_r_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a100_r_ccu_desc);
+ }
+ static const struct of_device_id sun50i_a100_r_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+index 81b48c73d389..913bb08e6dee 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+@@ -1247,7 +1247,7 @@ static int sun50i_a100_ccu_probe(struct platform_device *pdev)
+               writel(val, reg + sun50i_a100_usb2_clk_regs[i]);
+       }
+-      ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a100_ccu_desc);
+       if (ret)
+               return ret;
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+index 149cfde817cb..54f25c624f02 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+@@ -955,7 +955,7 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev)
+       writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
+-      ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a64_ccu_desc);
+       if (ret)
+               return ret;
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+index f8909a7ed553..f30d7eb5424d 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+@@ -232,7 +232,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
+               return;
+       }
+-      sunxi_ccu_probe(node, reg, desc);
++      of_sunxi_ccu_probe(node, reg, desc);
+ }
+ static void __init sun50i_h6_r_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+index bff446b78290..c0800da2fa3d 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+@@ -1240,7 +1240,7 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev)
+       val |= BIT(24);
+       writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG);
+-      return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc);
+ }
+ static const struct of_device_id sun50i_h6_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+index 225307305880..22eb18079a15 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+@@ -1141,9 +1141,7 @@ static void __init sun50i_h616_ccu_setup(struct device_node *node)
+       val |= BIT(24);
+       writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG);
+-      i = sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc);
+-      if (i)
+-              pr_err("%pOF: probing clocks fails: %d\n", node, i);
++      of_sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc);
+ }
+ CLK_OF_DECLARE(sun50i_h616_ccu, "allwinner,sun50i-h616-ccu",
+diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c
+index b78e9b507c1c..1f4bc0e773a7 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun5i.c
++++ b/drivers/clk/sunxi-ng/ccu-sun5i.c
+@@ -1012,7 +1012,7 @@ static void __init sun5i_ccu_init(struct device_node *node,
+       val &= ~GENMASK(7, 6);
+       writel(val | (2 << 6), reg + SUN5I_AHB_REG);
+-      sunxi_ccu_probe(node, reg, desc);
++      of_sunxi_ccu_probe(node, reg, desc);
+ }
+ static void __init sun5i_a10s_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+index 9b40d53266a3..3df5c0b41580 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
++++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+@@ -1257,7 +1257,7 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node)
+       val |= 0x3 << 12;
+       writel(val, reg + SUN6I_A31_AHB1_REG);
+-      sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
++      of_sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
+       ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
+                                 &sun6i_a31_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+index 103aa504f6c8..577bb235d658 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+@@ -745,7 +745,7 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node)
+       val &= ~BIT(16);
+       writel(val, reg + SUN8I_A23_PLL_MIPI_REG);
+-      sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc);
++      of_sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc);
+ }
+ CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu",
+              sun8i_a23_ccu_setup);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+index 91838cd11037..8f65cd03f5ac 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+@@ -805,7 +805,7 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
+       val &= ~BIT(16);
+       writel(val, reg + SUN8I_A33_PLL_MIPI_REG);
+-      sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
++      of_sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
+       /* Gate then ungate PLL CPU after any rate changes */
+       ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+index 2b434521c5cc..c2ddcd2ddab4 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+@@ -906,7 +906,7 @@ static int sun8i_a83t_ccu_probe(struct platform_device *pdev)
+       sun8i_a83t_cpu_pll_fixup(reg + SUN8I_A83T_PLL_C0CPUX_REG);
+       sun8i_a83t_cpu_pll_fixup(reg + SUN8I_A83T_PLL_C1CPUX_REG);
+-      return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_a83t_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a83t_ccu_desc);
+ }
+ static const struct of_device_id sun8i_a83t_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+index 524f33275bc7..4b94b6041b27 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+@@ -342,7 +342,7 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev)
+               goto err_disable_mod_clk;
+       }
+-      ret = sunxi_ccu_probe(pdev->dev.of_node, reg, ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
+       if (ret)
+               goto err_assert_reset;
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+index 7e629a4493af..d2fc2903787d 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+@@ -1154,7 +1154,7 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
+       val &= ~GENMASK(19, 16);
+       writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG);
+-      sunxi_ccu_probe(node, reg, desc);
++      of_sunxi_ccu_probe(node, reg, desc);
+       /* Gate then ungate PLL CPU after any rate changes */
+       ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+index 4c8c491b87c2..9e754d1f754a 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+@@ -265,7 +265,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
+               return;
+       }
+-      sunxi_ccu_probe(node, reg, desc);
++      of_sunxi_ccu_probe(node, reg, desc);
+ }
+ static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+index 84153418453f..002e0c3a04db 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+@@ -1346,7 +1346,7 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev)
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+-      ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_r40_ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_r40_ccu_desc);
+       if (ret)
+               return ret;
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+index f49724a22540..ce150f83ab54 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+@@ -822,7 +822,7 @@ static void __init sun8i_v3_v3s_ccu_init(struct device_node *node,
+       val &= ~GENMASK(19, 16);
+       writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG);
+-      sunxi_ccu_probe(node, reg, ccu_desc);
++      of_sunxi_ccu_probe(node, reg, ccu_desc);
+ }
+ static void __init sun8i_v3s_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+index 6616e8114f62..261e64416f26 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+@@ -246,8 +246,7 @@ static int sun9i_a80_de_clk_probe(struct platform_device *pdev)
+               goto err_disable_clk;
+       }
+-      ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
+-                            &sun9i_a80_de_clk_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_de_clk_desc);
+       if (ret)
+               goto err_assert_reset;
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+index 4b4a507d04ed..596243b3e0fa 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+@@ -117,8 +117,7 @@ static int sun9i_a80_usb_clk_probe(struct platform_device *pdev)
+               return ret;
+       }
+-      ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
+-                            &sun9i_a80_usb_clk_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_usb_clk_desc);
+       if (ret)
+               goto err_disable_clk;
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+index ef29582676f6..97aaed0e6850 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+@@ -1231,7 +1231,7 @@ static int sun9i_a80_ccu_probe(struct platform_device *pdev)
+       sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C0CPUX_REG);
+       sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C1CPUX_REG);
+-      return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun9i_a80_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_ccu_desc);
+ }
+ static const struct of_device_id sun9i_a80_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+index 7ecc3a5a5b5e..61ad7ee91c11 100644
+--- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
++++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+@@ -538,7 +538,7 @@ static void __init suniv_f1c100s_ccu_setup(struct device_node *node)
+       val &= ~GENMASK(19, 16);
+       writel(val | (3 << 16), reg + SUNIV_PLL_AUDIO_REG);
+-      sunxi_ccu_probe(node, reg, &suniv_ccu_desc);
++      of_sunxi_ccu_probe(node, reg, &suniv_ccu_desc);
+       /* Gate then ungate PLL CPU after any rate changes */
+       ccu_pll_notifier_register(&suniv_pll_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
+index 2e20e650b6c0..88cb569e5835 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.c
++++ b/drivers/clk/sunxi-ng/ccu_common.c
+@@ -7,6 +7,7 @@
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
++#include <linux/device.h>
+ #include <linux/iopoll.h>
+ #include <linux/slab.h>
+@@ -14,6 +15,11 @@
+ #include "ccu_gate.h"
+ #include "ccu_reset.h"
++struct sunxi_ccu {
++      const struct sunxi_ccu_desc     *desc;
++      struct ccu_reset                reset;
++};
++
+ static DEFINE_SPINLOCK(ccu_lock);
+ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
+@@ -79,12 +85,15 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb)
+                                    &pll_nb->clk_nb);
+ }
+-int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+-                  const struct sunxi_ccu_desc *desc)
++static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
++                         struct device_node *node, void __iomem *reg,
++                         const struct sunxi_ccu_desc *desc)
+ {
+       struct ccu_reset *reset;
+       int i, ret;
++      ccu->desc = desc;
++
+       for (i = 0; i < desc->num_ccu_clks; i++) {
+               struct ccu_common *cclk = desc->ccu_clks[i];
+@@ -103,7 +112,10 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+                       continue;
+               name = hw->init->name;
+-              ret = of_clk_hw_register(node, hw);
++              if (dev)
++                      ret = clk_hw_register(dev, hw);
++              else
++                      ret = of_clk_hw_register(node, hw);
+               if (ret) {
+                       pr_err("Couldn't register clock %d - %s\n", i, name);
+                       goto err_clk_unreg;
+@@ -115,15 +127,10 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+       if (ret)
+               goto err_clk_unreg;
+-      reset = kzalloc(sizeof(*reset), GFP_KERNEL);
+-      if (!reset) {
+-              ret = -ENOMEM;
+-              goto err_alloc_reset;
+-      }
+-
++      reset = &ccu->reset;
+       reset->rcdev.of_node = node;
+       reset->rcdev.ops = &ccu_reset_ops;
+-      reset->rcdev.owner = THIS_MODULE;
++      reset->rcdev.owner = dev ? dev->driver->owner : THIS_MODULE;
+       reset->rcdev.nr_resets = desc->num_resets;
+       reset->base = reg;
+       reset->lock = &ccu_lock;
+@@ -131,13 +138,11 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+       ret = reset_controller_register(&reset->rcdev);
+       if (ret)
+-              goto err_of_clk_unreg;
++              goto err_del_provider;
+       return 0;
+-err_of_clk_unreg:
+-      kfree(reset);
+-err_alloc_reset:
++err_del_provider:
+       of_clk_del_provider(node);
+ err_clk_unreg:
+       while (--i >= 0) {
+@@ -149,3 +154,59 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+       }
+       return ret;
+ }
++
++static void devm_sunxi_ccu_release(struct device *dev, void *res)
++{
++      struct sunxi_ccu *ccu = res;
++      const struct sunxi_ccu_desc *desc = ccu->desc;
++      int i;
++
++      reset_controller_unregister(&ccu->reset.rcdev);
++      of_clk_del_provider(dev->of_node);
++
++      for (i = 0; i < desc->hw_clks->num; i++) {
++              struct clk_hw *hw = desc->hw_clks->hws[i];
++
++              if (!hw)
++                      continue;
++              clk_hw_unregister(hw);
++      }
++}
++
++int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg,
++                       const struct sunxi_ccu_desc *desc)
++{
++      struct sunxi_ccu *ccu;
++      int ret;
++
++      ccu = devres_alloc(devm_sunxi_ccu_release, sizeof(*ccu), GFP_KERNEL);
++      if (!ccu)
++              return -ENOMEM;
++
++      ret = sunxi_ccu_probe(ccu, dev, dev->of_node, reg, desc);
++      if (ret) {
++              devres_free(ccu);
++              return ret;
++      }
++
++      devres_add(dev, ccu);
++
++      return 0;
++}
++
++void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
++                      const struct sunxi_ccu_desc *desc)
++{
++      struct sunxi_ccu *ccu;
++      int ret;
++
++      ccu = kzalloc(sizeof(*ccu), GFP_KERNEL);
++      if (!ccu)
++              return;
++
++      ret = sunxi_ccu_probe(ccu, NULL, node, reg, desc);
++      if (ret) {
++              pr_err("%pOF: probing clocks failed: %d\n", node, ret);
++              kfree(ccu);
++      }
++}
+diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
+index 04e7a12200a2..98a1834b58bb 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.h
++++ b/drivers/clk/sunxi-ng/ccu_common.h
+@@ -63,7 +63,9 @@ struct ccu_pll_nb {
+ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb);
+-int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+-                  const struct sunxi_ccu_desc *desc);
++int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg,
++                       const struct sunxi_ccu_desc *desc);
++void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
++                      const struct sunxi_ccu_desc *desc);
+ #endif /* _COMMON_H_ */
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0002-5.16-clk-sunxi-ng-Prevent-unbinding-CCUs-via-sysfs.patch b/target/linux/sunxid1/patches-5.15/0002-5.16-clk-sunxi-ng-Prevent-unbinding-CCUs-via-sysfs.patch
new file mode 100644 (file)
index 0000000..ed66c08
--- /dev/null
@@ -0,0 +1,126 @@
+From 98249d575dc3956e61214da83098cab4983aebd3 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 1 Sep 2021 00:05:20 -0500
+Subject: [PATCH 002/124] clk: sunxi-ng: Prevent unbinding CCUs via sysfs
+
+The CCU drivers are not really designed to be unbound. Unbinding a SoC's
+main CCU is especially pointless, as very few of the peripherals on the
+SoC will work without it. Let's avoid any potential problems by removing
+the bind/unbind attributes from sysfs for these drivers.
+
+This change is not applied to the "secondary" CCUs (DE, USB) as those
+could reasonably be unbound without making the system useless.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+Link: https://lore.kernel.org/r/20210901050526.45673-3-samuel@sholland.org
+---
+ drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c | 1 +
+ drivers/clk/sunxi-ng/ccu-sun50i-a100.c   | 1 +
+ drivers/clk/sunxi-ng/ccu-sun50i-a64.c    | 1 +
+ drivers/clk/sunxi-ng/ccu-sun50i-h6.c     | 1 +
+ drivers/clk/sunxi-ng/ccu-sun8i-a83t.c    | 1 +
+ drivers/clk/sunxi-ng/ccu-sun8i-r40.c     | 1 +
+ drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c  | 1 +
+ drivers/clk/sunxi-ng/ccu-sun9i-a80.c     | 1 +
+ 8 files changed, 8 insertions(+)
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+index 6f2a58970556..804729e0a208 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+@@ -208,6 +208,7 @@ static struct platform_driver sun50i_a100_r_ccu_driver = {
+       .probe  = sun50i_a100_r_ccu_probe,
+       .driver = {
+               .name   = "sun50i-a100-r-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun50i_a100_r_ccu_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+index 913bb08e6dee..1d475d5a3d91 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+@@ -1270,6 +1270,7 @@ static struct platform_driver sun50i_a100_ccu_driver = {
+       .probe  = sun50i_a100_ccu_probe,
+       .driver = {
+               .name   = "sun50i-a100-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun50i_a100_ccu_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+index 54f25c624f02..fcbd914e84e0 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+@@ -978,6 +978,7 @@ static struct platform_driver sun50i_a64_ccu_driver = {
+       .probe  = sun50i_a64_ccu_probe,
+       .driver = {
+               .name   = "sun50i-a64-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun50i_a64_ccu_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+index c0800da2fa3d..9a8902f702c5 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+@@ -1252,6 +1252,7 @@ static struct platform_driver sun50i_h6_ccu_driver = {
+       .probe  = sun50i_h6_ccu_probe,
+       .driver = {
+               .name   = "sun50i-h6-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun50i_h6_ccu_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+index c2ddcd2ddab4..e663ab0c9935 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+@@ -918,6 +918,7 @@ static struct platform_driver sun8i_a83t_ccu_driver = {
+       .probe  = sun8i_a83t_ccu_probe,
+       .driver = {
+               .name   = "sun8i-a83t-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun8i_a83t_ccu_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+index 002e0c3a04db..a2144ee728a0 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+@@ -1369,6 +1369,7 @@ static struct platform_driver sun8i_r40_ccu_driver = {
+       .probe  = sun8i_r40_ccu_probe,
+       .driver = {
+               .name   = "sun8i-r40-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun8i_r40_ccu_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+index 261e64416f26..d2072972b614 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+@@ -268,6 +268,7 @@ static struct platform_driver sun9i_a80_de_clk_driver = {
+       .probe  = sun9i_a80_de_clk_probe,
+       .driver = {
+               .name   = "sun9i-a80-de-clks",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun9i_a80_de_clk_ids,
+       },
+ };
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+index 97aaed0e6850..68b30fdc60fd 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+@@ -1243,6 +1243,7 @@ static struct platform_driver sun9i_a80_ccu_driver = {
+       .probe  = sun9i_a80_ccu_probe,
+       .driver = {
+               .name   = "sun9i-a80-ccu",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun9i_a80_ccu_ids,
+       },
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0003-5.16-clk-sunxi-ng-Use-a-separate-lock-for-each-CCU-instan.patch b/target/linux/sunxid1/patches-5.15/0003-5.16-clk-sunxi-ng-Use-a-separate-lock-for-each-CCU-instan.patch
new file mode 100644 (file)
index 0000000..c91ac1f
--- /dev/null
@@ -0,0 +1,65 @@
+From 93395c038bc0a1750fec54eec531c5d36eec1aaf Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 1 Sep 2021 00:05:21 -0500
+Subject: [PATCH 003/124] clk: sunxi-ng: Use a separate lock for each CCU
+ instance
+
+Some platforms have more than one CCU driver loaded: the main CCU, the
+PRCM, the display engine, and possibly others. All of these hardware
+blocks have separate MMIO spaces, so there is no need to synchronize
+between them.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+Link: https://lore.kernel.org/r/20210901050526.45673-4-samuel@sholland.org
+---
+ drivers/clk/sunxi-ng/ccu_common.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
+index 88cb569e5835..31af8b6b5286 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.c
++++ b/drivers/clk/sunxi-ng/ccu_common.c
+@@ -17,11 +17,10 @@
+ struct sunxi_ccu {
+       const struct sunxi_ccu_desc     *desc;
++      spinlock_t                      lock;
+       struct ccu_reset                reset;
+ };
+-static DEFINE_SPINLOCK(ccu_lock);
+-
+ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
+ {
+       void __iomem *addr;
+@@ -94,6 +93,8 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
+       ccu->desc = desc;
++      spin_lock_init(&ccu->lock);
++
+       for (i = 0; i < desc->num_ccu_clks; i++) {
+               struct ccu_common *cclk = desc->ccu_clks[i];
+@@ -101,7 +102,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
+                       continue;
+               cclk->base = reg;
+-              cclk->lock = &ccu_lock;
++              cclk->lock = &ccu->lock;
+       }
+       for (i = 0; i < desc->hw_clks->num ; i++) {
+@@ -133,7 +134,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
+       reset->rcdev.owner = dev ? dev->driver->owner : THIS_MODULE;
+       reset->rcdev.nr_resets = desc->num_resets;
+       reset->base = reg;
+-      reset->lock = &ccu_lock;
++      reset->lock = &ccu->lock;
+       reset->reset_map = desc->resets;
+       ret = reset_controller_register(&reset->rcdev);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0004-5.16-rtc-sun6i-Allow-probing-without-an-early-clock-provi.patch b/target/linux/sunxid1/patches-5.15/0004-5.16-rtc-sun6i-Allow-probing-without-an-early-clock-provi.patch
new file mode 100644 (file)
index 0000000..69044fb
--- /dev/null
@@ -0,0 +1,46 @@
+From 0dfc140602711a3d2a72cdc9bd24f2937b14ef01 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Tue, 28 Sep 2021 03:03:32 -0500
+Subject: [PATCH 004/124] rtc: sun6i: Allow probing without an early clock
+ provider
+
+Some SoCs have an RTC supported by this RTC driver, but do not have an
+early clock provider declared here. Currently, this prevents the RTC
+driver from probing, because it expects a global struct to already be
+allocated. Fix probing the driver by copying the missing pieces from the
+clock provider setup function, replacing them with the devm variants.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Link: https://lore.kernel.org/r/20210928080335.36706-7-samuel@sholland.org
+---
+ drivers/rtc/rtc-sun6i.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index adec1b14a8de..711832c758ae 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -673,8 +673,17 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
+       struct sun6i_rtc_dev *chip = sun6i_rtc;
+       int ret;
+-      if (!chip)
+-              return -ENODEV;
++      if (!chip) {
++              chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
++              if (!chip)
++                      return -ENOMEM;
++
++              spin_lock_init(&chip->lock);
++
++              chip->base = devm_platform_ioremap_resource(pdev, 0);
++              if (IS_ERR(chip->base))
++                      return PTR_ERR(chip->base);
++      }
+       platform_set_drvdata(pdev, chip);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0005-5.16-riscv-remove-.text-section-size-limitation-for-XIP.patch b/target/linux/sunxid1/patches-5.15/0005-5.16-riscv-remove-.text-section-size-limitation-for-XIP.patch
new file mode 100644 (file)
index 0000000..2be08e7
--- /dev/null
@@ -0,0 +1,148 @@
+From cdbe9f3ed5fd2fa0395f317b81e653781c768d7e Mon Sep 17 00:00:00 2001
+From: Vitaly Wool <vitaly.wool@konsulko.com>
+Date: Mon, 11 Oct 2021 11:14:14 +0200
+Subject: [PATCH 005/124] riscv: remove .text section size limitation for XIP
+
+Currently there's a limit of 8MB for the .text section of a RISC-V
+image in the XIP case. This breaks compilation of many automatic
+builds and is generally inconvenient. This patch removes that
+limitation and optimizes XIP image file size at the same time.
+
+Signed-off-by: Vitaly Wool <vitaly.wool@konsulko.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+---
+ arch/riscv/include/asm/pgtable.h    |  6 ++++--
+ arch/riscv/kernel/head.S            | 12 ++++++++++++
+ arch/riscv/kernel/vmlinux-xip.lds.S | 10 +++++++---
+ arch/riscv/mm/init.c                |  7 +++----
+ 4 files changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index 39b550310ec6..bf204e7c1f74 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -75,7 +75,8 @@
+ #endif
+ #ifdef CONFIG_XIP_KERNEL
+-#define XIP_OFFSET            SZ_8M
++#define XIP_OFFSET            SZ_32M
++#define XIP_OFFSET_MASK               (SZ_32M - 1)
+ #else
+ #define XIP_OFFSET            0
+ #endif
+@@ -97,7 +98,8 @@
+ #ifdef CONFIG_XIP_KERNEL
+ #define XIP_FIXUP(addr) ({                                                    \
+       uintptr_t __a = (uintptr_t)(addr);                                      \
+-      (__a >= CONFIG_XIP_PHYS_ADDR && __a < CONFIG_XIP_PHYS_ADDR + SZ_16M) ?  \
++      (__a >= CONFIG_XIP_PHYS_ADDR && \
++       __a < CONFIG_XIP_PHYS_ADDR + XIP_OFFSET * 2) ? \
+               __a - CONFIG_XIP_PHYS_ADDR + CONFIG_PHYS_RAM_BASE - XIP_OFFSET :\
+               __a;                                                            \
+       })
+diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
+index 52c5ff9804c5..ebd577b51c5c 100644
+--- a/arch/riscv/kernel/head.S
++++ b/arch/riscv/kernel/head.S
+@@ -20,10 +20,20 @@
+       REG_L t0, _xip_fixup
+       add \reg, \reg, t0
+ .endm
++.macro XIP_FIXUP_FLASH_OFFSET reg
++      la t1, __data_loc
++      li t0, XIP_OFFSET_MASK
++      and t1, t1, t0
++      li t1, XIP_OFFSET
++      sub t0, t0, t1
++      sub \reg, \reg, t0
++.endm
+ _xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET
+ #else
+ .macro XIP_FIXUP_OFFSET reg
+ .endm
++.macro XIP_FIXUP_FLASH_OFFSET reg
++.endm
+ #endif /* CONFIG_XIP_KERNEL */
+ __HEAD
+@@ -267,6 +277,7 @@ pmp_done:
+       la a3, hart_lottery
+       mv a2, a3
+       XIP_FIXUP_OFFSET a2
++      XIP_FIXUP_FLASH_OFFSET a3
+       lw t1, (a3)
+       amoswap.w t0, t1, (a2)
+       /* first time here if hart_lottery in RAM is not set */
+@@ -305,6 +316,7 @@ clear_bss_done:
+       XIP_FIXUP_OFFSET sp
+ #ifdef CONFIG_BUILTIN_DTB
+       la a0, __dtb_start
++      XIP_FIXUP_OFFSET a0
+ #else
+       mv a0, s1
+ #endif /* CONFIG_BUILTIN_DTB */
+diff --git a/arch/riscv/kernel/vmlinux-xip.lds.S b/arch/riscv/kernel/vmlinux-xip.lds.S
+index 9c9f35091ef0..f5ed08262139 100644
+--- a/arch/riscv/kernel/vmlinux-xip.lds.S
++++ b/arch/riscv/kernel/vmlinux-xip.lds.S
+@@ -64,8 +64,11 @@ SECTIONS
+ /*
+  * From this point, stuff is considered writable and will be copied to RAM
+  */
+-      __data_loc = ALIGN(16);         /* location in file */
+-      . = LOAD_OFFSET + XIP_OFFSET;   /* location in memory */
++      __data_loc = ALIGN(PAGE_SIZE);          /* location in file */
++      . = KERNEL_LINK_ADDR + XIP_OFFSET;      /* location in memory */
++
++#undef LOAD_OFFSET
++#define LOAD_OFFSET (KERNEL_LINK_ADDR + XIP_OFFSET - (__data_loc & XIP_OFFSET_MASK))
+       _sdata = .;                     /* Start of data section */
+       _data = .;
+@@ -96,7 +99,6 @@ SECTIONS
+               KEEP(*(__soc_builtin_dtb_table))
+               __soc_builtin_dtb_table_end = .;
+       }
+-      PERCPU_SECTION(L1_CACHE_BYTES)
+       . = ALIGN(8);
+       .alternative : {
+@@ -122,6 +124,8 @@ SECTIONS
+       BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
++      PERCPU_SECTION(L1_CACHE_BYTES)
++
+       .rel.dyn : AT(ADDR(.rel.dyn) - LOAD_OFFSET) {
+               *(.rel.dyn*)
+       }
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index c0cddf0fc22d..24b2b8044602 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -41,7 +41,7 @@ phys_addr_t phys_ram_base __ro_after_init;
+ EXPORT_SYMBOL(phys_ram_base);
+ #ifdef CONFIG_XIP_KERNEL
+-extern char _xiprom[], _exiprom[];
++extern char _xiprom[], _exiprom[], __data_loc;
+ #endif
+ unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
+@@ -454,10 +454,9 @@ static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
+ /* called from head.S with MMU off */
+ asmlinkage void __init __copy_data(void)
+ {
+-      void *from = (void *)(&_sdata);
+-      void *end = (void *)(&_end);
++      void *from = (void *)(&__data_loc);
+       void *to = (void *)CONFIG_PHYS_RAM_BASE;
+-      size_t sz = (size_t)(end - from + 1);
++      size_t sz = (size_t)((uintptr_t)(&_end) - (uintptr_t)(&_sdata));
+       memcpy(to, from, sz);
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0006-5.16-irq-simplify-handle_domain_-irq-nmi.patch b/target/linux/sunxid1/patches-5.15/0006-5.16-irq-simplify-handle_domain_-irq-nmi.patch
new file mode 100644 (file)
index 0000000..9b40fdb
--- /dev/null
@@ -0,0 +1,76 @@
+From 2f0335228bf4bf224f5535464a940753c18af8f9 Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Tue, 19 Oct 2021 10:40:45 +0100
+Subject: [PATCH 006/124] irq: simplify handle_domain_{irq,nmi}()
+
+There's no need for handle_domain_{irq,nmi}() to open-code the NULL
+check performed by handle_irq_desc(), nor the resolution of the desc
+performed by generic_handle_domain_irq().
+
+Use generic_handle_domain_irq() directly, as this is functioanlly
+equivalent and clearer. At the same time, delete the stale comments,
+which are no longer helpful.
+
+There should be no functional change as a result of this patch.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ kernel/irq/irqdesc.c | 24 ++++--------------------
+ 1 file changed, 4 insertions(+), 20 deletions(-)
+
+diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
+index 4e3c29bb603c..b07d0e1552bc 100644
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -690,17 +690,11 @@ int handle_domain_irq(struct irq_domain *domain,
+                     unsigned int hwirq, struct pt_regs *regs)
+ {
+       struct pt_regs *old_regs = set_irq_regs(regs);
+-      struct irq_desc *desc;
+-      int ret = 0;
++      int ret;
+       irq_enter();
+-      /* The irqdomain code provides boundary checks */
+-      desc = irq_resolve_mapping(domain, hwirq);
+-      if (likely(desc))
+-              handle_irq_desc(desc);
+-      else
+-              ret = -EINVAL;
++      ret = generic_handle_domain_irq(domain, hwirq);
+       irq_exit();
+       set_irq_regs(old_regs);
+@@ -721,24 +715,14 @@ int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
+                     struct pt_regs *regs)
+ {
+       struct pt_regs *old_regs = set_irq_regs(regs);
+-      struct irq_desc *desc;
+-      int ret = 0;
++      int ret;
+       /*
+        * NMI context needs to be setup earlier in order to deal with tracing.
+        */
+       WARN_ON(!in_nmi());
+-      desc = irq_resolve_mapping(domain, hwirq);
+-
+-      /*
+-       * ack_bad_irq is not NMI-safe, just report
+-       * an invalid interrupt.
+-       */
+-      if (likely(desc))
+-              handle_irq_desc(desc);
+-      else
+-              ret = -EINVAL;
++      ret = generic_handle_domain_irq(domain, hwirq);
+       set_irq_regs(old_regs);
+       return ret;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0007-5.16-irq-unexport-handle_irq_desc.patch b/target/linux/sunxid1/patches-5.15/0007-5.16-irq-unexport-handle_irq_desc.patch
new file mode 100644 (file)
index 0000000..49e6c2c
--- /dev/null
@@ -0,0 +1,31 @@
+From 5066cc5deaca0171b8b27079f81a924471be0e78 Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Fri, 22 Oct 2021 15:35:04 +0100
+Subject: [PATCH 007/124] irq: unexport handle_irq_desc()
+
+There are no modular users of handle_irq_desc(). Remove the export
+before we gain any.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Suggested-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ kernel/irq/irqdesc.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
+index b07d0e1552bc..e25d4bddf3d8 100644
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -646,7 +646,6 @@ int handle_irq_desc(struct irq_desc *desc)
+       generic_handle_irq_desc(desc);
+       return 0;
+ }
+-EXPORT_SYMBOL_GPL(handle_irq_desc);
+ /**
+  * generic_handle_irq - Invoke the handler for a particular irq
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0008-5.16-irq-add-a-temporary-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTR.patch b/target/linux/sunxid1/patches-5.15/0008-5.16-irq-add-a-temporary-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTR.patch
new file mode 100644 (file)
index 0000000..2b4745e
--- /dev/null
@@ -0,0 +1,193 @@
+From 48f86fb2e394a3daf227faaf2ada4b130d0da6ca Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Tue, 19 Oct 2021 11:12:31 +0100
+Subject: [PATCH 008/124] irq: add a (temporary)
+ CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY
+
+Going forward we want architecture/entry code to perform all the
+necessary work to enter/exit IRQ context, with irqchip code merely
+handling the mapping of the interrupt to any handler(s). Among other
+reasons, this is necessary to consistently fix some longstanding issues
+with the ordering of lockdep/RCU/tracing instrumentation which many
+architectures get wrong today in their entry code.
+
+Importantly, rcu_irq_{enter,exit}() must be called precisely once per
+IRQ exception, so that rcu_is_cpu_rrupt_from_idle() can correctly
+identify when an interrupt was taken from an idle context which must be
+explicitly preempted. Currently handle_domain_irq() calls
+rcu_irq_{enter,exit}() via irq_{enter,exit}(), but entry code needs to
+be able to call rcu_irq_{enter,exit}() earlier for correct ordering
+across lockdep/RCU/tracing updates for sequences such as:
+
+  lockdep_hardirqs_off(CALLER_ADDR0);
+  rcu_irq_enter();
+  trace_hardirqs_off_finish();
+
+To permit each architecture to be converted to the new style in turn,
+this patch adds a new CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY selected by all
+current users of HANDLE_DOMAIN_IRQ, which gates the existing behaviour.
+When CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY is not selected,
+handle_domain_irq() requires entry code to perform the
+irq_{enter,exit}() work, with an explicit check for this matching the
+style of handle_domain_nmi().
+
+Subsequent patches will:
+
+1) Add the necessary IRQ entry accounting to each architecture in turn,
+   dropping CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY from that architecture's
+   Kconfig.
+
+2) Remove CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY once it is no longer
+   selected.
+
+3) Convert irqchip drivers to consistently use
+   generic_handle_domain_irq() rather than handle_domain_irq().
+
+4) Remove handle_domain_irq() and CONFIG_HANDLE_DOMAIN_IRQ.
+
+... which should leave us with a clear split of responsiblity across the
+entry and irqchip code, making it possible to perform additional
+cleanups and fixes for the aforementioned longstanding issues with entry
+code.
+
+There should be no functional change as a result of this patch.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ arch/arm/Kconfig      |  1 +
+ arch/arm64/Kconfig    |  1 +
+ arch/csky/Kconfig     |  1 +
+ arch/openrisc/Kconfig |  1 +
+ arch/riscv/Kconfig    |  1 +
+ kernel/irq/Kconfig    |  4 ++++
+ kernel/irq/irqdesc.c  | 30 ++++++++++++++++++++++++++++++
+ 7 files changed, 39 insertions(+)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index dcf2df6da98f..2a84c0c7e161 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -65,6 +65,7 @@ config ARM
+       select GENERIC_SCHED_CLOCK
+       select GENERIC_SMP_IDLE_THREAD
+       select HANDLE_DOMAIN_IRQ
++      select HANDLE_DOMAIN_IRQ_IRQENTRY
+       select HARDIRQS_SW_RESEND
+       select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
+       select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index fee914c716aa..e7fbea796ed5 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -134,6 +134,7 @@ config ARM64
+       select GENERIC_GETTIMEOFDAY
+       select GENERIC_VDSO_TIME_NS
+       select HANDLE_DOMAIN_IRQ
++      select HANDLE_DOMAIN_IRQ_IRQENTRY
+       select HARDIRQS_SW_RESEND
+       select HAVE_MOVE_PMD
+       select HAVE_MOVE_PUD
+diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig
+index 823d3d5a9e11..d8453dcff94e 100644
+--- a/arch/csky/Kconfig
++++ b/arch/csky/Kconfig
+@@ -18,6 +18,7 @@ config CSKY
+       select DMA_DIRECT_REMAP
+       select IRQ_DOMAIN
+       select HANDLE_DOMAIN_IRQ
++      select HANDLE_DOMAIN_IRQ_IRQENTRY
+       select DW_APB_TIMER_OF
+       select GENERIC_IOREMAP
+       select GENERIC_LIB_ASHLDI3
+diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
+index e804026b4797..ed783a67065e 100644
+--- a/arch/openrisc/Kconfig
++++ b/arch/openrisc/Kconfig
+@@ -14,6 +14,7 @@ config OPENRISC
+       select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
+       select HANDLE_DOMAIN_IRQ
++      select HANDLE_DOMAIN_IRQ_IRQENTRY
+       select GPIOLIB
+       select HAVE_ARCH_TRACEHOOK
+       select SPARSE_IRQ
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index f076cee11af6..ff159d5eb33e 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -63,6 +63,7 @@ config RISCV
+       select GENERIC_SMP_IDLE_THREAD
+       select GENERIC_TIME_VSYSCALL if MMU && 64BIT
+       select HANDLE_DOMAIN_IRQ
++      select HANDLE_DOMAIN_IRQ_IRQENTRY
+       select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
+       select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
+diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
+index fbc54c2a7f23..897dfc552bb0 100644
+--- a/kernel/irq/Kconfig
++++ b/kernel/irq/Kconfig
+@@ -100,6 +100,10 @@ config IRQ_MSI_IOMMU
+ config HANDLE_DOMAIN_IRQ
+       bool
++# Legacy behaviour; architectures should call irq_{enter,exit}() themselves
++config HANDLE_DOMAIN_IRQ_IRQENTRY
++      bool
++
+ config IRQ_TIMINGS
+       bool
+diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
+index e25d4bddf3d8..5677a849cf1f 100644
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -676,6 +676,7 @@ int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
+ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
+ #ifdef CONFIG_HANDLE_DOMAIN_IRQ
++#ifdef CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY
+ /**
+  * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
+  *                     usually for a root interrupt controller
+@@ -699,6 +700,35 @@ int handle_domain_irq(struct irq_domain *domain,
+       set_irq_regs(old_regs);
+       return ret;
+ }
++#else
++/**
++ * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
++ *                     usually for a root interrupt controller
++ * @domain:   The domain where to perform the lookup
++ * @hwirq:    The HW irq number to convert to a logical one
++ * @regs:     Register file coming from the low-level handling code
++ *
++ *            This function must be called from an IRQ context.
++ *
++ * Returns:   0 on success, or -EINVAL if conversion has failed
++ */
++int handle_domain_irq(struct irq_domain *domain,
++                    unsigned int hwirq, struct pt_regs *regs)
++{
++      struct pt_regs *old_regs = set_irq_regs(regs);
++      int ret;
++
++      /*
++       * IRQ context needs to be setup earlier.
++       */
++      WARN_ON(!in_irq());
++
++      ret = generic_handle_domain_irq(domain, hwirq);
++
++      set_irq_regs(old_regs);
++      return ret;
++}
++#endif
+ /**
+  * handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0009-5.16-irq-remove-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY.patch b/target/linux/sunxid1/patches-5.15/0009-5.16-irq-remove-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY.patch
new file mode 100644 (file)
index 0000000..ad28c83
--- /dev/null
@@ -0,0 +1,63 @@
+From 0a7b76c9ec957c83a5b2f4b06ec66220b4804c03 Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Wed, 20 Oct 2021 15:49:03 +0100
+Subject: [PATCH 009/124] irq: remove CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY
+
+Now that all users of CONFIG_HANDLE_DOMAIN_IRQ perform the irq entry
+work themselves, we can remove the legacy
+CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY behaviour.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ kernel/irq/irqdesc.c | 26 --------------------------
+ 1 file changed, 26 deletions(-)
+
+diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
+index 5677a849cf1f..7041698a7bff 100644
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -676,31 +676,6 @@ int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
+ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
+ #ifdef CONFIG_HANDLE_DOMAIN_IRQ
+-#ifdef CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY
+-/**
+- * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
+- *                     usually for a root interrupt controller
+- * @domain:   The domain where to perform the lookup
+- * @hwirq:    The HW irq number to convert to a logical one
+- * @regs:     Register file coming from the low-level handling code
+- *
+- * Returns:   0 on success, or -EINVAL if conversion has failed
+- */
+-int handle_domain_irq(struct irq_domain *domain,
+-                    unsigned int hwirq, struct pt_regs *regs)
+-{
+-      struct pt_regs *old_regs = set_irq_regs(regs);
+-      int ret;
+-
+-      irq_enter();
+-
+-      ret = generic_handle_domain_irq(domain, hwirq);
+-
+-      irq_exit();
+-      set_irq_regs(old_regs);
+-      return ret;
+-}
+-#else
+ /**
+  * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
+  *                     usually for a root interrupt controller
+@@ -728,7 +703,6 @@ int handle_domain_irq(struct irq_domain *domain,
+       set_irq_regs(old_regs);
+       return ret;
+ }
+-#endif
+ /**
+  * handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0010-5.16-irq-add-generic_handle_arch_irq.patch b/target/linux/sunxid1/patches-5.15/0010-5.16-irq-add-generic_handle_arch_irq.patch
new file mode 100644 (file)
index 0000000..2320921
--- /dev/null
@@ -0,0 +1,76 @@
+From 226328e72b232a1702e29f8f6747c4d889d4425c Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Wed, 20 Oct 2021 11:24:06 +0100
+Subject: [PATCH 010/124] irq: add generic_handle_arch_irq()
+
+Several architectures select GENERIC_IRQ_MULTI_HANDLER and branch to
+handle_arch_irq() without performing any entry accounting.
+
+Add a generic wrapper to handle the common irqentry work when invoking
+handle_arch_irq(). Where an architecture needs to perform some entry
+accounting itself, it will need to invoke handle_arch_irq() itself.
+
+In subsequent patches it will become the responsibilty of the entry code
+to set the irq regs when entering an IRQ (rather than deferring this to
+an irqchip handler), so generic_handle_arch_irq() is made to set the irq
+regs now. This can be redundant in some cases, but is never harmful as
+saving/restoring the old regs nests safely.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Guo Ren <guoren@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ include/linux/irq.h |  1 +
+ kernel/irq/handle.c | 18 ++++++++++++++++++
+ 2 files changed, 19 insertions(+)
+
+diff --git a/include/linux/irq.h b/include/linux/irq.h
+index c8293c817646..988c225eef2d 100644
+--- a/include/linux/irq.h
++++ b/include/linux/irq.h
+@@ -1261,6 +1261,7 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *));
+  * top-level IRQ handler.
+  */
+ extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
++asmlinkage void generic_handle_arch_irq(struct pt_regs *regs);
+ #else
+ #ifndef set_handle_irq
+ #define set_handle_irq(handle_irq)            \
+diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
+index 221d80c31e94..27182003b879 100644
+--- a/kernel/irq/handle.c
++++ b/kernel/irq/handle.c
+@@ -14,6 +14,8 @@
+ #include <linux/interrupt.h>
+ #include <linux/kernel_stat.h>
++#include <asm/irq_regs.h>
++
+ #include <trace/events/irq.h>
+ #include "internals.h"
+@@ -226,4 +228,20 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
+       handle_arch_irq = handle_irq;
+       return 0;
+ }
++
++/**
++ * generic_handle_arch_irq - root irq handler for architectures which do no
++ *                           entry accounting themselves
++ * @regs:     Register file coming from the low-level handling code
++ */
++asmlinkage void noinstr generic_handle_arch_irq(struct pt_regs *regs)
++{
++      struct pt_regs *old_regs;
++
++      irq_enter();
++      old_regs = set_irq_regs(regs);
++      handle_arch_irq(regs);
++      set_irq_regs(old_regs);
++      irq_exit();
++}
+ #endif
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0011-5.16-irq-riscv-perform-irqentry-in-entry-code.patch b/target/linux/sunxid1/patches-5.15/0011-5.16-irq-riscv-perform-irqentry-in-entry-code.patch
new file mode 100644 (file)
index 0000000..1490468
--- /dev/null
@@ -0,0 +1,96 @@
+From ef1f47034f47324dfdb12e97253401438a9ff18d Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Wed, 20 Oct 2021 11:33:49 +0100
+Subject: [PATCH 011/124] irq: riscv: perform irqentry in entry code
+
+In preparation for removing HANDLE_DOMAIN_IRQ_IRQENTRY, have arch/riscv
+perform all the irqentry accounting in its entry code. As arch/riscv
+uses GENERIC_IRQ_MULTI_HANDLER, we can use generic_handle_arch_irq() to
+do so.
+
+Since generic_handle_arch_irq() handles the irq entry and setting the
+irq regs, and happens before the irqchip code calls handle_IPI(), we can
+remove the redundant irq entry and irq regs manipulation from
+handle_IPI().
+
+There should be no functional change as a result of this patch.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Reviewed-by: Guo Ren <guoren@kernel.org>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: Albert Ou <aou@eecs.berkeley.edu>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+Cc: Paul Walmsley <paul.walmsley@sifive.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ arch/riscv/Kconfig        | 1 -
+ arch/riscv/kernel/entry.S | 3 +--
+ arch/riscv/kernel/smp.c   | 9 +--------
+ 3 files changed, 2 insertions(+), 11 deletions(-)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index ff159d5eb33e..f076cee11af6 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -63,7 +63,6 @@ config RISCV
+       select GENERIC_SMP_IDLE_THREAD
+       select GENERIC_TIME_VSYSCALL if MMU && 64BIT
+       select HANDLE_DOMAIN_IRQ
+-      select HANDLE_DOMAIN_IRQ_IRQENTRY
+       select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
+       select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
+diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
+index 98f502654edd..64236f7efde5 100644
+--- a/arch/riscv/kernel/entry.S
++++ b/arch/riscv/kernel/entry.S
+@@ -130,8 +130,7 @@ skip_context_tracking:
+       /* Handle interrupts */
+       move a0, sp /* pt_regs */
+-      la a1, handle_arch_irq
+-      REG_L a1, (a1)
++      la a1, generic_handle_arch_irq
+       jr a1
+ 1:
+       /*
+diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
+index 921d9d7df400..2f6da845c9ae 100644
+--- a/arch/riscv/kernel/smp.c
++++ b/arch/riscv/kernel/smp.c
+@@ -140,12 +140,9 @@ void arch_irq_work_raise(void)
+ void handle_IPI(struct pt_regs *regs)
+ {
+-      struct pt_regs *old_regs = set_irq_regs(regs);
+       unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
+       unsigned long *stats = ipi_data[smp_processor_id()].stats;
+-      irq_enter();
+-
+       riscv_clear_ipi();
+       while (true) {
+@@ -156,7 +153,7 @@ void handle_IPI(struct pt_regs *regs)
+               ops = xchg(pending_ipis, 0);
+               if (ops == 0)
+-                      goto done;
++                      return;
+               if (ops & (1 << IPI_RESCHEDULE)) {
+                       stats[IPI_RESCHEDULE]++;
+@@ -189,10 +186,6 @@ void handle_IPI(struct pt_regs *regs)
+               /* Order data access and bit testing. */
+               mb();
+       }
+-
+-done:
+-      irq_exit();
+-      set_irq_regs(old_regs);
+ }
+ static const char * const ipi_names[] = {
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0012-5.16-irq-remove-handle_domain_-irq-nmi.patch b/target/linux/sunxid1/patches-5.15/0012-5.16-irq-remove-handle_domain_-irq-nmi.patch
new file mode 100644 (file)
index 0000000..e1a5052
--- /dev/null
@@ -0,0 +1,221 @@
+From 1c0b62a931ffc5ef35421dc8410dcf5213a135f0 Mon Sep 17 00:00:00 2001
+From: Mark Rutland <mark.rutland@arm.com>
+Date: Wed, 20 Oct 2021 20:23:09 +0100
+Subject: [PATCH 012/124] irq: remove handle_domain_{irq,nmi}()
+
+Now that entry code handles IRQ entry (including setting the IRQ regs)
+before calling irqchip code, irqchip code can safely call
+generic_handle_domain_irq(), and there's no functional reason for it to
+call handle_domain_irq().
+
+Let's cement this split of responsibility and remove handle_domain_irq()
+entirely, updating irqchip drivers to call generic_handle_domain_irq().
+
+For consistency, handle_domain_nmi() is similarly removed and replaced
+with a generic_handle_domain_nmi() function which also does not perform
+any entry logic.
+
+Previously handle_domain_{irq,nmi}() had a WARN_ON() which would fire
+when they were called in an inappropriate context. So that we can
+identify similar issues going forward, similar WARN_ON_ONCE() logic is
+added to the generic_handle_*() functions, and comments are updated for
+clarity and consistency.
+
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+---
+ arch/riscv/Kconfig               |  1 -
+ drivers/irqchip/irq-riscv-intc.c |  2 +-
+ drivers/irqchip/irq-sun4i.c      |  2 +-
+ include/linux/irqdesc.h          |  9 +----
+ kernel/irq/Kconfig               |  7 ----
+ kernel/irq/irqdesc.c             | 68 ++++++++------------------------
+ 6 files changed, 20 insertions(+), 69 deletions(-)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index f076cee11af6..c28b743eba57 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -62,7 +62,6 @@ config RISCV
+       select GENERIC_SCHED_CLOCK
+       select GENERIC_SMP_IDLE_THREAD
+       select GENERIC_TIME_VSYSCALL if MMU && 64BIT
+-      select HANDLE_DOMAIN_IRQ
+       select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
+       select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
+diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
+index 8017f6d32d52..b65bd8878d4f 100644
+--- a/drivers/irqchip/irq-riscv-intc.c
++++ b/drivers/irqchip/irq-riscv-intc.c
+@@ -37,7 +37,7 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs)
+               break;
+ #endif
+       default:
+-              handle_domain_irq(intc_domain, cause, regs);
++              generic_handle_domain_irq(intc_domain, cause);
+               break;
+       }
+ }
+diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
+index 8a315d6a3399..dd506ebfdacb 100644
+--- a/drivers/irqchip/irq-sun4i.c
++++ b/drivers/irqchip/irq-sun4i.c
+@@ -195,7 +195,7 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
+               return;
+       do {
+-              handle_domain_irq(irq_ic_data->irq_domain, hwirq, regs);
++              generic_handle_domain_irq(irq_ic_data->irq_domain, hwirq);
+               hwirq = readl(irq_ic_data->irq_base +
+                               SUN4I_IRQ_VECTOR_REG) >> 2;
+       } while (hwirq != 0);
+diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
+index 59aea39785bf..93d270ca0c56 100644
+--- a/include/linux/irqdesc.h
++++ b/include/linux/irqdesc.h
+@@ -168,14 +168,7 @@ int generic_handle_irq(unsigned int irq);
+  * conversion failed.
+  */
+ int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
+-
+-#ifdef CONFIG_HANDLE_DOMAIN_IRQ
+-int handle_domain_irq(struct irq_domain *domain,
+-                    unsigned int hwirq, struct pt_regs *regs);
+-
+-int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
+-                    struct pt_regs *regs);
+-#endif
++int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq);
+ #endif
+ /* Test to see if a driver has successfully requested an irq */
+diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
+index 897dfc552bb0..1b41078222f3 100644
+--- a/kernel/irq/Kconfig
++++ b/kernel/irq/Kconfig
+@@ -97,13 +97,6 @@ config GENERIC_MSI_IRQ_DOMAIN
+ config IRQ_MSI_IOMMU
+       bool
+-config HANDLE_DOMAIN_IRQ
+-      bool
+-
+-# Legacy behaviour; architectures should call irq_{enter,exit}() themselves
+-config HANDLE_DOMAIN_IRQ_IRQENTRY
+-      bool
+-
+ config IRQ_TIMINGS
+       bool
+diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
+index 7041698a7bff..2267e6527db3 100644
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -651,7 +651,11 @@ int handle_irq_desc(struct irq_desc *desc)
+  * generic_handle_irq - Invoke the handler for a particular irq
+  * @irq:      The irq number to handle
+  *
+- */
++ * Returns:   0 on success, or -EINVAL if conversion has failed
++ *
++ *            This function must be called from an IRQ context with irq regs
++ *            initialized.
++  */
+ int generic_handle_irq(unsigned int irq)
+ {
+       return handle_irq_desc(irq_to_desc(irq));
+@@ -661,77 +665,39 @@ EXPORT_SYMBOL_GPL(generic_handle_irq);
+ #ifdef CONFIG_IRQ_DOMAIN
+ /**
+  * generic_handle_domain_irq - Invoke the handler for a HW irq belonging
+- *                             to a domain, usually for a non-root interrupt
+- *                             controller
++ *                             to a domain.
+  * @domain:   The domain where to perform the lookup
+  * @hwirq:    The HW irq number to convert to a logical one
+  *
+  * Returns:   0 on success, or -EINVAL if conversion has failed
+  *
++ *            This function must be called from an IRQ context with irq regs
++ *            initialized.
+  */
+ int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
+ {
++      WARN_ON_ONCE(!in_irq());
+       return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
+ }
+ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
+-#ifdef CONFIG_HANDLE_DOMAIN_IRQ
+ /**
+- * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
+- *                     usually for a root interrupt controller
++ * generic_handle_domain_nmi - Invoke the handler for a HW nmi belonging
++ *                             to a domain.
+  * @domain:   The domain where to perform the lookup
+  * @hwirq:    The HW irq number to convert to a logical one
+- * @regs:     Register file coming from the low-level handling code
+- *
+- *            This function must be called from an IRQ context.
+  *
+  * Returns:   0 on success, or -EINVAL if conversion has failed
+- */
+-int handle_domain_irq(struct irq_domain *domain,
+-                    unsigned int hwirq, struct pt_regs *regs)
+-{
+-      struct pt_regs *old_regs = set_irq_regs(regs);
+-      int ret;
+-
+-      /*
+-       * IRQ context needs to be setup earlier.
+-       */
+-      WARN_ON(!in_irq());
+-
+-      ret = generic_handle_domain_irq(domain, hwirq);
+-
+-      set_irq_regs(old_regs);
+-      return ret;
+-}
+-
+-/**
+- * handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain
+- * @domain:   The domain where to perform the lookup
+- * @hwirq:    The HW irq number to convert to a logical one
+- * @regs:     Register file coming from the low-level handling code
+- *
+- *            This function must be called from an NMI context.
+  *
+- * Returns:   0 on success, or -EINVAL if conversion has failed
+- */
+-int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
+-                    struct pt_regs *regs)
++ *            This function must be called from an NMI context with irq regs
++ *            initialized.
++ **/
++int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)
+ {
+-      struct pt_regs *old_regs = set_irq_regs(regs);
+-      int ret;
+-
+-      /*
+-       * NMI context needs to be setup earlier in order to deal with tracing.
+-       */
+-      WARN_ON(!in_nmi());
+-
+-      ret = generic_handle_domain_irq(domain, hwirq);
+-
+-      set_irq_regs(old_regs);
+-      return ret;
++      WARN_ON_ONCE(!in_nmi());
++      return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
+ }
+ #endif
+-#endif
+ /* Dynamic interrupt handling */
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0013-5.16-soc-sunxi_sram-Make-use-of-the-helper-function-devm_.patch b/target/linux/sunxid1/patches-5.15/0013-5.16-soc-sunxi_sram-Make-use-of-the-helper-function-devm_.patch
new file mode 100644 (file)
index 0000000..3fcf4bb
--- /dev/null
@@ -0,0 +1,42 @@
+From cbb36ef09be83f9e0fdd97d33d28e90292860814 Mon Sep 17 00:00:00 2001
+From: Cai Huoqing <caihuoqing@baidu.com>
+Date: Wed, 8 Sep 2021 15:17:15 +0800
+Subject: [PATCH 013/124] soc: sunxi_sram: Make use of the helper function
+ devm_platform_ioremap_resource()
+
+Use the devm_platform_ioremap_resource() helper instead of
+calling platform_get_resource() and devm_ioremap_resource()
+separately
+
+Signed-off-by: Cai Huoqing <caihuoqing@baidu.com>
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+Link: https://lore.kernel.org/r/20210908071716.772-1-caihuoqing@baidu.com
+---
+ drivers/soc/sunxi/sunxi_sram.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index 42833e33a96c..a8f3876963a0 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -331,7 +331,6 @@ static struct regmap_config sunxi_sram_emac_clock_regmap = {
+ static int sunxi_sram_probe(struct platform_device *pdev)
+ {
+-      struct resource *res;
+       struct dentry *d;
+       struct regmap *emac_clock;
+       const struct sunxi_sramc_variant *variant;
+@@ -342,8 +341,7 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+       if (!variant)
+               return -EINVAL;
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      base = devm_ioremap_resource(&pdev->dev, res);
++      base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0014-input-sun4i-lradc-keys-Add-wakup-support.patch b/target/linux/sunxid1/patches-5.15/0014-input-sun4i-lradc-keys-Add-wakup-support.patch
new file mode 100644 (file)
index 0000000..3f2b09d
--- /dev/null
@@ -0,0 +1,74 @@
+From cacc7b781648cdcfe9866a0709143e05789b6555 Mon Sep 17 00:00:00 2001
+From: Ondrej Jirman <megous@megous.com>
+Date: Tue, 22 Oct 2019 00:15:41 +0200
+Subject: [PATCH 014/124] input: sun4i-lradc-keys - Add wakup support
+
+Allow the driver to wake the system on key press if the "wakeup-source"
+property is provided in the device tree. Using the LRADC as a wakeup
+source requires keeping the AVCC domain active during sleep. Since this
+has a nontrivial impact on power consumption (sometimes doubling it),
+disable the LRADC wakeup source by default.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Ondrej Jirman <megous@megous.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/input/keyboard/sun4i-lradc-keys.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
+index 4a796bed48ac..af1683d68c8c 100644
+--- a/drivers/input/keyboard/sun4i-lradc-keys.c
++++ b/drivers/input/keyboard/sun4i-lradc-keys.c
+@@ -22,6 +22,8 @@
+ #include <linux/module.h>
+ #include <linux/of_platform.h>
+ #include <linux/platform_device.h>
++#include <linux/pm_wakeirq.h>
++#include <linux/pm_wakeup.h>
+ #include <linux/regulator/consumer.h>
+ #include <linux/slab.h>
+@@ -226,8 +228,7 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
+ {
+       struct sun4i_lradc_data *lradc;
+       struct device *dev = &pdev->dev;
+-      int i;
+-      int error;
++      int error, i, irq;
+       lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
+       if (!lradc)
+@@ -272,8 +273,11 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
+       if (IS_ERR(lradc->base))
+               return PTR_ERR(lradc->base);
+-      error = devm_request_irq(dev, platform_get_irq(pdev, 0),
+-                               sun4i_lradc_irq, 0,
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return irq;
++
++      error = devm_request_irq(dev, irq, sun4i_lradc_irq, 0,
+                                "sun4i-a10-lradc-keys", lradc);
+       if (error)
+               return error;
+@@ -282,6 +286,14 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
+       if (error)
+               return error;
++      if (device_property_read_bool(dev, "wakeup-source")) {
++              device_set_wakeup_capable(dev, true);
++
++              error = dev_pm_set_wake_irq(dev, irq);
++              if (error)
++                      dev_warn(dev, "Failed to set wake IRQ\n");
++      }
++
+       return 0;
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0015-thermal-sun8i-Document-the-unknown-field.patch b/target/linux/sunxid1/patches-5.15/0015-thermal-sun8i-Document-the-unknown-field.patch
new file mode 100644 (file)
index 0000000..045c9c5
--- /dev/null
@@ -0,0 +1,63 @@
+From 9dec9d2aec1607dffe516c901d137adb0e8839e1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 10:04:52 -0500
+Subject: [PATCH 015/124] thermal: sun8i: Document the unknown field
+
+The H616 and newer user manuals document this field as the ADC
+acquisition time. Update the defintion and the timing calculations
+using the diagram in the manual.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/thermal/sun8i_thermal.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
+index d9cd23cbb671..f05e70e280dd 100644
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -50,7 +50,8 @@
+ #define SUN8I_THS_CTRL2_T_ACQ1(x)             ((GENMASK(15, 0) & (x)) << 16)
+ #define SUN8I_THS_DATA_IRQ_STS(x)             BIT(x + 8)
+-#define SUN50I_THS_CTRL0_T_ACQ(x)             ((GENMASK(15, 0) & (x)) << 16)
++#define SUN50I_THS_CTRL0_FS_DIV(x)            ((GENMASK(15, 0) & (x)) << 16)
++#define SUN50I_THS_CTRL0_T_ACQ(x)             (GENMASK(15, 0) & (x))
+ #define SUN50I_THS_FILTER_EN                  BIT(2)
+ #define SUN50I_THS_FILTER_TYPE(x)             (GENMASK(1, 0) & (x))
+ #define SUN50I_H6_THS_PC_TEMP_PERIOD(x)               ((GENMASK(19, 0) & (x)) << 12)
+@@ -417,25 +418,22 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev)
+       return 0;
+ }
+-/*
+- * Without this undocumented value, the returned temperatures would
+- * be higher than real ones by about 20C.
+- */
+-#define SUN50I_H6_CTRL0_UNK 0x0000002f
+-
+ static int sun50i_h6_thermal_init(struct ths_device *tmdev)
+ {
+       int val;
+       /*
+-       * T_acq = 20us
++       * T_sample = 20us > T_acq + T_conv
++       * T_acq = 2us
++       * T_conv = 14 cycles
+        * clkin = 24MHz
+        *
+-       * x = T_acq * clkin - 1
++       * x = T_sample * clkin - 1
+        *   = 479
+        */
+       regmap_write(tmdev->regmap, SUN50I_THS_CTRL0,
+-                   SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479));
++                   SUN50I_THS_CTRL0_FS_DIV(479) |
++                   SUN50I_THS_CTRL0_T_ACQ(47));
+       /* average over 4 samples */
+       regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC,
+                    SUN50I_THS_FILTER_EN |
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0016-thermal-sun8i-Set-the-event-type-for-new-samples.patch b/target/linux/sunxid1/patches-5.15/0016-thermal-sun8i-Set-the-event-type-for-new-samples.patch
new file mode 100644 (file)
index 0000000..c3a6a5b
--- /dev/null
@@ -0,0 +1,29 @@
+From 307dad7755974e3712d87b08972bff67ac9ce652 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 23 Jun 2021 19:29:37 -0500
+Subject: [PATCH 016/124] thermal: sun8i: Set the event type for new samples
+
+Currently, an IRQ is only configured to trigger when a new sample is
+available. So report this event type to the thermal core.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/thermal/sun8i_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
+index f05e70e280dd..ddd21ef4e3eb 100644
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -192,7 +192,7 @@ static irqreturn_t sun8i_irq_thread(int irq, void *data)
+       for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) {
+               thermal_zone_device_update(tmdev->sensor[i].tzd,
+-                                         THERMAL_EVENT_UNSPECIFIED);
++                                         THERMAL_EVENT_TEMP_SAMPLE);
+       }
+       return IRQ_HANDLED;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0017-thermal-sun8i-Use-optional-clock-reset-getters.patch b/target/linux/sunxid1/patches-5.15/0017-thermal-sun8i-Use-optional-clock-reset-getters.patch
new file mode 100644 (file)
index 0000000..405458b
--- /dev/null
@@ -0,0 +1,114 @@
+From 02ca2ba7daef709e1271dc5176c6efe7c635b15a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 23 Jun 2021 19:30:10 -0500
+Subject: [PATCH 017/124] thermal: sun8i: Use optional clock/reset getters
+
+The driver does not need to care about what variants have which clocks
+and resets; the devicetree binding already enforces that the necessary
+resources are provided. Simplify the logic by always calling the
+optional version of the getters, to pick up whatever references exist.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/thermal/sun8i_thermal.c | 34 +++++++++------------------------
+ 1 file changed, 9 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
+index ddd21ef4e3eb..be8064e89906 100644
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -66,8 +66,6 @@ struct tsensor {
+ };
+ struct ths_thermal_chip {
+-      bool            has_mod_clk;
+-      bool            has_bus_clk_reset;
+       int             sensor_num;
+       int             offset;
+       int             scale;
+@@ -335,21 +333,17 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
+       if (IS_ERR(tmdev->regmap))
+               return PTR_ERR(tmdev->regmap);
+-      if (tmdev->chip->has_bus_clk_reset) {
+-              tmdev->reset = devm_reset_control_get(dev, NULL);
+-              if (IS_ERR(tmdev->reset))
+-                      return PTR_ERR(tmdev->reset);
++      tmdev->reset = devm_reset_control_get_optional(dev, NULL);
++      if (IS_ERR(tmdev->reset))
++              return PTR_ERR(tmdev->reset);
+-              tmdev->bus_clk = devm_clk_get(&pdev->dev, "bus");
+-              if (IS_ERR(tmdev->bus_clk))
+-                      return PTR_ERR(tmdev->bus_clk);
+-      }
++      tmdev->bus_clk = devm_clk_get_optional(&pdev->dev, "bus");
++      if (IS_ERR(tmdev->bus_clk))
++              return PTR_ERR(tmdev->bus_clk);
+-      if (tmdev->chip->has_mod_clk) {
+-              tmdev->mod_clk = devm_clk_get(&pdev->dev, "mod");
+-              if (IS_ERR(tmdev->mod_clk))
+-                      return PTR_ERR(tmdev->mod_clk);
+-      }
++      tmdev->mod_clk = devm_clk_get_optional(&pdev->dev, "mod");
++      if (IS_ERR(tmdev->mod_clk))
++              return PTR_ERR(tmdev->mod_clk);
+       ret = reset_control_deassert(tmdev->reset);
+       if (ret)
+@@ -554,8 +548,6 @@ static const struct ths_thermal_chip sun8i_h3_ths = {
+       .sensor_num = 1,
+       .scale = 1211,
+       .offset = 217000,
+-      .has_mod_clk = true,
+-      .has_bus_clk_reset = true,
+       .temp_data_base = SUN8I_THS_TEMP_DATA,
+       .calibrate = sun8i_h3_ths_calibrate,
+       .init = sun8i_h3_thermal_init,
+@@ -567,8 +559,6 @@ static const struct ths_thermal_chip sun8i_r40_ths = {
+       .sensor_num = 2,
+       .offset = 251086,
+       .scale = 1130,
+-      .has_mod_clk = true,
+-      .has_bus_clk_reset = true,
+       .temp_data_base = SUN8I_THS_TEMP_DATA,
+       .calibrate = sun8i_h3_ths_calibrate,
+       .init = sun8i_h3_thermal_init,
+@@ -580,8 +570,6 @@ static const struct ths_thermal_chip sun50i_a64_ths = {
+       .sensor_num = 3,
+       .offset = 260890,
+       .scale = 1170,
+-      .has_mod_clk = true,
+-      .has_bus_clk_reset = true,
+       .temp_data_base = SUN8I_THS_TEMP_DATA,
+       .calibrate = sun8i_h3_ths_calibrate,
+       .init = sun8i_h3_thermal_init,
+@@ -591,7 +579,6 @@ static const struct ths_thermal_chip sun50i_a64_ths = {
+ static const struct ths_thermal_chip sun50i_a100_ths = {
+       .sensor_num = 3,
+-      .has_bus_clk_reset = true,
+       .ft_deviation = 8000,
+       .offset = 187744,
+       .scale = 672,
+@@ -604,8 +591,6 @@ static const struct ths_thermal_chip sun50i_a100_ths = {
+ static const struct ths_thermal_chip sun50i_h5_ths = {
+       .sensor_num = 2,
+-      .has_mod_clk = true,
+-      .has_bus_clk_reset = true,
+       .temp_data_base = SUN8I_THS_TEMP_DATA,
+       .calibrate = sun8i_h3_ths_calibrate,
+       .init = sun8i_h3_thermal_init,
+@@ -615,7 +600,6 @@ static const struct ths_thermal_chip sun50i_h5_ths = {
+ static const struct ths_thermal_chip sun50i_h6_ths = {
+       .sensor_num = 2,
+-      .has_bus_clk_reset = true,
+       .ft_deviation = 7000,
+       .offset = 187744,
+       .scale = 672,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0018-thermal-sun8i-Ensure-vref-is-powered.patch b/target/linux/sunxid1/patches-5.15/0018-thermal-sun8i-Ensure-vref-is-powered.patch
new file mode 100644 (file)
index 0000000..cfa5a61
--- /dev/null
@@ -0,0 +1,81 @@
+From 8bd42cf0216141eee71e303895a9e011f9951286 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 23 Jun 2021 20:17:46 -0500
+Subject: [PATCH 018/124] thermal: sun8i: Ensure vref is powered
+
+On some boards, the supply for the reference voltage (AVCC) is not
+always on. For the thermal sensor to work, that supply must be powered.
+So add the necessary regulator consumer.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/thermal/sun8i_thermal.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
+index be8064e89906..fa88fd91f997 100644
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -17,6 +17,7 @@
+ #include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
+ #include <linux/reset.h>
+ #include <linux/slab.h>
+ #include <linux/thermal.h>
+@@ -84,6 +85,7 @@ struct ths_device {
+       struct device                           *dev;
+       struct regmap                           *regmap;
+       struct reset_control                    *reset;
++      struct regulator                        *vref_supply;
+       struct clk                              *bus_clk;
+       struct clk                              *mod_clk;
+       struct tsensor                          sensor[MAX_SENSOR_NUM];
+@@ -333,6 +335,10 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
+       if (IS_ERR(tmdev->regmap))
+               return PTR_ERR(tmdev->regmap);
++      tmdev->vref_supply = devm_regulator_get(dev, "vref");
++      if (IS_ERR(tmdev->vref_supply))
++              return PTR_ERR(tmdev->vref_supply);
++
+       tmdev->reset = devm_reset_control_get_optional(dev, NULL);
+       if (IS_ERR(tmdev->reset))
+               return PTR_ERR(tmdev->reset);
+@@ -345,10 +351,14 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
+       if (IS_ERR(tmdev->mod_clk))
+               return PTR_ERR(tmdev->mod_clk);
+-      ret = reset_control_deassert(tmdev->reset);
++      ret = regulator_enable(tmdev->vref_supply);
+       if (ret)
+               return ret;
++      ret = reset_control_deassert(tmdev->reset);
++      if (ret)
++              goto disable_vref_supply;
++
+       ret = clk_prepare_enable(tmdev->bus_clk);
+       if (ret)
+               goto assert_reset;
+@@ -373,6 +383,8 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
+       clk_disable_unprepare(tmdev->bus_clk);
+ assert_reset:
+       reset_control_assert(tmdev->reset);
++disable_vref_supply:
++      regulator_disable(tmdev->vref_supply);
+       return ret;
+ }
+@@ -529,6 +541,7 @@ static int sun8i_ths_remove(struct platform_device *pdev)
+       clk_disable_unprepare(tmdev->mod_clk);
+       clk_disable_unprepare(tmdev->bus_clk);
+       reset_control_assert(tmdev->reset);
++      regulator_disable(tmdev->vref_supply);
+       return 0;
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0019-thermal-sun8i-Add-support-for-the-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0019-thermal-sun8i-Add-support-for-the-D1-variant.patch
new file mode 100644 (file)
index 0000000..d5a7767
--- /dev/null
@@ -0,0 +1,46 @@
+From 9e6cbc170439341082c5dfc36ac2d47a621152f2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 10:05:08 -0500
+Subject: [PATCH 019/124] thermal: sun8i: Add support for the D1 variant
+
+D1 has a thermal sensor block like other SoCs in the H6 generation.
+It has a single sensor channel and a unique temperature formula.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/thermal/sun8i_thermal.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
+index fa88fd91f997..1994e503bf15 100644
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -579,6 +579,17 @@ static const struct ths_thermal_chip sun8i_r40_ths = {
+       .calc_temp = sun8i_ths_calc_temp,
+ };
++static const struct ths_thermal_chip sun20i_d1_ths = {
++      .sensor_num = 1,
++      .offset = 188147,
++      .scale = 672,
++      .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
++      .calibrate = sun50i_h6_ths_calibrate,
++      .init = sun50i_h6_thermal_init,
++      .irq_ack = sun50i_h6_irq_ack,
++      .calc_temp = sun8i_ths_calc_temp,
++};
++
+ static const struct ths_thermal_chip sun50i_a64_ths = {
+       .sensor_num = 3,
+       .offset = 260890,
+@@ -627,6 +638,7 @@ static const struct of_device_id of_ths_match[] = {
+       { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
+       { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
+       { .compatible = "allwinner,sun8i-r40-ths", .data = &sun8i_r40_ths },
++      { .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths },
+       { .compatible = "allwinner,sun50i-a64-ths", .data = &sun50i_a64_ths },
+       { .compatible = "allwinner,sun50i-a100-ths", .data = &sun50i_a100_ths },
+       { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths },
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0020-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch b/target/linux/sunxid1/patches-5.15/0020-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch
new file mode 100644 (file)
index 0000000..59e455e
--- /dev/null
@@ -0,0 +1,35 @@
+From 617298fc711e9f5611dbfb44622cef4b330c66f0 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 13 Nov 2021 11:12:14 -0600
+Subject: [PATCH 020/124] ASoC: sun4i-spdif: Assert reset when removing the
+ device
+
+This completes reversing the process done in the probe function.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-spdif.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
+index a10949bf0ca1..ab42df6da8d8 100644
+--- a/sound/soc/sunxi/sun4i-spdif.c
++++ b/sound/soc/sunxi/sun4i-spdif.c
+@@ -589,10 +589,14 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
+ static int sun4i_spdif_remove(struct platform_device *pdev)
+ {
++      struct sun4i_spdif_dev *host = dev_get_drvdata(&pdev->dev);
++
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               sun4i_spdif_runtime_suspend(&pdev->dev);
++      reset_control_assert(host->rst);
++
+       return 0;
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0021-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch b/target/linux/sunxid1/patches-5.15/0021-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch
new file mode 100644 (file)
index 0000000..3b6711b
--- /dev/null
@@ -0,0 +1,83 @@
+From 5ca31032fb45e99ead74963601492fce57a261b6 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 13 Nov 2021 11:14:30 -0600
+Subject: [PATCH 021/124] ASoC: sun4i-spdif: Simplify code around optional
+ resets
+
+The driver does not need to care about which variants have a reset;
+the devicetree binding already enforces that the necessary resources are
+provided. Simplify the logic by always calling the optional getter,
+which will return NULL if no reset reference is found.
+
+Also clean up the error handling, which should not print a misleading
+error in the EPROBE_DEFER case.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-spdif.c | 22 ++++++----------------
+ 1 file changed, 6 insertions(+), 16 deletions(-)
+
+diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
+index ab42df6da8d8..a0255802be5f 100644
+--- a/sound/soc/sunxi/sun4i-spdif.c
++++ b/sound/soc/sunxi/sun4i-spdif.c
+@@ -168,12 +168,10 @@
+  * struct sun4i_spdif_quirks - Differences between SoC variants.
+  *
+  * @reg_dac_txdata: TX FIFO offset for DMA config.
+- * @has_reset: SoC needs reset deasserted.
+  * @val_fctl_ftx: TX FIFO flush bitmask.
+  */
+ struct sun4i_spdif_quirks {
+       unsigned int reg_dac_txdata;
+-      bool has_reset;
+       unsigned int val_fctl_ftx;
+ };
+@@ -432,19 +430,16 @@ static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
+ static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
+       .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
+-      .has_reset      = true,
+ };
+ static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
+       .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
+-      .has_reset      = true,
+ };
+ static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
+       .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
+-      .has_reset      = true,
+ };
+ static const struct of_device_id sun4i_spdif_of_match[] = {
+@@ -551,17 +546,12 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
+       platform_set_drvdata(pdev, host);
+-      if (quirks->has_reset) {
+-              host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
+-                                                                    NULL);
+-              if (PTR_ERR(host->rst) == -EPROBE_DEFER) {
+-                      ret = -EPROBE_DEFER;
+-                      dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
+-                      return ret;
+-              }
+-              if (!IS_ERR(host->rst))
+-                      reset_control_deassert(host->rst);
+-      }
++      host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
++      if (IS_ERR(host->rst))
++              return dev_err_probe(&pdev->dev, PTR_ERR(host->rst),
++                                   "Failed to get reset\n");
++
++      reset_control_deassert(host->rst);
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                               &sun4i_spdif_component, &sun4i_spdif_dai, 1);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0022-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch b/target/linux/sunxid1/patches-5.15/0022-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch
new file mode 100644 (file)
index 0000000..8ff9beb
--- /dev/null
@@ -0,0 +1,121 @@
+From 3153907498e377c97f0eb3026a87b6834e48b166 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:53:16 -0500
+Subject: [PATCH 022/124] ASoC: sun4i-spdif: Add support for separate RX/TX
+ clocks
+
+On older variants of the hardware, the RX and TX blocks share a single
+module clock, named "spdif" in the DT binding. The D1 variant has
+separate RX and TX clocks, so the TX module clock is named "tx" in the
+binding. To support this, supply the clock name in the quirks structure.
+
+Since the driver supports only TX, only the TX clock name is needed.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-spdif.c | 24 +++++++++++++++---------
+ 1 file changed, 15 insertions(+), 9 deletions(-)
+
+diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
+index a0255802be5f..748fb048a1f8 100644
+--- a/sound/soc/sunxi/sun4i-spdif.c
++++ b/sound/soc/sunxi/sun4i-spdif.c
+@@ -167,18 +167,20 @@
+ /**
+  * struct sun4i_spdif_quirks - Differences between SoC variants.
+  *
++ * @tx_clk_name: firmware name for the TX clock reference.
+  * @reg_dac_txdata: TX FIFO offset for DMA config.
+  * @val_fctl_ftx: TX FIFO flush bitmask.
+  */
+ struct sun4i_spdif_quirks {
++      const char *tx_clk_name;
+       unsigned int reg_dac_txdata;
+       unsigned int val_fctl_ftx;
+ };
+ struct sun4i_spdif_dev {
+       struct platform_device *pdev;
+-      struct clk *spdif_clk;
+       struct clk *apb_clk;
++      struct clk *tx_clk;
+       struct reset_control *rst;
+       struct snd_soc_dai_driver cpu_dai_drv;
+       struct regmap *regmap;
+@@ -310,7 +312,7 @@ static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
+               return -EINVAL;
+       }
+-      ret = clk_set_rate(host->spdif_clk, mclk);
++      ret = clk_set_rate(host->tx_clk, mclk);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "Setting SPDIF clock rate for %d Hz failed!\n", mclk);
+@@ -423,21 +425,25 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
+ };
+ static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
++      .tx_clk_name    = "spdif",
+       .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
+ };
+ static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
++      .tx_clk_name    = "spdif",
+       .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
+ };
+ static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
++      .tx_clk_name    = "spdif",
+       .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
+ };
+ static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
++      .tx_clk_name    = "spdif",
+       .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+       .val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
+ };
+@@ -471,7 +477,7 @@ static int sun4i_spdif_runtime_suspend(struct device *dev)
+ {
+       struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
+-      clk_disable_unprepare(host->spdif_clk);
++      clk_disable_unprepare(host->tx_clk);
+       clk_disable_unprepare(host->apb_clk);
+       return 0;
+@@ -482,12 +488,12 @@ static int sun4i_spdif_runtime_resume(struct device *dev)
+       struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
+       int ret;
+-      ret = clk_prepare_enable(host->spdif_clk);
++      ret = clk_prepare_enable(host->tx_clk);
+       if (ret)
+               return ret;
+       ret = clk_prepare_enable(host->apb_clk);
+       if (ret)
+-              clk_disable_unprepare(host->spdif_clk);
++              clk_disable_unprepare(host->tx_clk);
+       return ret;
+ }
+@@ -534,10 +540,10 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
+               return PTR_ERR(host->apb_clk);
+       }
+-      host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
+-      if (IS_ERR(host->spdif_clk)) {
+-              dev_err(&pdev->dev, "failed to get a spdif clock.\n");
+-              return PTR_ERR(host->spdif_clk);
++      host->tx_clk = devm_clk_get(&pdev->dev, quirks->tx_clk_name);
++      if (IS_ERR(host->tx_clk)) {
++              dev_err(&pdev->dev, "failed to get TX module clock.\n");
++              return PTR_ERR(host->tx_clk);
+       }
+       host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0023-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0023-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch
new file mode 100644 (file)
index 0000000..9f6f61e
--- /dev/null
@@ -0,0 +1,45 @@
+From 1fb53b6fb639f45d2ba4bf2a885e3fd5fbe95d8c Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:53:26 -0500
+Subject: [PATCH 023/124] ASoC: sun4i-spdif: Add support for the D1 variant
+
+The D1 variant is similar to the H6 variant, except for its clock setup.
+The clock tree changes impact some register fields on the RX side, but
+those are not yet relevant, because RX is not supported by this driver.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-spdif.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
+index 748fb048a1f8..7c6d596da84f 100644
+--- a/sound/soc/sunxi/sun4i-spdif.c
++++ b/sound/soc/sunxi/sun4i-spdif.c
+@@ -442,6 +442,12 @@ static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
+       .val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
+ };
++static const struct sun4i_spdif_quirks sun20i_d1_spdif_quirks = {
++      .tx_clk_name    = "tx",
++      .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
++      .val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
++};
++
+ static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
+       .tx_clk_name    = "spdif",
+       .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+@@ -461,6 +467,10 @@ static const struct of_device_id sun4i_spdif_of_match[] = {
+               .compatible = "allwinner,sun8i-h3-spdif",
+               .data = &sun8i_h3_spdif_quirks,
+       },
++      {
++              .compatible = "allwinner,sun20i-d1-spdif",
++              .data = &sun20i_d1_spdif_quirks,
++      },
+       {
+               .compatible = "allwinner,sun50i-h6-spdif",
+               .data = &sun50i_h6_spdif_quirks,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0024-nvmem-sunxi_sid-Add-support-for-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0024-nvmem-sunxi_sid-Add-support-for-D1-variant.patch
new file mode 100644 (file)
index 0000000..e0d6083
--- /dev/null
@@ -0,0 +1,40 @@
+From d69154525ee615f7f24b772658416f3a1093df23 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:43:20 -0500
+Subject: [PATCH 024/124] nvmem: sunxi_sid: Add support for D1 variant
+
+D1 has a smaller eFuse block than some other recent SoCs, and it no
+longer requires a workaround to read the eFuse data.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/nvmem/sunxi_sid.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
+index 275b9155e473..5750e1f4bcdb 100644
+--- a/drivers/nvmem/sunxi_sid.c
++++ b/drivers/nvmem/sunxi_sid.c
+@@ -184,6 +184,11 @@ static const struct sunxi_sid_cfg sun8i_h3_cfg = {
+       .need_register_readout = true,
+ };
++static const struct sunxi_sid_cfg sun20i_d1_cfg = {
++      .value_offset = 0x200,
++      .size = 0x100,
++};
++
+ static const struct sunxi_sid_cfg sun50i_a64_cfg = {
+       .value_offset = 0x200,
+       .size = 0x100,
+@@ -200,6 +205,7 @@ static const struct of_device_id sunxi_sid_of_match[] = {
+       { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
+       { .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg },
+       { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
++      { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg },
+       { .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg },
+       { .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg },
+       { .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg },
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0025-Input-sun4i-lradc-keys-Add-optional-clock-reset-supp.patch b/target/linux/sunxid1/patches-5.15/0025-Input-sun4i-lradc-keys-Add-optional-clock-reset-supp.patch
new file mode 100644 (file)
index 0000000..2a5a7f9
--- /dev/null
@@ -0,0 +1,101 @@
+From 92e9840b41f64e5f98bb846b8db061276898e791 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 09:30:39 -0500
+Subject: [PATCH 025/124] Input: sun4i-lradc-keys: Add optional clock/reset
+ support
+
+Until the R329, the LRADC hardware was always active. Now it requires
+enabling a clock gate and deasserting a reset line. Do this if the clock
+and reset are provided in the device tree, but keep them optional to
+maintain support for the existing binding.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/input/keyboard/sun4i-lradc-keys.c | 29 +++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
+index af1683d68c8c..cf8813d56208 100644
+--- a/drivers/input/keyboard/sun4i-lradc-keys.c
++++ b/drivers/input/keyboard/sun4i-lradc-keys.c
+@@ -14,6 +14,7 @@
+  * there are no boards known to use channel 1.
+  */
++#include <linux/clk.h>
+ #include <linux/err.h>
+ #include <linux/init.h>
+ #include <linux/input.h>
+@@ -25,6 +26,7 @@
+ #include <linux/pm_wakeirq.h>
+ #include <linux/pm_wakeup.h>
+ #include <linux/regulator/consumer.h>
++#include <linux/reset.h>
+ #include <linux/slab.h>
+ #define LRADC_CTRL            0x00
+@@ -85,6 +87,8 @@ struct sun4i_lradc_data {
+       struct device *dev;
+       struct input_dev *input;
+       void __iomem *base;
++      struct clk *clk;
++      struct reset_control *reset;
+       struct regulator *vref_supply;
+       struct sun4i_lradc_keymap *chan0_map;
+       const struct lradc_variant *variant;
+@@ -142,6 +146,14 @@ static int sun4i_lradc_open(struct input_dev *dev)
+       if (error)
+               return error;
++      error = reset_control_deassert(lradc->reset);
++      if (error)
++              goto err_disable_reg;
++
++      error = clk_prepare_enable(lradc->clk);
++      if (error)
++              goto err_assert_reset;
++
+       lradc->vref = regulator_get_voltage(lradc->vref_supply) *
+                     lradc->variant->divisor_numerator /
+                     lradc->variant->divisor_denominator;
+@@ -155,6 +167,13 @@ static int sun4i_lradc_open(struct input_dev *dev)
+       writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);
+       return 0;
++
++err_assert_reset:
++      reset_control_assert(lradc->reset);
++err_disable_reg:
++      regulator_disable(lradc->vref_supply);
++
++      return error;
+ }
+ static void sun4i_lradc_close(struct input_dev *dev)
+@@ -166,6 +185,8 @@ static void sun4i_lradc_close(struct input_dev *dev)
+               SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
+       writel(0, lradc->base + LRADC_INTC);
++      clk_disable_unprepare(lradc->clk);
++      reset_control_assert(lradc->reset);
+       regulator_disable(lradc->vref_supply);
+ }
+@@ -244,6 +265,14 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
+               return -EINVAL;
+       }
++      lradc->clk = devm_clk_get_optional(dev, NULL);
++      if (IS_ERR(lradc->clk))
++              return PTR_ERR(lradc->clk);
++
++      lradc->reset = devm_reset_control_get_optional_exclusive(dev, NULL);
++      if (IS_ERR(lradc->reset))
++              return PTR_ERR(lradc->reset);
++
+       lradc->vref_supply = devm_regulator_get(dev, "vref");
+       if (IS_ERR(lradc->vref_supply))
+               return PTR_ERR(lradc->vref_supply);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0026-Input-sun4i-lradc-keys-Add-support-for-R329-and-D1.patch b/target/linux/sunxid1/patches-5.15/0026-Input-sun4i-lradc-keys-Add-support-for-R329-and-D1.patch
new file mode 100644 (file)
index 0000000..d8ccdb4
--- /dev/null
@@ -0,0 +1,30 @@
+From a592f18da0fa6a1cdcc3b06302c78d0b32f20d62 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 09:31:10 -0500
+Subject: [PATCH 026/124] Input: sun4i-lradc-keys: Add support for R329 and D1
+
+This LRADC variant uses the same 3/4*AVCC reference voltage as the A83T
+variant. The R329 and D1 LRADCs appear to be identical, so D1 support is
+accomplished through having the R329 LRADC as a fallback compatible.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/input/keyboard/sun4i-lradc-keys.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
+index cf8813d56208..bec53c7a89b1 100644
+--- a/drivers/input/keyboard/sun4i-lradc-keys.c
++++ b/drivers/input/keyboard/sun4i-lradc-keys.c
+@@ -331,6 +331,8 @@ static const struct of_device_id sun4i_lradc_of_match[] = {
+               .data = &lradc_variant_a10 },
+       { .compatible = "allwinner,sun8i-a83t-r-lradc",
+               .data = &r_lradc_variant_a83t },
++      { .compatible = "allwinner,sun50i-r329-lradc",
++              .data = &r_lradc_variant_a83t },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0027-leds-sunxi-New-driver-for-the-R329-D1-LED-controller.patch b/target/linux/sunxid1/patches-5.15/0027-leds-sunxi-New-driver-for-the-R329-D1-LED-controller.patch
new file mode 100644 (file)
index 0000000..ae667e6
--- /dev/null
@@ -0,0 +1,611 @@
+From 929bb1c60474dc25b8c8f2d855ee704e16fe97b9 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 26 Jun 2021 11:02:49 -0500
+Subject: [PATCH 027/124] leds: sunxi: New driver for the R329/D1 LED
+ controller
+
+Some Allwinner sunxi SoCs, starting with the R329, contain an LED
+controller designed to drive RGB LED pixels. Add a driver for it using
+the multicolor LED framework, and with LEDs defined in the device tree.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/leds/Kconfig            |   8 +
+ drivers/leds/Makefile           |   1 +
+ drivers/leds/leds-sun50i-r329.c | 553 ++++++++++++++++++++++++++++++++
+ 3 files changed, 562 insertions(+)
+ create mode 100644 drivers/leds/leds-sun50i-r329.c
+
+diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
+index ed800f5da7d8..d5c1396788fe 100644
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -297,6 +297,14 @@ config LEDS_SUNFIRE
+         This option enables support for the Left, Middle, and Right
+         LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
++config LEDS_SUN50I_R329
++      tristate "LED support for Allwinner R329 LED controller"
++      depends on LEDS_CLASS
++      depends on ARCH_SUNXI || COMPILE_TEST
++      help
++        This option enables support for the RGB LED controller
++        provided in some Allwinner sunxi SoCs, like the R329.
++
+ config LEDS_IPAQ_MICRO
+       tristate "LED Support for the Compaq iPAQ h3xxx"
+       depends on LEDS_CLASS
+diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
+index c636ec069612..506b2617099d 100644
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -77,6 +77,7 @@ obj-$(CONFIG_LEDS_PWM)                       += leds-pwm.o
+ obj-$(CONFIG_LEDS_REGULATOR)          += leds-regulator.o
+ obj-$(CONFIG_LEDS_S3C24XX)            += leds-s3c24xx.o
+ obj-$(CONFIG_LEDS_SC27XX_BLTC)                += leds-sc27xx-bltc.o
++obj-$(CONFIG_LEDS_SUN50I_R329)                += leds-sun50i-r329.o
+ obj-$(CONFIG_LEDS_SUNFIRE)            += leds-sunfire.o
+ obj-$(CONFIG_LEDS_SYSCON)             += leds-syscon.o
+ obj-$(CONFIG_LEDS_TCA6507)            += leds-tca6507.o
+diff --git a/drivers/leds/leds-sun50i-r329.c b/drivers/leds/leds-sun50i-r329.c
+new file mode 100644
+index 000000000000..ada6625e2bbc
+--- /dev/null
++++ b/drivers/leds/leds-sun50i-r329.c
+@@ -0,0 +1,553 @@
++// SPDX-License-Identifier: GPL-2.0
++//
++// Copyright (c) 2021 Samuel Holland <samuel@sholland.org>
++//
++// Partly based on drivers/leds/leds-turris-omnia.c, which is:
++//     Copyright (c) 2020 by Marek Behún <kabel@kernel.org>
++//
++
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/led-class-multicolor.h>
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/reset.h>
++#include <linux/spinlock.h>
++
++#define LEDC_CTRL_REG                 0x0000
++#define LEDC_CTRL_REG_DATA_LENGTH             (0x1fff << 16)
++#define LEDC_CTRL_REG_RGB_MODE                        (0x7 << 6)
++#define LEDC_CTRL_REG_LEDC_EN                 BIT(0)
++#define LEDC_T01_TIMING_CTRL_REG      0x0004
++#define LEDC_T01_TIMING_CTRL_REG_T1H          (0x3f << 21)
++#define LEDC_T01_TIMING_CTRL_REG_T1L          (0x1f << 16)
++#define LEDC_T01_TIMING_CTRL_REG_T0H          (0x1f << 6)
++#define LEDC_T01_TIMING_CTRL_REG_T0L          (0x3f << 0)
++#define LEDC_RESET_TIMING_CTRL_REG    0x000c
++#define LEDC_RESET_TIMING_CTRL_REG_LED_NUM    (0x3ff << 0)
++#define LEDC_DATA_REG                 0x0014
++#define LEDC_DMA_CTRL_REG             0x0018
++#define LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL     (0x1f << 0)
++#define LEDC_INT_CTRL_REG             0x001c
++#define LEDC_INT_CTRL_REG_GLOBAL_INT_EN               BIT(5)
++#define LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN  BIT(1)
++#define LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN BIT(0)
++#define LEDC_INT_STS_REG              0x0020
++#define LEDC_INT_STS_REG_FIFO_CPUREQ_INT      BIT(1)
++#define LEDC_INT_STS_REG_TRANS_FINISH_INT     BIT(0)
++
++#define LEDC_FIFO_DEPTH                       32
++#define LEDC_MAX_LEDS                 1024
++
++#define LEDS_TO_BYTES(n)              ((n) * sizeof(u32))
++
++struct sun50i_r329_ledc_led {
++      struct led_classdev_mc mc_cdev;
++      struct mc_subled subled_info[3];
++};
++#define to_ledc_led(mc) container_of(mc, struct sun50i_r329_ledc_led, mc_cdev)
++
++struct sun50i_r329_ledc_timing {
++      u32 t0h_ns;
++      u32 t0l_ns;
++      u32 t1h_ns;
++      u32 t1l_ns;
++      u32 treset_ns;
++};
++
++struct sun50i_r329_ledc {
++      struct device *dev;
++      void __iomem *base;
++      struct clk *bus_clk;
++      struct clk *mod_clk;
++      struct reset_control *reset;
++
++      u32 *buffer;
++      struct dma_chan *dma_chan;
++      dma_addr_t dma_handle;
++      int pio_length;
++      int pio_offset;
++
++      spinlock_t lock;
++      int next_length;
++      bool xfer_active;
++
++      u32 format;
++      struct sun50i_r329_ledc_timing timing;
++
++      int num_leds;
++      struct sun50i_r329_ledc_led leds[];
++};
++
++static int sun50i_r329_ledc_dma_xfer(struct sun50i_r329_ledc *priv, int length)
++{
++      struct dma_async_tx_descriptor *desc;
++      dma_cookie_t cookie;
++
++      desc = dmaengine_prep_slave_single(priv->dma_chan, priv->dma_handle,
++                                         LEDS_TO_BYTES(length),
++                                         DMA_MEM_TO_DEV, 0);
++      if (!desc)
++              return -ENOMEM;
++
++      cookie = dmaengine_submit(desc);
++      if (dma_submit_error(cookie))
++              return -EIO;
++
++      dma_async_issue_pending(priv->dma_chan);
++
++      return 0;
++}
++
++static void sun50i_r329_ledc_pio_xfer(struct sun50i_r329_ledc *priv, int length)
++{
++      u32 burst, offset, val;
++
++      if (length) {
++              /* New transfer (FIFO is empty). */
++              offset = 0;
++              burst  = min(length, LEDC_FIFO_DEPTH);
++      } else {
++              /* Existing transfer (FIFO is half-full). */
++              length = priv->pio_length;
++              offset = priv->pio_offset;
++              burst  = min(length, LEDC_FIFO_DEPTH / 2);
++      }
++
++      iowrite32_rep(priv->base + LEDC_DATA_REG, priv->buffer + offset, burst);
++
++      if (burst < length) {
++              priv->pio_length = length - burst;
++              priv->pio_offset = offset + burst;
++
++              if (!offset) {
++                      val = readl(priv->base + LEDC_INT_CTRL_REG);
++                      val |= LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN;
++                      writel(val, priv->base + LEDC_INT_CTRL_REG);
++              }
++      } else {
++              /* Disable the request IRQ once all data is written. */
++              val = readl(priv->base + LEDC_INT_CTRL_REG);
++              val &= ~LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN;
++              writel(val, priv->base + LEDC_INT_CTRL_REG);
++      }
++}
++
++static void sun50i_r329_ledc_start_xfer(struct sun50i_r329_ledc *priv,
++                                      int length)
++{
++      u32 val;
++
++      dev_dbg(priv->dev, "Updating %d LEDs\n", length);
++
++      val = readl(priv->base + LEDC_CTRL_REG);
++      val &= ~LEDC_CTRL_REG_DATA_LENGTH;
++      val |= length << 16 | LEDC_CTRL_REG_LEDC_EN;
++      writel(val, priv->base + LEDC_CTRL_REG);
++
++      if (length > LEDC_FIFO_DEPTH) {
++              int ret = sun50i_r329_ledc_dma_xfer(priv, length);
++
++              if (!ret)
++                      return;
++
++              dev_warn(priv->dev, "Failed to set up DMA: %d\n", ret);
++      }
++
++      sun50i_r329_ledc_pio_xfer(priv, length);
++}
++
++static irqreturn_t sun50i_r329_ledc_irq(int irq, void *dev_id)
++{
++      struct sun50i_r329_ledc *priv = dev_id;
++      u32 val;
++
++      val = readl(priv->base + LEDC_INT_STS_REG);
++
++      if (val & LEDC_INT_STS_REG_TRANS_FINISH_INT) {
++              int next_length;
++
++              /* Start the next transfer if needed. */
++              spin_lock(&priv->lock);
++              next_length = priv->next_length;
++              if (next_length)
++                      priv->next_length = 0;
++              else
++                      priv->xfer_active = false;
++              spin_unlock(&priv->lock);
++
++              if (next_length)
++                      sun50i_r329_ledc_start_xfer(priv, next_length);
++      } else if (val & LEDC_INT_STS_REG_FIFO_CPUREQ_INT) {
++              /* Continue the current transfer. */
++              sun50i_r329_ledc_pio_xfer(priv, 0);
++      }
++
++      writel(val, priv->base + LEDC_INT_STS_REG);
++
++      return IRQ_HANDLED;
++}
++
++static void sun50i_r329_ledc_brightness_set(struct led_classdev *cdev,
++                                          enum led_brightness brightness)
++{
++      struct sun50i_r329_ledc *priv = dev_get_drvdata(cdev->dev->parent);
++      struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
++      struct sun50i_r329_ledc_led *led = to_ledc_led(mc_cdev);
++      int addr = led - priv->leds;
++      unsigned long flags;
++      bool xfer_active;
++      int next_length;
++
++      led_mc_calc_color_components(mc_cdev, brightness);
++
++      priv->buffer[addr] = led->subled_info[0].brightness << 16 |
++                           led->subled_info[1].brightness <<  8 |
++                           led->subled_info[2].brightness;
++
++      dev_dbg(priv->dev, "LED %d -> #%06x\n", addr, priv->buffer[addr]);
++
++      spin_lock_irqsave(&priv->lock, flags);
++      next_length = max(priv->next_length, addr + 1);
++      xfer_active = priv->xfer_active;
++      if (xfer_active)
++              priv->next_length = next_length;
++      else
++              priv->xfer_active = true;
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      if (!xfer_active)
++              sun50i_r329_ledc_start_xfer(priv, next_length);
++}
++
++static const char *const sun50i_r329_ledc_formats[] = {
++      "rgb",
++      "rbg",
++      "grb",
++      "gbr",
++      "brg",
++      "bgr",
++};
++
++static int sun50i_r329_ledc_parse_format(const struct device_node *np,
++                                       struct sun50i_r329_ledc *priv)
++{
++      const char *format = "grb";
++      u32 i;
++
++      of_property_read_string(np, "allwinner,pixel-format", &format);
++
++      for (i = 0; i < ARRAY_SIZE(sun50i_r329_ledc_formats); ++i) {
++              if (!strcmp(format, sun50i_r329_ledc_formats[i])) {
++                      priv->format = i;
++                      return 0;
++              }
++      }
++
++      dev_err(priv->dev, "Bad pixel format '%s'\n", format);
++
++      return -EINVAL;
++}
++
++static void sun50i_r329_ledc_set_format(struct sun50i_r329_ledc *priv)
++{
++      u32 val;
++
++      val = readl(priv->base + LEDC_CTRL_REG);
++      val &= ~LEDC_CTRL_REG_RGB_MODE;
++      val |= priv->format << 6;
++      writel(val, priv->base + LEDC_CTRL_REG);
++}
++
++static const struct sun50i_r329_ledc_timing sun50i_r329_ledc_default_timing = {
++      .t0h_ns = 336,
++      .t0l_ns = 840,
++      .t1h_ns = 882,
++      .t1l_ns = 294,
++      .treset_ns = 300000,
++};
++
++static int sun50i_r329_ledc_parse_timing(const struct device_node *np,
++                                       struct sun50i_r329_ledc *priv)
++{
++      struct sun50i_r329_ledc_timing *timing = &priv->timing;
++
++      *timing = sun50i_r329_ledc_default_timing;
++
++      of_property_read_u32(np, "allwinner,t0h-ns", &timing->t0h_ns);
++      of_property_read_u32(np, "allwinner,t0l-ns", &timing->t0l_ns);
++      of_property_read_u32(np, "allwinner,t1h-ns", &timing->t1h_ns);
++      of_property_read_u32(np, "allwinner,t1l-ns", &timing->t1l_ns);
++      of_property_read_u32(np, "allwinner,treset-ns", &timing->treset_ns);
++
++      return 0;
++}
++
++static void sun50i_r329_ledc_set_timing(struct sun50i_r329_ledc *priv)
++{
++      const struct sun50i_r329_ledc_timing *timing = &priv->timing;
++      unsigned long mod_freq = clk_get_rate(priv->mod_clk);
++      u32 cycle_ns = NSEC_PER_SEC / mod_freq;
++      u32 val;
++
++      val = (timing->t1h_ns / cycle_ns) << 21 |
++            (timing->t1l_ns / cycle_ns) << 16 |
++            (timing->t0h_ns / cycle_ns) <<  6 |
++            (timing->t0l_ns / cycle_ns);
++      writel(val, priv->base + LEDC_T01_TIMING_CTRL_REG);
++
++      val = (timing->treset_ns / cycle_ns) << 16 |
++            (priv->num_leds - 1);
++      writel(val, priv->base + LEDC_RESET_TIMING_CTRL_REG);
++}
++
++static int sun50i_r329_ledc_resume(struct device *dev)
++{
++      struct sun50i_r329_ledc *priv = dev_get_drvdata(dev);
++      u32 val;
++      int ret;
++
++      ret = reset_control_deassert(priv->reset);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(priv->bus_clk);
++      if (ret)
++              goto err_assert_reset;
++
++      ret = clk_prepare_enable(priv->mod_clk);
++      if (ret)
++              goto err_disable_bus_clk;
++
++      sun50i_r329_ledc_set_format(priv);
++      sun50i_r329_ledc_set_timing(priv);
++
++      /* The trigger level must be at least the burst length. */
++      val = readl(priv->base + LEDC_DMA_CTRL_REG);
++      val &= ~LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL;
++      val |= LEDC_FIFO_DEPTH / 2;
++      writel(val, priv->base + LEDC_DMA_CTRL_REG);
++
++      val = LEDC_INT_CTRL_REG_GLOBAL_INT_EN |
++            LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN;
++      writel(val, priv->base + LEDC_INT_CTRL_REG);
++
++      return 0;
++
++err_disable_bus_clk:
++      clk_disable_unprepare(priv->bus_clk);
++err_assert_reset:
++      reset_control_assert(priv->reset);
++
++      return ret;
++}
++
++static int sun50i_r329_ledc_suspend(struct device *dev)
++{
++      struct sun50i_r329_ledc *priv = dev_get_drvdata(dev);
++
++      clk_disable_unprepare(priv->mod_clk);
++      clk_disable_unprepare(priv->bus_clk);
++      reset_control_assert(priv->reset);
++
++      return 0;
++}
++
++static void sun50i_r329_ledc_dma_cleanup(void *data)
++{
++      struct sun50i_r329_ledc *priv = data;
++      struct device *dma_dev = dmaengine_get_dma_device(priv->dma_chan);
++
++      if (priv->buffer)
++              dma_free_wc(dma_dev, LEDS_TO_BYTES(priv->num_leds),
++                          priv->buffer, priv->dma_handle);
++      dma_release_channel(priv->dma_chan);
++}
++
++static int sun50i_r329_ledc_probe(struct platform_device *pdev)
++{
++      const struct device_node *np = pdev->dev.of_node;
++      struct dma_slave_config dma_cfg = {};
++      struct led_init_data init_data = {};
++      struct device *dev = &pdev->dev;
++      struct device_node *child;
++      struct sun50i_r329_ledc *priv;
++      struct resource *mem;
++      int count, irq, ret;
++
++      count = of_get_available_child_count(np);
++      if (!count)
++              return -ENODEV;
++      if (count > LEDC_MAX_LEDS) {
++              dev_err(dev, "Too many LEDs! (max is %d)\n", LEDC_MAX_LEDS);
++              return -EINVAL;
++      }
++
++      priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      priv->dev = dev;
++      priv->num_leds = count;
++      spin_lock_init(&priv->lock);
++      dev_set_drvdata(dev, priv);
++
++      ret = sun50i_r329_ledc_parse_format(np, priv);
++      if (ret)
++              return ret;
++
++      ret = sun50i_r329_ledc_parse_timing(np, priv);
++      if (ret)
++              return ret;
++
++      priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
++      if (IS_ERR(priv->base))
++              return PTR_ERR(priv->base);
++
++      priv->bus_clk = devm_clk_get(dev, "bus");
++      if (IS_ERR(priv->bus_clk))
++              return PTR_ERR(priv->bus_clk);
++
++      priv->mod_clk = devm_clk_get(dev, "mod");
++      if (IS_ERR(priv->mod_clk))
++              return PTR_ERR(priv->mod_clk);
++
++      priv->reset = devm_reset_control_get_exclusive(dev, NULL);
++      if (IS_ERR(priv->reset))
++              return PTR_ERR(priv->reset);
++
++      priv->dma_chan = dma_request_chan(dev, "tx");
++      if (IS_ERR(priv->dma_chan))
++              return PTR_ERR(priv->dma_chan);
++
++      ret = devm_add_action_or_reset(dev, sun50i_r329_ledc_dma_cleanup, priv);
++      if (ret)
++              return ret;
++
++      dma_cfg.dst_addr        = mem->start + LEDC_DATA_REG;
++      dma_cfg.dst_addr_width  = DMA_SLAVE_BUSWIDTH_4_BYTES;
++      dma_cfg.dst_maxburst    = LEDC_FIFO_DEPTH / 2;
++      ret = dmaengine_slave_config(priv->dma_chan, &dma_cfg);
++      if (ret)
++              return ret;
++
++      priv->buffer = dma_alloc_wc(dmaengine_get_dma_device(priv->dma_chan),
++                                  LEDS_TO_BYTES(priv->num_leds),
++                                  &priv->dma_handle, GFP_KERNEL);
++      if (!priv->buffer)
++              return -ENOMEM;
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return irq;
++
++      ret = devm_request_irq(dev, irq, sun50i_r329_ledc_irq,
++                             0, dev_name(dev), priv);
++      if (ret)
++              return ret;
++
++      ret = sun50i_r329_ledc_resume(dev);
++      if (ret)
++              return ret;
++
++      for_each_available_child_of_node(np, child) {
++              struct sun50i_r329_ledc_led *led;
++              struct led_classdev *cdev;
++              u32 addr, color;
++
++              ret = of_property_read_u32(child, "reg", &addr);
++              if (ret || addr >= count) {
++                      dev_err(dev, "LED 'reg' values must be from 0 to %d\n",
++                              priv->num_leds - 1);
++                      ret = -EINVAL;
++                      goto err_put_child;
++              }
++
++              ret = of_property_read_u32(child, "color", &color);
++              if (ret || color != LED_COLOR_ID_RGB) {
++                      dev_err(dev, "LED 'color' must be LED_COLOR_ID_RGB\n");
++                      ret = -EINVAL;
++                      goto err_put_child;
++              }
++
++              led = &priv->leds[addr];
++
++              led->subled_info[0].color_index = LED_COLOR_ID_RED;
++              led->subled_info[0].channel = 0;
++              led->subled_info[1].color_index = LED_COLOR_ID_GREEN;
++              led->subled_info[1].channel = 1;
++              led->subled_info[2].color_index = LED_COLOR_ID_BLUE;
++              led->subled_info[2].channel = 2;
++
++              led->mc_cdev.num_colors = ARRAY_SIZE(led->subled_info);
++              led->mc_cdev.subled_info = led->subled_info;
++
++              cdev = &led->mc_cdev.led_cdev;
++              cdev->max_brightness = U8_MAX;
++              cdev->brightness_set = sun50i_r329_ledc_brightness_set;
++
++              init_data.fwnode = of_fwnode_handle(child);
++
++              ret = devm_led_classdev_multicolor_register_ext(dev,
++                                                              &led->mc_cdev,
++                                                              &init_data);
++              if (ret) {
++                      dev_err(dev, "Failed to register LED %u: %d\n",
++                              addr, ret);
++                      goto err_put_child;
++              }
++      }
++
++      dev_info(dev, "Registered %d LEDs\n", priv->num_leds);
++
++      return 0;
++
++err_put_child:
++      of_node_put(child);
++      sun50i_r329_ledc_suspend(&pdev->dev);
++
++      return ret;
++}
++
++static int sun50i_r329_ledc_remove(struct platform_device *pdev)
++{
++      sun50i_r329_ledc_suspend(&pdev->dev);
++
++      return 0;
++}
++
++static void sun50i_r329_ledc_shutdown(struct platform_device *pdev)
++{
++      sun50i_r329_ledc_suspend(&pdev->dev);
++}
++
++static const struct of_device_id sun50i_r329_ledc_of_match[] = {
++      { .compatible = "allwinner,sun50i-r329-ledc" },
++      {}
++};
++MODULE_DEVICE_TABLE(of, sun50i_r329_ledc_of_match);
++
++static SIMPLE_DEV_PM_OPS(sun50i_r329_ledc_pm,
++                       sun50i_r329_ledc_suspend, sun50i_r329_ledc_resume);
++
++static struct platform_driver sun50i_r329_ledc_driver = {
++      .probe          = sun50i_r329_ledc_probe,
++      .remove         = sun50i_r329_ledc_remove,
++      .shutdown       = sun50i_r329_ledc_shutdown,
++      .driver         = {
++              .name           = "sun50i-r329-ledc",
++              .of_match_table = sun50i_r329_ledc_of_match,
++              .pm             = pm_ptr(&sun50i_r329_ledc_pm),
++      },
++};
++module_platform_driver(sun50i_r329_ledc_driver);
++
++MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
++MODULE_DESCRIPTION("Allwinner R329 LED controller driver");
++MODULE_LICENSE("GPL");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0028-ASoC-sun4i-i2s-Update-registers-for-more-channels.patch b/target/linux/sunxid1/patches-5.15/0028-ASoC-sun4i-i2s-Update-registers-for-more-channels.patch
new file mode 100644 (file)
index 0000000..e8ec6a5
--- /dev/null
@@ -0,0 +1,99 @@
+From 8a568791d2dcb2f81df3e0664418dddc71d42500 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:50:41 -0500
+Subject: [PATCH 028/124] ASoC: sun4i-i2s: Update registers for more channels
+
+H6 expands the number of channels in each direction to 16, so the slot
+number fields need to be expanded from 3 to 4 bits each.
+
+R329/D1 expand that further by allowing each of the 16 slots to map to
+any of 4 data pins. For TX, the configuration of each pin is
+independent, so there is a copy of the mapping registers for each pin.
+For RX, each of the 16 slots can map to only one pin, so the registers
+were changed to add the pin selection inline with the channel mapping.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-i2s.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
+index 1e9116cd365e..7da8a16955a1 100644
+--- a/sound/soc/sunxi/sun4i-i2s.c
++++ b/sound/soc/sunxi/sun4i-i2s.c
+@@ -115,9 +115,9 @@
+ #define SUN8I_I2S_FIFO_TX_REG         0x20
+ #define SUN8I_I2S_CHAN_CFG_REG                0x30
+-#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK   GENMASK(6, 4)
++#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK   GENMASK(7, 4)
+ #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)  ((chan - 1) << 4)
+-#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK   GENMASK(2, 0)
++#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK   GENMASK(3, 0)
+ #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)  (chan - 1)
+ #define SUN8I_I2S_TX_CHAN_MAP_REG     0x44
+@@ -138,13 +138,19 @@
+ #define SUN50I_H6_I2S_TX_CHAN_EN_MASK         GENMASK(15, 0)
+ #define SUN50I_H6_I2S_TX_CHAN_EN(num_chan)    (((1 << num_chan) - 1))
+-#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG        0x44
+-#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG        0x48
++#define SUN50I_H6_I2S_TX_CHAN_SEL_REG(pin)    (0x34 + 4 * (pin))
++#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(pin)   (0x44 + 8 * (pin))
++#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(pin)   (0x48 + 8 * (pin))
+ #define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64
+ #define SUN50I_H6_I2S_RX_CHAN_MAP0_REG        0x68
+ #define SUN50I_H6_I2S_RX_CHAN_MAP1_REG        0x6C
++#define SUN50I_R329_I2S_RX_CHAN_MAP0_REG 0x68
++#define SUN50I_R329_I2S_RX_CHAN_MAP1_REG 0x6c
++#define SUN50I_R329_I2S_RX_CHAN_MAP2_REG 0x70
++#define SUN50I_R329_I2S_RX_CHAN_MAP3_REG 0x74
++
+ struct sun4i_i2s;
+ /**
+@@ -523,13 +529,13 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+       unsigned int lrck_period;
+       /* Map the channels for playback and capture */
+-      regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98);
+-      regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210);
++      regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98);
++      regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210);
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
+       /* Configure the channels */
+-      regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
++      regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),
+                          SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+       regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+@@ -563,7 +569,7 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+                          SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+                          SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
+-      regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
++      regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),
+                          SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_EN(channels));
+@@ -1210,9 +1216,9 @@ static const struct reg_default sun50i_h6_i2s_reg_defaults[] = {
+       { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
+       { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
+       { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
+-      { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
+-      { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
+-      { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
++      { SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 0x00000000 },
++      { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 },
++      { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x00000000 },
+       { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
+       { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
+       { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0029-ASoC-sun4i-i2s-Add-support-for-the-R329-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0029-ASoC-sun4i-i2s-Add-support-for-the-R329-D1-variant.patch
new file mode 100644 (file)
index 0000000..a905037
--- /dev/null
@@ -0,0 +1,98 @@
+From 8da658ca3f0aa0b4727333d544518bf985c72e8f Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:51:37 -0500
+Subject: [PATCH 029/124] ASoC: sun4i-i2s: Add support for the R329/D1 variant
+
+This adds a new set of quirks to set the right RX channel map. Since
+that is the only change to the register layout, reuse the H6 regmap
+config by extending its last register. R329 support is added by its
+compatible string. D1 uses R329 as its fallback compatible, so no
+additional code change is needed for it.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++++---
+ 1 file changed, 37 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
+index 7da8a16955a1..7047f71629ab 100644
+--- a/sound/soc/sunxi/sun4i-i2s.c
++++ b/sound/soc/sunxi/sun4i-i2s.c
+@@ -181,6 +181,9 @@ struct sun4i_i2s_quirks {
+       struct reg_field                field_fmt_wss;
+       struct reg_field                field_fmt_sr;
++      unsigned int                    num_din_pins;
++      unsigned int                    num_dout_pins;
++
+       const struct sun4i_i2s_clk_div  *bclk_dividers;
+       unsigned int                    num_bclk_dividers;
+       const struct sun4i_i2s_clk_div  *mclk_dividers;
+@@ -531,8 +534,15 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+       /* Map the channels for playback and capture */
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98);
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210);
+-      regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
+-      regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
++      if (i2s->variant->num_din_pins > 1) {
++              regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP0_REG, 0x0F0E0D0C);
++              regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP1_REG, 0x0B0A0908);
++              regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP2_REG, 0x07060504);
++              regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP3_REG, 0x03020100);
++      } else {
++              regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
++              regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
++      }
+       /* Configure the channels */
+       regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),
+@@ -1255,7 +1265,7 @@ static const struct regmap_config sun50i_h6_i2s_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+-      .max_register   = SUN50I_H6_I2S_RX_CHAN_MAP1_REG,
++      .max_register   = SUN50I_R329_I2S_RX_CHAN_MAP3_REG,
+       .cache_type     = REGCACHE_FLAT,
+       .reg_defaults   = sun50i_h6_i2s_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults),
+@@ -1440,6 +1450,26 @@ static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
+       .set_fmt                = sun50i_h6_i2s_set_soc_fmt,
+ };
++static const struct sun4i_i2s_quirks sun50i_r329_i2s_quirks = {
++      .has_reset              = true,
++      .reg_offset_txdata      = SUN8I_I2S_FIFO_TX_REG,
++      .sun4i_i2s_regmap       = &sun50i_h6_i2s_regmap_config,
++      .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
++      .field_fmt_wss          = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
++      .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
++      .num_din_pins           = 4,
++      .num_dout_pins          = 4,
++      .bclk_dividers          = sun8i_i2s_clk_div,
++      .num_bclk_dividers      = ARRAY_SIZE(sun8i_i2s_clk_div),
++      .mclk_dividers          = sun8i_i2s_clk_div,
++      .num_mclk_dividers      = ARRAY_SIZE(sun8i_i2s_clk_div),
++      .get_bclk_parent_rate   = sun8i_i2s_get_bclk_parent_rate,
++      .get_sr                 = sun8i_i2s_get_sr_wss,
++      .get_wss                = sun8i_i2s_get_sr_wss,
++      .set_chan_cfg           = sun50i_h6_i2s_set_chan_cfg,
++      .set_fmt                = sun50i_h6_i2s_set_soc_fmt,
++};
++
+ static int sun4i_i2s_init_regmap_fields(struct device *dev,
+                                       struct sun4i_i2s *i2s)
+ {
+@@ -1612,6 +1642,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
+               .compatible = "allwinner,sun50i-h6-i2s",
+               .data = &sun50i_h6_i2s_quirks,
+       },
++      {
++              .compatible = "allwinner,sun50i-r329-i2s",
++              .data = &sun50i_r329_i2s_quirks,
++      },
+       {}
+ };
+ MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0030-hwspinlock-sun6i-Clarify-bank-counting-logic.patch b/target/linux/sunxid1/patches-5.15/0030-hwspinlock-sun6i-Clarify-bank-counting-logic.patch
new file mode 100644 (file)
index 0000000..95ca5f0
--- /dev/null
@@ -0,0 +1,69 @@
+From 2040266a0a941ec34949f049a2245f88a0b58ebc Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:42:19 -0500
+Subject: [PATCH 030/124] hwspinlock: sun6i: Clarify bank counting logic
+
+In some of the most recent datasheets, the register definition was
+updated in a way that resolves the conflict here: the field is only two
+bits wide, and a value of "4" really means a bit pattern of "0". Correct
+the code to reflect this, but leave an updated comment because some
+datasheets still have incorrect information in them.
+
+Fixes: 3c881e05c814 ("hwspinlock: add sun6i hardware spinlock support")
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/hwspinlock/sun6i_hwspinlock.c | 36 +++++++++++----------------
+ 1 file changed, 14 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/hwspinlock/sun6i_hwspinlock.c b/drivers/hwspinlock/sun6i_hwspinlock.c
+index c2d314588046..21dfbbc7a8ae 100644
+--- a/drivers/hwspinlock/sun6i_hwspinlock.c
++++ b/drivers/hwspinlock/sun6i_hwspinlock.c
+@@ -129,30 +129,22 @@ static int sun6i_hwspinlock_probe(struct platform_device *pdev)
+       }
+       /*
+-       * bit 28 and 29 represents the hwspinlock setup
++       * Bits 28 and 29 represent the number of available locks.
+        *
+-       * every datasheet (A64, A80, A83T, H3, H5, H6 ...) says the default value is 0x1 and 0x1
+-       * to 0x4 represent 32, 64, 128 and 256 locks
+-       * but later datasheets (H5, H6) say 00, 01, 10, 11 represent 32, 64, 128 and 256 locks,
+-       * but that would mean H5 and H6 have 64 locks, while their datasheets talk about 32 locks
+-       * all the time, not a single mentioning of 64 locks
+-       * the 0x4 value is also not representable by 2 bits alone, so some datasheets are not
+-       * correct
+-       * one thing have all in common, default value of the sysstatus register is 0x10000000,
+-       * which results in bit 28 being set
+-       * this is the reason 0x1 is considered being 32 locks and bit 30 is taken into account
+-       * verified on H2+ (datasheet 0x1 = 32 locks) and H5 (datasheet 01 = 64 locks)
++       * The datasheets have two conflicting interpretations for these bits:
++       *   |  00 | 01 |  10 |  11 |
++       *   +-----+----+-----+-----+
++       *   | 256 | 32 |  64 | 128 | A80, A83T, H3, A64, A50, D1
++       *   |  32 | 64 | 128 | 256 | H5, H6, R329
++       * where some datasheets use "4" instead of "0" for the first column.
++       *
++       * Experiments shows that the first interpretation is correct, as all
++       * known implementations report the value "1" and have 32 spinlocks.
+        */
+-      num_banks = readl(io_base + SPINLOCK_SYSSTATUS_REG) >> 28;
+-      switch (num_banks) {
+-      case 1 ... 4:
+-              priv->nlocks = 1 << (4 + num_banks);
+-              break;
+-      default:
+-              err = -EINVAL;
+-              dev_err(&pdev->dev, "unsupported hwspinlock setup (%d)\n", num_banks);
+-              goto bank_fail;
+-      }
++      num_banks = readl(io_base + SPINLOCK_SYSSTATUS_REG) >> 28 & 0x3;
++      if (!num_banks)
++              num_banks = 4;
++      priv->nlocks = 1 << (4 + num_banks);
+       priv->bank = devm_kzalloc(&pdev->dev, struct_size(priv->bank, lock, priv->nlocks),
+                                 GFP_KERNEL);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0031-hwspinlock-sun6i-Fix-driver-to-match-binding.patch b/target/linux/sunxid1/patches-5.15/0031-hwspinlock-sun6i-Fix-driver-to-match-binding.patch
new file mode 100644 (file)
index 0000000..6ae488b
--- /dev/null
@@ -0,0 +1,42 @@
+From d9e58fa4c5704d94f3fec0d73eb018e7684b634b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:41:44 -0500
+Subject: [PATCH 031/124] hwspinlock: sun6i: Fix driver to match binding
+
+The binding for this device does not allow using the clock-names and
+reset-names properties, so the driver should not reference the clock or
+reset by name.
+
+Fixes: 3c881e05c814 ("hwspinlock: add sun6i hardware spinlock support")
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/hwspinlock/sun6i_hwspinlock.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/hwspinlock/sun6i_hwspinlock.c b/drivers/hwspinlock/sun6i_hwspinlock.c
+index 21dfbbc7a8ae..11b63ce3bd46 100644
+--- a/drivers/hwspinlock/sun6i_hwspinlock.c
++++ b/drivers/hwspinlock/sun6i_hwspinlock.c
+@@ -104,14 +104,12 @@ static int sun6i_hwspinlock_probe(struct platform_device *pdev)
+       if (!priv)
+               return -ENOMEM;
+-      priv->ahb_clk = devm_clk_get(&pdev->dev, "ahb");
+-      if (IS_ERR(priv->ahb_clk)) {
+-              err = PTR_ERR(priv->ahb_clk);
+-              dev_err(&pdev->dev, "unable to get AHB clock (%d)\n", err);
+-              return err;
+-      }
++      priv->ahb_clk = devm_clk_get(&pdev->dev, NULL);
++      if (IS_ERR(priv->ahb_clk))
++              return dev_err_probe(&pdev->dev, PTR_ERR(priv->ahb_clk),
++                                   "unable to get AHB clock\n");
+-      priv->reset = devm_reset_control_get(&pdev->dev, "ahb");
++      priv->reset = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->reset))
+               return dev_err_probe(&pdev->dev, PTR_ERR(priv->reset),
+                                    "unable to get reset control\n");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0032-dmaengine-sun6i-Do-not-use-virt_to_phys.patch b/target/linux/sunxid1/patches-5.15/0032-dmaengine-sun6i-Do-not-use-virt_to_phys.patch
new file mode 100644 (file)
index 0000000..7a83d2b
--- /dev/null
@@ -0,0 +1,116 @@
+From a79bb5d39c26fa96ceb3e306ab2b1a418ec96541 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 14:50:51 -0500
+Subject: [PATCH 032/124] dmaengine: sun6i: Do not use virt_to_phys
+
+This breaks on RISC-V, because dma_pool_alloc returns addresses which
+are not in the linear map. Instead, plumb through the physical address
+which is already known anyway.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/dma/sun6i-dma.c | 38 +++++++++++++++++++-------------------
+ 1 file changed, 19 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
+index 5cadd4d2b824..a9334f969b28 100644
+--- a/drivers/dma/sun6i-dma.c
++++ b/drivers/dma/sun6i-dma.c
+@@ -241,9 +241,7 @@ static inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev)
+ static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev,
+                                           struct sun6i_pchan *pchan)
+ {
+-      phys_addr_t reg = virt_to_phys(pchan->base);
+-
+-      dev_dbg(sdev->slave.dev, "Chan %d reg: %pa\n"
++      dev_dbg(sdev->slave.dev, "Chan %d reg: 0x%lx\n"
+               "\t___en(%04x): \t0x%08x\n"
+               "\tpause(%04x): \t0x%08x\n"
+               "\tstart(%04x): \t0x%08x\n"
+@@ -252,7 +250,7 @@ static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev,
+               "\t__dst(%04x): \t0x%08x\n"
+               "\tcount(%04x): \t0x%08x\n"
+               "\t_para(%04x): \t0x%08x\n\n",
+-              pchan->idx, &reg,
++              pchan->idx, pchan->base - sdev->base,
+               DMA_CHAN_ENABLE,
+               readl(pchan->base + DMA_CHAN_ENABLE),
+               DMA_CHAN_PAUSE,
+@@ -385,17 +383,16 @@ static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
+ }
+ static inline void sun6i_dma_dump_lli(struct sun6i_vchan *vchan,
+-                                    struct sun6i_dma_lli *lli)
++                                    struct sun6i_dma_lli *v_lli,
++                                    dma_addr_t p_lli)
+ {
+-      phys_addr_t p_lli = virt_to_phys(lli);
+-
+       dev_dbg(chan2dev(&vchan->vc.chan),
+-              "\n\tdesc:   p - %pa v - 0x%p\n"
++              "\n\tdesc:\tp - %pad v - 0x%p\n"
+               "\t\tc - 0x%08x s - 0x%08x d - 0x%08x\n"
+               "\t\tl - 0x%08x p - 0x%08x n - 0x%08x\n",
+-              &p_lli, lli,
+-              lli->cfg, lli->src, lli->dst,
+-              lli->len, lli->para, lli->p_lli_next);
++              &p_lli, v_lli,
++              v_lli->cfg, v_lli->src, v_lli->dst,
++              v_lli->len, v_lli->para, v_lli->p_lli_next);
+ }
+ static void sun6i_dma_free_desc(struct virt_dma_desc *vd)
+@@ -445,7 +442,7 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
+       pchan->desc = to_sun6i_desc(&desc->tx);
+       pchan->done = NULL;
+-      sun6i_dma_dump_lli(vchan, pchan->desc->v_lli);
++      sun6i_dma_dump_lli(vchan, pchan->desc->v_lli, pchan->desc->p_lli);
+       irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
+       irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
+@@ -670,7 +667,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
+       sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
+-      sun6i_dma_dump_lli(vchan, v_lli);
++      sun6i_dma_dump_lli(vchan, v_lli, p_lli);
+       return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+@@ -746,14 +743,16 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
+       }
+       dev_dbg(chan2dev(chan), "First: %pad\n", &txd->p_lli);
+-      for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
+-              sun6i_dma_dump_lli(vchan, prev);
++      for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli;
++           p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next)
++              sun6i_dma_dump_lli(vchan, v_lli, p_lli);
+       return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+ err_lli_free:
+-      for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
+-              dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
++      for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli;
++           p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next)
++              dma_pool_free(sdev->pool, v_lli, p_lli);
+       kfree(txd);
+       return NULL;
+ }
+@@ -820,8 +819,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
+       return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+ err_lli_free:
+-      for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
+-              dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
++      for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli;
++           p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next)
++              dma_pool_free(sdev->pool, v_lli, p_lli);
+       kfree(txd);
+       return NULL;
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0033-dmaengine-sun6i-Add-support-for-34-bit-physical-addr.patch b/target/linux/sunxid1/patches-5.15/0033-dmaengine-sun6i-Add-support-for-34-bit-physical-addr.patch
new file mode 100644 (file)
index 0000000..f59212d
--- /dev/null
@@ -0,0 +1,157 @@
+From c14eb7526a01f87568c5f063eff3e628299b09e4 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 14:44:12 -0500
+Subject: [PATCH 033/124] dmaengine: sun6i: Add support for 34-bit physical
+ addresses
+
+Recent Allwinner SoCs support >4 GiB of DRAM, so those variants of the
+DMA engine support >32 bit physical addresses. This is accomplished by
+placing the high bits in the "para" word in the DMA descriptor.
+
+DMA descriptors themselves can be located at >32 bit addresses by
+putting the high bits in the LSBs of the descriptor address register,
+taking advantage of the required DMA desciptor alignment. However,
+support for this is not really necessary, so we can avoid the
+complication by allocating them from the DMA_32 zone.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/dma/sun6i-dma.c | 39 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 34 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
+index a9334f969b28..8c7cce643cdc 100644
+--- a/drivers/dma/sun6i-dma.c
++++ b/drivers/dma/sun6i-dma.c
+@@ -90,6 +90,14 @@
+ #define DMA_CHAN_CUR_PARA     0x1c
++/*
++ * LLI address mangling
++ *
++ * The LLI link physical address is also mangled, but we avoid dealing
++ * with that by allocating LLIs from the DMA32 zone.
++ */
++#define SET_SRC_HIGH_ADDR(x)          ((((x) >> 32) & 0x3U) << 16)
++#define SET_DST_HIGH_ADDR(x)          ((((x) >> 32) & 0x3U) << 18)
+ /*
+  * Various hardware related defines
+@@ -132,6 +140,7 @@ struct sun6i_dma_config {
+       u32 dst_burst_lengths;
+       u32 src_addr_widths;
+       u32 dst_addr_widths;
++      bool has_high_addr;
+       bool has_mbus_clk;
+ };
+@@ -223,6 +232,12 @@ to_sun6i_desc(struct dma_async_tx_descriptor *tx)
+       return container_of(tx, struct sun6i_desc, vd.tx);
+ }
++static inline bool sun6i_dma_has_high_addr(struct sun6i_dma_dev *sdev)
++{
++      return IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
++              sdev->cfg->has_high_addr;
++}
++
+ static inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev)
+ {
+       dev_dbg(sdev->slave.dev, "Common register:\n"
+@@ -645,7 +660,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
+       if (!txd)
+               return NULL;
+-      v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
++      v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32|GFP_NOWAIT, &p_lli);
+       if (!v_lli) {
+               dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
+               goto err_txd_free;
+@@ -655,6 +670,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
+       v_lli->dst = dest;
+       v_lli->len = len;
+       v_lli->para = NORMAL_WAIT;
++      if (sun6i_dma_has_high_addr(sdev))
++              v_lli->para |= SET_SRC_HIGH_ADDR(src) |
++                             SET_DST_HIGH_ADDR(dest);
+       burst = convert_burst(8);
+       width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
+@@ -705,7 +723,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
+               return NULL;
+       for_each_sg(sgl, sg, sg_len, i) {
+-              v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
++              v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32|GFP_NOWAIT, &p_lli);
+               if (!v_lli)
+                       goto err_lli_free;
+@@ -715,6 +733,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
+               if (dir == DMA_MEM_TO_DEV) {
+                       v_lli->src = sg_dma_address(sg);
+                       v_lli->dst = sconfig->dst_addr;
++                      if (sun6i_dma_has_high_addr(sdev))
++                              v_lli->para |= SET_SRC_HIGH_ADDR(sg_dma_address(sg)) |
++                                             SET_DST_HIGH_ADDR(sconfig->dst_addr);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
+                       sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
+@@ -728,6 +749,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
+               } else {
+                       v_lli->src = sconfig->src_addr;
+                       v_lli->dst = sg_dma_address(sg);
++                      if (sun6i_dma_has_high_addr(sdev))
++                              v_lli->para |= SET_SRC_HIGH_ADDR(sconfig->src_addr) |
++                                             SET_DST_HIGH_ADDR(sg_dma_address(sg));
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
+                       sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
+@@ -786,7 +810,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
+               return NULL;
+       for (i = 0; i < periods; i++) {
+-              v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
++              v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32|GFP_NOWAIT, &p_lli);
+               if (!v_lli) {
+                       dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
+                       goto err_lli_free;
+@@ -798,12 +822,18 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
+               if (dir == DMA_MEM_TO_DEV) {
+                       v_lli->src = buf_addr + period_len * i;
+                       v_lli->dst = sconfig->dst_addr;
++                      if (sun6i_dma_has_high_addr(sdev))
++                              v_lli->para |= SET_SRC_HIGH_ADDR(buf_addr + period_len * i) |
++                                             SET_DST_HIGH_ADDR(sconfig->dst_addr);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
+                       sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
+               } else {
+                       v_lli->src = sconfig->src_addr;
+                       v_lli->dst = buf_addr + period_len * i;
++                      if (sun6i_dma_has_high_addr(sdev))
++                              v_lli->para |= SET_SRC_HIGH_ADDR(sconfig->src_addr) |
++                                             SET_DST_HIGH_ADDR(buf_addr + period_len * i);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
+                       sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
+@@ -1174,8 +1204,6 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
+ };
+ /*
+- * TODO: Add support for more than 4g physical addressing.
+- *
+  * The A100 binding uses the number of dma channels from the
+  * device tree node.
+  */
+@@ -1194,6 +1222,7 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
+                            BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+                            BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+                            BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
++      .has_high_addr = true,
+       .has_mbus_clk = true,
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0034-crypto-sun8i-ce-Add-support-for-the-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0034-crypto-sun8i-ce-Add-support-for-the-D1-variant.patch
new file mode 100644 (file)
index 0000000..d1d6e63
--- /dev/null
@@ -0,0 +1,76 @@
+From 2d56be1a7b337a5b73afbf5bb762a314835e9ed4 Mon Sep 17 00:00:00 2001
+From: Corentin Labbe <clabbe.montjoie@gmail.com>
+Date: Mon, 14 Jun 2021 20:54:01 +0200
+Subject: [PATCH 034/124] crypto: sun8i-ce: Add support for the D1 variant
+
+The Allwinner D1 SoC has a crypto engine compatible with sun8i-ce.
+Add support for it.
+
+Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ .../crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 21 +++++++++++++++++++
+ drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h  |  1 +
+ 2 files changed, 22 insertions(+)
+
+diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
+index 00194d1d9ae6..d8623c7e0d1d 100644
+--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
++++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
+@@ -106,6 +106,24 @@ static const struct ce_variant ce_a64_variant = {
+       .trng = CE_ID_NOTSUPP,
+ };
++static const struct ce_variant ce_d1_variant = {
++      .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
++      },
++      .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,
++              CE_ALG_SHA384, CE_ALG_SHA512
++      },
++      .op_mode = { CE_OP_ECB, CE_OP_CBC
++      },
++      .ce_clks = {
++              { "bus", 0, 200000000 },
++              { "mod", 300000000, 0 },
++              { "ram", 0, 400000000 },
++              },
++      .esr = ESR_D1,
++      .prng = CE_ALG_PRNG,
++      .trng = CE_ALG_TRNG,
++};
++
+ static const struct ce_variant ce_r40_variant = {
+       .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
+       },
+@@ -192,6 +210,7 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)
+                       dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");
+               break;
+       case ESR_A64:
++      case ESR_D1:
+       case ESR_H5:
+       case ESR_R40:
+               v >>= (flow * 4);
+@@ -990,6 +1009,8 @@ static const struct of_device_id sun8i_ce_crypto_of_match_table[] = {
+         .data = &ce_h3_variant },
+       { .compatible = "allwinner,sun8i-r40-crypto",
+         .data = &ce_r40_variant },
++      { .compatible = "allwinner,sun20i-d1-crypto",
++        .data = &ce_d1_variant },
+       { .compatible = "allwinner,sun50i-a64-crypto",
+         .data = &ce_a64_variant },
+       { .compatible = "allwinner,sun50i-h5-crypto",
+diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
+index cec781d5063c..624a5926f21f 100644
+--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
++++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
+@@ -94,6 +94,7 @@
+ #define ESR_R40       2
+ #define ESR_H5        3
+ #define ESR_H6        4
++#define ESR_D1        5
+ #define PRNG_DATA_SIZE (160 / 8)
+ #define PRNG_SEED_SIZE DIV_ROUND_UP(175, 8)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0035-bus-sun50i-de2-Prevent-driver-from-being-unbound.patch b/target/linux/sunxid1/patches-5.15/0035-bus-sun50i-de2-Prevent-driver-from-being-unbound.patch
new file mode 100644 (file)
index 0000000..83eb866
--- /dev/null
@@ -0,0 +1,44 @@
+From 692f382f2d8e87d65e19ef44f7c1794ceac14126 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 13 Nov 2021 11:39:01 -0600
+Subject: [PATCH 035/124] bus: sun50i-de2: Prevent driver from being unbound
+
+Currently, the driver can be unbound via sysfs. Because it does not call
+of_platform_depopulate, unbinding the driver will ...
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/bus/sun50i-de2.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c
+index 672518741f86..740957de1077 100644
+--- a/drivers/bus/sun50i-de2.c
++++ b/drivers/bus/sun50i-de2.c
+@@ -25,12 +25,6 @@ static int sun50i_de2_bus_probe(struct platform_device *pdev)
+       return 0;
+ }
+-static int sun50i_de2_bus_remove(struct platform_device *pdev)
+-{
+-      sunxi_sram_release(&pdev->dev);
+-      return 0;
+-}
+-
+ static const struct of_device_id sun50i_de2_bus_of_match[] = {
+       { .compatible = "allwinner,sun50i-a64-de2", },
+       { /* sentinel */ }
+@@ -38,9 +32,9 @@ static const struct of_device_id sun50i_de2_bus_of_match[] = {
+ static struct platform_driver sun50i_de2_bus_driver = {
+       .probe = sun50i_de2_bus_probe,
+-      .remove = sun50i_de2_bus_remove,
+       .driver = {
+               .name = "sun50i-de2-bus",
++              .suppress_bind_attrs = true,
+               .of_match_table = sun50i_de2_bus_of_match,
+       },
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0036-clk-sunxi-ng-Export-symbols-used-by-CCU-drivers.patch b/target/linux/sunxid1/patches-5.15/0036-clk-sunxi-ng-Export-symbols-used-by-CCU-drivers.patch
new file mode 100644 (file)
index 0000000..4192a12
--- /dev/null
@@ -0,0 +1,342 @@
+From 6ff4e726d98f36bcd5669cf5dac3f84cb9f8f9cf Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 18 Jul 2021 18:12:53 -0500
+Subject: [PATCH 036/124] clk: sunxi-ng: Export symbols used by CCU drivers
+
+For the individual CCU drivers to be built as modules, the ops structs,
+helper functions, and callback registration functions must be exported.
+These symbols are intended for use only by the adjacent CCU drivers, so
+export them into the SUNXI_CCU namespace.
+
+of_sunxi_ccu_probe is not exported because it is only used by built-in
+OF clock providers.
+
+Cover-changes: 1
+ - Patches 1-3 of 8 were merged.
+ - Name modules using Makefile logic, not by renaming the source files.
+   (Drop patch 4 of 8.)
+
+Series-changes: 2
+ - Export symbols to the SUNXI_CCU namespace.
+
+Series-changes: 3
+ - Also export helper functions.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu_common.c | 3 +++
+ drivers/clk/sunxi-ng/ccu_div.c    | 1 +
+ drivers/clk/sunxi-ng/ccu_frac.c   | 6 ++++++
+ drivers/clk/sunxi-ng/ccu_gate.c   | 4 ++++
+ drivers/clk/sunxi-ng/ccu_mp.c     | 2 ++
+ drivers/clk/sunxi-ng/ccu_mult.c   | 1 +
+ drivers/clk/sunxi-ng/ccu_mux.c    | 6 ++++++
+ drivers/clk/sunxi-ng/ccu_nk.c     | 1 +
+ drivers/clk/sunxi-ng/ccu_nkm.c    | 1 +
+ drivers/clk/sunxi-ng/ccu_nkmp.c   | 1 +
+ drivers/clk/sunxi-ng/ccu_nm.c     | 1 +
+ drivers/clk/sunxi-ng/ccu_phase.c  | 1 +
+ drivers/clk/sunxi-ng/ccu_reset.c  | 1 +
+ drivers/clk/sunxi-ng/ccu_sdm.c    | 6 ++++++
+ 14 files changed, 35 insertions(+)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
+index 31af8b6b5286..6afdedbce6a2 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.c
++++ b/drivers/clk/sunxi-ng/ccu_common.c
+@@ -36,6 +36,7 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
+       WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, SUNXI_CCU);
+ /*
+  * This clock notifier is called when the frequency of a PLL clock is
+@@ -83,6 +84,7 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb)
+       return clk_notifier_register(pll_nb->common->hw.clk,
+                                    &pll_nb->clk_nb);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_pll_notifier_register, SUNXI_CCU);
+ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
+                          struct device_node *node, void __iomem *reg,
+@@ -194,6 +196,7 @@ int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg,
+       return 0;
+ }
++EXPORT_SYMBOL_NS_GPL(devm_sunxi_ccu_probe, SUNXI_CCU);
+ void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+                       const struct sunxi_ccu_desc *desc)
+diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
+index 4c297089483c..cb10a3ea23f9 100644
+--- a/drivers/clk/sunxi-ng/ccu_div.c
++++ b/drivers/clk/sunxi-ng/ccu_div.c
+@@ -141,3 +141,4 @@ const struct clk_ops ccu_div_ops = {
+       .recalc_rate    = ccu_div_recalc_rate,
+       .set_rate       = ccu_div_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_div_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_frac.c b/drivers/clk/sunxi-ng/ccu_frac.c
+index 44fcded8b354..b31f3ad946d6 100644
+--- a/drivers/clk/sunxi-ng/ccu_frac.c
++++ b/drivers/clk/sunxi-ng/ccu_frac.c
+@@ -18,6 +18,7 @@ bool ccu_frac_helper_is_enabled(struct ccu_common *common,
+       return !(readl(common->base + common->reg) & cf->enable);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU);
+ void ccu_frac_helper_enable(struct ccu_common *common,
+                           struct ccu_frac_internal *cf)
+@@ -33,6 +34,7 @@ void ccu_frac_helper_enable(struct ccu_common *common,
+       writel(reg & ~cf->enable, common->base + common->reg);
+       spin_unlock_irqrestore(common->lock, flags);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU);
+ void ccu_frac_helper_disable(struct ccu_common *common,
+                            struct ccu_frac_internal *cf)
+@@ -48,6 +50,7 @@ void ccu_frac_helper_disable(struct ccu_common *common,
+       writel(reg | cf->enable, common->base + common->reg);
+       spin_unlock_irqrestore(common->lock, flags);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU);
+ bool ccu_frac_helper_has_rate(struct ccu_common *common,
+                             struct ccu_frac_internal *cf,
+@@ -58,6 +61,7 @@ bool ccu_frac_helper_has_rate(struct ccu_common *common,
+       return (cf->rates[0] == rate) || (cf->rates[1] == rate);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU);
+ unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
+                                       struct ccu_frac_internal *cf)
+@@ -79,6 +83,7 @@ unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
+       return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU);
+ int ccu_frac_helper_set_rate(struct ccu_common *common,
+                            struct ccu_frac_internal *cf,
+@@ -107,3 +112,4 @@ int ccu_frac_helper_set_rate(struct ccu_common *common,
+       return 0;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c
+index 3d5ca092b08f..a2115a21807d 100644
+--- a/drivers/clk/sunxi-ng/ccu_gate.c
++++ b/drivers/clk/sunxi-ng/ccu_gate.c
+@@ -24,6 +24,7 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
+       spin_unlock_irqrestore(common->lock, flags);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU);
+ static void ccu_gate_disable(struct clk_hw *hw)
+ {
+@@ -49,6 +50,7 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
+       return 0;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU);
+ static int ccu_gate_enable(struct clk_hw *hw)
+ {
+@@ -64,6 +66,7 @@ int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
+       return readl(common->base + common->reg) & gate;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU);
+ static int ccu_gate_is_enabled(struct clk_hw *hw)
+ {
+@@ -124,3 +127,4 @@ const struct clk_ops ccu_gate_ops = {
+       .set_rate       = ccu_gate_set_rate,
+       .recalc_rate    = ccu_gate_recalc_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
+index 9d3a76604d94..57cf2d615148 100644
+--- a/drivers/clk/sunxi-ng/ccu_mp.c
++++ b/drivers/clk/sunxi-ng/ccu_mp.c
+@@ -245,6 +245,7 @@ const struct clk_ops ccu_mp_ops = {
+       .recalc_rate    = ccu_mp_recalc_rate,
+       .set_rate       = ccu_mp_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_mp_ops, SUNXI_CCU);
+ /*
+  * Support for MMC timing mode switching
+@@ -325,3 +326,4 @@ const struct clk_ops ccu_mp_mmc_ops = {
+       .recalc_rate    = ccu_mp_mmc_recalc_rate,
+       .set_rate       = ccu_mp_mmc_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_mp_mmc_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c
+index 7c8cf2e04e94..7bee217ef111 100644
+--- a/drivers/clk/sunxi-ng/ccu_mult.c
++++ b/drivers/clk/sunxi-ng/ccu_mult.c
+@@ -170,3 +170,4 @@ const struct clk_ops ccu_mult_ops = {
+       .recalc_rate    = ccu_mult_recalc_rate,
+       .set_rate       = ccu_mult_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_mult_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
+index 7d75da9a1f2e..2306a1cd83e4 100644
+--- a/drivers/clk/sunxi-ng/ccu_mux.c
++++ b/drivers/clk/sunxi-ng/ccu_mux.c
+@@ -64,6 +64,7 @@ unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
+ {
+       return parent_rate / ccu_mux_get_prediv(common, cm, parent_index);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, SUNXI_CCU);
+ static unsigned long ccu_mux_helper_unapply_prediv(struct ccu_common *common,
+                                           struct ccu_mux_internal *cm,
+@@ -152,6 +153,7 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common,
+       req->rate = best_rate;
+       return 0;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_determine_rate, SUNXI_CCU);
+ u8 ccu_mux_helper_get_parent(struct ccu_common *common,
+                            struct ccu_mux_internal *cm)
+@@ -174,6 +176,7 @@ u8 ccu_mux_helper_get_parent(struct ccu_common *common,
+       return parent;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_get_parent, SUNXI_CCU);
+ int ccu_mux_helper_set_parent(struct ccu_common *common,
+                             struct ccu_mux_internal *cm,
+@@ -195,6 +198,7 @@ int ccu_mux_helper_set_parent(struct ccu_common *common,
+       return 0;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_set_parent, SUNXI_CCU);
+ static void ccu_mux_disable(struct clk_hw *hw)
+ {
+@@ -251,6 +255,7 @@ const struct clk_ops ccu_mux_ops = {
+       .determine_rate = __clk_mux_determine_rate,
+       .recalc_rate    = ccu_mux_recalc_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU);
+ /*
+  * This clock notifier is called when the frequency of the of the parent
+@@ -285,3 +290,4 @@ int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb)
+       return clk_notifier_register(clk, &mux_nb->clk_nb);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_mux_notifier_register, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c
+index aee68b00f3b2..c4fb82af97e8 100644
+--- a/drivers/clk/sunxi-ng/ccu_nk.c
++++ b/drivers/clk/sunxi-ng/ccu_nk.c
+@@ -157,3 +157,4 @@ const struct clk_ops ccu_nk_ops = {
+       .round_rate     = ccu_nk_round_rate,
+       .set_rate       = ccu_nk_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_nk_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
+index b9cfee0276ea..67da2c189b53 100644
+--- a/drivers/clk/sunxi-ng/ccu_nkm.c
++++ b/drivers/clk/sunxi-ng/ccu_nkm.c
+@@ -206,3 +206,4 @@ const struct clk_ops ccu_nkm_ops = {
+       .recalc_rate    = ccu_nkm_recalc_rate,
+       .set_rate       = ccu_nkm_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_nkm_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
+index bda87b38c45c..39413cb0985c 100644
+--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
++++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
+@@ -230,3 +230,4 @@ const struct clk_ops ccu_nkmp_ops = {
+       .round_rate     = ccu_nkmp_round_rate,
+       .set_rate       = ccu_nkmp_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_nkmp_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
+index e6bcc0a7170c..9ca9257f4426 100644
+--- a/drivers/clk/sunxi-ng/ccu_nm.c
++++ b/drivers/clk/sunxi-ng/ccu_nm.c
+@@ -238,3 +238,4 @@ const struct clk_ops ccu_nm_ops = {
+       .round_rate     = ccu_nm_round_rate,
+       .set_rate       = ccu_nm_set_rate,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_nm_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_phase.c b/drivers/clk/sunxi-ng/ccu_phase.c
+index 92ab8bd66427..e4cae2afe9db 100644
+--- a/drivers/clk/sunxi-ng/ccu_phase.c
++++ b/drivers/clk/sunxi-ng/ccu_phase.c
+@@ -121,3 +121,4 @@ const struct clk_ops ccu_phase_ops = {
+       .get_phase      = ccu_phase_get_phase,
+       .set_phase      = ccu_phase_set_phase,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_phase_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_reset.c b/drivers/clk/sunxi-ng/ccu_reset.c
+index 483100e45df3..6577aa18cb01 100644
+--- a/drivers/clk/sunxi-ng/ccu_reset.c
++++ b/drivers/clk/sunxi-ng/ccu_reset.c
+@@ -75,3 +75,4 @@ const struct reset_control_ops ccu_reset_ops = {
+       .reset          = ccu_reset_reset,
+       .status         = ccu_reset_status,
+ };
++EXPORT_SYMBOL_NS_GPL(ccu_reset_ops, SUNXI_CCU);
+diff --git a/drivers/clk/sunxi-ng/ccu_sdm.c b/drivers/clk/sunxi-ng/ccu_sdm.c
+index 79581a1c649a..41937ed0766d 100644
+--- a/drivers/clk/sunxi-ng/ccu_sdm.c
++++ b/drivers/clk/sunxi-ng/ccu_sdm.c
+@@ -20,6 +20,7 @@ bool ccu_sdm_helper_is_enabled(struct ccu_common *common,
+       return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, SUNXI_CCU);
+ void ccu_sdm_helper_enable(struct ccu_common *common,
+                          struct ccu_sdm_internal *sdm,
+@@ -49,6 +50,7 @@ void ccu_sdm_helper_enable(struct ccu_common *common,
+       writel(reg | sdm->enable, common->base + common->reg);
+       spin_unlock_irqrestore(common->lock, flags);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, SUNXI_CCU);
+ void ccu_sdm_helper_disable(struct ccu_common *common,
+                           struct ccu_sdm_internal *sdm)
+@@ -69,6 +71,7 @@ void ccu_sdm_helper_disable(struct ccu_common *common,
+       writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg);
+       spin_unlock_irqrestore(common->lock, flags);
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, SUNXI_CCU);
+ /*
+  * Sigma delta modulation provides a way to do fractional-N frequency
+@@ -102,6 +105,7 @@ bool ccu_sdm_helper_has_rate(struct ccu_common *common,
+       return false;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_has_rate, SUNXI_CCU);
+ unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
+                                      struct ccu_sdm_internal *sdm,
+@@ -132,6 +136,7 @@ unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
+       /* We can't calculate the effective clock rate, so just fail. */
+       return 0;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_read_rate, SUNXI_CCU);
+ int ccu_sdm_helper_get_factors(struct ccu_common *common,
+                              struct ccu_sdm_internal *sdm,
+@@ -153,3 +158,4 @@ int ccu_sdm_helper_get_factors(struct ccu_common *common,
+       /* nothing found */
+       return -EINVAL;
+ }
++EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_get_factors, SUNXI_CCU);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0037-clk-sunxi-ng-Allow-drivers-to-be-built-as-modules.patch b/target/linux/sunxid1/patches-5.15/0037-clk-sunxi-ng-Allow-drivers-to-be-built-as-modules.patch
new file mode 100644 (file)
index 0000000..2d03d09
--- /dev/null
@@ -0,0 +1,387 @@
+From de552526eb4e1add4a2d4b616c46435e01650022 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 18 Jul 2021 17:48:02 -0500
+Subject: [PATCH 037/124] clk: sunxi-ng: Allow drivers to be built as modules
+
+While it is useful to build all of the CCU drivers at once, only 1-3 of
+them will be loaded at a time, or possibly none of them if the kernel is
+booted on a non-sunxi platform. These CCU drivers are relatively large;
+32-bit drivers have 30-50k of data each, while the 64-bit ones are
+50-75k due to the increased pointer overhead. About half of that data
+comes from relocations. Let's allow the user to build these drivers as
+modules so only the necessary data is loaded.
+
+As a first step, convert the CCUs that are already platform drivers.
+
+When the drivers are built as modules, normally the file name becomes
+the module name. However, the current file names are inconsistent with
+the <platform>-<peripheral> name used everywhere else: the devicetree
+bindings, the platform driver names, and the Kconfig symbols. Use
+Makfile logic to rename the modules so they follow the usual pattern.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/Kconfig             | 16 +++---
+ drivers/clk/sunxi-ng/Makefile            | 64 ++++++++++++++++--------
+ drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c |  4 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-a100.c   |  4 +-
+ drivers/clk/sunxi-ng/ccu-sun50i-a64.c    |  7 ++-
+ drivers/clk/sunxi-ng/ccu-sun50i-h6.c     |  7 ++-
+ drivers/clk/sunxi-ng/ccu-sun8i-a83t.c    |  7 ++-
+ drivers/clk/sunxi-ng/ccu-sun8i-de2.c     |  9 ++--
+ drivers/clk/sunxi-ng/ccu-sun8i-r40.c     |  6 ++-
+ drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c  |  7 ++-
+ drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c |  7 ++-
+ drivers/clk/sunxi-ng/ccu-sun9i-a80.c     |  7 ++-
+ 12 files changed, 98 insertions(+), 47 deletions(-)
+
+diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
+index cd46d8853876..7cfdf21717f7 100644
+--- a/drivers/clk/sunxi-ng/Kconfig
++++ b/drivers/clk/sunxi-ng/Kconfig
+@@ -13,22 +13,22 @@ config SUNIV_F1C100S_CCU
+       depends on MACH_SUNIV || COMPILE_TEST
+ config SUN50I_A64_CCU
+-      bool "Support for the Allwinner A64 CCU"
++      tristate "Support for the Allwinner A64 CCU"
+       default ARM64 && ARCH_SUNXI
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN50I_A100_CCU
+-      bool "Support for the Allwinner A100 CCU"
++      tristate "Support for the Allwinner A100 CCU"
+       default ARM64 && ARCH_SUNXI
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN50I_A100_R_CCU
+-      bool "Support for the Allwinner A100 PRCM CCU"
++      tristate "Support for the Allwinner A100 PRCM CCU"
+       default ARM64 && ARCH_SUNXI
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN50I_H6_CCU
+-      bool "Support for the Allwinner H6 CCU"
++      tristate "Support for the Allwinner H6 CCU"
+       default ARM64 && ARCH_SUNXI
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+@@ -69,7 +69,7 @@ config SUN8I_A33_CCU
+       depends on MACH_SUN8I || COMPILE_TEST
+ config SUN8I_A83T_CCU
+-      bool "Support for the Allwinner A83T CCU"
++      tristate "Support for the Allwinner A83T CCU"
+       default MACH_SUN8I
+ config SUN8I_H3_CCU
+@@ -83,16 +83,16 @@ config SUN8I_V3S_CCU
+       depends on MACH_SUN8I || COMPILE_TEST
+ config SUN8I_DE2_CCU
+-      bool "Support for the Allwinner SoCs DE2 CCU"
++      tristate "Support for the Allwinner SoCs DE2 CCU"
+       default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
+ config SUN8I_R40_CCU
+-      bool "Support for the Allwinner R40 CCU"
++      tristate "Support for the Allwinner R40 CCU"
+       default MACH_SUN8I
+       depends on MACH_SUN8I || COMPILE_TEST
+ config SUN9I_A80_CCU
+-      bool "Support for the Allwinner A80 CCU"
++      tristate "Support for the Allwinner A80 CCU"
+       default MACH_SUN9I
+       depends on MACH_SUN9I || COMPILE_TEST
+diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
+index 96c324306d97..1020ed49a588 100644
+--- a/drivers/clk/sunxi-ng/Makefile
++++ b/drivers/clk/sunxi-ng/Makefile
+@@ -21,24 +21,46 @@ obj-y                              += ccu_nm.o
+ obj-y                         += ccu_mp.o
+ # SoC support
+-obj-$(CONFIG_SUNIV_F1C100S_CCU)       += ccu-suniv-f1c100s.o
+-obj-$(CONFIG_SUN50I_A64_CCU)  += ccu-sun50i-a64.o
+-obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o
+-obj-$(CONFIG_SUN50I_A100_R_CCU)       += ccu-sun50i-a100-r.o
+-obj-$(CONFIG_SUN50I_H6_CCU)   += ccu-sun50i-h6.o
+-obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o
+-obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o
+-obj-$(CONFIG_SUN4I_A10_CCU)   += ccu-sun4i-a10.o
+-obj-$(CONFIG_SUN5I_CCU)               += ccu-sun5i.o
+-obj-$(CONFIG_SUN6I_A31_CCU)   += ccu-sun6i-a31.o
+-obj-$(CONFIG_SUN8I_A23_CCU)   += ccu-sun8i-a23.o
+-obj-$(CONFIG_SUN8I_A33_CCU)   += ccu-sun8i-a33.o
+-obj-$(CONFIG_SUN8I_A83T_CCU)  += ccu-sun8i-a83t.o
+-obj-$(CONFIG_SUN8I_H3_CCU)    += ccu-sun8i-h3.o
+-obj-$(CONFIG_SUN8I_V3S_CCU)   += ccu-sun8i-v3s.o
+-obj-$(CONFIG_SUN8I_DE2_CCU)   += ccu-sun8i-de2.o
+-obj-$(CONFIG_SUN8I_R_CCU)     += ccu-sun8i-r.o
+-obj-$(CONFIG_SUN8I_R40_CCU)   += ccu-sun8i-r40.o
+-obj-$(CONFIG_SUN9I_A80_CCU)   += ccu-sun9i-a80.o
+-obj-$(CONFIG_SUN9I_A80_CCU)   += ccu-sun9i-a80-de.o
+-obj-$(CONFIG_SUN9I_A80_CCU)   += ccu-sun9i-a80-usb.o
++obj-$(CONFIG_SUNIV_F1C100S_CCU)       += suniv-f1c100s-ccu.o
++obj-$(CONFIG_SUN50I_A64_CCU)  += sun50i-a64-ccu.o
++obj-$(CONFIG_SUN50I_A100_CCU) += sun50i-a100-ccu.o
++obj-$(CONFIG_SUN50I_A100_R_CCU)       += sun50i-a100-r-ccu.o
++obj-$(CONFIG_SUN50I_H6_CCU)   += sun50i-h6-ccu.o
++obj-$(CONFIG_SUN50I_H6_R_CCU) += sun50i-h6-r-ccu.o
++obj-$(CONFIG_SUN50I_H616_CCU) += sun50i-h616-ccu.o
++obj-$(CONFIG_SUN4I_A10_CCU)   += sun4i-a10-ccu.o
++obj-$(CONFIG_SUN5I_CCU)               += sun5i-ccu.o
++obj-$(CONFIG_SUN6I_A31_CCU)   += sun6i-a31-ccu.o
++obj-$(CONFIG_SUN8I_A23_CCU)   += sun8i-a23-ccu.o
++obj-$(CONFIG_SUN8I_A33_CCU)   += sun8i-a33-ccu.o
++obj-$(CONFIG_SUN8I_A83T_CCU)  += sun8i-a83t-ccu.o
++obj-$(CONFIG_SUN8I_H3_CCU)    += sun8i-h3-ccu.o
++obj-$(CONFIG_SUN8I_R40_CCU)   += sun8i-r40-ccu.o
++obj-$(CONFIG_SUN8I_V3S_CCU)   += sun8i-v3s-ccu.o
++obj-$(CONFIG_SUN8I_DE2_CCU)   += sun8i-de2-ccu.o
++obj-$(CONFIG_SUN8I_R_CCU)     += sun8i-r-ccu.o
++obj-$(CONFIG_SUN9I_A80_CCU)   += sun9i-a80-ccu.o
++obj-$(CONFIG_SUN9I_A80_CCU)   += sun9i-a80-de-ccu.o
++obj-$(CONFIG_SUN9I_A80_CCU)   += sun9i-a80-usb-ccu.o
++
++suniv-f1c100s-ccu-y           += ccu-suniv-f1c100s.o
++sun50i-a64-ccu-y              += ccu-sun50i-a64.o
++sun50i-a100-ccu-y             += ccu-sun50i-a100.o
++sun50i-a100-r-ccu-y           += ccu-sun50i-a100-r.o
++sun50i-h6-ccu-y                       += ccu-sun50i-h6.o
++sun50i-h6-r-ccu-y             += ccu-sun50i-h6-r.o
++sun50i-h616-ccu-y             += ccu-sun50i-h616.o
++sun4i-a10-ccu-y                       += ccu-sun4i-a10.o
++sun5i-ccu-y                   += ccu-sun5i.o
++sun6i-a31-ccu-y                       += ccu-sun6i-a31.o
++sun8i-a23-ccu-y                       += ccu-sun8i-a23.o
++sun8i-a33-ccu-y                       += ccu-sun8i-a33.o
++sun8i-a83t-ccu-y              += ccu-sun8i-a83t.o
++sun8i-h3-ccu-y                        += ccu-sun8i-h3.o
++sun8i-r40-ccu-y                       += ccu-sun8i-r40.o
++sun8i-v3s-ccu-y                       += ccu-sun8i-v3s.o
++sun8i-de2-ccu-y                       += ccu-sun8i-de2.o
++sun8i-r-ccu-y                 += ccu-sun8i-r.o
++sun9i-a80-ccu-y                       += ccu-sun9i-a80.o
++sun9i-a80-de-ccu-y            += ccu-sun9i-a80-de.o
++sun9i-a80-usb-ccu-y           += ccu-sun9i-a80-usb.o
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+index 804729e0a208..fddd6c877cec 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+@@ -5,7 +5,6 @@
+ #include <linux/clk-provider.h>
+ #include <linux/module.h>
+-#include <linux/of_address.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -213,3 +212,6 @@ static struct platform_driver sun50i_a100_r_ccu_driver = {
+       },
+ };
+ module_platform_driver(sun50i_a100_r_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+index 1d475d5a3d91..5f93b5526e13 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+@@ -6,7 +6,6 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
+-#include <linux/of_address.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -1275,3 +1274,6 @@ static struct platform_driver sun50i_a100_ccu_driver = {
+       },
+ };
+ module_platform_driver(sun50i_a100_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+index fcbd914e84e0..df0395d5542d 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+@@ -5,7 +5,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -982,4 +982,7 @@ static struct platform_driver sun50i_a64_ccu_driver = {
+               .of_match_table = sun50i_a64_ccu_ids,
+       },
+ };
+-builtin_platform_driver(sun50i_a64_ccu_driver);
++module_platform_driver(sun50i_a64_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+index 9a8902f702c5..db81d1db0378 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+@@ -5,7 +5,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -1256,4 +1256,7 @@ static struct platform_driver sun50i_h6_ccu_driver = {
+               .of_match_table = sun50i_h6_ccu_ids,
+       },
+ };
+-builtin_platform_driver(sun50i_h6_ccu_driver);
++module_platform_driver(sun50i_h6_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+index e663ab0c9935..c6b936ee8435 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+@@ -5,7 +5,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -922,4 +922,7 @@ static struct platform_driver sun8i_a83t_ccu_driver = {
+               .of_match_table = sun8i_a83t_ccu_ids,
+       },
+ };
+-builtin_platform_driver(sun8i_a83t_ccu_driver);
++module_platform_driver(sun8i_a83t_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+index 4b94b6041b27..e67ba1febedb 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+@@ -5,8 +5,8 @@
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
+-#include <linux/of_address.h>
+-#include <linux/of_platform.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/reset.h>
+@@ -396,4 +396,7 @@ static struct platform_driver sunxi_de2_clk_driver = {
+               .of_match_table = sunxi_de2_clk_ids,
+       },
+ };
+-builtin_platform_driver(sunxi_de2_clk_driver);
++module_platform_driver(sunxi_de2_clk_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+index a2144ee728a0..1a06bc518f9e 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+@@ -5,6 +5,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
+@@ -1373,4 +1374,7 @@ static struct platform_driver sun8i_r40_ccu_driver = {
+               .of_match_table = sun8i_r40_ccu_ids,
+       },
+ };
+-builtin_platform_driver(sun8i_r40_ccu_driver);
++module_platform_driver(sun8i_r40_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+index d2072972b614..690d944a7ab0 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+@@ -5,7 +5,7 @@
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/reset.h>
+@@ -272,4 +272,7 @@ static struct platform_driver sun9i_a80_de_clk_driver = {
+               .of_match_table = sun9i_a80_de_clk_ids,
+       },
+ };
+-builtin_platform_driver(sun9i_a80_de_clk_driver);
++module_platform_driver(sun9i_a80_de_clk_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+index 596243b3e0fa..31d1c00b69e8 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+@@ -5,7 +5,7 @@
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -140,4 +140,7 @@ static struct platform_driver sun9i_a80_usb_clk_driver = {
+               .of_match_table = sun9i_a80_usb_clk_ids,
+       },
+ };
+-builtin_platform_driver(sun9i_a80_usb_clk_driver);
++module_platform_driver(sun9i_a80_usb_clk_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+index 68b30fdc60fd..02550ecbd5c8 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+@@ -5,7 +5,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -1247,4 +1247,7 @@ static struct platform_driver sun9i_a80_ccu_driver = {
+               .of_match_table = sun9i_a80_ccu_ids,
+       },
+ };
+-builtin_platform_driver(sun9i_a80_ccu_driver);
++module_platform_driver(sun9i_a80_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0038-clk-sunxi-ng-Convert-early-providers-to-platform-dri.patch b/target/linux/sunxid1/patches-5.15/0038-clk-sunxi-ng-Convert-early-providers-to-platform-dri.patch
new file mode 100644 (file)
index 0000000..72a5363
--- /dev/null
@@ -0,0 +1,891 @@
+From f5fb7ccecb5c4404eeb96d6d5662d1e4d84f80ba Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 17 Jul 2021 19:24:36 -0500
+Subject: [PATCH 038/124] clk: sunxi-ng: Convert early providers to platform
+ drivers
+
+The PRCM CCU drivers depend on clocks provided by other CCU drivers. For
+example, the sun8i-r-ccu driver uses the "pll-periph" clock provided by
+the SoC's main CCU.
+
+However, sun8i-r-ccu is an early OF clock provider, and many of the
+main CCUs (e.g. sun50i-a64-ccu) use platform drivers. This means that
+the consumer clocks will be orphaned until the supplier driver is bound.
+This can be avoided by converting the remaining CCUs to use platform
+drivers. Then fw_devlink will ensure the drivers are bound in the
+optimal order.
+
+The sun5i CCU is the only one which actually needs to be an early clock
+provider, because it provides the clock for the system timer. That one
+is left alone.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/Kconfig             | 20 ++++----
+ drivers/clk/sunxi-ng/ccu-sun4i-a10.c     | 58 +++++++++++++--------
+ drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c   | 56 ++++++++++++--------
+ drivers/clk/sunxi-ng/ccu-sun50i-h616.c   | 33 ++++++++----
+ drivers/clk/sunxi-ng/ccu-sun6i-a31.c     | 40 +++++++++++----
+ drivers/clk/sunxi-ng/ccu-sun8i-a23.c     | 35 +++++++++----
+ drivers/clk/sunxi-ng/ccu-sun8i-a33.c     | 40 +++++++++++----
+ drivers/clk/sunxi-ng/ccu-sun8i-h3.c      | 62 ++++++++++++++--------
+ drivers/clk/sunxi-ng/ccu-sun8i-r.c       | 65 ++++++++++++++----------
+ drivers/clk/sunxi-ng/ccu-sun8i-v3s.c     | 57 +++++++++++++--------
+ drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c | 38 ++++++++++----
+ 11 files changed, 332 insertions(+), 172 deletions(-)
+
+diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
+index 7cfdf21717f7..cbae3612a9ef 100644
+--- a/drivers/clk/sunxi-ng/Kconfig
++++ b/drivers/clk/sunxi-ng/Kconfig
+@@ -8,7 +8,7 @@ config SUNXI_CCU
+ if SUNXI_CCU
+ config SUNIV_F1C100S_CCU
+-      bool "Support for the Allwinner newer F1C100s CCU"
++      tristate "Support for the Allwinner newer F1C100s CCU"
+       default MACH_SUNIV
+       depends on MACH_SUNIV || COMPILE_TEST
+@@ -33,17 +33,17 @@ config SUN50I_H6_CCU
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN50I_H616_CCU
+-      bool "Support for the Allwinner H616 CCU"
++      tristate "Support for the Allwinner H616 CCU"
+       default ARM64 && ARCH_SUNXI
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN50I_H6_R_CCU
+-      bool "Support for the Allwinner H6 and H616 PRCM CCU"
++      tristate "Support for the Allwinner H6 and H616 PRCM CCU"
+       default ARM64 && ARCH_SUNXI
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN4I_A10_CCU
+-      bool "Support for the Allwinner A10/A20 CCU"
++      tristate "Support for the Allwinner A10/A20 CCU"
+       default MACH_SUN4I
+       default MACH_SUN7I
+       depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
+@@ -54,17 +54,17 @@ config SUN5I_CCU
+       depends on MACH_SUN5I || COMPILE_TEST
+ config SUN6I_A31_CCU
+-      bool "Support for the Allwinner A31/A31s CCU"
++      tristate "Support for the Allwinner A31/A31s CCU"
+       default MACH_SUN6I
+       depends on MACH_SUN6I || COMPILE_TEST
+ config SUN8I_A23_CCU
+-      bool "Support for the Allwinner A23 CCU"
++      tristate "Support for the Allwinner A23 CCU"
+       default MACH_SUN8I
+       depends on MACH_SUN8I || COMPILE_TEST
+ config SUN8I_A33_CCU
+-      bool "Support for the Allwinner A33 CCU"
++      tristate "Support for the Allwinner A33 CCU"
+       default MACH_SUN8I
+       depends on MACH_SUN8I || COMPILE_TEST
+@@ -73,12 +73,12 @@ config SUN8I_A83T_CCU
+       default MACH_SUN8I
+ config SUN8I_H3_CCU
+-      bool "Support for the Allwinner H3 CCU"
++      tristate "Support for the Allwinner H3 CCU"
+       default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
+       depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ config SUN8I_V3S_CCU
+-      bool "Support for the Allwinner V3s CCU"
++      tristate "Support for the Allwinner V3s CCU"
+       default MACH_SUN8I
+       depends on MACH_SUN8I || COMPILE_TEST
+@@ -97,7 +97,7 @@ config SUN9I_A80_CCU
+       depends on MACH_SUN9I || COMPILE_TEST
+ config SUN8I_R_CCU
+-      bool "Support for Allwinner SoCs' PRCM CCUs"
++      tristate "Support for Allwinner SoCs' PRCM CCUs"
+       default MACH_SUN8I || (ARCH_SUNXI && ARM64)
+ endif
+diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+index bd9a8782fec3..c19828f1aa0f 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
++++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+@@ -7,7 +7,9 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -1425,18 +1427,19 @@ static const struct sunxi_ccu_desc sun7i_a20_ccu_desc = {
+       .num_resets     = ARRAY_SIZE(sunxi_a10_a20_ccu_resets),
+ };
+-static void __init sun4i_ccu_init(struct device_node *node,
+-                                const struct sunxi_ccu_desc *desc)
++static int sun4i_a10_ccu_probe(struct platform_device *pdev)
+ {
++      const struct sunxi_ccu_desc *desc;
+       void __iomem *reg;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%s: Could not map the clock registers\n",
+-                     of_node_full_name(node));
+-              return;
+-      }
++      desc = of_device_get_match_data(&pdev->dev);
++      if (!desc)
++              return -EINVAL;
++
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       val = readl(reg + SUN4I_PLL_AUDIO_REG);
+@@ -1464,19 +1467,30 @@ static void __init sun4i_ccu_init(struct device_node *node,
+       val &= ~GENMASK(7, 6);
+       writel(val | (2 << 6), reg + SUN4I_AHB_REG);
+-      of_sunxi_ccu_probe(node, reg, desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
+ }
+-static void __init sun4i_a10_ccu_setup(struct device_node *node)
+-{
+-      sun4i_ccu_init(node, &sun4i_a10_ccu_desc);
+-}
+-CLK_OF_DECLARE(sun4i_a10_ccu, "allwinner,sun4i-a10-ccu",
+-             sun4i_a10_ccu_setup);
++static const struct of_device_id sun4i_a10_ccu_ids[] = {
++      {
++              .compatible = "allwinner,sun4i-a10-ccu",
++              .data = &sun4i_a10_ccu_desc,
++      },
++      {
++              .compatible = "allwinner,sun7i-a20-ccu",
++              .data = &sun7i_a20_ccu_desc,
++      },
++      { }
++};
+-static void __init sun7i_a20_ccu_setup(struct device_node *node)
+-{
+-      sun4i_ccu_init(node, &sun7i_a20_ccu_desc);
+-}
+-CLK_OF_DECLARE(sun7i_a20_ccu, "allwinner,sun7i-a20-ccu",
+-             sun7i_a20_ccu_setup);
++static struct platform_driver sun4i_a10_ccu_driver = {
++      .probe  = sun4i_a10_ccu_probe,
++      .driver = {
++              .name                   = "sun4i-a10-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun4i_a10_ccu_ids,
++      },
++};
++module_platform_driver(sun4i_a10_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+index f30d7eb5424d..712e103382d8 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+@@ -4,7 +4,8 @@
+  */
+ #include <linux/clk-provider.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -221,30 +222,43 @@ static const struct sunxi_ccu_desc sun50i_h616_r_ccu_desc = {
+       .num_resets     = ARRAY_SIZE(sun50i_h616_r_ccu_resets),
+ };
+-static void __init sunxi_r_ccu_init(struct device_node *node,
+-                                  const struct sunxi_ccu_desc *desc)
++static int sun50i_h6_r_ccu_probe(struct platform_device *pdev)
+ {
++      const struct sunxi_ccu_desc *desc;
+       void __iomem *reg;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      desc = of_device_get_match_data(&pdev->dev);
++      if (!desc)
++              return -EINVAL;
+-      of_sunxi_ccu_probe(node, reg, desc);
+-}
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+-static void __init sun50i_h6_r_ccu_setup(struct device_node *node)
+-{
+-      sunxi_r_ccu_init(node, &sun50i_h6_r_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
+ }
+-CLK_OF_DECLARE(sun50i_h6_r_ccu, "allwinner,sun50i-h6-r-ccu",
+-             sun50i_h6_r_ccu_setup);
+-static void __init sun50i_h616_r_ccu_setup(struct device_node *node)
+-{
+-      sunxi_r_ccu_init(node, &sun50i_h616_r_ccu_desc);
+-}
+-CLK_OF_DECLARE(sun50i_h616_r_ccu, "allwinner,sun50i-h616-r-ccu",
+-             sun50i_h616_r_ccu_setup);
++static const struct of_device_id sun50i_h6_r_ccu_ids[] = {
++      {
++              .compatible = "allwinner,sun50i-h6-r-ccu",
++              .data = &sun50i_h6_r_ccu_desc,
++      },
++      {
++              .compatible = "allwinner,sun50i-h616-r-ccu",
++              .data = &sun50i_h616_r_ccu_desc,
++      },
++      { }
++};
++
++static struct platform_driver sun50i_h6_r_ccu_driver = {
++      .probe  = sun50i_h6_r_ccu_probe,
++      .driver = {
++              .name                   = "sun50i-h6-r-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun50i_h6_r_ccu_ids,
++      },
++};
++module_platform_driver(sun50i_h6_r_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+index 22eb18079a15..49a2474cf314 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+@@ -7,7 +7,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -1082,17 +1082,15 @@ static const u32 usb2_clk_regs[] = {
+       SUN50I_H616_USB3_CLK_REG,
+ };
+-static void __init sun50i_h616_ccu_setup(struct device_node *node)
++static int sun50i_h616_ccu_probe(struct platform_device *pdev)
+ {
+       void __iomem *reg;
+       u32 val;
+       int i;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map clock registers\n", node);
+-              return;
+-      }
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Enable the lock bits and the output enable bits on all PLLs */
+       for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
+@@ -1141,8 +1139,23 @@ static void __init sun50i_h616_ccu_setup(struct device_node *node)
+       val |= BIT(24);
+       writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG);
+-      of_sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h616_ccu_desc);
+ }
+-CLK_OF_DECLARE(sun50i_h616_ccu, "allwinner,sun50i-h616-ccu",
+-             sun50i_h616_ccu_setup);
++static const struct of_device_id sun50i_h616_ccu_ids[] = {
++      { .compatible = "allwinner,sun50i-h616-ccu" },
++      { }
++};
++
++static struct platform_driver sun50i_h616_ccu_driver = {
++      .probe  = sun50i_h616_ccu_probe,
++      .driver = {
++              .name                   = "sun50i-h616-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun50i_h616_ccu_ids,
++      },
++};
++module_platform_driver(sun50i_h616_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+index 3df5c0b41580..0762deffb33c 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
++++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+@@ -9,7 +9,8 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -1226,16 +1227,15 @@ static struct ccu_mux_nb sun6i_a31_cpu_nb = {
+       .bypass_index   = 1, /* index of 24 MHz oscillator */
+ };
+-static void __init sun6i_a31_ccu_setup(struct device_node *node)
++static int sun6i_a31_ccu_probe(struct platform_device *pdev)
+ {
+       void __iomem *reg;
++      int ret;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Force the PLL-Audio-1x divider to 1 */
+       val = readl(reg + SUN6I_A31_PLL_AUDIO_REG);
+@@ -1257,10 +1257,30 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node)
+       val |= 0x3 << 12;
+       writel(val, reg + SUN6I_A31_AHB1_REG);
+-      of_sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun6i_a31_ccu_desc);
++      if (ret)
++              return ret;
+       ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
+                                 &sun6i_a31_cpu_nb);
++
++      return 0;
+ }
+-CLK_OF_DECLARE(sun6i_a31_ccu, "allwinner,sun6i-a31-ccu",
+-             sun6i_a31_ccu_setup);
++
++static const struct of_device_id sun6i_a31_ccu_ids[] = {
++      { .compatible = "allwinner,sun6i-a31-ccu" },
++      { }
++};
++
++static struct platform_driver sun6i_a31_ccu_driver = {
++      .probe  = sun6i_a31_ccu_probe,
++      .driver = {
++              .name                   = "sun6i-a31-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun6i_a31_ccu_ids,
++      },
++};
++module_platform_driver(sun6i_a31_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+index 577bb235d658..e80cc3864e44 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+@@ -5,7 +5,8 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -724,16 +725,14 @@ static const struct sunxi_ccu_desc sun8i_a23_ccu_desc = {
+       .num_resets     = ARRAY_SIZE(sun8i_a23_ccu_resets),
+ };
+-static void __init sun8i_a23_ccu_setup(struct device_node *node)
++static int sun8i_a23_ccu_probe(struct platform_device *pdev)
+ {
+       void __iomem *reg;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Force the PLL-Audio-1x divider to 1 */
+       val = readl(reg + SUN8I_A23_PLL_AUDIO_REG);
+@@ -745,7 +744,23 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node)
+       val &= ~BIT(16);
+       writel(val, reg + SUN8I_A23_PLL_MIPI_REG);
+-      of_sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a23_ccu_desc);
+ }
+-CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu",
+-             sun8i_a23_ccu_setup);
++
++static const struct of_device_id sun8i_a23_ccu_ids[] = {
++      { .compatible = "allwinner,sun8i-a23-ccu" },
++      { }
++};
++
++static struct platform_driver sun8i_a23_ccu_driver = {
++      .probe  = sun8i_a23_ccu_probe,
++      .driver = {
++              .name                   = "sun8i-a23-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun8i_a23_ccu_ids,
++      },
++};
++module_platform_driver(sun8i_a23_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+index 8f65cd03f5ac..d12878a1ba9e 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+@@ -5,7 +5,8 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -784,16 +785,15 @@ static struct ccu_mux_nb sun8i_a33_cpu_nb = {
+       .bypass_index   = 1, /* index of 24 MHz oscillator */
+ };
+-static void __init sun8i_a33_ccu_setup(struct device_node *node)
++static int sun8i_a33_ccu_probe(struct platform_device *pdev)
+ {
+       void __iomem *reg;
++      int ret;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Force the PLL-Audio-1x divider to 1 */
+       val = readl(reg + SUN8I_A33_PLL_AUDIO_REG);
+@@ -805,7 +805,9 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
+       val &= ~BIT(16);
+       writel(val, reg + SUN8I_A33_PLL_MIPI_REG);
+-      of_sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a33_ccu_desc);
++      if (ret)
++              return ret;
+       /* Gate then ungate PLL CPU after any rate changes */
+       ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb);
+@@ -813,6 +815,24 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
+       /* Reparent CPU during PLL CPU rate changes */
+       ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
+                                 &sun8i_a33_cpu_nb);
++
++      return 0;
+ }
+-CLK_OF_DECLARE(sun8i_a33_ccu, "allwinner,sun8i-a33-ccu",
+-             sun8i_a33_ccu_setup);
++
++static const struct of_device_id sun8i_a33_ccu_ids[] = {
++      { .compatible = "allwinner,sun8i-a33-ccu" },
++      { }
++};
++
++static struct platform_driver sun8i_a33_ccu_driver = {
++      .probe  = sun8i_a33_ccu_probe,
++      .driver = {
++              .name                   = "sun8i-a33-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun8i_a33_ccu_ids,
++      },
++};
++module_platform_driver(sun8i_a33_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+index d2fc2903787d..e058cf691aea 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+@@ -5,7 +5,9 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -1137,24 +1139,29 @@ static struct ccu_mux_nb sun8i_h3_cpu_nb = {
+       .bypass_index   = 1, /* index of 24 MHz oscillator */
+ };
+-static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
+-                                      const struct sunxi_ccu_desc *desc)
++static int sun8i_h3_ccu_probe(struct platform_device *pdev)
+ {
++      const struct sunxi_ccu_desc *desc;
+       void __iomem *reg;
++      int ret;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      desc = of_device_get_match_data(&pdev->dev);
++      if (!desc)
++              return -EINVAL;
++
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Force the PLL-Audio-1x divider to 1 */
+       val = readl(reg + SUN8I_H3_PLL_AUDIO_REG);
+       val &= ~GENMASK(19, 16);
+       writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG);
+-      of_sunxi_ccu_probe(node, reg, desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
++      if (ret)
++              return ret;
+       /* Gate then ungate PLL CPU after any rate changes */
+       ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb);
+@@ -1162,18 +1169,31 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
+       /* Reparent CPU during PLL CPU rate changes */
+       ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
+                                 &sun8i_h3_cpu_nb);
+-}
+-static void __init sun8i_h3_ccu_setup(struct device_node *node)
+-{
+-      sunxi_h3_h5_ccu_init(node, &sun8i_h3_ccu_desc);
++      return 0;
+ }
+-CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu",
+-             sun8i_h3_ccu_setup);
+-static void __init sun50i_h5_ccu_setup(struct device_node *node)
+-{
+-      sunxi_h3_h5_ccu_init(node, &sun50i_h5_ccu_desc);
+-}
+-CLK_OF_DECLARE(sun50i_h5_ccu, "allwinner,sun50i-h5-ccu",
+-             sun50i_h5_ccu_setup);
++static const struct of_device_id sun8i_h3_ccu_ids[] = {
++      {
++              .compatible = "allwinner,sun8i-h3-ccu",
++              .data = &sun8i_h3_ccu_desc,
++      },
++      {
++              .compatible = "allwinner,sun50i-h5-ccu",
++              .data = &sun50i_h5_ccu_desc,
++      },
++      { }
++};
++
++static struct platform_driver sun8i_h3_ccu_driver = {
++      .probe  = sun8i_h3_ccu_probe,
++      .driver = {
++              .name                   = "sun8i-h3-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun8i_h3_ccu_ids,
++      },
++};
++module_platform_driver(sun8i_h3_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+index 9e754d1f754a..5b7fab832a52 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+@@ -4,7 +4,8 @@
+  */
+ #include <linux/clk-provider.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include "ccu_common.h"
+@@ -254,37 +255,47 @@ static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = {
+       .num_resets     = ARRAY_SIZE(sun50i_a64_r_ccu_resets),
+ };
+-static void __init sunxi_r_ccu_init(struct device_node *node,
+-                                  const struct sunxi_ccu_desc *desc)
++static int sun8i_r_ccu_probe(struct platform_device *pdev)
+ {
++      const struct sunxi_ccu_desc *desc;
+       void __iomem *reg;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      desc = of_device_get_match_data(&pdev->dev);
++      if (!desc)
++              return -EINVAL;
+-      of_sunxi_ccu_probe(node, reg, desc);
+-}
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+-static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
+-{
+-      sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
+ }
+-CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu",
+-             sun8i_a83t_r_ccu_setup);
+-static void __init sun8i_h3_r_ccu_setup(struct device_node *node)
+-{
+-      sunxi_r_ccu_init(node, &sun8i_h3_r_ccu_desc);
+-}
+-CLK_OF_DECLARE(sun8i_h3_r_ccu, "allwinner,sun8i-h3-r-ccu",
+-             sun8i_h3_r_ccu_setup);
++static const struct of_device_id sun8i_r_ccu_ids[] = {
++      {
++              .compatible = "allwinner,sun8i-a83t-r-ccu",
++              .data = &sun8i_a83t_r_ccu_desc,
++      },
++      {
++              .compatible = "allwinner,sun8i-h3-r-ccu",
++              .data = &sun8i_h3_r_ccu_desc,
++      },
++      {
++              .compatible = "allwinner,sun50i-a64-r-ccu",
++              .data = &sun50i_a64_r_ccu_desc,
++      },
++      { }
++};
+-static void __init sun50i_a64_r_ccu_setup(struct device_node *node)
+-{
+-      sunxi_r_ccu_init(node, &sun50i_a64_r_ccu_desc);
+-}
+-CLK_OF_DECLARE(sun50i_a64_r_ccu, "allwinner,sun50i-a64-r-ccu",
+-             sun50i_a64_r_ccu_setup);
++static struct platform_driver sun8i_r_ccu_driver = {
++      .probe  = sun8i_r_ccu_probe,
++      .driver = {
++              .name                   = "sun8i-r-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun8i_r_ccu_ids,
++      },
++};
++module_platform_driver(sun8i_r_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+index ce150f83ab54..87f87d6ea3ad 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+@@ -8,7 +8,9 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -805,38 +807,49 @@ static const struct sunxi_ccu_desc sun8i_v3_ccu_desc = {
+       .num_resets     = ARRAY_SIZE(sun8i_v3_ccu_resets),
+ };
+-static void __init sun8i_v3_v3s_ccu_init(struct device_node *node,
+-                                       const struct sunxi_ccu_desc *ccu_desc)
++static int sun8i_v3s_ccu_probe(struct platform_device *pdev)
+ {
++      const struct sunxi_ccu_desc *desc;
+       void __iomem *reg;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      desc = of_device_get_match_data(&pdev->dev);
++      if (!desc)
++              return -EINVAL;
++
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Force the PLL-Audio-1x divider to 1 */
+       val = readl(reg + SUN8I_V3S_PLL_AUDIO_REG);
+       val &= ~GENMASK(19, 16);
+       writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG);
+-      of_sunxi_ccu_probe(node, reg, ccu_desc);
+-}
+-
+-static void __init sun8i_v3s_ccu_setup(struct device_node *node)
+-{
+-      sun8i_v3_v3s_ccu_init(node, &sun8i_v3s_ccu_desc);
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
+ }
+-static void __init sun8i_v3_ccu_setup(struct device_node *node)
+-{
+-      sun8i_v3_v3s_ccu_init(node, &sun8i_v3_ccu_desc);
+-}
++static const struct of_device_id sun8i_v3s_ccu_ids[] = {
++      {
++              .compatible = "allwinner,sun8i-v3-ccu",
++              .data = &sun8i_v3_ccu_desc,
++      },
++      {
++              .compatible = "allwinner,sun8i-v3s-ccu",
++              .data = &sun8i_v3s_ccu_desc,
++      },
++      { }
++};
+-CLK_OF_DECLARE(sun8i_v3s_ccu, "allwinner,sun8i-v3s-ccu",
+-             sun8i_v3s_ccu_setup);
++static struct platform_driver sun8i_v3s_ccu_driver = {
++      .probe  = sun8i_v3s_ccu_probe,
++      .driver = {
++              .name                   = "sun8i-v3s-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun8i_v3s_ccu_ids,
++      },
++};
++module_platform_driver(sun8i_v3s_ccu_driver);
+-CLK_OF_DECLARE(sun8i_v3_ccu, "allwinner,sun8i-v3-ccu",
+-             sun8i_v3_ccu_setup);
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+index 61ad7ee91c11..a36dcab517e3 100644
+--- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
++++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+@@ -6,7 +6,8 @@
+ #include <linux/clk-provider.h>
+ #include <linux/io.h>
+-#include <linux/of_address.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
+ #include "ccu_common.h"
+ #include "ccu_reset.h"
+@@ -525,20 +526,21 @@ static struct ccu_mux_nb suniv_cpu_nb = {
+ static void __init suniv_f1c100s_ccu_setup(struct device_node *node)
+ {
+       void __iomem *reg;
++      int ret;
+       u32 val;
+-      reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+-      if (IS_ERR(reg)) {
+-              pr_err("%pOF: Could not map the clock registers\n", node);
+-              return;
+-      }
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
+       /* Force the PLL-Audio-1x divider to 4 */
+       val = readl(reg + SUNIV_PLL_AUDIO_REG);
+       val &= ~GENMASK(19, 16);
+       writel(val | (3 << 16), reg + SUNIV_PLL_AUDIO_REG);
+-      of_sunxi_ccu_probe(node, reg, &suniv_ccu_desc);
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &suniv_ccu_desc);
++      if (ret)
++              return ret;
+       /* Gate then ungate PLL CPU after any rate changes */
+       ccu_pll_notifier_register(&suniv_pll_cpu_nb);
+@@ -546,6 +548,24 @@ static void __init suniv_f1c100s_ccu_setup(struct device_node *node)
+       /* Reparent CPU during PLL CPU rate changes */
+       ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
+                                 &suniv_cpu_nb);
++
++      return 0;
+ }
+-CLK_OF_DECLARE(suniv_f1c100s_ccu, "allwinner,suniv-f1c100s-ccu",
+-             suniv_f1c100s_ccu_setup);
++
++static const struct of_device_id suniv_f1c100s_ccu_ids[] = {
++      { .compatible = "allwinner,suniv-f1c100s-ccu" },
++      { }
++};
++
++static struct platform_driver suniv_f1c100s_ccu_driver = {
++      .probe  = suniv_f1c100s_ccu_probe,
++      .driver = {
++              .name                   = "suniv-f1c100s-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = suniv_f1c100s_ccu_ids,
++      },
++};
++module_platform_driver(suniv_f1c100s_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0039-clk-sunxi-ng-Allow-the-CCU-core-to-be-built-as-a-mod.patch b/target/linux/sunxid1/patches-5.15/0039-clk-sunxi-ng-Allow-the-CCU-core-to-be-built-as-a-mod.patch
new file mode 100644 (file)
index 0000000..265195c
--- /dev/null
@@ -0,0 +1,176 @@
+From c1ddd74ba3ddff59352333477f66a85bbfb414eb Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 18 Jul 2021 18:10:44 -0500
+Subject: [PATCH 039/124] clk: sunxi-ng: Allow the CCU core to be built as a
+ module
+
+Like the individual CCU drivers, it can be beneficial for memory
+consumption of cross-platform configurations to only load the CCU core
+on the relevant platform. For example, a generic arm64 kernel sees the
+following improvement when building the CCU core and drivers as modules:
+
+  before:
+    text      data     bss     dec       hex      filename
+    13882360  5251670  360800  19494830  12977ae  vmlinux
+
+  after:
+    text      data     bss     dec       hex      filename
+    13734787  5086442  360800  19182029  124b1cd  vmlinux
+
+So the result is a 390KB total reduction in kernel image size.
+
+The one early clock provider (sun5i) requires the core to be built in.
+
+Now that loading the MMC driver will trigger loading the CCU core, the
+MMC timing mode functions do not need a compile-time fallback.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/Makefile              |  2 +-
+ drivers/clk/sunxi-ng/Kconfig      |  3 ++-
+ drivers/clk/sunxi-ng/Makefile     | 33 +++++++++++++++++--------------
+ drivers/clk/sunxi-ng/ccu_common.c |  3 +++
+ drivers/mmc/host/Kconfig          |  1 +
+ include/linux/clk/sunxi-ng.h      | 15 --------------
+ 6 files changed, 25 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
+index e42312121e51..6afe36bd2c0a 100644
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -110,7 +110,7 @@ obj-$(CONFIG_PLAT_SPEAR)           += spear/
+ obj-y                                 += sprd/
+ obj-$(CONFIG_ARCH_STI)                        += st/
+ obj-$(CONFIG_ARCH_SUNXI)              += sunxi/
+-obj-$(CONFIG_SUNXI_CCU)                       += sunxi-ng/
++obj-y                                 += sunxi-ng/
+ obj-$(CONFIG_ARCH_TEGRA)              += tegra/
+ obj-y                                 += ti/
+ obj-$(CONFIG_CLK_UNIPHIER)            += uniphier/
+diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
+index cbae3612a9ef..ee383658ff4d 100644
+--- a/drivers/clk/sunxi-ng/Kconfig
++++ b/drivers/clk/sunxi-ng/Kconfig
+@@ -1,6 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ config SUNXI_CCU
+-      bool "Clock support for Allwinner SoCs"
++      tristate "Clock support for Allwinner SoCs"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       select RESET_CONTROLLER
+       default ARCH_SUNXI
+@@ -52,6 +52,7 @@ config SUN5I_CCU
+       bool "Support for the Allwinner sun5i family CCM"
+       default MACH_SUN5I
+       depends on MACH_SUN5I || COMPILE_TEST
++      depends on SUNXI_CCU=y
+ config SUN6I_A31_CCU
+       tristate "Support for the Allwinner A31/A31s CCU"
+diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
+index 1020ed49a588..659d55150c32 100644
+--- a/drivers/clk/sunxi-ng/Makefile
++++ b/drivers/clk/sunxi-ng/Makefile
+@@ -1,24 +1,27 @@
+ # SPDX-License-Identifier: GPL-2.0
++
++obj-$(CONFIG_SUNXI_CCU)               += sunxi-ccu.o
++
+ # Common objects
+-obj-y                         += ccu_common.o
+-obj-y                         += ccu_mmc_timing.o
+-obj-y                         += ccu_reset.o
++sunxi-ccu-y                   += ccu_common.o
++sunxi-ccu-y                   += ccu_mmc_timing.o
++sunxi-ccu-y                   += ccu_reset.o
+ # Base clock types
+-obj-y                         += ccu_div.o
+-obj-y                         += ccu_frac.o
+-obj-y                         += ccu_gate.o
+-obj-y                         += ccu_mux.o
+-obj-y                         += ccu_mult.o
+-obj-y                         += ccu_phase.o
+-obj-y                         += ccu_sdm.o
++sunxi-ccu-y                   += ccu_div.o
++sunxi-ccu-y                   += ccu_frac.o
++sunxi-ccu-y                   += ccu_gate.o
++sunxi-ccu-y                   += ccu_mux.o
++sunxi-ccu-y                   += ccu_mult.o
++sunxi-ccu-y                   += ccu_phase.o
++sunxi-ccu-y                   += ccu_sdm.o
+ # Multi-factor clocks
+-obj-y                         += ccu_nk.o
+-obj-y                         += ccu_nkm.o
+-obj-y                         += ccu_nkmp.o
+-obj-y                         += ccu_nm.o
+-obj-y                         += ccu_mp.o
++sunxi-ccu-y                   += ccu_nk.o
++sunxi-ccu-y                   += ccu_nkm.o
++sunxi-ccu-y                   += ccu_nkmp.o
++sunxi-ccu-y                   += ccu_nm.o
++sunxi-ccu-y                   += ccu_mp.o
+ # SoC support
+ obj-$(CONFIG_SUNIV_F1C100S_CCU)       += suniv-f1c100s-ccu.o
+diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
+index 6afdedbce6a2..8d28a7a079d0 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.c
++++ b/drivers/clk/sunxi-ng/ccu_common.c
+@@ -9,6 +9,7 @@
+ #include <linux/clk-provider.h>
+ #include <linux/device.h>
+ #include <linux/iopoll.h>
++#include <linux/module.h>
+ #include <linux/slab.h>
+ #include "ccu_common.h"
+@@ -214,3 +215,5 @@ void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+               kfree(ccu);
+       }
+ }
++
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index ccc148cdb5ee..cd9f3c626053 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -964,6 +964,7 @@ config MMC_REALTEK_USB
+ config MMC_SUNXI
+       tristate "Allwinner sunxi SD/MMC Host Controller support"
+       depends on ARCH_SUNXI || COMPILE_TEST
++      depends on SUNXI_CCU
+       help
+         This selects support for the SD/MMC Host Controller on
+         Allwinner sunxi SoCs.
+diff --git a/include/linux/clk/sunxi-ng.h b/include/linux/clk/sunxi-ng.h
+index 3cd14acde0a1..cf32123b39f5 100644
+--- a/include/linux/clk/sunxi-ng.h
++++ b/include/linux/clk/sunxi-ng.h
+@@ -6,22 +6,7 @@
+ #ifndef _LINUX_CLK_SUNXI_NG_H_
+ #define _LINUX_CLK_SUNXI_NG_H_
+-#include <linux/errno.h>
+-
+-#ifdef CONFIG_SUNXI_CCU
+ int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode);
+ int sunxi_ccu_get_mmc_timing_mode(struct clk *clk);
+-#else
+-static inline int sunxi_ccu_set_mmc_timing_mode(struct clk *clk,
+-                                              bool new_mode)
+-{
+-      return -ENOTSUPP;
+-}
+-
+-static inline int sunxi_ccu_get_mmc_timing_mode(struct clk *clk)
+-{
+-      return -ENOTSUPP;
+-}
+-#endif
+ #endif
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0040-clk-sunxi-ng-mux-Allow-muxes-to-have-keys.patch b/target/linux/sunxid1/patches-5.15/0040-clk-sunxi-ng-mux-Allow-muxes-to-have-keys.patch
new file mode 100644 (file)
index 0000000..eb58ba4
--- /dev/null
@@ -0,0 +1,63 @@
+From 88f4f9b057dda3d521fb13d7a7fbd09cf95fda41 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 20 May 2021 00:07:32 -0500
+Subject: [PATCH 040/124] clk: sunxi-ng: mux: Allow muxes to have keys
+
+The muxes in the RTC can only be updated when setting a key field to a
+specific value. Add a feature flag to denote muxes with this property.
+
+Since so far the key value is always the same, it does not need to be
+provided separately for each mux.
+
+Series-changes: 3
+ - Drop the SUNXI_CCU_MUX_HW_WITH_KEY macro, since it is no longer used.
+
+Cover-changes: 3
+ - Also drop the patch adding the SUNXI_CCU_MUX_DATA_WITH_GATE macro.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu_common.h | 1 +
+ drivers/clk/sunxi-ng/ccu_mux.c    | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
+index 98a1834b58bb..fbf16c6b896d 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.h
++++ b/drivers/clk/sunxi-ng/ccu_common.h
+@@ -17,6 +17,7 @@
+ #define CCU_FEATURE_LOCK_REG          BIT(5)
+ #define CCU_FEATURE_MMC_TIMING_SWITCH BIT(6)
+ #define CCU_FEATURE_SIGMA_DELTA_MOD   BIT(7)
++#define CCU_FEATURE_KEY_FIELD         BIT(8)
+ /* MMC timing mode switch bit */
+ #define CCU_MMC_NEW_TIMING_MODE               BIT(30)
+diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
+index 2306a1cd83e4..1d557e323169 100644
+--- a/drivers/clk/sunxi-ng/ccu_mux.c
++++ b/drivers/clk/sunxi-ng/ccu_mux.c
+@@ -12,6 +12,8 @@
+ #include "ccu_gate.h"
+ #include "ccu_mux.h"
++#define CCU_MUX_KEY_VALUE             0x16aa0000
++
+ static u16 ccu_mux_get_prediv(struct ccu_common *common,
+                             struct ccu_mux_internal *cm,
+                             int parent_index)
+@@ -191,6 +193,11 @@ int ccu_mux_helper_set_parent(struct ccu_common *common,
+       spin_lock_irqsave(common->lock, flags);
+       reg = readl(common->base + common->reg);
++
++      /* The key field always reads as zero. */
++      if (common->features & CCU_FEATURE_KEY_FIELD)
++              reg |= CCU_MUX_KEY_VALUE;
++
+       reg &= ~GENMASK(cm->width + cm->shift - 1, cm->shift);
+       writel(reg | (index << cm->shift), common->base + common->reg);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0041-of-irq-Use-interrupts-extended-to-find-parent.patch b/target/linux/sunxid1/patches-5.15/0041-of-irq-Use-interrupts-extended-to-find-parent.patch
new file mode 100644 (file)
index 0000000..1db738b
--- /dev/null
@@ -0,0 +1,59 @@
+From 442fb5f5b81fbf5535d77859af73d2c05c930956 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:43:58 -0500
+Subject: [PATCH 041/124] of/irq: Use interrupts-extended to find parent
+
+Some OF irqchips, such as the RISC-V PLIC, use interrupts-extended to
+specify their parent domain(s). So that binding does not allow using the
+interrupt-parent property in the irqchip node. That prevents of_irq_init
+from properly detecting the irqchip hierarchy.
+
+If no interrupt-parent property is present in the enclosing bus or root
+node, then desc->interrupt_parent will be NULL for both the per-CPU
+RISC-V INTCs (the actual root domains) and the PLIC. Similarly, if the
+bus or root node specifies `interrupt-parent = <&plic>`, then
+of_irq_init will hit the `desc->interrupt_parent == np` check, and again
+all parents will be NULL. So things happen to work today for some boards
+due to Makefile ordering.
+
+However, things break when another irqchip (call it "foo") is stacked
+with the PLIC. The bus/root node will have `interrupt-parent = <&foo>`,
+since that is what all of the other peripherals need. When of_irq_init
+runs, it will try to find the PLIC's parent domain. But because
+of_irq_find_parent ignores interrupts-extended, it will fall back to the
+interrupt-parent of the PLIC's parent node (i.e. the bus or root node),
+and see "foo" as the PLIC's parent domain. But this is wrong, because
+"foo" is actually the PLIC's child domain!
+
+So of_irq_init wrongly attempts to init the stacked irqchip before the
+PLIC. This fails and prevents boot.
+
+Fix this by having of_irq_find_parent return the first node referenced
+by interrupts-extended when that property is present. Even if the
+property references multiple different IRQ domains, this will still work
+reliably in of_irq_init as long as all referenced domains are the same
+distance from some root domain (e.g. the RISC-V INTCs referenced by the
+PLIC are always all root domains).
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/of/irq.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/of/irq.c b/drivers/of/irq.c
+index 352e14b007e7..d84d27fb2203 100644
+--- a/drivers/of/irq.c
++++ b/drivers/of/irq.c
+@@ -60,7 +60,8 @@ struct device_node *of_irq_find_parent(struct device_node *child)
+               return NULL;
+       do {
+-              if (of_property_read_u32(child, "interrupt-parent", &parent)) {
++              if (of_property_read_u32(child, "interrupt-parent", &parent) &&
++                  of_property_read_u32(child, "interrupts-extended", &parent)) {
+                       p = of_get_parent(child);
+               } else  {
+                       if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0042-RISC-V-Use-SBI-SRST-extension-when-available.patch b/target/linux/sunxid1/patches-5.15/0042-RISC-V-Use-SBI-SRST-extension-when-available.patch
new file mode 100644 (file)
index 0000000..cede184
--- /dev/null
@@ -0,0 +1,134 @@
+From 10c33c9b9734fc0c93d4766c1c7bfa87739ef712 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Fri, 25 Sep 2020 11:40:49 +0530
+Subject: [PATCH 042/124] RISC-V: Use SBI SRST extension when available
+
+The SBI SRST extension provides a standard way to poweroff and
+reboot the system irrespective to whether Linux RISC-V S-mode
+is running natively (HS-mode) or inside Guest/VM (VS-mode).
+
+The SBI SRST extension is available in the SBI v0.3 specification.
+(Refer, https://github.com/riscv-non-isa/riscv-sbi-doc/releases/tag/v0.3.0)
+
+This patch extends Linux RISC-V SBI implementation to detect
+and use SBI SRST extension.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+Reviewed-by: Atish Patra <atish.patra@wdc.com>
+---
+ arch/riscv/include/asm/sbi.h | 24 ++++++++++++++++++++++++
+ arch/riscv/kernel/sbi.c      | 35 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 59 insertions(+)
+
+diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
+index 0d42693cb65e..289621da4a2a 100644
+--- a/arch/riscv/include/asm/sbi.h
++++ b/arch/riscv/include/asm/sbi.h
+@@ -27,6 +27,7 @@ enum sbi_ext_id {
+       SBI_EXT_IPI = 0x735049,
+       SBI_EXT_RFENCE = 0x52464E43,
+       SBI_EXT_HSM = 0x48534D,
++      SBI_EXT_SRST = 0x53525354,
+ };
+ enum sbi_ext_base_fid {
+@@ -70,6 +71,21 @@ enum sbi_hsm_hart_status {
+       SBI_HSM_HART_STATUS_STOP_PENDING,
+ };
++enum sbi_ext_srst_fid {
++      SBI_EXT_SRST_RESET = 0,
++};
++
++enum sbi_srst_reset_type {
++      SBI_SRST_RESET_TYPE_SHUTDOWN = 0,
++      SBI_SRST_RESET_TYPE_COLD_REBOOT,
++      SBI_SRST_RESET_TYPE_WARM_REBOOT,
++};
++
++enum sbi_srst_reset_reason {
++      SBI_SRST_RESET_REASON_NONE = 0,
++      SBI_SRST_RESET_REASON_SYS_FAILURE,
++};
++
+ #define SBI_SPEC_VERSION_DEFAULT      0x1
+ #define SBI_SPEC_VERSION_MAJOR_SHIFT  24
+ #define SBI_SPEC_VERSION_MAJOR_MASK   0x7f
+@@ -148,6 +164,14 @@ static inline unsigned long sbi_minor_version(void)
+       return sbi_spec_version & SBI_SPEC_VERSION_MINOR_MASK;
+ }
++/* Make SBI version */
++static inline unsigned long sbi_mk_version(unsigned long major,
++                                          unsigned long minor)
++{
++      return ((major & SBI_SPEC_VERSION_MAJOR_MASK) <<
++              SBI_SPEC_VERSION_MAJOR_SHIFT) | minor;
++}
++
+ int sbi_err_map_linux_errno(int err);
+ #else /* CONFIG_RISCV_SBI */
+ static inline int sbi_remote_fence_i(const unsigned long *hart_mask) { return -1; }
+diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
+index 7402a417f38e..9a84f0cb5175 100644
+--- a/arch/riscv/kernel/sbi.c
++++ b/arch/riscv/kernel/sbi.c
+@@ -7,6 +7,7 @@
+ #include <linux/init.h>
+ #include <linux/pm.h>
++#include <linux/reboot.h>
+ #include <asm/sbi.h>
+ #include <asm/smp.h>
+@@ -501,6 +502,32 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
+ }
+ EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
++static void sbi_srst_reset(unsigned long type, unsigned long reason)
++{
++      sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason,
++                0, 0, 0, 0);
++      pr_warn("%s: type=0x%lx reason=0x%lx failed\n",
++              __func__, type, reason);
++}
++
++static int sbi_srst_reboot(struct notifier_block *this,
++                         unsigned long mode, void *cmd)
++{
++      sbi_srst_reset((mode == REBOOT_WARM || mode == REBOOT_SOFT) ?
++                     SBI_SRST_RESET_TYPE_WARM_REBOOT :
++                     SBI_SRST_RESET_TYPE_COLD_REBOOT,
++                     SBI_SRST_RESET_REASON_NONE);
++      return NOTIFY_DONE;
++}
++
++static struct notifier_block sbi_srst_reboot_nb;
++
++static void sbi_srst_power_off(void)
++{
++      sbi_srst_reset(SBI_SRST_RESET_TYPE_SHUTDOWN,
++                     SBI_SRST_RESET_REASON_NONE);
++}
++
+ /**
+  * sbi_probe_extension() - Check if an SBI extension ID is supported or not.
+  * @extid: The extension ID to be probed.
+@@ -608,6 +635,14 @@ void __init sbi_init(void)
+               } else {
+                       __sbi_rfence    = __sbi_rfence_v01;
+               }
++              if ((sbi_spec_version >= sbi_mk_version(0, 3)) &&
++                  (sbi_probe_extension(SBI_EXT_SRST) > 0)) {
++                      pr_info("SBI SRST extension detected\n");
++                      pm_power_off = sbi_srst_power_off;
++                      sbi_srst_reboot_nb.notifier_call = sbi_srst_reboot;
++                      sbi_srst_reboot_nb.priority = 192;
++                      register_restart_handler(&sbi_srst_reboot_nb);
++              }
+       } else {
+               __sbi_set_timer = __sbi_set_timer_v01;
+               __sbi_send_ipi  = __sbi_send_ipi_v01;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0043-RISC-V-Enable-CPU_IDLE-drivers.patch b/target/linux/sunxid1/patches-5.15/0043-RISC-V-Enable-CPU_IDLE-drivers.patch
new file mode 100644 (file)
index 0000000..208aa1f
--- /dev/null
@@ -0,0 +1,119 @@
+From 1efcd21929800a5435e6f6cfcf8397f7fe621a33 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Mon, 8 Feb 2021 17:00:06 +0530
+Subject: [PATCH 043/124] RISC-V: Enable CPU_IDLE drivers
+
+We force select CPU_PM and provide asm/cpuidle.h so that we can
+use CPU IDLE drivers for Linux RISC-V kernel.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/Kconfig                |  7 +++++++
+ arch/riscv/configs/defconfig      |  1 +
+ arch/riscv/configs/rv32_defconfig |  1 +
+ arch/riscv/include/asm/cpuidle.h  | 24 ++++++++++++++++++++++++
+ arch/riscv/kernel/process.c       |  3 ++-
+ 5 files changed, 35 insertions(+), 1 deletion(-)
+ create mode 100644 arch/riscv/include/asm/cpuidle.h
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index c28b743eba57..655f35ea2e74 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -45,6 +45,7 @@ config RISCV
+       select CLONE_BACKWARDS
+       select CLINT_TIMER if !MMU
+       select COMMON_CLK
++      select CPU_PM if CPU_IDLE
+       select EDAC_SUPPORT
+       select GENERIC_ARCH_TOPOLOGY if SMP
+       select GENERIC_ATOMIC64 if !64BIT
+@@ -566,3 +567,9 @@ menu "Power management options"
+ source "kernel/power/Kconfig"
+ endmenu
++
++menu "CPU Power Management"
++
++source "drivers/cpuidle/Kconfig"
++
++endmenu
+diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
+index 4ebc80315f01..66552914be3f 100644
+--- a/arch/riscv/configs/defconfig
++++ b/arch/riscv/configs/defconfig
+@@ -19,6 +19,7 @@ CONFIG_SOC_VIRT=y
+ CONFIG_SOC_MICROCHIP_POLARFIRE=y
+ CONFIG_SMP=y
+ CONFIG_HOTPLUG_CPU=y
++CONFIG_CPU_IDLE=y
+ CONFIG_JUMP_LABEL=y
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
+index 434ef5b64599..3093f8efd7e5 100644
+--- a/arch/riscv/configs/rv32_defconfig
++++ b/arch/riscv/configs/rv32_defconfig
+@@ -19,6 +19,7 @@ CONFIG_SOC_VIRT=y
+ CONFIG_ARCH_RV32I=y
+ CONFIG_SMP=y
+ CONFIG_HOTPLUG_CPU=y
++CONFIG_CPU_IDLE=y
+ CONFIG_JUMP_LABEL=y
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+diff --git a/arch/riscv/include/asm/cpuidle.h b/arch/riscv/include/asm/cpuidle.h
+new file mode 100644
+index 000000000000..71fdc607d4bc
+--- /dev/null
++++ b/arch/riscv/include/asm/cpuidle.h
+@@ -0,0 +1,24 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2021 Allwinner Ltd
++ * Copyright (C) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#ifndef _ASM_RISCV_CPUIDLE_H
++#define _ASM_RISCV_CPUIDLE_H
++
++#include <asm/barrier.h>
++#include <asm/processor.h>
++
++static inline void cpu_do_idle(void)
++{
++      /*
++       * Add mb() here to ensure that all
++       * IO/MEM accesses are completed prior
++       * to entering WFI.
++       */
++      mb();
++      wait_for_interrupt();
++}
++
++#endif
+diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
+index 03ac3aa611f5..504b496787aa 100644
+--- a/arch/riscv/kernel/process.c
++++ b/arch/riscv/kernel/process.c
+@@ -23,6 +23,7 @@
+ #include <asm/string.h>
+ #include <asm/switch_to.h>
+ #include <asm/thread_info.h>
++#include <asm/cpuidle.h>
+ register unsigned long gp_in_global __asm__("gp");
+@@ -37,7 +38,7 @@ extern asmlinkage void ret_from_kernel_thread(void);
+ void arch_cpu_idle(void)
+ {
+-      wait_for_interrupt();
++      cpu_do_idle();
+       raw_local_irq_enable();
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0044-RISC-V-Rename-relocate-and-make-it-global.patch b/target/linux/sunxid1/patches-5.15/0044-RISC-V-Rename-relocate-and-make-it-global.patch
new file mode 100644 (file)
index 0000000..b259064
--- /dev/null
@@ -0,0 +1,53 @@
+From 10b6c02d5a9baadfeb9b1d16ef2c62de35d8bfa5 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Sun, 10 Oct 2021 10:52:13 +0530
+Subject: [PATCH 044/124] RISC-V: Rename relocate() and make it global
+
+The low-level relocate() function enables mmu and relocates
+execution to link-time addresses. We rename relocate() function
+to relocate_enable_mmu() function which is more informative.
+
+Also, the relocate_enable_mmu() function will be used in the
+resume path when a CPU wakes-up from a non-retentive suspend
+so we make it global symbol.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+---
+ arch/riscv/kernel/head.S | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
+index ebd577b51c5c..ab3248f9cd25 100644
+--- a/arch/riscv/kernel/head.S
++++ b/arch/riscv/kernel/head.S
+@@ -89,7 +89,8 @@ pe_head_start:
+ .align 2
+ #ifdef CONFIG_MMU
+-relocate:
++      .global relocate_enable_mmu
++relocate_enable_mmu:
+       /* Relocate return address */
+       la a1, kernel_map
+       XIP_FIXUP_OFFSET a1
+@@ -184,7 +185,7 @@ secondary_start_common:
+       /* Enable virtual memory and relocate to virtual address */
+       la a0, swapper_pg_dir
+       XIP_FIXUP_OFFSET a0
+-      call relocate
++      call relocate_enable_mmu
+ #endif
+       call setup_trap_vector
+       tail smp_callin
+@@ -324,7 +325,7 @@ clear_bss_done:
+ #ifdef CONFIG_MMU
+       la a0, early_pg_dir
+       XIP_FIXUP_OFFSET a0
+-      call relocate
++      call relocate_enable_mmu
+ #endif /* CONFIG_MMU */
+       call setup_trap_vector
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0045-RISC-V-Add-arch-functions-for-non-retentive-suspend-.patch b/target/linux/sunxid1/patches-5.15/0045-RISC-V-Add-arch-functions-for-non-retentive-suspend-.patch
new file mode 100644 (file)
index 0000000..130c41f
--- /dev/null
@@ -0,0 +1,394 @@
+From c79b186f87c991b22271451520d211de26e5fd7d Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Wed, 10 Feb 2021 09:13:08 +0530
+Subject: [PATCH 045/124] RISC-V: Add arch functions for non-retentive suspend
+ entry/exit
+
+The hart registers and CSRs are not preserved in non-retentative
+suspend state so we provide arch specific helper functions which
+will save/restore hart context upon entry/exit to non-retentive
+suspend state. These helper functions can be used by cpuidle
+drivers for non-retentive suspend entry/exit.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/include/asm/asm.h      |  27 +++++++
+ arch/riscv/include/asm/suspend.h  |  35 +++++++++
+ arch/riscv/kernel/Makefile        |   2 +
+ arch/riscv/kernel/asm-offsets.c   |   3 +
+ arch/riscv/kernel/head.S          |  21 -----
+ arch/riscv/kernel/suspend.c       |  86 +++++++++++++++++++++
+ arch/riscv/kernel/suspend_entry.S | 123 ++++++++++++++++++++++++++++++
+ 7 files changed, 276 insertions(+), 21 deletions(-)
+ create mode 100644 arch/riscv/include/asm/suspend.h
+ create mode 100644 arch/riscv/kernel/suspend.c
+ create mode 100644 arch/riscv/kernel/suspend_entry.S
+
+diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h
+index 618d7c5af1a2..8afd81ad0c1e 100644
+--- a/arch/riscv/include/asm/asm.h
++++ b/arch/riscv/include/asm/asm.h
+@@ -67,4 +67,31 @@
+ #error "Unexpected __SIZEOF_SHORT__"
+ #endif
++#ifdef __ASSEMBLY__
++
++/* Common assembly source macros */
++
++#ifdef CONFIG_XIP_KERNEL
++.macro XIP_FIXUP_OFFSET reg
++      REG_L t0, _xip_fixup
++      add \reg, \reg, t0
++.endm
++.macro XIP_FIXUP_FLASH_OFFSET reg
++      la t1, __data_loc
++      li t0, XIP_OFFSET_MASK
++      and t1, t1, t0
++      li t1, XIP_OFFSET
++      sub t0, t0, t1
++      sub \reg, \reg, t0
++.endm
++_xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET
++#else
++.macro XIP_FIXUP_OFFSET reg
++.endm
++.macro XIP_FIXUP_FLASH_OFFSET reg
++.endm
++#endif /* CONFIG_XIP_KERNEL */
++
++#endif
++
+ #endif /* _ASM_RISCV_ASM_H */
+diff --git a/arch/riscv/include/asm/suspend.h b/arch/riscv/include/asm/suspend.h
+new file mode 100644
+index 000000000000..63e9f434fb89
+--- /dev/null
++++ b/arch/riscv/include/asm/suspend.h
+@@ -0,0 +1,35 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#ifndef _ASM_RISCV_SUSPEND_H
++#define _ASM_RISCV_SUSPEND_H
++
++#include <asm/ptrace.h>
++
++struct suspend_context {
++      /* Saved and restored by low-level functions */
++      struct pt_regs regs;
++      /* Saved and restored by high-level functions */
++      unsigned long scratch;
++      unsigned long tvec;
++      unsigned long ie;
++#ifdef CONFIG_MMU
++      unsigned long satp;
++#endif
++};
++
++/* Low-level CPU suspend entry function */
++int __cpu_suspend_enter(struct suspend_context *context);
++
++/* High-level CPU suspend which will save context and call finish() */
++int cpu_suspend(unsigned long arg,
++              int (*finish)(unsigned long arg,
++                            unsigned long entry,
++                            unsigned long context));
++
++/* Low-level CPU resume entry function */
++int __cpu_resume_enter(unsigned long hartid, unsigned long context);
++
++#endif
+diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
+index 3397ddac1a30..4320629c07c3 100644
+--- a/arch/riscv/kernel/Makefile
++++ b/arch/riscv/kernel/Makefile
+@@ -47,6 +47,8 @@ obj-$(CONFIG_SMP)            += cpu_ops_spinwait.o
+ obj-$(CONFIG_MODULES)         += module.o
+ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
++obj-$(CONFIG_CPU_PM)          += suspend_entry.o suspend.o
++
+ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
+ obj-$(CONFIG_DYNAMIC_FTRACE)  += mcount-dyn.o
+diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
+index 90f8ce64fa6f..cf64dab398da 100644
+--- a/arch/riscv/kernel/asm-offsets.c
++++ b/arch/riscv/kernel/asm-offsets.c
+@@ -10,6 +10,7 @@
+ #include <linux/sched.h>
+ #include <asm/thread_info.h>
+ #include <asm/ptrace.h>
++#include <asm/suspend.h>
+ void asm_offsets(void);
+@@ -306,6 +307,8 @@ void asm_offsets(void)
+               - offsetof(struct task_struct, thread.fstate.f[0])
+       );
++      OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs);
++
+       /*
+        * We allocate a pt_regs on the stack when entering the kernel.  This
+        * ensures the alignment is sane.
+diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
+index ab3248f9cd25..141a1ac308f7 100644
+--- a/arch/riscv/kernel/head.S
++++ b/arch/riscv/kernel/head.S
+@@ -15,27 +15,6 @@
+ #include <asm/image.h>
+ #include "efi-header.S"
+-#ifdef CONFIG_XIP_KERNEL
+-.macro XIP_FIXUP_OFFSET reg
+-      REG_L t0, _xip_fixup
+-      add \reg, \reg, t0
+-.endm
+-.macro XIP_FIXUP_FLASH_OFFSET reg
+-      la t1, __data_loc
+-      li t0, XIP_OFFSET_MASK
+-      and t1, t1, t0
+-      li t1, XIP_OFFSET
+-      sub t0, t0, t1
+-      sub \reg, \reg, t0
+-.endm
+-_xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET
+-#else
+-.macro XIP_FIXUP_OFFSET reg
+-.endm
+-.macro XIP_FIXUP_FLASH_OFFSET reg
+-.endm
+-#endif /* CONFIG_XIP_KERNEL */
+-
+ __HEAD
+ ENTRY(_start)
+       /*
+diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c
+new file mode 100644
+index 000000000000..49dddec30e99
+--- /dev/null
++++ b/arch/riscv/kernel/suspend.c
+@@ -0,0 +1,86 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#include <linux/ftrace.h>
++#include <asm/csr.h>
++#include <asm/suspend.h>
++
++static void suspend_save_csrs(struct suspend_context *context)
++{
++      context->scratch = csr_read(CSR_SCRATCH);
++      context->tvec = csr_read(CSR_TVEC);
++      context->ie = csr_read(CSR_IE);
++
++      /*
++       * No need to save/restore IP CSR (i.e. MIP or SIP) because:
++       *
++       * 1. For no-MMU (M-mode) kernel, the bits in MIP are set by
++       *    external devices (such as interrupt controller, timer, etc).
++       * 2. For MMU (S-mode) kernel, the bits in SIP are set by
++       *    M-mode firmware and external devices (such as interrupt
++       *    controller, etc).
++       */
++
++#ifdef CONFIG_MMU
++      context->satp = csr_read(CSR_SATP);
++#endif
++}
++
++static void suspend_restore_csrs(struct suspend_context *context)
++{
++      csr_write(CSR_SCRATCH, context->scratch);
++      csr_write(CSR_TVEC, context->tvec);
++      csr_write(CSR_IE, context->ie);
++
++#ifdef CONFIG_MMU
++      csr_write(CSR_SATP, context->satp);
++#endif
++}
++
++int cpu_suspend(unsigned long arg,
++              int (*finish)(unsigned long arg,
++                            unsigned long entry,
++                            unsigned long context))
++{
++      int rc = 0;
++      struct suspend_context context = { 0 };
++
++      /* Finisher should be non-NULL */
++      if (!finish)
++              return -EINVAL;
++
++      /* Save additional CSRs*/
++      suspend_save_csrs(&context);
++
++      /*
++       * Function graph tracer state gets incosistent when the kernel
++       * calls functions that never return (aka finishers) hence disable
++       * graph tracing during their execution.
++       */
++      pause_graph_tracing();
++
++      /* Save context on stack */
++      if (__cpu_suspend_enter(&context)) {
++              /* Call the finisher */
++              rc = finish(arg, __pa_symbol(__cpu_resume_enter),
++                          (ulong)&context);
++
++              /*
++               * Should never reach here, unless the suspend finisher
++               * fails. Successful cpu_suspend() should return from
++               * __cpu_resume_entry()
++               */
++              if (!rc)
++                      rc = -EOPNOTSUPP;
++      }
++
++      /* Enable function graph tracer */
++      unpause_graph_tracing();
++
++      /* Restore additional CSRs */
++      suspend_restore_csrs(&context);
++
++      return rc;
++}
+diff --git a/arch/riscv/kernel/suspend_entry.S b/arch/riscv/kernel/suspend_entry.S
+new file mode 100644
+index 000000000000..b8d20decfc28
+--- /dev/null
++++ b/arch/riscv/kernel/suspend_entry.S
+@@ -0,0 +1,123 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#include <linux/linkage.h>
++#include <asm/asm.h>
++#include <asm/asm-offsets.h>
++#include <asm/csr.h>
++
++      .text
++      .altmacro
++      .option norelax
++
++ENTRY(__cpu_suspend_enter)
++      /* Save registers (except A0 and T0-T6) */
++      REG_S   ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0)
++      REG_S   sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0)
++      REG_S   gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0)
++      REG_S   tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0)
++      REG_S   s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0)
++      REG_S   s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0)
++      REG_S   a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0)
++      REG_S   a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0)
++      REG_S   a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0)
++      REG_S   a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0)
++      REG_S   a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0)
++      REG_S   a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0)
++      REG_S   a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0)
++      REG_S   s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0)
++      REG_S   s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0)
++      REG_S   s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0)
++      REG_S   s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0)
++      REG_S   s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0)
++      REG_S   s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0)
++      REG_S   s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0)
++      REG_S   s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0)
++      REG_S   s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0)
++      REG_S   s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0)
++
++      /* Save CSRs */
++      csrr    t0, CSR_EPC
++      REG_S   t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0)
++      csrr    t0, CSR_STATUS
++      REG_S   t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0)
++      csrr    t0, CSR_TVAL
++      REG_S   t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0)
++      csrr    t0, CSR_CAUSE
++      REG_S   t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0)
++
++      /* Return non-zero value */
++      li      a0, 1
++
++      /* Return to C code */
++      ret
++END(__cpu_suspend_enter)
++
++ENTRY(__cpu_resume_enter)
++      /* Load the global pointer */
++      .option push
++      .option norelax
++              la gp, __global_pointer$
++      .option pop
++
++#ifdef CONFIG_MMU
++      /* Save A0 and A1 */
++      add     t0, a0, zero
++      add     t1, a1, zero
++
++      /* Enable MMU */
++      la      a0, swapper_pg_dir
++      XIP_FIXUP_OFFSET a0
++      call    relocate_enable_mmu
++
++      /* Restore A0 and A1 */
++      add     a0, t0, zero
++      add     a1, t1, zero
++#endif
++
++      /* Make A0 point to suspend context */
++      add     a0, a1, zero
++
++      /* Restore CSRs */
++      REG_L   t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0)
++      csrw    CSR_EPC, t0
++      REG_L   t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0)
++      csrw    CSR_STATUS, t0
++      REG_L   t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0)
++      csrw    CSR_TVAL, t0
++      REG_L   t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0)
++      csrw    CSR_CAUSE, t0
++
++      /* Restore registers (except A0 and T0-T6) */
++      REG_L   ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0)
++      REG_L   sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0)
++      REG_L   gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0)
++      REG_L   tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0)
++      REG_L   s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0)
++      REG_L   s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0)
++      REG_L   a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0)
++      REG_L   a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0)
++      REG_L   a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0)
++      REG_L   a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0)
++      REG_L   a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0)
++      REG_L   a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0)
++      REG_L   a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0)
++      REG_L   s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0)
++      REG_L   s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0)
++      REG_L   s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0)
++      REG_L   s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0)
++      REG_L   s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0)
++      REG_L   s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0)
++      REG_L   s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0)
++      REG_L   s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0)
++      REG_L   s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0)
++      REG_L   s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0)
++
++      /* Return zero value */
++      add     a0, zero, zero
++
++      /* Return to C code */
++      ret
++END(__cpu_resume_enter)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0046-RISC-V-Add-SBI-HSM-suspend-related-defines.patch b/target/linux/sunxid1/patches-5.15/0046-RISC-V-Add-SBI-HSM-suspend-related-defines.patch
new file mode 100644 (file)
index 0000000..193e150
--- /dev/null
@@ -0,0 +1,72 @@
+From 6a6733ae3666b12d2288e8f75e4406c3e2137cf4 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Mon, 15 Feb 2021 10:43:39 +0530
+Subject: [PATCH 046/124] RISC-V: Add SBI HSM suspend related defines
+
+We add defines related to SBI HSM suspend call and also
+update HSM states naming as-per latest SBI specification.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+---
+ arch/riscv/include/asm/sbi.h    | 27 ++++++++++++++++++++++-----
+ arch/riscv/kernel/cpu_ops_sbi.c |  2 +-
+ 2 files changed, 23 insertions(+), 6 deletions(-)
+
+diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
+index 289621da4a2a..ab9782f8da52 100644
+--- a/arch/riscv/include/asm/sbi.h
++++ b/arch/riscv/include/asm/sbi.h
+@@ -62,15 +62,32 @@ enum sbi_ext_hsm_fid {
+       SBI_EXT_HSM_HART_START = 0,
+       SBI_EXT_HSM_HART_STOP,
+       SBI_EXT_HSM_HART_STATUS,
++      SBI_EXT_HSM_HART_SUSPEND,
+ };
+-enum sbi_hsm_hart_status {
+-      SBI_HSM_HART_STATUS_STARTED = 0,
+-      SBI_HSM_HART_STATUS_STOPPED,
+-      SBI_HSM_HART_STATUS_START_PENDING,
+-      SBI_HSM_HART_STATUS_STOP_PENDING,
++enum sbi_hsm_hart_state {
++      SBI_HSM_STATE_STARTED = 0,
++      SBI_HSM_STATE_STOPPED,
++      SBI_HSM_STATE_START_PENDING,
++      SBI_HSM_STATE_STOP_PENDING,
++      SBI_HSM_STATE_SUSPENDED,
++      SBI_HSM_STATE_SUSPEND_PENDING,
++      SBI_HSM_STATE_RESUME_PENDING,
+ };
++#define SBI_HSM_SUSP_BASE_MASK                        0x7fffffff
++#define SBI_HSM_SUSP_NON_RET_BIT              0x80000000
++#define SBI_HSM_SUSP_PLAT_BASE                        0x10000000
++
++#define SBI_HSM_SUSPEND_RET_DEFAULT           0x00000000
++#define SBI_HSM_SUSPEND_RET_PLATFORM          SBI_HSM_SUSP_PLAT_BASE
++#define SBI_HSM_SUSPEND_RET_LAST              SBI_HSM_SUSP_BASE_MASK
++#define SBI_HSM_SUSPEND_NON_RET_DEFAULT               SBI_HSM_SUSP_NON_RET_BIT
++#define SBI_HSM_SUSPEND_NON_RET_PLATFORM      (SBI_HSM_SUSP_NON_RET_BIT | \
++                                               SBI_HSM_SUSP_PLAT_BASE)
++#define SBI_HSM_SUSPEND_NON_RET_LAST          (SBI_HSM_SUSP_NON_RET_BIT | \
++                                               SBI_HSM_SUSP_BASE_MASK)
++
+ enum sbi_ext_srst_fid {
+       SBI_EXT_SRST_RESET = 0,
+ };
+diff --git a/arch/riscv/kernel/cpu_ops_sbi.c b/arch/riscv/kernel/cpu_ops_sbi.c
+index 685fae72b7f5..5fd90f03a3e9 100644
+--- a/arch/riscv/kernel/cpu_ops_sbi.c
++++ b/arch/riscv/kernel/cpu_ops_sbi.c
+@@ -97,7 +97,7 @@ static int sbi_cpu_is_stopped(unsigned int cpuid)
+       rc = sbi_hsm_hart_get_status(hartid);
+-      if (rc == SBI_HSM_HART_STATUS_STOPPED)
++      if (rc == SBI_HSM_STATE_STOPPED)
+               return 0;
+       return rc;
+ }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0047-cpuidle-Factor-out-power-domain-related-code-from-PS.patch b/target/linux/sunxid1/patches-5.15/0047-cpuidle-Factor-out-power-domain-related-code-from-PS.patch
new file mode 100644 (file)
index 0000000..e7f0783
--- /dev/null
@@ -0,0 +1,548 @@
+From 21cdb37bf5cdf1b4466b2a5f9fb1494adc55feac Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Wed, 17 Feb 2021 18:52:00 +0530
+Subject: [PATCH 047/124] cpuidle: Factor-out power domain related code from
+ PSCI domain driver
+
+The generic power domain related code in PSCI domain driver is largely
+independent of PSCI and can be shared with RISC-V SBI domain driver
+hence we factor-out this code into dt_idle_genpd.c and dt_idle_genpd.h.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ MAINTAINERS                           |   7 +
+ drivers/cpuidle/Kconfig               |   4 +
+ drivers/cpuidle/Kconfig.arm           |   1 +
+ drivers/cpuidle/Makefile              |   1 +
+ drivers/cpuidle/cpuidle-psci-domain.c | 138 +-------------------
+ drivers/cpuidle/cpuidle-psci.h        |  15 ++-
+ drivers/cpuidle/dt_idle_genpd.c       | 177 ++++++++++++++++++++++++++
+ drivers/cpuidle/dt_idle_genpd.h       |  50 ++++++++
+ 8 files changed, 258 insertions(+), 135 deletions(-)
+ create mode 100644 drivers/cpuidle/dt_idle_genpd.c
+ create mode 100644 drivers/cpuidle/dt_idle_genpd.h
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 3b79fd441dde..b209020decb9 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4911,6 +4911,13 @@ S:      Supported
+ F:    drivers/cpuidle/cpuidle-psci.h
+ F:    drivers/cpuidle/cpuidle-psci-domain.c
++CPUIDLE DRIVER - DT IDLE PM DOMAIN
++M:    Ulf Hansson <ulf.hansson@linaro.org>
++L:    linux-pm@vger.kernel.org
++S:    Supported
++F:    drivers/cpuidle/dt_idle_genpd.c
++F:    drivers/cpuidle/dt_idle_genpd.h
++
+ CRAMFS FILESYSTEM
+ M:    Nicolas Pitre <nico@fluxnic.net>
+ S:    Maintained
+diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
+index c0aeedd66f02..f1afe7ab6b54 100644
+--- a/drivers/cpuidle/Kconfig
++++ b/drivers/cpuidle/Kconfig
+@@ -47,6 +47,10 @@ config CPU_IDLE_GOV_HALTPOLL
+ config DT_IDLE_STATES
+       bool
++config DT_IDLE_GENPD
++      depends on PM_GENERIC_DOMAINS_OF
++      bool
++
+ menu "ARM CPU Idle Drivers"
+ depends on ARM || ARM64
+ source "drivers/cpuidle/Kconfig.arm"
+diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
+index 334f83e56120..be12a9ca78f0 100644
+--- a/drivers/cpuidle/Kconfig.arm
++++ b/drivers/cpuidle/Kconfig.arm
+@@ -27,6 +27,7 @@ config ARM_PSCI_CPUIDLE_DOMAIN
+       bool "PSCI CPU idle Domain"
+       depends on ARM_PSCI_CPUIDLE
+       depends on PM_GENERIC_DOMAINS_OF
++      select DT_IDLE_GENPD
+       default y
+       help
+         Select this to enable the PSCI based CPUidle driver to use PM domains,
+diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
+index 26bbc5e74123..11a26cef279f 100644
+--- a/drivers/cpuidle/Makefile
++++ b/drivers/cpuidle/Makefile
+@@ -6,6 +6,7 @@
+ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
+ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
+ obj-$(CONFIG_DT_IDLE_STATES)            += dt_idle_states.o
++obj-$(CONFIG_DT_IDLE_GENPD)             += dt_idle_genpd.o
+ obj-$(CONFIG_ARCH_HAS_CPU_RELAX)        += poll_state.o
+ obj-$(CONFIG_HALTPOLL_CPUIDLE)                  += cpuidle-haltpoll.o
+diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c
+index ff2c3f8e4668..755bbdfc5b82 100644
+--- a/drivers/cpuidle/cpuidle-psci-domain.c
++++ b/drivers/cpuidle/cpuidle-psci-domain.c
+@@ -47,73 +47,14 @@ static int psci_pd_power_off(struct generic_pm_domain *pd)
+       return 0;
+ }
+-static int psci_pd_parse_state_nodes(struct genpd_power_state *states,
+-                                   int state_count)
+-{
+-      int i, ret;
+-      u32 psci_state, *psci_state_buf;
+-
+-      for (i = 0; i < state_count; i++) {
+-              ret = psci_dt_parse_state_node(to_of_node(states[i].fwnode),
+-                                      &psci_state);
+-              if (ret)
+-                      goto free_state;
+-
+-              psci_state_buf = kmalloc(sizeof(u32), GFP_KERNEL);
+-              if (!psci_state_buf) {
+-                      ret = -ENOMEM;
+-                      goto free_state;
+-              }
+-              *psci_state_buf = psci_state;
+-              states[i].data = psci_state_buf;
+-      }
+-
+-      return 0;
+-
+-free_state:
+-      i--;
+-      for (; i >= 0; i--)
+-              kfree(states[i].data);
+-      return ret;
+-}
+-
+-static int psci_pd_parse_states(struct device_node *np,
+-                      struct genpd_power_state **states, int *state_count)
+-{
+-      int ret;
+-
+-      /* Parse the domain idle states. */
+-      ret = of_genpd_parse_idle_states(np, states, state_count);
+-      if (ret)
+-              return ret;
+-
+-      /* Fill out the PSCI specifics for each found state. */
+-      ret = psci_pd_parse_state_nodes(*states, *state_count);
+-      if (ret)
+-              kfree(*states);
+-
+-      return ret;
+-}
+-
+-static void psci_pd_free_states(struct genpd_power_state *states,
+-                              unsigned int state_count)
+-{
+-      int i;
+-
+-      for (i = 0; i < state_count; i++)
+-              kfree(states[i].data);
+-      kfree(states);
+-}
+-
+ static int psci_pd_init(struct device_node *np, bool use_osi)
+ {
+       struct generic_pm_domain *pd;
+       struct psci_pd_provider *pd_provider;
+       struct dev_power_governor *pd_gov;
+-      struct genpd_power_state *states = NULL;
+       int ret = -ENOMEM, state_count = 0;
+-      pd = kzalloc(sizeof(*pd), GFP_KERNEL);
++      pd = dt_idle_pd_alloc(np, psci_dt_parse_state_node);
+       if (!pd)
+               goto out;
+@@ -121,22 +62,6 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
+       if (!pd_provider)
+               goto free_pd;
+-      pd->name = kasprintf(GFP_KERNEL, "%pOF", np);
+-      if (!pd->name)
+-              goto free_pd_prov;
+-
+-      /*
+-       * Parse the domain idle states and let genpd manage the state selection
+-       * for those being compatible with "domain-idle-state".
+-       */
+-      ret = psci_pd_parse_states(np, &states, &state_count);
+-      if (ret)
+-              goto free_name;
+-
+-      pd->free_states = psci_pd_free_states;
+-      pd->name = kbasename(pd->name);
+-      pd->states = states;
+-      pd->state_count = state_count;
+       pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;
+       /* Allow power off when OSI has been successfully enabled. */
+@@ -149,10 +74,8 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
+       pd_gov = state_count > 0 ? &pm_domain_cpu_gov : NULL;
+       ret = pm_genpd_init(pd, pd_gov, false);
+-      if (ret) {
+-              psci_pd_free_states(states, state_count);
+-              goto free_name;
+-      }
++      if (ret)
++              goto free_pd_prov;
+       ret = of_genpd_add_provider_simple(np, pd);
+       if (ret)
+@@ -166,12 +89,10 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
+ remove_pd:
+       pm_genpd_remove(pd);
+-free_name:
+-      kfree(pd->name);
+ free_pd_prov:
+       kfree(pd_provider);
+ free_pd:
+-      kfree(pd);
++      dt_idle_pd_free(pd);
+ out:
+       pr_err("failed to init PM domain ret=%d %pOF\n", ret, np);
+       return ret;
+@@ -195,30 +116,6 @@ static void psci_pd_remove(void)
+       }
+ }
+-static int psci_pd_init_topology(struct device_node *np)
+-{
+-      struct device_node *node;
+-      struct of_phandle_args child, parent;
+-      int ret;
+-
+-      for_each_child_of_node(np, node) {
+-              if (of_parse_phandle_with_args(node, "power-domains",
+-                                      "#power-domain-cells", 0, &parent))
+-                      continue;
+-
+-              child.np = node;
+-              child.args_count = 0;
+-              ret = of_genpd_add_subdomain(&parent, &child);
+-              of_node_put(parent.np);
+-              if (ret) {
+-                      of_node_put(node);
+-                      return ret;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+ static bool psci_pd_try_set_osi_mode(void)
+ {
+       int ret;
+@@ -282,7 +179,7 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
+               goto no_pd;
+       /* Link genpd masters/subdomains to model the CPU topology. */
+-      ret = psci_pd_init_topology(np);
++      ret = dt_idle_pd_init_topology(np);
+       if (ret)
+               goto remove_pd;
+@@ -314,28 +211,3 @@ static int __init psci_idle_init_domains(void)
+       return platform_driver_register(&psci_cpuidle_domain_driver);
+ }
+ subsys_initcall(psci_idle_init_domains);
+-
+-struct device *psci_dt_attach_cpu(int cpu)
+-{
+-      struct device *dev;
+-
+-      dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), "psci");
+-      if (IS_ERR_OR_NULL(dev))
+-              return dev;
+-
+-      pm_runtime_irq_safe(dev);
+-      if (cpu_online(cpu))
+-              pm_runtime_get_sync(dev);
+-
+-      dev_pm_syscore_device(dev, true);
+-
+-      return dev;
+-}
+-
+-void psci_dt_detach_cpu(struct device *dev)
+-{
+-      if (IS_ERR_OR_NULL(dev))
+-              return;
+-
+-      dev_pm_domain_detach(dev, false);
+-}
+diff --git a/drivers/cpuidle/cpuidle-psci.h b/drivers/cpuidle/cpuidle-psci.h
+index d8e925e84c27..4e132640ed64 100644
+--- a/drivers/cpuidle/cpuidle-psci.h
++++ b/drivers/cpuidle/cpuidle-psci.h
+@@ -10,8 +10,19 @@ void psci_set_domain_state(u32 state);
+ int psci_dt_parse_state_node(struct device_node *np, u32 *state);
+ #ifdef CONFIG_ARM_PSCI_CPUIDLE_DOMAIN
+-struct device *psci_dt_attach_cpu(int cpu);
+-void psci_dt_detach_cpu(struct device *dev);
++
++#include "dt_idle_genpd.h"
++
++static inline struct device *psci_dt_attach_cpu(int cpu)
++{
++      return dt_idle_attach_cpu(cpu, "psci");
++}
++
++static inline void psci_dt_detach_cpu(struct device *dev)
++{
++      dt_idle_detach_cpu(dev);
++}
++
+ #else
+ static inline struct device *psci_dt_attach_cpu(int cpu) { return NULL; }
+ static inline void psci_dt_detach_cpu(struct device *dev) { }
+diff --git a/drivers/cpuidle/dt_idle_genpd.c b/drivers/cpuidle/dt_idle_genpd.c
+new file mode 100644
+index 000000000000..db385fd2507e
+--- /dev/null
++++ b/drivers/cpuidle/dt_idle_genpd.c
+@@ -0,0 +1,177 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * PM domains for CPUs via genpd.
++ *
++ * Copyright (C) 2019 Linaro Ltd.
++ * Author: Ulf Hansson <ulf.hansson@linaro.org>
++ *
++ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#define pr_fmt(fmt) "dt-idle-genpd: " fmt
++
++#include <linux/cpu.h>
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/pm_domain.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#include "dt_idle_genpd.h"
++
++static int pd_parse_state_nodes(
++                      int (*parse_state)(struct device_node *, u32 *),
++                      struct genpd_power_state *states, int state_count)
++{
++      int i, ret;
++      u32 state, *state_buf;
++
++      for (i = 0; i < state_count; i++) {
++              ret = parse_state(to_of_node(states[i].fwnode), &state);
++              if (ret)
++                      goto free_state;
++
++              state_buf = kmalloc(sizeof(u32), GFP_KERNEL);
++              if (!state_buf) {
++                      ret = -ENOMEM;
++                      goto free_state;
++              }
++              *state_buf = state;
++              states[i].data = state_buf;
++      }
++
++      return 0;
++
++free_state:
++      i--;
++      for (; i >= 0; i--)
++              kfree(states[i].data);
++      return ret;
++}
++
++static int pd_parse_states(struct device_node *np,
++                         int (*parse_state)(struct device_node *, u32 *),
++                         struct genpd_power_state **states,
++                         int *state_count)
++{
++      int ret;
++
++      /* Parse the domain idle states. */
++      ret = of_genpd_parse_idle_states(np, states, state_count);
++      if (ret)
++              return ret;
++
++      /* Fill out the dt specifics for each found state. */
++      ret = pd_parse_state_nodes(parse_state, *states, *state_count);
++      if (ret)
++              kfree(*states);
++
++      return ret;
++}
++
++static void pd_free_states(struct genpd_power_state *states,
++                          unsigned int state_count)
++{
++      int i;
++
++      for (i = 0; i < state_count; i++)
++              kfree(states[i].data);
++      kfree(states);
++}
++
++void dt_idle_pd_free(struct generic_pm_domain *pd)
++{
++      pd_free_states(pd->states, pd->state_count);
++      kfree(pd->name);
++      kfree(pd);
++}
++
++struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np,
++                      int (*parse_state)(struct device_node *, u32 *))
++{
++      struct generic_pm_domain *pd;
++      struct genpd_power_state *states = NULL;
++      int ret, state_count = 0;
++
++      pd = kzalloc(sizeof(*pd), GFP_KERNEL);
++      if (!pd)
++              goto out;
++
++      pd->name = kasprintf(GFP_KERNEL, "%pOF", np);
++      if (!pd->name)
++              goto free_pd;
++
++      /*
++       * Parse the domain idle states and let genpd manage the state selection
++       * for those being compatible with "domain-idle-state".
++       */
++      ret = pd_parse_states(np, parse_state, &states, &state_count);
++      if (ret)
++              goto free_name;
++
++      pd->free_states = pd_free_states;
++      pd->name = kbasename(pd->name);
++      pd->states = states;
++      pd->state_count = state_count;
++
++      pr_debug("alloc PM domain %s\n", pd->name);
++      return pd;
++
++free_name:
++      kfree(pd->name);
++free_pd:
++      kfree(pd);
++out:
++      pr_err("failed to alloc PM domain %pOF\n", np);
++      return NULL;
++}
++
++int dt_idle_pd_init_topology(struct device_node *np)
++{
++      struct device_node *node;
++      struct of_phandle_args child, parent;
++      int ret;
++
++      for_each_child_of_node(np, node) {
++              if (of_parse_phandle_with_args(node, "power-domains",
++                                      "#power-domain-cells", 0, &parent))
++                      continue;
++
++              child.np = node;
++              child.args_count = 0;
++              ret = of_genpd_add_subdomain(&parent, &child);
++              of_node_put(parent.np);
++              if (ret) {
++                      of_node_put(node);
++                      return ret;
++              }
++      }
++
++      return 0;
++}
++
++struct device *dt_idle_attach_cpu(int cpu, const char *name)
++{
++      struct device *dev;
++
++      dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), name);
++      if (IS_ERR_OR_NULL(dev))
++              return dev;
++
++      pm_runtime_irq_safe(dev);
++      if (cpu_online(cpu))
++              pm_runtime_get_sync(dev);
++
++      dev_pm_syscore_device(dev, true);
++
++      return dev;
++}
++
++void dt_idle_detach_cpu(struct device *dev)
++{
++      if (IS_ERR_OR_NULL(dev))
++              return;
++
++      dev_pm_domain_detach(dev, false);
++}
+diff --git a/drivers/cpuidle/dt_idle_genpd.h b/drivers/cpuidle/dt_idle_genpd.h
+new file mode 100644
+index 000000000000..a95483d08a02
+--- /dev/null
++++ b/drivers/cpuidle/dt_idle_genpd.h
+@@ -0,0 +1,50 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __DT_IDLE_GENPD
++#define __DT_IDLE_GENPD
++
++struct device_node;
++struct generic_pm_domain;
++
++#ifdef CONFIG_DT_IDLE_GENPD
++
++void dt_idle_pd_free(struct generic_pm_domain *pd);
++
++struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np,
++                      int (*parse_state)(struct device_node *, u32 *));
++
++int dt_idle_pd_init_topology(struct device_node *np);
++
++struct device *dt_idle_attach_cpu(int cpu, const char *name);
++
++void dt_idle_detach_cpu(struct device *dev);
++
++#else
++
++static inline void dt_idle_pd_free(struct generic_pm_domain *pd)
++{
++}
++
++static inline struct generic_pm_domain *dt_idle_pd_alloc(
++                      struct device_node *np,
++                      int (*parse_state)(struct device_node *, u32 *))
++{
++      return NULL;
++}
++
++static inline int dt_idle_pd_init_topology(struct device_node *np)
++{
++      return 0;
++}
++
++static inline struct device *dt_idle_attach_cpu(int cpu, const char *name)
++{
++      return NULL;
++}
++
++static inline void dt_idle_detach_cpu(struct device *dev)
++{
++}
++
++#endif
++
++#endif
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0048-cpuidle-Add-RISC-V-SBI-CPU-idle-driver.patch b/target/linux/sunxid1/patches-5.15/0048-cpuidle-Add-RISC-V-SBI-CPU-idle-driver.patch
new file mode 100644 (file)
index 0000000..ddd2c1d
--- /dev/null
@@ -0,0 +1,725 @@
+From 583adf3464089e7f164d45bbddae08fc2e60fe2a Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Fri, 12 Feb 2021 09:55:34 +0530
+Subject: [PATCH 048/124] cpuidle: Add RISC-V SBI CPU idle driver
+
+The RISC-V SBI HSM extension provides HSM suspend call which can
+be used by Linux RISC-V to enter platform specific low-power state.
+
+This patch adds a CPU idle driver based on RISC-V SBI calls which
+will populate idle states from device tree and use SBI calls to
+entry these idle states.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+---
+ MAINTAINERS                         |   7 +
+ drivers/cpuidle/Kconfig             |   5 +
+ drivers/cpuidle/Kconfig.riscv       |  15 +
+ drivers/cpuidle/Makefile            |   4 +
+ drivers/cpuidle/cpuidle-riscv-sbi.c | 626 ++++++++++++++++++++++++++++
+ 5 files changed, 657 insertions(+)
+ create mode 100644 drivers/cpuidle/Kconfig.riscv
+ create mode 100644 drivers/cpuidle/cpuidle-riscv-sbi.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index b209020decb9..8b4809d2c789 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4918,6 +4918,13 @@ S:      Supported
+ F:    drivers/cpuidle/dt_idle_genpd.c
+ F:    drivers/cpuidle/dt_idle_genpd.h
++CPUIDLE DRIVER - RISC-V SBI
++M:    Anup Patel <anup.patel@wdc.com>
++L:    linux-pm@vger.kernel.org
++L:    linux-riscv@lists.infradead.org
++S:    Maintained
++F:    drivers/cpuidle/cpuidle-riscv-sbi.c
++
+ CRAMFS FILESYSTEM
+ M:    Nicolas Pitre <nico@fluxnic.net>
+ S:    Maintained
+diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
+index f1afe7ab6b54..ff71dd662880 100644
+--- a/drivers/cpuidle/Kconfig
++++ b/drivers/cpuidle/Kconfig
+@@ -66,6 +66,11 @@ depends on PPC
+ source "drivers/cpuidle/Kconfig.powerpc"
+ endmenu
++menu "RISC-V CPU Idle Drivers"
++depends on RISCV
++source "drivers/cpuidle/Kconfig.riscv"
++endmenu
++
+ config HALTPOLL_CPUIDLE
+       tristate "Halt poll cpuidle driver"
+       depends on X86 && KVM_GUEST
+diff --git a/drivers/cpuidle/Kconfig.riscv b/drivers/cpuidle/Kconfig.riscv
+new file mode 100644
+index 000000000000..78518c26af74
+--- /dev/null
++++ b/drivers/cpuidle/Kconfig.riscv
+@@ -0,0 +1,15 @@
++# SPDX-License-Identifier: GPL-2.0-only
++#
++# RISC-V CPU Idle drivers
++#
++
++config RISCV_SBI_CPUIDLE
++      bool "RISC-V SBI CPU idle Driver"
++      depends on RISCV_SBI
++      select DT_IDLE_STATES
++      select CPU_IDLE_MULTIPLE_DRIVERS
++      select DT_IDLE_GENPD if PM_GENERIC_DOMAINS_OF
++      help
++        Select this option to enable RISC-V SBI firmware based CPU idle
++        driver for RISC-V systems. This drivers also supports hierarchical
++        DT based layout of the idle state.
+diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
+index 11a26cef279f..d103342b7cfc 100644
+--- a/drivers/cpuidle/Makefile
++++ b/drivers/cpuidle/Makefile
+@@ -35,3 +35,7 @@ obj-$(CONFIG_MIPS_CPS_CPUIDLE)               += cpuidle-cps.o
+ # POWERPC drivers
+ obj-$(CONFIG_PSERIES_CPUIDLE)         += cpuidle-pseries.o
+ obj-$(CONFIG_POWERNV_CPUIDLE)         += cpuidle-powernv.o
++
++###############################################################################
++# RISC-V drivers
++obj-$(CONFIG_RISCV_SBI_CPUIDLE)               += cpuidle-riscv-sbi.o
+diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c
+new file mode 100644
+index 000000000000..1f80e27c5cfb
+--- /dev/null
++++ b/drivers/cpuidle/cpuidle-riscv-sbi.c
+@@ -0,0 +1,626 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * RISC-V SBI CPU idle driver.
++ *
++ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt
++
++#include <linux/cpuidle.h>
++#include <linux/cpumask.h>
++#include <linux/cpu_pm.h>
++#include <linux/cpu_cooling.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/pm_domain.h>
++#include <linux/pm_runtime.h>
++#include <asm/cpuidle.h>
++#include <asm/sbi.h>
++#include <asm/suspend.h>
++
++#include "dt_idle_states.h"
++#include "dt_idle_genpd.h"
++
++struct sbi_cpuidle_data {
++      u32 *states;
++      struct device *dev;
++};
++
++struct sbi_domain_state {
++      bool available;
++      u32 state;
++};
++
++static DEFINE_PER_CPU_READ_MOSTLY(struct sbi_cpuidle_data, sbi_cpuidle_data);
++static DEFINE_PER_CPU(struct sbi_domain_state, domain_state);
++static bool sbi_cpuidle_use_osi;
++static bool sbi_cpuidle_use_cpuhp;
++static bool sbi_cpuidle_pd_allow_domain_state;
++
++static inline void sbi_set_domain_state(u32 state)
++{
++      struct sbi_domain_state *data = this_cpu_ptr(&domain_state);
++
++      data->available = true;
++      data->state = state;
++}
++
++static inline u32 sbi_get_domain_state(void)
++{
++      struct sbi_domain_state *data = this_cpu_ptr(&domain_state);
++
++      return data->state;
++}
++
++static inline void sbi_clear_domain_state(void)
++{
++      struct sbi_domain_state *data = this_cpu_ptr(&domain_state);
++
++      data->available = false;
++}
++
++static inline bool sbi_is_domain_state_available(void)
++{
++      struct sbi_domain_state *data = this_cpu_ptr(&domain_state);
++
++      return data->available;
++}
++
++static int sbi_suspend_finisher(unsigned long suspend_type,
++                              unsigned long resume_addr,
++                              unsigned long opaque)
++{
++      struct sbiret ret;
++
++      ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_SUSPEND,
++                      suspend_type, resume_addr, opaque, 0, 0, 0);
++
++      return (ret.error) ? sbi_err_map_linux_errno(ret.error) : 0;
++}
++
++static int sbi_suspend(u32 state)
++{
++      if (state & SBI_HSM_SUSP_NON_RET_BIT)
++              return cpu_suspend(state, sbi_suspend_finisher);
++      else
++              return sbi_suspend_finisher(state, 0, 0);
++}
++
++static int sbi_cpuidle_enter_state(struct cpuidle_device *dev,
++                                 struct cpuidle_driver *drv, int idx)
++{
++      u32 *states = __this_cpu_read(sbi_cpuidle_data.states);
++
++      return CPU_PM_CPU_IDLE_ENTER_PARAM(sbi_suspend, idx, states[idx]);
++}
++
++static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev,
++                                        struct cpuidle_driver *drv, int idx,
++                                        bool s2idle)
++{
++      struct sbi_cpuidle_data *data = this_cpu_ptr(&sbi_cpuidle_data);
++      u32 *states = data->states;
++      struct device *pd_dev = data->dev;
++      u32 state;
++      int ret;
++
++      ret = cpu_pm_enter();
++      if (ret)
++              return -1;
++
++      /* Do runtime PM to manage a hierarchical CPU toplogy. */
++      rcu_irq_enter_irqson();
++      if (s2idle)
++              dev_pm_genpd_suspend(pd_dev);
++      else
++              pm_runtime_put_sync_suspend(pd_dev);
++      rcu_irq_exit_irqson();
++
++      if (sbi_is_domain_state_available())
++              state = sbi_get_domain_state();
++      else
++              state = states[idx];
++
++      ret = sbi_suspend(state) ? -1 : idx;
++
++      rcu_irq_enter_irqson();
++      if (s2idle)
++              dev_pm_genpd_resume(pd_dev);
++      else
++              pm_runtime_get_sync(pd_dev);
++      rcu_irq_exit_irqson();
++
++      cpu_pm_exit();
++
++      /* Clear the domain state to start fresh when back from idle. */
++      sbi_clear_domain_state();
++      return ret;
++}
++
++static int sbi_enter_domain_idle_state(struct cpuidle_device *dev,
++                                     struct cpuidle_driver *drv, int idx)
++{
++      return __sbi_enter_domain_idle_state(dev, drv, idx, false);
++}
++
++static int sbi_enter_s2idle_domain_idle_state(struct cpuidle_device *dev,
++                                            struct cpuidle_driver *drv,
++                                            int idx)
++{
++      return __sbi_enter_domain_idle_state(dev, drv, idx, true);
++}
++
++static int sbi_cpuidle_cpuhp_up(unsigned int cpu)
++{
++      struct device *pd_dev = __this_cpu_read(sbi_cpuidle_data.dev);
++
++      if (pd_dev)
++              pm_runtime_get_sync(pd_dev);
++
++      return 0;
++}
++
++static int sbi_cpuidle_cpuhp_down(unsigned int cpu)
++{
++      struct device *pd_dev = __this_cpu_read(sbi_cpuidle_data.dev);
++
++      if (pd_dev) {
++              pm_runtime_put_sync(pd_dev);
++              /* Clear domain state to start fresh at next online. */
++              sbi_clear_domain_state();
++      }
++
++      return 0;
++}
++
++static void sbi_idle_init_cpuhp(void)
++{
++      int err;
++
++      if (!sbi_cpuidle_use_cpuhp)
++              return;
++
++      err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING,
++                                      "cpuidle/sbi:online",
++                                      sbi_cpuidle_cpuhp_up,
++                                      sbi_cpuidle_cpuhp_down);
++      if (err)
++              pr_warn("Failed %d while setup cpuhp state\n", err);
++}
++
++static const struct of_device_id sbi_cpuidle_state_match[] = {
++      { .compatible = "riscv,idle-state",
++        .data = sbi_cpuidle_enter_state },
++      { },
++};
++
++static bool sbi_suspend_state_is_valid(u32 state)
++{
++      if (state > SBI_HSM_SUSPEND_RET_DEFAULT &&
++          state < SBI_HSM_SUSPEND_RET_PLATFORM)
++              return false;
++      if (state > SBI_HSM_SUSPEND_NON_RET_DEFAULT &&
++          state < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
++              return false;
++      return true;
++}
++
++static int sbi_dt_parse_state_node(struct device_node *np, u32 *state)
++{
++      int err = of_property_read_u32(np, "riscv,sbi-suspend-param", state);
++
++      if (err) {
++              pr_warn("%pOF missing riscv,sbi-suspend-param property\n", np);
++              return err;
++      }
++
++      if (!sbi_suspend_state_is_valid(*state)) {
++              pr_warn("Invalid SBI suspend state %#x\n", *state);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static int sbi_dt_cpu_init_topology(struct cpuidle_driver *drv,
++                                   struct sbi_cpuidle_data *data,
++                                   unsigned int state_count, int cpu)
++{
++      /* Currently limit the hierarchical topology to be used in OSI mode. */
++      if (!sbi_cpuidle_use_osi)
++              return 0;
++
++      data->dev = dt_idle_attach_cpu(cpu, "sbi");
++      if (IS_ERR_OR_NULL(data->dev))
++              return PTR_ERR_OR_ZERO(data->dev);
++
++      /*
++       * Using the deepest state for the CPU to trigger a potential selection
++       * of a shared state for the domain, assumes the domain states are all
++       * deeper states.
++       */
++      drv->states[state_count - 1].enter = sbi_enter_domain_idle_state;
++      drv->states[state_count - 1].enter_s2idle =
++                                      sbi_enter_s2idle_domain_idle_state;
++      sbi_cpuidle_use_cpuhp = true;
++
++      return 0;
++}
++
++static int sbi_cpuidle_dt_init_states(struct device *dev,
++                                      struct cpuidle_driver *drv,
++                                      unsigned int cpu,
++                                      unsigned int state_count)
++{
++      struct sbi_cpuidle_data *data = per_cpu_ptr(&sbi_cpuidle_data, cpu);
++      struct device_node *state_node;
++      struct device_node *cpu_node;
++      u32 *states;
++      int i, ret;
++
++      cpu_node = of_cpu_device_node_get(cpu);
++      if (!cpu_node)
++              return -ENODEV;
++
++      states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL);
++      if (!states) {
++              ret = -ENOMEM;
++              goto fail;
++      }
++
++      /* Parse SBI specific details from state DT nodes */
++      for (i = 1; i < state_count; i++) {
++              state_node = of_get_cpu_state_node(cpu_node, i - 1);
++              if (!state_node)
++                      break;
++
++              ret = sbi_dt_parse_state_node(state_node, &states[i]);
++              of_node_put(state_node);
++
++              if (ret)
++                      return ret;
++
++              pr_debug("sbi-state %#x index %d\n", states[i], i);
++      }
++      if (i != state_count) {
++              ret = -ENODEV;
++              goto fail;
++      }
++
++      /* Initialize optional data, used for the hierarchical topology. */
++      ret = sbi_dt_cpu_init_topology(drv, data, state_count, cpu);
++      if (ret < 0)
++              return ret;
++
++      /* Store states in the per-cpu struct. */
++      data->states = states;
++
++fail:
++      of_node_put(cpu_node);
++
++      return ret;
++}
++
++static void sbi_cpuidle_deinit_cpu(int cpu)
++{
++      struct sbi_cpuidle_data *data = per_cpu_ptr(&sbi_cpuidle_data, cpu);
++
++      dt_idle_detach_cpu(data->dev);
++      sbi_cpuidle_use_cpuhp = false;
++}
++
++static int sbi_cpuidle_init_cpu(struct device *dev, int cpu)
++{
++      struct cpuidle_driver *drv;
++      unsigned int state_count = 0;
++      int ret = 0;
++
++      drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
++      if (!drv)
++              return -ENOMEM;
++
++      drv->name = "sbi_cpuidle";
++      drv->owner = THIS_MODULE;
++      drv->cpumask = (struct cpumask *)cpumask_of(cpu);
++
++      /* RISC-V architectural WFI to be represented as state index 0. */
++      drv->states[0].enter = sbi_cpuidle_enter_state;
++      drv->states[0].exit_latency = 1;
++      drv->states[0].target_residency = 1;
++      drv->states[0].power_usage = UINT_MAX;
++      strcpy(drv->states[0].name, "WFI");
++      strcpy(drv->states[0].desc, "RISC-V WFI");
++
++      /*
++       * If no DT idle states are detected (ret == 0) let the driver
++       * initialization fail accordingly since there is no reason to
++       * initialize the idle driver if only wfi is supported, the
++       * default archictectural back-end already executes wfi
++       * on idle entry.
++       */
++      ret = dt_init_idle_driver(drv, sbi_cpuidle_state_match, 1);
++      if (ret <= 0) {
++              pr_debug("HART%ld: failed to parse DT idle states\n",
++                       cpuid_to_hartid_map(cpu));
++              return ret ? : -ENODEV;
++      }
++      state_count = ret + 1; /* Include WFI state as well */
++
++      /* Initialize idle states from DT. */
++      ret = sbi_cpuidle_dt_init_states(dev, drv, cpu, state_count);
++      if (ret) {
++              pr_err("HART%ld: failed to init idle states\n",
++                     cpuid_to_hartid_map(cpu));
++              return ret;
++      }
++
++      ret = cpuidle_register(drv, NULL);
++      if (ret)
++              goto deinit;
++
++      cpuidle_cooling_register(drv);
++
++      return 0;
++deinit:
++      sbi_cpuidle_deinit_cpu(cpu);
++      return ret;
++}
++
++static void sbi_cpuidle_domain_sync_state(struct device *dev)
++{
++      /*
++       * All devices have now been attached/probed to the PM domain
++       * topology, hence it's fine to allow domain states to be picked.
++       */
++      sbi_cpuidle_pd_allow_domain_state = true;
++}
++
++#ifdef CONFIG_DT_IDLE_GENPD
++
++static int sbi_cpuidle_pd_power_off(struct generic_pm_domain *pd)
++{
++      struct genpd_power_state *state = &pd->states[pd->state_idx];
++      u32 *pd_state;
++
++      if (!state->data)
++              return 0;
++
++      if (!sbi_cpuidle_pd_allow_domain_state)
++              return -EBUSY;
++
++      /* OSI mode is enabled, set the corresponding domain state. */
++      pd_state = state->data;
++      sbi_set_domain_state(*pd_state);
++
++      return 0;
++}
++
++struct sbi_pd_provider {
++      struct list_head link;
++      struct device_node *node;
++};
++
++static LIST_HEAD(sbi_pd_providers);
++
++static int sbi_pd_init(struct device_node *np)
++{
++      struct generic_pm_domain *pd;
++      struct sbi_pd_provider *pd_provider;
++      struct dev_power_governor *pd_gov;
++      int ret = -ENOMEM, state_count = 0;
++
++      pd = dt_idle_pd_alloc(np, sbi_dt_parse_state_node);
++      if (!pd)
++              goto out;
++
++      pd_provider = kzalloc(sizeof(*pd_provider), GFP_KERNEL);
++      if (!pd_provider)
++              goto free_pd;
++
++      pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;
++
++      /* Allow power off when OSI is available. */
++      if (sbi_cpuidle_use_osi)
++              pd->power_off = sbi_cpuidle_pd_power_off;
++      else
++              pd->flags |= GENPD_FLAG_ALWAYS_ON;
++
++      /* Use governor for CPU PM domains if it has some states to manage. */
++      pd_gov = state_count > 0 ? &pm_domain_cpu_gov : NULL;
++
++      ret = pm_genpd_init(pd, pd_gov, false);
++      if (ret)
++              goto free_pd_prov;
++
++      ret = of_genpd_add_provider_simple(np, pd);
++      if (ret)
++              goto remove_pd;
++
++      pd_provider->node = of_node_get(np);
++      list_add(&pd_provider->link, &sbi_pd_providers);
++
++      pr_debug("init PM domain %s\n", pd->name);
++      return 0;
++
++remove_pd:
++      pm_genpd_remove(pd);
++free_pd_prov:
++      kfree(pd_provider);
++free_pd:
++      dt_idle_pd_free(pd);
++out:
++      pr_err("failed to init PM domain ret=%d %pOF\n", ret, np);
++      return ret;
++}
++
++static void sbi_pd_remove(void)
++{
++      struct sbi_pd_provider *pd_provider, *it;
++      struct generic_pm_domain *genpd;
++
++      list_for_each_entry_safe(pd_provider, it, &sbi_pd_providers, link) {
++              of_genpd_del_provider(pd_provider->node);
++
++              genpd = of_genpd_remove_last(pd_provider->node);
++              if (!IS_ERR(genpd))
++                      kfree(genpd);
++
++              of_node_put(pd_provider->node);
++              list_del(&pd_provider->link);
++              kfree(pd_provider);
++      }
++}
++
++static int sbi_genpd_probe(struct device_node *np)
++{
++      struct device_node *node;
++      int ret = 0, pd_count = 0;
++
++      if (!np)
++              return -ENODEV;
++
++      /*
++       * Parse child nodes for the "#power-domain-cells" property and
++       * initialize a genpd/genpd-of-provider pair when it's found.
++       */
++      for_each_child_of_node(np, node) {
++              if (!of_find_property(node, "#power-domain-cells", NULL))
++                      continue;
++
++              ret = sbi_pd_init(node);
++              if (ret)
++                      goto put_node;
++
++              pd_count++;
++      }
++
++      /* Bail out if not using the hierarchical CPU topology. */
++      if (!pd_count)
++              goto no_pd;
++
++      /* Link genpd masters/subdomains to model the CPU topology. */
++      ret = dt_idle_pd_init_topology(np);
++      if (ret)
++              goto remove_pd;
++
++      return 0;
++
++put_node:
++      of_node_put(node);
++remove_pd:
++      sbi_pd_remove();
++      pr_err("failed to create CPU PM domains ret=%d\n", ret);
++no_pd:
++      return ret;
++}
++
++#else
++
++static inline int sbi_genpd_probe(struct device_node *np)
++{
++      return 0;
++}
++
++#endif
++
++static int sbi_cpuidle_probe(struct platform_device *pdev)
++{
++      int cpu, ret;
++      struct cpuidle_driver *drv;
++      struct cpuidle_device *dev;
++      struct device_node *np, *pds_node;
++
++      /* Detect OSI support based on CPU DT nodes */
++      sbi_cpuidle_use_osi = true;
++      for_each_possible_cpu(cpu) {
++              np = of_cpu_device_node_get(cpu);
++              if (np &&
++                  of_find_property(np, "power-domains", NULL) &&
++                  of_find_property(np, "power-domain-names", NULL)) {
++                      continue;
++              } else {
++                      sbi_cpuidle_use_osi = false;
++                      break;
++              }
++      }
++
++      /* Populate generic power domains from DT nodes */
++      pds_node = of_find_node_by_path("/cpus/power-domains");
++      if (pds_node) {
++              ret = sbi_genpd_probe(pds_node);
++              of_node_put(pds_node);
++              if (ret)
++                      return ret;
++      }
++
++      /* Initialize CPU idle driver for each CPU */
++      for_each_possible_cpu(cpu) {
++              ret = sbi_cpuidle_init_cpu(&pdev->dev, cpu);
++              if (ret) {
++                      pr_debug("HART%ld: idle driver init failed\n",
++                               cpuid_to_hartid_map(cpu));
++                      goto out_fail;
++              }
++      }
++
++      /* Setup CPU hotplut notifiers */
++      sbi_idle_init_cpuhp();
++
++      pr_info("idle driver registered for all CPUs\n");
++
++      return 0;
++
++out_fail:
++      while (--cpu >= 0) {
++              dev = per_cpu(cpuidle_devices, cpu);
++              drv = cpuidle_get_cpu_driver(dev);
++              cpuidle_unregister(drv);
++              sbi_cpuidle_deinit_cpu(cpu);
++      }
++
++      return ret;
++}
++
++static struct platform_driver sbi_cpuidle_driver = {
++      .probe = sbi_cpuidle_probe,
++      .driver = {
++              .name = "sbi-cpuidle",
++              .sync_state = sbi_cpuidle_domain_sync_state,
++      },
++};
++
++static int __init sbi_cpuidle_init(void)
++{
++      int ret;
++      struct platform_device *pdev;
++
++      /*
++       * The SBI HSM suspend function is only available when:
++       * 1) SBI version is 0.3 or higher
++       * 2) SBI HSM extension is available
++       */
++      if ((sbi_spec_version < sbi_mk_version(0, 3)) ||
++          sbi_probe_extension(SBI_EXT_HSM) <= 0) {
++              pr_info("HSM suspend not available\n");
++              return 0;
++      }
++
++      ret = platform_driver_register(&sbi_cpuidle_driver);
++      if (ret)
++              return ret;
++
++      pdev = platform_device_register_simple("sbi-cpuidle",
++                                              -1, NULL, 0);
++      if (IS_ERR(pdev)) {
++              platform_driver_unregister(&sbi_cpuidle_driver);
++              return PTR_ERR(pdev);
++      }
++
++      return 0;
++}
++device_initcall(sbi_cpuidle_init);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0049-RISC-V-Enable-RISC-V-SBI-CPU-Idle-driver-for-QEMU-vi.patch b/target/linux/sunxid1/patches-5.15/0049-RISC-V-Enable-RISC-V-SBI-CPU-Idle-driver-for-QEMU-vi.patch
new file mode 100644 (file)
index 0000000..426f197
--- /dev/null
@@ -0,0 +1,57 @@
+From 908cff58b3a2185c8fa22adfc96a5a7ce33c3387 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Wed, 17 Feb 2021 14:53:25 +0530
+Subject: [PATCH 049/124] RISC-V: Enable RISC-V SBI CPU Idle driver for QEMU
+ virt machine
+
+We enable RISC-V SBI CPU Idle driver for QEMU virt machine to test
+SBI HSM Supend on QEMU.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+---
+ arch/riscv/Kconfig.socs           | 3 +++
+ arch/riscv/configs/defconfig      | 1 +
+ arch/riscv/configs/rv32_defconfig | 1 +
+ 3 files changed, 5 insertions(+)
+
+diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
+index 30676ebb16eb..56bafc3dad4c 100644
+--- a/arch/riscv/Kconfig.socs
++++ b/arch/riscv/Kconfig.socs
+@@ -28,6 +28,9 @@ config SOC_VIRT
+       select GOLDFISH
+       select RTC_DRV_GOLDFISH if RTC_CLASS
+       select SIFIVE_PLIC
++      select PM_GENERIC_DOMAINS if PM
++      select PM_GENERIC_DOMAINS_OF if PM && OF
++      select RISCV_SBI_CPUIDLE if CPU_IDLE
+       help
+         This enables support for QEMU Virt Machine.
+diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
+index 66552914be3f..2911f78240aa 100644
+--- a/arch/riscv/configs/defconfig
++++ b/arch/riscv/configs/defconfig
+@@ -19,6 +19,7 @@ CONFIG_SOC_VIRT=y
+ CONFIG_SOC_MICROCHIP_POLARFIRE=y
+ CONFIG_SMP=y
+ CONFIG_HOTPLUG_CPU=y
++CONFIG_PM=y
+ CONFIG_CPU_IDLE=y
+ CONFIG_JUMP_LABEL=y
+ CONFIG_MODULES=y
+diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
+index 3093f8efd7e5..a8cbae623fd8 100644
+--- a/arch/riscv/configs/rv32_defconfig
++++ b/arch/riscv/configs/rv32_defconfig
+@@ -19,6 +19,7 @@ CONFIG_SOC_VIRT=y
+ CONFIG_ARCH_RV32I=y
+ CONFIG_SMP=y
+ CONFIG_HOTPLUG_CPU=y
++CONFIG_PM=y
+ CONFIG_CPU_IDLE=y
+ CONFIG_JUMP_LABEL=y
+ CONFIG_MODULES=y
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0050-RISC-V-Clear-SIP-bit-only-when-using-SBI-IPI-operati.patch b/target/linux/sunxid1/patches-5.15/0050-RISC-V-Clear-SIP-bit-only-when-using-SBI-IPI-operati.patch
new file mode 100644 (file)
index 0000000..ffe7cce
--- /dev/null
@@ -0,0 +1,53 @@
+From 65fb9bd8dc188403f9f922542ee2faae64f96a54 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Thu, 13 May 2021 14:10:34 +0530
+Subject: [PATCH 050/124] RISC-V: Clear SIP bit only when using SBI IPI
+ operations
+
+The software interrupt pending (i.e. [M|S]SIP) bit is writeable for
+S-mode but read-only for M-mode so we clear this bit only when using
+SBI IPI operations.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
+---
+ arch/riscv/kernel/sbi.c | 8 +++++++-
+ arch/riscv/kernel/smp.c | 2 --
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
+index 9a84f0cb5175..8aeca26198f2 100644
+--- a/arch/riscv/kernel/sbi.c
++++ b/arch/riscv/kernel/sbi.c
+@@ -598,8 +598,14 @@ static void sbi_send_cpumask_ipi(const struct cpumask *target)
+       sbi_send_ipi(cpumask_bits(&hartid_mask));
+ }
++static void sbi_ipi_clear(void)
++{
++      csr_clear(CSR_IP, IE_SIE);
++}
++
+ static const struct riscv_ipi_ops sbi_ipi_ops = {
+-      .ipi_inject = sbi_send_cpumask_ipi
++      .ipi_inject = sbi_send_cpumask_ipi,
++      .ipi_clear = sbi_ipi_clear
+ };
+ void __init sbi_init(void)
+diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
+index 2f6da845c9ae..f2bbaa670f72 100644
+--- a/arch/riscv/kernel/smp.c
++++ b/arch/riscv/kernel/smp.c
+@@ -99,8 +99,6 @@ void riscv_clear_ipi(void)
+ {
+       if (ipi_ops && ipi_ops->ipi_clear)
+               ipi_ops->ipi_clear();
+-
+-      csr_clear(CSR_IP, IE_SIE);
+ }
+ EXPORT_SYMBOL_GPL(riscv_clear_ipi);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0051-RISC-V-Treat-IPIs-as-normal-Linux-IRQs.patch b/target/linux/sunxid1/patches-5.15/0051-RISC-V-Treat-IPIs-as-normal-Linux-IRQs.patch
new file mode 100644 (file)
index 0000000..60a8e79
--- /dev/null
@@ -0,0 +1,843 @@
+From b3977c0e4c7396a190e8d9636573a76bd7868656 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Wed, 16 Jun 2021 14:39:29 +0530
+Subject: [PATCH 051/124] RISC-V: Treat IPIs as normal Linux IRQs
+
+Currently, the RISC-V kernel provides arch specific hooks (i.e.
+struct riscv_ipi_ops) to register IPI handling methods. The stats
+gathering of IPIs is also arch specific in the RISC-V kernel.
+
+Other architectures (such as ARM, ARM64, and MIPS) have moved away
+from custom arch specific IPI handling methods. Currently, these
+architectures have Linux irqchip drivers providing a range of Linux
+IRQ numbers to be used as IPIs and IPI triggering is done using
+generic IPI APIs. This approach allows architectures to treat IPIs
+as normal Linux IRQs and IPI stats gathering is done by the generic
+Linux IRQ subsystem.
+
+We extend the RISC-V IPI handling as-per above approach so that
+arch specific IPI handling methods (struct riscv_ipi_ops) can be
+removed and the IPI handling is totally contained within Linux
+irqchip drivers.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+---
+ arch/riscv/Kconfig                |   1 +
+ arch/riscv/include/asm/sbi.h      |   2 +
+ arch/riscv/include/asm/smp.h      |  35 +++--
+ arch/riscv/kernel/Makefile        |   1 +
+ arch/riscv/kernel/cpu-hotplug.c   |   3 +-
+ arch/riscv/kernel/irq.c           |   3 +-
+ arch/riscv/kernel/sbi-ipi.c       | 218 ++++++++++++++++++++++++++++++
+ arch/riscv/kernel/sbi.c           |  21 ---
+ arch/riscv/kernel/smp.c           | 153 +++++++++++----------
+ arch/riscv/kernel/smpboot.c       |   5 +-
+ drivers/clocksource/timer-clint.c |  23 ----
+ drivers/irqchip/irq-riscv-intc.c  |  55 ++++----
+ 12 files changed, 349 insertions(+), 171 deletions(-)
+ create mode 100644 arch/riscv/kernel/sbi-ipi.c
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index 655f35ea2e74..1d7b5066ce80 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -54,6 +54,7 @@ config RISCV
+       select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO
+       select GENERIC_IDLE_POLL_SETUP
+       select GENERIC_IOREMAP if MMU
++      select GENERIC_IRQ_IPI
+       select GENERIC_IRQ_MULTI_HANDLER
+       select GENERIC_IRQ_SHOW
+       select GENERIC_IRQ_SHOW_LEVEL
+diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
+index ab9782f8da52..ff5cecd13bda 100644
+--- a/arch/riscv/include/asm/sbi.h
++++ b/arch/riscv/include/asm/sbi.h
+@@ -123,6 +123,7 @@ struct sbiret {
+ };
+ void sbi_init(void);
++void sbi_ipi_init(void);
+ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+                       unsigned long arg1, unsigned long arg2,
+                       unsigned long arg3, unsigned long arg4,
+@@ -192,6 +193,7 @@ static inline unsigned long sbi_mk_version(unsigned long major,
+ int sbi_err_map_linux_errno(int err);
+ #else /* CONFIG_RISCV_SBI */
+ static inline int sbi_remote_fence_i(const unsigned long *hart_mask) { return -1; }
++static inline void sbi_ipi_init(void) { }
+ static inline void sbi_init(void) {}
+ #endif /* CONFIG_RISCV_SBI */
+ #endif /* _ASM_RISCV_SBI_H */
+diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
+index a7d2811f3536..e5480d75b2d9 100644
+--- a/arch/riscv/include/asm/smp.h
++++ b/arch/riscv/include/asm/smp.h
+@@ -15,11 +15,6 @@
+ struct seq_file;
+ extern unsigned long boot_cpu_hartid;
+-struct riscv_ipi_ops {
+-      void (*ipi_inject)(const struct cpumask *target);
+-      void (*ipi_clear)(void);
+-};
+-
+ #ifdef CONFIG_SMP
+ /*
+  * Mapping between linux logical cpu index and hartid.
+@@ -33,9 +28,6 @@ void show_ipi_stats(struct seq_file *p, int prec);
+ /* SMP initialization hook for setup_arch */
+ void __init setup_smp(void);
+-/* Called from C code, this handles an IPI. */
+-void handle_IPI(struct pt_regs *regs);
+-
+ /* Hook for the generic smp_call_function_many() routine. */
+ void arch_send_call_function_ipi_mask(struct cpumask *mask);
+@@ -45,11 +37,17 @@ void arch_send_call_function_single_ipi(int cpu);
+ int riscv_hartid_to_cpuid(int hartid);
+ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
+-/* Set custom IPI operations */
+-void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops);
++/* Enable IPI for CPU hotplug */
++void riscv_ipi_enable(void);
++
++/* Disable IPI for CPU hotplug */
++void riscv_ipi_disable(void);
+-/* Clear IPI for current CPU */
+-void riscv_clear_ipi(void);
++/* Check if IPI interrupt numbers are available */
++bool riscv_ipi_have_virq_range(void);
++
++/* Set the IPI interrupt numbers for arch (called by irqchip drivers) */
++void riscv_ipi_set_virq_range(int virq, int nr_irqs);
+ /* Secondary hart entry */
+ asmlinkage void smp_callin(void);
+@@ -92,11 +90,20 @@ static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
+       cpumask_set_cpu(boot_cpu_hartid, out);
+ }
+-static inline void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops)
++static inline void riscv_ipi_enable(void)
+ {
+ }
+-static inline void riscv_clear_ipi(void)
++static inline void riscv_ipi_disable(void)
++{
++}
++
++static inline bool riscv_ipi_have_virq_range(void)
++{
++      return false;
++}
++
++static inline void riscv_ipi_set_virq_range(int virq, int nr)
+ {
+ }
+diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
+index 4320629c07c3..65bcd8e344b6 100644
+--- a/arch/riscv/kernel/Makefile
++++ b/arch/riscv/kernel/Makefile
+@@ -56,6 +56,7 @@ obj-$(CONFIG_RISCV_BASE_PMU) += perf_event.o
+ obj-$(CONFIG_PERF_EVENTS)     += perf_callchain.o
+ obj-$(CONFIG_HAVE_PERF_REGS)  += perf_regs.o
+ obj-$(CONFIG_RISCV_SBI)               += sbi.o
++obj-$(CONFIG_RISCV_SBI)               += sbi-ipi.o
+ ifeq ($(CONFIG_RISCV_SBI), y)
+ obj-$(CONFIG_SMP) += cpu_ops_sbi.o
+ endif
+diff --git a/arch/riscv/kernel/cpu-hotplug.c b/arch/riscv/kernel/cpu-hotplug.c
+index df84e0c13db1..141f8a01d706 100644
+--- a/arch/riscv/kernel/cpu-hotplug.c
++++ b/arch/riscv/kernel/cpu-hotplug.c
+@@ -12,7 +12,7 @@
+ #include <linux/sched/hotplug.h>
+ #include <asm/irq.h>
+ #include <asm/cpu_ops.h>
+-#include <asm/sbi.h>
++#include <asm/smp.h>
+ void cpu_stop(void);
+ void arch_cpu_idle_dead(void)
+@@ -47,6 +47,7 @@ int __cpu_disable(void)
+       remove_cpu_topology(cpu);
+       set_cpu_online(cpu, false);
++      riscv_ipi_disable();
+       irq_migrate_all_off_this_cpu();
+       return ret;
+diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c
+index 7207fa08d78f..a179350d2208 100644
+--- a/arch/riscv/kernel/irq.c
++++ b/arch/riscv/kernel/irq.c
+@@ -8,7 +8,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/irqchip.h>
+ #include <linux/seq_file.h>
+-#include <asm/smp.h>
++#include <asm/sbi.h>
+ int arch_show_interrupts(struct seq_file *p, int prec)
+ {
+@@ -21,4 +21,5 @@ void __init init_IRQ(void)
+       irqchip_init();
+       if (!handle_arch_irq)
+               panic("No interrupt controller found.");
++      sbi_ipi_init();
+ }
+diff --git a/arch/riscv/kernel/sbi-ipi.c b/arch/riscv/kernel/sbi-ipi.c
+new file mode 100644
+index 000000000000..8d06b1e3d682
+--- /dev/null
++++ b/arch/riscv/kernel/sbi-ipi.c
+@@ -0,0 +1,218 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * SBI based IPI support.
++ *
++ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
++ */
++
++#define pr_fmt(fmt) "riscv-sbi-ipi: " fmt
++#include <linux/cpu.h>
++#include <linux/cpumask.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <linux/irqchip.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/of.h>
++#include <linux/smp.h>
++#include <asm/sbi.h>
++
++static int intc_parent_irq __ro_after_init;
++static struct irq_domain *sbi_ipi_domain __ro_after_init;
++static DEFINE_PER_CPU(unsigned long, sbi_ipi_bits);
++
++static void sbi_ipi_dummy(struct irq_data *d)
++{
++}
++
++static void sbi_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
++{
++      int cpu;
++      struct cpumask hartid_mask;
++
++      /* Barrier before doing atomic bit update to IPI bits */
++      smp_mb__before_atomic();
++      for_each_cpu(cpu, mask)
++              set_bit(d->hwirq, per_cpu_ptr(&sbi_ipi_bits, cpu));
++      /* Barrier after doing atomic bit update to IPI bits */
++      smp_mb__after_atomic();
++
++      riscv_cpuid_to_hartid_mask(mask, &hartid_mask);
++
++      sbi_send_ipi(cpumask_bits(&hartid_mask));
++}
++
++static struct irq_chip sbi_ipi_chip = {
++      .name           = "RISC-V SBI IPI",
++      .irq_mask       = sbi_ipi_dummy,
++      .irq_unmask     = sbi_ipi_dummy,
++      .ipi_send_mask  = sbi_ipi_send_mask,
++};
++
++static int sbi_ipi_domain_map(struct irq_domain *d, unsigned int irq,
++                            irq_hw_number_t hwirq)
++{
++      irq_set_percpu_devid(irq);
++      irq_domain_set_info(d, irq, hwirq, &sbi_ipi_chip, d->host_data,
++                          handle_percpu_devid_irq, NULL, NULL);
++
++      return 0;
++}
++
++static int sbi_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
++                              unsigned int nr_irqs, void *arg)
++{
++      int i, ret;
++      irq_hw_number_t hwirq;
++      unsigned int type = IRQ_TYPE_NONE;
++      struct irq_fwspec *fwspec = arg;
++
++      ret = irq_domain_translate_onecell(d, fwspec, &hwirq, &type);
++      if (ret)
++              return ret;
++
++      for (i = 0; i < nr_irqs; i++) {
++              ret = sbi_ipi_domain_map(d, virq + i, hwirq + i);
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static const struct irq_domain_ops sbi_ipi_domain_ops = {
++      .translate      = irq_domain_translate_onecell,
++      .alloc          = sbi_ipi_domain_alloc,
++      .free           = irq_domain_free_irqs_top,
++};
++
++static void sbi_ipi_handle_irq(struct irq_desc *desc)
++{
++      int err;
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      unsigned long irqs, *bits = this_cpu_ptr(&sbi_ipi_bits);
++      irq_hw_number_t hwirq;
++
++      chained_irq_enter(chip, desc);
++
++      while (true) {
++              csr_clear(CSR_IP, IE_SIE);
++
++              /* Order bit clearing and data access. */
++              mb();
++
++              irqs = xchg(bits, 0);
++              if (!irqs)
++                      goto done;
++
++              for_each_set_bit(hwirq, &irqs, BITS_PER_LONG) {
++                      err = generic_handle_domain_irq(sbi_ipi_domain,
++                                                      hwirq);
++                      if (unlikely(err))
++                              pr_warn_ratelimited(
++                                      "can't find mapping for hwirq %lu\n",
++                                      hwirq);
++              }
++      }
++
++done:
++      chained_irq_exit(chip, desc);
++}
++
++static int sbi_ipi_dying_cpu(unsigned int cpu)
++{
++      disable_percpu_irq(intc_parent_irq);
++      return 0;
++}
++
++static int sbi_ipi_starting_cpu(unsigned int cpu)
++{
++      enable_percpu_irq(intc_parent_irq,
++                        irq_get_trigger_type(intc_parent_irq));
++      return 0;
++}
++
++static int __init sbi_ipi_set_virq(void)
++{
++      int virq;
++      struct irq_fwspec ipi = {
++              .fwnode         = sbi_ipi_domain->fwnode,
++              .param_count    = 1,
++              .param[0]       = 0,
++      };
++
++      virq = __irq_domain_alloc_irqs(sbi_ipi_domain, -1, BITS_PER_LONG,
++                                     NUMA_NO_NODE, &ipi,
++                                     false, NULL);
++      if (virq <= 0) {
++              pr_err("unable to alloc IRQs from SBI IPI IRQ domain\n");
++              return -ENOMEM;
++      }
++
++      riscv_ipi_set_virq_range(virq, BITS_PER_LONG);
++
++      return 0;
++}
++
++static int __init sbi_ipi_domain_init(struct irq_domain *domain)
++{
++      struct irq_fwspec swi = {
++              .fwnode         = domain->fwnode,
++              .param_count    = 1,
++              .param[0]       = RV_IRQ_SOFT,
++      };
++
++      intc_parent_irq = __irq_domain_alloc_irqs(domain, -1, 1,
++                                                NUMA_NO_NODE, &swi,
++                                                false, NULL);
++      if (intc_parent_irq <= 0) {
++              pr_err("unable to alloc IRQ from INTC IRQ domain\n");
++              return -ENOMEM;
++      }
++
++      irq_set_chained_handler(intc_parent_irq, sbi_ipi_handle_irq);
++
++      sbi_ipi_domain = irq_domain_add_linear(NULL, BITS_PER_LONG,
++                                              &sbi_ipi_domain_ops, NULL);
++      if (!sbi_ipi_domain) {
++              pr_err("unable to add SBI IPI IRQ domain\n");
++              return -ENOMEM;
++      }
++
++      cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
++                        "irqchip/riscv/sbi-ipi:starting",
++                        sbi_ipi_starting_cpu, sbi_ipi_dying_cpu);
++
++      return sbi_ipi_set_virq();
++}
++
++void __init sbi_ipi_init(void)
++{
++      struct irq_domain *domain = NULL;
++      struct device_node *cpu, *child;
++
++      if (riscv_ipi_have_virq_range())
++              return;
++
++      for_each_of_cpu_node(cpu) {
++              child = of_get_compatible_child(cpu, "riscv,cpu-intc");
++              if (!child) {
++                      pr_err("failed to find INTC node [%pOF]\n", cpu);
++                      return;
++              }
++
++              domain = irq_find_host(child);
++              of_node_put(child);
++              if (domain)
++                      break;
++      }
++      if (!domain) {
++              pr_err("can't find INTC IRQ domain\n");
++              return;
++      }
++
++      if (sbi_ipi_domain_init(domain))
++              pr_err("failed to register IPI domain\n");
++      else
++              pr_info("registered IPI domain\n");
++}
+diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
+index 8aeca26198f2..372aa7e181d5 100644
+--- a/arch/riscv/kernel/sbi.c
++++ b/arch/riscv/kernel/sbi.c
+@@ -589,25 +589,6 @@ long sbi_get_mimpid(void)
+       return __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID);
+ }
+-static void sbi_send_cpumask_ipi(const struct cpumask *target)
+-{
+-      struct cpumask hartid_mask;
+-
+-      riscv_cpuid_to_hartid_mask(target, &hartid_mask);
+-
+-      sbi_send_ipi(cpumask_bits(&hartid_mask));
+-}
+-
+-static void sbi_ipi_clear(void)
+-{
+-      csr_clear(CSR_IP, IE_SIE);
+-}
+-
+-static const struct riscv_ipi_ops sbi_ipi_ops = {
+-      .ipi_inject = sbi_send_cpumask_ipi,
+-      .ipi_clear = sbi_ipi_clear
+-};
+-
+ void __init sbi_init(void)
+ {
+       int ret;
+@@ -654,6 +635,4 @@ void __init sbi_init(void)
+               __sbi_send_ipi  = __sbi_send_ipi_v01;
+               __sbi_rfence    = __sbi_rfence_v01;
+       }
+-
+-      riscv_set_ipi_ops(&sbi_ipi_ops);
+ }
+diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
+index f2bbaa670f72..53902cd1671f 100644
+--- a/arch/riscv/kernel/smp.c
++++ b/arch/riscv/kernel/smp.c
+@@ -17,9 +17,9 @@
+ #include <linux/sched.h>
+ #include <linux/seq_file.h>
+ #include <linux/delay.h>
++#include <linux/irq.h>
+ #include <linux/irq_work.h>
+-#include <asm/sbi.h>
+ #include <asm/tlbflush.h>
+ #include <asm/cacheflush.h>
+@@ -41,11 +41,9 @@ void __init smp_setup_processor_id(void)
+       cpuid_to_hartid_map(0) = boot_cpu_hartid;
+ }
+-/* A collection of single bit ipi messages.  */
+-static struct {
+-      unsigned long stats[IPI_MAX] ____cacheline_aligned;
+-      unsigned long bits ____cacheline_aligned;
+-} ipi_data[NR_CPUS] __cacheline_aligned;
++static int ipi_virq_base __ro_after_init;
++static int nr_ipi __ro_after_init = IPI_MAX;
++static struct irq_desc *ipi_desc[IPI_MAX] __read_mostly;
+ int riscv_hartid_to_cpuid(int hartid)
+ {
+@@ -87,46 +85,14 @@ static void ipi_stop(void)
+               wait_for_interrupt();
+ }
+-static const struct riscv_ipi_ops *ipi_ops __ro_after_init;
+-
+-void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops)
+-{
+-      ipi_ops = ops;
+-}
+-EXPORT_SYMBOL_GPL(riscv_set_ipi_ops);
+-
+-void riscv_clear_ipi(void)
+-{
+-      if (ipi_ops && ipi_ops->ipi_clear)
+-              ipi_ops->ipi_clear();
+-}
+-EXPORT_SYMBOL_GPL(riscv_clear_ipi);
+-
+ static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
+ {
+-      int cpu;
+-
+-      smp_mb__before_atomic();
+-      for_each_cpu(cpu, mask)
+-              set_bit(op, &ipi_data[cpu].bits);
+-      smp_mb__after_atomic();
+-
+-      if (ipi_ops && ipi_ops->ipi_inject)
+-              ipi_ops->ipi_inject(mask);
+-      else
+-              pr_warn("SMP: IPI inject method not available\n");
++      __ipi_send_mask(ipi_desc[op], mask);
+ }
+ static void send_ipi_single(int cpu, enum ipi_message_type op)
+ {
+-      smp_mb__before_atomic();
+-      set_bit(op, &ipi_data[cpu].bits);
+-      smp_mb__after_atomic();
+-
+-      if (ipi_ops && ipi_ops->ipi_inject)
+-              ipi_ops->ipi_inject(cpumask_of(cpu));
+-      else
+-              pr_warn("SMP: IPI inject method not available\n");
++      __ipi_send_mask(ipi_desc[op], cpumask_of(cpu));
+ }
+ #ifdef CONFIG_IRQ_WORK
+@@ -136,55 +102,88 @@ void arch_irq_work_raise(void)
+ }
+ #endif
+-void handle_IPI(struct pt_regs *regs)
++static irqreturn_t handle_IPI(int irq, void *data)
++{
++      int ipi = irq - ipi_virq_base;
++
++      switch (ipi) {
++      case IPI_RESCHEDULE:
++              scheduler_ipi();
++              break;
++      case IPI_CALL_FUNC:
++              generic_smp_call_function_interrupt();
++              break;
++      case IPI_CPU_STOP:
++              ipi_stop();
++              break;
++      case IPI_IRQ_WORK:
++              irq_work_run();
++              break;
++#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
++      case IPI_TIMER:
++              tick_receive_broadcast();
++              break;
++#endif
++      default:
++              pr_warn("CPU%d: unhandled IPI%d\n", smp_processor_id(), ipi);
++              break;
++      };
++
++      return IRQ_HANDLED;
++}
++
++void riscv_ipi_enable(void)
+ {
+-      unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
+-      unsigned long *stats = ipi_data[smp_processor_id()].stats;
++      int i;
+-      riscv_clear_ipi();
++      if (WARN_ON_ONCE(!ipi_virq_base))
++              return;
+-      while (true) {
+-              unsigned long ops;
++      for (i = 0; i < nr_ipi; i++)
++              enable_percpu_irq(ipi_virq_base + i, 0);
++}
+-              /* Order bit clearing and data access. */
+-              mb();
++void riscv_ipi_disable(void)
++{
++      int i;
+-              ops = xchg(pending_ipis, 0);
+-              if (ops == 0)
+-                      return;
++      if (WARN_ON_ONCE(!ipi_virq_base))
++              return;
+-              if (ops & (1 << IPI_RESCHEDULE)) {
+-                      stats[IPI_RESCHEDULE]++;
+-                      scheduler_ipi();
+-              }
++      for (i = 0; i < nr_ipi; i++)
++              disable_percpu_irq(ipi_virq_base + i);
++}
+-              if (ops & (1 << IPI_CALL_FUNC)) {
+-                      stats[IPI_CALL_FUNC]++;
+-                      generic_smp_call_function_interrupt();
+-              }
++bool riscv_ipi_have_virq_range(void)
++{
++      return (ipi_virq_base) ? true : false;
++}
+-              if (ops & (1 << IPI_CPU_STOP)) {
+-                      stats[IPI_CPU_STOP]++;
+-                      ipi_stop();
+-              }
++void riscv_ipi_set_virq_range(int virq, int nr)
++{
++      int i, err;
+-              if (ops & (1 << IPI_IRQ_WORK)) {
+-                      stats[IPI_IRQ_WORK]++;
+-                      irq_work_run();
+-              }
++      if (WARN_ON(ipi_virq_base))
++              return;
+-#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+-              if (ops & (1 << IPI_TIMER)) {
+-                      stats[IPI_TIMER]++;
+-                      tick_receive_broadcast();
+-              }
+-#endif
+-              BUG_ON((ops >> IPI_MAX) != 0);
++      WARN_ON(nr < IPI_MAX);
++      nr_ipi = min(nr, IPI_MAX);
++      ipi_virq_base = virq;
++
++      /* Request IPIs */
++      for (i = 0; i < nr_ipi; i++) {
++              err = request_percpu_irq(ipi_virq_base + i, handle_IPI,
++                                       "IPI", &ipi_virq_base);
++              WARN_ON(err);
+-              /* Order data access and bit testing. */
+-              mb();
++              ipi_desc[i] = irq_to_desc(ipi_virq_base + i);
++              irq_set_status_flags(ipi_virq_base + i, IRQ_HIDDEN);
+       }
++
++      /* Enabled IPIs for boot CPU immediately */
++      riscv_ipi_enable();
+ }
++EXPORT_SYMBOL_GPL(riscv_ipi_set_virq_range);
+ static const char * const ipi_names[] = {
+       [IPI_RESCHEDULE]        = "Rescheduling interrupts",
+@@ -202,7 +201,7 @@ void show_ipi_stats(struct seq_file *p, int prec)
+               seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
+                          prec >= 4 ? " " : "");
+               for_each_online_cpu(cpu)
+-                      seq_printf(p, "%10lu ", ipi_data[cpu].stats[i]);
++                      seq_printf(p, "%10u ", irq_desc_kstat_cpu(ipi_desc[i], cpu));
+               seq_printf(p, " %s\n", ipi_names[i]);
+       }
+ }
+diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
+index bd82375db51a..775d0026efd4 100644
+--- a/arch/riscv/kernel/smpboot.c
++++ b/arch/riscv/kernel/smpboot.c
+@@ -30,7 +30,6 @@
+ #include <asm/numa.h>
+ #include <asm/tlbflush.h>
+ #include <asm/sections.h>
+-#include <asm/sbi.h>
+ #include <asm/smp.h>
+ #include <asm/alternative.h>
+@@ -159,12 +158,12 @@ asmlinkage __visible void smp_callin(void)
+       struct mm_struct *mm = &init_mm;
+       unsigned int curr_cpuid = smp_processor_id();
+-      riscv_clear_ipi();
+-
+       /* All kernel threads share the same mm context.  */
+       mmgrab(mm);
+       current->active_mm = mm;
++      riscv_ipi_enable();
++
+       notify_cpu_starting(curr_cpuid);
+       numa_add_cpu(curr_cpuid);
+       update_siblings_masks(curr_cpuid);
+diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c
+index 6cfe2ab73eb0..3b68ed53fe4a 100644
+--- a/drivers/clocksource/timer-clint.c
++++ b/drivers/clocksource/timer-clint.c
+@@ -30,7 +30,6 @@
+ #define CLINT_TIMER_VAL_OFF   0xbff8
+ /* CLINT manages IPI and Timer for RISC-V M-mode  */
+-static u32 __iomem *clint_ipi_base;
+ static u64 __iomem *clint_timer_cmp;
+ static u64 __iomem *clint_timer_val;
+ static unsigned long clint_timer_freq;
+@@ -41,24 +40,6 @@ u64 __iomem *clint_time_val;
+ EXPORT_SYMBOL(clint_time_val);
+ #endif
+-static void clint_send_ipi(const struct cpumask *target)
+-{
+-      unsigned int cpu;
+-
+-      for_each_cpu(cpu, target)
+-              writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu));
+-}
+-
+-static void clint_clear_ipi(void)
+-{
+-      writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id()));
+-}
+-
+-static struct riscv_ipi_ops clint_ipi_ops = {
+-      .ipi_inject = clint_send_ipi,
+-      .ipi_clear = clint_clear_ipi,
+-};
+-
+ #ifdef CONFIG_64BIT
+ #define clint_get_cycles()    readq_relaxed(clint_timer_val)
+ #else
+@@ -189,7 +170,6 @@ static int __init clint_timer_init_dt(struct device_node *np)
+               return -ENODEV;
+       }
+-      clint_ipi_base = base + CLINT_IPI_OFF;
+       clint_timer_cmp = base + CLINT_TIMER_CMP_OFF;
+       clint_timer_val = base + CLINT_TIMER_VAL_OFF;
+       clint_timer_freq = riscv_timebase;
+@@ -228,9 +208,6 @@ static int __init clint_timer_init_dt(struct device_node *np)
+               goto fail_free_irq;
+       }
+-      riscv_set_ipi_ops(&clint_ipi_ops);
+-      clint_clear_ipi();
+-
+       return 0;
+ fail_free_irq:
+diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
+index b65bd8878d4f..c5380e3e2aa0 100644
+--- a/drivers/irqchip/irq-riscv-intc.c
++++ b/drivers/irqchip/irq-riscv-intc.c
+@@ -26,20 +26,7 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs)
+       if (unlikely(cause >= BITS_PER_LONG))
+               panic("unexpected interrupt cause");
+-      switch (cause) {
+-#ifdef CONFIG_SMP
+-      case RV_IRQ_SOFT:
+-              /*
+-               * We only use software interrupts to pass IPIs, so if a
+-               * non-SMP system gets one, then we don't know what to do.
+-               */
+-              handle_IPI(regs);
+-              break;
+-#endif
+-      default:
+-              generic_handle_domain_irq(intc_domain, cause);
+-              break;
+-      }
++      generic_handle_domain_irq(intc_domain, cause);
+ }
+ /*
+@@ -59,18 +46,6 @@ static void riscv_intc_irq_unmask(struct irq_data *d)
+       csr_set(CSR_IE, BIT(d->hwirq));
+ }
+-static int riscv_intc_cpu_starting(unsigned int cpu)
+-{
+-      csr_set(CSR_IE, BIT(RV_IRQ_SOFT));
+-      return 0;
+-}
+-
+-static int riscv_intc_cpu_dying(unsigned int cpu)
+-{
+-      csr_clear(CSR_IE, BIT(RV_IRQ_SOFT));
+-      return 0;
+-}
+-
+ static struct irq_chip riscv_intc_chip = {
+       .name = "RISC-V INTC",
+       .irq_mask = riscv_intc_irq_mask,
+@@ -87,9 +62,32 @@ static int riscv_intc_domain_map(struct irq_domain *d, unsigned int irq,
+       return 0;
+ }
++static int riscv_intc_domain_alloc(struct irq_domain *domain,
++                                 unsigned int virq, unsigned int nr_irqs,
++                                 void *arg)
++{
++      int i, ret;
++      irq_hw_number_t hwirq;
++      unsigned int type = IRQ_TYPE_NONE;
++      struct irq_fwspec *fwspec = arg;
++
++      ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
++      if (ret)
++              return ret;
++
++      for (i = 0; i < nr_irqs; i++) {
++              ret = riscv_intc_domain_map(domain, virq + i, hwirq + i);
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
++}
++
+ static const struct irq_domain_ops riscv_intc_domain_ops = {
+       .map    = riscv_intc_domain_map,
+       .xlate  = irq_domain_xlate_onecell,
++      .alloc  = riscv_intc_domain_alloc
+ };
+ static int __init riscv_intc_init(struct device_node *node,
+@@ -125,11 +123,6 @@ static int __init riscv_intc_init(struct device_node *node,
+               return rc;
+       }
+-      cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_STARTING,
+-                        "irqchip/riscv/intc:starting",
+-                        riscv_intc_cpu_starting,
+-                        riscv_intc_cpu_dying);
+-
+       pr_info("%d local interrupts mapped\n", BITS_PER_LONG);
+       return 0;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0052-clocksource-clint-Add-support-for-ACLINT-MTIMER-devi.patch b/target/linux/sunxid1/patches-5.15/0052-clocksource-clint-Add-support-for-ACLINT-MTIMER-devi.patch
new file mode 100644 (file)
index 0000000..1e4669c
--- /dev/null
@@ -0,0 +1,138 @@
+From 3877938e9a34e561cb6564ea033454d7d5615ca8 Mon Sep 17 00:00:00 2001
+From: Anup Patel <anup.patel@wdc.com>
+Date: Thu, 17 Jun 2021 16:36:16 +0530
+Subject: [PATCH 052/124] clocksource: clint: Add support for ACLINT MTIMER
+ device
+
+The RISC-V ACLINT specification is a modular specification and the
+ACLINT MTIMER device is backward compatible with the M-mode timer
+functionality of the CLINT device. This patch extends the CLINT
+timer driver to support both CLINT device and ACLINT MTIMER device.
+
+Signed-off-by: Anup Patel <anup.patel@wdc.com>
+Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
+---
+ drivers/clocksource/timer-clint.c | 59 ++++++++++++++++++++++++-------
+ 1 file changed, 47 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c
+index 3b68ed53fe4a..9d38dfce374e 100644
+--- a/drivers/clocksource/timer-clint.c
++++ b/drivers/clocksource/timer-clint.c
+@@ -2,8 +2,16 @@
+ /*
+  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+  *
+- * Most of the M-mode (i.e. NoMMU) RISC-V systems usually have a
+- * CLINT MMIO timer device.
++ * Most of the M-mode (i.e. NoMMU) RISC-V systems usually have a CLINT
++ * MMIO device which is a composite device capable of injecting M-mode
++ * software interrupts and M-mode timer interrupts.
++ *
++ * The RISC-V ACLINT specification is modular in nature and defines
++ * separate devices for M-mode software interrupt (MSWI), M-mode timer
++ * (MTIMER) and S-mode software interrupt (SSWI).
++ *
++ * This is a common timer driver for the CLINT device and the ACLINT
++ * MTIMER device.
+  */
+ #define pr_fmt(fmt) "clint: " fmt
+@@ -17,12 +25,16 @@
+ #include <linux/sched_clock.h>
+ #include <linux/io-64-nonatomic-lo-hi.h>
+ #include <linux/interrupt.h>
++#include <linux/irqchip/irq-riscv-aclint-swi.h>
+ #include <linux/of_irq.h>
+ #include <linux/smp.h>
+ #include <linux/timex.h>
+-#ifndef CONFIG_RISCV_M_MODE
++#ifdef CONFIG_RISCV_M_MODE
+ #include <asm/clint.h>
++
++u64 __iomem *clint_time_val;
++EXPORT_SYMBOL(clint_time_val);
+ #endif
+ #define CLINT_IPI_OFF         0
+@@ -35,11 +47,6 @@ static u64 __iomem *clint_timer_val;
+ static unsigned long clint_timer_freq;
+ static unsigned int clint_timer_irq;
+-#ifdef CONFIG_RISCV_M_MODE
+-u64 __iomem *clint_time_val;
+-EXPORT_SYMBOL(clint_time_val);
+-#endif
+-
+ #ifdef CONFIG_64BIT
+ #define clint_get_cycles()    readq_relaxed(clint_timer_val)
+ #else
+@@ -129,8 +136,10 @@ static int __init clint_timer_init_dt(struct device_node *np)
+ {
+       int rc;
+       u32 i, nr_irqs;
+-      void __iomem *base;
++      void __iomem *base = NULL;
++      void __iomem *base1 = NULL;
+       struct of_phandle_args oirq;
++      bool is_aclint = of_device_is_compatible(np, "riscv,aclint-mtimer");
+       /*
+        * Ensure that CLINT device interrupts are either RV_IRQ_TIMER or
+@@ -170,8 +179,19 @@ static int __init clint_timer_init_dt(struct device_node *np)
+               return -ENODEV;
+       }
+-      clint_timer_cmp = base + CLINT_TIMER_CMP_OFF;
+-      clint_timer_val = base + CLINT_TIMER_VAL_OFF;
++      if (is_aclint) {
++              clint_timer_val = base;
++              base1 = of_iomap(np, 1);
++              if (!base1) {
++                      rc = -ENODEV;
++                      pr_err("%pOFP: could not map registers\n", np);
++                      goto fail_iounmap;
++              }
++              clint_timer_cmp = base1;
++      } else {
++              clint_timer_cmp = base + CLINT_TIMER_CMP_OFF;
++              clint_timer_val = base + CLINT_TIMER_VAL_OFF;
++      }
+       clint_timer_freq = riscv_timebase;
+ #ifdef CONFIG_RISCV_M_MODE
+@@ -208,14 +228,29 @@ static int __init clint_timer_init_dt(struct device_node *np)
+               goto fail_free_irq;
+       }
++      if (!is_aclint) {
++              rc = aclint_swi_init(np, base + CLINT_IPI_OFF);
++              if (rc) {
++                      pr_err("%pOFP: aclint swi init failed [%d]\n",
++                             np, rc);
++                      goto fail_remove_cpuhp;
++              }
++      }
++
+       return 0;
++fail_remove_cpuhp:
++      cpuhp_remove_state(CPUHP_AP_CLINT_TIMER_STARTING);
+ fail_free_irq:
+       free_irq(clint_timer_irq, &clint_clock_event);
+ fail_iounmap:
+-      iounmap(base);
++      if (base1)
++              iounmap(base1);
++      if (base)
++              iounmap(base);
+       return rc;
+ }
+ TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt);
+ TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt);
++TIMER_OF_DECLARE(clint_timer2, "riscv,aclint-mtimer", clint_timer_init_dt);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0053-irqchip-sun20i-Add-Allwinner-D1-stacked-INTC-driver.patch b/target/linux/sunxid1/patches-5.15/0053-irqchip-sun20i-Add-Allwinner-D1-stacked-INTC-driver.patch
new file mode 100644 (file)
index 0000000..739a3c6
--- /dev/null
@@ -0,0 +1,156 @@
+From 41c15354d89edf12be64f19ababdaaee0cccaef2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 10:58:08 -0500
+Subject: [PATCH 053/124] irqchip/sun20i: Add Allwinner D1 stacked INTC driver
+
+The D1 SoC uses the RISC-V PLIC as its main interrupt controller, but
+the PLIC does not provide any interface for configuring IRQ trigger type
+or wakeup capability. So Allwinner added registers in a separate MMIO
+region (RISCV_CFG) to support these features.
+
+Neither of those features is needed at the moment: most peripherals use
+level interrupts, and RISC-V Linux does not yet support system suspend.
+Plus, there are some complications with this extra MMIO region requiring
+clocks/resets to access, which are not available during of_irq_init().
+
+However, adding this irqchip later would be a compatibility-breaking
+devicetree change, so at least a stub driver is needed for now.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/irqchip/Kconfig      |  3 ++
+ drivers/irqchip/Makefile     |  1 +
+ drivers/irqchip/irq-sun20i.c | 95 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 99 insertions(+)
+ create mode 100644 drivers/irqchip/irq-sun20i.c
+
+diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
+index aca7b595c4c7..ca982f2f6467 100644
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -522,6 +522,9 @@ config SIFIVE_PLIC
+          If you don't know what to do here, say Y.
++config SUN20I_INTC
++      bool
++
+ config EXYNOS_IRQ_COMBINER
+       bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST
+       depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST
+diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
+index f88cbf36a9d2..ba1097e01991 100644
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -98,6 +98,7 @@ obj-$(CONFIG_CSKY_MPINTC)            += irq-csky-mpintc.o
+ obj-$(CONFIG_CSKY_APB_INTC)           += irq-csky-apb-intc.o
+ obj-$(CONFIG_RISCV_INTC)              += irq-riscv-intc.o
+ obj-$(CONFIG_SIFIVE_PLIC)             += irq-sifive-plic.o
++obj-$(CONFIG_SUN20I_INTC)             += irq-sun20i.o
+ obj-$(CONFIG_IMX_IRQSTEER)            += irq-imx-irqsteer.o
+ obj-$(CONFIG_IMX_INTMUX)              += irq-imx-intmux.o
+ obj-$(CONFIG_MADERA_IRQ)              += irq-madera.o
+diff --git a/drivers/irqchip/irq-sun20i.c b/drivers/irqchip/irq-sun20i.c
+new file mode 100644
+index 000000000000..ee1b81aa7ff7
+--- /dev/null
++++ b/drivers/irqchip/irq-sun20i.c
+@@ -0,0 +1,95 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Allwinner sun20i (D1) wakeup irqchip driver.
++ */
++
++#include <linux/bitmap.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/irqchip.h>
++#include <linux/irqdomain.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/syscore_ops.h>
++
++#define SUN20I_HWIRQ_OFFSET           16
++#define SUN20I_NR_HWIRQS              160
++
++static struct irq_chip sun20i_intc_chip = {
++      .name                   = "sun20i-intc",
++      .irq_mask               = irq_chip_mask_parent,
++      .irq_unmask             = irq_chip_unmask_parent,
++      .irq_eoi                = irq_chip_eoi_parent,
++      .irq_set_affinity       = irq_chip_set_affinity_parent,
++};
++
++static int sun20i_intc_domain_translate(struct irq_domain *domain,
++                                      struct irq_fwspec *fwspec,
++                                      unsigned long *hwirq,
++                                      unsigned int *type)
++{
++      if (fwspec->param_count < 2)
++              return -EINVAL;
++      if (fwspec->param[0] < SUN20I_HWIRQ_OFFSET)
++              return -EINVAL;
++
++      *hwirq = fwspec->param[0];
++      *type  = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
++
++      return 0;
++}
++
++static int sun20i_intc_domain_alloc(struct irq_domain *domain,
++                                  unsigned int virq,
++                                  unsigned int nr_irqs, void *arg)
++{
++      struct irq_fwspec *fwspec = arg;
++      unsigned long hwirq;
++      unsigned int type;
++      int i, ret;
++
++      ret = sun20i_intc_domain_translate(domain, fwspec, &hwirq, &type);
++      if (ret)
++              return ret;
++      if (hwirq + nr_irqs > SUN20I_HWIRQ_OFFSET + SUN20I_NR_HWIRQS)
++              return -EINVAL;
++
++      ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, fwspec);
++      if (ret)
++              return ret;
++
++      for (i = 0; i < nr_irqs; ++i, ++hwirq, ++virq)
++              irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
++                                            &sun20i_intc_chip, 0);
++
++      return 0;
++}
++
++static const struct irq_domain_ops sun20i_intc_domain_ops = {
++      .translate      = sun20i_intc_domain_translate,
++      .alloc          = sun20i_intc_domain_alloc,
++      .free           = irq_domain_free_irqs_common,
++};
++
++static int __init sun20i_intc_init(struct device_node *node,
++                                 struct device_node *parent)
++{
++      struct irq_domain *domain, *parent_domain;
++
++      parent_domain = irq_find_host(parent);
++      if (!parent_domain) {
++              pr_err("%pOF: Failed to obtain parent domain\n", node);
++              return -ENXIO;
++      }
++
++      domain = irq_domain_add_hierarchy(parent_domain, 0, 0, node,
++                                        &sun20i_intc_domain_ops, NULL);
++      if (!domain) {
++              pr_err("%pOF: Failed to allocate domain\n", node);
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++IRQCHIP_DECLARE(sun20i_intc, "allwinner,sun20i-d1-intc", sun20i_intc_init);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0054-clk-sunxi-ng-div-Add-macros-using-clk_parent_data-an.patch b/target/linux/sunxid1/patches-5.15/0054-clk-sunxi-ng-div-Add-macros-using-clk_parent_data-an.patch
new file mode 100644 (file)
index 0000000..d6ff0fb
--- /dev/null
@@ -0,0 +1,115 @@
+From 020c708867842e41e96d6a73081a7d32415b2301 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 01:08:23 -0500
+Subject: [PATCH 054/124] clk: sunxi-ng: div: Add macros using clk_parent_data
+ and clk_hw
+
+Referencing parents with clk_hw pointers is more efficient and removes
+the dependency on global clock names. clk_parent_data is needed when
+some parent clocks are provided from another driver. Add macros for
+declaring dividers that take advantage of these.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu_div.h | 78 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 78 insertions(+)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h
+index 6682fde6043c..948e2b0c0c3b 100644
+--- a/drivers/clk/sunxi-ng/ccu_div.h
++++ b/drivers/clk/sunxi-ng/ccu_div.h
+@@ -108,6 +108,22 @@ struct ccu_div {
+                                     _shift, _width, _table, 0,        \
+                                     _flags)
++#define SUNXI_CCU_DIV_TABLE_HW(_struct, _name, _parent, _reg,         \
++                             _shift, _width,                          \
++                             _table, _flags)                          \
++      struct ccu_div _struct = {                                      \
++              .div            = _SUNXI_CCU_DIV_TABLE(_shift, _width,  \
++                                                     _table),         \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_HW(_name,         \
++                                                       _parent,       \
++                                                       &ccu_div_ops,  \
++                                                       _flags),       \
++              }                                                       \
++      }
++
++
+ #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name,                       \
+                                       _parents, _table,               \
+                                       _reg,                           \
+@@ -166,6 +182,68 @@ struct ccu_div {
+       SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg,            \
+                             _mshift, _mwidth, 0, _flags)
++#define SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,        \
++                                     _mshift, _mwidth,                \
++                                     _muxshift, _muxwidth,            \
++                                     _gate, _flags)                   \
++      struct ccu_div _struct = {                                      \
++              .enable = _gate,                                        \
++              .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
++              .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
++                                                                 _parents, \
++                                                                 &ccu_div_ops, \
++                                                                 _flags), \
++              },                                                      \
++      }
++
++#define SUNXI_CCU_M_DATA_WITH_MUX(_struct, _name, _parents, _reg,     \
++                                _mshift, _mwidth,                     \
++                                _muxshift, _muxwidth,                 \
++                                _flags)                               \
++      SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,  \
++                                     _mshift, _mwidth,                \
++                                     _muxshift, _muxwidth,            \
++                                     0, _flags)
++
++#define SUNXI_CCU_M_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,  \
++                                   _mshift, _mwidth, _muxshift, _muxwidth, \
++                                   _gate, _flags)                     \
++      struct ccu_div _struct = {                                      \
++              .enable = _gate,                                        \
++              .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
++              .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_PARENTS_HW(_name, \
++                                                               _parents, \
++                                                               &ccu_div_ops, \
++                                                               _flags), \
++              },                                                      \
++      }
++
++#define SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg,      \
++                                _mshift, _mwidth, _gate,              \
++                                _flags)                               \
++      struct ccu_div _struct = {                                      \
++              .enable = _gate,                                        \
++              .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_HWS(_name,        \
++                                                        _parent,      \
++                                                        &ccu_div_ops, \
++                                                        _flags),      \
++              },                                                      \
++      }
++
++#define SUNXI_CCU_M_HWS(_struct, _name, _parent, _reg, _mshift,               \
++                      _mwidth, _flags)                                \
++      SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg,        \
++                                _mshift, _mwidth, 0, _flags)
++
+ static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
+ {
+       struct ccu_common *common = hw_to_ccu_common(hw);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0055-clk-sunxi-ng-mp-Add-macros-using-clk_parent_data-and.patch b/target/linux/sunxid1/patches-5.15/0055-clk-sunxi-ng-mp-Add-macros-using-clk_parent_data-and.patch
new file mode 100644 (file)
index 0000000..96a2e98
--- /dev/null
@@ -0,0 +1,79 @@
+From 3ae434b57e6db1761db9403512a21cac890a8856 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 01:08:23 -0500
+Subject: [PATCH 055/124] clk: sunxi-ng: mp: Add macros using clk_parent_data
+ and clk_hw
+
+Referencing parents with clk_hw pointers is more efficient and removes
+the dependency on global clock names. clk_parent_data is needed when
+some parent clocks are provided from another driver. Add macros for
+declaring dividers that take advantage of these.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu_mp.h | 49 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h
+index b392e0d575b5..6e50f3728fb5 100644
+--- a/drivers/clk/sunxi-ng/ccu_mp.h
++++ b/drivers/clk/sunxi-ng/ccu_mp.h
+@@ -82,6 +82,55 @@ struct ccu_mp {
+                                  _muxshift, _muxwidth,                \
+                                  0, _flags)
++#define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,       \
++                                      _mshift, _mwidth,               \
++                                      _pshift, _pwidth,               \
++                                      _muxshift, _muxwidth,           \
++                                      _gate, _flags)                  \
++      struct ccu_mp _struct = {                                       \
++              .enable = _gate,                                        \
++              .m      = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
++              .p      = _SUNXI_CCU_DIV(_pshift, _pwidth),             \
++              .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
++                                                                 _parents, \
++                                                                 &ccu_mp_ops, \
++                                                                 _flags), \
++              }                                                       \
++      }
++
++#define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,    \
++                                 _mshift, _mwidth,                    \
++                                 _pshift, _pwidth,                    \
++                                 _muxshift, _muxwidth,                \
++                                 _flags)                              \
++      SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
++                                      _mshift, _mwidth,               \
++                                      _pshift, _pwidth,               \
++                                      _muxshift, _muxwidth,           \
++                                      0, _flags)
++
++#define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
++                                    _mshift, _mwidth,                 \
++                                    _pshift, _pwidth,                 \
++                                    _muxshift, _muxwidth,             \
++                                    _gate, _flags)                    \
++      struct ccu_mp _struct = {                                       \
++              .enable = _gate,                                        \
++              .m      = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
++              .p      = _SUNXI_CCU_DIV(_pshift, _pwidth),             \
++              .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_PARENTS_HW(_name, \
++                                                               _parents, \
++                                                               &ccu_mp_ops, \
++                                                               _flags), \
++              }                                                       \
++      }
++
+ static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
+ {
+       struct ccu_common *common = hw_to_ccu_common(hw);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0056-clk-sunxi-ng-mux-Add-macros-using-clk_parent_data-an.patch b/target/linux/sunxid1/patches-5.15/0056-clk-sunxi-ng-mux-Add-macros-using-clk_parent_data-an.patch
new file mode 100644 (file)
index 0000000..92a7799
--- /dev/null
@@ -0,0 +1,63 @@
+From 916bf0d78efdb771692043170aceaa87ebd29617 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 01:08:23 -0500
+Subject: [PATCH 056/124] clk: sunxi-ng: mux: Add macros using clk_parent_data
+ and clk_hw
+
+Referencing parents with clk_hw pointers is more efficient and removes
+the dependency on global clock names. clk_parent_data is needed when
+some parent clocks are provided from another driver. Add macros for
+declaring muxes that take advantage of these.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu_mux.h | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h
+index f165395effb5..f9a674c69c65 100644
+--- a/drivers/clk/sunxi-ng/ccu_mux.h
++++ b/drivers/clk/sunxi-ng/ccu_mux.h
+@@ -73,6 +73,39 @@ struct ccu_mux {
+       SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,   \
+                                     _reg, _shift, _width, 0, _flags)
++#define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,  \
++                                   _shift, _width, _gate, _flags)     \
++      struct ccu_mux _struct = {                                      \
++              .enable = _gate,                                        \
++              .mux    = _SUNXI_CCU_MUX(_shift, _width),               \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
++                                                                 _parents, \
++                                                                 &ccu_mux_ops, \
++                                                                 _flags), \
++              }                                                       \
++      }
++
++#define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg,            \
++                    _shift, _width, _flags)                           \
++      SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,    \
++                                   _shift, _width, 0, _flags)
++
++#define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg,    \
++                                 _shift, _width, _gate, _flags)       \
++      struct ccu_mux _struct = {                                      \
++              .enable = _gate,                                        \
++              .mux    = _SUNXI_CCU_MUX(_shift, _width),               \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .hw.init        = CLK_HW_INIT_PARENTS_HW(_name, \
++                                                               _parents, \
++                                                               &ccu_mux_ops, \
++                                                               _flags), \
++              }                                                       \
++      }
++
+ static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
+ {
+       struct ccu_common *common = hw_to_ccu_common(hw);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0057-clk-sunxi-ng-gate-Add-macros-for-gates-with-fixed-di.patch b/target/linux/sunxid1/patches-5.15/0057-clk-sunxi-ng-gate-Add-macros-for-gates-with-fixed-di.patch
new file mode 100644 (file)
index 0000000..fe6aa87
--- /dev/null
@@ -0,0 +1,75 @@
+From 6420720c7f1c456341f71a0a9da3b79f26d89f30 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 01:21:11 -0500
+Subject: [PATCH 057/124] clk: sunxi-ng: gate: Add macros for gates with fixed
+ dividers
+
+It is possible to declare a gate with a fixed divider, by using the
+CCU_FEATURE_ALL_PREDIV flag. Since this is not obvious, add a macro
+for declaring this type of clock.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu_gate.h | 32 +++++++++++++++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/sunxi-ng/ccu_gate.h b/drivers/clk/sunxi-ng/ccu_gate.h
+index c386689a952b..dc05ce06737a 100644
+--- a/drivers/clk/sunxi-ng/ccu_gate.h
++++ b/drivers/clk/sunxi-ng/ccu_gate.h
+@@ -53,7 +53,7 @@ struct ccu_gate {
+       }
+ /*
+- * The following two macros allow the re-use of the data structure
++ * The following macros allow the re-use of the data structure
+  * holding the parent info.
+  */
+ #define SUNXI_CCU_GATE_HWS(_struct, _name, _parent, _reg, _gate, _flags) \
+@@ -68,6 +68,21 @@ struct ccu_gate {
+               }                                                       \
+       }
++#define SUNXI_CCU_GATE_HWS_WITH_PREDIV(_struct, _name, _parent, _reg, \
++                                     _gate, _prediv, _flags)          \
++      struct ccu_gate _struct = {                                     \
++              .enable = _gate,                                        \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .prediv         = _prediv,                      \
++                      .features       = CCU_FEATURE_ALL_PREDIV,       \
++                      .hw.init        = CLK_HW_INIT_HWS(_name,        \
++                                                        _parent,      \
++                                                        &ccu_gate_ops, \
++                                                        _flags),      \
++              }                                                       \
++      }
++
+ #define SUNXI_CCU_GATE_DATA(_struct, _name, _data, _reg, _gate, _flags)       \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+@@ -81,6 +96,21 @@ struct ccu_gate {
+               }                                                       \
+       }
++#define SUNXI_CCU_GATE_DATA_WITH_PREDIV(_struct, _name, _parent, _reg,        \
++                                      _gate, _prediv, _flags)         \
++      struct ccu_gate _struct = {                                     \
++              .enable = _gate,                                        \
++              .common = {                                             \
++                      .reg            = _reg,                         \
++                      .prediv         = _prediv,                      \
++                      .features       = CCU_FEATURE_ALL_PREDIV,       \
++                      .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
++                                                                 _parent, \
++                                                                 &ccu_gate_ops, \
++                                                                 _flags), \
++              }                                                       \
++      }
++
+ static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
+ {
+       struct ccu_common *common = hw_to_ccu_common(hw);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0058-clk-sunxi-ng-Add-support-for-the-D1-SoC-clocks.patch b/target/linux/sunxid1/patches-5.15/0058-clk-sunxi-ng-Add-support-for-the-D1-SoC-clocks.patch
new file mode 100644 (file)
index 0000000..4221012
--- /dev/null
@@ -0,0 +1,1653 @@
+From 78feeb7c1c73da8480ca503812f289e0265a9345 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 20 May 2021 00:09:46 -0500
+Subject: [PATCH 058/124] clk: sunxi-ng: Add support for the D1 SoC clocks
+
+The D1 SoC contains a CCU and a R_CCU (PRCM CCU). Add support for them.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/Kconfig           |   10 +
+ drivers/clk/sunxi-ng/Makefile          |    4 +
+ drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c |  140 +++
+ drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h |   17 +
+ drivers/clk/sunxi-ng/ccu-sun20i-d1.c   | 1390 ++++++++++++++++++++++++
+ drivers/clk/sunxi-ng/ccu-sun20i-d1.h   |   15 +
+ 6 files changed, 1576 insertions(+)
+ create mode 100644 drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c
+ create mode 100644 drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h
+ create mode 100644 drivers/clk/sunxi-ng/ccu-sun20i-d1.c
+ create mode 100644 drivers/clk/sunxi-ng/ccu-sun20i-d1.h
+
+diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
+index ee383658ff4d..26555f59515d 100644
+--- a/drivers/clk/sunxi-ng/Kconfig
++++ b/drivers/clk/sunxi-ng/Kconfig
+@@ -12,6 +12,16 @@ config SUNIV_F1C100S_CCU
+       default MACH_SUNIV
+       depends on MACH_SUNIV || COMPILE_TEST
++config SUN20I_D1_CCU
++      tristate "Support for the Allwinner D1 CCU"
++      default RISCV && ARCH_SUNXI
++      depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST
++
++config SUN20I_D1_R_CCU
++      tristate "Support for the Allwinner D1 PRCM CCU"
++      default RISCV && ARCH_SUNXI
++      depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST
++
+ config SUN50I_A64_CCU
+       tristate "Support for the Allwinner A64 CCU"
+       default ARM64 && ARCH_SUNXI
+diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
+index 659d55150c32..ec931cb7aa14 100644
+--- a/drivers/clk/sunxi-ng/Makefile
++++ b/drivers/clk/sunxi-ng/Makefile
+@@ -25,6 +25,8 @@ sunxi-ccu-y                  += ccu_mp.o
+ # SoC support
+ obj-$(CONFIG_SUNIV_F1C100S_CCU)       += suniv-f1c100s-ccu.o
++obj-$(CONFIG_SUN20I_D1_CCU)   += sun20i-d1-ccu.o
++obj-$(CONFIG_SUN20I_D1_R_CCU) += sun20i-d1-r-ccu.o
+ obj-$(CONFIG_SUN50I_A64_CCU)  += sun50i-a64-ccu.o
+ obj-$(CONFIG_SUN50I_A100_CCU) += sun50i-a100-ccu.o
+ obj-$(CONFIG_SUN50I_A100_R_CCU)       += sun50i-a100-r-ccu.o
+@@ -47,6 +49,8 @@ obj-$(CONFIG_SUN9I_A80_CCU)  += sun9i-a80-de-ccu.o
+ obj-$(CONFIG_SUN9I_A80_CCU)   += sun9i-a80-usb-ccu.o
+ suniv-f1c100s-ccu-y           += ccu-suniv-f1c100s.o
++sun20i-d1-ccu-y                       += ccu-sun20i-d1.o
++sun20i-d1-r-ccu-y             += ccu-sun20i-d1-r.o
+ sun50i-a64-ccu-y              += ccu-sun50i-a64.o
+ sun50i-a100-ccu-y             += ccu-sun50i-a100.o
+ sun50i-a100-r-ccu-y           += ccu-sun50i-a100-r.o
+diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c
+new file mode 100644
+index 000000000000..9d3ffd3fb2c1
+--- /dev/null
++++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c
+@@ -0,0 +1,140 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include "ccu_common.h"
++#include "ccu_reset.h"
++
++#include "ccu_gate.h"
++#include "ccu_mp.h"
++
++#include "ccu-sun20i-d1-r.h"
++
++static const struct clk_parent_data r_ahb_apb0_parents[] = {
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++      { .fw_name = "iosc" },
++      { .fw_name = "pll-periph" },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX(r_ahb_clk, "r-ahb",
++                                r_ahb_apb0_parents, 0x000,
++                                0, 5,         /* M */
++                                8, 2,         /* P */
++                                24, 3,        /* mux */
++                                0);
++static const struct clk_hw *r_ahb_hw = &r_ahb_clk.common.hw;
++
++static SUNXI_CCU_MP_DATA_WITH_MUX(r_apb0_clk, "r-apb0",
++                                r_ahb_apb0_parents, 0x00c,
++                                0, 5,         /* M */
++                                8, 2,         /* P */
++                                24, 3,        /* mux */
++                                0);
++static const struct clk_hw *r_apb0_hw = &r_apb0_clk.common.hw;
++
++static SUNXI_CCU_GATE_HWS(bus_r_timer_clk,    "bus-r-timer",  &r_apb0_hw,
++                        0x11c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_r_twd_clk,      "bus-r-twd",    &r_apb0_hw,
++                        0x12c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_r_ppu_clk,      "bus-r-ppu",    &r_apb0_hw,
++                        0x1ac, BIT(0), 0);
++
++static const struct clk_parent_data r_ir_rx_parents[] = {
++      { .fw_name = "losc" },
++      { .fw_name = "hosc" },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(r_ir_rx_clk, "r-ir-rx",
++                                     r_ir_rx_parents, 0x1c0,
++                                     0, 5,    /* M */
++                                     8, 2,    /* P */
++                                     24, 2,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_GATE_HWS(bus_r_ir_rx_clk,    "bus-r-ir-rx",  &r_apb0_hw,
++                        0x1cc, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_r_rtc_clk,      "bus-r-rtc",    &r_ahb_hw,
++                        0x20c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_r_cpucfg_clk,   "bus-r-cpucfg", &r_apb0_hw,
++                        0x22c, BIT(0), 0);
++
++static struct ccu_common *sun20i_d1_r_ccu_clks[] = {
++      &r_ahb_clk.common,
++      &r_apb0_clk.common,
++      &bus_r_timer_clk.common,
++      &bus_r_twd_clk.common,
++      &bus_r_ppu_clk.common,
++      &r_ir_rx_clk.common,
++      &bus_r_ir_rx_clk.common,
++      &bus_r_rtc_clk.common,
++      &bus_r_cpucfg_clk.common,
++};
++
++static struct clk_hw_onecell_data sun20i_d1_r_hw_clks = {
++      .num    = CLK_NUMBER,
++      .hws    = {
++              [CLK_R_AHB]             = &r_ahb_clk.common.hw,
++              [CLK_R_APB0]            = &r_apb0_clk.common.hw,
++              [CLK_BUS_R_TIMER]       = &bus_r_timer_clk.common.hw,
++              [CLK_BUS_R_TWD]         = &bus_r_twd_clk.common.hw,
++              [CLK_BUS_R_PPU]         = &bus_r_ppu_clk.common.hw,
++              [CLK_R_IR_RX]           = &r_ir_rx_clk.common.hw,
++              [CLK_BUS_R_IR_RX]       = &bus_r_ir_rx_clk.common.hw,
++              [CLK_BUS_R_RTC]         = &bus_r_rtc_clk.common.hw,
++              [CLK_BUS_R_CPUCFG]      = &bus_r_cpucfg_clk.common.hw,
++      },
++};
++
++static struct ccu_reset_map sun20i_d1_r_ccu_resets[] = {
++      [RST_BUS_R_TIMER]       = { 0x11c, BIT(16) },
++      [RST_BUS_R_TWD]         = { 0x12c, BIT(16) },
++      [RST_BUS_R_PPU]         = { 0x1ac, BIT(16) },
++      [RST_BUS_R_IR_RX]       = { 0x1cc, BIT(16) },
++      [RST_BUS_R_RTC]         = { 0x20c, BIT(16) },
++      [RST_BUS_R_CPUCFG]      = { 0x22c, BIT(16) },
++};
++
++static const struct sunxi_ccu_desc sun20i_d1_r_ccu_desc = {
++      .ccu_clks       = sun20i_d1_r_ccu_clks,
++      .num_ccu_clks   = ARRAY_SIZE(sun20i_d1_r_ccu_clks),
++
++      .hw_clks        = &sun20i_d1_r_hw_clks,
++
++      .resets         = sun20i_d1_r_ccu_resets,
++      .num_resets     = ARRAY_SIZE(sun20i_d1_r_ccu_resets),
++};
++
++static int sun20i_d1_r_ccu_probe(struct platform_device *pdev)
++{
++      void __iomem *reg;
++
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
++
++      return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun20i_d1_r_ccu_desc);
++}
++
++static const struct of_device_id sun20i_d1_r_ccu_ids[] = {
++      { .compatible = "allwinner,sun20i-d1-r-ccu" },
++      { }
++};
++
++static struct platform_driver sun20i_d1_r_ccu_driver = {
++      .probe  = sun20i_d1_r_ccu_probe,
++      .driver = {
++              .name                   = "sun20i-d1-r-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun20i_d1_r_ccu_ids,
++      },
++};
++module_platform_driver(sun20i_d1_r_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h
+new file mode 100644
+index 000000000000..afd4342209ee
+--- /dev/null
++++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h
+@@ -0,0 +1,17 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2020 frank@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _CCU_SUN20I_D1_R_H
++#define _CCU_SUN20I_D1_R_H
++
++#include <dt-bindings/clock/sun20i-d1-r-ccu.h>
++#include <dt-bindings/reset/sun20i-d1-r-ccu.h>
++
++#define CLK_R_APB0            1
++
++#define CLK_NUMBER            (CLK_BUS_R_CPUCFG + 1)
++
++#endif /* _CCU_SUN20I_D1_R_H */
+diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c
+new file mode 100644
+index 000000000000..51058ba4db4d
+--- /dev/null
++++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c
+@@ -0,0 +1,1390 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include "../clk.h"
++
++#include "ccu_common.h"
++#include "ccu_reset.h"
++
++#include "ccu_div.h"
++#include "ccu_gate.h"
++#include "ccu_mp.h"
++#include "ccu_mult.h"
++#include "ccu_nk.h"
++#include "ccu_nkm.h"
++#include "ccu_nkmp.h"
++#include "ccu_nm.h"
++
++#include "ccu-sun20i-d1.h"
++
++static const struct clk_parent_data osc24M[] = {
++      { .fw_name = "hosc" }
++};
++
++/*
++ * For the CPU PLL, the output divider is described as "only for testing"
++ * in the user manual. So it's not modelled and forced to 0.
++ */
++#define SUN20I_D1_PLL_CPUX_REG                0x000
++static struct ccu_mult pll_cpux_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .mult           = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .common         = {
++              .reg            = 0x000,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-cpux", osc24M,
++                                                         &ccu_mult_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
++#define SUN20I_D1_PLL_DDR0_REG                0x010
++static struct ccu_nkmp pll_ddr0_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
++      .p              = _SUNXI_CCU_DIV(0, 1), /* output divider */
++      .common         = {
++              .reg            = 0x010,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-ddr0", osc24M,
++                                                         &ccu_nkmp_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++#define SUN20I_D1_PLL_PERIPH0_REG     0x020
++static struct ccu_nm pll_periph0_4x_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
++      .common         = {
++              .reg            = 0x020,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-periph0-4x", osc24M,
++                                                         &ccu_nm_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++static const struct clk_hw *pll_periph0_4x_hws[] = {
++      &pll_periph0_4x_clk.common.hw
++};
++static SUNXI_CCU_M_HWS(pll_periph0_2x_clk, "pll-periph0-2x",
++                     pll_periph0_4x_hws, 0x020, 16, 3, 0);
++static SUNXI_CCU_M_HWS(pll_periph0_800M_clk, "pll-periph0-800M",
++                     pll_periph0_4x_hws, 0x020, 20, 3, 0);
++
++static const struct clk_hw *pll_periph0_2x_hws[] = {
++      &pll_periph0_2x_clk.common.hw
++};
++static CLK_FIXED_FACTOR_HWS(pll_periph0_clk, "pll-periph0",
++                          pll_periph0_2x_hws, 2, 1, 0);
++
++static const struct clk_hw *pll_periph0_hws[] = { &pll_periph0_clk.hw };
++static CLK_FIXED_FACTOR_HWS(pll_periph0_div3_clk, "pll-periph0-div3",
++                          pll_periph0_2x_hws, 6, 1, 0);
++
++/*
++ * For Video PLLs, the output divider is described as "only for testing"
++ * in the user manual. So it's not modelled and forced to 0.
++ */
++#define SUN20I_D1_PLL_VIDEO0_REG      0x040
++static struct ccu_nm pll_video0_4x_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
++      .common         = {
++              .reg            = 0x040,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-video0-4x", osc24M,
++                                                         &ccu_nm_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++static const struct clk_hw *pll_video0_4x_hws[] = {
++      &pll_video0_4x_clk.common.hw
++};
++static CLK_FIXED_FACTOR_HWS(pll_video0_2x_clk, "pll-video0-2x",
++                          pll_video0_4x_hws, 2, 1, CLK_SET_RATE_PARENT);
++static CLK_FIXED_FACTOR_HWS(pll_video0_clk, "pll-video0",
++                          pll_video0_4x_hws, 4, 1, CLK_SET_RATE_PARENT);
++
++#define SUN20I_D1_PLL_VIDEO1_REG      0x048
++static struct ccu_nm pll_video1_4x_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
++      .common         = {
++              .reg            = 0x048,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-video1-4x", osc24M,
++                                                         &ccu_nm_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++static const struct clk_hw *pll_video1_4x_hws[] = {
++      &pll_video1_4x_clk.common.hw
++};
++static CLK_FIXED_FACTOR_HWS(pll_video1_2x_clk, "pll-video1-2x",
++                          pll_video1_4x_hws, 2, 1, CLK_SET_RATE_PARENT);
++static CLK_FIXED_FACTOR_HWS(pll_video1_clk, "pll-video1",
++                          pll_video1_4x_hws, 4, 1, CLK_SET_RATE_PARENT);
++
++#define SUN20I_D1_PLL_VE_REG          0x058
++static struct ccu_nkmp pll_ve_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
++      .p              = _SUNXI_CCU_DIV(0, 1), /* output divider */
++      .common         = {
++              .reg            = 0x058,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-ve", osc24M,
++                                                         &ccu_nkmp_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++/*
++ * PLL_AUDIO0 has m0, m1 dividers in addition to the usual N, M factors.
++ * Since we only need one frequency from this PLL (22.5792 x 4 == 90.3168 MHz),
++ * ignore them for now. Enforce the default for them, which is m1 = 0, m0 = 0.
++ * The M factor must be an even number to produce a 50% duty cycle output.
++ */
++#define SUN20I_D1_PLL_AUDIO0_REG              0x078
++static struct ccu_sdm_setting pll_audio0_sdm_table[] = {
++      { .rate = 90316800, .pattern = 0xc001288d, .m = 6, .n = 22 },
++};
++
++static struct ccu_nm pll_audio0_4x_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(16, 6),
++      .sdm            = _SUNXI_CCU_SDM(pll_audio0_sdm_table, BIT(24),
++                                       0x178, BIT(31)),
++      .common         = {
++              .reg            = 0x078,
++              .features       = CCU_FEATURE_SIGMA_DELTA_MOD,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-audio0-4x", osc24M,
++                                                         &ccu_nm_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++static const struct clk_hw *pll_audio0_4x_hws[] = {
++      &pll_audio0_4x_clk.common.hw
++};
++static CLK_FIXED_FACTOR_HWS(pll_audio0_2x_clk, "pll-audio0-2x",
++                          pll_audio0_4x_hws, 2, 1, 0);
++static CLK_FIXED_FACTOR_HWS(pll_audio0_clk, "pll-audio0",
++                          pll_audio0_4x_hws, 4, 1, 0);
++
++/*
++ * PLL_AUDIO1 doesn't need Fractional-N. The output is usually 614.4 MHz for
++ * audio. The ADC or DAC should divide the PLL output further to 24.576 MHz.
++ */
++#define SUN20I_D1_PLL_AUDIO1_REG              0x080
++static struct ccu_nm pll_audio1_clk = {
++      .enable         = BIT(27),
++      .lock           = BIT(28),
++      .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
++      .m              = _SUNXI_CCU_DIV(1, 1),
++      .common         = {
++              .reg            = 0x080,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-audio1", osc24M,
++                                                         &ccu_nm_ops,
++                                                         CLK_SET_RATE_UNGATE),
++      },
++};
++
++static const struct clk_hw *pll_audio1_hws[] = {
++      &pll_audio1_clk.common.hw
++};
++static SUNXI_CCU_M_HWS(pll_audio1_div2_clk, "pll-audio1-div2",
++                     pll_audio1_hws, 0x080, 16, 3, 0);
++static SUNXI_CCU_M_HWS(pll_audio1_div5_clk, "pll-audio1-div5",
++                     pll_audio1_hws, 0x080, 20, 3, 0);
++
++/*
++ * The CPUX gate is not modelled - it is in a separate register (0x504)
++ * and has a special key field. The clock does not need to be ungated anyway.
++ */
++static const struct clk_parent_data cpux_parents[] = {
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++      { .fw_name = "iosc" },
++      { .hw = &pll_cpux_clk.common.hw },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_periph0_2x_clk.common.hw },
++      { .hw = &pll_periph0_800M_clk.common.hw },
++};
++static SUNXI_CCU_MUX_DATA(cpux_clk, "cpux", cpux_parents,
++                        0x500, 24, 3, CLK_SET_RATE_PARENT);
++
++static const struct clk_hw *cpux_hws[] = { &cpux_clk.common.hw };
++static SUNXI_CCU_M_HWS(cpux_axi_clk, "cpux-axi",
++                     cpux_hws, 0x500, 0, 2, 0);
++static SUNXI_CCU_M_HWS(cpux_apb_clk, "cpux-apb",
++                     cpux_hws, 0x500, 8, 2, 0);
++
++static const struct clk_parent_data psi_ahb_parents[] = {
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++      { .fw_name = "iosc" },
++      { .hw = &pll_periph0_clk.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX(psi_ahb_clk, "psi-ahb", psi_ahb_parents, 0x510,
++                                0, 2,         /* M */
++                                8, 2,         /* P */
++                                24, 2,        /* mux */
++                                0);
++
++static const struct clk_parent_data apb0_apb1_parents[] = {
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++      { .hw = &psi_ahb_clk.common.hw },
++      { .hw = &pll_periph0_clk.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX(apb0_clk, "apb0", apb0_apb1_parents, 0x520,
++                                0, 5,         /* M */
++                                8, 2,         /* P */
++                                24, 2,        /* mux */
++                                0);
++
++static SUNXI_CCU_MP_DATA_WITH_MUX(apb1_clk, "apb1", apb0_apb1_parents, 0x524,
++                                0, 5,         /* M */
++                                8, 2,         /* P */
++                                24, 2,        /* mux */
++                                0);
++
++static const struct clk_hw *psi_ahb_hws[] = { &psi_ahb_clk.common.hw };
++static const struct clk_hw *apb0_hws[] = { &apb0_clk.common.hw };
++static const struct clk_hw *apb1_hws[] = { &apb1_clk.common.hw };
++
++static const struct clk_hw *de_di_g2d_parents[] = {
++      &pll_periph0_2x_clk.common.hw,
++      &pll_video0_4x_clk.common.hw,
++      &pll_video1_4x_clk.common.hw,
++      &pll_audio1_div2_clk.common.hw,
++};
++static SUNXI_CCU_M_HW_WITH_MUX_GATE(de_clk, "de", de_di_g2d_parents, 0x600,
++                                  0, 5,       /* M */
++                                  24, 3,      /* mux */
++                                  BIT(31),    /* gate */
++                                  CLK_SET_RATE_PARENT);
++
++static SUNXI_CCU_GATE_HWS(bus_de_clk, "bus-de", psi_ahb_hws,
++                        0x60c, BIT(0), 0);
++
++static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", de_di_g2d_parents, 0x620,
++                                  0, 5,       /* M */
++                                  24, 3,      /* mux */
++                                  BIT(31),    /* gate */
++                                  CLK_SET_RATE_PARENT);
++
++static SUNXI_CCU_GATE_HWS(bus_di_clk, "bus-di", psi_ahb_hws,
++                        0x62c, BIT(0), 0);
++
++static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", de_di_g2d_parents, 0x630,
++                                  0, 5,       /* M */
++                                  24, 3,      /* mux */
++                                  BIT(31),    /* gate */
++                                  0);
++
++static SUNXI_CCU_GATE_HWS(bus_g2d_clk, "bus-g2d", psi_ahb_hws,
++                        0x63c, BIT(0), 0);
++
++static const struct clk_parent_data ce_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_2x_clk.common.hw },
++      { .hw = &pll_periph0_clk.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_GATE_HWS(bus_ce_clk, "bus-ce", psi_ahb_hws,
++                        0x68c, BIT(0), 0);
++
++static const struct clk_hw *ve_parents[] = {
++      &pll_ve_clk.common.hw,
++      &pll_periph0_2x_clk.common.hw,
++};
++static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690,
++                                  0, 5,       /* M */
++                                  24, 1,      /* mux */
++                                  BIT(31),    /* gate */
++                                  CLK_SET_RATE_PARENT);
++
++static SUNXI_CCU_GATE_HWS(bus_ve_clk, "bus-ve", psi_ahb_hws,
++                        0x69c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_dma_clk, "bus-dma", psi_ahb_hws,
++                        0x70c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_msgbox0_clk, "bus-msgbox0", psi_ahb_hws,
++                        0x71c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_msgbox1_clk, "bus-msgbox1", psi_ahb_hws,
++                        0x71c, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(bus_msgbox2_clk, "bus-msgbox2", psi_ahb_hws,
++                        0x71c, BIT(2), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_spinlock_clk, "bus-spinlock", psi_ahb_hws,
++                        0x72c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_hstimer_clk, "bus-hstimer", psi_ahb_hws,
++                        0x73c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_DATA(avs_clk, "avs", osc24M,
++                         0x740, BIT(31), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_dbg_clk, "bus-dbg", psi_ahb_hws,
++                        0x78c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_pwm_clk, "bus-pwm", apb0_hws,
++                        0x7ac, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_iommu_clk, "bus-iommu", apb0_hws,
++                        0x7bc, BIT(0), 0);
++
++static const struct clk_hw *dram_parents[] = {
++      &pll_ddr0_clk.common.hw,
++      &pll_audio1_div2_clk.common.hw,
++      &pll_periph0_2x_clk.common.hw,
++      &pll_periph0_800M_clk.common.hw,
++};
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dram_clk, "dram", dram_parents, 0x800,
++                                   0, 2,      /* M */
++                                   8, 2,      /* P */
++                                   24, 2,     /* mux */
++                                   BIT(31), CLK_IS_CRITICAL);
++
++static CLK_FIXED_FACTOR_HW(mbus_clk, "mbus",
++                         &dram_clk.common.hw, 4, 1, 0);
++
++static const struct clk_hw *mbus_hws[] = { &mbus_clk.hw };
++
++static SUNXI_CCU_GATE_HWS(mbus_dma_clk, "mbus-dma", mbus_hws,
++                        0x804, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(mbus_ve_clk, "mbus-ve", mbus_hws,
++                        0x804, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(mbus_ce_clk, "mbus-ce", mbus_hws,
++                        0x804, BIT(2), 0);
++static SUNXI_CCU_GATE_HWS(mbus_tvin_clk, "mbus-tvin", mbus_hws,
++                        0x804, BIT(7), 0);
++static SUNXI_CCU_GATE_HWS(mbus_csi_clk, "mbus-csi", mbus_hws,
++                        0x804, BIT(8), 0);
++static SUNXI_CCU_GATE_HWS(mbus_g2d_clk, "mbus-g2d", mbus_hws,
++                        0x804, BIT(10), 0);
++static SUNXI_CCU_GATE_HWS(mbus_riscv_clk, "mbus-riscv", mbus_hws,
++                        0x804, BIT(11), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_dram_clk, "bus-dram", psi_ahb_hws,
++                        0x80c, BIT(0), CLK_IS_CRITICAL);
++
++static const struct clk_parent_data mmc0_mmc1_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_periph0_2x_clk.common.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_mmc1_parents, 0x830,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc0_mmc1_parents, 0x834,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static const struct clk_parent_data mmc2_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_periph0_2x_clk.common.hw },
++      { .hw = &pll_periph0_800M_clk.common.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x838,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", psi_ahb_hws,
++                        0x84c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_mmc1_clk, "bus-mmc1", psi_ahb_hws,
++                        0x84c, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(bus_mmc2_clk, "bus-mmc2", psi_ahb_hws,
++                        0x84c, BIT(2), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_uart0_clk, "bus-uart0", apb1_hws,
++                        0x90c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_uart1_clk, "bus-uart1", apb1_hws,
++                        0x90c, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(bus_uart2_clk, "bus-uart2", apb1_hws,
++                        0x90c, BIT(2), 0);
++static SUNXI_CCU_GATE_HWS(bus_uart3_clk, "bus-uart3", apb1_hws,
++                        0x90c, BIT(3), 0);
++static SUNXI_CCU_GATE_HWS(bus_uart4_clk, "bus-uart4", apb1_hws,
++                        0x90c, BIT(4), 0);
++static SUNXI_CCU_GATE_HWS(bus_uart5_clk, "bus-uart5", apb1_hws,
++                        0x90c, BIT(5), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_i2c0_clk, "bus-i2c0", apb1_hws,
++                        0x91c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_i2c1_clk, "bus-i2c1", apb1_hws,
++                        0x91c, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(bus_i2c2_clk, "bus-i2c2", apb1_hws,
++                        0x91c, BIT(2), 0);
++static SUNXI_CCU_GATE_HWS(bus_i2c3_clk, "bus-i2c3", apb1_hws,
++                        0x91c, BIT(3), 0);
++
++static const struct clk_parent_data spi_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_periph0_2x_clk.common.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++      { .hw = &pll_audio1_div5_clk.common.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi0_clk, "spi0", spi_parents, 0x940,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi1_clk, "spi1", spi_parents, 0x944,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_GATE_HWS(bus_spi0_clk, "bus-spi0", psi_ahb_hws,
++                        0x96c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_spi1_clk, "bus-spi1", psi_ahb_hws,
++                        0x96c, BIT(1), 0);
++
++static SUNXI_CCU_GATE_HWS_WITH_PREDIV(emac_25M_clk, "emac-25M", pll_periph0_hws,
++                                    0x970, BIT(31) | BIT(30), 24, 0);
++
++static SUNXI_CCU_GATE_HWS(bus_emac_clk, "bus-emac", psi_ahb_hws,
++                        0x97c, BIT(0), 0);
++
++static const struct clk_parent_data ir_tx_ledc_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_clk.hw },
++};
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ir_tx_clk, "ir-tx", ir_tx_ledc_parents, 0x9c0,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 3,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_GATE_HWS(bus_ir_tx_clk, "bus-ir-tx", apb0_hws,
++                        0x9cc, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_gpadc_clk, "bus-gpadc", apb0_hws,
++                        0x9ec, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_ths_clk, "bus-ths", apb0_hws,
++                        0x9fc, BIT(0), 0);
++
++static const struct clk_hw *i2s_spdif_tx_parents[] = {
++      &pll_audio0_clk.hw,
++      &pll_audio0_4x_clk.common.hw,
++      &pll_audio1_div2_clk.common.hw,
++      &pll_audio1_div5_clk.common.hw,
++};
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s0_clk, "i2s0", i2s_spdif_tx_parents, 0xa10,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s1_clk, "i2s1", i2s_spdif_tx_parents, 0xa14,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s2_clk, "i2s2", i2s_spdif_tx_parents, 0xa18,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static const struct clk_hw *i2s2_asrc_parents[] = {
++      &pll_audio0_4x_clk.common.hw,
++      &pll_periph0_clk.hw,
++      &pll_audio1_div2_clk.common.hw,
++      &pll_audio1_div5_clk.common.hw,
++};
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s2_asrc_clk, "i2s2-asrc", i2s2_asrc_parents, 0xa1c,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_GATE_HWS(bus_i2s0_clk, "bus-i2s0", apb0_hws,
++                        0xa20, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_i2s1_clk, "bus-i2s1", apb0_hws,
++                        0xa20, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(bus_i2s2_clk, "bus-i2s2", apb0_hws,
++                        0xa20, BIT(2), 0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(spdif_tx_clk, "spdif-tx", i2s_spdif_tx_parents, 0xa24,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static const struct clk_hw *spdif_rx_parents[] = {
++      &pll_periph0_clk.hw,
++      &pll_audio1_div2_clk.common.hw,
++      &pll_audio1_div5_clk.common.hw,
++};
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(spdif_rx_clk, "spdif-rx", spdif_rx_parents, 0xa28,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_GATE_HWS(bus_spdif_clk, "bus-spdif", apb0_hws,
++                        0xa2c, BIT(0), 0);
++
++static const struct clk_hw *dmic_codec_parents[] = {
++      &pll_audio0_clk.hw,
++      &pll_audio1_div2_clk.common.hw,
++      &pll_audio1_div5_clk.common.hw,
++};
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dmic_clk, "dmic", dmic_codec_parents, 0xa40,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_GATE_HWS(bus_dmic_clk, "bus-dmic", apb0_hws,
++                        0xa4c, BIT(0), 0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(audio_dac_clk, "audio-dac", dmic_codec_parents, 0xa50,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(audio_adc_clk, "audio-adc", dmic_codec_parents, 0xa54,
++                                   0, 5,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_GATE_HWS(bus_audio_clk, "bus-audio", apb0_hws,
++                        0xa5c, BIT(0), 0);
++
++
++/*
++ * The first parent is a 48 MHz input clock divided by 4. That 48 MHz clock is
++ * a 2x multiplier from osc24M synchronized by pll-periph0, and is also used by
++ * the OHCI module.
++ */
++static const struct clk_parent_data usb_ohci_parents[] = {
++      { .hw = &pll_periph0_clk.hw },
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++};
++static const struct ccu_mux_fixed_prediv usb_ohci_predivs[] = {
++      { .index = 0, .div = 50 },
++      { .index = 1, .div = 2 },
++};
++
++static struct ccu_mux usb_ohci0_clk = {
++      .enable         = BIT(31),
++      .mux            = {
++              .shift          = 24,
++              .width          = 2,
++              .fixed_predivs  = usb_ohci_predivs,
++              .n_predivs      = ARRAY_SIZE(usb_ohci_predivs),
++      },
++      .common         = {
++              .reg            = 0xa70,
++              .features       = CCU_FEATURE_FIXED_PREDIV,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("usb-ohci0",
++                                                         usb_ohci_parents,
++                                                         &ccu_mux_ops,
++                                                         0),
++      },
++};
++
++static struct ccu_mux usb_ohci1_clk = {
++      .enable         = BIT(31),
++      .mux            = {
++              .shift          = 24,
++              .width          = 2,
++              .fixed_predivs  = usb_ohci_predivs,
++              .n_predivs      = ARRAY_SIZE(usb_ohci_predivs),
++      },
++      .common         = {
++              .reg            = 0xa74,
++              .features       = CCU_FEATURE_FIXED_PREDIV,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("usb-ohci1",
++                                                         usb_ohci_parents,
++                                                         &ccu_mux_ops,
++                                                         0),
++      },
++};
++
++static SUNXI_CCU_GATE_HWS(bus_ohci0_clk, "bus-ohci0", psi_ahb_hws,
++                        0xa8c, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_ohci1_clk, "bus-ohci1", psi_ahb_hws,
++                        0xa8c, BIT(1), 0);
++static SUNXI_CCU_GATE_HWS(bus_ehci0_clk, "bus-ehci0", psi_ahb_hws,
++                        0xa8c, BIT(4), 0);
++static SUNXI_CCU_GATE_HWS(bus_ehci1_clk, "bus-ehci1", psi_ahb_hws,
++                        0xa8c, BIT(5), 0);
++static SUNXI_CCU_GATE_HWS(bus_otg_clk, "bus-otg", psi_ahb_hws,
++                        0xa8c, BIT(8), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_lradc_clk, "bus-lradc", apb0_hws,
++                        0xa9c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_dpss_top_clk, "bus-dpss-top", psi_ahb_hws,
++                        0xabc, BIT(0), 0);
++
++static SUNXI_CCU_GATE_DATA(hdmi_24M_clk, "hdmi-24M", osc24M,
++                         0xb04, BIT(31), 0);
++
++static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k",
++                                    pll_periph0_2x_hws,
++                                    0xb10, BIT(30), 36621, 0);
++
++static const struct clk_parent_data hdmi_cec_parents[] = {
++      { .fw_name = "losc" },
++      { .hw = &hdmi_cec_32k_clk.common.hw },
++};
++static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_cec_clk, "hdmi-cec", hdmi_cec_parents, 0xb10,
++                                  24, 1,      /* mux */
++                                  BIT(31),    /* gate */
++                                  0);
++
++static SUNXI_CCU_GATE_HWS(bus_hdmi_clk, "bus-hdmi", psi_ahb_hws,
++                        0xb1c, BIT(0), 0);
++
++static const struct clk_parent_data mipi_dsi_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_video0_2x_clk.hw },
++      { .hw = &pll_video1_2x_clk.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++};
++static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", mipi_dsi_parents, 0xb24,
++                                    0, 4,     /* M */
++                                    24, 3,    /* mux */
++                                    BIT(31),  /* gate */
++                                    CLK_SET_RATE_PARENT);
++
++static SUNXI_CCU_GATE_HWS(bus_mipi_dsi_clk, "bus-mipi-dsi", psi_ahb_hws,
++                        0xb4c, BIT(0), 0);
++
++static const struct clk_hw *tcon_tve_parents[] = {
++      &pll_video0_clk.hw,
++      &pll_video0_4x_clk.common.hw,
++      &pll_video1_clk.hw,
++      &pll_video1_4x_clk.common.hw,
++      &pll_periph0_2x_clk.common.hw,
++      &pll_audio1_div2_clk.common.hw,
++};
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_tve_parents, 0xb60,
++                                   0, 4,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   CLK_SET_RATE_PARENT);
++
++static SUNXI_CCU_GATE_HWS(bus_tcon_lcd0_clk, "bus-tcon-lcd0", psi_ahb_hws,
++                        0xb7c, BIT(0), 0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_tv_clk, "tcon-tv", tcon_tve_parents, 0xb80,
++                                   0, 4,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   CLK_SET_RATE_PARENT);
++
++static SUNXI_CCU_GATE_HWS(bus_tcon_tv_clk, "bus-tcon-tv", psi_ahb_hws,
++                        0xb9c, BIT(0), 0);
++
++static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tve_clk, "tve", tcon_tve_parents, 0xbb0,
++                                   0, 4,      /* M */
++                                   8, 2,      /* P */
++                                   24, 3,     /* mux */
++                                   BIT(31),   /* gate */
++                                   0);
++
++static SUNXI_CCU_GATE_HWS(bus_tve_top_clk, "bus-tve-top", psi_ahb_hws,
++                        0xbbc, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_tve_clk, "bus-tve", psi_ahb_hws,
++                        0xbbc, BIT(1), 0);
++
++static const struct clk_parent_data tvd_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_video0_clk.hw },
++      { .hw = &pll_video1_clk.hw },
++      { .hw = &pll_periph0_clk.hw },
++};
++static SUNXI_CCU_M_DATA_WITH_MUX_GATE(tvd_clk, "tvd", tvd_parents, 0xbc0,
++                                    0, 5,     /* M */
++                                    24, 3,    /* mux */
++                                    BIT(31),  /* gate */
++                                    0);
++
++static SUNXI_CCU_GATE_HWS(bus_tvd_top_clk, "bus-tvd-top", psi_ahb_hws,
++                        0xbdc, BIT(0), 0);
++static SUNXI_CCU_GATE_HWS(bus_tvd_clk, "bus-tvd", psi_ahb_hws,
++                        0xbdc, BIT(1), 0);
++
++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ir_tx_ledc_parents, 0xbf0,
++                                     0, 4,    /* M */
++                                     8, 2,    /* P */
++                                     24, 1,   /* mux */
++                                     BIT(31), /* gate */
++                                     0);
++
++static SUNXI_CCU_GATE_HWS(bus_ledc_clk, "bus-ledc", psi_ahb_hws,
++                        0xbfc, BIT(0), 0);
++
++static const struct clk_hw *csi_top_parents[] = {
++      &pll_periph0_2x_clk.common.hw,
++      &pll_video0_2x_clk.hw,
++      &pll_video1_2x_clk.hw,
++};
++static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_top_clk, "csi-top", csi_top_parents, 0xc04,
++                                  0, 4,       /* M */
++                                  24, 3,      /* mux */
++                                  BIT(31),    /* gate */
++                                  0);
++
++static const struct clk_parent_data csi_mclk_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_video0_clk.hw },
++      { .hw = &pll_video1_clk.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++      { .hw = &pll_audio1_div5_clk.common.hw },
++};
++static SUNXI_CCU_M_DATA_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, 0xc08,
++                                    0, 5,     /* M */
++                                    24, 3,    /* mux */
++                                    BIT(31),  /* gate */
++                                    0);
++
++static SUNXI_CCU_GATE_HWS(bus_csi_clk, "bus-csi", psi_ahb_hws,
++                        0xc1c, BIT(0), 0);
++
++static const struct clk_parent_data tpadc_parents[] = {
++      { .fw_name = "hosc" },
++      { .hw = &pll_audio0_clk.hw },
++};
++static SUNXI_CCU_MUX_DATA_WITH_GATE(tpadc_clk, "tpadc", tpadc_parents, 0xc50,
++                                  24, 3,      /* mux */
++                                  BIT(31),    /* gate */
++                                  0);
++
++static SUNXI_CCU_GATE_HWS(bus_tpadc_clk, "bus-tpadc", apb0_hws,
++                        0xc5c, BIT(0), 0);
++
++static SUNXI_CCU_GATE_HWS(bus_tzma_clk, "bus-tzma", apb0_hws,
++                        0xc6c, BIT(0), 0);
++
++static const struct clk_parent_data dsp_parents[] = {
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++      { .fw_name = "iosc" },
++      { .hw = &pll_periph0_2x_clk.common.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++};
++static SUNXI_CCU_M_DATA_WITH_MUX_GATE(dsp_clk, "dsp", dsp_parents, 0xc70,
++                                    0, 5,     /* M */
++                                    24, 3,    /* mux */
++                                    BIT(31),  /* gate */
++                                    0);
++
++static SUNXI_CCU_GATE_HWS(bus_dsp_cfg_clk, "bus-dsp-cfg", psi_ahb_hws,
++                        0xc7c, BIT(1), 0);
++
++/*
++ * The RISC-V gate is not modelled - it is in a separate register (0xd04)
++ * and has a special key field. The clock is critical anyway.
++ */
++static const struct clk_parent_data riscv_parents[] = {
++      { .fw_name = "hosc" },
++      { .fw_name = "losc" },
++      { .fw_name = "iosc" },
++      { .hw = &pll_periph0_800M_clk.common.hw },
++      { .hw = &pll_periph0_clk.hw },
++      { .hw = &pll_cpux_clk.common.hw },
++      { .hw = &pll_audio1_div2_clk.common.hw },
++};
++static SUNXI_CCU_M_DATA_WITH_MUX(riscv_clk, "riscv", riscv_parents, 0xd00,
++                               0, 5,  /* M */
++                               24, 3, /* mux */
++                               CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
++
++/* The riscv-axi clk must be divided by at least 2. */
++static struct clk_div_table riscv_axi_table[] = {
++      { .val = 1, .div = 2 },
++      { .val = 2, .div = 3 },
++      { .val = 3, .div = 4 },
++      { /* Sentinel */ }
++};
++static SUNXI_CCU_DIV_TABLE_HW(riscv_axi_clk, "riscv-axi", &riscv_clk.common.hw,
++                            0xd00, 8, 2, riscv_axi_table, 0);
++
++static SUNXI_CCU_GATE_HWS(bus_riscv_cfg_clk, "bus-riscv-cfg", psi_ahb_hws,
++                        0xd0c, BIT(0), CLK_IS_CRITICAL);
++
++static SUNXI_CCU_GATE_DATA(fanout_24M_clk, "fanout-24M", osc24M,
++                         0xf30, BIT(0), 0);
++static SUNXI_CCU_GATE_DATA_WITH_PREDIV(fanout_12M_clk, "fanout-12M", osc24M,
++                                     0xf30, BIT(1), 2, 0);
++static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph0_2x_hws,
++                                    0xf30, BIT(2), 75, 0);
++static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph0_hws,
++                                    0xf30, BIT(3), 24, 0);
++static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_32k_clk, "fanout-32k", pll_periph0_2x_hws,
++                                    0xf30, BIT(4), 36621, 0);
++
++/* This clock has a second divider that is not modelled and forced to 0. */
++#define SUN20I_D1_FANOUT_27M_REG      0xf34
++static const struct clk_hw *fanout_27M_parents[] = {
++      &pll_video0_clk.hw,
++      &pll_video1_clk.hw,
++};
++static SUNXI_CCU_M_HW_WITH_MUX_GATE(fanout_27M_clk, "fanout-27M", fanout_27M_parents, 0xf34,
++                                  0, 5,       /* M */
++                                  24, 2,      /* mux */
++                                  BIT(31),    /* gate */
++                                  0);
++
++static SUNXI_CCU_M_HWS_WITH_GATE(fanout_pclk_clk, "fanout-pclk", apb0_hws, 0xf38,
++                               0, 5,          /* M */
++                               BIT(31),       /* gate */
++                               0);
++
++static const struct clk_hw *fanout_parents[] = {
++      &fanout_32k_clk.common.hw,
++      &fanout_12M_clk.common.hw,
++      &fanout_16M_clk.common.hw,
++      &fanout_24M_clk.common.hw,
++      &fanout_25M_clk.common.hw,
++      &fanout_27M_clk.common.hw,
++      &fanout_pclk_clk.common.hw,
++};
++static SUNXI_CCU_MUX_HW_WITH_GATE(fanout0_clk, "fanout0", fanout_parents, 0xf3c,
++                                0, 3,         /* mux */
++                                BIT(21),      /* gate */
++                                0);
++static SUNXI_CCU_MUX_HW_WITH_GATE(fanout1_clk, "fanout1", fanout_parents, 0xf3c,
++                                3, 3,         /* mux */
++                                BIT(22),      /* gate */
++                                0);
++static SUNXI_CCU_MUX_HW_WITH_GATE(fanout2_clk, "fanout2", fanout_parents, 0xf3c,
++                                6, 3,         /* mux */
++                                BIT(23),      /* gate */
++                                0);
++
++static struct ccu_common *sun20i_d1_ccu_clks[] = {
++      &pll_cpux_clk.common,
++      &pll_ddr0_clk.common,
++      &pll_periph0_4x_clk.common,
++      &pll_periph0_2x_clk.common,
++      &pll_periph0_800M_clk.common,
++      &pll_video0_4x_clk.common,
++      &pll_video1_4x_clk.common,
++      &pll_ve_clk.common,
++      &pll_audio0_4x_clk.common,
++      &pll_audio1_clk.common,
++      &pll_audio1_div2_clk.common,
++      &pll_audio1_div5_clk.common,
++      &cpux_clk.common,
++      &cpux_axi_clk.common,
++      &cpux_apb_clk.common,
++      &psi_ahb_clk.common,
++      &apb0_clk.common,
++      &apb1_clk.common,
++      &de_clk.common,
++      &bus_de_clk.common,
++      &di_clk.common,
++      &bus_di_clk.common,
++      &g2d_clk.common,
++      &bus_g2d_clk.common,
++      &ce_clk.common,
++      &bus_ce_clk.common,
++      &ve_clk.common,
++      &bus_ve_clk.common,
++      &bus_dma_clk.common,
++      &bus_msgbox0_clk.common,
++      &bus_msgbox1_clk.common,
++      &bus_msgbox2_clk.common,
++      &bus_spinlock_clk.common,
++      &bus_hstimer_clk.common,
++      &avs_clk.common,
++      &bus_dbg_clk.common,
++      &bus_pwm_clk.common,
++      &bus_iommu_clk.common,
++      &dram_clk.common,
++      &mbus_dma_clk.common,
++      &mbus_ve_clk.common,
++      &mbus_ce_clk.common,
++      &mbus_tvin_clk.common,
++      &mbus_csi_clk.common,
++      &mbus_g2d_clk.common,
++      &mbus_riscv_clk.common,
++      &bus_dram_clk.common,
++      &mmc0_clk.common,
++      &mmc1_clk.common,
++      &mmc2_clk.common,
++      &bus_mmc0_clk.common,
++      &bus_mmc1_clk.common,
++      &bus_mmc2_clk.common,
++      &bus_uart0_clk.common,
++      &bus_uart1_clk.common,
++      &bus_uart2_clk.common,
++      &bus_uart3_clk.common,
++      &bus_uart4_clk.common,
++      &bus_uart5_clk.common,
++      &bus_i2c0_clk.common,
++      &bus_i2c1_clk.common,
++      &bus_i2c2_clk.common,
++      &bus_i2c3_clk.common,
++      &spi0_clk.common,
++      &spi1_clk.common,
++      &bus_spi0_clk.common,
++      &bus_spi1_clk.common,
++      &emac_25M_clk.common,
++      &bus_emac_clk.common,
++      &ir_tx_clk.common,
++      &bus_ir_tx_clk.common,
++      &bus_gpadc_clk.common,
++      &bus_ths_clk.common,
++      &i2s0_clk.common,
++      &i2s1_clk.common,
++      &i2s2_clk.common,
++      &i2s2_asrc_clk.common,
++      &bus_i2s0_clk.common,
++      &bus_i2s1_clk.common,
++      &bus_i2s2_clk.common,
++      &spdif_tx_clk.common,
++      &spdif_rx_clk.common,
++      &bus_spdif_clk.common,
++      &dmic_clk.common,
++      &bus_dmic_clk.common,
++      &audio_dac_clk.common,
++      &audio_adc_clk.common,
++      &bus_audio_clk.common,
++      &usb_ohci0_clk.common,
++      &usb_ohci1_clk.common,
++      &bus_ohci0_clk.common,
++      &bus_ohci1_clk.common,
++      &bus_ehci0_clk.common,
++      &bus_ehci1_clk.common,
++      &bus_otg_clk.common,
++      &bus_lradc_clk.common,
++      &bus_dpss_top_clk.common,
++      &hdmi_24M_clk.common,
++      &hdmi_cec_32k_clk.common,
++      &hdmi_cec_clk.common,
++      &bus_hdmi_clk.common,
++      &mipi_dsi_clk.common,
++      &bus_mipi_dsi_clk.common,
++      &tcon_lcd0_clk.common,
++      &bus_tcon_lcd0_clk.common,
++      &tcon_tv_clk.common,
++      &bus_tcon_tv_clk.common,
++      &tve_clk.common,
++      &bus_tve_top_clk.common,
++      &bus_tve_clk.common,
++      &tvd_clk.common,
++      &bus_tvd_top_clk.common,
++      &bus_tvd_clk.common,
++      &ledc_clk.common,
++      &bus_ledc_clk.common,
++      &csi_top_clk.common,
++      &csi_mclk_clk.common,
++      &bus_csi_clk.common,
++      &tpadc_clk.common,
++      &bus_tpadc_clk.common,
++      &bus_tzma_clk.common,
++      &dsp_clk.common,
++      &bus_dsp_cfg_clk.common,
++      &riscv_clk.common,
++      &riscv_axi_clk.common,
++      &bus_riscv_cfg_clk.common,
++      &fanout_24M_clk.common,
++      &fanout_12M_clk.common,
++      &fanout_16M_clk.common,
++      &fanout_25M_clk.common,
++      &fanout_32k_clk.common,
++      &fanout_27M_clk.common,
++      &fanout_pclk_clk.common,
++      &fanout0_clk.common,
++      &fanout1_clk.common,
++      &fanout2_clk.common,
++};
++
++static struct clk_hw_onecell_data sun20i_d1_hw_clks = {
++      .num    = CLK_NUMBER,
++      .hws    = {
++              [CLK_PLL_CPUX]          = &pll_cpux_clk.common.hw,
++              [CLK_PLL_DDR0]          = &pll_ddr0_clk.common.hw,
++              [CLK_PLL_PERIPH0_4X]    = &pll_periph0_4x_clk.common.hw,
++              [CLK_PLL_PERIPH0_2X]    = &pll_periph0_2x_clk.common.hw,
++              [CLK_PLL_PERIPH0_800M]  = &pll_periph0_800M_clk.common.hw,
++              [CLK_PLL_PERIPH0]       = &pll_periph0_clk.hw,
++              [CLK_PLL_PERIPH0_DIV3]  = &pll_periph0_div3_clk.hw,
++              [CLK_PLL_VIDEO0_4X]     = &pll_video0_4x_clk.common.hw,
++              [CLK_PLL_VIDEO0_2X]     = &pll_video0_2x_clk.hw,
++              [CLK_PLL_VIDEO0]        = &pll_video0_clk.hw,
++              [CLK_PLL_VIDEO1_4X]     = &pll_video1_4x_clk.common.hw,
++              [CLK_PLL_VIDEO1_2X]     = &pll_video1_2x_clk.hw,
++              [CLK_PLL_VIDEO1]        = &pll_video1_clk.hw,
++              [CLK_PLL_VE]            = &pll_ve_clk.common.hw,
++              [CLK_PLL_AUDIO0_4X]     = &pll_audio0_4x_clk.common.hw,
++              [CLK_PLL_AUDIO0_2X]     = &pll_audio0_2x_clk.hw,
++              [CLK_PLL_AUDIO0]        = &pll_audio0_clk.hw,
++              [CLK_PLL_AUDIO1]        = &pll_audio1_clk.common.hw,
++              [CLK_PLL_AUDIO1_DIV2]   = &pll_audio1_div2_clk.common.hw,
++              [CLK_PLL_AUDIO1_DIV5]   = &pll_audio1_div5_clk.common.hw,
++              [CLK_CPUX]              = &cpux_clk.common.hw,
++              [CLK_CPUX_AXI]          = &cpux_axi_clk.common.hw,
++              [CLK_CPUX_APB]          = &cpux_apb_clk.common.hw,
++              [CLK_PSI_AHB]           = &psi_ahb_clk.common.hw,
++              [CLK_APB0]              = &apb0_clk.common.hw,
++              [CLK_APB1]              = &apb1_clk.common.hw,
++              [CLK_MBUS]              = &mbus_clk.hw,
++              [CLK_DE]                = &de_clk.common.hw,
++              [CLK_BUS_DE]            = &bus_de_clk.common.hw,
++              [CLK_DI]                = &di_clk.common.hw,
++              [CLK_BUS_DI]            = &bus_di_clk.common.hw,
++              [CLK_G2D]               = &g2d_clk.common.hw,
++              [CLK_BUS_G2D]           = &bus_g2d_clk.common.hw,
++              [CLK_CE]                = &ce_clk.common.hw,
++              [CLK_BUS_CE]            = &bus_ce_clk.common.hw,
++              [CLK_VE]                = &ve_clk.common.hw,
++              [CLK_BUS_VE]            = &bus_ve_clk.common.hw,
++              [CLK_BUS_DMA]           = &bus_dma_clk.common.hw,
++              [CLK_BUS_MSGBOX0]       = &bus_msgbox0_clk.common.hw,
++              [CLK_BUS_MSGBOX1]       = &bus_msgbox1_clk.common.hw,
++              [CLK_BUS_MSGBOX2]       = &bus_msgbox2_clk.common.hw,
++              [CLK_BUS_SPINLOCK]      = &bus_spinlock_clk.common.hw,
++              [CLK_BUS_HSTIMER]       = &bus_hstimer_clk.common.hw,
++              [CLK_AVS]               = &avs_clk.common.hw,
++              [CLK_BUS_DBG]           = &bus_dbg_clk.common.hw,
++              [CLK_BUS_PWM]           = &bus_pwm_clk.common.hw,
++              [CLK_BUS_IOMMU]         = &bus_iommu_clk.common.hw,
++              [CLK_DRAM]              = &dram_clk.common.hw,
++              [CLK_MBUS_DMA]          = &mbus_dma_clk.common.hw,
++              [CLK_MBUS_VE]           = &mbus_ve_clk.common.hw,
++              [CLK_MBUS_CE]           = &mbus_ce_clk.common.hw,
++              [CLK_MBUS_TVIN]         = &mbus_tvin_clk.common.hw,
++              [CLK_MBUS_CSI]          = &mbus_csi_clk.common.hw,
++              [CLK_MBUS_G2D]          = &mbus_g2d_clk.common.hw,
++              [CLK_MBUS_RISCV]        = &mbus_riscv_clk.common.hw,
++              [CLK_BUS_DRAM]          = &bus_dram_clk.common.hw,
++              [CLK_MMC0]              = &mmc0_clk.common.hw,
++              [CLK_MMC1]              = &mmc1_clk.common.hw,
++              [CLK_MMC2]              = &mmc2_clk.common.hw,
++              [CLK_BUS_MMC0]          = &bus_mmc0_clk.common.hw,
++              [CLK_BUS_MMC1]          = &bus_mmc1_clk.common.hw,
++              [CLK_BUS_MMC2]          = &bus_mmc2_clk.common.hw,
++              [CLK_BUS_UART0]         = &bus_uart0_clk.common.hw,
++              [CLK_BUS_UART1]         = &bus_uart1_clk.common.hw,
++              [CLK_BUS_UART2]         = &bus_uart2_clk.common.hw,
++              [CLK_BUS_UART3]         = &bus_uart3_clk.common.hw,
++              [CLK_BUS_UART4]         = &bus_uart4_clk.common.hw,
++              [CLK_BUS_UART5]         = &bus_uart5_clk.common.hw,
++              [CLK_BUS_I2C0]          = &bus_i2c0_clk.common.hw,
++              [CLK_BUS_I2C1]          = &bus_i2c1_clk.common.hw,
++              [CLK_BUS_I2C2]          = &bus_i2c2_clk.common.hw,
++              [CLK_BUS_I2C3]          = &bus_i2c3_clk.common.hw,
++              [CLK_SPI0]              = &spi0_clk.common.hw,
++              [CLK_SPI1]              = &spi1_clk.common.hw,
++              [CLK_BUS_SPI0]          = &bus_spi0_clk.common.hw,
++              [CLK_BUS_SPI1]          = &bus_spi1_clk.common.hw,
++              [CLK_EMAC_25M]          = &emac_25M_clk.common.hw,
++              [CLK_BUS_EMAC]          = &bus_emac_clk.common.hw,
++              [CLK_IR_TX]             = &ir_tx_clk.common.hw,
++              [CLK_BUS_IR_TX]         = &bus_ir_tx_clk.common.hw,
++              [CLK_BUS_GPADC]         = &bus_gpadc_clk.common.hw,
++              [CLK_BUS_THS]           = &bus_ths_clk.common.hw,
++              [CLK_I2S0]              = &i2s0_clk.common.hw,
++              [CLK_I2S1]              = &i2s1_clk.common.hw,
++              [CLK_I2S2]              = &i2s2_clk.common.hw,
++              [CLK_I2S2_ASRC]         = &i2s2_asrc_clk.common.hw,
++              [CLK_BUS_I2S0]          = &bus_i2s0_clk.common.hw,
++              [CLK_BUS_I2S1]          = &bus_i2s1_clk.common.hw,
++              [CLK_BUS_I2S2]          = &bus_i2s2_clk.common.hw,
++              [CLK_SPDIF_TX]          = &spdif_tx_clk.common.hw,
++              [CLK_SPDIF_RX]          = &spdif_rx_clk.common.hw,
++              [CLK_BUS_SPDIF]         = &bus_spdif_clk.common.hw,
++              [CLK_DMIC]              = &dmic_clk.common.hw,
++              [CLK_BUS_DMIC]          = &bus_dmic_clk.common.hw,
++              [CLK_AUDIO_DAC]         = &audio_dac_clk.common.hw,
++              [CLK_AUDIO_ADC]         = &audio_adc_clk.common.hw,
++              [CLK_BUS_AUDIO]         = &bus_audio_clk.common.hw,
++              [CLK_USB_OHCI0]         = &usb_ohci0_clk.common.hw,
++              [CLK_USB_OHCI1]         = &usb_ohci1_clk.common.hw,
++              [CLK_BUS_OHCI0]         = &bus_ohci0_clk.common.hw,
++              [CLK_BUS_OHCI1]         = &bus_ohci1_clk.common.hw,
++              [CLK_BUS_EHCI0]         = &bus_ehci0_clk.common.hw,
++              [CLK_BUS_EHCI1]         = &bus_ehci1_clk.common.hw,
++              [CLK_BUS_OTG]           = &bus_otg_clk.common.hw,
++              [CLK_BUS_LRADC]         = &bus_lradc_clk.common.hw,
++              [CLK_BUS_DPSS_TOP]      = &bus_dpss_top_clk.common.hw,
++              [CLK_HDMI_24M]          = &hdmi_24M_clk.common.hw,
++              [CLK_HDMI_CEC_32K]      = &hdmi_cec_32k_clk.common.hw,
++              [CLK_HDMI_CEC]          = &hdmi_cec_clk.common.hw,
++              [CLK_BUS_HDMI]          = &bus_hdmi_clk.common.hw,
++              [CLK_MIPI_DSI]          = &mipi_dsi_clk.common.hw,
++              [CLK_BUS_MIPI_DSI]      = &bus_mipi_dsi_clk.common.hw,
++              [CLK_TCON_LCD0]         = &tcon_lcd0_clk.common.hw,
++              [CLK_BUS_TCON_LCD0]     = &bus_tcon_lcd0_clk.common.hw,
++              [CLK_TCON_TV]           = &tcon_tv_clk.common.hw,
++              [CLK_BUS_TCON_TV]       = &bus_tcon_tv_clk.common.hw,
++              [CLK_TVE]               = &tve_clk.common.hw,
++              [CLK_BUS_TVE_TOP]       = &bus_tve_top_clk.common.hw,
++              [CLK_BUS_TVE]           = &bus_tve_clk.common.hw,
++              [CLK_TVD]               = &tvd_clk.common.hw,
++              [CLK_BUS_TVD_TOP]       = &bus_tvd_top_clk.common.hw,
++              [CLK_BUS_TVD]           = &bus_tvd_clk.common.hw,
++              [CLK_LEDC]              = &ledc_clk.common.hw,
++              [CLK_BUS_LEDC]          = &bus_ledc_clk.common.hw,
++              [CLK_CSI_TOP]           = &csi_top_clk.common.hw,
++              [CLK_CSI_MCLK]          = &csi_mclk_clk.common.hw,
++              [CLK_BUS_CSI]           = &bus_csi_clk.common.hw,
++              [CLK_TPADC]             = &tpadc_clk.common.hw,
++              [CLK_BUS_TPADC]         = &bus_tpadc_clk.common.hw,
++              [CLK_BUS_TZMA]          = &bus_tzma_clk.common.hw,
++              [CLK_DSP]               = &dsp_clk.common.hw,
++              [CLK_BUS_DSP_CFG]       = &bus_dsp_cfg_clk.common.hw,
++              [CLK_RISCV]             = &riscv_clk.common.hw,
++              [CLK_RISCV_AXI]         = &riscv_axi_clk.common.hw,
++              [CLK_BUS_RISCV_CFG]     = &bus_riscv_cfg_clk.common.hw,
++              [CLK_FANOUT_24M]        = &fanout_24M_clk.common.hw,
++              [CLK_FANOUT_12M]        = &fanout_12M_clk.common.hw,
++              [CLK_FANOUT_16M]        = &fanout_16M_clk.common.hw,
++              [CLK_FANOUT_25M]        = &fanout_25M_clk.common.hw,
++              [CLK_FANOUT_32K]        = &fanout_32k_clk.common.hw,
++              [CLK_FANOUT_27M]        = &fanout_27M_clk.common.hw,
++              [CLK_FANOUT_PCLK]       = &fanout_pclk_clk.common.hw,
++              [CLK_FANOUT0]           = &fanout0_clk.common.hw,
++              [CLK_FANOUT1]           = &fanout1_clk.common.hw,
++              [CLK_FANOUT2]           = &fanout2_clk.common.hw,
++      },
++};
++
++static struct ccu_reset_map sun20i_d1_ccu_resets[] = {
++      [RST_MBUS]              = { 0x540, BIT(30) },
++      [RST_BUS_DE]            = { 0x60c, BIT(16) },
++      [RST_BUS_DI]            = { 0x62c, BIT(16) },
++      [RST_BUS_G2D]           = { 0x63c, BIT(16) },
++      [RST_BUS_CE]            = { 0x68c, BIT(16) },
++      [RST_BUS_VE]            = { 0x69c, BIT(16) },
++      [RST_BUS_DMA]           = { 0x70c, BIT(16) },
++      [RST_BUS_MSGBOX0]       = { 0x71c, BIT(16) },
++      [RST_BUS_MSGBOX1]       = { 0x71c, BIT(17) },
++      [RST_BUS_MSGBOX2]       = { 0x71c, BIT(18) },
++      [RST_BUS_SPINLOCK]      = { 0x72c, BIT(16) },
++      [RST_BUS_HSTIMER]       = { 0x73c, BIT(16) },
++      [RST_BUS_DBG]           = { 0x78c, BIT(16) },
++      [RST_BUS_PWM]           = { 0x7ac, BIT(16) },
++      [RST_BUS_DRAM]          = { 0x80c, BIT(16) },
++      [RST_BUS_MMC0]          = { 0x84c, BIT(16) },
++      [RST_BUS_MMC1]          = { 0x84c, BIT(17) },
++      [RST_BUS_MMC2]          = { 0x84c, BIT(18) },
++      [RST_BUS_UART0]         = { 0x90c, BIT(16) },
++      [RST_BUS_UART1]         = { 0x90c, BIT(17) },
++      [RST_BUS_UART2]         = { 0x90c, BIT(18) },
++      [RST_BUS_UART3]         = { 0x90c, BIT(19) },
++      [RST_BUS_UART4]         = { 0x90c, BIT(20) },
++      [RST_BUS_UART5]         = { 0x90c, BIT(21) },
++      [RST_BUS_I2C0]          = { 0x91c, BIT(16) },
++      [RST_BUS_I2C1]          = { 0x91c, BIT(17) },
++      [RST_BUS_I2C2]          = { 0x91c, BIT(18) },
++      [RST_BUS_I2C3]          = { 0x91c, BIT(19) },
++      [RST_BUS_SPI0]          = { 0x96c, BIT(16) },
++      [RST_BUS_SPI1]          = { 0x96c, BIT(17) },
++      [RST_BUS_EMAC]          = { 0x97c, BIT(16) },
++      [RST_BUS_IR_TX]         = { 0x9cc, BIT(16) },
++      [RST_BUS_GPADC]         = { 0x9ec, BIT(16) },
++      [RST_BUS_THS]           = { 0x9fc, BIT(16) },
++      [RST_BUS_I2S0]          = { 0xa20, BIT(16) },
++      [RST_BUS_I2S1]          = { 0xa20, BIT(17) },
++      [RST_BUS_I2S2]          = { 0xa20, BIT(18) },
++      [RST_BUS_SPDIF]         = { 0xa2c, BIT(16) },
++      [RST_BUS_DMIC]          = { 0xa4c, BIT(16) },
++      [RST_BUS_AUDIO]         = { 0xa5c, BIT(16) },
++      [RST_USB_PHY0]          = { 0xa70, BIT(30) },
++      [RST_USB_PHY1]          = { 0xa74, BIT(30) },
++      [RST_BUS_OHCI0]         = { 0xa8c, BIT(16) },
++      [RST_BUS_OHCI1]         = { 0xa8c, BIT(17) },
++      [RST_BUS_EHCI0]         = { 0xa8c, BIT(20) },
++      [RST_BUS_EHCI1]         = { 0xa8c, BIT(21) },
++      [RST_BUS_OTG]           = { 0xa8c, BIT(24) },
++      [RST_BUS_LRADC]         = { 0xa9c, BIT(16) },
++      [RST_BUS_DPSS_TOP]      = { 0xabc, BIT(16) },
++      [RST_BUS_HDMI_MAIN]     = { 0xb1c, BIT(16) },
++      [RST_BUS_HDMI_SUB]      = { 0xb1c, BIT(17) },
++      [RST_BUS_MIPI_DSI]      = { 0xb4c, BIT(16) },
++      [RST_BUS_TCON_LCD0]     = { 0xb7c, BIT(16) },
++      [RST_BUS_TCON_TV]       = { 0xb9c, BIT(16) },
++      [RST_BUS_LVDS0]         = { 0xbac, BIT(16) },
++      [RST_BUS_TVE_TOP]       = { 0xbbc, BIT(16) },
++      [RST_BUS_TVE]           = { 0xbbc, BIT(17) },
++      [RST_BUS_TVD_TOP]       = { 0xbdc, BIT(16) },
++      [RST_BUS_TVD]           = { 0xbdc, BIT(17) },
++      [RST_BUS_LEDC]          = { 0xbfc, BIT(16) },
++      [RST_BUS_CSI]           = { 0xc1c, BIT(16) },
++      [RST_BUS_TPADC]         = { 0xc5c, BIT(16) },
++      [RST_DSP]               = { 0xc7c, BIT(16) },
++      [RST_BUS_DSP_CFG]       = { 0xc7c, BIT(17) },
++      [RST_BUS_DSP_DBG]       = { 0xc7c, BIT(18) },
++      [RST_BUS_RISCV_CFG]     = { 0xd0c, BIT(16) },
++};
++
++static const struct sunxi_ccu_desc sun20i_d1_ccu_desc = {
++      .ccu_clks       = sun20i_d1_ccu_clks,
++      .num_ccu_clks   = ARRAY_SIZE(sun20i_d1_ccu_clks),
++
++      .hw_clks        = &sun20i_d1_hw_clks,
++
++      .resets         = sun20i_d1_ccu_resets,
++      .num_resets     = ARRAY_SIZE(sun20i_d1_ccu_resets),
++};
++
++static const u32 pll_regs[] = {
++      SUN20I_D1_PLL_CPUX_REG,
++      SUN20I_D1_PLL_DDR0_REG,
++      SUN20I_D1_PLL_PERIPH0_REG,
++      SUN20I_D1_PLL_VIDEO0_REG,
++      SUN20I_D1_PLL_VIDEO1_REG,
++      SUN20I_D1_PLL_VE_REG,
++      SUN20I_D1_PLL_AUDIO0_REG,
++      SUN20I_D1_PLL_AUDIO1_REG,
++};
++
++static const u32 pll_video_regs[] = {
++      SUN20I_D1_PLL_VIDEO0_REG,
++      SUN20I_D1_PLL_VIDEO1_REG,
++};
++
++static struct ccu_mux_nb sun20i_d1_riscv_nb = {
++      .common         = &riscv_clk.common,
++      .cm             = &riscv_clk.mux,
++      .delay_us       = 1,
++      .bypass_index   = 4, /* index of pll-periph0 */
++};
++
++static int sun20i_d1_ccu_probe(struct platform_device *pdev)
++{
++      void __iomem *reg;
++      u32 val;
++      int i, ret;
++
++      reg = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(reg))
++              return PTR_ERR(reg);
++
++      /* Enable the enable, LDO, and lock bits on all PLLs. */
++      for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
++              val = readl(reg + pll_regs[i]);
++              val |= BIT(31) | BIT(30) | BIT(29);
++              writel(val, reg + pll_regs[i]);
++      }
++
++      /* Force PLL_CPUX factor M to 0. */
++      val = readl(reg + SUN20I_D1_PLL_CPUX_REG);
++      val &= ~GENMASK(1, 0);
++      writel(val, reg + SUN20I_D1_PLL_CPUX_REG);
++
++      /*
++       * Force the output divider of video PLLs to 0.
++       *
++       * See the comment before pll-video0 definition for the reason.
++       */
++      for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) {
++              val = readl(reg + pll_video_regs[i]);
++              val &= ~BIT(0);
++              writel(val, reg + pll_video_regs[i]);
++      }
++
++      /* Enforce m1 = 0, m0 = 0 for PLL_AUDIO0 */
++      val = readl(reg + SUN20I_D1_PLL_AUDIO0_REG);
++      val &= ~BIT(1) | BIT(0);
++      writel(val, reg + SUN20I_D1_PLL_AUDIO0_REG);
++
++      /* Force fanout-27M factor N to 0. */
++      val = readl(reg + SUN20I_D1_FANOUT_27M_REG);
++      val &= ~GENMASK(9, 8);
++      writel(val, reg + SUN20I_D1_FANOUT_27M_REG);
++
++      ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun20i_d1_ccu_desc);
++      if (ret)
++              return ret;
++
++      /* Reparent CPU during PLL CPUX rate changes */
++      ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
++                                &sun20i_d1_riscv_nb);
++
++      return 0;
++}
++
++static const struct of_device_id sun20i_d1_ccu_ids[] = {
++      { .compatible = "allwinner,sun20i-d1-ccu" },
++      { }
++};
++
++static struct platform_driver sun20i_d1_ccu_driver = {
++      .probe  = sun20i_d1_ccu_probe,
++      .driver = {
++              .name                   = "sun20i-d1-ccu",
++              .suppress_bind_attrs    = true,
++              .of_match_table         = sun20i_d1_ccu_ids,
++      },
++};
++module_platform_driver(sun20i_d1_ccu_driver);
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h
+new file mode 100644
+index 000000000000..e303176f0d4e
+--- /dev/null
++++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h
+@@ -0,0 +1,15 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2020 frank@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _CCU_SUN20I_D1_H_
++#define _CCU_SUN20I_D1_H_
++
++#include <dt-bindings/clock/sun20i-d1-ccu.h>
++#include <dt-bindings/reset/sun20i-d1-ccu.h>
++
++#define CLK_NUMBER            (CLK_FANOUT2 + 1)
++
++#endif /* _CCU_SUN20I_D1_H_ */
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0059-clk-sunxi-ng-Add-support-for-the-sun6i-RTC-clocks.patch b/target/linux/sunxid1/patches-5.15/0059-clk-sunxi-ng-Add-support-for-the-sun6i-RTC-clocks.patch
new file mode 100644 (file)
index 0000000..b5d12ad
--- /dev/null
@@ -0,0 +1,518 @@
+From b3692a02024482ac18f684a4c38cfd4be2a2a12b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 20 May 2021 00:08:20 -0500
+Subject: [PATCH 059/124] clk: sunxi-ng: Add support for the sun6i RTC clocks
+
+The RTC power domain in sun6i and newer SoCs manages the 16 MHz RC
+oscillator (called "IOSC" or "osc16M") and the optional 32 kHz crystal
+oscillator (called "LOSC" or "osc32k"). Starting with the H6, this power
+domain also handles the 24 MHz DCXO (called variously "HOSC", "dcxo24M",
+or "osc24M") as well. The H6 also adds a calibration circuit for IOSC.
+
+Later SoCs introduce further variations on the design:
+ - H616 adds an additional mux for the 32 kHz fanout source.
+ - R329 adds an additional mux for the RTC timekeeping clock, a clock
+   for the SPI bus between power domains inside the RTC, and removes the
+   IOSC calibration functionality.
+
+Take advantage of the CCU framework to handle this increased complexity.
+The CCU framework provides pre-made widgets for the mux/gate/divider
+combinations. And it allows plugging in different clocks for the same
+specifiers based on the compatible string.
+
+This driver is intended to be a drop-in replacement for the existing RTC
+clock provider. So some runtime adjustment of the clock parents is
+needed, both to handle hardware differences, and to support the old
+binding which omitted some of the input clocks.
+
+Series-changes: 2
+ - Rebase on v2 of the CCU module support series.
+ - Load the CCU driver from the RTC driver, not as an OF provider.
+
+Series-changes: 3
+ - Rebase on v3 of the CCU module support series.
+ - Move IOSC calibration control to prepare/unprepare operations.
+ - Declare several `struct clk_init_data`s as static variables (instead
+   of as anonymous) so they can be modified from the probe function.
+ - Instead of creating two copies of clocks which may or may not have
+   muxes, change the number of parents to 1 in the non-mux case.
+ - Only include clocks that are part of the binding in the OF provider.
+ - Use a single CCU description for all variants.
+ - Use IS_REACHABLE to guard the call to sun6i_rtc_ccu_probe.
+ - Allow the driver to be built on !ARM64 (i.e. RISCV).
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/Kconfig         |   5 +
+ drivers/clk/sunxi-ng/Makefile        |   2 +
+ drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 366 +++++++++++++++++++++++++++
+ drivers/clk/sunxi-ng/ccu-sun6i-rtc.h |  10 +
+ drivers/rtc/rtc-sun6i.c              |   7 +
+ include/linux/clk/sunxi-ng.h         |   2 +
+ 6 files changed, 392 insertions(+)
+ create mode 100644 drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+ create mode 100644 drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
+
+diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
+index 26555f59515d..7af83d75623b 100644
+--- a/drivers/clk/sunxi-ng/Kconfig
++++ b/drivers/clk/sunxi-ng/Kconfig
+@@ -69,6 +69,11 @@ config SUN6I_A31_CCU
+       default MACH_SUN6I
+       depends on MACH_SUN6I || COMPILE_TEST
++config SUN6I_RTC_CCU
++      tristate "Support for the Allwinner H616/R329 RTC CCU"
++      default ARCH_SUNXI
++      depends on ARCH_SUNXI || COMPILE_TEST
++
+ config SUN8I_A23_CCU
+       tristate "Support for the Allwinner A23 CCU"
+       default MACH_SUN8I
+diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
+index ec931cb7aa14..6b3ae2b620db 100644
+--- a/drivers/clk/sunxi-ng/Makefile
++++ b/drivers/clk/sunxi-ng/Makefile
+@@ -36,6 +36,7 @@ obj-$(CONFIG_SUN50I_H616_CCU)        += sun50i-h616-ccu.o
+ obj-$(CONFIG_SUN4I_A10_CCU)   += sun4i-a10-ccu.o
+ obj-$(CONFIG_SUN5I_CCU)               += sun5i-ccu.o
+ obj-$(CONFIG_SUN6I_A31_CCU)   += sun6i-a31-ccu.o
++obj-$(CONFIG_SUN6I_RTC_CCU)   += sun6i-rtc-ccu.o
+ obj-$(CONFIG_SUN8I_A23_CCU)   += sun8i-a23-ccu.o
+ obj-$(CONFIG_SUN8I_A33_CCU)   += sun8i-a33-ccu.o
+ obj-$(CONFIG_SUN8I_A83T_CCU)  += sun8i-a83t-ccu.o
+@@ -60,6 +61,7 @@ sun50i-h616-ccu-y            += ccu-sun50i-h616.o
+ sun4i-a10-ccu-y                       += ccu-sun4i-a10.o
+ sun5i-ccu-y                   += ccu-sun5i.o
+ sun6i-a31-ccu-y                       += ccu-sun6i-a31.o
++sun6i-rtc-ccu-y                       += ccu-sun6i-rtc.o
+ sun8i-a23-ccu-y                       += ccu-sun8i-a23.o
+ sun8i-a33-ccu-y                       += ccu-sun8i-a33.o
+ sun8i-a83t-ccu-y              += ccu-sun8i-a83t.o
+diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+new file mode 100644
+index 000000000000..f563cee58a20
+--- /dev/null
++++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+@@ -0,0 +1,366 @@
++// SPDX-License-Identifier: GPL-2.0-only
++//
++// Copyright (c) 2021 Samuel Holland <samuel@sholland.org>
++//
++
++#include <linux/clk-provider.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++
++#include "ccu_common.h"
++
++#include "ccu_div.h"
++#include "ccu_gate.h"
++#include "ccu_mux.h"
++
++#include "ccu-sun6i-rtc.h"
++
++#define IOSC_ACCURACY                 300000000 /* 30% */
++#define IOSC_RATE                     16000000
++
++#define LOSC_RATE                     32768
++#define LOSC_RATE_SHIFT                       15
++
++#define LOSC_CTRL_REG                 0x0
++#define LOSC_CTRL_KEY                 0x16aa0000
++
++#define IOSC_32K_CLK_DIV_REG          0x8
++#define IOSC_32K_CLK_DIV              GENMASK(4, 0)
++#define IOSC_32K_PRE_DIV              32
++
++#define IOSC_CLK_CALI_REG             0xc
++#define IOSC_CLK_CALI_DIV_ONES                22
++#define IOSC_CLK_CALI_EN              BIT(1)
++#define IOSC_CLK_CALI_SRC_SEL         BIT(0)
++
++#define LOSC_OUT_GATING_REG           0x60
++
++#define DCXO_CTRL_REG                 0x160
++#define DCXO_CTRL_CLK16M_RC_EN                BIT(0)
++
++struct sun6i_rtc_match_data {
++      bool                            have_ext_osc32k         : 1;
++      bool                            have_iosc_calibration   : 1;
++      bool                            rtc_32k_single_parent   : 1;
++      const struct clk_parent_data    *osc32k_fanout_parents;
++      u8                              osc32k_fanout_nparents;
++};
++
++static bool have_iosc_calibration;
++
++static int ccu_iosc_enable(struct clk_hw *hw)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++
++      return ccu_gate_helper_enable(cm, DCXO_CTRL_CLK16M_RC_EN);
++}
++
++static void ccu_iosc_disable(struct clk_hw *hw)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++
++      return ccu_gate_helper_disable(cm, DCXO_CTRL_CLK16M_RC_EN);
++}
++
++static int ccu_iosc_is_enabled(struct clk_hw *hw)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++
++      return ccu_gate_helper_is_enabled(cm, DCXO_CTRL_CLK16M_RC_EN);
++}
++
++static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
++                                        unsigned long parent_rate)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++
++      if (have_iosc_calibration) {
++              u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
++
++              /*
++               * Recover the IOSC frequency by shifting the ones place of
++               * (fixed-point divider * 32768) into bit zero.
++               */
++              if (reg & IOSC_CLK_CALI_EN)
++                      return reg >> (IOSC_CLK_CALI_DIV_ONES - LOSC_RATE_SHIFT);
++      }
++
++      return IOSC_RATE;
++}
++
++static unsigned long ccu_iosc_recalc_accuracy(struct clk_hw *hw,
++                                            unsigned long parent_accuracy)
++{
++      return IOSC_ACCURACY;
++}
++
++static const struct clk_ops ccu_iosc_ops = {
++      .enable                 = ccu_iosc_enable,
++      .disable                = ccu_iosc_disable,
++      .is_enabled             = ccu_iosc_is_enabled,
++      .recalc_rate            = ccu_iosc_recalc_rate,
++      .recalc_accuracy        = ccu_iosc_recalc_accuracy,
++};
++
++static struct ccu_common iosc_clk = {
++      .reg            = DCXO_CTRL_REG,
++      .hw.init        = CLK_HW_INIT_NO_PARENT("iosc", &ccu_iosc_ops,
++                                              CLK_GET_RATE_NOCACHE),
++};
++
++static int ccu_iosc_32k_prepare(struct clk_hw *hw)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++      u32 val;
++
++      if (!have_iosc_calibration)
++              return 0;
++
++      val = readl(cm->base + IOSC_CLK_CALI_REG);
++      writel(val | IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL,
++             cm->base + IOSC_CLK_CALI_REG);
++
++      return 0;
++}
++
++static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++      u32 val;
++
++      if (!have_iosc_calibration)
++              return;
++
++      val = readl(cm->base + IOSC_CLK_CALI_REG);
++      writel(val & ~(IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL),
++             cm->base + IOSC_CLK_CALI_REG);
++}
++
++static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
++                                            unsigned long parent_rate)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++      u32 val;
++
++      if (have_iosc_calibration) {
++              val = readl(cm->base + IOSC_CLK_CALI_REG);
++
++              /* Assume the calibrated 32k clock is accurate. */
++              if (val & IOSC_CLK_CALI_SRC_SEL)
++                      return LOSC_RATE;
++      }
++
++      val = readl(cm->base + IOSC_32K_CLK_DIV_REG) & IOSC_32K_CLK_DIV;
++
++      return parent_rate / IOSC_32K_PRE_DIV / (val + 1);
++}
++
++static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
++                                                unsigned long parent_accuracy)
++{
++      struct ccu_common *cm = hw_to_ccu_common(hw);
++      u32 val;
++
++      if (have_iosc_calibration) {
++              val = readl(cm->base + IOSC_CLK_CALI_REG);
++
++              /* Assume the calibrated 32k clock is accurate. */
++              if (val & IOSC_CLK_CALI_SRC_SEL)
++                      return 0;
++      }
++
++      return parent_accuracy;
++}
++
++static const struct clk_ops ccu_iosc_32k_ops = {
++      .prepare                = ccu_iosc_32k_prepare,
++      .unprepare              = ccu_iosc_32k_unprepare,
++      .recalc_rate            = ccu_iosc_32k_recalc_rate,
++      .recalc_accuracy        = ccu_iosc_32k_recalc_accuracy,
++};
++
++static struct ccu_common iosc_32k_clk = {
++      .hw.init        = CLK_HW_INIT_HW("iosc-32k", &iosc_clk.hw,
++                                       &ccu_iosc_32k_ops,
++                                       CLK_GET_RATE_NOCACHE),
++};
++
++/* .fw_name will be cleared if the clock-names property is missing. */
++static struct clk_parent_data ext_osc32k[] = {
++      { .fw_name = "ext-osc32k", .index = 0 }
++};
++
++static SUNXI_CCU_GATE_DATA(ext_osc32k_gate_clk, "ext-osc32k-gate",
++                         ext_osc32k, 0x0, BIT(4), 0);
++
++static const struct clk_hw *osc32k_parents[] = {
++      &iosc_32k_clk.hw,
++      &ext_osc32k_gate_clk.common.hw
++};
++
++static struct clk_init_data osc32k_init_data = {
++      .name           = "osc32k",
++      .ops            = &ccu_mux_ops,
++      .parent_hws     = osc32k_parents,
++      .num_parents    = ARRAY_SIZE(osc32k_parents), /* updated during probe */
++};
++
++static struct ccu_mux osc32k_clk = {
++      .mux    = _SUNXI_CCU_MUX(0, 1),
++      .common = {
++              .reg            = LOSC_CTRL_REG,
++              .features       = CCU_FEATURE_KEY_FIELD,
++              .hw.init        = &osc32k_init_data,
++      },
++};
++
++/* This falls back to the global name for fwnodes without a named reference. */
++static const struct clk_parent_data osc24M[] = {
++      { .fw_name = "hosc", .name = "osc24M" }
++};
++
++static struct ccu_gate osc24M_32k_clk = {
++      .enable = BIT(16),
++      .common = {
++              .reg            = LOSC_OUT_GATING_REG,
++              .prediv         = 750,
++              .features       = CCU_FEATURE_ALL_PREDIV,
++              .hw.init        = CLK_HW_INIT_PARENTS_DATA("osc24M-32k", osc24M,
++                                                         &ccu_gate_ops, 0),
++      },
++};
++
++static const struct clk_hw *rtc_32k_parents[] = {
++      &osc32k_clk.common.hw,
++      &osc24M_32k_clk.common.hw
++};
++
++static struct clk_init_data rtc_32k_init_data = {
++      .name           = "rtc-32k",
++      .ops            = &ccu_mux_ops,
++      .parent_hws     = rtc_32k_parents,
++      .num_parents    = ARRAY_SIZE(rtc_32k_parents), /* updated during probe */
++};
++
++static struct ccu_mux rtc_32k_clk = {
++      .mux    = _SUNXI_CCU_MUX(1, 1),
++      .common = {
++              .reg            = LOSC_CTRL_REG,
++              .features       = CCU_FEATURE_KEY_FIELD,
++              .hw.init        = &rtc_32k_init_data,
++      },
++};
++
++static struct clk_init_data osc32k_fanout_init_data = {
++      .name           = "osc32k-fanout",
++      .ops            = &ccu_mux_ops,
++      /* parents are set during probe */
++};
++
++static struct ccu_mux osc32k_fanout_clk = {
++      .enable = BIT(0),
++      .mux    = _SUNXI_CCU_MUX(1, 2),
++      .common = {
++              .reg            = LOSC_OUT_GATING_REG,
++              .hw.init        = &osc32k_fanout_init_data,
++      },
++};
++
++static struct ccu_common *sun6i_rtc_ccu_clks[] = {
++      &iosc_clk,
++      &iosc_32k_clk,
++      &ext_osc32k_gate_clk.common, /* updated during probe */
++      &osc32k_clk.common,
++      &osc24M_32k_clk.common,
++      &rtc_32k_clk.common,
++      &osc32k_fanout_clk.common,
++};
++
++static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
++      .num = CLK_NUMBER,
++      .hws = {
++              [CLK_OSC32K]            = &osc32k_clk.common.hw,
++              [CLK_OSC32K_FANOUT]     = &osc32k_fanout_clk.common.hw,
++              [CLK_IOSC]              = &iosc_clk.hw,
++      },
++};
++
++static const struct sunxi_ccu_desc sun6i_rtc_ccu_desc = {
++      .ccu_clks       = sun6i_rtc_ccu_clks,
++      .num_ccu_clks   = ARRAY_SIZE(sun6i_rtc_ccu_clks),
++
++      .hw_clks        = &sun6i_rtc_ccu_hw_clks,
++};
++
++static const struct clk_parent_data sun50i_h616_osc32k_fanout_parents[] = {
++      { .hw = &osc32k_clk.common.hw },
++      { .fw_name = "pll-32k" },
++      { .hw = &osc24M_32k_clk.common.hw }
++};
++
++static const struct clk_parent_data sun50i_r329_osc32k_fanout_parents[] = {
++      { .hw = &osc32k_clk.common.hw },
++      { .hw = &ext_osc32k_gate_clk.common.hw },
++      { .hw = &osc24M_32k_clk.common.hw }
++};
++
++static const struct sun6i_rtc_match_data sun50i_h616_rtc_ccu_data = {
++      .have_iosc_calibration  = true,
++      .rtc_32k_single_parent  = true,
++      .osc32k_fanout_parents  = sun50i_h616_osc32k_fanout_parents,
++      .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_h616_osc32k_fanout_parents),
++};
++
++static const struct sun6i_rtc_match_data sun50i_r329_rtc_ccu_data = {
++      .have_ext_osc32k        = true,
++      .osc32k_fanout_parents  = sun50i_r329_osc32k_fanout_parents,
++      .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents),
++};
++
++static const struct of_device_id sun6i_rtc_ccu_match[] = {
++      {
++              .compatible     = "allwinner,sun50i-h616-rtc",
++              .data           = &sun50i_h616_rtc_ccu_data,
++      },
++      {
++              .compatible     = "allwinner,sun50i-r329-rtc",
++              .data           = &sun50i_r329_rtc_ccu_data,
++      },
++};
++
++int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
++{
++      struct device_node *node = dev->of_node;
++      const struct sun6i_rtc_match_data *data;
++      const struct of_device_id *match;
++
++      match = of_match_device(sun6i_rtc_ccu_match, dev);
++      if (!match)
++              return 0;
++
++      data = match->data;
++      have_iosc_calibration = data->have_iosc_calibration;
++
++      if (data->have_ext_osc32k) {
++              /* ext-osc32k was the only input clock in the old binding. */
++              if (!of_property_read_bool(node, "clock-names"))
++                      ext_osc32k->fw_name = NULL;
++      } else {
++              /* Do not register the orphan ext-osc32k-gate clock. */
++              sun6i_rtc_ccu_clks[2] = NULL;
++
++              osc32k_init_data.num_parents = 1;
++      }
++
++      if (data->rtc_32k_single_parent)
++              rtc_32k_init_data.num_parents = 1;
++
++      osc32k_fanout_init_data.parent_data = data->osc32k_fanout_parents;
++      osc32k_fanout_init_data.num_parents = data->osc32k_fanout_nparents;
++
++      return devm_sunxi_ccu_probe(dev, reg, &sun6i_rtc_ccu_desc);
++}
++
++MODULE_IMPORT_NS(SUNXI_CCU);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
+new file mode 100644
+index 000000000000..0c1ac4c705a0
+--- /dev/null
++++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
+@@ -0,0 +1,10 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++#ifndef _CCU_SUN6I_RTC_H
++#define _CCU_SUN6I_RTC_H
++
++#include <dt-bindings/clock/sun6i-rtc.h>
++
++#define CLK_NUMBER            (CLK_IOSC + 1)
++
++#endif /* _CCU_SUN6I_RTC_H */
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index 711832c758ae..12fd674b003d 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -13,6 +13,7 @@
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
++#include <linux/clk/sunxi-ng.h>
+ #include <linux/delay.h>
+ #include <linux/err.h>
+ #include <linux/fs.h>
+@@ -683,6 +684,12 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
+               chip->base = devm_platform_ioremap_resource(pdev, 0);
+               if (IS_ERR(chip->base))
+                       return PTR_ERR(chip->base);
++
++              if (IS_REACHABLE(CONFIG_SUN6I_RTC_CCU)) {
++                      ret = sun6i_rtc_ccu_probe(&pdev->dev, chip->base);
++                      if (ret)
++                              return ret;
++              }
+       }
+       platform_set_drvdata(pdev, chip);
+diff --git a/include/linux/clk/sunxi-ng.h b/include/linux/clk/sunxi-ng.h
+index cf32123b39f5..57c8ec44ab4e 100644
+--- a/include/linux/clk/sunxi-ng.h
++++ b/include/linux/clk/sunxi-ng.h
+@@ -9,4 +9,6 @@
+ int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode);
+ int sunxi_ccu_get_mmc_timing_mode(struct clk *clk);
++int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg);
++
+ #endif
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0060-clk-sunxi-ng-sun6i-rtc-Add-support-for-H6.patch b/target/linux/sunxid1/patches-5.15/0060-clk-sunxi-ng-sun6i-rtc-Add-support-for-H6.patch
new file mode 100644 (file)
index 0000000..f6a23e4
--- /dev/null
@@ -0,0 +1,91 @@
+From 026ed9ed88c6cb6b2ae8f005f7b83304800a6171 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Tue, 31 Aug 2021 23:01:42 -0500
+Subject: [PATCH 060/124] clk: sunxi-ng: sun6i-rtc: Add support for H6
+
+H6 supports IOSC calibration and an ext-osc32k input. Unlike newer SoCs,
+it has a single parent for its fanout clock.
+
+Add support for H6 in the CCU driver, replacing the support in the
+existing early OF clock provider.
+
+Series-changes: 3
+ - Rebase example on top of driver changes, and drop the second example.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 15 +++++++++++++++
+ drivers/rtc/rtc-sun6i.c              | 17 -----------------
+ 2 files changed, 15 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+index f563cee58a20..e5541da098f1 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
++++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+@@ -293,6 +293,10 @@ static const struct sunxi_ccu_desc sun6i_rtc_ccu_desc = {
+       .hw_clks        = &sun6i_rtc_ccu_hw_clks,
+ };
++static const struct clk_parent_data sun50i_h6_osc32k_fanout_parents[] = {
++      { .hw = &osc32k_clk.common.hw },
++};
++
+ static const struct clk_parent_data sun50i_h616_osc32k_fanout_parents[] = {
+       { .hw = &osc32k_clk.common.hw },
+       { .fw_name = "pll-32k" },
+@@ -305,6 +309,13 @@ static const struct clk_parent_data sun50i_r329_osc32k_fanout_parents[] = {
+       { .hw = &osc24M_32k_clk.common.hw }
+ };
++static const struct sun6i_rtc_match_data sun50i_h6_rtc_ccu_data = {
++      .have_ext_osc32k        = true,
++      .have_iosc_calibration  = true,
++      .osc32k_fanout_parents  = sun50i_h6_osc32k_fanout_parents,
++      .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_h6_osc32k_fanout_parents),
++};
++
+ static const struct sun6i_rtc_match_data sun50i_h616_rtc_ccu_data = {
+       .have_iosc_calibration  = true,
+       .rtc_32k_single_parent  = true,
+@@ -319,6 +330,10 @@ static const struct sun6i_rtc_match_data sun50i_r329_rtc_ccu_data = {
+ };
+ static const struct of_device_id sun6i_rtc_ccu_match[] = {
++      {
++              .compatible     = "allwinner,sun50i-h6-rtc",
++              .data           = &sun50i_h6_rtc_ccu_data,
++      },
+       {
+               .compatible     = "allwinner,sun50i-h616-rtc",
+               .data           = &sun50i_h616_rtc_ccu_data,
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index 12fd674b003d..4358cde143d4 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -364,23 +364,6 @@ CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc",
+ CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc",
+                     sun8i_h3_rtc_clk_init);
+-static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
+-      .rc_osc_rate = 16000000,
+-      .fixed_prescaler = 32,
+-      .has_prescaler = 1,
+-      .has_out_clk = 1,
+-      .export_iosc = 1,
+-      .has_losc_en = 1,
+-      .has_auto_swt = 1,
+-};
+-
+-static void __init sun50i_h6_rtc_clk_init(struct device_node *node)
+-{
+-      sun6i_rtc_clk_init(node, &sun50i_h6_rtc_data);
+-}
+-CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc",
+-                    sun50i_h6_rtc_clk_init);
+-
+ /*
+  * The R40 user manual is self-conflicting on whether the prescaler is
+  * fixed or configurable. The clock diagram shows it as fixed, but there
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0061-dmaengine-sun6i-Add-support-for-the-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0061-dmaengine-sun6i-Add-support-for-the-D1-variant.patch
new file mode 100644 (file)
index 0000000..cc67425
--- /dev/null
@@ -0,0 +1,41 @@
+From 739535112738d67cfeada06baea94fbc40f84328 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 12 Jun 2021 08:04:28 -0500
+Subject: [PATCH 061/124] dmaengine: sun6i: Add support for the D1 variant
+
+So far it appears to work identically to the A100 variant.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/dma/Kconfig     | 2 +-
+ drivers/dma/sun6i-dma.c | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
+index 80c2c03cb014..910ff963da60 100644
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -163,7 +163,7 @@ config DMA_SUN4I
+ config DMA_SUN6I
+       tristate "Allwinner A31 SoCs DMA support"
+-      depends on MACH_SUN6I || MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
++      depends on ARCH_SUNXI || COMPILE_TEST
+       depends on RESET_CONTROLLER
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
+index 8c7cce643cdc..795cce445532 100644
+--- a/drivers/dma/sun6i-dma.c
++++ b/drivers/dma/sun6i-dma.c
+@@ -1277,6 +1277,7 @@ static const struct of_device_id sun6i_dma_match[] = {
+       { .compatible = "allwinner,sun8i-a83t-dma", .data = &sun8i_a83t_dma_cfg },
+       { .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
+       { .compatible = "allwinner,sun8i-v3s-dma", .data = &sun8i_v3s_dma_cfg },
++      { .compatible = "allwinner,sun20i-d1-dma", .data = &sun50i_a100_dma_cfg },
+       { .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg },
+       { .compatible = "allwinner,sun50i-a100-dma", .data = &sun50i_a100_dma_cfg },
+       { .compatible = "allwinner,sun50i-h6-dma", .data = &sun50i_h6_dma_cfg },
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0062-riscv-pgtable-Fixup-_PAGE_CHG_MASK-usage.patch b/target/linux/sunxid1/patches-5.15/0062-riscv-pgtable-Fixup-_PAGE_CHG_MASK-usage.patch
new file mode 100644 (file)
index 0000000..e8b2269
--- /dev/null
@@ -0,0 +1,85 @@
+From db0b9488559ef01603ff9bc5799d41d7bd346b39 Mon Sep 17 00:00:00 2001
+From: Guo Ren <guoren@linux.alibaba.com>
+Date: Sun, 6 Jun 2021 09:04:02 +0000
+Subject: [PATCH 062/124] riscv: pgtable: Fixup _PAGE_CHG_MASK usage
+
+We should masks all attributes BITS first, and then
+using '>> _PAGE_PFN_SHIFT' to get the final PFN value.
+
+Adding '& _PAGE_CHG_MASK' makes the code semantics more accurate.
+
+Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
+Signed-off-by: Liu Shaohua <liush@allwinnertech.com>
+Cc: Anup Patel <anup.patel@wdc.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Chen-Yu Tsai <wens@csie.org>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Drew Fustini <drew@beagleboard.org>
+Cc: Maxime Ripard <maxime@cerno.tech>
+Cc: Palmer Dabbelt <palmerdabbelt@google.com>
+Cc: Wei Fu <wefu@redhat.com>
+Cc: Wei Wu <lazyparser@gmail.com>
+---
+ arch/riscv/include/asm/pgtable-64.h | 6 +++---
+ arch/riscv/include/asm/pgtable.h    | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
+index 228261aa9628..6df493b55dde 100644
+--- a/arch/riscv/include/asm/pgtable-64.h
++++ b/arch/riscv/include/asm/pgtable-64.h
+@@ -61,12 +61,12 @@ static inline void pud_clear(pud_t *pudp)
+ static inline pmd_t *pud_pgtable(pud_t pud)
+ {
+-      return (pmd_t *)pfn_to_virt(pud_val(pud) >> _PAGE_PFN_SHIFT);
++      return (pmd_t *)pfn_to_virt((pud_val(pud) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT);
+ }
+ static inline struct page *pud_page(pud_t pud)
+ {
+-      return pfn_to_page(pud_val(pud) >> _PAGE_PFN_SHIFT);
++      return pfn_to_page((pud_val(pud) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT);
+ }
+ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
+@@ -76,7 +76,7 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
+ static inline unsigned long _pmd_pfn(pmd_t pmd)
+ {
+-      return pmd_val(pmd) >> _PAGE_PFN_SHIFT;
++      return (pmd_val(pmd) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT;
+ }
+ #define mk_pmd(page, prot)    pfn_pmd(page_to_pfn(page), prot)
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index bf204e7c1f74..4866597886f1 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -232,12 +232,12 @@ static inline unsigned long _pgd_pfn(pgd_t pgd)
+ static inline struct page *pmd_page(pmd_t pmd)
+ {
+-      return pfn_to_page(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
++      return pfn_to_page((pmd_val(pmd) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT);
+ }
+ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+ {
+-      return (unsigned long)pfn_to_virt(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
++      return (unsigned long)pfn_to_virt((pmd_val(pmd) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT);
+ }
+ static inline pte_t pmd_pte(pmd_t pmd)
+@@ -253,7 +253,7 @@ static inline pte_t pud_pte(pud_t pud)
+ /* Yields the page frame number (PFN) of a page table entry */
+ static inline unsigned long pte_pfn(pte_t pte)
+ {
+-      return (pte_val(pte) >> _PAGE_PFN_SHIFT);
++      return (pte_val(pte) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT;
+ }
+ #define pte_page(x)     pfn_to_page(pte_pfn(x))
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0063-riscv-pgtable-Add-custom-protection_map-init.patch b/target/linux/sunxid1/patches-5.15/0063-riscv-pgtable-Add-custom-protection_map-init.patch
new file mode 100644 (file)
index 0000000..38686e9
--- /dev/null
@@ -0,0 +1,105 @@
+From 65bf9a94eed354bb356e61573b0a011e305e6fda Mon Sep 17 00:00:00 2001
+From: Guo Ren <guoren@linux.alibaba.com>
+Date: Sun, 6 Jun 2021 09:04:03 +0000
+Subject: [PATCH 063/124] riscv: pgtable: Add custom protection_map init
+
+Some RISC-V CPU vendors have defined their own PTE attributes to
+solve non-coherent DMA bus problems. That makes _P/SXXX definitions
+contain global variables which could be initialized at the early
+boot stage before setup_vm.
+
+This patch is similar to 316d097c4cd4  (x86/pti: Filter at
+vma->vm_page_prot population) which give a choice for arch custom
+implementation.
+
+Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+---
+ arch/riscv/Kconfig   |  4 ++++
+ arch/riscv/mm/init.c | 22 ++++++++++++++++++++++
+ mm/mmap.c            |  4 ++++
+ 3 files changed, 30 insertions(+)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index 1d7b5066ce80..7e907aa32ac8 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -23,6 +23,7 @@ config RISCV
+       select ARCH_HAS_GIGANTIC_PAGE
+       select ARCH_HAS_KCOV
+       select ARCH_HAS_MMIOWB
++      select ARCH_HAS_PROTECTION_MAP_INIT
+       select ARCH_HAS_PTE_SPECIAL
+       select ARCH_HAS_SET_DIRECT_MAP if MMU
+       select ARCH_HAS_SET_MEMORY if MMU
+@@ -211,6 +212,9 @@ config GENERIC_HWEIGHT
+ config FIX_EARLYCON_MEM
+       def_bool MMU
++config ARCH_HAS_PROTECTION_MAP_INIT
++      def_bool y
++
+ config PGTABLE_LEVELS
+       int
+       default 3 if 64BIT
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index 24b2b8044602..6ba585a974a6 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -588,10 +588,32 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
+       dtb_early_pa = dtb_pa;
+ }
++static void __init setup_protection_map(void)
++{
++      protection_map[0]  = __P000;
++      protection_map[1]  = __P001;
++      protection_map[2]  = __P010;
++      protection_map[3]  = __P011;
++      protection_map[4]  = __P100;
++      protection_map[5]  = __P101;
++      protection_map[6]  = __P110;
++      protection_map[7]  = __P111;
++      protection_map[8]  = __S000;
++      protection_map[9]  = __S001;
++      protection_map[10] = __S010;
++      protection_map[11] = __S011;
++      protection_map[12] = __S100;
++      protection_map[13] = __S101;
++      protection_map[14] = __S110;
++      protection_map[15] = __S111;
++}
++
+ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
+ {
+       pmd_t __maybe_unused fix_bmap_spmd, fix_bmap_epmd;
++      setup_protection_map();
++
+       kernel_map.virt_addr = KERNEL_LINK_ADDR;
+ #ifdef CONFIG_XIP_KERNEL
+diff --git a/mm/mmap.c b/mm/mmap.c
+index 88dcc5c25225..55b9da1f8b56 100644
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -100,10 +100,14 @@ static void unmap_region(struct mm_struct *mm,
+  *                                                            w: (no) no
+  *                                                            x: (yes) yes
+  */
++#ifdef CONFIG_ARCH_HAS_PROTECTION_MAP_INIT
++pgprot_t protection_map[16] __ro_after_init;
++#else
+ pgprot_t protection_map[16] __ro_after_init = {
+       __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
+       __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
+ };
++#endif
+ #ifndef CONFIG_ARCH_HAS_FILTER_PGPROT
+ static inline pgprot_t arch_filter_pgprot(pgprot_t prot)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0064-riscv-pgtable-Add-DMA_COHERENT-with-custom-PTE-attri.patch b/target/linux/sunxid1/patches-5.15/0064-riscv-pgtable-Add-DMA_COHERENT-with-custom-PTE-attri.patch
new file mode 100644 (file)
index 0000000..fe8a54d
--- /dev/null
@@ -0,0 +1,200 @@
+From d2579d2b8552501662320fbc57875f83f0d91a4f Mon Sep 17 00:00:00 2001
+From: Guo Ren <guoren@linux.alibaba.com>
+Date: Sun, 6 Jun 2021 09:04:04 +0000
+Subject: [PATCH 064/124] riscv: pgtable: Add DMA_COHERENT with custom PTE
+ attributes
+
+The dma-noncoherent SOCs need different virtual memory mappings
+with different attributes:
+ - noncached + Strong Order (for IO/DMA descriptor)
+ - noncached + Weak Order (for writecombine usage, eg: frame
+   buffer)
+
+All above base on PTE attributes by MMU hardware. That means
+address attributes are determined by PTE entry, not PMA. RISC-V
+soc vendors have defined their own custom PTE attributes for
+dma-noncoherency.
+
+Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
+Signed-off-by: Liu Shaohua <liush@allwinnertech.com>
+Cc: Palmer Dabbelt <palmerdabbelt@google.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Anup Patel <anup.patel@wdc.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Drew Fustini <drew@beagleboard.org>
+Cc: Wei Fu <wefu@redhat.com>
+Cc: Wei Wu <lazyparser@gmail.com>
+Cc: Chen-Yu Tsai <wens@csie.org>
+Cc: Maxime Ripard <maxime@cerno.tech>
+---
+ arch/riscv/include/asm/pgtable-bits.h  | 22 +++++++++++++++++++++-
+ arch/riscv/include/asm/pgtable.h       | 11 ++++-------
+ arch/riscv/include/asm/soc.h           |  1 +
+ arch/riscv/include/asm/vendorid_list.h |  1 +
+ arch/riscv/kernel/soc.c                | 22 ++++++++++++++++++++++
+ arch/riscv/mm/init.c                   |  4 ++++
+ 6 files changed, 53 insertions(+), 8 deletions(-)
+
+diff --git a/arch/riscv/include/asm/pgtable-bits.h b/arch/riscv/include/asm/pgtable-bits.h
+index 2ee413912926..e9e95666f9bd 100644
+--- a/arch/riscv/include/asm/pgtable-bits.h
++++ b/arch/riscv/include/asm/pgtable-bits.h
+@@ -24,6 +24,11 @@
+ #define _PAGE_DIRTY     (1 << 7)    /* Set by hardware on any write */
+ #define _PAGE_SOFT      (1 << 8)    /* Reserved for software */
++#define _PAGE_DMA_MASK        __riscv_custom_pte.mask
++#define _PAGE_DMA_CACHE       __riscv_custom_pte.cache
++#define _PAGE_DMA_IO  __riscv_custom_pte.io
++#define _PAGE_DMA_WC  __riscv_custom_pte.wc
++
+ #define _PAGE_SPECIAL   _PAGE_SOFT
+ #define _PAGE_TABLE     _PAGE_PRESENT
+@@ -35,10 +40,25 @@
+ #define _PAGE_PFN_SHIFT 10
++#ifndef __ASSEMBLY__
++
++struct riscv_custom_pte {
++      unsigned long cache;
++      unsigned long mask;
++      unsigned long io;
++      unsigned long wc;
++};
++
++extern struct riscv_custom_pte __riscv_custom_pte;
++
+ /* Set of bits to preserve across pte_modify() */
+ #define _PAGE_CHG_MASK  (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ |        \
+                                         _PAGE_WRITE | _PAGE_EXEC |    \
+-                                        _PAGE_USER | _PAGE_GLOBAL))
++                                        _PAGE_USER | _PAGE_GLOBAL |   \
++                                        _PAGE_DMA_MASK))
++
++#endif
++
+ /*
+  * when all of R/W/X are zero, the PTE is a pointer to the next level
+  * of the page table; otherwise, it is a leaf PTE.
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index 4866597886f1..6f2bdab5bfa7 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -117,7 +117,7 @@
+ #define USER_PTRS_PER_PGD   (TASK_SIZE / PGDIR_SIZE)
+ /* Page protection bits */
+-#define _PAGE_BASE    (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER)
++#define _PAGE_BASE    (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER | _PAGE_DMA_CACHE)
+ #define PAGE_NONE             __pgprot(_PAGE_PROT_NONE)
+ #define PAGE_READ             __pgprot(_PAGE_BASE | _PAGE_READ)
+@@ -138,7 +138,8 @@
+                               | _PAGE_PRESENT \
+                               | _PAGE_ACCESSED \
+                               | _PAGE_DIRTY \
+-                              | _PAGE_GLOBAL)
++                              | _PAGE_GLOBAL \
++                              | _PAGE_DMA_CACHE)
+ #define PAGE_KERNEL           __pgprot(_PAGE_KERNEL)
+ #define PAGE_KERNEL_READ      __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
+@@ -148,11 +149,7 @@
+ #define PAGE_TABLE            __pgprot(_PAGE_TABLE)
+-/*
+- * The RISC-V ISA doesn't yet specify how to query or modify PMAs, so we can't
+- * change the properties of memory regions.
+- */
+-#define _PAGE_IOREMAP _PAGE_KERNEL
++#define _PAGE_IOREMAP ((_PAGE_KERNEL & ~_PAGE_DMA_MASK) | _PAGE_DMA_IO)
+ extern pgd_t swapper_pg_dir[];
+diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h
+index f494066051a2..fc587d7d295d 100644
+--- a/arch/riscv/include/asm/soc.h
++++ b/arch/riscv/include/asm/soc.h
+@@ -17,6 +17,7 @@
+                = { .compatible = compat, .data = fn  }
+ void soc_early_init(void);
++void soc_setup_vm(void);
+ extern unsigned long __soc_early_init_table_start;
+ extern unsigned long __soc_early_init_table_end;
+diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h
+index 9d934215b3c8..c2710f391a89 100644
+--- a/arch/riscv/include/asm/vendorid_list.h
++++ b/arch/riscv/include/asm/vendorid_list.h
+@@ -6,5 +6,6 @@
+ #define ASM_VENDOR_LIST_H
+ #define SIFIVE_VENDOR_ID      0x489
++#define  THEAD_VENDOR_ID      0x401
+ #endif
+diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c
+index a0516172a33c..05fa76467e69 100644
+--- a/arch/riscv/kernel/soc.c
++++ b/arch/riscv/kernel/soc.c
+@@ -3,8 +3,10 @@
+  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+  */
+ #include <linux/init.h>
++#include <linux/mm.h>
+ #include <linux/libfdt.h>
+ #include <linux/pgtable.h>
++#include <asm/image.h>
+ #include <asm/soc.h>
+ /*
+@@ -26,3 +28,23 @@ void __init soc_early_init(void)
+               }
+       }
+ }
++
++static void __init thead_init(void)
++{
++      __riscv_custom_pte.cache = 0x7000000000000000;
++      __riscv_custom_pte.mask  = 0xf800000000000000;
++      __riscv_custom_pte.io    = BIT(63);
++      __riscv_custom_pte.wc    = 0;
++}
++
++void __init soc_setup_vm(void)
++{
++      unsigned long vendor_id =
++              ((struct riscv_image_header *)(&_start))->res1;
++
++      switch (vendor_id) {
++      case THEAD_VENDOR_ID:
++              thead_init();
++              break;
++      }
++};
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index 6ba585a974a6..4af87922c19f 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -612,6 +612,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
+ {
+       pmd_t __maybe_unused fix_bmap_spmd, fix_bmap_epmd;
++      soc_setup_vm();
+       setup_protection_map();
+       kernel_map.virt_addr = KERNEL_LINK_ADDR;
+@@ -876,3 +877,6 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
+       return vmemmap_populate_basepages(start, end, node, NULL);
+ }
+ #endif
++
++struct riscv_custom_pte __riscv_custom_pte __ro_after_init;
++EXPORT_SYMBOL(__riscv_custom_pte);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0065-riscv-fixup-PAGE_NONE.patch b/target/linux/sunxid1/patches-5.15/0065-riscv-fixup-PAGE_NONE.patch
new file mode 100644 (file)
index 0000000..3bc529f
--- /dev/null
@@ -0,0 +1,26 @@
+From 43e3d184609e4a46d17a5c897e7e1da113233ca2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 15 Nov 2021 23:37:41 -0600
+Subject: [PATCH 065/124] riscv: fixup PAGE_NONE
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/include/asm/pgtable.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index 6f2bdab5bfa7..cb24ca059442 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -119,7 +119,7 @@
+ /* Page protection bits */
+ #define _PAGE_BASE    (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER | _PAGE_DMA_CACHE)
+-#define PAGE_NONE             __pgprot(_PAGE_PROT_NONE)
++#define PAGE_NONE             __pgprot(_PAGE_DMA_CACHE | _PAGE_PROT_NONE)
+ #define PAGE_READ             __pgprot(_PAGE_BASE | _PAGE_READ)
+ #define PAGE_WRITE            __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_WRITE)
+ #define PAGE_EXEC             __pgprot(_PAGE_BASE | _PAGE_EXEC)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0066-riscv-cmo-Add-dma-noncoherency-support.patch b/target/linux/sunxid1/patches-5.15/0066-riscv-cmo-Add-dma-noncoherency-support.patch
new file mode 100644 (file)
index 0000000..976b25b
--- /dev/null
@@ -0,0 +1,253 @@
+From 346b9731f8704f684aa1e74b7ced812864d78da2 Mon Sep 17 00:00:00 2001
+From: Guo Ren <guoren@linux.alibaba.com>
+Date: Sun, 6 Jun 2021 09:04:05 +0000
+Subject: [PATCH 066/124] riscv: cmo: Add dma-noncoherency support
+
+To support DMA device in a non-coherent interconnect SOC system,
+we need the below facilities:
+ - Changing a virtual memory mapping region attributes from
+   cacheable to noncache + strong order which used in DMA
+   descriptors.
+ - Add noncache + weakorder virtual memory attributes for dma
+   mapping.
+ - Syncing the cache with memory before DMA start and after DMA
+   end with vendor custom CMO instructions.
+
+This patch enables linux kernel generic dma-noncoherency
+infrastructure and introduces new sbi_ecall API for dma_sync.
+
+@@ -27,6 +27,7 @@ enum sbi_ext_id {
++       SBI_EXT_DMA = 0xAB150401,
+
+Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
+Signed-off-by: Liu Shaohua <liush@allwinnertech.com>
+Cc: Palmer Dabbelt <palmerdabbelt@google.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Anup Patel <anup.patel@wdc.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Drew Fustini <drew@beagleboard.org>
+Cc: Wei Fu <wefu@redhat.com>
+Cc: Wei Wu <lazyparser@gmail.com>
+Cc: Chen-Yu Tsai <wens@csie.org>
+Cc: Maxime Ripard <maxime@cerno.tech>
+---
+ arch/riscv/Kconfig               |  5 +++
+ arch/riscv/include/asm/pgtable.h | 26 ++++++++++++++++
+ arch/riscv/include/asm/sbi.h     | 22 +++++++++++++
+ arch/riscv/kernel/sbi.c          | 19 ++++++++++++
+ arch/riscv/mm/Makefile           |  1 +
+ arch/riscv/mm/dma-mapping.c      | 53 ++++++++++++++++++++++++++++++++
+ 6 files changed, 126 insertions(+)
+ create mode 100644 arch/riscv/mm/dma-mapping.c
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index 7e907aa32ac8..fb462acf769b 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -18,6 +18,10 @@ config RISCV
+       select ARCH_HAS_DEBUG_VM_PGTABLE
+       select ARCH_HAS_DEBUG_VIRTUAL if MMU
+       select ARCH_HAS_DEBUG_WX
++      select ARCH_HAS_DMA_PREP_COHERENT
++      select ARCH_HAS_SYNC_DMA_FOR_CPU
++      select ARCH_HAS_SYNC_DMA_FOR_DEVICE
++      select ARCH_HAS_DMA_WRITE_COMBINE
+       select ARCH_HAS_FORTIFY_SOURCE
+       select ARCH_HAS_GCOV_PROFILE_ALL
+       select ARCH_HAS_GIGANTIC_PAGE
+@@ -47,6 +51,7 @@ config RISCV
+       select CLINT_TIMER if !MMU
+       select COMMON_CLK
+       select CPU_PM if CPU_IDLE
++      select DMA_DIRECT_REMAP
+       select EDAC_SUPPORT
+       select GENERIC_ARCH_TOPOLOGY if SMP
+       select GENERIC_ATOMIC64 if !64BIT
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index cb24ca059442..7f7047a32a82 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -489,6 +489,32 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
+       return ptep_test_and_clear_young(vma, address, ptep);
+ }
++#define pgprot_noncached pgprot_noncached
++static inline pgprot_t pgprot_noncached(pgprot_t _prot)
++{
++      unsigned long prot = pgprot_val(_prot);
++
++      prot &= ~_PAGE_DMA_MASK;
++      prot |= _PAGE_DMA_IO;
++
++      return __pgprot(prot);
++}
++
++#define pgprot_writecombine pgprot_writecombine
++static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
++{
++      unsigned long prot = pgprot_val(_prot);
++
++      prot &= ~_PAGE_DMA_MASK;
++      prot |= _PAGE_DMA_WC;
++
++      return __pgprot(prot);
++}
++
++#define __HAVE_PHYS_MEM_ACCESS_PROT
++extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
++                                   unsigned long size, pgprot_t vma_prot);
++
+ /*
+  * THP functions
+  */
+diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
+index ff5cecd13bda..9d4398595714 100644
+--- a/arch/riscv/include/asm/sbi.h
++++ b/arch/riscv/include/asm/sbi.h
+@@ -28,6 +28,7 @@ enum sbi_ext_id {
+       SBI_EXT_RFENCE = 0x52464E43,
+       SBI_EXT_HSM = 0x48534D,
+       SBI_EXT_SRST = 0x53525354,
++      SBI_EXT_DMA = 0xAB150401,
+ };
+ enum sbi_ext_base_fid {
+@@ -103,6 +104,24 @@ enum sbi_srst_reset_reason {
+       SBI_SRST_RESET_REASON_SYS_FAILURE,
+ };
++enum sbi_ext_dma_fid {
++      SBI_DMA_SYNC = 0,
++};
++
++enum sbi_dma_sync_data_direction {
++      SBI_DMA_BIDIRECTIONAL = 0,
++      SBI_DMA_TO_DEVICE = 1,
++      SBI_DMA_FROM_DEVICE = 2,
++      SBI_DMA_NONE = 3,
++};
++
++enum sbi_hsm_hart_status {
++      SBI_HSM_HART_STATUS_STARTED = 0,
++      SBI_HSM_HART_STATUS_STOPPED,
++      SBI_HSM_HART_STATUS_START_PENDING,
++      SBI_HSM_HART_STATUS_STOP_PENDING,
++};
++
+ #define SBI_SPEC_VERSION_DEFAULT      0x1
+ #define SBI_SPEC_VERSION_MAJOR_SHIFT  24
+ #define SBI_SPEC_VERSION_MAJOR_MASK   0x7f
+@@ -162,6 +181,9 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
+                               unsigned long size,
+                               unsigned long asid);
+ int sbi_probe_extension(int ext);
++void sbi_dma_sync(unsigned long start,
++                unsigned long size,
++                enum sbi_dma_sync_data_direction dir);
+ /* Check if current SBI specification version is 0.1 or not */
+ static inline int sbi_spec_is_0_1(void)
+diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
+index 372aa7e181d5..4daea631c078 100644
+--- a/arch/riscv/kernel/sbi.c
++++ b/arch/riscv/kernel/sbi.c
+@@ -548,6 +548,25 @@ int sbi_probe_extension(int extid)
+ }
+ EXPORT_SYMBOL(sbi_probe_extension);
++void sbi_dma_sync(unsigned long start,
++                unsigned long size,
++                enum sbi_dma_sync_data_direction dir)
++{
++#if 0
++      sbi_ecall(SBI_EXT_DMA, SBI_DMA_SYNC, start, size, dir,
++                0, 0, 0);
++#else
++      /* Just for try, it should be in sbi ecall and will be removed before merged */
++      register unsigned long i asm("a0") = start & ~(L1_CACHE_BYTES - 1);
++
++      for (; i < ALIGN(start + size, L1_CACHE_BYTES); i += L1_CACHE_BYTES)
++              __asm__ __volatile__(".long 0x02b5000b");
++
++      __asm__ __volatile__(".long 0x01b0000b");
++#endif
++}
++EXPORT_SYMBOL(sbi_dma_sync);
++
+ static long __sbi_base_ecall(int fid)
+ {
+       struct sbiret ret;
+diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile
+index 7ebaef10ea1b..ca0ff9064953 100644
+--- a/arch/riscv/mm/Makefile
++++ b/arch/riscv/mm/Makefile
+@@ -13,6 +13,7 @@ obj-y += extable.o
+ obj-$(CONFIG_MMU) += fault.o pageattr.o
+ obj-y += cacheflush.o
+ obj-y += context.o
++obj-y += dma-mapping.o
+ ifeq ($(CONFIG_MMU),y)
+ obj-$(CONFIG_SMP) += tlbflush.o
+diff --git a/arch/riscv/mm/dma-mapping.c b/arch/riscv/mm/dma-mapping.c
+new file mode 100644
+index 000000000000..4afd9dc32618
+--- /dev/null
++++ b/arch/riscv/mm/dma-mapping.c
+@@ -0,0 +1,53 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/dma-map-ops.h>
++#include <asm/sbi.h>
++
++void arch_dma_prep_coherent(struct page *page, size_t size)
++{
++      void *ptr = page_address(page);
++
++      memset(ptr, 0, size);
++      sbi_dma_sync(page_to_phys(page), size, SBI_DMA_BIDIRECTIONAL);
++}
++
++void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
++              enum dma_data_direction dir)
++{
++      switch (dir) {
++      case DMA_TO_DEVICE:
++      case DMA_FROM_DEVICE:
++      case DMA_BIDIRECTIONAL:
++              sbi_dma_sync(paddr, size, dir);
++              break;
++      default:
++              BUG();
++      }
++}
++
++void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
++              enum dma_data_direction dir)
++{
++      switch (dir) {
++      case DMA_TO_DEVICE:
++              return;
++      case DMA_FROM_DEVICE:
++      case DMA_BIDIRECTIONAL:
++              sbi_dma_sync(paddr, size, dir);
++              break;
++      default:
++              BUG();
++      }
++}
++
++pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
++                            unsigned long size, pgprot_t vma_prot)
++{
++      if (!pfn_valid(pfn))
++              return pgprot_noncached(vma_prot);
++      else if (file->f_flags & O_SYNC)
++              return pgprot_writecombine(vma_prot);
++
++      return vma_prot;
++}
++EXPORT_SYMBOL(phys_mem_access_prot);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0067-riscv-cmo-Add-vendor-custom-icache-sync.patch b/target/linux/sunxid1/patches-5.15/0067-riscv-cmo-Add-vendor-custom-icache-sync.patch
new file mode 100644 (file)
index 0000000..b4a94db
--- /dev/null
@@ -0,0 +1,182 @@
+From 23c539154e9c3ef77bfa17398121eaa3ef26eee5 Mon Sep 17 00:00:00 2001
+From: Guo Ren <guoren@linux.alibaba.com>
+Date: Sun, 6 Jun 2021 09:04:06 +0000
+Subject: [PATCH 067/124] riscv: cmo: Add vendor custom icache sync
+
+It's a draft version to show you how T-HEAD C9xx work with the
+icache sync (We use hardware broadcast mechanism, and our icache
+is VIPT):
+ - icache.i(v/p)a will broadcast all harts' icache invalidtion
+ - sync.is will broadcast all harts' pipeline flush and ensure all
+   broadcasts finished.
+
+This patch could improve the performance of OpenJDK on JIT and
+reduce flush_icache_all in linux.
+
+Epecially:
+static inline void set_pte_at(struct mm_struct *mm,
+        unsigned long addr, pte_t *ptep, pte_t pteval)
+{
+       if (pte_present(pteval) && pte_exec(pteval))
+               flush_icache_pte(pteval);
+
+       set_pte(ptep, pteval);
+}
+
+Different from sbi_dma_sync, it can't be hidden in SBI and we must
+set up a framework to hold all vendors' implementations in
+linux/arch/riscv.
+
+Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
+Signed-off-by: Liu Shaohua <liush@allwinnertech.com>
+Cc: Anup Patel <anup.patel@wdc.com>
+Cc: Atish Patra <atish.patra@wdc.com>
+Cc: Palmer Dabbelt <palmerdabbelt@google.com>
+Cc: Chen-Yu Tsai <wens@csie.org>
+Cc: Drew Fustini <drew@beagleboard.org>
+Cc: Maxime Ripard <maxime@cerno.tech>
+Cc: Palmer Dabbelt <palmerdabbelt@google.com>
+Cc: Wei Fu <wefu@redhat.com>
+Cc: Wei Wu <lazyparser@gmail.com>
+---
+ arch/riscv/include/asm/cacheflush.h   | 48 ++++++++++++++++++++++++++-
+ arch/riscv/kernel/vdso/flush_icache.S | 33 ++++++++++++++----
+ arch/riscv/mm/cacheflush.c            |  3 +-
+ 3 files changed, 76 insertions(+), 8 deletions(-)
+
+diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h
+index 23ff70350992..2e2dba17084d 100644
+--- a/arch/riscv/include/asm/cacheflush.h
++++ b/arch/riscv/include/asm/cacheflush.h
+@@ -22,11 +22,57 @@ static inline void flush_dcache_page(struct page *page)
+ }
+ #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
++#define ICACHE_IPA_X5   ".long 0x0382800b"
++#define ICACHE_IVA_X5   ".long 0x0302800b"
++#define SYNC_IS         ".long 0x01b0000b"
++
++static inline void flush_icache_range(unsigned long start, unsigned long end)
++{
++      register unsigned long tmp asm("x5") = start & (~(L1_CACHE_BYTES-1));
++
++      for (; tmp < ALIGN(end, L1_CACHE_BYTES); tmp += L1_CACHE_BYTES) {
++              __asm__ __volatile__ (
++                              ICACHE_IVA_X5
++                              :
++                              : "r" (tmp)
++                              : "memory");
++      }
++
++      __asm__ __volatile__(SYNC_IS);
++
++      return;
++}
++
++static inline void flush_icache_range_phy(unsigned long start, unsigned long end)
++{
++      register unsigned long tmp asm("x5") = start & (~(L1_CACHE_BYTES-1));
++
++      for (; tmp < ALIGN(end, L1_CACHE_BYTES); tmp += L1_CACHE_BYTES) {
++              __asm__ __volatile__ (
++                              ICACHE_IPA_X5
++                              :
++                              : "r" (tmp)
++                              : "memory");
++      }
++
++      __asm__ __volatile__(SYNC_IS);
++
++      return;
++}
++
++static inline void __flush_icache_page(struct page *page) {
++      unsigned long start = PFN_PHYS(page_to_pfn(page));
++
++      flush_icache_range_phy(start, start + PAGE_SIZE);
++
++      return;
++}
++
+ /*
+  * RISC-V doesn't have an instruction to flush parts of the instruction cache,
+  * so instead we just flush the whole thing.
+  */
+-#define flush_icache_range(start, end) flush_icache_all()
++#define flush_icache_range(start, end) flush_icache_range(start, end)
+ #define flush_icache_user_page(vma, pg, addr, len) \
+       flush_icache_mm(vma->vm_mm, 0)
+diff --git a/arch/riscv/kernel/vdso/flush_icache.S b/arch/riscv/kernel/vdso/flush_icache.S
+index 82f97d67c23e..efb2d2e8a768 100644
+--- a/arch/riscv/kernel/vdso/flush_icache.S
++++ b/arch/riscv/kernel/vdso/flush_icache.S
+@@ -5,18 +5,39 @@
+ #include <linux/linkage.h>
+ #include <asm/unistd.h>
++#include <asm/cache.h>
++
++/*
++ * icache.ipa rs1
++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
++ *   0000001    11000      rs1       000      00000  0001011
++ *
++ * icache.iva rs1
++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
++ *   0000001    10000      rs1       000      00000  0001011
++ *
++ * sync.is
++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
++ *   0000000    11011     00000      000      00000  0001011
++ */
++#define ICACHE_IPA_X5 .long 0x0382800b
++#define ICACHE_IVA_X5 .long 0x0302800b
++#define SYNC_IS               .long 0x01b0000b
+       .text
+ /* int __vdso_flush_icache(void *start, void *end, unsigned long flags); */
+ ENTRY(__vdso_flush_icache)
+       .cfi_startproc
+-#ifdef CONFIG_SMP
+-      li a7, __NR_riscv_flush_icache
+-      ecall
+-#else
+-      fence.i
++      srli    t0, a0, L1_CACHE_SHIFT
++      slli    t0, t0, L1_CACHE_SHIFT
++      addi    a1, a1, (L1_CACHE_BYTES - 1)
++      srli    a1, a1, L1_CACHE_SHIFT
++      slli    a1, a1, L1_CACHE_SHIFT
++1:    ICACHE_IVA_X5
++      addi    t0, t0, L1_CACHE_BYTES
++      bne     t0, a1, 1b
++      SYNC_IS
+       li a0, 0
+-#endif
+       ret
+       .cfi_endproc
+ ENDPROC(__vdso_flush_icache)
+diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c
+index 89f81067e09e..9d2e5fa9d0e0 100644
+--- a/arch/riscv/mm/cacheflush.c
++++ b/arch/riscv/mm/cacheflush.c
+@@ -3,6 +3,7 @@
+  * Copyright (C) 2017 SiFive
+  */
++#include <linux/pfn.h>
+ #include <asm/cacheflush.h>
+ #ifdef CONFIG_SMP
+@@ -86,6 +87,6 @@ void flush_icache_pte(pte_t pte)
+       struct page *page = pte_page(pte);
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+-              flush_icache_all();
++              __flush_icache_page(page);
+ }
+ #endif /* CONFIG_MMU */
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0068-fixed-UB-which-lead-to-cache-coherence-bug.patch b/target/linux/sunxid1/patches-5.15/0068-fixed-UB-which-lead-to-cache-coherence-bug.patch
new file mode 100644 (file)
index 0000000..54b35a5
--- /dev/null
@@ -0,0 +1,25 @@
+From 933ba1cb66d124454889c8c2b844fee2b0e0960b Mon Sep 17 00:00:00 2001
+From: Yangyu Chen <cyy@cyyself.name>
+Date: Tue, 26 Oct 2021 15:40:38 +0800
+Subject: [PATCH 068/124] fixed UB which lead to cache coherence bug
+
+---
+ arch/riscv/kernel/sbi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
+index 4daea631c078..77132e824954 100644
+--- a/arch/riscv/kernel/sbi.c
++++ b/arch/riscv/kernel/sbi.c
+@@ -560,7 +560,7 @@ void sbi_dma_sync(unsigned long start,
+       register unsigned long i asm("a0") = start & ~(L1_CACHE_BYTES - 1);
+       for (; i < ALIGN(start + size, L1_CACHE_BYTES); i += L1_CACHE_BYTES)
+-              __asm__ __volatile__(".long 0x02b5000b");
++              __asm__ __volatile__(".long 0x02b5000b" : : "r"(i));
+       __asm__ __volatile__(".long 0x01b0000b");
+ #endif
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0069-Enable-T-HEAD-MMU-extensions-unconditionally.patch b/target/linux/sunxid1/patches-5.15/0069-Enable-T-HEAD-MMU-extensions-unconditionally.patch
new file mode 100644 (file)
index 0000000..83fa0c2
--- /dev/null
@@ -0,0 +1,26 @@
+From c35eeb146ba1a615b686951a6a89794ee5682148 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 14:17:30 -0500
+Subject: [PATCH 069/124] Enable T-HEAD MMU extensions unconditionally
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/kernel/soc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c
+index 05fa76467e69..8c9f33f921b4 100644
+--- a/arch/riscv/kernel/soc.c
++++ b/arch/riscv/kernel/soc.c
+@@ -44,6 +44,8 @@ void __init soc_setup_vm(void)
+       switch (vendor_id) {
+       case THEAD_VENDOR_ID:
++      // Do not rely on the bootloader...
++      default:
+               thead_init();
+               break;
+       }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0070-riscv-Allow-suspend.patch b/target/linux/sunxid1/patches-5.15/0070-riscv-Allow-suspend.patch
new file mode 100644 (file)
index 0000000..ab4d259
--- /dev/null
@@ -0,0 +1,27 @@
+From 8255fd9e0ea6e7c0d621f401fc6fbc7fdfc73ab2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 15 Nov 2021 23:38:00 -0600
+Subject: [PATCH 070/124] riscv: Allow suspend
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/Kconfig | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index fb462acf769b..2d996d6f4265 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -194,6 +194,9 @@ config ARCH_WANT_GENERAL_HUGETLB
+ config ARCH_SUPPORTS_UPROBES
+       def_bool y
++config ARCH_SUSPEND_POSSIBLE
++      def_bool y
++
+ config STACKTRACE_SUPPORT
+       def_bool y
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0071-riscv-cacheinfo-Remind-myself-to-fix-this.patch b/target/linux/sunxid1/patches-5.15/0071-riscv-cacheinfo-Remind-myself-to-fix-this.patch
new file mode 100644 (file)
index 0000000..0ccfe3e
--- /dev/null
@@ -0,0 +1,25 @@
+From 751def916449fd13685e28c913032c51266b6d10 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 21:46:50 -0500
+Subject: [PATCH 071/124] riscv: cacheinfo: Remind myself to fix this
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/kernel/cacheinfo.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/riscv/kernel/cacheinfo.c b/arch/riscv/kernel/cacheinfo.c
+index 90deabfe63ea..a1874a68a17e 100644
+--- a/arch/riscv/kernel/cacheinfo.c
++++ b/arch/riscv/kernel/cacheinfo.c
+@@ -94,6 +94,7 @@ static void fill_cacheinfo(struct cacheinfo **this_leaf,
+ {
+       unsigned int size, sets, line_size;
++      /* Buggy: may not init leaves, but num_leaves was set below. */
+       if (!of_property_read_u32(node, "cache-size", &size) &&
+           !of_property_read_u32(node, "cache-block-size", &line_size) &&
+           !of_property_read_u32(node, "cache-sets", &sets)) {
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0072-clocksource-riscv-Prefer-it-over-MMIO-clocksources.patch b/target/linux/sunxid1/patches-5.15/0072-clocksource-riscv-Prefer-it-over-MMIO-clocksources.patch
new file mode 100644 (file)
index 0000000..95be929
--- /dev/null
@@ -0,0 +1,26 @@
+From bab6179fa6b0f3f819968c4034c1517283eb3dc7 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:54:21 -0500
+Subject: [PATCH 072/124] clocksource: riscv: Prefer it over MMIO clocksources
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clocksource/timer-riscv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
+index c51c5ed15aa7..a035bdf6fc58 100644
+--- a/drivers/clocksource/timer-riscv.c
++++ b/drivers/clocksource/timer-riscv.c
+@@ -54,7 +54,7 @@ static u64 notrace riscv_sched_clock(void)
+ static struct clocksource riscv_clocksource = {
+       .name           = "riscv_clocksource",
+-      .rating         = 300,
++      .rating         = 400,
+       .mask           = CLOCKSOURCE_MASK(64),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .read           = riscv_clocksource_rdtime,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0073-riscv-Enable-cpufreq.patch b/target/linux/sunxid1/patches-5.15/0073-riscv-Enable-cpufreq.patch
new file mode 100644 (file)
index 0000000..7828276
--- /dev/null
@@ -0,0 +1,26 @@
+From 71f14616158d3a2bc1ffb726b05d4aa6bec0f459 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 15:02:27 -0500
+Subject: [PATCH 073/124] riscv: Enable cpufreq
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/Kconfig | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index 2d996d6f4265..5f11f14f93a8 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -583,6 +583,8 @@ endmenu
+ menu "CPU Power Management"
++source "drivers/cpufreq/Kconfig"
++
+ source "drivers/cpuidle/Kconfig"
+ endmenu
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0074-cpufreq-sun50i-add-efuse_xlate-to-get-efuse-version.patch b/target/linux/sunxid1/patches-5.15/0074-cpufreq-sun50i-add-efuse_xlate-to-get-efuse-version.patch
new file mode 100644 (file)
index 0000000..8b48626
--- /dev/null
@@ -0,0 +1,162 @@
+From 48836972991b23a270f5505e1ee42de7466ac9c1 Mon Sep 17 00:00:00 2001
+From: Shuosheng Huang <huangshuosheng@allwinnertech.com>
+Date: Tue, 8 Dec 2020 15:19:28 +0800
+Subject: [PATCH 074/124] cpufreq: sun50i: add efuse_xlate to get efuse
+ version.
+
+It's better to use efuse_xlate to extract the differentiated part
+regarding different SoC.
+
+Signed-off-by: Shuosheng Huang <huangshuosheng@allwinnertech.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/cpufreq/sun50i-cpufreq-nvmem.c | 84 ++++++++++++++++----------
+ 1 file changed, 52 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+index 2deed8d8773f..e29ada03873d 100644
+--- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c
++++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+@@ -19,24 +19,51 @@
+ #define MAX_NAME_LEN  7
+-#define NVMEM_MASK    0x7
+-#define NVMEM_SHIFT   5
++#define SUN50I_H6_NVMEM_MASK          0x7
++#define SUN50I_H6_NVMEM_SHIFT         5
++
++struct sunxi_cpufreq_soc_data {
++      int (*efuse_xlate)(struct nvmem_cell *speedbin_nvmem);
++};
+ static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
++static int sun50i_h6_efuse_xlate(struct nvmem_cell *speedbin_nvmem)
++{
++      size_t len;
++      u32 *speedbin;
++      u32 efuse_value;
++
++      speedbin = nvmem_cell_read(speedbin_nvmem, &len);
++      if (IS_ERR(speedbin))
++              return PTR_ERR(speedbin);
++
++      efuse_value = (*speedbin >> SUN50I_H6_NVMEM_SHIFT) & SUN50I_H6_NVMEM_MASK;
++      kfree(speedbin);
++
++      /*
++       * We treat unexpected efuse values as if the SoC was from
++       * the slowest bin. Expected efuse values are 1-3, slowest
++       * to fastest.
++       */
++      if (efuse_value >= 1 && efuse_value <= 3)
++              return efuse_value - 1;
++      else
++              return 0;
++}
++
+ /**
+  * sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value
+- * @versions: Set to the value parsed from efuse
++ * @soc_data: pointer to sunxi_cpufreq_soc_data context
+  *
+- * Returns 0 if success.
++ * Returns speed grade (OPP voltage index) if successful.
+  */
+-static int sun50i_cpufreq_get_efuse(u32 *versions)
++static int sun50i_cpufreq_get_efuse(const struct sunxi_cpufreq_soc_data *soc_data)
+ {
+       struct nvmem_cell *speedbin_nvmem;
+       struct device_node *np;
+       struct device *cpu_dev;
+-      u32 *speedbin, efuse_value;
+-      size_t len;
++      int speed;
+       int ret;
+       cpu_dev = get_cpu_device(0);
+@@ -63,43 +90,33 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
+               return PTR_ERR(speedbin_nvmem);
+       }
+-      speedbin = nvmem_cell_read(speedbin_nvmem, &len);
++      speed = soc_data->efuse_xlate(speedbin_nvmem);
+       nvmem_cell_put(speedbin_nvmem);
+-      if (IS_ERR(speedbin))
+-              return PTR_ERR(speedbin);
+-
+-      efuse_value = (*speedbin >> NVMEM_SHIFT) & NVMEM_MASK;
+-      /*
+-       * We treat unexpected efuse values as if the SoC was from
+-       * the slowest bin. Expected efuse values are 1-3, slowest
+-       * to fastest.
+-       */
+-      if (efuse_value >= 1 && efuse_value <= 3)
+-              *versions = efuse_value - 1;
+-      else
+-              *versions = 0;
+-
+-      kfree(speedbin);
+-      return 0;
++      return speed;
+ };
+ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
+ {
++      const struct of_device_id *match;
+       struct opp_table **opp_tables;
+       char name[MAX_NAME_LEN];
+       unsigned int cpu;
+-      u32 speed = 0;
++      int speed = 0;
+       int ret;
++      match = dev_get_platdata(&pdev->dev);
++      if (!match)
++              return -EINVAL;
++
+       opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables),
+                            GFP_KERNEL);
+       if (!opp_tables)
+               return -ENOMEM;
+-      ret = sun50i_cpufreq_get_efuse(&speed);
+-      if (ret)
+-              return ret;
++      speed = sun50i_cpufreq_get_efuse(match->data);
++      if (speed < 0)
++              return speed;
+       snprintf(name, MAX_NAME_LEN, "speed%d", speed);
+@@ -163,8 +180,12 @@ static struct platform_driver sun50i_cpufreq_driver = {
+       },
+ };
++static const struct sunxi_cpufreq_soc_data sun50i_h6_data = {
++      .efuse_xlate = sun50i_h6_efuse_xlate,
++};
++
+ static const struct of_device_id sun50i_cpufreq_match_list[] = {
+-      { .compatible = "allwinner,sun50i-h6" },
++      { .compatible = "allwinner,sun50i-h6", .data = &sun50i_h6_data },
+       {}
+ };
+ MODULE_DEVICE_TABLE(of, sun50i_cpufreq_match_list);
+@@ -199,9 +220,8 @@ static int __init sun50i_cpufreq_init(void)
+       if (unlikely(ret < 0))
+               return ret;
+-      sun50i_cpufreq_pdev =
+-              platform_device_register_simple("sun50i-cpufreq-nvmem",
+-                                              -1, NULL, 0);
++      sun50i_cpufreq_pdev = platform_device_register_data(NULL,
++              "sun50i-cpufreq-nvmem", -1, match, sizeof(*match));
+       ret = PTR_ERR_OR_ZERO(sun50i_cpufreq_pdev);
+       if (ret == 0)
+               return 0;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0075-cpufreq-sun50i-add-A100-cpufreq-support.patch b/target/linux/sunxid1/patches-5.15/0075-cpufreq-sun50i-add-A100-cpufreq-support.patch
new file mode 100644 (file)
index 0000000..e11c2a9
--- /dev/null
@@ -0,0 +1,90 @@
+From cd8725b4b8e7f00a06c5256162d499dff50ec3b8 Mon Sep 17 00:00:00 2001
+From: Shuosheng Huang <huangshuosheng@allwinnertech.com>
+Date: Tue, 8 Dec 2020 15:19:53 +0800
+Subject: [PATCH 075/124] cpufreq: sun50i: add A100 cpufreq support
+
+Add nvmem based cpufreq for Allwinner A100 SoC, which is similar to H6.
+
+Signed-off-by: Shuosheng Huang <huangshuosheng@allwinnertech.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/cpufreq/cpufreq-dt-platdev.c   |  1 +
+ drivers/cpufreq/sun50i-cpufreq-nvmem.c | 31 ++++++++++++++++++++++++++
+ 2 files changed, 32 insertions(+)
+
+diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
+index ca1d103ec449..b85fe43d0257 100644
+--- a/drivers/cpufreq/cpufreq-dt-platdev.c
++++ b/drivers/cpufreq/cpufreq-dt-platdev.c
+@@ -101,6 +101,7 @@ static const struct of_device_id allowlist[] __initconst = {
+  * platforms using "operating-points-v2" property.
+  */
+ static const struct of_device_id blocklist[] __initconst = {
++      { .compatible = "allwinner,sun50i-a100", },
+       { .compatible = "allwinner,sun50i-h6", },
+       { .compatible = "arm,vexpress", },
+diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+index e29ada03873d..3534133c3c9c 100644
+--- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c
++++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+@@ -19,6 +19,9 @@
+ #define MAX_NAME_LEN  7
++#define SUN50I_A100_NVMEM_MASK                0xf
++#define SUN50I_A100_NVMEM_SHIFT               12
++
+ #define SUN50I_H6_NVMEM_MASK          0x7
+ #define SUN50I_H6_NVMEM_SHIFT         5
+@@ -28,6 +31,29 @@ struct sunxi_cpufreq_soc_data {
+ static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
++static int sun50i_a100_efuse_xlate(struct nvmem_cell *speedbin_nvmem)
++{
++      size_t len;
++      u16 *speedbin;
++      u16 efuse_value;
++
++      speedbin = nvmem_cell_read(speedbin_nvmem, &len);
++      if (IS_ERR(speedbin))
++              return PTR_ERR(speedbin);
++
++      efuse_value = (*speedbin >> SUN50I_A100_NVMEM_SHIFT) & SUN50I_A100_NVMEM_MASK;
++      kfree(speedbin);
++
++      switch (efuse_value) {
++      case 0b100:
++              return 2;
++      case 0b010:
++              return 1;
++      default:
++              return 0;
++      }
++}
++
+ static int sun50i_h6_efuse_xlate(struct nvmem_cell *speedbin_nvmem)
+ {
+       size_t len;
+@@ -180,11 +206,16 @@ static struct platform_driver sun50i_cpufreq_driver = {
+       },
+ };
++static const struct sunxi_cpufreq_soc_data sun50i_a100_data = {
++      .efuse_xlate = sun50i_a100_efuse_xlate,
++};
++
+ static const struct sunxi_cpufreq_soc_data sun50i_h6_data = {
+       .efuse_xlate = sun50i_h6_efuse_xlate,
+ };
+ static const struct of_device_id sun50i_cpufreq_match_list[] = {
++      { .compatible = "allwinner,sun50i-a100", .data = &sun50i_a100_data },
+       { .compatible = "allwinner,sun50i-h6", .data = &sun50i_h6_data },
+       {}
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0076-cpufreq-sun50i-Move-out-of-ARM-specific-section.patch b/target/linux/sunxid1/patches-5.15/0076-cpufreq-sun50i-Move-out-of-ARM-specific-section.patch
new file mode 100644 (file)
index 0000000..820736f
--- /dev/null
@@ -0,0 +1,98 @@
+From d1645eeec1f5361067b04213ffc9ab5ae6ba773b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 21:18:52 -0500
+Subject: [PATCH 076/124] cpufreq: sun50i: Move out of ARM-specific section
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm64/configs/defconfig |  2 +-
+ drivers/cpufreq/Kconfig      | 12 ++++++++++++
+ drivers/cpufreq/Kconfig.arm  | 12 ------------
+ drivers/cpufreq/Makefile     |  2 +-
+ 4 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
+index 545197bc0501..7a5a8bfd654c 100644
+--- a/arch/arm64/configs/defconfig
++++ b/arch/arm64/configs/defconfig
+@@ -90,7 +90,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+ CONFIG_CPUFREQ_DT=y
+ CONFIG_ACPI_CPPC_CPUFREQ=m
+-CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM=m
+ CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
+ CONFIG_ARM_SCPI_CPUFREQ=y
+ CONFIG_ARM_IMX_CPUFREQ_DT=m
+@@ -100,6 +99,7 @@ CONFIG_ARM_RASPBERRYPI_CPUFREQ=m
+ CONFIG_ARM_SCMI_CPUFREQ=y
+ CONFIG_ARM_TEGRA186_CPUFREQ=y
+ CONFIG_QORIQ_CPUFREQ=y
++CONFIG_SUN50I_CPUFREQ_NVMEM=m
+ CONFIG_ARM_SCMI_PROTOCOL=y
+ CONFIG_ARM_SCPI_PROTOCOL=y
+ CONFIG_RASPBERRYPI_FIRMWARE=y
+diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
+index c3038cdc6865..3f98b0603c0c 100644
+--- a/drivers/cpufreq/Kconfig
++++ b/drivers/cpufreq/Kconfig
+@@ -321,5 +321,17 @@ config QORIQ_CPUFREQ
+         This adds the CPUFreq driver support for Freescale QorIQ SoCs
+         which are capable of changing the CPU's frequency dynamically.
++config SUN50I_CPUFREQ_NVMEM
++      tristate "Allwinner nvmem based SUN50I CPUFreq driver"
++      depends on ARCH_SUNXI || COMPILE_TEST
++      depends on NVMEM_SUNXI_SID
++      select PM_OPP
++      help
++        This adds the nvmem based CPUFreq driver for Allwinner
++        sun20i/sun50i SoCs.
++
++        To compile this driver as a module, choose M here: the
++        module will be called sun50i-cpufreq-nvmem.
++
+ endif
+ endmenu
+diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
+index 954749afb5fe..6b0aca5e0e2b 100644
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -29,18 +29,6 @@ config ACPI_CPPC_CPUFREQ_FIE
+         If in doubt, say N.
+-config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
+-      tristate "Allwinner nvmem based SUN50I CPUFreq driver"
+-      depends on ARCH_SUNXI
+-      depends on NVMEM_SUNXI_SID
+-      select PM_OPP
+-      help
+-        This adds the nvmem based CPUFreq driver for Allwinner
+-        h6 SoC.
+-
+-        To compile this driver as a module, choose M here: the
+-        module will be called sun50i-cpufreq-nvmem.
+-
+ config ARM_ARMADA_37XX_CPUFREQ
+       tristate "Armada 37xx CPUFreq support"
+       depends on ARCH_MVEBU && CPUFREQ_DT
+diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
+index 48ee5859030c..61c80e5bd02f 100644
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -78,7 +78,6 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ)               += scmi-cpufreq.o
+ obj-$(CONFIG_ARM_SCPI_CPUFREQ)                += scpi-cpufreq.o
+ obj-$(CONFIG_ARM_SPEAR_CPUFREQ)               += spear-cpufreq.o
+ obj-$(CONFIG_ARM_STI_CPUFREQ)         += sti-cpufreq.o
+-obj-$(CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM) += sun50i-cpufreq-nvmem.o
+ obj-$(CONFIG_ARM_TEGRA20_CPUFREQ)     += tegra20-cpufreq.o
+ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)    += tegra124-cpufreq.o
+ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ)    += tegra186-cpufreq.o
+@@ -108,3 +107,4 @@ obj-$(CONFIG_LOONGSON1_CPUFREQ)            += loongson1-cpufreq.o
+ obj-$(CONFIG_SH_CPU_FREQ)             += sh-cpufreq.o
+ obj-$(CONFIG_SPARC_US2E_CPUFREQ)      += sparc-us2e-cpufreq.o
+ obj-$(CONFIG_SPARC_US3_CPUFREQ)               += sparc-us3-cpufreq.o
++obj-$(CONFIG_SUN50I_CPUFREQ_NVMEM)    += sun50i-cpufreq-nvmem.o
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0077-cpufreq-sun50i-Add-D1-cpufreq-support.patch b/target/linux/sunxid1/patches-5.15/0077-cpufreq-sun50i-Add-D1-cpufreq-support.patch
new file mode 100644 (file)
index 0000000..769447e
--- /dev/null
@@ -0,0 +1,61 @@
+From 2b483c0072cc28b59bafa7fe9c4250b4f32dd5e0 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 22:10:05 -0500
+Subject: [PATCH 077/124] cpufreq: sun50i: Add D1 cpufreq support
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/cpufreq/cpufreq-dt-platdev.c   |  1 +
+ drivers/cpufreq/sun50i-cpufreq-nvmem.c | 10 ++++++++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
+index b85fe43d0257..d5f8f01f098d 100644
+--- a/drivers/cpufreq/cpufreq-dt-platdev.c
++++ b/drivers/cpufreq/cpufreq-dt-platdev.c
+@@ -101,6 +101,7 @@ static const struct of_device_id allowlist[] __initconst = {
+  * platforms using "operating-points-v2" property.
+  */
+ static const struct of_device_id blocklist[] __initconst = {
++      { .compatible = "allwinner,sun20i-d1", },
+       { .compatible = "allwinner,sun50i-a100", },
+       { .compatible = "allwinner,sun50i-h6", },
+diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+index 3534133c3c9c..7eaf91f0e5de 100644
+--- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c
++++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+@@ -31,6 +31,11 @@ struct sunxi_cpufreq_soc_data {
+ static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
++static int sun20i_d1_efuse_xlate(struct nvmem_cell *speedbin_nvmem)
++{
++      return 0;
++}
++
+ static int sun50i_a100_efuse_xlate(struct nvmem_cell *speedbin_nvmem)
+ {
+       size_t len;
+@@ -206,6 +211,10 @@ static struct platform_driver sun50i_cpufreq_driver = {
+       },
+ };
++static const struct sunxi_cpufreq_soc_data sun20i_d1_data = {
++      .efuse_xlate = sun20i_d1_efuse_xlate,
++};
++
+ static const struct sunxi_cpufreq_soc_data sun50i_a100_data = {
+       .efuse_xlate = sun50i_a100_efuse_xlate,
+ };
+@@ -215,6 +224,7 @@ static const struct sunxi_cpufreq_soc_data sun50i_h6_data = {
+ };
+ static const struct of_device_id sun50i_cpufreq_match_list[] = {
++      { .compatible = "allwinner,sun20i-d1", .data = &sun20i_d1_data },
+       { .compatible = "allwinner,sun50i-a100", .data = &sun50i_a100_data },
+       { .compatible = "allwinner,sun50i-h6", .data = &sun50i_h6_data },
+       {}
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0078-dmaengine-sun6i-Changes-from-BSP.patch b/target/linux/sunxid1/patches-5.15/0078-dmaengine-sun6i-Changes-from-BSP.patch
new file mode 100644 (file)
index 0000000..992e6a8
--- /dev/null
@@ -0,0 +1,59 @@
+From e3547799347f60c1b177406849bddec867fad343 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 14:51:23 -0500
+Subject: [PATCH 078/124] dmaengine: sun6i: Changes from BSP
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/dma/sun6i-dma.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
+index 795cce445532..0387a06c0774 100644
+--- a/drivers/dma/sun6i-dma.c
++++ b/drivers/dma/sun6i-dma.c
+@@ -938,6 +938,7 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
+       vchan_get_all_descriptors(&vchan->vc, &head);
+       if (pchan) {
++              writel(DMA_CHAN_PAUSE_PAUSE, pchan->base + DMA_CHAN_PAUSE);
+               writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE);
+               writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE);
+@@ -954,6 +955,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
+       return 0;
+ }
++static void sun6i_dma_synchronize(struct dma_chan *chan)
++{
++      struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
++
++      vchan_synchronize(&vchan->vc);
++}
++
+ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
+                                          dma_cookie_t cookie,
+                                          struct dma_tx_state *state)
+@@ -1357,6 +1365,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
+       sdc->slave.device_pause                 = sun6i_dma_pause;
+       sdc->slave.device_resume                = sun6i_dma_resume;
+       sdc->slave.device_terminate_all         = sun6i_dma_terminate_all;
++      sdc->slave.device_synchronize           = sun6i_dma_synchronize;
+       sdc->slave.src_addr_widths              = sdc->cfg->src_addr_widths;
+       sdc->slave.dst_addr_widths              = sdc->cfg->dst_addr_widths;
+       sdc->slave.directions                   = BIT(DMA_DEV_TO_MEM) |
+@@ -1415,9 +1424,9 @@ static int sun6i_dma_probe(struct platform_device *pdev)
+               vchan_init(&vchan->vc, &sdc->slave);
+       }
+-      ret = reset_control_deassert(sdc->rstc);
++      ret = reset_control_reset(sdc->rstc);
+       if (ret) {
+-              dev_err(&pdev->dev, "Couldn't deassert the device from reset\n");
++              dev_err(&pdev->dev, "Couldn't reset the device\n");
+               goto err_chan_free;
+       }
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0079-iommu-sun50i-Add-support-for-D1-IOMMU.patch b/target/linux/sunxid1/patches-5.15/0079-iommu-sun50i-Add-support-for-D1-IOMMU.patch
new file mode 100644 (file)
index 0000000..72aec64
--- /dev/null
@@ -0,0 +1,75 @@
+From c32597907fa4dfdbdf96424f930b6b288acc1ee0 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 10:21:00 -0500
+Subject: [PATCH 079/124] iommu/sun50i: Add support for D1 IOMMU
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/iommu/sun50i-iommu.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c
+index 92997021e188..ba8341f21478 100644
+--- a/drivers/iommu/sun50i-iommu.c
++++ b/drivers/iommu/sun50i-iommu.c
+@@ -47,15 +47,20 @@
+ #define IOMMU_TLB_FLUSH_MACRO_TLB             BIT(16)
+ #define IOMMU_TLB_FLUSH_MICRO_TLB(i)          (BIT(i) & GENMASK(5, 0))
++#define IOMMU_TLB_IVLD_MODE_SEL_REG   0x084
++#define IOMMU_TLB_IVLD_START_ADDR_REG 0x088
++#define IOMMU_TLB_IVLD_END_ADDR_REG   0x08c
+ #define IOMMU_TLB_IVLD_ADDR_REG               0x090
+ #define IOMMU_TLB_IVLD_ADDR_MASK_REG  0x094
+ #define IOMMU_TLB_IVLD_ENABLE_REG     0x098
+ #define IOMMU_TLB_IVLD_ENABLE_ENABLE          BIT(0)
+ #define IOMMU_PC_IVLD_ADDR_REG                0x0a0
++#define IOMMU_PC_IVLD_START_ADDR_REG  0x0a4
+ #define IOMMU_PC_IVLD_ENABLE_REG      0x0a8
+ #define IOMMU_PC_IVLD_ENABLE_ENABLE           BIT(0)
++#define IOMMU_PC_IVLD_END_ADDR_REG    0x0ac
+ #define IOMMU_DM_AUT_CTRL_REG(d)      (0x0b0 + ((d) / 2) * 4)
+ #define IOMMU_DM_AUT_CTRL_RD_UNAVAIL(d, m)    (1 << (((d & 1) * 16) + ((m) * 2)))
+ #define IOMMU_DM_AUT_CTRL_WR_UNAVAIL(d, m)    (1 << (((d & 1) * 16) + ((m) * 2) + 1))
+@@ -71,6 +76,19 @@
+ #define IOMMU_L1PG_INT_REG            0x0180
+ #define IOMMU_L2PG_INT_REG            0x0184
++#define IOMMU_VA_REG                  0x0190
++#define IOMMU_VA_DATA_REG             0x0194
++#define IOMMU_VA_CONFIG_REG           0x0198
++#define IOMMU_PMU_ENABLE_REG          0x0200
++#define IOMMU_PMU_CLR_REG             0x0210
++#define IOMMU_PMU_ACCESS_LOW_REG(i)   (0x230 + (i) * 16)
++#define IOMMU_PMU_ACCESS_HIGH_REG(i)  (0x234 + (i) * 16)
++#define IOMMU_PMU_HIT_LOW_REG(i)      (0x238 + (i) * 16)
++#define IOMMU_PMU_HIT_HIGH_REG(i)     (0x23c + (i) * 16)
++#define IOMMU_PMU_TL_LOW_REG(i)               (0x300 + (i) * 16)
++#define IOMMU_PMU_TL_HIGH_REG(i)      (0x304 + (i) * 16)
++#define IOMMU_PMU_ML_REG(i)           (0x308 + (i) * 16)
++
+ #define IOMMU_INT_INVALID_L2PG                        BIT(17)
+ #define IOMMU_INT_INVALID_L1PG                        BIT(16)
+ #define IOMMU_INT_MASTER_PERMISSION(m)                BIT(m)
+@@ -945,7 +963,7 @@ static int sun50i_iommu_probe(struct platform_device *pdev)
+               goto err_free_group;
+       }
+-      iommu->reset = devm_reset_control_get(&pdev->dev, NULL);
++      iommu->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(iommu->reset)) {
+               dev_err(&pdev->dev, "Couldn't get our reset line.\n");
+               ret = PTR_ERR(iommu->reset);
+@@ -986,6 +1004,7 @@ static int sun50i_iommu_probe(struct platform_device *pdev)
+ }
+ static const struct of_device_id sun50i_iommu_dt[] = {
++      { .compatible = "allwinner,sun20i-d1-iommu", },
+       { .compatible = "allwinner,sun50i-h6-iommu", },
+       { /* sentinel */ },
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0080-irqchip-sifive-plic-Add-T-HEAD-PLIC-compatible.patch b/target/linux/sunxid1/patches-5.15/0080-irqchip-sifive-plic-Add-T-HEAD-PLIC-compatible.patch
new file mode 100644 (file)
index 0000000..0ac7c2d
--- /dev/null
@@ -0,0 +1,22 @@
+From e18f604236129fd20868c53e5dc32f119e469be9 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 15 Nov 2021 23:37:02 -0600
+Subject: [PATCH 080/124] irqchip/sifive-plic: Add T-HEAD PLIC compatible
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/irqchip/irq-sifive-plic.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
+index cf74cfa82045..0397a3174aad 100644
+--- a/drivers/irqchip/irq-sifive-plic.c
++++ b/drivers/irqchip/irq-sifive-plic.c
+@@ -392,3 +392,4 @@ static int __init plic_init(struct device_node *node,
+ IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
+ IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
++IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0081-mailbox-Add-v2-mailbox.patch b/target/linux/sunxid1/patches-5.15/0081-mailbox-Add-v2-mailbox.patch
new file mode 100644 (file)
index 0000000..7feeecb
--- /dev/null
@@ -0,0 +1,145 @@
+From f0e764625b5bcfc260f74ede0a9d4ed497609211 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 17 May 2021 00:00:52 -0500
+Subject: [PATCH 081/124] mailbox: Add v2 mailbox
+
+---
+ .../mailbox/allwinner,sun20i-d1-msgbox.yaml   | 70 +++++++++++++++++++
+ drivers/mailbox/Kconfig                       | 13 +++-
+ .../dt-bindings/mailbox/sun20i-d1-msgbox.h    | 18 +++++
+ 3 files changed, 99 insertions(+), 2 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mailbox/allwinner,sun20i-d1-msgbox.yaml
+ create mode 100644 include/dt-bindings/mailbox/sun20i-d1-msgbox.h
+
+diff --git a/Documentation/devicetree/bindings/mailbox/allwinner,sun20i-d1-msgbox.yaml b/Documentation/devicetree/bindings/mailbox/allwinner,sun20i-d1-msgbox.yaml
+new file mode 100644
+index 000000000000..d61237dbbd33
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mailbox/allwinner,sun20i-d1-msgbox.yaml
+@@ -0,0 +1,70 @@
++# SPDX-License-Identifier: GPL-2.0
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mailbox/allwinner,sun20i-d1-msgbox.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Allwinner sunxi Message Box v2
++
++maintainers:
++  - Samuel Holland <samuel@sholland.org>
++
++properties:
++  compatible:
++    oneOf:
++      - const: allwinner,sun20i-d1-msgbox
++
++  reg:
++    maxItems: 1
++
++  clocks:
++    maxItems: 1
++    description: bus clock
++
++  resets:
++    maxItems: 1
++    description: bus reset
++
++  interrupts:
++    items:
++      - description: receive interrupt
++      - description: transmit interrupt
++
++  interrupt-names:
++    items:
++      - const: "rx"
++      - const: "tx"
++
++  '#mbox-cells':
++    const: 2
++    description: first cell is the user/channel number, second is direction
++
++required:
++  - compatible
++  - reg
++  - clocks
++  - resets
++  - interrupts
++  - interrupt-names
++  - '#mbox-cells'
++
++additionalProperties: false
++
++examples:
++  - |
++    #include <dt-bindings/clock/sun20i-d1-ccu.h>
++    #include <dt-bindings/interrupt-controller/irq.h>
++    #include <dt-bindings/reset/sun20i-d1-ccu.h>
++
++    msgbox: mailbox@3003000 {
++          compatible = "allwinner,sun20i-d1-msgbox";
++          reg = <0x3003000 0x1000>;
++          clocks = <&ccu CLK_BUS_MSGBOX0>;
++          resets = <&ccu RST_BUS_MSGBOX0>;
++          interrupts = <101 IRQ_TYPE_LEVEL_HIGH>,
++                       <102 IRQ_TYPE_LEVEL_HIGH>;
++          interrupt-names = "rx", "tx";
++          #mbox-cells = <2>;
++    };
++
++...
+diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
+index c9fc06c7e685..75adbdfe19cc 100644
+--- a/drivers/mailbox/Kconfig
++++ b/drivers/mailbox/Kconfig
+@@ -247,13 +247,22 @@ config ZYNQMP_IPI_MBOX
+         registers to kick the other processor or enquire status.
+ config SUN6I_MSGBOX
+-      tristate "Allwinner sun6i/sun8i/sun9i/sun50i Message Box"
++      tristate "Allwinner sun6i/sun8i/sun9i/sun50i ARISC Message Box"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       default ARCH_SUNXI
+       help
+         Mailbox implementation for the hardware message box present in
+         various Allwinner SoCs. This mailbox is used for communication
+-        between the application CPUs and the power management coprocessor.
++        between the ARM CPUs and the ARISC power management coprocessor.
++
++config SUN8I_MSGBOX
++      tristate "Allwinner sun8i/sun20i/sun50i DSP/RISC-V Message Box"
++      depends on ARCH_SUNXI || COMPILE_TEST
++      default ARCH_SUNXI
++      help
++        Mailbox implementation for the hardware message box present in
++        various Allwinner SoCs. This mailbox is used for communication
++        between the ARM/RISC-V CPUs and the integrated DSP.
+ config SPRD_MBOX
+       tristate "Spreadtrum Mailbox"
+diff --git a/include/dt-bindings/mailbox/sun20i-d1-msgbox.h b/include/dt-bindings/mailbox/sun20i-d1-msgbox.h
+new file mode 100644
+index 000000000000..2f149f6d59f3
+--- /dev/null
++++ b/include/dt-bindings/mailbox/sun20i-d1-msgbox.h
+@@ -0,0 +1,18 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * This header provides constants for binding nvidia,tegra186-hsp.
++ */
++
++#ifndef _DT_BINDINGS_MAILBOX_SUN20I_D1_MSGBOX_H_
++#define _DT_BINDINGS_MAILBOX_SUN20I_D1_MSGBOX_H_
++
++/* First cell: channel (transmitting user) */
++#define MBOX_USER_CPUX                        0
++#define MBOX_USER_DSP                 1
++#define MBOX_USER_RISCV                       2
++
++/* Second cell: direction (RX if phandle references local mailbox, else TX) */
++#define MBOX_RX                               0
++#define MBOX_TX                               1
++
++#endif /* _DT_BINDINGS_MAILBOX_SUN20I_D1_MSGBOX_H_ */
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0082-media-cedrus-Add-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0082-media-cedrus-Add-D1-variant.patch
new file mode 100644 (file)
index 0000000..bfb8f2b
--- /dev/null
@@ -0,0 +1,43 @@
+From 0d13a0d00a53d70b8a45437dadec46c42be7b56a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:47:22 -0500
+Subject: [PATCH 082/124] media: cedrus: Add D1 variant
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/staging/media/sunxi/cedrus/cedrus.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
+index c0d005dafc6c..98c66431b232 100644
+--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
+@@ -527,6 +527,14 @@ static const struct cedrus_variant sun8i_r40_cedrus_variant = {
+       .mod_rate       = 297000000,
+ };
++static const struct cedrus_variant sun20i_d1_cedrus_variant = {
++      .capabilities   = CEDRUS_CAPABILITY_UNTILED |
++                        CEDRUS_CAPABILITY_MPEG2_DEC |
++                        CEDRUS_CAPABILITY_H264_DEC |
++                        CEDRUS_CAPABILITY_H265_DEC,
++      .mod_rate       = 432000000,
++};
++
+ static const struct cedrus_variant sun50i_a64_cedrus_variant = {
+       .capabilities   = CEDRUS_CAPABILITY_UNTILED |
+                         CEDRUS_CAPABILITY_MPEG2_DEC |
+@@ -583,6 +591,10 @@ static const struct of_device_id cedrus_dt_match[] = {
+               .compatible = "allwinner,sun8i-r40-video-engine",
+               .data = &sun8i_r40_cedrus_variant,
+       },
++      {
++              .compatible = "allwinner,sun20i-d1-video-engine",
++              .data = &sun20i_d1_cedrus_variant,
++      },
+       {
+               .compatible = "allwinner,sun50i-a64-video-engine",
+               .data = &sun50i_a64_cedrus_variant,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0083-mmc-sunxi-mmc-Correct-the-maximum-transfer-size.patch b/target/linux/sunxid1/patches-5.15/0083-mmc-sunxi-mmc-Correct-the-maximum-transfer-size.patch
new file mode 100644 (file)
index 0000000..8f60ff0
--- /dev/null
@@ -0,0 +1,59 @@
+From 7be2c5fed24014995642b24f14d414c4471b79e4 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:15:56 -0500
+Subject: [PATCH 083/124] mmc: sunxi-mmc: Correct the maximum transfer size
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mmc/host/sunxi-mmc.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
+index 2702736a1c57..4e0d593dbbe7 100644
+--- a/drivers/mmc/host/sunxi-mmc.c
++++ b/drivers/mmc/host/sunxi-mmc.c
+@@ -214,6 +214,9 @@
+ #define SDXC_IDMAC_DES0_CES   BIT(30) /* card error summary */
+ #define SDXC_IDMAC_DES0_OWN   BIT(31) /* 1-idma owns it, 0-host owns it */
++/* Buffer size must be a multiple of 4 bytes. */
++#define SDXC_IDMAC_DES1_ALIGN 4
++
+ #define SDXC_CLK_400K         0
+ #define SDXC_CLK_25M          1
+ #define SDXC_CLK_50M          2
+@@ -361,17 +364,16 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
+ {
+       struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
+       dma_addr_t next_desc = host->sg_dma;
+-      int i, max_len = (1 << host->cfg->idma_des_size_bits);
++      int i;
+       for (i = 0; i < data->sg_len; i++) {
+               pdes[i].config = cpu_to_le32(SDXC_IDMAC_DES0_CH |
+                                            SDXC_IDMAC_DES0_OWN |
+                                            SDXC_IDMAC_DES0_DIC);
+-              if (data->sg[i].length == max_len)
+-                      pdes[i].buf_size = 0; /* 0 == max_len */
+-              else
+-                      pdes[i].buf_size = cpu_to_le32(data->sg[i].length);
++              pdes[i].buf_size =
++                      cpu_to_le32(ALIGN(data->sg[i].length,
++                                        SDXC_IDMAC_DES1_ALIGN));
+               next_desc += sizeof(struct sunxi_idma_des);
+               pdes[i].buf_addr_ptr1 =
+@@ -1411,7 +1413,8 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
+       mmc->max_blk_count      = 8192;
+       mmc->max_blk_size       = 4096;
+       mmc->max_segs           = PAGE_SIZE / sizeof(struct sunxi_idma_des);
+-      mmc->max_seg_size       = (1 << host->cfg->idma_des_size_bits);
++      mmc->max_seg_size       = (1 << host->cfg->idma_des_size_bits) -
++                                SDXC_IDMAC_DES1_ALIGN;
+       mmc->max_req_size       = mmc->max_seg_size * mmc->max_segs;
+       /* 400kHz ~ 52MHz */
+       mmc->f_min              =   400000;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0084-mmc-sunxi-mmc-Fix-DMA-descriptors-above-32-bits.patch b/target/linux/sunxid1/patches-5.15/0084-mmc-sunxi-mmc-Fix-DMA-descriptors-above-32-bits.patch
new file mode 100644 (file)
index 0000000..609d866
--- /dev/null
@@ -0,0 +1,29 @@
+From 24c1d741a49938258a8664959e0dbb17e151cae3 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:16:30 -0500
+Subject: [PATCH 084/124] mmc: sunxi-mmc: Fix DMA descriptors above 32 bits
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mmc/host/sunxi-mmc.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
+index 4e0d593dbbe7..d99aba9d7304 100644
+--- a/drivers/mmc/host/sunxi-mmc.c
++++ b/drivers/mmc/host/sunxi-mmc.c
+@@ -379,8 +379,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
+               pdes[i].buf_addr_ptr1 =
+                       cpu_to_le32(sg_dma_address(&data->sg[i]) >>
+                                   host->cfg->idma_des_shift);
+-              pdes[i].buf_addr_ptr2 = cpu_to_le32((u32)next_desc >>
+-                                                  host->cfg->idma_des_shift);
++              pdes[i].buf_addr_ptr2 =
++                      cpu_to_le32(next_desc >>
++                                  host->cfg->idma_des_shift);
+       }
+       pdes[0].config |= cpu_to_le32(SDXC_IDMAC_DES0_FD);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0085-mmc-sunxi-mmc-Add-D1-MMC-compatible.patch b/target/linux/sunxid1/patches-5.15/0085-mmc-sunxi-mmc-Add-D1-MMC-compatible.patch
new file mode 100644 (file)
index 0000000..26b360e
--- /dev/null
@@ -0,0 +1,40 @@
+From 8d2fd59f8a638745eabd207d3db9fa02d2f9ba98 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:16:55 -0500
+Subject: [PATCH 085/124] mmc: sunxi-mmc: Add D1 MMC compatible
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mmc/host/sunxi-mmc.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
+index d99aba9d7304..cde3e8dbc94b 100644
+--- a/drivers/mmc/host/sunxi-mmc.c
++++ b/drivers/mmc/host/sunxi-mmc.c
+@@ -1170,6 +1170,14 @@ static const struct sunxi_mmc_cfg sun9i_a80_cfg = {
+       .can_calibrate = false,
+ };
++static const struct sunxi_mmc_cfg sun20i_d1_cfg = {
++      .idma_des_size_bits = 13,
++      .idma_des_shift = 2,
++      .can_calibrate = true,
++      .mask_data0 = true,
++      .needs_new_timings = true,
++};
++
+ static const struct sunxi_mmc_cfg sun50i_a64_cfg = {
+       .idma_des_size_bits = 16,
+       .clk_delays = NULL,
+@@ -1208,6 +1216,7 @@ static const struct of_device_id sunxi_mmc_of_match[] = {
+       { .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },
+       { .compatible = "allwinner,sun8i-a83t-emmc", .data = &sun8i_a83t_emmc_cfg },
+       { .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },
++      { .compatible = "allwinner,sun20i-d1-mmc", .data = &sun20i_d1_cfg },
+       { .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
+       { .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },
+       { .compatible = "allwinner,sun50i-a100-mmc", .data = &sun50i_a100_cfg },
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0086-mmc-sunxi-mmc-Add-more-registers.patch b/target/linux/sunxid1/patches-5.15/0086-mmc-sunxi-mmc-Add-more-registers.patch
new file mode 100644 (file)
index 0000000..1e3cc9e
--- /dev/null
@@ -0,0 +1,104 @@
+From 22fa62f3cad1d1a053760e32d2de7cf1209a4a91 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:40:49 -0500
+Subject: [PATCH 086/124] mmc: sunxi-mmc: Add more registers
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mmc/host/sunxi-mmc.c | 55 ++++++++++++++++++++++++++++--------
+ 1 file changed, 43 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
+index cde3e8dbc94b..e6a21bcc3b47 100644
+--- a/drivers/mmc/host/sunxi-mmc.c
++++ b/drivers/mmc/host/sunxi-mmc.c
+@@ -54,25 +54,56 @@
+ #define SDXC_REG_MISTA        (0x34) /* SMC Masked Interrupt Status Register */
+ #define SDXC_REG_RINTR        (0x38) /* SMC Raw Interrupt Status Register */
+ #define SDXC_REG_STAS (0x3C) /* SMC Status Register */
+-#define SDXC_REG_FTRGL        (0x40) /* SMC FIFO Threshold Watermark Registe */
++#define SDXC_REG_FTRGL        (0x40) /* SMC FIFO Threshold Watermark Register */
+ #define SDXC_REG_FUNS (0x44) /* SMC Function Select Register */
+ #define SDXC_REG_CBCR (0x48) /* SMC CIU Byte Count Register */
+ #define SDXC_REG_BBCR (0x4C) /* SMC BIU Byte Count Register */
+ #define SDXC_REG_DBGC (0x50) /* SMC Debug Enable Register */
+-#define SDXC_REG_HWRST        (0x78) /* SMC Card Hardware Reset for Register */
++#define SDXC_REG_HWRST        (0x78) /* SMC Card Hardware Reset Register */
+ #define SDXC_REG_DMAC (0x80) /* SMC IDMAC Control Register */
+-#define SDXC_REG_DLBA (0x84) /* SMC IDMAC Descriptor List Base Addre */
++#define SDXC_REG_DLBA (0x84) /* SMC IDMAC Descriptor List Base Address */
+ #define SDXC_REG_IDST (0x88) /* SMC IDMAC Status Register */
+ #define SDXC_REG_IDIE (0x8C) /* SMC IDMAC Interrupt Enable Register */
+-#define SDXC_REG_CHDA (0x90)
+-#define SDXC_REG_CBDA (0x94)
++#define SDXC_REG_CHDA (0x90) /* Current Host Descriptor Address */
++#define SDXC_REG_CBDA (0x94) /* Current Buffer Descriptor Address */
++
++/* New registers introduced in A80 */
++#define SDXC_REG_A12A         0x058 /* Auto Command 12 Register */
++#define SDXC_REG_THLD         0x100 /* Card Threshold Control Register */
++#define SDXC_REG_DSBD         0x10C /* eMMC 4.5 DDR Start Bit Detection */
++
++/* New registers introduced in A83T */
++#define SDXC_REG_NTSR         0x05C /* New Timing Set Register */
++#define SDXC_REG_SDBG         0x060 /* New Timing Set Debug Register */
++
++/* New registers introduced in H3 */
++#define SDXC_REG_RES_CRC      0x110 /* CRC Response from Card/eMMC */
++#define SDXC_REG_D7_CRC               0x114 /* CRC Data 7 from Card/eMMC */
++#define SDXC_REG_D6_CRC               0x118 /* CRC Data 6 from Card/eMMC */
++#define SDXC_REG_D5_CRC               0x11C /* CRC Data 5 from Card/eMMC */
++#define SDXC_REG_D4_CRC               0x120 /* CRC Data 4 from Card/eMMC */
++#define SDXC_REG_D3_CRC               0x124 /* CRC Data 3 from Card/eMMC */
++#define SDXC_REG_D2_CRC               0x128 /* CRC Data 2 from Card/eMMC */
++#define SDXC_REG_D1_CRC               0x12C /* CRC Data 1 from Card/eMMC */
++#define SDXC_REG_D0_CRC               0x130 /* CRC Data 0 from Card/eMMC */
++#define SDXC_REG_CRC_STA      0x134 /* CRC Status from Write Operation */
+ /* New registers introduced in A64 */
+-#define SDXC_REG_A12A         0x058 /* SMC Auto Command 12 Register */
+-#define SDXC_REG_SD_NTSR      0x05C /* SMC New Timing Set Register */
++#define SDXC_REG_CSDC         0x054 /* CRC Status Detect Register */
+ #define SDXC_REG_DRV_DL               0x140 /* Drive Delay Control Register */
+-#define SDXC_REG_SAMP_DL_REG  0x144 /* SMC sample delay control */
+-#define SDXC_REG_DS_DL_REG    0x148 /* SMC data strobe delay control */
++#define SDXC_REG_SAMP_DL      0x144 /* Sample Delay Control Register */
++#define SDXC_REG_DS_DL                0x148 /* Data Strobe Delay Control Register */
++
++/* New registers introduced in H6 */
++#define SDXC_REG_EMCE         0x064 /* Embedded Encrypt/Decrypt Control */
++#define SDXC_REG_EMCE_DBG     0x068 /* Embedded Encrypt/Decrypt Debug */
++
++/* New registers introduced in H616 */
++#define SDXC_REG_EXT_CMD      0x138 /* Extended Command Register */
++#define SDXC_REG_EXT_RESP     0x13C /* Extended Response Register */
++
++/* New registers introduced in A100 */
++#define SDXC_REG_HS400_DL     0x14C /* HS400 Delay Control Register */
+ #define mmc_readl(host, reg) \
+       readl((host)->reg_base + SDXC_##reg)
+@@ -836,9 +867,9 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
+        */
+       if (host->use_new_timings) {
+               /* Don't touch the delay bits */
+-              rval = mmc_readl(host, REG_SD_NTSR);
++              rval = mmc_readl(host, REG_NTSR);
+               rval |= SDXC_2X_TIMING_MODE;
+-              mmc_writel(host, REG_SD_NTSR, rval);
++              mmc_writel(host, REG_NTSR, rval);
+       }
+       /* sunxi_mmc_clk_set_phase expects the actual card clock rate */
+@@ -846,7 +877,7 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
+       if (ret)
+               return ret;
+-      ret = sunxi_mmc_calibrate(host, SDXC_REG_SAMP_DL_REG);
++      ret = sunxi_mmc_calibrate(host, SDXC_REG_SAMP_DL);
+       if (ret)
+               return ret;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0087-phy-sun4i-usb-Rework-HCI-PHY-aka.-pmu_unk1-handling.patch b/target/linux/sunxid1/patches-5.15/0087-phy-sun4i-usb-Rework-HCI-PHY-aka.-pmu_unk1-handling.patch
new file mode 100644 (file)
index 0000000..8330925
--- /dev/null
@@ -0,0 +1,164 @@
+From 0f84a1ffd2d5e74c17bf50642e137f5f356567df Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Tue, 15 Jun 2021 12:06:29 +0100
+Subject: [PATCH 087/124] phy: sun4i-usb: Rework HCI PHY (aka. "pmu_unk1")
+ handling
+
+As Icenowy pointed out, newer manuals (starting with H6) actually
+document the register block at offset 0x800 as "HCI controller and PHY
+interface", also describe the bits in our "PMU_UNK1" register.
+Let's put proper names to those "unknown" variables and symbols.
+
+While we are at it, generalise the existing code by allowing a bitmap
+of bits to clear and set, to cover newer SoCs: The A100 and H616 use a
+different bit for the SIDDQ control.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/phy/allwinner/phy-sun4i-usb.c | 30 ++++++++++++---------------
+ 1 file changed, 13 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
+index 788dd5cdbb7d..142f4cafdc78 100644
+--- a/drivers/phy/allwinner/phy-sun4i-usb.c
++++ b/drivers/phy/allwinner/phy-sun4i-usb.c
+@@ -43,7 +43,7 @@
+ #define REG_PHYCTL_A33                        0x10
+ #define REG_PHY_OTGCTL                        0x20
+-#define REG_PMU_UNK1                  0x10
++#define REG_HCI_PHY_CTL                       0x10
+ #define PHYCTL_DATA                   BIT(7)
+@@ -82,6 +82,7 @@
+ /* A83T specific control bits for PHY0 */
+ #define PHY_CTL_VBUSVLDEXT            BIT(5)
+ #define PHY_CTL_SIDDQ                 BIT(3)
++#define PHY_CTL_H3_SIDDQ              BIT(1)
+ /* A83T specific control bits for PHY2 HSIC */
+ #define SUNXI_EHCI_HS_FORCE           BIT(20)
+@@ -115,9 +116,9 @@ struct sun4i_usb_phy_cfg {
+       int hsic_index;
+       enum sun4i_usb_phy_type type;
+       u32 disc_thresh;
++      u32 hci_phy_ctl_clear;
+       u8 phyctl_offset;
+       bool dedicated_clocks;
+-      bool enable_pmu_unk1;
+       bool phy0_dual_route;
+       int missing_phys;
+ };
+@@ -288,6 +289,12 @@ static int sun4i_usb_phy_init(struct phy *_phy)
+               return ret;
+       }
++      if (phy->pmu && data->cfg->hci_phy_ctl_clear) {
++              val = readl(phy->pmu + REG_HCI_PHY_CTL);
++              val &= ~data->cfg->hci_phy_ctl_clear;
++              writel(val, phy->pmu + REG_HCI_PHY_CTL);
++      }
++
+       if (data->cfg->type == sun8i_a83t_phy ||
+           data->cfg->type == sun50i_h6_phy) {
+               if (phy->index == 0) {
+@@ -297,11 +304,6 @@ static int sun4i_usb_phy_init(struct phy *_phy)
+                       writel(val, data->base + data->cfg->phyctl_offset);
+               }
+       } else {
+-              if (phy->pmu && data->cfg->enable_pmu_unk1) {
+-                      val = readl(phy->pmu + REG_PMU_UNK1);
+-                      writel(val & ~2, phy->pmu + REG_PMU_UNK1);
+-              }
+-
+               /* Enable USB 45 Ohm resistor calibration */
+               if (phy->index == 0)
+                       sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
+@@ -863,7 +865,6 @@ static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A10,
+       .dedicated_clocks = false,
+-      .enable_pmu_unk1 = false,
+ };
+ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
+@@ -872,7 +873,6 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
+       .disc_thresh = 2,
+       .phyctl_offset = REG_PHYCTL_A10,
+       .dedicated_clocks = false,
+-      .enable_pmu_unk1 = false,
+ };
+ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
+@@ -881,7 +881,6 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A10,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = false,
+ };
+ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
+@@ -890,7 +889,6 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
+       .disc_thresh = 2,
+       .phyctl_offset = REG_PHYCTL_A10,
+       .dedicated_clocks = false,
+-      .enable_pmu_unk1 = false,
+ };
+ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
+@@ -899,7 +897,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A10,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = false,
+ };
+ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
+@@ -908,7 +905,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = false,
+ };
+ static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
+@@ -925,7 +921,7 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = true,
++      .hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
+       .phy0_dual_route = true,
+ };
+@@ -935,7 +931,7 @@ static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = true,
++      .hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
+       .phy0_dual_route = true,
+ };
+@@ -945,7 +941,7 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = true,
++      .hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
+       .phy0_dual_route = true,
+ };
+@@ -955,7 +951,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+-      .enable_pmu_unk1 = true,
++      .hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
+       .phy0_dual_route = true,
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0088-phy-sun4i-usb-Remove-disc_thresh-where-not-applicabl.patch b/target/linux/sunxid1/patches-5.15/0088-phy-sun4i-usb-Remove-disc_thresh-where-not-applicabl.patch
new file mode 100644 (file)
index 0000000..ab51419
--- /dev/null
@@ -0,0 +1,26 @@
+From 7aff4d9c913586d7d4ffe33f88c17d8d4d8302bd Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 23 Jun 2021 22:14:15 -0500
+Subject: [PATCH 088/124] phy: sun4i-usb: Remove disc_thresh where not
+ applicable
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/phy/allwinner/phy-sun4i-usb.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
+index 142f4cafdc78..6675dad17415 100644
+--- a/drivers/phy/allwinner/phy-sun4i-usb.c
++++ b/drivers/phy/allwinner/phy-sun4i-usb.c
+@@ -958,7 +958,6 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
+ static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
+       .num_phys = 4,
+       .type = sun50i_h6_phy,
+-      .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+       .phy0_dual_route = true,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0089-phy-sun4i-usb-Add-D1-variant.patch b/target/linux/sunxid1/patches-5.15/0089-phy-sun4i-usb-Add-D1-variant.patch
new file mode 100644 (file)
index 0000000..28726ab
--- /dev/null
@@ -0,0 +1,44 @@
+From b3518c170a136e9c3ec605d89a944203324cee1b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:45:25 -0500
+Subject: [PATCH 089/124] phy: sun4i-usb: Add D1 variant
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/phy/allwinner/phy-sun4i-usb.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
+index 6675dad17415..021335c91661 100644
+--- a/drivers/phy/allwinner/phy-sun4i-usb.c
++++ b/drivers/phy/allwinner/phy-sun4i-usb.c
+@@ -945,6 +945,15 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
+       .phy0_dual_route = true,
+ };
++static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = {
++      .num_phys = 2,
++      .type = sun50i_h6_phy,
++      .phyctl_offset = REG_PHYCTL_A33,
++      .dedicated_clocks = true,
++      .hci_phy_ctl_clear = PHY_CTL_SIDDQ,
++      .phy0_dual_route = true,
++};
++
+ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
+       .num_phys = 2,
+       .type = sun50i_a64_phy,
+@@ -975,8 +984,8 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
+       { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
+       { .compatible = "allwinner,sun8i-r40-usb-phy", .data = &sun8i_r40_cfg },
+       { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
+-      { .compatible = "allwinner,sun50i-a64-usb-phy",
+-        .data = &sun50i_a64_cfg},
++      { .compatible = "allwinner,sun20i-d1-usb-phy", .data = &sun20i_d1_cfg },
++      { .compatible = "allwinner,sun50i-a64-usb-phy", .data = &sun50i_a64_cfg },
+       { .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
+       { },
+ };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0090-pinctrl-sunxi-Support-new-2.5V-I-O-bias-mode.patch b/target/linux/sunxid1/patches-5.15/0090-pinctrl-sunxi-Support-new-2.5V-I-O-bias-mode.patch
new file mode 100644 (file)
index 0000000..3932cf9
--- /dev/null
@@ -0,0 +1,68 @@
+From fa878b2c67b76258b85b00af41e46ec205720be0 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 19:56:23 -0500
+Subject: [PATCH 090/124] pinctrl: sunxi: Support new 2.5V I/O bias mode
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 11 +++++++++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.h |  7 +++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index 862c84efb718..8a9c0ee98d8e 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -654,6 +654,16 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
+               reg &= ~IO_BIAS_MASK;
+               writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
+               return 0;
++      case BIAS_VOLTAGE_PIO_POW_MODE_CTL:
++              val = 1800000 < uV && uV <= 2500000 ? BIT(bank) : 0;
++
++              raw_spin_lock_irqsave(&pctl->lock, flags);
++              reg = readl(pctl->membase + PIO_POW_MOD_CTL_REG);
++              reg &= ~BIT(bank);
++              writel(reg | val, pctl->membase + PIO_POW_MOD_CTL_REG);
++              raw_spin_unlock_irqrestore(&pctl->lock, flags);
++
++              fallthrough;
+       case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
+               val = uV <= 1800000 ? 1 : 0;
+@@ -662,6 +672,7 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
+               reg &= ~(1 << bank);
+               writel(reg | val << bank, pctl->membase + PIO_POW_MOD_SEL_REG);
+               raw_spin_unlock_irqrestore(&pctl->lock, flags);
++
+               return 0;
+       default:
+               return -EINVAL;
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+index a32bb5bcb754..0f1aab58650c 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+@@ -98,6 +98,7 @@
+ #define PINCTRL_SUN8I_V3S     BIT(10)
+ #define PIO_POW_MOD_SEL_REG   0x340
++#define PIO_POW_MOD_CTL_REG   0x344
+ enum sunxi_desc_bias_voltage {
+       BIAS_VOLTAGE_NONE,
+@@ -111,6 +112,12 @@ enum sunxi_desc_bias_voltage {
+        * register, as seen on H6 SoC, for example.
+        */
+       BIAS_VOLTAGE_PIO_POW_MODE_SEL,
++      /*
++       * Bias voltage is set through PIO_POW_MOD_SEL_REG
++       * and PIO_POW_MOD_CTL_REG register, as seen on
++       * A100 and D1 SoC, for example.
++       */
++      BIAS_VOLTAGE_PIO_POW_MODE_CTL,
+ };
+ struct sunxi_desc_function {
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0091-pinctrl-sunxi-Adapt-for-D1-register-layout.patch b/target/linux/sunxid1/patches-5.15/0091-pinctrl-sunxi-Adapt-for-D1-register-layout.patch
new file mode 100644 (file)
index 0000000..f70f9d4
--- /dev/null
@@ -0,0 +1,51 @@
+From 0d32a8415787d2833c67d4710bba4eb264abd13c Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:06:19 -0500
+Subject: [PATCH 091/124] pinctrl: sunxi: Adapt for D1 register layout
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+index 0f1aab58650c..8ebba0ab5f69 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+@@ -34,11 +34,11 @@
+ #define SUNXI_PIN_NAME_MAX_LEN        5
+-#define BANK_MEM_SIZE         0x24
++#define BANK_MEM_SIZE         0x30
+ #define MUX_REGS_OFFSET               0x0
+ #define DATA_REGS_OFFSET      0x10
+ #define DLEVEL_REGS_OFFSET    0x14
+-#define PULL_REGS_OFFSET      0x1c
++#define PULL_REGS_OFFSET      0x24
+ #define PINS_PER_BANK         32
+ #define MUX_PINS_PER_REG      8
+@@ -47,8 +47,8 @@
+ #define DATA_PINS_PER_REG     32
+ #define DATA_PINS_BITS                1
+ #define DATA_PINS_MASK                0x01
+-#define DLEVEL_PINS_PER_REG   16
+-#define DLEVEL_PINS_BITS      2
++#define DLEVEL_PINS_PER_REG   8
++#define DLEVEL_PINS_BITS      4
+ #define DLEVEL_PINS_MASK      0x03
+ #define PULL_PINS_PER_REG     16
+ #define PULL_PINS_BITS                2
+@@ -84,7 +84,7 @@
+ #define IO_BIAS_MASK          GENMASK(3, 0)
+ #define SUN4I_FUNC_INPUT      0
+-#define SUN4I_FUNC_IRQ                6
++#define SUN4I_FUNC_IRQ                0xe
+ #define PINCTRL_SUN5I_A10S    BIT(1)
+ #define PINCTRL_SUN5I_A13     BIT(2)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0092-pinctrl-sunxi-Add-support-for-Allwinner-D1-SoC.patch b/target/linux/sunxid1/patches-5.15/0092-pinctrl-sunxi-Add-support-for-Allwinner-D1-SoC.patch
new file mode 100644 (file)
index 0000000..dab6833
--- /dev/null
@@ -0,0 +1,886 @@
+From 80a49483f4354770415223ffdcb46ad5f4c3f73a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:13:04 -0500
+Subject: [PATCH 092/124] pinctrl: sunxi: Add support for Allwinner D1 SoC
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pinctrl/sunxi/Kconfig             |   5 +
+ drivers/pinctrl/sunxi/Makefile            |   1 +
+ drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c | 836 ++++++++++++++++++++++
+ 3 files changed, 842 insertions(+)
+ create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c
+
+diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
+index 33751a6a0757..a6ac1c1f2585 100644
+--- a/drivers/pinctrl/sunxi/Kconfig
++++ b/drivers/pinctrl/sunxi/Kconfig
+@@ -84,6 +84,11 @@ config PINCTRL_SUN9I_A80_R
+       depends on RESET_CONTROLLER
+       select PINCTRL_SUNXI
++config PINCTRL_SUN20I_D1
++      bool "Support for the Allwinner D1 PIO"
++      default RISCV && ARCH_SUNXI
++      select PINCTRL_SUNXI
++
+ config PINCTRL_SUN50I_A64
+       bool "Support for the Allwinner A64 PIO"
+       default ARM64 && ARCH_SUNXI
+diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
+index d3440c42b9d6..2ff5a55927ad 100644
+--- a/drivers/pinctrl/sunxi/Makefile
++++ b/drivers/pinctrl/sunxi/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_PINCTRL_SUN8I_A83T_R)   += pinctrl-sun8i-a83t-r.o
+ obj-$(CONFIG_PINCTRL_SUN8I_H3)                += pinctrl-sun8i-h3.o
+ obj-$(CONFIG_PINCTRL_SUN8I_H3_R)      += pinctrl-sun8i-h3-r.o
+ obj-$(CONFIG_PINCTRL_SUN8I_V3S)               += pinctrl-sun8i-v3s.o
++obj-$(CONFIG_PINCTRL_SUN20I_D1)               += pinctrl-sun20i-d1.o
+ obj-$(CONFIG_PINCTRL_SUN50I_H5)               += pinctrl-sun50i-h5.o
+ obj-$(CONFIG_PINCTRL_SUN50I_H6)               += pinctrl-sun50i-h6.o
+ obj-$(CONFIG_PINCTRL_SUN50I_H6_R)     += pinctrl-sun50i-h6-r.o
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c
+new file mode 100644
+index 000000000000..ed72ebc1e2cd
+--- /dev/null
++++ b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c
+@@ -0,0 +1,836 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Allwinner D1 SoC pinctrl driver.
++ *
++ * Copyright (c) 2020 wuyan@allwinnertech.com
++ * Copyright (c) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/pinctrl.h>
++
++#include "pinctrl-sunxi.h"
++
++/* PB:8pins,PC:8pins,PD:23pins,PE:18pins,PF:7pins, PG:16pins */
++static const struct sunxi_desc_pin d1_pins[] = {
++      /* PB */
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "pwm"),
++              SUNXI_FUNCTION(0x3, "ir"),              /* TX */
++              SUNXI_FUNCTION(0x4, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "spi1"),            /* WP */
++              SUNXI_FUNCTION(0x6, "uart0"),           /* TX */
++              SUNXI_FUNCTION(0x7, "uart2"),           /* TX */
++              SUNXI_FUNCTION(0x8, "spdif"),           /* OUT */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 0)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "pwm"),
++              SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT3 */
++              SUNXI_FUNCTION(0x4, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN3 */
++              SUNXI_FUNCTION(0x6, "uart0"),           /* RX */
++              SUNXI_FUNCTION(0x7, "uart2"),           /* RX */
++              SUNXI_FUNCTION(0x8, "ir"),              /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 1)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D0 */
++              SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT2 */
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN2 */
++              SUNXI_FUNCTION(0x6, "lcd0"),            /* D18 */
++              SUNXI_FUNCTION(0x7, "uart4"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 2)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D1 */
++              SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT1 */
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN0 */
++              SUNXI_FUNCTION(0x6, "lcd0"),            /* D19 */
++              SUNXI_FUNCTION(0x7, "uart4"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 3)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D8 */
++              SUNXI_FUNCTION(0x3, "i2s2_dout"),       /* DOUT0 */
++              SUNXI_FUNCTION(0x4, "i2c1"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "i2s2_din"),        /* DIN1 */
++              SUNXI_FUNCTION(0x6, "lcd0"),            /* D20 */
++              SUNXI_FUNCTION(0x7, "uart5"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 4)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D9 */
++              SUNXI_FUNCTION(0x3, "i2s2"),            /* BCLK */
++              SUNXI_FUNCTION(0x4, "i2c1"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION(0x6, "lcd0"),            /* D21 */
++              SUNXI_FUNCTION(0x7, "uart5"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 5)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D16 */
++              SUNXI_FUNCTION(0x3, "i2s2"),            /* LRCK */
++              SUNXI_FUNCTION(0x4, "i2c3"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION(0x6, "lcd0"),            /* D22 */
++              SUNXI_FUNCTION(0x7, "uart3"),           /* TX */
++              SUNXI_FUNCTION(0x8, "bist0"),           /* BIST_RESULT0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 6)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D17 */
++              SUNXI_FUNCTION(0x3, "i2s2"),            /* MCLK */
++              SUNXI_FUNCTION(0x4, "i2c3"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "ir"),              /* RX */
++              SUNXI_FUNCTION(0x6, "lcd0"),            /* D23 */
++              SUNXI_FUNCTION(0x7, "uart3"),           /* RX */
++              SUNXI_FUNCTION(0x8, "bist1"),           /* BIST_RESULT1 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 7)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "dmic"),            /* DATA3 */
++              SUNXI_FUNCTION(0x3, "pwm"),
++              SUNXI_FUNCTION(0x4, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "spi1"),            /* HOLD */
++              SUNXI_FUNCTION(0x6, "uart0"),           /* TX */
++              SUNXI_FUNCTION(0x7, "uart1"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 8)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "dmic"),            /* DATA2 */
++              SUNXI_FUNCTION(0x3, "pwm"),
++              SUNXI_FUNCTION(0x4, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "spi1"),            /* MISO */
++              SUNXI_FUNCTION(0x6, "uart0"),           /* RX */
++              SUNXI_FUNCTION(0x7, "uart1"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 9)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "dmic"),            /* DATA1 */
++              SUNXI_FUNCTION(0x3, "pwm"),
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "spi1"),            /* MOSI */
++              SUNXI_FUNCTION(0x6, "clk"),             /* FANOUT0 */
++              SUNXI_FUNCTION(0x7, "uart1"),           /* RTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 10)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "dmic"),            /* DATA0 */
++              SUNXI_FUNCTION(0x3, "pwm"),
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "spi1"),            /* CLK */
++              SUNXI_FUNCTION(0x6, "clk"),             /* FANOUT1 */
++              SUNXI_FUNCTION(0x7, "uart1"),           /* CTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 11)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "dmic"),            /* CLK */
++              SUNXI_FUNCTION(0x3, "pwm"),
++              SUNXI_FUNCTION(0x4, "spdif"),           /* IN */
++              SUNXI_FUNCTION(0x5, "spi1"),            /* CS0 */
++              SUNXI_FUNCTION(0x6, "clk"),             /* FANOUT2 */
++              SUNXI_FUNCTION(0x7, "ir"),              /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 12)),
++      /* PC */
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart2"),           /* TX */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "ledc"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 0)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart2"),           /* RX */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 1)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spi0"),            /* CLK */
++              SUNXI_FUNCTION(0x3, "mmc2"),            /* CLK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 2)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spi0"),            /* CS0 */
++              SUNXI_FUNCTION(0x3, "mmc2"),            /* CMD */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 3)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spi0"),            /* MOSI */
++              SUNXI_FUNCTION(0x3, "mmc2"),            /* D2 */
++              SUNXI_FUNCTION(0x4, "boot"),            /* SEL0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 4)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spi0"),            /* MISO */
++              SUNXI_FUNCTION(0x3, "mmc2"),            /* D1 */
++              SUNXI_FUNCTION(0x4, "boot"),            /* SEL1 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 5)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spi0"),            /* WP */
++              SUNXI_FUNCTION(0x3, "mmc2"),            /* D0 */
++              SUNXI_FUNCTION(0x4, "uart3"),           /* TX */
++              SUNXI_FUNCTION(0x5, "i2c3"),            /* SCK */
++              SUNXI_FUNCTION(0x6, "pll"),             /* DBG-CLK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 6)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spi0"),            /* HOLD */
++              SUNXI_FUNCTION(0x3, "mmc2"),            /* D3 */
++              SUNXI_FUNCTION(0x4, "uart3"),           /* RX */
++              SUNXI_FUNCTION(0x5, "i2c3"),            /* SDA */
++              SUNXI_FUNCTION(0x6, "tcon"),            /* TRIG0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 7)),
++      /* PD */
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D2 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V0P */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D0P */
++              SUNXI_FUNCTION(0x5, "i2c0"),            /* SCK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 0)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D3 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V0N */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D0N */
++              SUNXI_FUNCTION(0x5, "uart2"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 1)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D4 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V1P */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D1P */
++              SUNXI_FUNCTION(0x5, "uart2"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 2)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D5 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V1N */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D1N */
++              SUNXI_FUNCTION(0x5, "uart2"),           /* RTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 3)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D6 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V2P */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* CKP */
++              SUNXI_FUNCTION(0x5, "uart2"),           /* CTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 4)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D7 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V2N */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* CKN */
++              SUNXI_FUNCTION(0x5, "uart5"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 5)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D10 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* CKP */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D2P */
++              SUNXI_FUNCTION(0x5, "uart5"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 6)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D11 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* CKN */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D2N */
++              SUNXI_FUNCTION(0x5, "uart4"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 7)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D12 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V3P */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D3P */
++              SUNXI_FUNCTION(0x5, "uart4"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 8)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D13 */
++              SUNXI_FUNCTION(0x3, "lvds0"),           /* V3N */
++              SUNXI_FUNCTION(0x4, "dsi"),             /* D3N */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 9)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D14 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V0P */
++              SUNXI_FUNCTION(0x4, "spi1"),            /* CS0 */
++              SUNXI_FUNCTION(0x5, "uart3"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 10)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D15 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V0N */
++              SUNXI_FUNCTION(0x4, "spi1"),            /* CLK */
++              SUNXI_FUNCTION(0x5, "uart3"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 11)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D18 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V1P */
++              SUNXI_FUNCTION(0x4, "spi1"),            /* MOSI */
++              SUNXI_FUNCTION(0x5, "i2c0"),            /* SDA */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 12)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D19 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V1N */
++              SUNXI_FUNCTION(0x4, "spi1"),            /* MISO */
++              SUNXI_FUNCTION(0x5, "uart3"),           /* RTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 13)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D20 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V2P */
++              SUNXI_FUNCTION(0x4, "spi1"),            /* HOLD */
++              SUNXI_FUNCTION(0x5, "uart3"),           /* CTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 14)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D21 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V2N */
++              SUNXI_FUNCTION(0x4, "spi1"),            /* WP */
++              SUNXI_FUNCTION(0x5, "ir"),              /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 15)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D22 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* CKP */
++              SUNXI_FUNCTION(0x4, "dmic"),            /* DATA3 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 16)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* D23 */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* CKN */
++              SUNXI_FUNCTION(0x4, "dmic"),            /* DATA2 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 17)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* CLK */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V3P */
++              SUNXI_FUNCTION(0x4, "dmic"),            /* DATA1 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 18)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* DE */
++              SUNXI_FUNCTION(0x3, "lvds1"),           /* V3N */
++              SUNXI_FUNCTION(0x4, "dmic"),            /* DATA0 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 19)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* HSYNC */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "dmic"),            /* CLK */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 20)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "lcd0"),            /* VSYNC */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "uart1"),           /* TX */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 21)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "spdif"),           /* OUT */
++              SUNXI_FUNCTION(0x3, "ir"),              /* RX */
++              SUNXI_FUNCTION(0x4, "uart1"),           /* RX */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 22)),
++      /* PE */
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* HSYNC */
++              SUNXI_FUNCTION(0x3, "uart2"),           /* RTS */
++              SUNXI_FUNCTION(0x4, "i2c1"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "lcd0"),            /* HSYNC */
++              SUNXI_FUNCTION(0x8, "emac"),            /* RXCTL/CRS_DV */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 0)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* VSYNC */
++              SUNXI_FUNCTION(0x3, "uart2"),           /* CTS */
++              SUNXI_FUNCTION(0x4, "i2c1"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "lcd0"),            /* VSYNC */
++              SUNXI_FUNCTION(0x8, "emac"),            /* RXD0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 1)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* PCLK */
++              SUNXI_FUNCTION(0x3, "uart2"),           /* TX */
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT0 */
++              SUNXI_FUNCTION(0x6, "uart0"),           /* TX */
++              SUNXI_FUNCTION(0x8, "emac"),            /* RXD1 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 2)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "csi0"),            /* MCLK */
++              SUNXI_FUNCTION(0x3, "uart2"),           /* RX */
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT1 */
++              SUNXI_FUNCTION(0x6, "uart0"),           /* RX */
++              SUNXI_FUNCTION(0x8, "emac"),            /* TXCK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 3)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D0 */
++              SUNXI_FUNCTION(0x3, "uart4"),           /* TX */
++              SUNXI_FUNCTION(0x4, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT2 */
++              SUNXI_FUNCTION(0x6, "d_jtag"),          /* MS */
++              SUNXI_FUNCTION(0x7, "r_jtag"),          /* MS */
++              SUNXI_FUNCTION(0x8, "emac"),            /* TXD0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 4)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D1 */
++              SUNXI_FUNCTION(0x3, "uart4"),           /* RX */
++              SUNXI_FUNCTION(0x4, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "ledc"),
++              SUNXI_FUNCTION(0x6, "d_jtag"),          /* D1 */
++              SUNXI_FUNCTION(0x7, "r_jtag"),          /* D1 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* TXD1 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 5)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D2 */
++              SUNXI_FUNCTION(0x3, "uart5"),           /* TX */
++              SUNXI_FUNCTION(0x4, "i2c3"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "spdif"),           /* IN */
++              SUNXI_FUNCTION(0x6, "d_jtag"),          /* D0 */
++              SUNXI_FUNCTION(0x7, "r_jtag"),          /* D0 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* TXCTL/TXEN */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 6)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D3 */
++              SUNXI_FUNCTION(0x3, "uart5"),           /* RX */
++              SUNXI_FUNCTION(0x4, "i2c3"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "spdif"),           /* OUT */
++              SUNXI_FUNCTION(0x6, "d_jtag"),          /* CK */
++              SUNXI_FUNCTION(0x7, "r_jtag"),          /* CK */
++              SUNXI_FUNCTION(0x8, "emac"),            /* CK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 7)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D4 */
++              SUNXI_FUNCTION(0x3, "uart1"),           /* RTS */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "uart3"),           /* TX */
++              SUNXI_FUNCTION(0x6, "jtag"),            /* MS */
++              SUNXI_FUNCTION(0x8, "emac"),            /* MDC */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 8)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D5 */
++              SUNXI_FUNCTION(0x3, "uart1"),           /* CTS */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "uart3"),           /* RX */
++              SUNXI_FUNCTION(0x6, "jtag"),            /* D1 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* MDIO */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 9)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D6 */
++              SUNXI_FUNCTION(0x3, "uart1"),           /* TX */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "ir"),              /* RX */
++              SUNXI_FUNCTION(0x6, "jtag"),            /* D0 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* EPHY-25M */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 10)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ncsi0"),           /* D7 */
++              SUNXI_FUNCTION(0x3, "uart1"),           /* RX */
++              SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT3 */
++              SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN3 */
++              SUNXI_FUNCTION(0x6, "jtag"),            /* CK */
++              SUNXI_FUNCTION(0x8, "emac"),            /* TXD2 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 11)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x3, "ncsi0"),           /* FIELD */
++              SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT2 */
++              SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN2 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* TXD3 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 12)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x3, "pwm"),
++              SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT0 */
++              SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN1 */
++              SUNXI_FUNCTION(0x6, "dmic"),            /* DATA3 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* RXD2 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 13)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2c1"),            /* SCK */
++              SUNXI_FUNCTION(0x3, "d_jtag"),          /* MS */
++              SUNXI_FUNCTION(0x4, "i2s0_dout"),       /* DOUT1 */
++              SUNXI_FUNCTION(0x5, "i2s0_din"),        /* DIN0 */
++              SUNXI_FUNCTION(0x6, "dmic"),            /* DATA2 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* RXD3 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 14)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2c1"),            /* SDA */
++              SUNXI_FUNCTION(0x3, "d_jtag"),          /* D1 */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "i2s0"),            /* LRCK */
++              SUNXI_FUNCTION(0x6, "dmic"),            /* DATA1 */
++              SUNXI_FUNCTION(0x8, "emac"),            /* RXCK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 15)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2c3"),            /* SCK */
++              SUNXI_FUNCTION(0x3, "d_jtag"),          /* D0 */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "i2s0"),            /* BCLK */
++              SUNXI_FUNCTION(0x6, "dmic"),            /* DATA0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 16)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2c3"),            /* SDA */
++              SUNXI_FUNCTION(0x3, "d_jtag"),          /* CK */
++              SUNXI_FUNCTION(0x4, "ir"),              /* TX */
++              SUNXI_FUNCTION(0x5, "i2s0"),            /* MCLK */
++              SUNXI_FUNCTION(0x6, "dmic"),            /* CLK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 17)),
++      /* PF */
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc0"),            /* D1 */
++              SUNXI_FUNCTION(0x3, "jtag"),            /* MS */
++              SUNXI_FUNCTION(0x4, "r_jtag"),          /* MS */
++              SUNXI_FUNCTION(0x5, "i2s2_dout"),       /* DOUT1 */
++              SUNXI_FUNCTION(0x6, "i2s2_din"),        /* DIN0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 0)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc0"),            /* D0 */
++              SUNXI_FUNCTION(0x3, "jtag"),            /* DI */
++              SUNXI_FUNCTION(0x4, "r_jtag"),          /* DI */
++              SUNXI_FUNCTION(0x5, "i2s2_dout"),       /* DOUT0 */
++              SUNXI_FUNCTION(0x6, "i2s2_din"),        /* DIN1 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 1)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc0"),            /* CLK */
++              SUNXI_FUNCTION(0x3, "uart0"),           /* TX */
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SCK */
++              SUNXI_FUNCTION(0x5, "ledc"),
++              SUNXI_FUNCTION(0x6, "spdif"),           /* IN */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 2)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc0"),            /* CMD */
++              SUNXI_FUNCTION(0x3, "jtag"),            /* DO */
++              SUNXI_FUNCTION(0x4, "r_jtag"),          /* DO */
++              SUNXI_FUNCTION(0x5, "i2s2"),            /* BCLK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 3)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc0"),            /* D3 */
++              SUNXI_FUNCTION(0x3, "uart0"),           /* RX */
++              SUNXI_FUNCTION(0x4, "i2c0"),            /* SDA */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION(0x6, "ir"),              /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 4)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc0"),            /* D2 */
++              SUNXI_FUNCTION(0x3, "jtag"),            /* CK */
++              SUNXI_FUNCTION(0x4, "r_jtag"),          /* CK */
++              SUNXI_FUNCTION(0x5, "i2s2"),            /* LRCK */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 5)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x3, "spdif"),           /* OUT */
++              SUNXI_FUNCTION(0x4, "ir"),              /* RX */
++              SUNXI_FUNCTION(0x5, "i2s2"),            /* MCLK */
++              SUNXI_FUNCTION(0x6, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 6)),
++      /* PG */
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc1"),            /* CLK */
++              SUNXI_FUNCTION(0x3, "uart3"),           /* TX */
++              SUNXI_FUNCTION(0x4, "emac"),            /* RXCTRL/CRS_DV */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 0)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc1"),            /* CMD */
++              SUNXI_FUNCTION(0x3, "uart3"),           /* RX */
++              SUNXI_FUNCTION(0x4, "emac"),            /* RXD0 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 1)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc1"),            /* D0 */
++              SUNXI_FUNCTION(0x3, "uart3"),           /* RTS */
++              SUNXI_FUNCTION(0x4, "emac"),            /* RXD1 */
++              SUNXI_FUNCTION(0x5, "uart4"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 2)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc1"),            /* D1 */
++              SUNXI_FUNCTION(0x3, "uart3"),           /* CTS */
++              SUNXI_FUNCTION(0x4, "emac"),            /* TXCK */
++              SUNXI_FUNCTION(0x5, "uart4"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 3)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc1"),            /* D2 */
++              SUNXI_FUNCTION(0x3, "uart5"),           /* TX */
++              SUNXI_FUNCTION(0x4, "emac"),            /* TXD0 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 4)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "mmc1"),            /* D3 */
++              SUNXI_FUNCTION(0x3, "uart5"),           /* RX */
++              SUNXI_FUNCTION(0x4, "emac"),            /* TXD1 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 5)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart1"),           /* TX */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "emac"),            /* TXD2 */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 6)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart1"),           /* RX */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "emac"),            /* TXD3 */
++              SUNXI_FUNCTION(0x5, "spdif"),           /* IN */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 7)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart1"),           /* RTS */
++              SUNXI_FUNCTION(0x3, "i2c1"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "emac"),            /* RXD2 */
++              SUNXI_FUNCTION(0x5, "uart3"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 8)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart1"),           /* CTS */
++              SUNXI_FUNCTION(0x3, "i2c1"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "emac"),            /* RXD3 */
++              SUNXI_FUNCTION(0x5, "uart3"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 9)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "pwm"),
++              SUNXI_FUNCTION(0x3, "i2c3"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "emac"),            /* RXCK */
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT0 */
++              SUNXI_FUNCTION(0x6, "ir"),              /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 10)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2s1"),            /* MCLK */
++              SUNXI_FUNCTION(0x3, "i2c3"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "emac"),            /* EPHY-25M */
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT1 */
++              SUNXI_FUNCTION(0x6, "tcon"),            /* TRIG0 */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 11)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2s1"),            /* LRCK */
++              SUNXI_FUNCTION(0x3, "i2c0"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "emac"),            /* TXCTL/TXEN */
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT2 */
++              SUNXI_FUNCTION(0x6, "pwm"),
++              SUNXI_FUNCTION(0x7, "uart1"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 12)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2s1"),            /* BCLK */
++              SUNXI_FUNCTION(0x3, "i2c0"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "emac"),            /* CLKIN/RXER */
++              SUNXI_FUNCTION(0x5, "pwm"),
++              SUNXI_FUNCTION(0x6, "ledc"),
++              SUNXI_FUNCTION(0x7, "uart1"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 13)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2s1_din"),        /* DIN0 */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "emac"),            /* MDC */
++              SUNXI_FUNCTION(0x5, "i2s1_dout"),       /* DOUT1 */
++              SUNXI_FUNCTION(0x6, "spi0"),            /* WP */
++              SUNXI_FUNCTION(0x7, "uart1"),           /* RTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 14)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "i2s1_dout"),       /* DOUT0 */
++              SUNXI_FUNCTION(0x3, "i2c2"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "emac"),            /* MDIO */
++              SUNXI_FUNCTION(0x5, "i2s1_din"),        /* DIN1 */
++              SUNXI_FUNCTION(0x6, "spi0"),            /* HOLD */
++              SUNXI_FUNCTION(0x7, "uart1"),           /* CTS */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 15)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "ir"),              /* RX */
++              SUNXI_FUNCTION(0x3, "tcon"),            /* TRIG0 */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT2 */
++              SUNXI_FUNCTION(0x6, "spdif"),           /* IN */
++              SUNXI_FUNCTION(0x7, "ledc"),
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 16)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart2"),           /* TX */
++              SUNXI_FUNCTION(0x3, "i2c3"),            /* SCK */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT0 */
++              SUNXI_FUNCTION(0x6, "ir"),              /* TX */
++              SUNXI_FUNCTION(0x7, "uart0"),           /* TX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 17)),
++      SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18),
++              SUNXI_FUNCTION(0x0, "gpio_in"),
++              SUNXI_FUNCTION(0x1, "gpio_out"),
++              SUNXI_FUNCTION(0x2, "uart2"),           /* RX */
++              SUNXI_FUNCTION(0x3, "i2c3"),            /* SDA */
++              SUNXI_FUNCTION(0x4, "pwm"),
++              SUNXI_FUNCTION(0x5, "clk"),             /* FANOUT1 */
++              SUNXI_FUNCTION(0x6, "spdif"),           /* OUT */
++              SUNXI_FUNCTION(0x7, "uart0"),           /* RX */
++              SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 18)),
++};
++
++static const unsigned int d1_irq_bank_map[] = { 1, 2, 3, 4, 5, 6 };
++
++static const struct sunxi_pinctrl_desc d1_pinctrl_data = {
++      .pins = d1_pins,
++      .npins = ARRAY_SIZE(d1_pins),
++      .irq_banks = ARRAY_SIZE(d1_irq_bank_map),
++      .irq_bank_map = d1_irq_bank_map,
++      .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
++};
++
++static int d1_pinctrl_probe(struct platform_device *pdev)
++{
++      return sunxi_pinctrl_init(pdev, &d1_pinctrl_data);
++}
++
++static const struct of_device_id d1_pinctrl_match[] = {
++      { .compatible = "allwinner,sun20i-d1-pinctrl" },
++      {}
++};
++
++static struct platform_driver d1_pinctrl_driver = {
++      .probe  = d1_pinctrl_probe,
++      .driver = {
++              .name           = "sun20i-d1-pinctrl",
++              .of_match_table = d1_pinctrl_match,
++      },
++};
++builtin_platform_driver(d1_pinctrl_driver);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0093-pwm-sun8i-v536-document-device-tree-bindings.patch b/target/linux/sunxid1/patches-5.15/0093-pwm-sun8i-v536-document-device-tree-bindings.patch
new file mode 100644 (file)
index 0000000..374fd54
--- /dev/null
@@ -0,0 +1,46 @@
+From c19eb2d30c0af0add66346252b9f2c742aa02f47 Mon Sep 17 00:00:00 2001
+From: Ban Tao <fengzheng923@gmail.com>
+Date: Tue, 2 Mar 2021 20:40:23 +0800
+Subject: [PATCH 093/124] pwm: sun8i-v536: document device tree bindings
+
+This adds binding documentation for sun8i-v536 SoC PWM driver.
+
+Signed-off-by: Ban Tao <fengzheng923@gmail.com>
+---
+ .../bindings/pwm/pwm-sun8i-v536.txt           | 24 +++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/pwm/pwm-sun8i-v536.txt
+
+diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun8i-v536.txt b/Documentation/devicetree/bindings/pwm/pwm-sun8i-v536.txt
+new file mode 100644
+index 000000000000..ab3f4fe0560a
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pwm/pwm-sun8i-v536.txt
+@@ -0,0 +1,24 @@
++Allwinner sun8i-v536 SoC PWM controller
++
++Required properties:
++ - compatible: should be "allwinner,<name>-pwm"
++   "allwinner,sun8i-v833-pwm"
++   "allwinner,sun8i-v536-pwm"
++   "allwinner,sun50i-r818-pwm"
++   "allwinner,sun50i-a133-pwm"
++   "allwinner,sun50i-r329-pwm"
++ - reg: physical base address and length of the controller's registers
++ - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
++   the cells format.
++ - clocks: From common clock binding, handle to the parent clock.
++ - resets: From reset clock binding, handle to the parent clock.
++
++Example:
++
++      pwm: pwm@300a0000 {
++              compatible = "allwinner,sun50i-r818-pwm";
++              reg = <0x0300a000 0x3ff>;
++              clocks = <&ccu CLK_BUS_PWM>;
++              resets = <&ccu RST_BUS_PWM>;
++              #pwm-cells = <3>;
++      };
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0094-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch b/target/linux/sunxid1/patches-5.15/0094-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch
new file mode 100644 (file)
index 0000000..6b593e0
--- /dev/null
@@ -0,0 +1,478 @@
+From 042d00b1479f3f1ad314ac2f3f0041dc806b9c5b Mon Sep 17 00:00:00 2001
+From: Ban Tao <fengzheng923@gmail.com>
+Date: Tue, 2 Mar 2021 20:37:37 +0800
+Subject: [PATCH 094/124] pwm: sunxi: Add Allwinner SoC PWM controller driver
+
+The Allwinner R818, A133, R329, V536 and V833 has a new PWM controller
+IP compared to the older Allwinner SoCs.
+
+Signed-off-by: Ban Tao <fengzheng923@gmail.com>
+---
+ MAINTAINERS                  |   6 +
+ drivers/pwm/Kconfig          |  11 +
+ drivers/pwm/Makefile         |   1 +
+ drivers/pwm/pwm-sun8i-v536.c | 401 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 419 insertions(+)
+ create mode 100644 drivers/pwm/pwm-sun8i-v536.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 8b4809d2c789..bba1b777dee0 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -779,6 +779,12 @@ L:        linux-media@vger.kernel.org
+ S:    Maintained
+ F:    drivers/staging/media/sunxi/cedrus/
++ALLWINNER PWM DRIVER
++M:    Ban Tao <fengzheng923@gmail.com>
++L:    linux-pwm@vger.kernel.org
++S:    Maintained
++F:    drivers/pwm/pwm-sun8i-v536.c
++
+ ALPHA PORT
+ M:    Richard Henderson <rth@twiddle.net>
+ M:    Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index aa29841bbb79..e31884525081 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -570,6 +570,17 @@ config PWM_SUN4I
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-sun4i.
++config PWM_SUN8I_V536
++      tristate "Allwinner SUN8I_V536 PWM support"
++      depends on ARCH_SUNXI || COMPILE_TEST
++      depends on HAS_IOMEM && COMMON_CLK
++      help
++        Enhanced PWM framework driver for Allwinner R818, A133, R329,
++        V536 and V833 SoCs.
++
++        To compile this driver as a module, choose M here: the module
++        will be called pwm-sun8i-v536.
++
+ config PWM_TEGRA
+       tristate "NVIDIA Tegra PWM support"
+       depends on ARCH_TEGRA || COMPILE_TEST
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index 708840b7fba8..2ab762e719ff 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -53,6 +53,7 @@ obj-$(CONFIG_PWM_STM32)              += pwm-stm32.o
+ obj-$(CONFIG_PWM_STM32_LP)    += pwm-stm32-lp.o
+ obj-$(CONFIG_PWM_STMPE)               += pwm-stmpe.o
+ obj-$(CONFIG_PWM_SUN4I)               += pwm-sun4i.o
++obj-$(CONFIG_PWM_SUN8I_V536)  += pwm-sun8i-v536.o
+ obj-$(CONFIG_PWM_TEGRA)               += pwm-tegra.o
+ obj-$(CONFIG_PWM_TIECAP)      += pwm-tiecap.o
+ obj-$(CONFIG_PWM_TIEHRPWM)    += pwm-tiehrpwm.o
+diff --git a/drivers/pwm/pwm-sun8i-v536.c b/drivers/pwm/pwm-sun8i-v536.c
+new file mode 100644
+index 000000000000..52101df6bd41
+--- /dev/null
++++ b/drivers/pwm/pwm-sun8i-v536.c
+@@ -0,0 +1,401 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Driver for Allwinner sun8i-v536 Pulse Width Modulation Controller
++ *
++ * Copyright (C) 2021 Ban Tao <fengzheng923@gmail.com>
++ *
++ *
++ * Limitations:
++ * - When PWM is disabled, the output is driven to inactive.
++ * - If the register is reconfigured while PWM is running,
++ *   it does not complete the currently running period.
++ * - If the user input duty is beyond acceptible limits,
++ *   -EINVAL is returned.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/pwm.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++
++#define PWM_GET_CLK_OFFSET(chan)      (0x20 + ((chan >> 1) * 0x4))
++#define PWM_CLK_APB_SCR                       BIT(7)
++#define PWM_DIV_M                     0
++#define PWM_DIV_M_MASK                        GENMASK(3, PWM_DIV_M)
++
++#define PWM_CLK_REG                   0x40
++#define PWM_CLK_GATING                        BIT(0)
++
++#define PWM_ENABLE_REG                        0x80
++#define PWM_EN                                BIT(0)
++
++#define PWM_CTL_REG(chan)             (0x100 + 0x20 * chan)
++#define PWM_ACT_STA                   BIT(8)
++#define PWM_PRESCAL_K                 0
++#define PWM_PRESCAL_K_MASK            GENMASK(7, PWM_PRESCAL_K)
++
++#define PWM_PERIOD_REG(chan)          (0x104 + 0x20 * chan)
++#define PWM_ENTIRE_CYCLE                      16
++#define PWM_ENTIRE_CYCLE_MASK         GENMASK(31, PWM_ENTIRE_CYCLE)
++#define PWM_ACT_CYCLE                 0
++#define PWM_ACT_CYCLE_MASK            GENMASK(15, PWM_ACT_CYCLE)
++
++#define BIT_CH(bit, chan)             ((bit) << (chan))
++#define SET_BITS(shift, mask, reg, val) \
++          (((reg) & ~mask) | (val << (shift)))
++
++#define PWM_OSC_CLK                   24000000
++#define PWM_PRESCALER_MAX             256
++#define PWM_CLK_DIV_M__MAX            9
++#define PWM_ENTIRE_CYCLE_MAX          65536
++
++struct sun8i_pwm_data {
++      unsigned int npwm;
++};
++
++struct sun8i_pwm_chip {
++      struct pwm_chip chip;
++      struct clk *clk;
++      struct reset_control *rst_clk;
++      void __iomem *base;
++      const struct sun8i_pwm_data *data;
++};
++
++static inline struct sun8i_pwm_chip *to_sun8i_pwm_chip(struct pwm_chip *chip)
++{
++      return container_of(chip, struct sun8i_pwm_chip, chip);
++}
++
++static inline u32 sun8i_pwm_readl(struct sun8i_pwm_chip *chip,
++                                 unsigned long offset)
++{
++      return readl(chip->base + offset);
++}
++
++static inline void sun8i_pwm_writel(struct sun8i_pwm_chip *chip,
++                                   u32 val, unsigned long offset)
++{
++      writel(val, chip->base + offset);
++}
++
++static void sun8i_pwm_get_state(struct pwm_chip *chip,
++                               struct pwm_device *pwm,
++                               struct pwm_state *state)
++{
++      struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip);
++      u64 clk_rate;
++      u32 tmp, entire_cycles, active_cycles;
++      unsigned int prescaler, div_m;
++
++      tmp = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++      if (tmp & PWM_CLK_APB_SCR)
++              clk_rate = clk_get_rate(pc->clk);
++      else
++              clk_rate = PWM_OSC_CLK;
++
++      tmp = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++      div_m = 0x1 << (tmp & PWM_DIV_M_MASK);
++
++      tmp = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm));
++      prescaler = (tmp & PWM_PRESCAL_K_MASK) + 1;
++
++      tmp = sun8i_pwm_readl(pc, PWM_PERIOD_REG(pwm->hwpwm));
++      entire_cycles = (tmp >> PWM_ENTIRE_CYCLE) + 1;
++      active_cycles = (tmp & PWM_ACT_CYCLE_MASK);
++
++      /* (clk / div_m / prescaler) / entire_cycles = NSEC_PER_SEC / period_ns. */
++      state->period = DIV_ROUND_CLOSEST_ULL(entire_cycles * NSEC_PER_SEC,
++                                            clk_rate) * div_m * prescaler;
++      /* duty_ns / period_ns = active_cycles / entire_cycles. */
++      state->duty_cycle = DIV_ROUND_CLOSEST_ULL(active_cycles * state->period,
++                                                entire_cycles);
++
++      /* parsing polarity */
++      tmp = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm));
++      if (tmp & PWM_ACT_STA)
++              state->polarity = PWM_POLARITY_NORMAL;
++      else
++              state->polarity = PWM_POLARITY_INVERSED;
++
++      /* parsing enabled */
++      tmp = sun8i_pwm_readl(pc, PWM_ENABLE_REG);
++      if (tmp & BIT_CH(PWM_EN, pwm->hwpwm))
++              state->enabled = true;
++      else
++              state->enabled = false;
++
++      dev_dbg(chip->dev, "duty_ns=%lld period_ns=%lld polarity=%s enabled=%s.\n",
++                              state->duty_cycle, state->period,
++                              state->polarity ? "inversed":"normal",
++                              state->enabled ? "true":"false");
++}
++
++static void sun8i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
++                                  enum pwm_polarity polarity)
++{
++      struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip);
++      u32 temp;
++
++      temp = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm));
++
++      if (polarity == PWM_POLARITY_NORMAL)
++              temp |= PWM_ACT_STA;
++      else
++              temp &= ~PWM_ACT_STA;
++
++      sun8i_pwm_writel(pc, temp, PWM_CTL_REG(pwm->hwpwm));
++}
++
++static int sun8i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++                            const struct pwm_state *state)
++{
++      struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip);
++      unsigned long long c;
++      unsigned long entire_cycles, active_cycles;
++      unsigned int div_m, prescaler;
++      u64 duty_ns = state->duty_cycle, period_ns = state->period;
++      u32 config;
++      int ret = 0;
++
++      if (period_ns > 334) {
++              /* if freq < 3M, then select 24M clock */
++              c = PWM_OSC_CLK;
++              config = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++              config &= ~PWM_CLK_APB_SCR;
++              sun8i_pwm_writel(pc, config, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++      } else {
++              /* if freq > 3M, then select APB as clock */
++              c = clk_get_rate(pc->clk);
++              config = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++              config |= PWM_CLK_APB_SCR;
++              sun8i_pwm_writel(pc, config, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++      }
++
++      dev_dbg(chip->dev, "duty_ns=%lld period_ns=%lld c =%llu.\n",
++                      duty_ns, period_ns, c);
++
++      /*
++       * (clk / div_m / prescaler) / entire_cycles = NSEC_PER_SEC / period_ns.
++       * So, entire_cycles = clk * period_ns / NSEC_PER_SEC / div_m / prescaler.
++       */
++      c = c * period_ns;
++      c = DIV_ROUND_CLOSEST_ULL(c, NSEC_PER_SEC);
++      for (div_m = 0; div_m < PWM_CLK_DIV_M__MAX; div_m++) {
++              for (prescaler = 0; prescaler < PWM_PRESCALER_MAX; prescaler++) {
++                      /*
++                       * actual prescaler = prescaler(reg value) + 1.
++                       * actual div_m = 0x1 << div_m(reg value).
++                       */
++                      entire_cycles = ((unsigned long)c >> div_m)/(prescaler + 1);
++                      if (entire_cycles <= PWM_ENTIRE_CYCLE_MAX)
++                              goto calc_end;
++              }
++      }
++      ret = -EINVAL;
++      goto exit;
++
++calc_end:
++      /*
++       * duty_ns / period_ns = active_cycles / entire_cycles.
++       * So, active_cycles = entire_cycles * duty_ns / period_ns.
++       */
++      c = (unsigned long long)entire_cycles * duty_ns;
++      c = DIV_ROUND_CLOSEST_ULL(c, period_ns);
++      active_cycles = c;
++      if (entire_cycles == 0)
++              entire_cycles++;
++
++      /* config  clk div_m*/
++      config = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++      config = SET_BITS(PWM_DIV_M, PWM_DIV_M_MASK, config, div_m);
++      sun8i_pwm_writel(pc, config, PWM_GET_CLK_OFFSET(pwm->hwpwm));
++
++      /* config prescaler */
++      config = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm));
++      config = SET_BITS(PWM_PRESCAL_K, PWM_PRESCAL_K_MASK, config, prescaler);
++      sun8i_pwm_writel(pc, config, PWM_CTL_REG(pwm->hwpwm));
++
++      /* config active and period cycles */
++      config = sun8i_pwm_readl(pc, PWM_PERIOD_REG(pwm->hwpwm));
++      config = SET_BITS(PWM_ACT_CYCLE, PWM_ACT_CYCLE_MASK, config, active_cycles);
++      config = SET_BITS(PWM_ENTIRE_CYCLE, PWM_ENTIRE_CYCLE_MASK,
++                      config, (entire_cycles - 1));
++      sun8i_pwm_writel(pc, config, PWM_PERIOD_REG(pwm->hwpwm));
++
++      dev_dbg(chip->dev, "active_cycles=%lu entire_cycles=%lu prescaler=%u div_m=%u\n",
++                         active_cycles, entire_cycles, prescaler, div_m);
++
++exit:
++      return ret;
++}
++
++static void sun8i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm,
++                           bool enable)
++{
++      struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip);
++      u32 clk, pwm_en;
++
++      clk = sun8i_pwm_readl(pc, PWM_CLK_REG);
++      pwm_en = sun8i_pwm_readl(pc, PWM_ENABLE_REG);
++
++      if (enable) {
++              clk |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
++              sun8i_pwm_writel(pc, clk, PWM_CLK_REG);
++
++              pwm_en |= BIT_CH(PWM_EN, pwm->hwpwm);
++              sun8i_pwm_writel(pc, pwm_en, PWM_ENABLE_REG);
++      } else {
++              pwm_en &= ~BIT_CH(PWM_EN, pwm->hwpwm);
++              sun8i_pwm_writel(pc, pwm_en, PWM_ENABLE_REG);
++
++              clk &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
++              sun8i_pwm_writel(pc, clk, PWM_CLK_REG);
++      }
++}
++
++static int sun8i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
++                            const struct pwm_state *state)
++{
++      struct pwm_state curstate;
++      int ret;
++
++      pwm_get_state(pwm, &curstate);
++
++      ret = sun8i_pwm_config(chip, pwm, state);
++
++      if (state->polarity != curstate.polarity)
++              sun8i_pwm_set_polarity(chip, pwm, state->polarity);
++
++      if (state->enabled != curstate.enabled)
++              sun8i_pwm_enable(chip, pwm, state->enabled);
++
++      return ret;
++}
++
++static const struct pwm_ops sun8i_pwm_ops = {
++      .get_state = sun8i_pwm_get_state,
++      .apply = sun8i_pwm_apply,
++      .owner = THIS_MODULE,
++};
++
++static const struct sun8i_pwm_data sun8i_pwm_data_c9 = {
++      .npwm = 9,
++};
++
++static const struct sun8i_pwm_data sun50i_pwm_data_c16 = {
++      .npwm = 16,
++};
++
++static const struct of_device_id sun8i_pwm_dt_ids[] = {
++      {
++              .compatible = "allwinner,sun8i-v536-pwm",
++              .data = &sun8i_pwm_data_c9,
++      }, {
++              .compatible = "allwinner,sun50i-r818-pwm",
++              .data = &sun50i_pwm_data_c16,
++      }, {
++              /* sentinel */
++      },
++};
++MODULE_DEVICE_TABLE(of, sun8i_pwm_dt_ids);
++
++static int sun8i_pwm_probe(struct platform_device *pdev)
++{
++      struct sun8i_pwm_chip *pc;
++      int ret;
++
++      pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
++      if (!pc)
++              return dev_err_probe(&pdev->dev, -ENOMEM,
++                                   "memory allocation failed\n");
++
++      pc->data = of_device_get_match_data(&pdev->dev);
++      if (!pc->data)
++              return dev_err_probe(&pdev->dev, -ENODEV,
++                                   "can't get match data\n");
++
++      pc->base = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(pc->base))
++              return dev_err_probe(&pdev->dev, PTR_ERR(pc->base),
++                                   "can't remap pwm resource\n");
++
++      pc->clk = devm_clk_get(&pdev->dev, NULL);
++      if (IS_ERR(pc->clk))
++              return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
++                                   "get clock failed\n");
++
++      pc->rst_clk = devm_reset_control_get_exclusive(&pdev->dev, NULL);
++      if (IS_ERR(pc->rst_clk))
++              return dev_err_probe(&pdev->dev, PTR_ERR(pc->rst_clk),
++                                   "get reset failed\n");
++
++      /* Deassert reset */
++      ret = reset_control_deassert(pc->rst_clk);
++      if (ret < 0)
++              return dev_err_probe(&pdev->dev, ret,
++                                   "cannot deassert reset control\n");
++
++      ret = clk_prepare_enable(pc->clk);
++      if (ret) {
++              dev_err(&pdev->dev, "cannot prepare and enable clk %pe\n",
++                      ERR_PTR(ret));
++              goto err_clk;
++      }
++
++      pc->chip.dev = &pdev->dev;
++      pc->chip.ops = &sun8i_pwm_ops;
++      pc->chip.npwm = pc->data->npwm;
++      pc->chip.of_xlate = of_pwm_xlate_with_flags;
++      pc->chip.base = -1;
++      pc->chip.of_pwm_n_cells = 3;
++
++      ret = pwmchip_add(&pc->chip);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
++              goto err_pwm_add;
++      }
++
++      platform_set_drvdata(pdev, pc);
++
++      return 0;
++
++err_pwm_add:
++      clk_disable_unprepare(pc->clk);
++err_clk:
++      reset_control_assert(pc->rst_clk);
++
++      return ret;
++}
++
++static int sun8i_pwm_remove(struct platform_device *pdev)
++{
++      struct sun8i_pwm_chip *pc = platform_get_drvdata(pdev);
++      int ret;
++
++      ret = pwmchip_remove(&pc->chip);
++      if (ret)
++              return ret;
++
++      clk_disable_unprepare(pc->clk);
++      reset_control_assert(pc->rst_clk);
++
++      return 0;
++}
++
++static struct platform_driver sun8i_pwm_driver = {
++      .driver = {
++              .name = "sun8i-pwm-v536",
++              .of_match_table = sun8i_pwm_dt_ids,
++      },
++      .probe = sun8i_pwm_probe,
++      .remove = sun8i_pwm_remove,
++};
++module_platform_driver(sun8i_pwm_driver);
++
++MODULE_ALIAS("platform:sun8i-v536-pwm");
++MODULE_AUTHOR("Ban Tao <fengzheng923@gmail.com>");
++MODULE_DESCRIPTION("Allwinner sun8i-v536 PWM driver");
++MODULE_LICENSE("GPL v2");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0095-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch b/target/linux/sunxid1/patches-5.15/0095-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch
new file mode 100644 (file)
index 0000000..6bd9773
--- /dev/null
@@ -0,0 +1,50 @@
+From 526751701c01331fb898334df5f491a2b10bc9b1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 11:05:20 -0500
+Subject: [PATCH 095/124] squash? pwm: sunxi: Add Allwinner SoC PWM controller
+ driver
+
+---
+ drivers/pwm/Kconfig          | 4 ++--
+ drivers/pwm/pwm-sun8i-v536.c | 6 +-----
+ 2 files changed, 3 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index e31884525081..f956bb0a65bf 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -571,11 +571,11 @@ config PWM_SUN4I
+         will be called pwm-sun4i.
+ config PWM_SUN8I_V536
+-      tristate "Allwinner SUN8I_V536 PWM support"
++      tristate "Allwinner SUN8I V536 enhanced PWM support"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       depends on HAS_IOMEM && COMMON_CLK
+       help
+-        Enhanced PWM framework driver for Allwinner R818, A133, R329,
++        Enhanced PWM framework driver for Allwinner A133, D1, R329, R818,
+         V536 and V833 SoCs.
+         To compile this driver as a module, choose M here: the module
+diff --git a/drivers/pwm/pwm-sun8i-v536.c b/drivers/pwm/pwm-sun8i-v536.c
+index 52101df6bd41..ab302c6cb4ee 100644
+--- a/drivers/pwm/pwm-sun8i-v536.c
++++ b/drivers/pwm/pwm-sun8i-v536.c
+@@ -373,12 +373,8 @@ static int sun8i_pwm_probe(struct platform_device *pdev)
+ static int sun8i_pwm_remove(struct platform_device *pdev)
+ {
+       struct sun8i_pwm_chip *pc = platform_get_drvdata(pdev);
+-      int ret;
+-
+-      ret = pwmchip_remove(&pc->chip);
+-      if (ret)
+-              return ret;
++      pwmchip_remove(&pc->chip);
+       clk_disable_unprepare(pc->clk);
+       reset_control_assert(pc->rst_clk);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0096-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch b/target/linux/sunxid1/patches-5.15/0096-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch
new file mode 100644 (file)
index 0000000..d13398f
--- /dev/null
@@ -0,0 +1,38 @@
+From 75fe896da6096919effe9d00cfa21dbb0c6b367e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 10:56:25 -0500
+Subject: [PATCH 096/124] pwm: sun8i-v536: Add support for the Allwinner D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pwm/pwm-sun8i-v536.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/pwm/pwm-sun8i-v536.c b/drivers/pwm/pwm-sun8i-v536.c
+index ab302c6cb4ee..732f15c88b67 100644
+--- a/drivers/pwm/pwm-sun8i-v536.c
++++ b/drivers/pwm/pwm-sun8i-v536.c
+@@ -285,6 +285,10 @@ static const struct sun8i_pwm_data sun8i_pwm_data_c9 = {
+       .npwm = 9,
+ };
++static const struct sun8i_pwm_data sun20i_pwm_data_c8 = {
++      .npwm = 8,
++};
++
+ static const struct sun8i_pwm_data sun50i_pwm_data_c16 = {
+       .npwm = 16,
+ };
+@@ -293,6 +297,9 @@ static const struct of_device_id sun8i_pwm_dt_ids[] = {
+       {
+               .compatible = "allwinner,sun8i-v536-pwm",
+               .data = &sun8i_pwm_data_c9,
++      }, {
++              .compatible = "allwinner,sun20i-d1-pwm",
++              .data = &sun20i_pwm_data_c8,
+       }, {
+               .compatible = "allwinner,sun50i-r818-pwm",
+               .data = &sun50i_pwm_data_c16,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0097-remoteproc-sun8i-dsp-Add-a-driver-for-the-DSPs-in-su.patch b/target/linux/sunxid1/patches-5.15/0097-remoteproc-sun8i-dsp-Add-a-driver-for-the-DSPs-in-su.patch
new file mode 100644 (file)
index 0000000..0019d38
--- /dev/null
@@ -0,0 +1,321 @@
+From 52c9bd03a8e25ee0de97ade64ebfd8f0b40eaa2d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 11 Jul 2021 10:54:55 -0500
+Subject: [PATCH 097/124] remoteproc: sun8i-dsp: Add a driver for the DSPs in
+ sunxi SoCs
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/remoteproc/Kconfig           |   7 +
+ drivers/remoteproc/Makefile          |   1 +
+ drivers/remoteproc/sun8i_dsp_rproc.c | 269 +++++++++++++++++++++++++++
+ 3 files changed, 277 insertions(+)
+ create mode 100644 drivers/remoteproc/sun8i_dsp_rproc.c
+
+diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
+index 9a6eedc3994a..3dbdf61be7ee 100644
+--- a/drivers/remoteproc/Kconfig
++++ b/drivers/remoteproc/Kconfig
+@@ -289,6 +289,13 @@ config STM32_RPROC
+         This can be either built-in or a loadable module.
++config SUN8I_DSP_REMOTEPROC
++      tristate "Allwinner sun8i DSP remoteproc support"
++      depends on ARCH_SUNXI || COMPILE_TEST
++      help
++        Say y here to support the DSP in some sun8i/sun20i/sun50i SoCs
++        via the remote processor framework.
++
+ config TI_K3_DSP_REMOTEPROC
+       tristate "TI K3 DSP remoteproc support"
+       depends on ARCH_K3
+diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
+index bb26c9e4ef9c..e2daa32065a4 100644
+--- a/drivers/remoteproc/Makefile
++++ b/drivers/remoteproc/Makefile
+@@ -33,5 +33,6 @@ qcom_wcnss_pil-y                     += qcom_wcnss_iris.o
+ obj-$(CONFIG_ST_REMOTEPROC)           += st_remoteproc.o
+ obj-$(CONFIG_ST_SLIM_REMOTEPROC)      += st_slim_rproc.o
+ obj-$(CONFIG_STM32_RPROC)             += stm32_rproc.o
++obj-$(CONFIG_SUN8I_DSP_REMOTEPROC)    += sun8i_dsp_rproc.o
+ obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)    += ti_k3_dsp_remoteproc.o
+ obj-$(CONFIG_TI_K3_R5_REMOTEPROC)     += ti_k3_r5_remoteproc.o
+diff --git a/drivers/remoteproc/sun8i_dsp_rproc.c b/drivers/remoteproc/sun8i_dsp_rproc.c
+new file mode 100644
+index 000000000000..0d7682a4788e
+--- /dev/null
++++ b/drivers/remoteproc/sun8i_dsp_rproc.c
+@@ -0,0 +1,269 @@
++// SPDX-License-Identifier: GPL-2.0
++//
++// Copyright (c) 2021 Samuel Holland <samuel@sholland.org>
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/mailbox_client.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/remoteproc.h>
++#include <linux/reset.h>
++#include <linux/soc/sunxi/sunxi_sram.h>
++
++#include "remoteproc_internal.h"
++
++#define SUN8I_DSP_RESET_VEC_REG               0x0000
++#define SUN8I_DSP_CTRL_REG0           0x0004
++#define SUN8I_DSP_CTRL_REG0_RUN_STALL         BIT(0)
++#define SUN8I_DSP_CTRL_REG0_RESET_VEC_SEL     BIT(1)
++#define SUN8I_DSP_CTRL_REG0_DSP_CLKEN         BIT(2)
++#define SUN8I_DSP_CTRL_REG1           0x0008
++#define SUN8I_DSP_PRID_REG            0x000c
++#define SUN8I_DSP_PRID_REG_PRID_MASK          (0xff << 0)
++#define SUN8I_DSP_STAT_REG            0x0010
++#define SUN8I_DSP_STAT_REG_PFAULT_INFO_VALID  BIT(0)
++#define SUN8I_DSP_STAT_REG_PFAULT_ERROR               BIT(1)
++#define SUN8I_DSP_STAT_REG_DOUBLE_EXCE_ERROR  BIT(2)
++#define SUN8I_DSP_STAT_REG_XOCD_MODE          BIT(3)
++#define SUN8I_DSP_STAT_REG_DEBUG_MODE         BIT(4)
++#define SUN8I_DSP_STAT_REG_PWAIT_MODE         BIT(5)
++#define SUN8I_DSP_STAT_REG_IRAM0_LOAD_STORE   BIT(6)
++#define SUN8I_DSP_BIST_CTRL_REG               0x0014
++#define SUN8I_DSP_BIST_CTRL_REG_EN            BIT(0)
++#define SUN8I_DSP_BIST_CTRL_REG_WDATA_PAT_MASK        (0x7 << 1)
++#define SUN8I_DSP_BIST_CTRL_REG_ADDR_MODE_SEL BIT(4)
++#define SUN8I_DSP_BIST_CTRL_REG_REG_SEL_MASK  (0x7 << 5)
++#define SUN8I_DSP_BIST_CTRL_REG_BUSY          BIT(8)
++#define SUN8I_DSP_BIST_CTRL_REG_STOP          BIT(9)
++#define SUN8I_DSP_BIST_CTRL_REG_ERR_CYC_MASK  (0x3 << 10)
++#define SUN8I_DSP_BIST_CTRL_REG_ERR_PAT_MASK  (0x7 << 12)
++#define SUN8I_DSP_BIST_CTRL_REG_ERR_STA               BIT(15)
++#define SUN8I_DSP_BIST_CTRL_REG_SELECT_MASK   (0xf << 16)
++#define SUN8I_DSP_JTRST_REG           0x001c
++#define SUN8I_DSP_VER_REG             0x0020
++#define SUN8I_DSP_VER_REG_MINOR_VER_MASK      (0x1f << 0)
++#define SUN8I_DSP_VER_REG_MAJOR_VER_MASK      (0x1f << 16)
++
++#define SUN8I_DSP_CLK_FREQ            400000000
++
++struct sun8i_dsp_rproc {
++      void __iomem            *cfg_base;
++      struct clk              *cfg_clk;
++      struct reset_control    *cfg_reset;
++      struct reset_control    *dbg_reset;
++      struct clk              *dsp_clk;
++      struct reset_control    *dsp_reset;
++      struct mbox_client      client;
++      struct mbox_chan        *rx_chan;
++      struct mbox_chan        *tx_chan;
++};
++
++static int sun8i_dsp_rproc_start(struct rproc *rproc)
++{
++      struct sun8i_dsp_rproc *dsp = rproc->priv;
++      int ret;
++      u32 val;
++
++      ret = sunxi_sram_claim(rproc->dev.parent);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(dsp->cfg_clk);
++      if (ret)
++              goto err_release_sram;
++
++      ret = reset_control_deassert(dsp->cfg_reset);
++      if (ret)
++              goto err_gate_cfg;
++
++      ret = reset_control_deassert(dsp->dbg_reset);
++      if (ret)
++              goto err_reset_cfg;
++
++      writel(rproc->bootaddr, dsp->cfg_base + SUN8I_DSP_RESET_VEC_REG);
++
++      val = readl(dsp->cfg_base + SUN8I_DSP_CTRL_REG0);
++      val |= SUN8I_DSP_CTRL_REG0_RESET_VEC_SEL |
++             SUN8I_DSP_CTRL_REG0_RUN_STALL;
++      writel(val, dsp->cfg_base + SUN8I_DSP_CTRL_REG0);
++
++      ret = clk_prepare_enable(dsp->dsp_clk);
++      if (ret)
++              goto err_reset_dbg;
++
++      ret = reset_control_deassert(dsp->dsp_reset);
++      if (ret)
++              goto err_gate_dsp;
++
++      val &= ~SUN8I_DSP_CTRL_REG0_RUN_STALL;
++      writel(val, dsp->cfg_base + SUN8I_DSP_CTRL_REG0);
++
++      return 0;
++
++err_gate_dsp:
++      clk_disable_unprepare(dsp->dsp_clk);
++err_reset_dbg:
++      reset_control_assert(dsp->dbg_reset);
++err_reset_cfg:
++      reset_control_assert(dsp->cfg_reset);
++err_gate_cfg:
++      clk_disable_unprepare(dsp->cfg_clk);
++err_release_sram:
++      sunxi_sram_release(rproc->dev.parent);
++
++      return ret;
++}
++
++static int sun8i_dsp_rproc_stop(struct rproc *rproc)
++{
++      struct sun8i_dsp_rproc *dsp = rproc->priv;
++
++      reset_control_assert(dsp->dsp_reset);
++      clk_disable_unprepare(dsp->dsp_clk);
++      reset_control_assert(dsp->dbg_reset);
++      reset_control_assert(dsp->cfg_reset);
++      clk_disable_unprepare(dsp->cfg_clk);
++      sunxi_sram_release(rproc->dev.parent);
++
++      return 0;
++}
++
++static void sun8i_dsp_rproc_kick(struct rproc *rproc, int vqid)
++{
++      struct sun8i_dsp_rproc *dsp = rproc->priv;
++      long msg = vqid;
++      int ret;
++
++      ret = mbox_send_message(dsp->tx_chan, (void *)msg);
++      if (ret)
++              dev_warn(&rproc->dev, "Failed to kick: %d\n", ret);
++}
++
++static const struct rproc_ops sun8i_dsp_rproc_ops = {
++      .start          = sun8i_dsp_rproc_start,
++      .stop           = sun8i_dsp_rproc_stop,
++      .kick           = sun8i_dsp_rproc_kick,
++};
++
++static void sun8i_dsp_rproc_mbox_rx_callback(struct mbox_client *client, void *msg)
++{
++      struct rproc *rproc = dev_get_drvdata(client->dev);
++
++      rproc_vq_interrupt(rproc, (long)msg);
++}
++
++static void sun8i_dsp_rproc_mbox_free(void *data)
++{
++      struct sun8i_dsp_rproc *dsp = data;
++
++      if (!IS_ERR_OR_NULL(dsp->tx_chan))
++              mbox_free_channel(dsp->tx_chan);
++      if (!IS_ERR_OR_NULL(dsp->rx_chan))
++              mbox_free_channel(dsp->rx_chan);
++}
++
++static int sun8i_dsp_rproc_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct device *dev = &pdev->dev;
++      struct sun8i_dsp_rproc *dsp;
++      const char *firmware_name;
++      struct rproc *rproc;
++      int i, ret;
++      u32 freq;
++
++      firmware_name = NULL;
++      of_property_read_string(np, "firmware-name", &firmware_name);
++      rproc = devm_rproc_alloc(dev, dev_name(dev), &sun8i_dsp_rproc_ops,
++                               firmware_name, sizeof(struct sun8i_dsp_rproc));
++      if (!rproc)
++              return -ENOMEM;
++
++      dev_set_drvdata(dev, rproc);
++      dsp = rproc->priv;
++
++      i = of_property_match_string(np, "reg-names", "cfg");
++      if (i < 0)
++              return -EINVAL;
++
++      dsp->cfg_base = devm_platform_ioremap_resource(pdev, i);
++      if (IS_ERR(dsp->cfg_base))
++              return dev_err_probe(dev, PTR_ERR(dsp->cfg_base),
++                                   "Failed to map cfg\n");
++
++      dsp->cfg_clk = devm_clk_get(dev, "cfg");
++      if (IS_ERR(dsp->cfg_clk))
++              return dev_err_probe(dev, PTR_ERR(dsp->cfg_clk),
++                                   "Failed to get %s clock\n", "cfg");
++
++      dsp->cfg_reset = devm_reset_control_get_exclusive(dev, "cfg");
++      if (IS_ERR(dsp->cfg_reset))
++              return dev_err_probe(dev, PTR_ERR(dsp->cfg_reset),
++                                   "Failed to get %s reset\n", "cfg");
++
++      dsp->cfg_reset = devm_reset_control_get_exclusive(dev, "dbg");
++      if (IS_ERR(dsp->cfg_reset))
++              return dev_err_probe(dev, PTR_ERR(dsp->cfg_reset),
++                                   "Failed to get %s reset\n", "dbg");
++
++      dsp->dsp_clk = devm_clk_get(dev, "dsp");
++      if (IS_ERR(dsp->dsp_clk))
++              return dev_err_probe(dev, PTR_ERR(dsp->dsp_clk),
++                                   "Failed to get %s clock\n", "dsp");
++
++      freq = SUN8I_DSP_CLK_FREQ;
++      of_property_read_u32(np, "clock-frequency", &freq);
++      ret = clk_set_rate(dsp->dsp_clk, freq);
++      if (ret)
++              return dev_err_probe(dev, ret,
++                                   "Failed to set clock frequency\n");
++
++      dsp->dsp_reset = devm_reset_control_get_exclusive(dev, "dsp");
++      if (IS_ERR(dsp->dsp_reset))
++              return dev_err_probe(dev, PTR_ERR(dsp->dsp_reset),
++                                   "Failed to get %s reset\n", "dsp");
++
++      dsp->client.dev = dev;
++      dsp->client.rx_callback = sun8i_dsp_rproc_mbox_rx_callback;
++
++      ret = devm_add_action(dev, sun8i_dsp_rproc_mbox_free, dsp);
++      if (ret)
++              return ret;
++
++      dsp->rx_chan = mbox_request_channel_byname(&dsp->client, "rx");
++      if (IS_ERR(dsp->rx_chan))
++              return dev_err_probe(dev, PTR_ERR(dsp->rx_chan),
++                                   "Failed to request RX channel\n");
++
++      dsp->tx_chan = mbox_request_channel_byname(&dsp->client, "tx");
++      if (IS_ERR(dsp->tx_chan))
++              return dev_err_probe(dev, PTR_ERR(dsp->tx_chan),
++                                   "Failed to request TX channel\n");
++
++      ret = devm_rproc_add(dev, rproc);
++      if (ret)
++              return dev_err_probe(dev, ret, "Failed to register rproc\n");
++
++      return 0;
++}
++
++static const struct of_device_id sun8i_dsp_rproc_of_match[] = {
++      { .compatible = "allwinner,sun20i-d1-dsp" },
++      {}
++};
++MODULE_DEVICE_TABLE(of, sun8i_dsp_rproc_of_match);
++
++static struct platform_driver sun8i_dsp_rproc_driver = {
++      .probe          = sun8i_dsp_rproc_probe,
++      .driver         = {
++              .name           = "sun8i-dsp-rproc",
++              .of_match_table = sun8i_dsp_rproc_of_match,
++      },
++};
++module_platform_driver(sun8i_dsp_rproc_driver);
++
++MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
++MODULE_DESCRIPTION("Allwinner sun8i DSP remoteproc driver");
++MODULE_LICENSE("GPL");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0098-rtc-sun6i-Add-support-for-linear-day-storage.patch b/target/linux/sunxid1/patches-5.15/0098-rtc-sun6i-Add-support-for-linear-day-storage.patch
new file mode 100644 (file)
index 0000000..1409ce5
--- /dev/null
@@ -0,0 +1,126 @@
+From 6d3665651113e11ec7f8e6e24f471376064d23d2 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 26 Feb 2021 10:27:51 +0000
+Subject: [PATCH 098/124] rtc: sun6i: Add support for linear day storage
+
+Newer versions of the Allwinner RTC, as for instance found in the H616
+SoC, no longer store a broken-down day/month/year representation in the
+RTC_DAY_REG, but just a linear day number.
+The user manual does not give any indication about the expected epoch
+time of this day count, but the BSP kernel uses the UNIX epoch, which
+allows easy support due to existing conversion functions in the kernel.
+
+Allow tagging a compatible string with a flag, and use that to mark
+those new RTCs. Then convert between a UNIX day number (converted into
+seconds) and the broken-down day representation using mktime64() and
+time64_to_tm() in the set_time/get_time functions.
+
+That enables support for the RTC in those new chips.
+
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/rtc/rtc-sun6i.c | 58 +++++++++++++++++++++++++++++------------
+ 1 file changed, 41 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index 4358cde143d4..1d2a72438bcf 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -134,12 +134,15 @@ struct sun6i_rtc_clk_data {
+       unsigned int has_auto_swt : 1;
+ };
++#define RTC_LINEAR_DAY        BIT(0)
++
+ struct sun6i_rtc_dev {
+       struct rtc_device *rtc;
+       const struct sun6i_rtc_clk_data *data;
+       void __iomem *base;
+       int irq;
+       unsigned long alarm;
++      unsigned long flags;
+       struct clk_hw hw;
+       struct clk_hw *int_osc;
+@@ -455,17 +458,30 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+       rtc_tm->tm_min  = SUN6I_TIME_GET_MIN_VALUE(time);
+       rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time);
+-      rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date);
+-      rtc_tm->tm_mon  = SUN6I_DATE_GET_MON_VALUE(date);
+-      rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date);
+-
+-      rtc_tm->tm_mon  -= 1;
+-
+-      /*
+-       * switch from (data_year->min)-relative offset to
+-       * a (1900)-relative one
+-       */
+-      rtc_tm->tm_year += SUN6I_YEAR_OFF;
++      if (chip->flags & RTC_LINEAR_DAY) {
++              struct tm tm;
++
++              /*
++               * Newer chips store a linear day number, the manual
++               * does not mandate any epoch base. The BSP driver uses
++               * the UNIX epoch, let's just copy that, as it's the
++               * easiest anyway.
++               */
++              time64_to_tm((date & 0xffff) * 3600ULL * 24, 0, &tm);
++              rtc_tm->tm_mday = tm.tm_mday;
++              rtc_tm->tm_mon  = tm.tm_mon;
++              rtc_tm->tm_year = tm.tm_year;
++      } else {
++              rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date);
++              rtc_tm->tm_mon  = SUN6I_DATE_GET_MON_VALUE(date) - 1;
++              rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date);
++
++              /*
++               * switch from (data_year->min)-relative offset to
++               * a (1900)-relative one
++               */
++              rtc_tm->tm_year += SUN6I_YEAR_OFF;
++      }
+       return 0;
+ }
+@@ -555,15 +571,21 @@ static int sun6i_rtc_settime(struct device *dev, struct rtc_time *rtc_tm)
+       u32 date = 0;
+       u32 time = 0;
+-      rtc_tm->tm_year -= SUN6I_YEAR_OFF;
+       rtc_tm->tm_mon += 1;
+-      date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) |
+-              SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon)  |
+-              SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year);
++      if (chip->flags & RTC_LINEAR_DAY) {
++              date = mktime64(rtc_tm->tm_year + 1900, rtc_tm->tm_mon,
++                              rtc_tm->tm_mday, 0, 0, 0) / (3600ULL * 24);
++      } else {
++              rtc_tm->tm_year -= SUN6I_YEAR_OFF;
++
++              date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) |
++                      SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon)  |
++                      SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year);
+-      if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN))
+-              date |= SUN6I_LEAP_SET_VALUE(1);
++              if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN))
++                      date |= SUN6I_LEAP_SET_VALUE(1);
++      }
+       time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec)  |
+               SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min)  |
+@@ -677,6 +699,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
+       platform_set_drvdata(pdev, chip);
++      chip->flags = (unsigned long)of_device_get_match_data(&pdev->dev);
++
+       chip->irq = platform_get_irq(pdev, 0);
+       if (chip->irq < 0)
+               return chip->irq;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0099-rtc-sun6i-Add-Allwinner-H616-support.patch b/target/linux/sunxid1/patches-5.15/0099-rtc-sun6i-Add-Allwinner-H616-support.patch
new file mode 100644 (file)
index 0000000..cdd3e59
--- /dev/null
@@ -0,0 +1,30 @@
+From a502296b25fd6244b196f49409aecdf5050304e5 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Wed, 21 Apr 2021 12:46:43 +0100
+Subject: [PATCH 099/124] rtc: sun6i: Add Allwinner H616 support
+
+The H616 RTC changes its day storage to the newly introduced linear day
+scheme, so pair the new compatible string with this feature flag.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/rtc/rtc-sun6i.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index 1d2a72438bcf..e067082df356 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -772,6 +772,8 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
+       { .compatible = "allwinner,sun8i-v3-rtc" },
+       { .compatible = "allwinner,sun50i-h5-rtc" },
+       { .compatible = "allwinner,sun50i-h6-rtc" },
++      { .compatible = "allwinner,sun50i-h616-rtc",
++              .data = (void *)RTC_LINEAR_DAY },
+       { /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0100-rtc-sun6i-Add-Allwinner-D1-support.patch b/target/linux/sunxid1/patches-5.15/0100-rtc-sun6i-Add-Allwinner-D1-support.patch
new file mode 100644 (file)
index 0000000..b5c2478
--- /dev/null
@@ -0,0 +1,26 @@
+From 121b5566f4642b44b396a3221b6a3cfdfdf46f7d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 21:51:03 -0500
+Subject: [PATCH 100/124] rtc: sun6i: Add Allwinner D1 support
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/rtc/rtc-sun6i.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
+index e067082df356..c966dea4394e 100644
+--- a/drivers/rtc/rtc-sun6i.c
++++ b/drivers/rtc/rtc-sun6i.c
+@@ -774,6 +774,8 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
+       { .compatible = "allwinner,sun50i-h6-rtc" },
+       { .compatible = "allwinner,sun50i-h616-rtc",
+               .data = (void *)RTC_LINEAR_DAY },
++      { .compatible = "allwinner,sun20i-d1-rtc",
++              .data = (void *)RTC_LINEAR_DAY },
+       { /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0101-soc-sunxi-sram-Actually-marked-claimed-regions-as-cl.patch b/target/linux/sunxid1/patches-5.15/0101-soc-sunxi-sram-Actually-marked-claimed-regions-as-cl.patch
new file mode 100644 (file)
index 0000000..352f325
--- /dev/null
@@ -0,0 +1,26 @@
+From 233da064f08769f760c7ceaa708791ec7687f8c8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 19 Jan 2020 15:52:21 -0600
+Subject: [PATCH 101/124] soc: sunxi: sram: Actually marked claimed regions as
+ claimed
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index a8f3876963a0..f3d3f9259df9 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -254,6 +254,7 @@ int sunxi_sram_claim(struct device *dev)
+       writel(val | ((device << sram_data->offset) & mask),
+              base + sram_data->reg);
++      sram_desc->claimed = true;
+       spin_unlock(&sram_lock);
+       return 0;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0102-soc-sunxi-sram-Map-SRAM-back-to-CPU-on-release.patch b/target/linux/sunxid1/patches-5.15/0102-soc-sunxi-sram-Map-SRAM-back-to-CPU-on-release.patch
new file mode 100644 (file)
index 0000000..b1f3e9a
--- /dev/null
@@ -0,0 +1,45 @@
+From 08c2a7e1ffff8ff09f7159e8eeab246a6ee1220b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 11 Jul 2021 10:56:17 -0500
+Subject: [PATCH 102/124] soc: sunxi: sram: Map SRAM back to CPU on release
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index f3d3f9259df9..bb8d8d44a621 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -265,17 +265,26 @@ int sunxi_sram_release(struct device *dev)
+ {
+       const struct sunxi_sram_data *sram_data;
+       struct sunxi_sram_desc *sram_desc;
++      unsigned int device;
++      u32 val, mask;
+       if (!dev || !dev->of_node)
+               return -EINVAL;
+-      sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
++      sram_data = sunxi_sram_of_parse(dev->of_node, &device);
+       if (IS_ERR(sram_data))
+               return -EINVAL;
+       sram_desc = to_sram_desc(sram_data);
+       spin_lock(&sram_lock);
++      mask = GENMASK(sram_data->offset + sram_data->width - 1,
++                     sram_data->offset);
++      val = readl(base + sram_data->reg);
++      val &= ~mask;
++      writel(val | ((~device << sram_data->offset) & mask),
++             base + sram_data->reg);
++
+       sram_desc->claimed = false;
+       spin_unlock(&sram_lock);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0103-soc-sunxi-sram-Fix-debugfs-file-leak.patch b/target/linux/sunxid1/patches-5.15/0103-soc-sunxi-sram-Fix-debugfs-file-leak.patch
new file mode 100644 (file)
index 0000000..3b72b41
--- /dev/null
@@ -0,0 +1,71 @@
+From 16e90c44a87be00a2727d745f8dfe1b29dd93300 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:47:08 -0500
+Subject: [PATCH 103/124] soc: sunxi: sram: Fix debugfs file leak
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index bb8d8d44a621..6fb8c6de8c91 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -106,6 +106,7 @@ static struct device *sram_dev;
+ static LIST_HEAD(claimed_sram);
+ static DEFINE_SPINLOCK(sram_lock);
+ static void __iomem *base;
++static struct dentry *debugfs_dir;
+ static int sunxi_sram_show(struct seq_file *s, void *data)
+ {
+@@ -341,7 +342,6 @@ static struct regmap_config sunxi_sram_emac_clock_regmap = {
+ static int sunxi_sram_probe(struct platform_device *pdev)
+ {
+-      struct dentry *d;
+       struct regmap *emac_clock;
+       const struct sunxi_sramc_variant *variant;
+@@ -357,11 +357,6 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+       of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+-      d = debugfs_create_file("sram", S_IRUGO, NULL, NULL,
+-                              &sunxi_sram_fops);
+-      if (!d)
+-              return -ENOMEM;
+-
+       if (variant->num_emac_clocks > 0) {
+               emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
+                                                  &sunxi_sram_emac_clock_regmap);
+@@ -370,6 +365,17 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+                       return PTR_ERR(emac_clock);
+       }
++      debugfs_dir = debugfs_create_dir("sunxi-sram", NULL);
++      debugfs_create_file("sram", S_IRUGO, debugfs_dir, NULL,
++                          &sunxi_sram_fops);
++
++      return 0;
++}
++
++static int sunxi_sram_remove(struct platform_device *pdev)
++{
++      debugfs_remove(debugfs_dir);
++
+       return 0;
+ }
+@@ -420,6 +426,7 @@ static struct platform_driver sunxi_sram_driver = {
+               .of_match_table = sunxi_sram_dt_match,
+       },
+       .probe  = sunxi_sram_probe,
++      .remove = sunxi_sram_remove,
+ };
+ module_platform_driver(sunxi_sram_driver);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0104-soc-sunxi-sram-Use-devm_of_platform_populate.patch b/target/linux/sunxid1/patches-5.15/0104-soc-sunxi-sram-Use-devm_of_platform_populate.patch
new file mode 100644 (file)
index 0000000..42213fd
--- /dev/null
@@ -0,0 +1,45 @@
+From acd63d88d3461bacd505de88dc66c5ae2f313de2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:48:49 -0500
+Subject: [PATCH 104/124] soc: sunxi: sram: Use devm_of_platform_populate
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index 6fb8c6de8c91..17b89b5a8e6e 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -344,6 +344,7 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+ {
+       struct regmap *emac_clock;
+       const struct sunxi_sramc_variant *variant;
++      int ret;
+       sram_dev = &pdev->dev;
+@@ -355,8 +356,6 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+-      of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+-
+       if (variant->num_emac_clocks > 0) {
+               emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
+                                                  &sunxi_sram_emac_clock_regmap);
+@@ -365,6 +364,10 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+                       return PTR_ERR(emac_clock);
+       }
++      ret = devm_of_platform_populate(&pdev->dev);
++      if (ret)
++              return ret;
++
+       debugfs_dir = debugfs_create_dir("sunxi-sram", NULL);
+       debugfs_create_file("sram", S_IRUGO, debugfs_dir, NULL,
+                           &sunxi_sram_fops);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0105-soc-sunxi-sram-Add-support-for-D1-LDOs.patch b/target/linux/sunxid1/patches-5.15/0105-soc-sunxi-sram-Add-support-for-D1-LDOs.patch
new file mode 100644 (file)
index 0000000..c9ea1fe
--- /dev/null
@@ -0,0 +1,148 @@
+From 16cf89f5a45d680974614ec3847f3609e15de9ab Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:49:10 -0500
+Subject: [PATCH 105/124] soc: sunxi: sram: Add support for D1 LDOs
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 71 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 68 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index 17b89b5a8e6e..a82351220c04 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -18,9 +18,13 @@
+ #include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
++#include <linux/regulator/driver.h>
+ #include <linux/soc/sunxi/sunxi_sram.h>
++#define SUNXI_SRAM_EMAC_CLOCK_REG     0x30
++#define SUNXI_SYS_LDO_CTRL_REG                0x150
++
+ struct sunxi_sram_func {
+       char    *func;
+       u8      val;
+@@ -293,7 +297,47 @@ int sunxi_sram_release(struct device *dev)
+ }
+ EXPORT_SYMBOL(sunxi_sram_release);
++static const struct regulator_ops sunxi_ldo_ops = {
++      .list_voltage           = regulator_list_voltage_linear,
++      .map_voltage            = regulator_map_voltage_linear,
++      .set_voltage_sel        = regulator_set_voltage_sel_regmap,
++      .get_voltage_sel        = regulator_get_voltage_sel_regmap,
++};
++
++static const struct regulator_desc sun20i_d1_ldos[] = {
++      {
++              .name           = "ldoa",
++              .supply_name    = "ldo-in",
++              .of_match       = "ldoa",
++              .regulators_node = "regulators",
++              .ops            = &sunxi_ldo_ops,
++              .type           = REGULATOR_VOLTAGE,
++              .owner          = THIS_MODULE,
++              .n_voltages     = BIT(5),
++              .min_uV         = 1600005, /* nominally 1.8 V */
++              .uV_step        = 13333,
++              .vsel_reg       = SUNXI_SYS_LDO_CTRL_REG,
++              .vsel_mask      = GENMASK(7, 0),
++      },
++      {
++              .name           = "ldob",
++              .supply_name    = "ldo-in",
++              .of_match       = "ldob",
++              .regulators_node = "regulators",
++              .ops            = &sunxi_ldo_ops,
++              .type           = REGULATOR_VOLTAGE,
++              .owner          = THIS_MODULE,
++              .n_voltages     = BIT(6),
++              .min_uV         = 1166675, /* nominally 1.5 V */
++              .uV_step        = 13333,
++              .vsel_reg       = SUNXI_SYS_LDO_CTRL_REG,
++              .vsel_mask      = GENMASK(15, 8),
++      },
++};
++
+ struct sunxi_sramc_variant {
++      const struct regulator_desc *ldos;
++      int num_ldos;
+       int num_emac_clocks;
+ };
+@@ -305,6 +349,12 @@ static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = {
+       .num_emac_clocks = 1,
+ };
++static const struct sunxi_sramc_variant sun20i_d1_sramc_variant = {
++      .ldos = sun20i_d1_ldos,
++      .num_ldos = ARRAY_SIZE(sun20i_d1_ldos),
++      .num_emac_clocks = 1,
++};
++
+ static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
+       .num_emac_clocks = 1,
+ };
+@@ -313,7 +363,6 @@ static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = {
+       .num_emac_clocks = 2,
+ };
+-#define SUNXI_SRAM_EMAC_CLOCK_REG     0x30
+ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
+                                            unsigned int reg)
+ {
+@@ -321,6 +370,8 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
+       variant = of_device_get_match_data(dev);
++      if (reg == SUNXI_SYS_LDO_CTRL_REG)
++              return true;
+       if (reg < SUNXI_SRAM_EMAC_CLOCK_REG)
+               return false;
+       if (reg > SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
+@@ -334,7 +385,7 @@ static struct regmap_config sunxi_sram_emac_clock_regmap = {
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       /* last defined register */
+-      .max_register   = SUNXI_SRAM_EMAC_CLOCK_REG + 4,
++      .max_register   = SUNXI_SYS_LDO_CTRL_REG,
+       /* other devices have no business accessing other registers */
+       .readable_reg   = sunxi_sram_regmap_accessible_reg,
+       .writeable_reg  = sunxi_sram_regmap_accessible_reg,
+@@ -356,7 +407,7 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+-      if (variant->num_emac_clocks > 0) {
++      if (variant->num_ldos || variant->num_emac_clocks) {
+               emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
+                                                  &sunxi_sram_emac_clock_regmap);
+@@ -364,6 +415,20 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+                       return PTR_ERR(emac_clock);
+       }
++      if (variant->num_ldos) {
++              struct regulator_config config = { .dev = &pdev->dev };
++              struct regulator_dev *rdev;
++              int i;
++
++              for (i = 0; i < variant->num_ldos; ++i) {
++                      const struct regulator_desc *desc = &variant->ldos[i];
++
++                      rdev = devm_regulator_register(&pdev->dev, desc, &config);
++                      if (IS_ERR(rdev))
++                              return PTR_ERR(rdev);
++              }
++      }
++
+       ret = devm_of_platform_populate(&pdev->dev);
+       if (ret)
+               return ret;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0106-soc-sunxi-sram-Fix-debugfs-for-A64-SRAM-C.patch b/target/linux/sunxid1/patches-5.15/0106-soc-sunxi-sram-Fix-debugfs-for-A64-SRAM-C.patch
new file mode 100644 (file)
index 0000000..96e679e
--- /dev/null
@@ -0,0 +1,28 @@
+From 8278aabd7e8a85327973e770aafdffb7e767f32e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:46:04 -0500
+Subject: [PATCH 106/124] soc: sunxi: sram: Fix debugfs for A64 SRAM C
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index a82351220c04..8b5356ef04be 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -82,8 +82,8 @@ static struct sunxi_sram_desc sun4i_a10_sram_d = {
+ static struct sunxi_sram_desc sun50i_a64_sram_c = {
+       .data   = SUNXI_SRAM_DATA("C", 0x4, 24, 1,
+-                                SUNXI_SRAM_MAP(0, 1, "cpu"),
+-                                SUNXI_SRAM_MAP(1, 0, "de2")),
++                                SUNXI_SRAM_MAP(1, 0, "cpu"),
++                                SUNXI_SRAM_MAP(0, 1, "de2")),
+ };
+ static const struct of_device_id sunxi_sram_dt_ids[] = {
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0107-soc-sunxi-sram-Add-D1-DSP-SRAM.patch b/target/linux/sunxid1/patches-5.15/0107-soc-sunxi-sram-Add-D1-DSP-SRAM.patch
new file mode 100644 (file)
index 0000000..038aa44
--- /dev/null
@@ -0,0 +1,41 @@
+From d7dcb35564295be22f4cffb5cab335d6b75ad49d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:46:19 -0500
+Subject: [PATCH 107/124] soc: sunxi: sram: Add D1 DSP SRAM
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index 8b5356ef04be..49d5ba9f74ba 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -80,6 +80,12 @@ static struct sunxi_sram_desc sun4i_a10_sram_d = {
+                                 SUNXI_SRAM_MAP(1, 1, "usb-otg")),
+ };
++static struct sunxi_sram_desc sun20i_d1_dsp_sram = {
++      .data   = SUNXI_SRAM_DATA("DSP", 0x8, 0, 1,
++                                SUNXI_SRAM_MAP(1, 0, "cpu"),
++                                SUNXI_SRAM_MAP(0, 1, "dsp")),
++};
++
+ static struct sunxi_sram_desc sun50i_a64_sram_c = {
+       .data   = SUNXI_SRAM_DATA("C", 0x4, 24, 1,
+                                 SUNXI_SRAM_MAP(1, 0, "cpu"),
+@@ -99,6 +105,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
+               .compatible     = "allwinner,sun4i-a10-sram-d",
+               .data           = &sun4i_a10_sram_d.data,
+       },
++      {
++              .compatible     = "allwinner,sun20i-d1-dsp-sram",
++              .data           = &sun20i_d1_dsp_sram.data,
++      },
+       {
+               .compatible     = "allwinner,sun50i-a64-sram-c",
+               .data           = &sun50i_a64_sram_c.data,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0108-soc-sunxi-sram-Add-D1-syscon-variant.patch b/target/linux/sunxid1/patches-5.15/0108-soc-sunxi-sram-Add-D1-syscon-variant.patch
new file mode 100644 (file)
index 0000000..5b36ac5
--- /dev/null
@@ -0,0 +1,28 @@
+From a456c9424e9a3b092e2c8ad6e41b6f41c1a89b4f Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:46:45 -0500
+Subject: [PATCH 108/124] soc: sunxi: sram: Add D1 syscon variant
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/soc/sunxi/sunxi_sram.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index 49d5ba9f74ba..3f6118998f4e 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -478,6 +478,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = {
+               .compatible = "allwinner,sun8i-h3-system-control",
+               .data = &sun8i_h3_sramc_variant,
+       },
++      {
++              .compatible = "allwinner,sun20i-d1-system-control",
++              .data = &sun20i_d1_sramc_variant,
++      },
+       {
+               .compatible = "allwinner,sun50i-a64-sram-controller",
+               .data = &sun50i_a64_sramc_variant,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0109-spi-spi-sun6i-Use-a-struct-for-quirks.patch b/target/linux/sunxid1/patches-5.15/0109-spi-spi-sun6i-Use-a-struct-for-quirks.patch
new file mode 100644 (file)
index 0000000..53b37c5
--- /dev/null
@@ -0,0 +1,114 @@
+From 548fbde3da6fc700ec040e78a763470f5b844865 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 16 Jul 2021 21:33:16 -0500
+Subject: [PATCH 109/124] spi: spi-sun6i: Use a struct for quirks
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/spi/spi-sun6i.c | 32 ++++++++++++++++++++++----------
+ 1 file changed, 22 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
+index 23ad052528db..125fd3052db5 100644
+--- a/drivers/spi/spi-sun6i.c
++++ b/drivers/spi/spi-sun6i.c
+@@ -85,7 +85,12 @@
+ #define SUN6I_TXDATA_REG              0x200
+ #define SUN6I_RXDATA_REG              0x300
++struct sun6i_spi_quirks {
++      unsigned long           fifo_depth;
++};
++
+ struct sun6i_spi {
++      const struct sun6i_spi_quirks *quirks;
+       struct spi_master       *master;
+       void __iomem            *base_addr;
+       dma_addr_t              dma_addr_rx;
+@@ -99,7 +104,6 @@ struct sun6i_spi {
+       const u8                *tx_buf;
+       u8                      *rx_buf;
+       int                     len;
+-      unsigned long           fifo_depth;
+ };
+ static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
+@@ -156,7 +160,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
+       u8 byte;
+       /* See how much data we can fit */
+-      cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
++      cnt = sspi->quirks->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
+       len = min((int)cnt, sspi->len);
+@@ -289,14 +293,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
+                * the hardcoded value used in old generation of Allwinner
+                * SPI controller. (See spi-sun4i.c)
+                */
+-              trig_level = sspi->fifo_depth / 4 * 3;
++              trig_level = sspi->quirks->fifo_depth / 4 * 3;
+       } else {
+               /*
+                * Setup FIFO DMA request trigger level
+                * We choose 1/2 of the full fifo depth, that value will
+                * be used as DMA burst length.
+                */
+-              trig_level = sspi->fifo_depth / 2;
++              trig_level = sspi->quirks->fifo_depth / 2;
+               if (tfr->tx_buf)
+                       reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
+@@ -410,9 +414,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
+       reg = SUN6I_INT_CTL_TC;
+       if (!use_dma) {
+-              if (rx_len > sspi->fifo_depth)
++              if (rx_len > sspi->quirks->fifo_depth)
+                       reg |= SUN6I_INT_CTL_RF_RDY;
+-              if (tx_len > sspi->fifo_depth)
++              if (tx_len > sspi->quirks->fifo_depth)
+                       reg |= SUN6I_INT_CTL_TF_ERQ;
+       }
+@@ -543,7 +547,7 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
+        * the fifo length we can just fill the fifo and wait for a single
+        * irq, so don't bother setting up dma
+        */
+-      return xfer->len > sspi->fifo_depth;
++      return xfer->len > sspi->quirks->fifo_depth;
+ }
+ static int sun6i_spi_probe(struct platform_device *pdev)
+@@ -582,7 +586,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
+       }
+       sspi->master = master;
+-      sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev);
++      sspi->quirks = of_device_get_match_data(&pdev->dev);
+       master->max_speed_hz = 100 * 1000 * 1000;
+       master->min_speed_hz = 3 * 1000;
+@@ -696,9 +700,17 @@ static int sun6i_spi_remove(struct platform_device *pdev)
+       return 0;
+ }
++static const struct sun6i_spi_quirks sun6i_a31_spi_quirks = {
++      .fifo_depth             = SUN6I_FIFO_DEPTH,
++};
++
++static const struct sun6i_spi_quirks sun8i_h3_spi_quirks = {
++      .fifo_depth             = SUN8I_FIFO_DEPTH,
++};
++
+ static const struct of_device_id sun6i_spi_match[] = {
+-      { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH },
+-      { .compatible = "allwinner,sun8i-h3-spi",  .data = (void *)SUN8I_FIFO_DEPTH },
++      { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_quirks },
++      { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_quirks },
+       {}
+ };
+ MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0110-spi-spi-sun6i-Add-Allwinner-R329-support.patch b/target/linux/sunxid1/patches-5.15/0110-spi-spi-sun6i-Add-Allwinner-R329-support.patch
new file mode 100644 (file)
index 0000000..1f9b98a
--- /dev/null
@@ -0,0 +1,151 @@
+From da1ec11ed9fe9d7239506b84d06c48e31238e10e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 16 Jul 2021 21:46:31 -0500
+Subject: [PATCH 110/124] spi: spi-sun6i: Add Allwinner R329 support
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/spi/spi-sun6i.c | 78 ++++++++++++++++++++++++++---------------
+ 1 file changed, 49 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
+index 125fd3052db5..77a9e0646f3f 100644
+--- a/drivers/spi/spi-sun6i.c
++++ b/drivers/spi/spi-sun6i.c
+@@ -30,6 +30,7 @@
+ #define SUN6I_GBL_CTL_REG             0x04
+ #define SUN6I_GBL_CTL_BUS_ENABLE              BIT(0)
+ #define SUN6I_GBL_CTL_MASTER                  BIT(1)
++#define SUN6I_GBL_CTL_SAMPLE_MODE             BIT(2)
+ #define SUN6I_GBL_CTL_TP                      BIT(7)
+ #define SUN6I_GBL_CTL_RST                     BIT(31)
+@@ -87,6 +88,8 @@
+ struct sun6i_spi_quirks {
+       unsigned long           fifo_depth;
++      bool                    has_divider : 1;
++      bool                    has_new_sample_mode : 1;
+ };
+ struct sun6i_spi {
+@@ -351,38 +354,44 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
+       sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+       /* Ensure that we have a parent clock fast enough */
+-      mclk_rate = clk_get_rate(sspi->mclk);
+-      if (mclk_rate < (2 * tfr->speed_hz)) {
+-              clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
++      if (sspi->quirks->has_divider) {
+               mclk_rate = clk_get_rate(sspi->mclk);
+-      }
++              if (mclk_rate < (2 * tfr->speed_hz)) {
++                      clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
++                      mclk_rate = clk_get_rate(sspi->mclk);
++              }
+-      /*
+-       * Setup clock divider.
+-       *
+-       * We have two choices there. Either we can use the clock
+-       * divide rate 1, which is calculated thanks to this formula:
+-       * SPI_CLK = MOD_CLK / (2 ^ cdr)
+-       * Or we can use CDR2, which is calculated with the formula:
+-       * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+-       * Wether we use the former or the latter is set through the
+-       * DRS bit.
+-       *
+-       * First try CDR2, and if we can't reach the expected
+-       * frequency, fall back to CDR1.
+-       */
+-      div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
+-      div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
+-      if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+-              reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
+-              tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
++              /*
++               * Setup clock divider.
++               *
++               * We have two choices there. Either we can use the clock
++               * divide rate 1, which is calculated thanks to this formula:
++               * SPI_CLK = MOD_CLK / (2 ^ cdr)
++               * Or we can use CDR2, which is calculated with the formula:
++               * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
++               * Wether we use the former or the latter is set through the
++               * DRS bit.
++               *
++               * First try CDR2, and if we can't reach the expected
++               * frequency, fall back to CDR1.
++               */
++              div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
++              div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
++              if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
++                      reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
++                      tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
++              } else {
++                      div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
++                      reg = SUN6I_CLK_CTL_CDR1(div);
++                      tfr->effective_speed_hz = mclk_rate / (1 << div);
++              }
++              sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+       } else {
+-              div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
+-              reg = SUN6I_CLK_CTL_CDR1(div);
+-              tfr->effective_speed_hz = mclk_rate / (1 << div);
++              clk_set_rate(sspi->mclk, tfr->speed_hz);
++              mclk_rate = clk_get_rate(sspi->mclk);
++              tfr->effective_speed_hz = mclk_rate;
+       }
+-      sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+       /* Finally enable the bus - doing so before might raise SCK to HIGH */
+       reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
+       reg |= SUN6I_GBL_CTL_BUS_ENABLE;
+@@ -492,6 +501,7 @@ static int sun6i_spi_runtime_resume(struct device *dev)
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sun6i_spi *sspi = spi_master_get_devdata(master);
+       int ret;
++      u32 reg;
+       ret = clk_prepare_enable(sspi->hclk);
+       if (ret) {
+@@ -511,8 +521,10 @@ static int sun6i_spi_runtime_resume(struct device *dev)
+               goto err2;
+       }
+-      sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
+-                      SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
++      reg = SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP;
++      if (sspi->quirks->has_new_sample_mode)
++              reg |= SUN6I_GBL_CTL_SAMPLE_MODE;
++      sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
+       return 0;
+@@ -702,15 +714,23 @@ static int sun6i_spi_remove(struct platform_device *pdev)
+ static const struct sun6i_spi_quirks sun6i_a31_spi_quirks = {
+       .fifo_depth             = SUN6I_FIFO_DEPTH,
++      .has_divider            = true,
+ };
+ static const struct sun6i_spi_quirks sun8i_h3_spi_quirks = {
+       .fifo_depth             = SUN8I_FIFO_DEPTH,
++      .has_divider            = true,
++};
++
++static const struct sun6i_spi_quirks sun50i_r329_spi_quirks = {
++      .fifo_depth             = SUN8I_FIFO_DEPTH,
++      .has_new_sample_mode    = true,
+ };
+ static const struct of_device_id sun6i_spi_match[] = {
+       { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_quirks },
+       { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_quirks },
++      { .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_quirks },
+       {}
+ };
+ MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0111-spi-spi-sun6i-Dual-Quad-RX-Support.patch b/target/linux/sunxid1/patches-5.15/0111-spi-spi-sun6i-Dual-Quad-RX-Support.patch
new file mode 100644 (file)
index 0000000..50502a6
--- /dev/null
@@ -0,0 +1,55 @@
+From f45398824024d393f28667e96ad8c4203add0770 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 17 Jul 2021 11:19:29 -0500
+Subject: [PATCH 111/124] spi: spi-sun6i: Dual/Quad RX Support
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/spi/spi-sun6i.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
+index 77a9e0646f3f..a80ccf0973a8 100644
+--- a/drivers/spi/spi-sun6i.c
++++ b/drivers/spi/spi-sun6i.c
+@@ -82,6 +82,8 @@
+ #define SUN6I_XMIT_CNT_REG            0x34
+ #define SUN6I_BURST_CTL_CNT_REG               0x38
++#define SUN6I_BURST_CTL_CNT_QUAD_EN           BIT(29)
++#define SUN6I_BURST_CTL_CNT_DUAL_EN           BIT(28)
+ #define SUN6I_TXDATA_REG              0x200
+ #define SUN6I_RXDATA_REG              0x300
+@@ -404,7 +406,17 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
+       /* Setup the counters */
+       sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len);
+       sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len);
+-      sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
++
++      reg = tx_len;
++      switch (tfr->rx_nbits) {
++      case SPI_NBITS_QUAD:
++              reg |= SUN6I_BURST_CTL_CNT_QUAD_EN;
++              break;
++      case SPI_NBITS_DUAL:
++              reg |= SUN6I_BURST_CTL_CNT_DUAL_EN;
++              break;
++      }
++      sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, reg);
+       if (!use_dma) {
+               /* Fill the TX FIFO */
+@@ -606,7 +618,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
+       master->set_cs = sun6i_spi_set_cs;
+       master->transfer_one = sun6i_spi_transfer_one;
+       master->num_chipselect = 4;
+-      master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
++      master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST
++                        | SPI_RX_DUAL | SPI_RX_QUAD;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->dev.of_node = pdev->dev.of_node;
+       master->auto_runtime_pm = true;
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0112-thermal-of-Remove-duplicate-null-check.patch b/target/linux/sunxid1/patches-5.15/0112-thermal-of-Remove-duplicate-null-check.patch
new file mode 100644 (file)
index 0000000..8f89890
--- /dev/null
@@ -0,0 +1,28 @@
+From 3b46883dc7c1f51aeca6b189121eef5f43560e82 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 23 Jun 2021 20:25:05 -0500
+Subject: [PATCH 112/124] thermal/of: Remove duplicate null check
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/thermal/thermal_of.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
+index 6379f26a335f..3d1527ba003f 100644
+--- a/drivers/thermal/thermal_of.c
++++ b/drivers/thermal/thermal_of.c
+@@ -555,10 +555,6 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
+       tz = tzd->devdata;
+-      /* no __thermal_zone, nothing to be done */
+-      if (!tz)
+-              return;
+-
+       /* stop temperature polling */
+       thermal_zone_device_disable(tzd);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0113-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch b/target/linux/sunxid1/patches-5.15/0113-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch
new file mode 100644 (file)
index 0000000..5ad4575
--- /dev/null
@@ -0,0 +1,25 @@
+From 875adee436d43269aa11d98c0396dc298407975a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:50:57 -0500
+Subject: [PATCH 113/124] ASoC: sun4i-i2s: Also set capture DMA width
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-i2s.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
+index 7047f71629ab..75075acc8658 100644
+--- a/sound/soc/sunxi/sun4i-i2s.c
++++ b/sound/soc/sunxi/sun4i-i2s.c
+@@ -631,6 +631,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
+                       params_physical_width(params));
+               return -EINVAL;
+       }
++      i2s->capture_dma_data.addr_width = width;
+       i2s->playback_dma_data.addr_width = width;
+       sr = i2s->variant->get_sr(word_size);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0114-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch b/target/linux/sunxid1/patches-5.15/0114-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch
new file mode 100644 (file)
index 0000000..c128805
--- /dev/null
@@ -0,0 +1,39 @@
+From 7794f47389db9147af69e4a7aa07902d25547827 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:52:47 -0500
+Subject: [PATCH 114/124] ASoC: sun4i-spdif: Add support for separate resets
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun4i-spdif.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
+index 7c6d596da84f..ecbe8e51b9a5 100644
+--- a/sound/soc/sunxi/sun4i-spdif.c
++++ b/sound/soc/sunxi/sun4i-spdif.c
+@@ -26,10 +26,11 @@
+ #include <sound/soc.h>
+ #define       SUN4I_SPDIF_CTL         (0x00)
++      #define SUN4I_SPDIF_CTL_RST_RX                  BIT(12)
+       #define SUN4I_SPDIF_CTL_MCLKDIV(v)              ((v) << 4) /* v even */
+       #define SUN4I_SPDIF_CTL_MCLKOUTEN               BIT(2)
+       #define SUN4I_SPDIF_CTL_GEN                     BIT(1)
+-      #define SUN4I_SPDIF_CTL_RESET                   BIT(0)
++      #define SUN4I_SPDIF_CTL_RST_TX                  BIT(0)
+ #define SUN4I_SPDIF_TXCFG     (0x04)
+       #define SUN4I_SPDIF_TXCFG_SINGLEMOD             BIT(31)
+@@ -193,7 +194,7 @@ static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
+       const struct sun4i_spdif_quirks *quirks = host->quirks;
+       /* soft reset SPDIF */
+-      regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
++      regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RST_TX);
+       /* flush TX FIFO */
+       regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0115-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch b/target/linux/sunxid1/patches-5.15/0115-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch
new file mode 100644 (file)
index 0000000..f22d644
--- /dev/null
@@ -0,0 +1,990 @@
+From bcf8b842b5cfeeccb52acade92c4b0318a9eaf68 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 12 Jun 2021 23:42:48 -0500
+Subject: [PATCH 115/124] ASoC: sun20i-codec: New driver for D1 internal codec
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/Kconfig        |   6 +
+ sound/soc/sunxi/Makefile       |   1 +
+ sound/soc/sunxi/sun20i-codec.c | 939 +++++++++++++++++++++++++++++++++
+ 3 files changed, 946 insertions(+)
+ create mode 100644 sound/soc/sunxi/sun20i-codec.c
+
+diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
+index ddcaaa98d3cb..c4ef1f41b244 100644
+--- a/sound/soc/sunxi/Kconfig
++++ b/sound/soc/sunxi/Kconfig
+@@ -30,6 +30,12 @@ config SND_SUN8I_CODEC_ANALOG
+         Say Y or M if you want to add support for the analog controls for
+         the codec embedded in newer Allwinner SoCs.
++config SND_SUN20I_CODEC
++      tristate "Allwinner D1 (sun20i) Audio Codec"
++      depends on ARCH_SUNXI || COMPILE_TEST
++      help
++        Say Y or M to add support for the audio codec in Allwinner D1 SoC.
++
+ config SND_SUN50I_CODEC_ANALOG
+       tristate "Allwinner sun50i Codec Analog Controls Support"
+       depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
+index a86be340a076..7bbe2526e16e 100644
+--- a/sound/soc/sunxi/Makefile
++++ b/sound/soc/sunxi/Makefile
+@@ -3,6 +3,7 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
+ obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
+ obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
+ obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
++obj-$(CONFIG_SND_SUN20I_CODEC) += sun20i-codec.o
+ obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o
+ obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
+ obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o
+diff --git a/sound/soc/sunxi/sun20i-codec.c b/sound/soc/sunxi/sun20i-codec.c
+new file mode 100644
+index 000000000000..f99e81f93a1b
+--- /dev/null
++++ b/sound/soc/sunxi/sun20i-codec.c
+@@ -0,0 +1,939 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/regulator/driver.h>
++#include <linux/reset.h>
++
++#include <sound/dmaengine_pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/simple_card_utils.h>
++#include <sound/soc.h>
++#include <sound/soc-dai.h>
++#include <sound/soc-dapm.h>
++#include <sound/tlv.h>
++
++#define SUN20I_CODEC_DAC_DPC          0x0000
++#define SUN20I_CODEC_DAC_DPC_EN_DA            31
++#define SUN20I_CODEC_DAC_DPC_HPF_EN           18
++#define SUN20I_CODEC_DAC_DPC_DVOL             12
++#define SUN20I_CODEC_DAC_VOL_CTRL     0x0004
++#define SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_SEL 16
++#define SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_L   8
++#define SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_R   0
++#define SUN20I_CODEC_DAC_FIFOC                0x0010
++#define SUN20I_CODEC_DAC_FIFOC_FS             29
++#define SUN20I_CODEC_DAC_FIFOC_FIFO_MODE      24
++#define SUN20I_CODEC_DAC_FIFOC_DRQ_CLR_CNT    21
++#define SUN20I_CODEC_DAC_FIFOC_TRIG_LEVEL     8
++#define SUN20I_CODEC_DAC_FIFOC_MONO_EN                6
++#define SUN20I_CODEC_DAC_FIFOC_SAMPLE_BITS    5
++#define SUN20I_CODEC_DAC_FIFOC_DRQ_EN         4
++#define SUN20I_CODEC_DAC_FIFOC_FIFO_FLUSH     0
++#define SUN20I_CODEC_DAC_TXDATA               0x0020
++#define SUN20I_CODEC_DAC_DEBUG                0x0028
++#define SUN20I_CODEC_DAC_DEBUG_DA_SWP         6
++#define SUN20I_CODEC_DAC_ADDA_LOOP_MODE               0
++
++#define SUN20I_CODEC_ADC_FIFOC                0x0030
++#define SUN20I_CODEC_ADC_FIFOC_FS             29
++#define SUN20I_CODEC_ADC_FIFOC_EN_AD          28
++#define SUN20I_CODEC_ADC_FIFOC_FIFO_MODE      24
++#define SUN20I_CODEC_ADC_FIFOC_SAMPLE_BITS    16
++#define SUN20I_CODEC_ADC_FIFOC_TRIG_LEVEL     4
++#define SUN20I_CODEC_ADC_FIFOC_DRQ_EN         3
++#define SUN20I_CODEC_ADC_FIFOC_FIFO_FLUSH     0
++#define SUN20I_CODEC_ADC_VOL_CTRL     0x0034
++#define SUN20I_CODEC_ADC_VOL_CTRL_ADC3_VOL    16
++#define SUN20I_CODEC_ADC_VOL_CTRL_ADC2_VOL    8
++#define SUN20I_CODEC_ADC_VOL_CTRL_ADC1_VOL    0
++#define SUN20I_CODEC_ADC_RXDATA               0x0040
++#define SUN20I_CODEC_ADC_DEBUG                0x004c
++#define SUN20I_CODEC_ADC_DEBUG_AD_SWP1                24
++#define SUN20I_CODEC_ADC_DIG_CTRL     0x0050
++#define SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN  16
++#define SUN20I_CODEC_ADC_DIG_CTRL_ADC_EN      0
++
++#define SUN20I_CODEC_DAC_DAP_CTRL     0x00f0
++#define SUN20I_CODEC_DAC_DAP_CTRL_DAP_EN      31
++#define SUN20I_CODEC_DAC_DAP_CTRL_DAP_DRC_EN  29
++#define SUN20I_CODEC_DAC_DAP_CTRL_DAP_HPF_EN  28
++
++#define SUN20I_CODEC_ADC_DAP_CTRL     0x00f8
++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP0_EN     31
++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP0_DRC_EN 29
++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP0_HPF_EN 28
++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP1_EN     27
++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP1_DRC_EN 25
++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP1_HPF_EN 24
++
++#define SUN20I_CODEC_ADC1             0x0300
++#define SUN20I_CODEC_ADC1_ADC1_EN             31
++#define SUN20I_CODEC_ADC1_MICIN1_PGA_EN               30
++#define SUN20I_CODEC_ADC1_ADC1_DITHER_EN      29
++#define SUN20I_CODEC_ADC1_MICIN1_SIN_EN               28
++#define SUN20I_CODEC_ADC1_FMINL_EN            27
++#define SUN20I_CODEC_ADC1_FMINL_GAIN          26
++#define SUN20I_CODEC_ADC1_DITHER_LEVEL                24
++#define SUN20I_CODEC_ADC1_LINEINL_EN          23
++#define SUN20I_CODEC_ADC1_LINEINL_GAIN                22
++#define SUN20I_CODEC_ADC1_ADC1_PGA_GAIN               8
++#define SUN20I_CODEC_ADC2             0x0304
++#define SUN20I_CODEC_ADC2_ADC2_EN             31
++#define SUN20I_CODEC_ADC2_MICIN2_PGA_EN               30
++#define SUN20I_CODEC_ADC2_ADC2_DITHER_EN      29
++#define SUN20I_CODEC_ADC2_MICIN2_SIN_EN               28
++#define SUN20I_CODEC_ADC2_FMINR_EN            27
++#define SUN20I_CODEC_ADC2_FMINR_GAIN          26
++#define SUN20I_CODEC_ADC2_DITHER_LEVEL                24
++#define SUN20I_CODEC_ADC2_LINEINR_EN          23
++#define SUN20I_CODEC_ADC2_LINEINR_GAIN                22
++#define SUN20I_CODEC_ADC2_ADC2_PGA_GAIN               8
++#define SUN20I_CODEC_ADC3             0x0308
++#define SUN20I_CODEC_ADC3_ADC3_EN             31
++#define SUN20I_CODEC_ADC3_MICIN3_PGA_EN               30
++#define SUN20I_CODEC_ADC3_ADC3_DITHER_EN      29
++#define SUN20I_CODEC_ADC3_MICIN3_SIN_EN               28
++#define SUN20I_CODEC_ADC3_DITHER_LEVEL                24
++#define SUN20I_CODEC_ADC3_ADC3_PGA_GAIN               8
++
++#define SUN20I_CODEC_DAC              0x0310
++#define SUN20I_CODEC_DAC_DACL_EN              15
++#define SUN20I_CODEC_DAC_DACR_EN              14
++#define SUN20I_CODEC_DAC_LINEOUTL_EN          13
++#define SUN20I_CODEC_DAC_LMUTE                        12
++#define SUN20I_CODEC_DAC_LINEOUTR_EN          11
++#define SUN20I_CODEC_DAC_RMUTE                        10
++#define SUN20I_CODEC_DAC_LINEOUTL_DIFFEN      6
++#define SUN20I_CODEC_DAC_LINEOUTR_DIFFEN      5
++#define SUN20I_CODEC_DAC_LINEOUT_VOL_CTRL     0
++
++#define SUN20I_CODEC_MICBIAS          0x0318
++#define SUN20I_CODEC_MICBIAS_SELDETADCFS      28
++#define SUN20I_CODEC_MICBIAS_SELDETADCDB      26
++#define SUN20I_CODEC_MICBIAS_SELDETADCBF      24
++#define SUN20I_CODEC_MICBIAS_JACKDETEN                23
++#define SUN20I_CODEC_MICBIAS_SELDETADCDY      21
++#define SUN20I_CODEC_MICBIAS_MICADCEN         20
++#define SUN20I_CODEC_MICBIAS_POPFREE          19
++#define SUN20I_CODEC_MICBIAS_DET_MODE         18
++#define SUN20I_CODEC_MICBIAS_AUTOPLEN         17
++#define SUN20I_CODEC_MICBIAS_MICDETPL         16
++#define SUN20I_CODEC_MICBIAS_HMICBIASEN               15
++#define SUN20I_CODEC_MICBIAS_HMICBIASSEL      13
++#define SUN20I_CODEC_MICBIAS_HMIC_CHOPPER_EN  12
++#define SUN20I_CODEC_MICBIAS_HMIC_CHOPPER_CLK 10
++#define SUN20I_CODEC_MICBIAS_MMICBIASEN               7
++#define SUN20I_CODEC_MICBIAS_MMICBIASSEL      5
++#define SUN20I_CODEC_MICBIAS_MMIC_CHOPPER_EN  4
++#define SUN20I_CODEC_MICBIAS_MMIC_CHOPPER_CLK 2
++
++/* TODO */
++#define SUN20I_CODEC_RAMP             0x031c
++#define SUN20I_CODEC_RAMP_HP_PULL_OUT_EN      15
++
++#define SUN20I_CODEC_HMIC_CTRL                0x0328
++#define SUN20I_CODEC_HMIC_CTRL_SAMPLE_SELECT  21
++#define SUN20I_CODEC_HMIC_CTRL_MDATA_THRESHOLD        16
++#define SUN20I_CODEC_HMIC_CTRL_SF             14
++#define SUN20I_CODEC_HMIC_CTRL_M              10
++#define SUN20I_CODEC_HMIC_CTRL_N              6
++#define SUN20I_CODEC_HMIC_CTRL_THRESH_DEBOUNCE        3
++#define SUN20I_CODEC_HMIC_CTRL_JACK_OUT_IRQ_EN        2
++#define SUN20I_CODEC_HMIC_CTRL_JACK_IN_IRQ_EN 1
++#define SUN20I_CODEC_HMIC_CTRL_MIC_DET_IRQ_EN 0
++#define SUN20I_CODEC_HMIC_STS         0x032c
++#define SUN20I_CODEC_HMIC_STS_MDATA_DISCARD   13
++#define SUN20I_CODEC_HMIC_STS_HMIC_DATA               8
++#define SUN20I_CODEC_HMIC_STS_JACK_OUT_IRQ    4
++#define SUN20I_CODEC_HMIC_STS_JACK_IN_IRQ     3
++#define SUN20I_CODEC_HMIC_STS_MIC_DET_IRQ     0
++
++#define SUN20I_CODEC_HP2              0x0340
++#define SUN20I_CODEC_HP2_HPFB_BUF_EN          31
++#define SUN20I_CODEC_HP2_HEADPHONE_GAIN               28
++#define SUN20I_CODEC_HP2_HPFB_RES             26
++#define SUN20I_CODEC_HP2_HP_DRVEN             21
++#define SUN20I_CODEC_HP2_HP_DRVOUTEN          20
++#define SUN20I_CODEC_HP2_RSWITCH              19
++#define SUN20I_CODEC_HP2_RAMPEN                       18
++#define SUN20I_CODEC_HP2_HPFB_IN_EN           17
++#define SUN20I_CODEC_HP2_RAMP_FINAL_CONTROL   16
++#define SUN20I_CODEC_HP2_RAMP_OUT_EN          15
++#define SUN20I_CODEC_HP2_RAMP_FINAL_STATE_RES 13
++
++/* Not affected by codec bus clock/reset */
++#define SUN20I_CODEC_POWER            0x0348
++#define SUN20I_CODEC_POWER_ALDO_EN_MASK               BIT(31)
++#define SUN20I_CODEC_POWER_HPLDO_EN_MASK      BIT(30)
++#define SUN20I_CODEC_POWER_ALDO_VOLTAGE_MASK  GENMASK(14, 12)
++#define SUN20I_CODEC_POWER_HPLDO_VOLTAGE_MASK GENMASK(10, 8)
++
++#define SUN20I_CODEC_ADC_CUR          0x034c
++
++#define SUN20I_CODEC_PCM_FORMATS      (SNDRV_PCM_FMTBIT_S16_LE|\
++                                       SNDRV_PCM_FMTBIT_S20_LE|\
++                                       SNDRV_PCM_FMTBIT_S32_LE)
++
++#define DRIVER_NAME                   "sun20i-codec"
++#define PREFIX                                "allwinner,"
++
++/* snd_soc_register_card() takes over drvdata, so the card must be first! */
++struct sun20i_codec {
++      struct snd_soc_card                     card;
++      struct snd_soc_dai_link                 dai_link;
++      struct snd_soc_dai_link_component       dlcs[3];
++      struct snd_dmaengine_dai_dma_data       dma_data[2];
++
++      struct clk              *bus_clk;
++      struct clk              *adc_clk;
++      struct clk              *dac_clk;
++      struct reset_control    *reset;
++};
++
++static int sun20i_codec_dai_probe(struct snd_soc_dai *dai)
++{
++      struct sun20i_codec *codec = snd_soc_dai_get_drvdata(dai);
++
++      snd_soc_dai_init_dma_data(dai,
++                                &codec->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
++                                &codec->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
++
++      return 0;
++}
++
++static struct clk *sun20i_codec_get_clk(struct snd_pcm_substream *substream,
++                                      struct snd_soc_dai *dai)
++{
++      struct sun20i_codec *codec = snd_soc_dai_get_drvdata(dai);
++
++      return substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
++              codec->adc_clk : codec->dac_clk;
++}
++
++static const unsigned int sun20i_codec_rates[] = {
++       7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
++      29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
++};
++
++static const struct snd_pcm_hw_constraint_list sun20i_codec_rate_lists[] = {
++      [SNDRV_PCM_STREAM_PLAYBACK] = {
++              .list   = sun20i_codec_rates,
++              .count  = ARRAY_SIZE(sun20i_codec_rates),
++      },
++      [SNDRV_PCM_STREAM_CAPTURE] = {
++              .list   = sun20i_codec_rates,
++              .count  = ARRAY_SIZE(sun20i_codec_rates) - 4, /* max 48 kHz */
++      },
++};
++
++static int sun20i_codec_startup(struct snd_pcm_substream *substream,
++                              struct snd_soc_dai *dai)
++{
++      const struct snd_pcm_hw_constraint_list *list;
++      int ret;
++
++      list = &sun20i_codec_rate_lists[substream->stream];
++      ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
++                                       SNDRV_PCM_HW_PARAM_RATE, list);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(sun20i_codec_get_clk(substream, dai));
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static void sun20i_codec_shutdown(struct snd_pcm_substream *substream,
++                                struct snd_soc_dai *dai)
++{
++      clk_disable_unprepare(sun20i_codec_get_clk(substream, dai));
++}
++
++static unsigned int sun20i_codec_get_clk_rate(unsigned int sample_rate)
++{
++      return (sample_rate % 4000) ? 22579200 : 24576000;
++}
++
++static const unsigned short sun20i_codec_divisors[] = {
++      512, 1024, 2048, 128,
++      768, 1536, 3072, 256,
++};
++
++static int sun20i_codec_get_fs(unsigned int clk_rate, unsigned int sample_rate)
++{
++      unsigned int divisor = clk_rate / sample_rate;
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(sun20i_codec_divisors); ++i)
++              if (sun20i_codec_divisors[i] == divisor)
++                      return i;
++
++      return -EINVAL;
++}
++
++static int sun20i_codec_hw_params(struct snd_pcm_substream *substream,
++                                struct snd_pcm_hw_params *params,
++                                struct snd_soc_dai *dai)
++{
++      struct sun20i_codec *codec = snd_soc_dai_get_drvdata(dai);
++      struct snd_soc_component *component = dai->component;
++      unsigned int channels = params_channels(params);
++      unsigned int sample_bits = params_width(params);
++      unsigned int sample_rate = params_rate(params);
++      unsigned int clk_rate = sun20i_codec_get_clk_rate(sample_rate);
++      enum dma_slave_buswidth dma_width;
++      unsigned int reg;
++      int ret, val;
++
++      switch (params_physical_width(params)) {
++      case 16:
++              dma_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
++              break;
++      case 32:
++              dma_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++              break;
++      default:
++              dev_err(dai->dev, "Unsupported physical sample width: %d\n",
++                      params_physical_width(params));
++              return -EINVAL;
++      }
++      codec->dma_data[substream->stream].addr_width = dma_width;
++
++      ret = clk_set_rate(sun20i_codec_get_clk(substream, dai),
++                         sun20i_codec_get_clk_rate(sample_rate));
++      if (ret)
++              return ret;
++
++      reg = substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
++              SUN20I_CODEC_ADC_FIFOC : SUN20I_CODEC_DAC_FIFOC;
++
++      val = sun20i_codec_get_fs(clk_rate, sample_rate);
++      if (val < 0)
++              return val;
++      snd_soc_component_update_bits(component, reg,
++                                    0x7 << SUN20I_CODEC_DAC_FIFOC_FS,
++                                    val << SUN20I_CODEC_DAC_FIFOC_FS);
++
++      /* Data is at MSB for full 4-byte samples, otherwise at LSB. */
++      val = sample_bits != 32;
++      snd_soc_component_update_bits(component, reg,
++                                    0x1 << SUN20I_CODEC_DAC_FIFOC_FIFO_MODE,
++                                    val << SUN20I_CODEC_DAC_FIFOC_FIFO_MODE);
++
++      if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
++              val = sample_bits > 16;
++              snd_soc_component_update_bits(component, reg,
++                                            0x1 << SUN20I_CODEC_ADC_FIFOC_SAMPLE_BITS,
++                                            val << SUN20I_CODEC_ADC_FIFOC_SAMPLE_BITS);
++
++              val = BIT(channels) - 1;
++              snd_soc_component_update_bits(component, SUN20I_CODEC_ADC_DIG_CTRL,
++                                            0xf << SUN20I_CODEC_ADC_DIG_CTRL_ADC_EN,
++                                            val << SUN20I_CODEC_ADC_DIG_CTRL_ADC_EN);
++      } else {
++              val = sample_bits > 16;
++              snd_soc_component_update_bits(component, reg,
++                                            0x1 << SUN20I_CODEC_DAC_FIFOC_SAMPLE_BITS,
++                                            val << SUN20I_CODEC_DAC_FIFOC_SAMPLE_BITS);
++
++              val = channels == 1;
++              snd_soc_component_update_bits(component, reg,
++                                            0x1 << SUN20I_CODEC_DAC_FIFOC_MONO_EN,
++                                            val << SUN20I_CODEC_DAC_FIFOC_MONO_EN);
++      }
++
++      return 0;
++}
++
++static int sun20i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
++                              struct snd_soc_dai *dai)
++{
++      struct snd_soc_component *component = dai->component;
++      unsigned int reg, mask;
++
++      if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
++              reg  = SUN20I_CODEC_ADC_FIFOC;
++              mask = BIT(SUN20I_CODEC_ADC_FIFOC_DRQ_EN);
++      } else {
++              reg  = SUN20I_CODEC_DAC_FIFOC;
++              mask = BIT(SUN20I_CODEC_DAC_FIFOC_DRQ_EN);
++      }
++
++      switch (cmd) {
++      case SNDRV_PCM_TRIGGER_START:
++      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++      case SNDRV_PCM_TRIGGER_RESUME:
++              mask |= BIT(SUN20I_CODEC_DAC_FIFOC_FIFO_FLUSH);
++              snd_soc_component_update_bits(component, reg, mask, mask);
++              break;
++      case SNDRV_PCM_TRIGGER_STOP:
++      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++      case SNDRV_PCM_TRIGGER_SUSPEND:
++              snd_soc_component_update_bits(component, reg, mask, 0);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static const struct snd_soc_dai_ops sun20i_codec_dai_ops = {
++      .startup        = sun20i_codec_startup,
++      .shutdown       = sun20i_codec_shutdown,
++      .hw_params      = sun20i_codec_hw_params,
++      .trigger        = sun20i_codec_trigger,
++};
++
++static struct snd_soc_dai_driver sun20i_codec_dai = {
++      .name = DRIVER_NAME,
++      .probe = sun20i_codec_dai_probe,
++      .ops = &sun20i_codec_dai_ops,
++      .capture = {
++              .stream_name    = "Capture",
++              .channels_min   = 1,
++              .channels_max   = 3, /* ??? */
++              .rates          = SNDRV_PCM_RATE_CONTINUOUS,
++              .formats        = SUN20I_CODEC_PCM_FORMATS,
++              .sig_bits       = 20,
++      },
++      .playback = {
++              .stream_name    = "Playback",
++              .channels_min   = 1,
++              .channels_max   = 2,
++              .rates          = SNDRV_PCM_RATE_CONTINUOUS,
++              .formats        = SUN20I_CODEC_PCM_FORMATS,
++              .sig_bits       = 20,
++      },
++};
++
++static const DECLARE_TLV_DB_SCALE(sun20i_codec_boost_vol_scale, 0, 600, 0);
++static const DECLARE_TLV_DB_SCALE(sun20i_codec_digital_vol_scale, -12000, 75, 1);
++static const DECLARE_TLV_DB_SCALE(sun20i_codec_headphone_vol_scale, -4200, 600, 0);
++/* FIXME */
++static const DECLARE_TLV_DB_SCALE(sun20i_codec_line_out_vol_scale, -4650, 150, 1);
++/* FIXME */
++static const DECLARE_TLV_DB_SCALE(sun20i_codec_pga_vol_scale, 500, 100, 0);
++
++static const char *const sun20i_codec_line_out_mode_enum_text[] = {
++      "Single-Ended", "Differential"
++};
++
++static const SOC_ENUM_DOUBLE_DECL(sun20i_codec_line_out_mode_enum,
++                                SUN20I_CODEC_DAC,
++                                SUN20I_CODEC_DAC_LINEOUTL_DIFFEN,
++                                SUN20I_CODEC_DAC_LINEOUTR_DIFFEN,
++                                sun20i_codec_line_out_mode_enum_text);
++
++static const struct snd_kcontrol_new sun20i_codec_controls[] = {
++      /* Digital Controls */
++      SOC_DOUBLE_TLV("DAC Playback Volume",
++                     SUN20I_CODEC_DAC_VOL_CTRL,
++                     SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_L,
++                     SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_R,
++                     0xc0, 0, sun20i_codec_digital_vol_scale),
++      SOC_SINGLE_TLV("ADC3 Capture Volume",
++                     SUN20I_CODEC_ADC_VOL_CTRL,
++                     SUN20I_CODEC_ADC_VOL_CTRL_ADC3_VOL,
++                     0xc0, 0, sun20i_codec_digital_vol_scale),
++      SOC_SINGLE_TLV("ADC2 Capture Volume",
++                     SUN20I_CODEC_ADC_VOL_CTRL,
++                     SUN20I_CODEC_ADC_VOL_CTRL_ADC2_VOL,
++                     0xc0, 0, sun20i_codec_digital_vol_scale),
++      SOC_SINGLE_TLV("ADC1 Capture Volume",
++                     SUN20I_CODEC_ADC_VOL_CTRL,
++                     SUN20I_CODEC_ADC_VOL_CTRL_ADC1_VOL,
++                     0xc0, 0, sun20i_codec_digital_vol_scale),
++
++      /* Analog Controls */
++      SOC_DOUBLE_R_TLV("FM Capture Volume",
++                       SUN20I_CODEC_ADC1,
++                       SUN20I_CODEC_ADC2,
++                       SUN20I_CODEC_ADC1_FMINL_GAIN,
++                       0x1, 0, sun20i_codec_boost_vol_scale),
++      SOC_DOUBLE_R_TLV("Line In Capture Volume",
++                       SUN20I_CODEC_ADC1,
++                       SUN20I_CODEC_ADC2,
++                       SUN20I_CODEC_ADC1_LINEINL_GAIN,
++                       0x1, 0, sun20i_codec_boost_vol_scale),
++      SOC_ENUM("Line Out Mode Playback Enum",
++               sun20i_codec_line_out_mode_enum),
++      SOC_SINGLE_TLV("Line Out Playback Volume",
++                     SUN20I_CODEC_DAC,
++                     SUN20I_CODEC_DAC_LINEOUT_VOL_CTRL,
++                     0x1f, 0, sun20i_codec_line_out_vol_scale),
++      SOC_SINGLE_TLV("Headphone Playback Volume",
++                     SUN20I_CODEC_HP2,
++                     SUN20I_CODEC_HP2_HEADPHONE_GAIN,
++                     0x7, 1, sun20i_codec_headphone_vol_scale),
++};
++
++static const struct snd_kcontrol_new sun20i_codec_line_out_switch =
++      SOC_DAPM_DOUBLE("Line Out Playback Switch",
++                      SUN20I_CODEC_DAC,
++                      SUN20I_CODEC_DAC_LMUTE,
++                      SUN20I_CODEC_DAC_RMUTE, 1, 1);
++
++static const struct snd_kcontrol_new sun20i_codec_hp_switch =
++      SOC_DAPM_SINGLE("Headphone Playback Switch",
++                      SUN20I_CODEC_HP2,
++                      SUN20I_CODEC_HP2_HP_DRVOUTEN, 1, 0);
++
++static const struct snd_kcontrol_new sun20i_codec_adc12_mixer_controls[] = {
++      /* ADC1 Only */
++      SOC_DAPM_SINGLE("Mic1 Capture Switch",
++                      SUN20I_CODEC_ADC1,
++                      SUN20I_CODEC_ADC1_MICIN1_SIN_EN, 1, 0),
++      /* Shared */
++      SOC_DAPM_DOUBLE_R("FM Capture Switch",
++                        SUN20I_CODEC_ADC1,
++                        SUN20I_CODEC_ADC2,
++                        SUN20I_CODEC_ADC1_FMINL_EN, 1, 0),
++      /* Shared */
++      SOC_DAPM_DOUBLE_R("Line In Capture Switch",
++                        SUN20I_CODEC_ADC1,
++                        SUN20I_CODEC_ADC2,
++                        SUN20I_CODEC_ADC1_LINEINL_EN, 1, 0),
++      /* ADC2 Only */
++      SOC_DAPM_SINGLE("Mic2 Capture Switch",
++                      SUN20I_CODEC_ADC2,
++                      SUN20I_CODEC_ADC2_MICIN2_SIN_EN, 1, 0),
++};
++
++static const struct snd_kcontrol_new sun20i_codec_adc3_mixer_controls[] = {
++      SOC_DAPM_SINGLE("Mic3 Capture Switch",
++                      SUN20I_CODEC_ADC3,
++                      SUN20I_CODEC_ADC3_MICIN3_SIN_EN, 1, 0),
++};
++
++static const struct snd_kcontrol_new sun20i_codec_mic1_volume =
++      SOC_DAPM_SINGLE_TLV("Capture Volume",
++                          SUN20I_CODEC_ADC1,
++                          SUN20I_CODEC_ADC1_ADC1_PGA_GAIN,
++                          0x1f, 0, sun20i_codec_pga_vol_scale);
++
++static const struct snd_kcontrol_new sun20i_codec_mic2_volume =
++      SOC_DAPM_SINGLE_TLV("Capture Volume",
++                          SUN20I_CODEC_ADC2,
++                          SUN20I_CODEC_ADC2_ADC2_PGA_GAIN,
++                          0x1f, 0, sun20i_codec_pga_vol_scale);
++
++static const struct snd_kcontrol_new sun20i_codec_mic3_volume =
++      SOC_DAPM_SINGLE_TLV("Capture Volume",
++                          SUN20I_CODEC_ADC3,
++                          SUN20I_CODEC_ADC3_ADC3_PGA_GAIN,
++                          0x1f, 0, sun20i_codec_pga_vol_scale);
++
++static const struct snd_soc_dapm_widget sun20i_codec_widgets[] = {
++      /* Playback */
++      SND_SOC_DAPM_OUTPUT("LINEOUTL"),
++      SND_SOC_DAPM_OUTPUT("LINEOUTR"),
++
++      SND_SOC_DAPM_SWITCH("LINEOUTL Switch",
++                          SUN20I_CODEC_DAC,
++                          SUN20I_CODEC_DAC_LINEOUTL_EN, 0,
++                          &sun20i_codec_line_out_switch),
++      SND_SOC_DAPM_SWITCH("LINEOUTR Switch",
++                          SUN20I_CODEC_DAC,
++                          SUN20I_CODEC_DAC_LINEOUTR_EN, 0,
++                          &sun20i_codec_line_out_switch),
++
++      SND_SOC_DAPM_OUTPUT("HPOUTL"),
++      SND_SOC_DAPM_OUTPUT("HPOUTR"),
++
++      SND_SOC_DAPM_SWITCH("HPOUTL Switch",
++                          SND_SOC_NOPM, 0, 0, &sun20i_codec_hp_switch),
++      SND_SOC_DAPM_SWITCH("HPOUTR Switch",
++                          SND_SOC_NOPM, 0, 0, &sun20i_codec_hp_switch),
++      SND_SOC_DAPM_SUPPLY("Headphone Driver",
++                          SUN20I_CODEC_HP2,
++                          SUN20I_CODEC_HP2_HP_DRVEN, 0, NULL, 0),
++
++      SND_SOC_DAPM_DAC("DACL", NULL,
++                       SUN20I_CODEC_DAC,
++                       SUN20I_CODEC_DAC_DACL_EN, 0),
++      SND_SOC_DAPM_DAC("DACR", NULL,
++                       SUN20I_CODEC_DAC,
++                       SUN20I_CODEC_DAC_DACR_EN, 0),
++      SND_SOC_DAPM_SUPPLY("DAC",
++                          SUN20I_CODEC_DAC_DPC,
++                          SUN20I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
++
++      SND_SOC_DAPM_AIF_IN("DACL FIFO", "Playback", 0,
++                          SND_SOC_NOPM, 0, 0),
++      SND_SOC_DAPM_AIF_IN("DACR FIFO", "Playback", 1,
++                          SND_SOC_NOPM, 0, 0),
++
++      /* Capture */
++      SND_SOC_DAPM_AIF_OUT("ADC1 FIFO", "Capture", 0,
++                           SND_SOC_NOPM, 0, 0),
++      SND_SOC_DAPM_AIF_OUT("ADC2 FIFO", "Capture", 1,
++                           SND_SOC_NOPM, 0, 0),
++      SND_SOC_DAPM_AIF_OUT("ADC3 FIFO", "Capture", 2,
++                           SND_SOC_NOPM, 0, 0),
++
++      SND_SOC_DAPM_ADC("ADC1", NULL,
++                       SUN20I_CODEC_ADC1,
++                       SUN20I_CODEC_ADC1_ADC1_EN, 0),
++      SND_SOC_DAPM_ADC("ADC2", NULL,
++                       SUN20I_CODEC_ADC2,
++                       SUN20I_CODEC_ADC2_ADC2_EN, 0),
++      SND_SOC_DAPM_ADC("ADC3", NULL,
++                       SUN20I_CODEC_ADC3,
++                       SUN20I_CODEC_ADC3_ADC3_EN, 0),
++      SND_SOC_DAPM_SUPPLY("ADC",
++                          SUN20I_CODEC_ADC_FIFOC,
++                          SUN20I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
++
++      SND_SOC_DAPM_MIXER_NAMED_CTL("ADC1 Mixer", SND_SOC_NOPM, 0, 0,
++                                   sun20i_codec_adc12_mixer_controls, 3),
++      SND_SOC_DAPM_MIXER_NAMED_CTL("ADC2 Mixer", SND_SOC_NOPM, 0, 0,
++                                   sun20i_codec_adc12_mixer_controls + 1, 3),
++      SND_SOC_DAPM_MIXER_NAMED_CTL("ADC3 Mixer", SND_SOC_NOPM, 0, 0,
++                                   sun20i_codec_adc3_mixer_controls,
++                                   ARRAY_SIZE(sun20i_codec_adc3_mixer_controls)),
++
++      SND_SOC_DAPM_PGA("Mic1",
++                       SUN20I_CODEC_ADC1,
++                       SUN20I_CODEC_ADC1_MICIN1_PGA_EN, 0,
++                       &sun20i_codec_mic1_volume, 1),
++      SND_SOC_DAPM_PGA("Mic2",
++                       SUN20I_CODEC_ADC2,
++                       SUN20I_CODEC_ADC2_MICIN2_PGA_EN, 0,
++                       &sun20i_codec_mic2_volume, 1),
++      SND_SOC_DAPM_PGA("Mic3",
++                       SUN20I_CODEC_ADC3,
++                       SUN20I_CODEC_ADC3_MICIN3_PGA_EN, 0,
++                       &sun20i_codec_mic3_volume, 1),
++
++      SND_SOC_DAPM_INPUT("MICIN1"),
++      SND_SOC_DAPM_INPUT("MICIN2"),
++      SND_SOC_DAPM_INPUT("MICIN3"),
++
++      SND_SOC_DAPM_INPUT("FMINL"),
++      SND_SOC_DAPM_INPUT("FMINR"),
++
++      SND_SOC_DAPM_INPUT("LINEINL"),
++      SND_SOC_DAPM_INPUT("LINEINR"),
++
++      SND_SOC_DAPM_SUPPLY("HBIAS",
++                          SUN20I_CODEC_MICBIAS,
++                          SUN20I_CODEC_MICBIAS_HMICBIASEN, 0, NULL, 0),
++      SND_SOC_DAPM_SUPPLY("MBIAS",
++                          SUN20I_CODEC_MICBIAS,
++                          SUN20I_CODEC_MICBIAS_MMICBIASEN, 0, NULL, 0),
++
++      SND_SOC_DAPM_REGULATOR_SUPPLY("avcc", 0, 0),
++      SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0),
++      SND_SOC_DAPM_REGULATOR_SUPPLY("vdd33", 0, 0),
++};
++
++static const struct snd_soc_dapm_route sun20i_codec_routes[] = {
++      /* Playback */
++      { "LINEOUTL", NULL, "LINEOUTL Switch" },
++      { "LINEOUTR", NULL, "LINEOUTR Switch" },
++
++      { "LINEOUTL Switch", "Line Out Playback Switch", "DACL" },
++      { "LINEOUTR Switch", "Line Out Playback Switch", "DACR" },
++
++      { "HPOUTL", NULL, "HPOUTL Switch" },
++      { "HPOUTR", NULL, "HPOUTR Switch" },
++
++      { "HPOUTL Switch", "Headphone Playback Switch", "DACL" },
++      { "HPOUTR Switch", "Headphone Playback Switch", "DACR" },
++      { "HPOUTL Switch", NULL, "Headphone Driver" },
++      { "HPOUTR Switch", NULL, "Headphone Driver" },
++      { "Headphone Driver", NULL, "hpvcc" },
++
++      { "DACL", NULL, "DACL FIFO" },
++      { "DACR", NULL, "DACR FIFO" },
++      { "DACL", NULL, "DAC" },
++      { "DACR", NULL, "DAC" },
++      { "DACL", NULL, "avcc" },
++      { "DACR", NULL, "avcc" },
++
++      /* Capture */
++      { "ADC1 FIFO", NULL, "ADC1" },
++      { "ADC2 FIFO", NULL, "ADC2" },
++      { "ADC3 FIFO", NULL, "ADC3" },
++
++      { "ADC1", NULL, "ADC1 Mixer" },
++      { "ADC2", NULL, "ADC2 Mixer" },
++      { "ADC3", NULL, "ADC3 Mixer" },
++      { "ADC1", NULL, "ADC" },
++      { "ADC2", NULL, "ADC" },
++      { "ADC3", NULL, "ADC" },
++      { "ADC1", NULL, "avcc" },
++      { "ADC2", NULL, "avcc" },
++      { "ADC3", NULL, "avcc" },
++
++      { "ADC1 Mixer", "Mic1 Capture Switch", "Mic1" },
++      { "ADC2 Mixer", "Mic2 Capture Switch", "Mic2" },
++      { "ADC3 Mixer", "Mic3 Capture Switch", "Mic3" },
++      { "ADC1 Mixer", "FM Capture Switch", "FMINL" },
++      { "ADC2 Mixer", "FM Capture Switch", "FMINR" },
++      { "ADC1 Mixer", "Line In Capture Switch", "LINEINL" },
++      { "ADC2 Mixer", "Line In Capture Switch", "LINEINR" },
++
++      { "Mic1", NULL, "MICIN1" },
++      { "Mic2", NULL, "MICIN2" },
++      { "Mic3", NULL, "MICIN3" },
++
++      { "HBIAS", NULL, "vdd33" },
++      { "MBIAS", NULL, "vdd33" },
++};
++
++static int sun20i_codec_component_probe(struct snd_soc_component *component)
++{
++      struct sun20i_codec *codec = snd_soc_component_get_drvdata(component);
++      int ret;
++
++      ret = reset_control_deassert(codec->reset);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(codec->bus_clk);
++      if (ret)
++              goto err_assert_reset;
++
++      /* Enable digital volume control. */
++      snd_soc_component_update_bits(component, SUN20I_CODEC_DAC_VOL_CTRL,
++                                    0x1 << SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_SEL,
++                                    0x1 << SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_SEL);
++      snd_soc_component_update_bits(component, SUN20I_CODEC_ADC_DIG_CTRL,
++                                    0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN,
++                                    0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN);
++
++      return 0;
++
++err_assert_reset:
++      reset_control_assert(codec->reset);
++
++      return ret;
++}
++
++static void sun20i_codec_component_remove(struct snd_soc_component *component)
++{
++      struct sun20i_codec *codec = snd_soc_component_get_drvdata(component);
++
++      clk_disable_unprepare(codec->bus_clk);
++      reset_control_assert(codec->reset);
++}
++
++static const struct snd_soc_component_driver sun20i_codec_component = {
++      .controls               = sun20i_codec_controls,
++      .num_controls           = ARRAY_SIZE(sun20i_codec_controls),
++      .dapm_widgets           = sun20i_codec_widgets,
++      .num_dapm_widgets       = ARRAY_SIZE(sun20i_codec_widgets),
++      .dapm_routes            = sun20i_codec_routes,
++      .num_dapm_routes        = ARRAY_SIZE(sun20i_codec_routes),
++      .probe                  = sun20i_codec_component_probe,
++      .remove                 = sun20i_codec_component_remove,
++};
++
++static int sun20i_codec_init_card(struct device *dev,
++                                struct sun20i_codec *codec)
++{
++      struct snd_soc_dai_link *dai_link = &codec->dai_link;
++      struct snd_soc_card *card = &codec->card;
++      int ret;
++
++      codec->dlcs[0].of_node  = dev->of_node;
++      codec->dlcs[0].dai_name = DRIVER_NAME;
++      codec->dlcs[1].name     = "snd-soc-dummy";
++      codec->dlcs[1].dai_name = "snd-soc-dummy-dai";
++      codec->dlcs[2].of_node  = dev->of_node;
++
++      dai_link->name          = DRIVER_NAME;
++      dai_link->stream_name   = DRIVER_NAME;
++      dai_link->cpus          = &codec->dlcs[0];
++      dai_link->num_cpus      = 1;
++      dai_link->codecs        = &codec->dlcs[1];
++      dai_link->num_codecs    = 1;
++      dai_link->platforms     = &codec->dlcs[2];
++      dai_link->num_platforms = 1;
++
++      card->name              = DRIVER_NAME;
++      card->dev               = dev;
++      card->owner             = THIS_MODULE;
++      card->dai_link          = dai_link;
++      card->num_links         = 1;
++      card->fully_routed      = true;
++
++      ret = snd_soc_of_parse_audio_simple_widgets(card, PREFIX "widgets");
++      if (ret)
++              return ret;
++
++      ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing");
++      if (ret)
++              return ret;
++
++      ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static const struct regmap_config sun20i_codec_regmap_config = {
++      .reg_bits               = 32,
++      .reg_stride             = 4,
++      .val_bits               = 32,
++      .max_register           = SUN20I_CODEC_ADC_CUR,
++};
++
++static const struct regulator_ops sun20i_codec_ldo_ops = {
++      .list_voltage           = regulator_list_voltage_linear,
++      .map_voltage            = regulator_map_voltage_linear,
++      .set_voltage_sel        = regulator_set_voltage_sel_regmap,
++      .get_voltage_sel        = regulator_get_voltage_sel_regmap,
++      .enable                 = regulator_enable_regmap,
++      .disable                = regulator_disable_regmap,
++      .is_enabled             = regulator_is_enabled_regmap,
++};
++
++static const struct regulator_desc sun20i_codec_ldos[] = {
++      {
++              .name           = "aldo",
++              .supply_name    = "vdd33",
++              .of_match       = "aldo",
++              .regulators_node = "regulators",
++              .ops            = &sun20i_codec_ldo_ops,
++              .type           = REGULATOR_VOLTAGE,
++              .owner          = THIS_MODULE,
++              .n_voltages     = BIT(3),
++              .min_uV         = 1650000,
++              .uV_step        = 50000,
++              .vsel_reg       = SUN20I_CODEC_POWER,
++              .vsel_mask      = SUN20I_CODEC_POWER_ALDO_VOLTAGE_MASK,
++              .enable_reg     = SUN20I_CODEC_POWER,
++              .enable_mask    = SUN20I_CODEC_POWER_ALDO_EN_MASK,
++      },
++      {
++              .name           = "hpldo",
++              .supply_name    = "hpldoin",
++              .of_match       = "hpldo",
++              .regulators_node = "regulators",
++              .ops            = &sun20i_codec_ldo_ops,
++              .type           = REGULATOR_VOLTAGE,
++              .owner          = THIS_MODULE,
++              .n_voltages     = BIT(3),
++              .min_uV         = 1650000,
++              .uV_step        = 50000,
++              .vsel_reg       = SUN20I_CODEC_POWER,
++              .vsel_mask      = SUN20I_CODEC_POWER_HPLDO_VOLTAGE_MASK,
++              .enable_reg     = SUN20I_CODEC_POWER,
++              .enable_mask    = SUN20I_CODEC_POWER_HPLDO_EN_MASK,
++      },
++};
++
++static int sun20i_codec_probe(struct platform_device *pdev)
++{
++      struct regulator_config config = { .dev = &pdev->dev };
++      struct device *dev = &pdev->dev;
++      struct sun20i_codec *codec;
++      struct regulator_dev *rdev;
++      struct regmap *regmap;
++      struct resource *res;
++      void __iomem *base;
++      int i, ret;
++
++      codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
++      if (!codec)
++              return -ENOMEM;
++
++      dev_set_drvdata(dev, codec);
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      base = devm_ioremap_resource(dev, res);
++      if (IS_ERR(base))
++              return dev_err_probe(dev, PTR_ERR(base),
++                                   "Failed to map registers\n");
++
++      regmap = devm_regmap_init_mmio(dev, base,
++                                     &sun20i_codec_regmap_config);
++      if (IS_ERR(regmap))
++              return dev_err_probe(dev, PTR_ERR(regmap),
++                                   "Failed to create regmap\n");
++
++      codec->bus_clk = devm_clk_get(dev, "bus");
++      if (IS_ERR(codec->bus_clk))
++              return dev_err_probe(dev, PTR_ERR(codec->bus_clk),
++                                   "Failed to get bus clock\n");
++
++      codec->adc_clk = devm_clk_get(dev, "adc");
++      if (IS_ERR(codec->adc_clk))
++              return dev_err_probe(dev, PTR_ERR(codec->adc_clk),
++                                   "Failed to get ADC clock\n");
++
++      codec->dac_clk = devm_clk_get(dev, "dac");
++      if (IS_ERR(codec->dac_clk))
++              return dev_err_probe(dev, PTR_ERR(codec->dac_clk),
++                                   "Failed to get DAC clock\n");
++
++      codec->reset = devm_reset_control_get_exclusive(dev, NULL);
++      if (IS_ERR(codec->reset))
++              return dev_err_probe(dev, PTR_ERR(codec->reset),
++                                   "Failed to get reset\n");
++
++      for (i = 0; i < ARRAY_SIZE(sun20i_codec_ldos); ++i) {
++              const struct regulator_desc *desc = &sun20i_codec_ldos[i];
++
++              rdev = devm_regulator_register(dev, desc, &config);
++              if (IS_ERR(rdev))
++                      return PTR_ERR(rdev);
++      }
++
++      ret = devm_snd_soc_register_component(dev, &sun20i_codec_component,
++                                            &sun20i_codec_dai, 1);
++      if (ret)
++              return dev_err_probe(dev, ret, "Failed to register component\n");
++
++      codec->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
++                      res->start + SUN20I_CODEC_DAC_TXDATA;
++      codec->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 8;
++      codec->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
++                      res->start + SUN20I_CODEC_ADC_RXDATA;
++      codec->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 8;
++
++      ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
++      if (ret)
++              return dev_err_probe(dev, ret, "Failed to register PCM\n");
++
++      ret = sun20i_codec_init_card(dev, codec);
++      if (ret)
++              return dev_err_probe(dev, ret, "Failed to initialize card\n");
++
++      ret = devm_snd_soc_register_card(dev, &codec->card);
++      if (ret)
++              return dev_err_probe(dev, ret, "Failed to register card\n");
++
++      return 0;
++}
++
++static const struct of_device_id sun20i_codec_of_match[] = {
++      { .compatible = "allwinner,sun20i-d1-audio-codec" },
++      {}
++};
++MODULE_DEVICE_TABLE(of, sun20i_codec_of_match);
++
++static struct platform_driver sun20i_codec_driver = {
++      .driver = {
++              .name           = DRIVER_NAME,
++              .of_match_table = sun20i_codec_of_match,
++      },
++      .probe  = sun20i_codec_probe,
++};
++module_platform_driver(sun20i_codec_driver);
++
++MODULE_DESCRIPTION("Allwinner D1 (sun20i) codec driver");
++MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:sun20i-codec");
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0116-ASoC-sun20i-codec-What-is-this-ramp-thing.patch b/target/linux/sunxid1/patches-5.15/0116-ASoC-sun20i-codec-What-is-this-ramp-thing.patch
new file mode 100644 (file)
index 0000000..226d18c
--- /dev/null
@@ -0,0 +1,28 @@
+From fa221fe84aced5348277f372b327b4362b2123f8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 23 Jun 2021 21:18:47 -0500
+Subject: [PATCH 116/124] ASoC: sun20i-codec: What is this ramp thing?
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ sound/soc/sunxi/sun20i-codec.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/sound/soc/sunxi/sun20i-codec.c b/sound/soc/sunxi/sun20i-codec.c
+index f99e81f93a1b..18551f5ef14e 100644
+--- a/sound/soc/sunxi/sun20i-codec.c
++++ b/sound/soc/sunxi/sun20i-codec.c
+@@ -711,6 +711,10 @@ static int sun20i_codec_component_probe(struct snd_soc_component *component)
+                                     0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN,
+                                     0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN);
++      /* Maaagic... */
++      snd_soc_component_update_bits(component, SUN20I_CODEC_RAMP,
++                                    BIT(1) | BIT(0), BIT(0));
++
+       return 0;
+ err_assert_reset:
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0117-Disable-broken-ARCH_SUNXI-drivers.patch b/target/linux/sunxid1/patches-5.15/0117-Disable-broken-ARCH_SUNXI-drivers.patch
new file mode 100644 (file)
index 0000000..c811d7e
--- /dev/null
@@ -0,0 +1,44 @@
+From 837e54cc6396950ad0ca852aff40a3c7c9e03fe1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 15 Nov 2021 00:48:47 -0600
+Subject: [PATCH 117/124] Disable broken ARCH_SUNXI drivers
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/irqchip/Makefile  | 6 +++---
+ drivers/soc/sunxi/Kconfig | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
+index ba1097e01991..1b9e412577e8 100644
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -23,9 +23,9 @@ obj-$(CONFIG_OMPIC)                  += irq-ompic.o
+ obj-$(CONFIG_OR1K_PIC)                        += irq-or1k-pic.o
+ obj-$(CONFIG_ORION_IRQCHIP)           += irq-orion.o
+ obj-$(CONFIG_OMAP_IRQCHIP)            += irq-omap-intc.o
+-obj-$(CONFIG_ARCH_SUNXI)              += irq-sun4i.o
+-obj-$(CONFIG_ARCH_SUNXI)              += irq-sun6i-r.o
+-obj-$(CONFIG_ARCH_SUNXI)              += irq-sunxi-nmi.o
++#obj-$(CONFIG_ARCH_SUNXI)             += irq-sun4i.o
++#obj-$(CONFIG_ARCH_SUNXI)             += irq-sun6i-r.o
++#obj-$(CONFIG_ARCH_SUNXI)             += irq-sunxi-nmi.o
+ obj-$(CONFIG_ARCH_SPEAR3XX)           += spear-shirq.o
+ obj-$(CONFIG_ARM_GIC)                 += irq-gic.o irq-gic-common.o
+ obj-$(CONFIG_ARM_GIC_PM)              += irq-gic-pm.o
+diff --git a/drivers/soc/sunxi/Kconfig b/drivers/soc/sunxi/Kconfig
+index 1fef0e711056..7762020ac56d 100644
+--- a/drivers/soc/sunxi/Kconfig
++++ b/drivers/soc/sunxi/Kconfig
+@@ -5,7 +5,7 @@
+ config SUNXI_MBUS
+       bool
+-      default ARCH_SUNXI
++      default ARCH_SUNXI && !RISCV
+       help
+         Say y to enable the fixups needed to support the Allwinner
+         MBUS DMA quirks.
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0118-riscv-Add-Allwinner-D1-SoC-support.patch b/target/linux/sunxid1/patches-5.15/0118-riscv-Add-Allwinner-D1-SoC-support.patch
new file mode 100644 (file)
index 0000000..4e7a4b3
--- /dev/null
@@ -0,0 +1,52 @@
+From 9e923b083e3c46b02c67a00ea9c973d66fcb5fa2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:17:45 -0500
+Subject: [PATCH 118/124] riscv: Add Allwinner D1 SoC support
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/Kconfig.socs                | 9 +++++++++
+ arch/riscv/boot/dts/Makefile           | 1 +
+ arch/riscv/boot/dts/allwinner/Makefile | 1 +
+ 3 files changed, 11 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/allwinner/Makefile
+
+diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
+index 56bafc3dad4c..48c0812e2f8a 100644
+--- a/arch/riscv/Kconfig.socs
++++ b/arch/riscv/Kconfig.socs
+@@ -1,5 +1,14 @@
+ menu "SoC selection"
++config ARCH_SUNXI
++      bool "Allwinner sunXi SoCs"
++      select SIFIVE_PLIC
++      select SUN4I_TIMER
++      select SUN5I_HSTIMER
++      select SUN20I_INTC
++      help
++        This enables support for Allwinner sunXi SoC platforms.
++
+ config SOC_MICROCHIP_POLARFIRE
+       bool "Microchip PolarFire SoCs"
+       select MCHP_CLK_MPFS
+diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile
+index fe996b88319e..05b36b76eaac 100644
+--- a/arch/riscv/boot/dts/Makefile
++++ b/arch/riscv/boot/dts/Makefile
+@@ -1,4 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
++subdir-y += allwinner
+ subdir-y += sifive
+ subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan
+ subdir-y += microchip
+diff --git a/arch/riscv/boot/dts/allwinner/Makefile b/arch/riscv/boot/dts/allwinner/Makefile
+new file mode 100644
+index 000000000000..f66554cd5c45
+--- /dev/null
++++ b/arch/riscv/boot/dts/allwinner/Makefile
+@@ -0,0 +1 @@
++# SPDX-License-Identifier: GPL-2.0
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0119-riscv-Add-Allwinner-D1-SoC-device-tree.patch b/target/linux/sunxid1/patches-5.15/0119-riscv-Add-Allwinner-D1-SoC-device-tree.patch
new file mode 100644 (file)
index 0000000..24a2483
--- /dev/null
@@ -0,0 +1,1179 @@
+From df2ef356052fd89dda0d44e374dc423be773a6a1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:18:17 -0500
+Subject: [PATCH 119/124] riscv: Add Allwinner D1 SoC device tree
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 1159 ++++++++++++++++++
+ 1 file changed, 1159 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi
+
+diff --git a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi
+new file mode 100644
+index 000000000000..af0fdadc0d14
+--- /dev/null
++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi
+@@ -0,0 +1,1159 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++
++#include <dt-bindings/clock/sun20i-d1-ccu.h>
++#include <dt-bindings/clock/sun20i-d1-r-ccu.h>
++#include <dt-bindings/clock/sun6i-rtc.h>
++#include <dt-bindings/clock/sun8i-de2.h>
++#include <dt-bindings/clock/sun8i-tcon-top.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/mailbox/sun20i-d1-msgbox.h>
++#include <dt-bindings/reset/sun20i-d1-ccu.h>
++#include <dt-bindings/reset/sun20i-d1-r-ccu.h>
++#include <dt-bindings/reset/sun8i-de2.h>
++#include <dt-bindings/thermal/thermal.h>
++
++/ {
++      #address-cells = <1>;
++      #size-cells = <1>;
++
++      // FIXME: no riscv architecture support for cpufreq
++      cpu_opp_table: cpu-opp-table {
++              compatible = "allwinner,sun20i-d1-operating-points",
++                           "allwinner,sun50i-h6-operating-points";
++              nvmem-cells = <&cpu_speed_grade>;
++
++              opp-1080000000 {
++                      // FIXME: this is probably wrong now.
++                      clock-latency-ns = <244144>; /* 8 32k periods */
++                      opp-hz = /bits/ 64 <1008000000>;
++
++                      // FIXME: derive a real voltage range.
++                      opp-microvolt-speed0 = <1100000>;
++              };
++      };
++
++      cpus {
++              #address-cells = <1>;
++              #size-cells = <0>;
++              timebase-frequency = <24000000>;
++
++              cpu0: cpu@0 {
++                      // FIXME: is this the right compatible?
++                      compatible = "thead,c906", "riscv";
++                      device_type = "cpu";
++                      reg = <0>;
++                      clocks = <&ccu CLK_RISCV>;
++                      clock-frequency = <24000000>;
++                      #cooling-cells = <2>;
++                      d-cache-block-size = <64>;
++                      d-cache-sets = <256>;
++                      d-cache-size = <32768>;
++                      i-cache-block-size = <64>;
++                      i-cache-sets = <128>;
++                      i-cache-size = <32768>;
++                      mmu-type = "riscv,sv39";
++                      operating-points-v2 = <&cpu_opp_table>;
++                      riscv,isa = "rv64imafdc";
++
++                      cpu0_intc: interrupt-controller {
++                              compatible = "riscv,cpu-intc";
++                              #address-cells = <0>;
++                              interrupt-controller;
++                              #interrupt-cells = <1>;
++                      };
++              };
++      };
++
++      osc24M: osc24M_clk {
++              #clock-cells = <0>;
++              compatible = "fixed-clock";
++              clock-frequency = <24000000>;
++              clock-output-names = "osc24M";
++      };
++
++      // FIXME: depends on what T-HEAD tries to upstream.
++      pmu {
++              compatible = "thead,c900-pmu";
++      };
++
++      thermal-zones {
++              cpu-thermal {
++                      polling-delay = <0>;
++                      polling-delay-passive = <0>;
++                      thermal-sensors = <&ths 0>;
++
++                      trips {
++                              cpu_target: cpu-target {
++                                      hysteresis = <3000>;
++                                      temperature = <85000>;
++                                      type = "passive";
++                              };
++
++                              cpu-crit {
++                                      hysteresis = <0>;
++                                      temperature = <110000>;
++                                      type = "critical";
++                              };
++                      };
++
++                      cooling-maps {
++                              map0 {
++                                      trip = <&cpu_target>;
++                                      cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
++                              };
++                      };
++              };
++      };
++
++      soc {
++              compatible = "simple-bus";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              ranges;
++              interrupt-parent = <&intc>;
++
++              // TODO: write a binding and driver.
++              dsp: dsp@1700000 {
++                      compatible = "allwinner,sun20i-d1-dsp";
++                      reg = <0x1700000 0x400>;
++                      reg-names = "cfg";
++                      clocks = <&ccu CLK_BUS_DSP_CFG>,
++                               <&ccu CLK_DSP>;
++                      clock-names = "cfg", "dsp";
++                      resets = <&ccu RST_BUS_DSP_CFG>,
++                               <&ccu RST_BUS_DSP_DBG>,
++                               <&ccu RST_DSP>;
++                      allwinner,sram = <&dsp_sram 1>;
++                      interrupts = <136 IRQ_TYPE_LEVEL_HIGH>,
++                                   <137 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "dee", "pfe";
++                      // FIXME: this will be different for R528 (CPUX).
++                      mboxes = <&riscv_msgbox MBOX_USER_DSP MBOX_RX>,
++                               <&dsp_msgbox MBOX_USER_RISCV MBOX_TX>;
++                      mbox-names = "rx", "tx";
++              };
++
++              dsp_wdt: watchdog@1700400 {
++                      compatible = "allwinner,sun20i-d1-wdt";
++                      reg = <0x1700400 0x20>;
++                      clocks = <&osc24M>;
++                      interrupts = <138 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "reserved";
++              };
++
++              // TODO: write a binding and driver.
++              dsp_msgbox: mailbox@1701000 {
++                      compatible = "allwinner,sun20i-d1-msgbox";
++                      reg = <0x1701000 0x1000>;
++                      clocks = <&ccu CLK_BUS_MSGBOX1>;
++                      resets = <&ccu RST_BUS_MSGBOX1>;
++                      interrupts = <139 IRQ_TYPE_LEVEL_HIGH>,
++                                   <140 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "rx", "tx";
++                      #mbox-cells = <2>;
++              };
++
++              ve: video-codec@1c0e000 {
++                      compatible = "allwinner,sun20i-d1-video-engine";
++                      reg = <0x1c0e000 0x2000>;
++                      clocks = <&ccu CLK_BUS_VE>,
++                               <&ccu CLK_VE>,
++                               <&ccu CLK_MBUS_VE>;
++                      clock-names = "ahb", "mod", "ram";
++                      resets = <&ccu RST_BUS_VE>;
++                      allwinner,sram = <&ve_sram 1>;
++                      interconnects = <&mbus 4>;
++                      interconnect-names = "dma-mem";
++                      interrupts = <82 IRQ_TYPE_LEVEL_HIGH>;
++                      iommus = <&iommu 0>;
++              };
++
++              gpio: pinctrl@2000000 {
++                      compatible = "allwinner,sun20i-d1-pinctrl";
++                      #address-cells = <0>;
++                      reg = <0x2000000 0x800>;
++                      clocks = <&ccu CLK_APB0>,
++                               <&osc24M>,
++                               <&rtc CLK_OSC32K>;
++                      clock-names = "apb", "hosc", "losc";
++                      gpio-controller;
++                      #gpio-cells = <3>;
++                      interrupts = <85 IRQ_TYPE_LEVEL_HIGH>,
++                                   <87 IRQ_TYPE_LEVEL_HIGH>,
++                                   <89 IRQ_TYPE_LEVEL_HIGH>,
++                                   <91 IRQ_TYPE_LEVEL_HIGH>,
++                                   <93 IRQ_TYPE_LEVEL_HIGH>,
++                                   <95 IRQ_TYPE_LEVEL_HIGH>;
++                      // FIXME: not in binding, should we add these?
++                      interrupt-names = "pb", "pc", "pd", "pe", "pf", "pg";
++                      interrupt-controller;
++                      #interrupt-cells = <3>;
++
++                      /omit-if-no-ref/
++                      i2c0_pb10_pins: i2c0-pb10-pins {
++                              pins = "PB10", "PB11";
++                              function = "i2c0";
++                      };
++
++                      /omit-if-no-ref/
++                      i2c2_pb0_pins: i2c2-pb0-pins {
++                              pins = "PB0", "PB1";
++                              function = "i2c2";
++                      };
++
++                      /omit-if-no-ref/
++                      i2c3_pb6_pins: i2c3-pb6-pins {
++                              pins = "PB6", "PB7";
++                              function = "i2c3";
++                      };
++
++                      /omit-if-no-ref/
++                      mmc0_pins: mmc0-pins {
++                              pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
++                              function = "mmc0";
++                      };
++
++                      /omit-if-no-ref/
++                      mmc1_pins: mmc1-pins {
++                              pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5";
++                              function = "mmc1";
++                      };
++
++                      /omit-if-no-ref/
++                      mmc2_pins: mmc2-pins {
++                              pins = "PC2", "PC3", "PC4", "PC5", "PC6", "PC7";
++                              function = "mmc2";
++                      };
++
++                      /omit-if-no-ref/
++                      rgmii_pe_pins: rgmii-pe-pins {
++                              pins = "PE0", "PE1", "PE2", "PE3", "PE4",
++                                     "PE5", "PE6", "PE7", "PE8", "PE9",
++                                     "PE11", "PE12", "PE13", "PE14", "PE15";
++                              function = "emac";
++                      };
++
++                      /omit-if-no-ref/
++                      spi0_pins: spi0-pins {
++                              pins = "PC2", "PC3", "PC4", "PC5", "PC6", "PC7";
++                              function = "spi0";
++                      };
++
++                      /omit-if-no-ref/
++                      spi1_pb_pins: spi1-pb-pins {
++                              pins = "PB0", "PB8", "PB9", "PB10", "PB11", "PB12";
++                              function = "spi1";
++                      };
++
++                      /omit-if-no-ref/
++                      spi1_pd_pins: spi1-pd-pins {
++                              pins = "PD10", "PD11", "PD12", "PD13", "PD14", "PD15";
++                              function = "spi1";
++                      };
++
++                      /omit-if-no-ref/
++                      uart0_pb8_pins: uart0-pb8-pins {
++                              pins = "PB8", "PB9";
++                              function = "uart0";
++                      };
++
++                      /omit-if-no-ref/
++                      uart1_pg6_pins: uart1-pg6-pins {
++                              pins = "PG6", "PG7";
++                              function = "uart1";
++                      };
++
++                      /omit-if-no-ref/
++                      uart1_pg8_rts_cts_pins: uart1-pg8-rts-cts-pins {
++                              pins = "PG8", "PG9";
++                              function = "uart1";
++                      };
++              };
++
++              pwm: pwm@2000c00 {
++                      compatible = "allwinner,sun20i-d1-pwm";
++                      reg = <0x2000c00 0x400>;
++                      clocks = <&ccu CLK_BUS_PWM>, <&osc24M>;
++                      clock-names = "bus", "mod";
++                      resets = <&ccu RST_BUS_PWM>;
++                      interrupts = <34 IRQ_TYPE_LEVEL_HIGH>;
++                      #pwm-cells = <3>;
++                      status = "disabled";
++              };
++
++              ccu: clock-controller@2001000 {
++                      compatible = "allwinner,sun20i-d1-ccu";
++                      reg = <0x2001000 0x1000>;
++                      clocks = <&osc24M>,
++                               <&rtc CLK_OSC32K>,
++                               <&rtc CLK_IOSC>;
++                      clock-names = "hosc", "losc", "iosc";
++                      #clock-cells = <1>;
++                      #reset-cells = <1>;
++              };
++
++              // TODO: write a binding and driver.
++              ir_tx: irled@2003000 {
++                      compatible = "allwinner,sun20i-d1-ir-tx";
++                      reg = <0x2003000 0x400>;
++                      clocks = <&ccu CLK_BUS_IR_TX>,
++                               <&osc24M>,
++                               <&ccu CLK_IR_TX>;
++                      clock-names = "bus", "pclk", "mclk";
++                      resets = <&ccu RST_BUS_IR_TX>;
++                      dmas = <&dma 13>;
++                      dma-names = "tx";
++                      interrupts = <35 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              ledc: led-controller@2008000 {
++                      compatible = "allwinner,sun20i-d1-ledc",
++                                   "allwinner,sun50i-r329-ledc";
++                      reg = <0x2008000 0x400>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_LEDC>, <&ccu CLK_LEDC>;
++                      clock-names = "bus", "mod";
++                      resets = <&ccu RST_BUS_LEDC>;
++                      dmas = <&dma 42>;
++                      dma-names = "tx";
++                      interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a binding and driver.
++              gpadc: adc@2009000 {
++                      compatible = "allwinner,sun20i-d1-gpadc";
++                      reg = <0x2009000 0x400>;
++                      clocks = <&ccu CLK_BUS_GPADC>;
++                      resets = <&ccu RST_BUS_GPADC>;
++                      dmas = <&dma 12>;
++                      dma-names = "rx";
++                      interrupts = <73 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              ths: temperature-sensor@2009400 {
++                      compatible = "allwinner,sun20i-d1-ths";
++                      reg = <0x2009400 0x400>;
++                      clocks = <&ccu CLK_BUS_THS>, <&osc24M>;
++                      clock-names = "bus", "mod";
++                      resets = <&ccu RST_BUS_THS>;
++                      interrupts = <74 IRQ_TYPE_LEVEL_HIGH>;
++                      nvmem-cells = <&ths_calib>;
++                      nvmem-cell-names = "calibration";
++                      #thermal-sensor-cells = <0>;
++              };
++
++              lradc: keys@2009800 {
++                      compatible = "allwinner,sun20i-d1-lradc",
++                                   "allwinner,sun50i-r329-lradc";
++                      reg = <0x2009800 0x400>;
++                      clocks = <&ccu CLK_BUS_LRADC>;
++                      resets = <&ccu RST_BUS_LRADC>;
++                      interrupts = <77 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a binding and driver.
++              tpadc: touchscreen@2009c00 {
++                      compatible = "allwinner,sun20i-d1-ts";
++                      reg = <0x2009c00 0x400>;
++                      clocks = <&ccu CLK_BUS_TPADC>, <&ccu CLK_TPADC>;
++                      clock-names = "bus", "mod";
++                      resets = <&ccu RST_BUS_TPADC>;
++                      dmas = <&dma 13>;
++                      dma-names = "rx";
++                      interrupts = <78 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // FIXME: this driver probably needs updates.
++              iommu: iommu@2010000 {
++                      compatible = "allwinner,sun20i-d1-iommu";
++                      reg = <0x2010000 0x10000>;
++                      clocks = <&ccu CLK_BUS_IOMMU>;
++                      interrupts = <80 IRQ_TYPE_LEVEL_HIGH>;
++                      #iommu-cells = <1>;
++              };
++
++              codec: audio-codec@2030000 {
++                      compatible = "allwinner,sun20i-d1-audio-codec";
++                      reg = <0x2030000 0x1000>;
++                      clocks = <&ccu CLK_BUS_AUDIO>,
++                               <&ccu CLK_AUDIO_ADC>,
++                               <&ccu CLK_AUDIO_DAC>,
++                               <&osc24M>,
++                               <&rtc CLK_OSC32K>;
++                      clock-names = "bus", "adc", "dac", "hosc", "losc";
++                      resets = <&ccu RST_BUS_AUDIO>;
++                      dmas = <&dma 7>, <&dma 7>;
++                      dma-names = "rx", "tx";
++                      interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
++                      #sound-dai-cells = <0>;
++                      status = "disabled";
++
++                      regulators {
++                              reg_aldo: aldo {
++                                      regulator-name = "aldo";
++                              };
++
++                              reg_hpldo: hpldo {
++                                      regulator-name = "hpldo";
++                              };
++                      };
++
++              };
++
++              // TODO: try the posted driver.
++              dmic: dmic@2031000 {
++                      compatible = "allwinner,sun20i-d1-dmic";
++                      reg = <0x2031000 0x400>;
++                      clocks = <&ccu CLK_BUS_DMIC>,
++                               <&ccu CLK_DMIC>;
++                      clock-names = "bus", "mod";
++                      resets = <&ccu RST_BUS_DMIC>;
++                      dmas = <&dma 8>;
++                      dma-names = "rx";
++                      interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
++                      #sound-dai-cells = <0>;
++                      status = "disabled";
++              };
++
++              i2s0: i2s@2032000 {
++                      compatible = "allwinner,sun20i-d1-i2s";
++                      reg = <0x2032000 0x1000>;
++                      clocks = <&ccu CLK_BUS_I2S0>,
++                               <&ccu CLK_I2S0>;
++                      clock-names = "apb", "mod";
++                      resets = <&ccu RST_BUS_I2S0>;
++                      dmas = <&dma 3>, <&dma 3>;
++                      dma-names = "rx", "tx";
++                      interrupts = <42 IRQ_TYPE_LEVEL_HIGH>;
++                      #sound-dai-cells = <0>;
++                      status = "disabled";
++              };
++
++              i2s1: i2s@2033000 {
++                      compatible = "allwinner,sun20i-d1-i2s";
++                      reg = <0x2033000 0x1000>;
++                      clocks = <&ccu CLK_BUS_I2S1>,
++                               <&ccu CLK_I2S1>;
++                      clock-names = "apb", "mod";
++                      resets = <&ccu RST_BUS_I2S1>;
++                      dmas = <&dma 4>, <&dma 4>;
++                      dma-names = "rx", "tx";
++                      interrupts = <43 IRQ_TYPE_LEVEL_HIGH>;
++                      #sound-dai-cells = <0>;
++                      status = "disabled";
++              };
++
++              // TODO: how to integrate ASRC? same or separate node?
++              i2s2: i2s@2034000 {
++                      compatible = "allwinner,sun20i-d1-i2s";
++                      reg = <0x2034000 0x1000>;
++                      clocks = <&ccu CLK_BUS_I2S2>,
++                               <&ccu CLK_I2S2>;
++                      clock-names = "apb", "mod";
++                      resets = <&ccu RST_BUS_I2S2>;
++                      dmas = <&dma 5>, <&dma 5>;
++                      dma-names = "rx", "tx";
++                      interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
++                      #sound-dai-cells = <0>;
++                      status = "disabled";
++              };
++
++              // TODO: add receive functionality
++              spdif: spdif@2036000 {
++                      compatible = "allwinner,sun20i-d1-spdif";
++                      reg = <0x2036000 0x400>;
++                      clocks = <&ccu CLK_BUS_SPDIF>,
++                               <&ccu CLK_SPDIF_RX>,
++                               <&ccu CLK_SPDIF_TX>;
++                      clock-names = "apb", "rx", "tx";
++                      resets = <&ccu RST_BUS_SPDIF>;
++                      dmas = <&dma 2>, <&dma 2>;
++                      dma-names = "rx", "tx";
++                      interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
++                      #sound-dai-cells = <0>;
++                      status = "disabled";
++              };
++
++              timer: timer@2050000 {
++                      compatible = "allwinner,sun20i-d1-timer",
++                                   "allwinner,sun8i-a23-timer";
++                      reg = <0x2050000 0xa0>;
++                      clocks = <&osc24M>;
++                      interrupts = <75 IRQ_TYPE_LEVEL_HIGH>,
++                                   <76 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              wdt: watchdog@20500a0 {
++                      compatible = "allwinner,sun20i-d1-wdt-reset",
++                                   "allwinner,sun20i-d1-wdt";
++                      reg = <0x20500a0 0x20>;
++                      clocks = <&osc24M>;
++                      interrupts = <79 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "reserved";
++              };
++
++              // TODO: write a driver.
++              uart0: serial@2500000 {
++                      compatible = "allwinner,sun20i-d1-uart",
++                                   "snps,dw-apb-uart";
++                      reg = <0x2500000 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      clocks = <&ccu CLK_BUS_UART0>;
++                      resets = <&ccu RST_BUS_UART0>;
++                      dmas = <&dma 14>, <&dma 14>;
++                      dma-names = "rx", "tx";
++                      fifo-size = <64>;
++                      interrupts = <18 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a driver, add IDMA?
++              uart1: serial@2500400 {
++                      compatible = "allwinner,sun20i-d1-uart1",
++                                   "allwinner,sun20i-d1-uart",
++                                   "snps,dw-apb-uart";
++                      reg = <0x2500400 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      clocks = <&ccu CLK_BUS_UART1>;
++                      resets = <&ccu RST_BUS_UART1>;
++                      dmas = <&dma 15>, <&dma 15>;
++                      dma-names = "rx", "tx";
++                      fifo-size = <256>;
++                      interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a driver.
++              uart2: serial@2500800 {
++                      compatible = "allwinner,sun20i-d1-uart",
++                                   "snps,dw-apb-uart";
++                      reg = <0x2500800 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      clocks = <&ccu CLK_BUS_UART2>;
++                      resets = <&ccu RST_BUS_UART2>;
++                      dmas = <&dma 16>, <&dma 16>;
++                      dma-names = "rx", "tx";
++                      fifo-size = <256>;
++                      interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a driver.
++              uart3: serial@2500c00 {
++                      compatible = "allwinner,sun20i-d1-uart",
++                                   "snps,dw-apb-uart";
++                      reg = <0x2500c00 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      clocks = <&ccu CLK_BUS_UART3>;
++                      resets = <&ccu RST_BUS_UART3>;
++                      dmas = <&dma 17>, <&dma 17>;
++                      dma-names = "rx", "tx";
++                      fifo-size = <256>;
++                      interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a driver.
++              uart4: serial@2501000 {
++                      compatible = "allwinner,sun20i-d1-uart",
++                                   "snps,dw-apb-uart";
++                      reg = <0x2501000 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      clocks = <&ccu CLK_BUS_UART4>;
++                      resets = <&ccu RST_BUS_UART4>;
++                      dmas = <&dma 18>, <&dma 18>;
++                      dma-names = "rx", "tx";
++                      fifo-size = <256>;
++                      interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              // TODO: write a driver.
++              uart5: serial@2501400 {
++                      compatible = "allwinner,sun20i-d1-uart",
++                                   "snps,dw-apb-uart";
++                      reg = <0x2501400 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      clocks = <&ccu CLK_BUS_UART5>;
++                      resets = <&ccu RST_BUS_UART5>;
++                      dmas = <&dma 19>, <&dma 19>;
++                      dma-names = "rx", "tx";
++                      fifo-size = <256>;
++                      interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              i2c0: i2c@2502000 {
++                      compatible = "allwinner,sun20i-d1-i2c",
++                                   "allwinner,sun6i-a31-i2c";
++                      reg = <0x2502000 0x400>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_I2C0>;
++                      resets = <&ccu RST_BUS_I2C0>;
++                      dmas = <&dma 43>, <&dma 43>;
++                      dma-names = "rx", "tx";
++                      interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              i2c1: i2c@2502400 {
++                      compatible = "allwinner,sun20i-d1-i2c",
++                                   "allwinner,sun6i-a31-i2c";
++                      reg = <0x2502400 0x400>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_I2C1>;
++                      resets = <&ccu RST_BUS_I2C1>;
++                      dmas = <&dma 44>, <&dma 44>;
++                      dma-names = "rx", "tx";
++                      interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              i2c2: i2c@2502800 {
++                      compatible = "allwinner,sun20i-d1-i2c",
++                                   "allwinner,sun6i-a31-i2c";
++                      reg = <0x2502800 0x400>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_I2C2>;
++                      resets = <&ccu RST_BUS_I2C2>;
++                      dmas = <&dma 45>, <&dma 45>;
++                      dma-names = "rx", "tx";
++                      interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              i2c3: i2c@2502c00 {
++                      compatible = "allwinner,sun20i-d1-i2c",
++                                   "allwinner,sun6i-a31-i2c";
++                      reg = <0x2502c00 0x400>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_I2C3>;
++                      resets = <&ccu RST_BUS_I2C3>;
++                      dmas = <&dma 46>, <&dma 46>;
++                      dma-names = "rx", "tx";
++                      interrupts = <28 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              syscon: syscon@3000000 {
++                      compatible = "allwinner,sun20i-d1-system-control";
++                      reg = <0x3000000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++                      ranges;
++
++                      regulators {
++                              reg_ldoa: ldoa {
++                                      regulator-name = "ldoa";
++                              };
++
++                              reg_ldob: ldob {
++                                      regulator-name = "ldob";
++                              };
++                      };
++
++                      sram@400000 {
++                              compatible = "mmio-sram";
++                              reg = <0x400000 0x20000>;
++                              #address-cells = <1>;
++                              #size-cells = <1>;
++                              ranges = <0 0x400000 0x20000>;
++
++                              /*
++                               * This can be further divided into DSP IRAM,
++                               * DSP DRAM0, and DSP DRAM1, but the mapping
++                               * of all three is controlled by a single bit.
++                               */
++                              dsp_sram: sram-section@0 {
++                                      compatible = "allwinner,sun20i-d1-dsp-sram";
++                                      reg = <0 0x20000>;
++                              };
++                      };
++
++                      // FIXME: Address is not verified. It is copied from A64/H6.
++                      sram@1d00000 {
++                              compatible = "mmio-sram";
++                              reg = <0x1d00000 0x40000>;
++                              #address-cells = <1>;
++                              #size-cells = <1>;
++                              ranges = <0 0x1d00000 0x40000>;
++
++                              ve_sram: sram-section@0 {
++                                      compatible = "allwinner,sun20i-d1-sram-c1",
++                                                   "allwinner,sun4i-a10-sram-c1";
++                                      reg = <0 0x40000>;
++                              };
++                      };
++              };
++
++              dma: dma-controller@3002000 {
++                      compatible = "allwinner,sun20i-d1-dma";
++                      reg = <0x3002000 0x1000>;
++                      clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>;
++                      clock-names = "bus", "mbus";
++                      resets = <&ccu RST_BUS_DMA>;
++                      #dma-cells = <1>;
++                      dma-channels = <16>;
++                      dma-requests = <48>;
++                      interrupts = <66 IRQ_TYPE_LEVEL_HIGH>,
++                                   <142 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              msgbox: mailbox@3003000 {
++                      compatible = "allwinner,sun20i-d1-msgbox";
++                      reg = <0x3003000 0x1000>;
++                      clocks = <&ccu CLK_BUS_MSGBOX0>;
++                      resets = <&ccu RST_BUS_MSGBOX0>;
++                      interrupts = <101 IRQ_TYPE_LEVEL_HIGH>,
++                                   <102 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "rx", "tx";
++                      #mbox-cells = <2>;
++              };
++
++              hwspinlock: hwlock@3005000 {
++                      compatible = "allwinner,sun20i-d1-hwspinlock",
++                                   "allwinner,sun6i-a31-hwspinlock";
++                      reg = <0x3005000 0x1000>;
++                      clocks = <&ccu CLK_BUS_SPINLOCK>;
++                      resets = <&ccu RST_BUS_SPINLOCK>;
++                      interrupts = <70 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              sid: efuse@3006000 {
++                      compatible = "allwinner,sun20i-d1-sid",
++                                   "allwinner,sun50i-a64-sid";
++                      reg = <0x3006000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++
++                      cpu_speed_grade: cpu-speed-grade@0 {
++                              reg = <0x0 0x2>;
++                      };
++
++                      ths_calib: ths-calib@14 {
++                              reg = <0x14 0x4>;
++                      };
++              };
++
++              // TODO: write a binding and driver.
++              hstimer: timer@3008000 {
++                      compatible = "allwinner,sun20i-d1-hstimer",
++                                   "allwinner,sun50i-h6-hstimer";
++                      reg = <0x3008000 0x1000>;
++                      clocks = <&ccu CLK_BUS_HSTIMER>;
++                      resets = <&ccu RST_BUS_HSTIMER>;
++                      interrupts = <71 IRQ_TYPE_LEVEL_HIGH>,
++                                   <72 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              crypto: crypto@3040000 {
++                      compatible = "allwinner,sun20i-d1-crypto";
++                      reg = <0x3040000 0x800>;
++                      clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>, <&ccu CLK_MBUS_CE>;
++                      clock-names = "bus", "mod", "ram";
++                      resets = <&ccu RST_BUS_CE>;
++                      interrupts = <68 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              // TODO: write a binding and driver.
++              mbus: dram-controller@3102000 {
++                      compatible = "allwinner,sun20i-d1-mbus";
++                      reg = <0x3102000 0x200000>;
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++                      clocks = <&ccu CLK_BUS_DRAM>,
++                               <&ccu CLK_DRAM>,
++                               <&ccu CLK_MBUS>;
++                      clock-names = "bus", "dram", "mbus";
++                      dma-ranges = <0 0x40000000 0x80000000>;
++                      #interconnect-cells = <1>;
++                      interrupts = <59 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              mmc0: mmc@4020000 {
++                      compatible = "allwinner,sun20i-d1-mmc";
++                      reg = <0x4020000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
++                      clock-names = "ahb", "mmc";
++                      resets = <&ccu RST_BUS_MMC0>;
++                      reset-names = "ahb";
++                      cap-sd-highspeed;
++                      interrupts = <56 IRQ_TYPE_LEVEL_HIGH>;
++                      max-frequency = <150000000>;
++                      no-mmc;
++                      status = "disabled";
++              };
++
++              mmc1: mmc@4021000 {
++                      compatible = "allwinner,sun20i-d1-mmc";
++                      reg = <0x4021000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
++                      clock-names = "ahb", "mmc";
++                      resets = <&ccu RST_BUS_MMC1>;
++                      reset-names = "ahb";
++                      cap-sd-highspeed;
++                      interrupts = <57 IRQ_TYPE_LEVEL_HIGH>;
++                      max-frequency = <150000000>;
++                      no-mmc;
++                      status = "disabled";
++              };
++
++              mmc2: mmc@4022000 {
++                      compatible = "allwinner,sun20i-d1-emmc";
++                      reg = <0x4022000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
++                      clock-names = "ahb", "mmc";
++                      resets = <&ccu RST_BUS_MMC2>;
++                      reset-names = "ahb";
++                      cap-mmc-highspeed;
++                      interrupts = <58 IRQ_TYPE_LEVEL_HIGH>;
++                      max-frequency = <150000000>;
++                      mmc-ddr-1_8v;
++                      mmc-ddr-3_3v;
++                      no-sd;
++                      no-sdio;
++                      status = "disabled";
++              };
++
++              spi0: spi@4025000 {
++                      compatible = "allwinner,sun20i-d1-spi",
++                                   "allwinner,sun50i-r329-spi";
++                      reg = <0x4025000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
++                      clock-names = "ahb", "mod";
++                      resets = <&ccu RST_BUS_SPI0>;
++                      dmas = <&dma 22>, <&dma 22>;
++                      dma-names = "rx", "tx";
++                      interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
++                      num-cs = <1>;
++                      status = "disabled";
++              };
++
++              spi1: spi@4026000 {
++                      compatible = "allwinner,sun20i-d1-spi-dbi",
++                                   "allwinner,sun50i-r329-spi-dbi",
++                                   "allwinner,sun50i-r329-spi";
++                      reg = <0x4026000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
++                      clock-names = "ahb", "mod";
++                      resets = <&ccu RST_BUS_SPI1>;
++                      dmas = <&dma 23>, <&dma 23>;
++                      dma-names = "rx", "tx";
++                      interrupts = <32 IRQ_TYPE_LEVEL_HIGH>;
++                      num-cs = <1>;
++                      status = "disabled";
++              };
++
++              usb_otg: usb@4100000 {
++                      compatible = "allwinner,sun20i-d1-musb",
++                                   "allwinner,sun8i-a33-musb";
++                      reg = <0x4100000 0x400>;
++                      clocks = <&ccu CLK_BUS_OTG>;
++                      resets = <&ccu RST_BUS_OTG>;
++                      dmas = <&dma 30>, <&dma 30>,
++                             <&dma 31>, <&dma 31>,
++                             <&dma 32>, <&dma 32>,
++                             <&dma 33>, <&dma 33>,
++                             <&dma 34>, <&dma 34>;
++                      dma-names = "ep1_rx", "ep1_tx",
++                                  "ep2_rx", "ep2_tx",
++                                  "ep3_rx", "ep3_tx",
++                                  "ep4_rx", "ep4_tx",
++                                  "ep5_rx", "ep5_tx";
++                      extcon = <&usbphy 0>;
++                      interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "mc";
++                      phys = <&usbphy 0>;
++                      phy-names = "usb";
++                      status = "disabled";
++              };
++
++              usbphy: phy@4100400 {
++                      compatible = "allwinner,sun20i-d1-usb-phy";
++                      reg = <0x4100400 0x100>,
++                            <0x4101800 0x100>,
++                            <0x4200800 0x100>;
++                      reg-names = "phy_ctrl",
++                                  "pmu0",
++                                  "pmu1";
++                      clocks = <&osc24M>,
++                               <&osc24M>;
++                      clock-names = "usb0_phy",
++                                    "usb1_phy";
++                      resets = <&ccu RST_USB_PHY0>,
++                               <&ccu RST_USB_PHY1>;
++                      reset-names = "usb0_reset",
++                                    "usb1_reset";
++                      #phy-cells = <1>;
++                      status = "disabled";
++              };
++
++              ehci0: usb@4101000 {
++                      compatible = "allwinner,sun20i-d1-ehci",
++                                   "generic-ehci";
++                      reg = <0x4101000 0x100>;
++                      clocks = <&ccu CLK_BUS_OHCI0>,
++                               <&ccu CLK_BUS_EHCI0>,
++                               <&ccu CLK_USB_OHCI0>;
++                      resets = <&ccu RST_BUS_OHCI0>,
++                               <&ccu RST_BUS_EHCI0>;
++                      interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
++                      phys = <&usbphy 0>;
++                      phy-names = "usb";
++                      status = "disabled";
++              };
++
++              ohci0: usb@4101400 {
++                      compatible = "allwinner,sun20i-d1-ohci",
++                                   "generic-ohci";
++                      reg = <0x4101400 0x100>;
++                      clocks = <&ccu CLK_BUS_OHCI0>,
++                               <&ccu CLK_USB_OHCI0>;
++                      resets = <&ccu RST_BUS_OHCI0>;
++                      interrupts = <47 IRQ_TYPE_LEVEL_HIGH>;
++                      phys = <&usbphy 0>;
++                      phy-names = "usb";
++                      status = "disabled";
++              };
++
++              ehci1: usb@4200000 {
++                      compatible = "allwinner,sun20i-d1-ehci",
++                                   "generic-ehci";
++                      reg = <0x4200000 0x100>;
++                      clocks = <&ccu CLK_BUS_OHCI1>,
++                               <&ccu CLK_BUS_EHCI1>,
++                               <&ccu CLK_USB_OHCI1>;
++                      resets = <&ccu RST_BUS_OHCI1>,
++                               <&ccu RST_BUS_EHCI1>;
++                      interrupts = <49 IRQ_TYPE_LEVEL_HIGH>;
++                      phys = <&usbphy 1>;
++                      phy-names = "usb";
++                      status = "disabled";
++              };
++
++              ohci1: usb@4200400 {
++                      compatible = "allwinner,sun20i-d1-ohci",
++                                   "generic-ohci";
++                      reg = <0x4200400 0x100>;
++                      clocks = <&ccu CLK_BUS_OHCI1>,
++                               <&ccu CLK_USB_OHCI1>;
++                      resets = <&ccu RST_BUS_OHCI1>;
++                      interrupts = <50 IRQ_TYPE_LEVEL_HIGH>;
++                      phys = <&usbphy 1>;
++                      phy-names = "usb";
++                      status = "disabled";
++              };
++
++              emac: ethernet@4500000 {
++                      compatible = "allwinner,sun20i-d1-emac",
++                                   "allwinner,sun50i-a64-emac";
++                      reg = <0x4500000 0x10000>;
++                      clocks = <&ccu CLK_BUS_EMAC>;
++                      clock-names = "stmmaceth";
++                      resets = <&ccu RST_BUS_EMAC>;
++                      reset-names = "stmmaceth";
++                      interrupts = <62 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "macirq";
++                      syscon = <&syscon>;
++                      status = "disabled";
++
++                      mdio: mdio {
++                              compatible = "snps,dwmac-mdio";
++                              #address-cells = <1>;
++                              #size-cells = <0>;
++                      };
++              };
++
++              de: display-engine@5000000 {
++                      reg = <0x5000000 0x400000>;
++                      interrupts = <103 IRQ_TYPE_LEVEL_HIGH>;
++                      interconnects = <&mbus 11>;
++                      interconnect-names = "dma-mem";
++                      iommus = <&iommu 2>;
++              };
++
++              deinterlace: deinterlace@5400000 {
++                      reg = <0x5400000 0x10000>;
++                      interconnects = <&mbus 10>;
++                      interconnect-names = "dma-mem";
++                      interrupts = <104 IRQ_TYPE_LEVEL_HIGH>;
++                      iommus = <&iommu 4>;
++              };
++
++              g2d: g2d@5410000 {
++                      reg = <0x5410000 0x40000>;
++                      interconnects = <&mbus 9>;
++                      interconnect-names = "dma-mem";
++                      interrupts = <105 IRQ_TYPE_LEVEL_HIGH>;
++                      iommus = <&iommu 3>;
++              };
++
++              dsi: dsi@5450000 {
++                      reg = <0x5450000 0x2000>;
++                      interrupts = <108 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              tcon_top: tcon-top@5460000 {
++                      reg = <0x5460000 0x1000>;
++              };
++
++              tcon_lcd: lcd-controller@5461000 {
++                      reg = <0x5461000 0x1000>;
++                      interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              tcon_tv: lcd-controller@5470000 {
++                      reg = <0x5470000 0x1000>;
++                      interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              hdmi: hdmi@5500000 {
++                      reg = <0x5500000 0x100000>;
++                      interrupts = <109 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              tve_top: video-codec@5600000 {
++                      reg = <0x5600000 0x4000>;
++              };
++
++              tve0: video-codec@5604000 {
++                      reg = <0x5604000 0x4000>;
++                      interrupts = <110 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              csi: csi@5800000 {
++                      reg = <0x5800000 0x400000>;
++                      interrupts = <111 IRQ_TYPE_LEVEL_HIGH>,
++                                   <112 IRQ_TYPE_LEVEL_HIGH>,
++                                   <116 IRQ_TYPE_LEVEL_HIGH>,
++                                   <122 IRQ_TYPE_LEVEL_HIGH>;
++                      interconnects = <&mbus 7>;
++                      interconnect-names = "dma-mem";
++                      iommus = <&iommu 1>;
++              };
++
++              tvd_top: video-codec@5c00000 {
++                      reg = <0x5c00000 0x1000>;
++                      interconnects = <&mbus 6>;
++                      interconnect-names = "dma-mem";
++              };
++
++              tvd0: video-codec@5c01000 {
++                      reg = <0x5c01000 0x1000>;
++                      interrupts = <123 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              intc: interrupt-controller@6010000 {
++                      compatible = "allwinner,sun20i-d1-intc";
++                      reg = <0x6010000 0x100>;
++                      #address-cells = <0>;
++                      clocks = <&ccu CLK_BUS_RISCV_CFG>;
++                      resets = <&ccu RST_BUS_RISCV_CFG>;
++                      interrupt-parent = <&plic>;
++                      interrupt-controller;
++                      #interrupt-cells = <2>;
++              };
++
++              riscv_wdt: watchdog@6011000 {
++                      compatible = "allwinner,sun20i-d1-wdt";
++                      reg = <0x6011000 0x20>;
++                      clocks = <&osc24M>;
++                      interrupts = <147 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              riscv_msgbox: mailbox@601f000 {
++                      compatible = "allwinner,sun20i-d1-msgbox";
++                      reg = <0x601f000 0x1000>;
++                      clocks = <&ccu CLK_BUS_MSGBOX2>;
++                      resets = <&ccu RST_BUS_MSGBOX2>;
++                      interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
++                                   <145 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "rx", "tx";
++                      #mbox-cells = <2>;
++              };
++
++              r_ccu: clock-controller@7010000 {
++                      compatible = "allwinner,sun20i-d1-r-ccu";
++                      reg = <0x7010000 0x400>;
++                      clocks = <&osc24M>,
++                               <&rtc CLK_OSC32K>,
++                               <&rtc CLK_IOSC>,
++                               <&ccu CLK_PLL_PERIPH0_DIV3>;
++                      clock-names = "hosc", "losc", "iosc", "pll-periph";
++                      #clock-cells = <1>;
++                      #reset-cells = <1>;
++                      interrupts = <64 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              r_ir_rx: ir@7040000 {
++                      compatible = "allwinner,sun20i-d1-ir",
++                                   "allwinner,sun6i-a31-ir";
++                      reg = <0x7040000 0x400>;
++                      clocks = <&r_ccu CLK_BUS_R_IR_RX>, <&r_ccu CLK_R_IR_RX>;
++                      clock-names = "apb", "ir";
++                      resets = <&r_ccu RST_BUS_R_IR_RX>;
++                      interrupts = <167 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              // TODO: audit all blocks for hidden use of CLK_DCXO24M
++              rtc: rtc@7090000 {
++                      compatible = "allwinner,sun20i-d1-rtc",
++                                   "allwinner,sun50i-r329-rtc";
++                      reg = <0x7090000 0x400>;
++                      clocks = <&r_ccu CLK_BUS_R_RTC>,
++                               <&osc24M>,
++                               <&r_ccu CLK_R_AHB>;
++                      clock-names = "bus", "hosc", "ahb";
++                      #clock-cells = <1>;
++                      interrupts = <160 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
++              plic: interrupt-controller@10000000 {
++                      compatible = "allwinner,sun20i-d1-plic",
++                                   "thead,c900-plic";
++                      reg = <0x10000000 0x4000000>;
++                      #address-cells = <0>;
++                      interrupts-extended = <&cpu0_intc 11>,
++                                            <&cpu0_intc 9>;
++                      interrupt-controller;
++                      #interrupt-cells = <1>;
++                      riscv,ndev = <176>;
++              };
++
++              clint: clint@14000000 {
++                      compatible = "allwinner,sun20i-d1-clint",
++                                   "sifive,clint0";
++                      reg = <0x14000000 0xc000>;
++                      reg-io-width = <4>;
++                      interrupts-extended = <&cpu0_intc 3>,
++                                            <&cpu0_intc 7>;
++              };
++      };
++};
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0120-riscv-Add-D1-Nezha-board-device-tree.patch b/target/linux/sunxid1/patches-5.15/0120-riscv-Add-D1-Nezha-board-device-tree.patch
new file mode 100644 (file)
index 0000000..cc1a2a9
--- /dev/null
@@ -0,0 +1,405 @@
+From 5ff65d483cc6aa18f21900a72ab3e78eb2308031 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 16 May 2021 14:18:46 -0500
+Subject: [PATCH 120/124] riscv: Add D1 Nezha board device tree
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/boot/dts/allwinner/Makefile        |   1 +
+ .../boot/dts/allwinner/sun20i-d1-nezha.dts    | 377 ++++++++++++++++++
+ 2 files changed, 378 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts
+
+diff --git a/arch/riscv/boot/dts/allwinner/Makefile b/arch/riscv/boot/dts/allwinner/Makefile
+index f66554cd5c45..b0a15e8c8d82 100644
+--- a/arch/riscv/boot/dts/allwinner/Makefile
++++ b/arch/riscv/boot/dts/allwinner/Makefile
+@@ -1 +1,2 @@
+ # SPDX-License-Identifier: GPL-2.0
++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-nezha.dtb
+diff --git a/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts
+new file mode 100644
+index 000000000000..cab31cb2b346
+--- /dev/null
++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts
+@@ -0,0 +1,377 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include "sun20i-d1.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/leds/common.h>
++#include <dt-bindings/pwm/pwm.h>
++
++/ {
++      model = "Allwinner D1 NeZha";
++      compatible = "allwinner,d1-nezha", "allwinner,sun20i-d1";
++
++      aliases {
++              ethernet0 = &emac;
++              mmc0 = &mmc0;
++              mmc1 = &mmc1;
++              mmc2 = &mmc2;
++              serial0 = &uart0;
++              spi0 = &spi0;
++      };
++
++      memory@40000000 {
++              device_type = "memory";
++              reg = <0x40000000 0x20000000>;
++      };
++
++      chosen {
++              stdout-path = "serial0:115200n8";
++      };
++
++      hdmi_connector: connector {
++              compatible = "hdmi-connector";
++              type = "a";
++
++              port {
++                      hdmi_con_in: endpoint {
++                              // FIXME: remote-endpoint = <&hdmi_out_con>;
++                      };
++              };
++      };
++
++      reg_usbvbus: usbvbus {
++              compatible = "regulator-fixed";
++              regulator-name = "usbvbus";
++              regulator-min-microvolt = <5000000>;
++              regulator-max-microvolt = <5000000>;
++              gpio = <&gpio 3 19 GPIO_ACTIVE_HIGH>; /* PD19 */
++              enable-active-high;
++              vin-supply = <&reg_vcc>;
++      };
++
++      reg_vcc: vcc {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc";
++              regulator-min-microvolt = <5000000>;
++              regulator-max-microvolt = <5000000>;
++      };
++
++      reg_vcc_3v3: vcc-3v3 {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-3v3";
++              regulator-min-microvolt = <3300000>;
++              regulator-max-microvolt = <3300000>;
++              vin-supply = <&reg_vcc>;
++      };
++
++      reg_vdd_cpu: vdd-cpu {
++              compatible = "pwm-regulator";
++              pwms = <&pwm 0 50000 0>;
++              pwm-supply = <&reg_vcc>;
++              regulator-name = "vdd-cpu";
++              regulator-min-microvolt = <810000>;
++              regulator-max-microvolt = <1160000>;
++      };
++
++      wifi_pwrseq: wifi-pwrseq {
++              compatible = "mmc-pwrseq-simple";
++              reset-gpios = <&gpio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */
++      };
++};
++
++&codec {
++      allwinner,routing = "Headphone Jack", "HPOUTL",
++                          "Headphone Jack", "HPOUTR",
++                          "LINEINL", "HPOUTL",
++                          "LINEINR", "HPOUTR",
++                          "MICIN3", "Headset Microphone",
++                          "Headset Microphone", "HBIAS";
++      allwinner,widgets = "Microphone", "Headset Microphone",
++                          "Headphone", "Headphone Jack";
++      avcc-supply = <&reg_aldo>;
++      hpvcc-supply = <&reg_hpldo>;
++      vdd33-supply = <&reg_vcc_3v3>;
++      status = "okay";
++};
++
++&cpu0 {
++      cpu-supply = <&reg_vdd_cpu>;
++};
++
++&ehci0 {
++      status = "okay";
++};
++
++&ehci1 {
++      status = "okay";
++};
++
++&emac {
++      pinctrl-0 = <&rgmii_pe_pins>;
++      pinctrl-names = "default";
++      phy-handle = <&ext_rgmii_phy>;
++      phy-mode = "rgmii-id";
++      phy-supply = <&reg_vcc_3v3>;
++      status = "okay";
++};
++
++&gpio {
++      vcc-pa-supply = <&reg_vcc_3v3>;
++      vcc-pb-supply = <&reg_vcc_3v3>;
++      vcc-pc-supply = <&reg_vcc_3v3>;
++      vcc-pd-supply = <&reg_vcc_3v3>;
++      vcc-pe-supply = <&reg_vcc_3v3>;
++      vcc-pf-supply = <&reg_vcc_3v3>;
++      vcc-pg-supply = <&reg_vcc_3v3>;
++
++      i2s2_pb_pins: i2s2-pb-pins {
++              pins = "PB5", "PB6", "PB7";
++              function = "i2s2";
++      };
++
++      i2s2_pb3_din_pin: i2s2-pb3-din-pin {
++              pins = "PB3";
++              function = "i2s2_din";
++      };
++
++      i2s2_pb4_dout_pin: i2s2-pb4-dout-pin {
++              pins = "PB4";
++              function = "i2s2_dout";
++      };
++
++      ledc_pc0_pin: ledc-pc0-pin {
++              pins = "PC0";
++              function = "ledc";
++      };
++
++      pwm0_pd16_pin: pwm0-pd16-pin {
++              pins = "PD16";
++              function = "pwm";
++      };
++
++      pwm2_pd18_pin: pwm2-pd18-pin {
++              pins = "PD18";
++              function = "pwm";
++      };
++
++      pwm7_pd22_pin: pwm7-pd22-pin {
++              pins = "PD22";
++              function = "pwm";
++      };
++
++      spdif_pd22_pin: spdif-pd22-pin {
++              pins = "PD22";
++              function = "spdif";
++      };
++};
++
++&i2c0 {
++      pinctrl-0 = <&i2c0_pb10_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&i2c2 {
++      pinctrl-0 = <&i2c2_pb0_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++
++      pcf8574a: gpio@38 {
++              compatible = "nxp,pcf8574a";
++              #address-cells = <0>;
++              reg = <0x38>;
++              gpio-controller;
++              #gpio-cells = <2>;
++              interrupts-extended = <&gpio 1 2 IRQ_TYPE_LEVEL_LOW>; /* PB2 */
++              interrupt-controller;
++              #interrupt-cells = <2>;
++      };
++};
++
++&i2s2 {
++      pinctrl-0 = <&i2s2_pb_pins>, <&i2s2_pb3_din_pin>, <&i2s2_pb4_dout_pin>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&ledc {
++      pinctrl-0 = <&ledc_pc0_pin>;
++      pinctrl-names = "default";
++      status = "okay";
++
++      led@0 {
++              reg = <0x0>;
++              color = <LED_COLOR_ID_RGB>;
++              function = LED_FUNCTION_INDICATOR;
++      };
++};
++
++&lradc {
++      vref-supply = <&reg_aldo>;
++      wakeup-source;
++      status = "okay";
++
++      button-160 {
++              label = "OK";
++              linux,code = <KEY_OK>;
++              channel = <0>;
++              voltage = <160000>;
++      };
++};
++
++&mdio {
++      ext_rgmii_phy: ethernet-phy@1 {
++              compatible = "ethernet-phy-ieee802.3-c22";
++              reg = <1>;
++      };
++};
++
++&mmc0 {
++      bus-width = <4>;
++      cd-gpios = <&gpio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
++      disable-wp;
++      vmmc-supply = <&reg_vcc_3v3>;
++      vqmmc-supply = <&reg_vcc_3v3>;
++      pinctrl-0 = <&mmc0_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&mmc1 {
++      bus-width = <4>;
++      mmc-pwrseq = <&wifi_pwrseq>;
++      non-removable;
++      vmmc-supply = <&reg_vcc_3v3>;
++      vqmmc-supply = <&reg_vcc_3v3>;
++      pinctrl-0 = <&mmc1_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++
++      xr829: wifi@1 {
++              reg = <1>;
++              host-wake-gpios = <&gpio 6 10 GPIO_ACTIVE_LOW>; /* PG10 */
++      };
++};
++
++&ohci0 {
++      status = "okay";
++};
++
++&ohci1 {
++      status = "okay";
++};
++
++&pwm {
++      pinctrl-0 = <&pwm0_pd16_pin>, <&pwm2_pd18_pin>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&reg_aldo {
++      regulator-min-microvolt = <1800000>;
++      regulator-max-microvolt = <1800000>;
++      vdd33-supply = <&reg_vcc_3v3>;
++};
++
++&reg_hpldo {
++      regulator-min-microvolt = <1800000>;
++      regulator-max-microvolt = <1800000>;
++      hpldoin-supply = <&reg_vcc_3v3>;
++};
++
++&reg_ldoa {
++      regulator-always-on;
++      regulator-min-microvolt = <1800000>;
++      regulator-max-microvolt = <1800000>;
++      ldo-in-supply = <&reg_vcc_3v3>;
++};
++
++&spdif {
++      pinctrl-0 = <&spdif_pd22_pin>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&spi0 {
++      pinctrl-0 = <&spi0_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++
++      flash@0 {
++              compatible = "spi-nand";
++              reg = <0>;
++
++              partitions {
++                      compatible = "fixed-partitions";
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++
++                      partition@0 {
++                              label = "boot0";
++                              reg = <0x00000000 0x00100000>;
++                      };
++
++                      partition@100000 {
++                              label = "uboot";
++                              reg = <0x00100000 0x00300000>;
++                      };
++
++                      partition@400000 {
++                              label = "secure_storage";
++                              reg = <0x00400000 0x00100000>;
++                      };
++
++                      partition@500000 {
++                              label = "sys";
++                              reg = <0x00500000 0x0fb00000>;
++                      };
++              };
++      };
++};
++
++&spi1 {
++      pinctrl-0 = <&spi1_pd_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&ths {
++      vref-supply = <&reg_aldo>;
++};
++
++&uart0 {
++      pinctrl-0 = <&uart0_pb8_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++};
++
++&uart1 {
++      pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
++      pinctrl-names = "default";
++      status = "okay";
++
++      bluetooth {
++              compatible = "xradio,xr829-bt";
++              device-wakeup-gpios = <&gpio 6 16 GPIO_ACTIVE_LOW>; /* PG16 */
++              interrupts-extended = <&gpio 6 17 IRQ_TYPE_LEVEL_LOW>; /* PG17 */
++              interrupt-names = "wakeup";
++              reset-gpios = <&gpio 6 18 GPIO_ACTIVE_LOW>; /* PG18 */
++      };
++};
++
++&usb_otg {
++      dr_mode = "otg";
++      status = "okay";
++};
++
++&usbphy {
++      usb0_id_det-gpios = <&gpio 3 21 GPIO_ACTIVE_LOW>; /* PD21 */
++      usb0_vbus_det-gpios = <&gpio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */
++      usb0_vbus-supply = <&reg_usbvbus>;
++      usb1_vbus-supply = <&reg_vcc>;
++      status = "okay";
++};
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0121-misc-changes.patch b/target/linux/sunxid1/patches-5.15/0121-misc-changes.patch
new file mode 100644 (file)
index 0000000..77417d6
--- /dev/null
@@ -0,0 +1,272 @@
+From bbac293092123341e0eaa3905508e2264f6b1cec Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 13 Jun 2021 23:54:42 -0500
+Subject: [PATCH 121/124] misc changes
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/Kconfig                    |  2 +-
+ arch/riscv/mm/physaddr.c              |  2 +-
+ drivers/mmc/host/sunxi-mmc.c          | 15 +++++++++++----
+ drivers/of/irq.c                      |  7 ++++---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c |  8 ++++++++
+ include/linux/dmaengine.h             |  2 +-
+ sound/soc/soc-core.c                  |  3 +++
+ sound/soc/soc-dapm.c                  |  2 +-
+ sound/soc/sunxi/Makefile              |  4 ++--
+ sound/soc/sunxi/sun4i-i2s.c           |  6 ------
+ sound/soc/sunxi/sun4i-spdif.c         | 11 +++++++++--
+ 11 files changed, 41 insertions(+), 21 deletions(-)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index 5f11f14f93a8..b942ba3e8eae 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -261,7 +261,7 @@ config ARCH_RV64I
+       select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_TRACER if !XIP_KERNEL
+-      select SWIOTLB if MMU
++      # select SWIOTLB if MMU
+ endchoice
+diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c
+index e7fd0c253c7b..917d9868bb90 100644
+--- a/arch/riscv/mm/physaddr.c
++++ b/arch/riscv/mm/physaddr.c
+@@ -14,7 +14,7 @@ phys_addr_t __virt_to_phys(unsigned long x)
+        * Boundary checking aginst the kernel linear mapping space.
+        */
+       WARN(y >= KERN_VIRT_SIZE,
+-           "virt_to_phys used for non-linear address: %pK (%pS)\n",
++           "virt_to_phys used for non-linear address: %p (%pS)\n",
+            (void *)x, (void *)x);
+       return __va_to_pa_nodebug(x);
+diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
+index e6a21bcc3b47..09a85de3e5f2 100644
+--- a/drivers/mmc/host/sunxi-mmc.c
++++ b/drivers/mmc/host/sunxi-mmc.c
+@@ -749,6 +749,17 @@ static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off)
+        */
+       writel(SDXC_CAL_DL_SW_EN, host->reg_base + reg_off);
++#if 0
++      writel(SDXC_CAL_START, host->reg_base + reg_off);
++
++      unsigned long expire = jiffies + msecs_to_jiffies(250);
++      u32 rval;
++
++      do {
++              rval = readl(host->reg_base + reg_off);
++      } while (time_before(jiffies, expire) && !(rval & SDXC_CAL_DONE));
++#endif
++
+       return 0;
+ }
+@@ -1211,7 +1222,6 @@ static const struct sunxi_mmc_cfg sun20i_d1_cfg = {
+ static const struct sunxi_mmc_cfg sun50i_a64_cfg = {
+       .idma_des_size_bits = 16,
+-      .clk_delays = NULL,
+       .can_calibrate = true,
+       .mask_data0 = true,
+       .needs_new_timings = true,
+@@ -1219,7 +1229,6 @@ static const struct sunxi_mmc_cfg sun50i_a64_cfg = {
+ static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
+       .idma_des_size_bits = 13,
+-      .clk_delays = NULL,
+       .can_calibrate = true,
+       .needs_new_timings = true,
+ };
+@@ -1227,7 +1236,6 @@ static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
+ static const struct sunxi_mmc_cfg sun50i_a100_cfg = {
+       .idma_des_size_bits = 16,
+       .idma_des_shift = 2,
+-      .clk_delays = NULL,
+       .can_calibrate = true,
+       .mask_data0 = true,
+       .needs_new_timings = true,
+@@ -1236,7 +1244,6 @@ static const struct sunxi_mmc_cfg sun50i_a100_cfg = {
+ static const struct sunxi_mmc_cfg sun50i_a100_emmc_cfg = {
+       .idma_des_size_bits = 13,
+       .idma_des_shift = 2,
+-      .clk_delays = NULL,
+       .can_calibrate = true,
+       .needs_new_timings = true,
+ };
+diff --git a/drivers/of/irq.c b/drivers/of/irq.c
+index d84d27fb2203..33878ffb9a49 100644
+--- a/drivers/of/irq.c
++++ b/drivers/of/irq.c
+@@ -511,6 +511,8 @@ void __init of_irq_init(const struct of_device_id *matches)
+               desc->interrupt_parent = of_irq_find_parent(np);
+               if (desc->interrupt_parent == np)
+                       desc->interrupt_parent = NULL;
++              pr_notice("of_irq_init: found %pOF with parent %pOF\n",
++                        desc->dev, desc->interrupt_parent);
+               list_add_tail(&desc->list, &intc_desc_list);
+       }
+@@ -535,9 +537,8 @@ void __init of_irq_init(const struct of_device_id *matches)
+                       of_node_set_flag(desc->dev, OF_POPULATED);
+-                      pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
+-                               desc->dev,
+-                               desc->dev, desc->interrupt_parent);
++                      pr_notice("of_irq_init: init %pOF with parent %pOF\n",
++                                desc->dev, desc->interrupt_parent);
+                       ret = desc->irq_init_cb(desc->dev,
+                                               desc->interrupt_parent);
+                       if (ret) {
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index 8a9c0ee98d8e..d5814eaac183 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -10,6 +10,7 @@
+  * warranty of any kind, whether express or implied.
+  */
++#define DEBUG
+ #include <linux/io.h>
+ #include <linux/clk.h>
+ #include <linux/gpio/driver.h>
+@@ -1026,8 +1027,15 @@ static void sunxi_pinctrl_irq_ack(struct irq_data *d)
+       u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq);
+       u8 status_idx = sunxi_irq_status_offset(d->hwirq);
++      u32 old = readl(pctl->membase + status_reg);
++
+       /* Clear the IRQ */
+       writel(1 << status_idx, pctl->membase + status_reg);
++
++      u32 new = readl(pctl->membase + status_reg);
++
++      pr_err("acked %ld in 0x%08x, was 0x%08x, now 0x%08x\n",
++              d->hwirq, status_reg, old, new);
+ }
+ static void sunxi_pinctrl_irq_mask(struct irq_data *d)
+diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
+index e5c2c9e71bf1..1a9072556c01 100644
+--- a/include/linux/dmaengine.h
++++ b/include/linux/dmaengine.h
+@@ -394,7 +394,7 @@ enum dma_slave_buswidth {
+  * should be read (RX), if the source is memory this argument is
+  * ignored.
+  * @dst_addr: this is the physical address where DMA slave data
+- * should be written (TX), if the source is memory this argument
++ * should be written (TX), if the destination is memory this argument
+  * is ignored.
+  * @src_addr_width: this is the width in bytes of the source (RX)
+  * register where DMA data shall be read. If the source
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 80ca260595fd..21ec90b1901a 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -17,6 +17,7 @@
+ //   o Add more codecs and platforms to ensure good API coverage.
+ //   o Support TDM on PCM and I2S
++#define DEBUG
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/init.h>
+@@ -1042,6 +1043,8 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
+                       if (!snd_soc_is_matching_component(platform, component))
+                               continue;
++                      dev_warn(card->dev, "ASoC: Adding component %s for platform %pOF\n",
++                               component->name, platform->of_node);
+                       snd_soc_rtd_add_component(rtd, component);
+               }
+       }
+diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
+index 59d07648a7e7..2c2ce6682eeb 100644
+--- a/sound/soc/soc-dapm.c
++++ b/sound/soc/soc-dapm.c
+@@ -2339,7 +2339,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
+                * right channel.
+                *
+                * A stereo control is signified by a valid 'rconnect'
+-               * value, either 0 for unconnected, or >= 0 for connected.
++               * value, either 0 for unconnected, or > 0 for connected.
+                * This is chosen instead of using snd_soc_volsw_is_stereo,
+                * so that the behavior of snd_soc_dapm_mixer_update_power
+                * doesn't change even when the kcontrol passed in is
+diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
+index 7bbe2526e16e..4392e0e49dd0 100644
+--- a/sound/soc/sunxi/Makefile
++++ b/sound/soc/sunxi/Makefile
+@@ -2,8 +2,8 @@
+ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
+ obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
+ obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
++obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o
++obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
+ obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
+ obj-$(CONFIG_SND_SUN20I_CODEC) += sun20i-codec.o
+ obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o
+-obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
+-obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o
+diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
+index 75075acc8658..7f7d45d2827c 100644
+--- a/sound/soc/sunxi/sun4i-i2s.c
++++ b/sound/soc/sunxi/sun4i-i2s.c
+@@ -38,10 +38,6 @@
+ #define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK     BIT(6)
+ #define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED         (1 << 6)
+ #define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL           (0 << 6)
+-#define SUN4I_I2S_FMT0_SR_MASK                        GENMASK(5, 4)
+-#define SUN4I_I2S_FMT0_SR(sr)                         ((sr) << 4)
+-#define SUN4I_I2S_FMT0_WSS_MASK                       GENMASK(3, 2)
+-#define SUN4I_I2S_FMT0_WSS(wss)                               ((wss) << 2)
+ #define SUN4I_I2S_FMT0_FMT_MASK                       GENMASK(1, 0)
+ #define SUN4I_I2S_FMT0_FMT_RIGHT_J                    (2 << 0)
+ #define SUN4I_I2S_FMT0_FMT_LEFT_J                     (1 << 0)
+@@ -71,8 +67,6 @@
+ #define SUN4I_I2S_INT_STA_REG         0x20
+ #define SUN4I_I2S_CLK_DIV_REG         0x24
+-#define SUN4I_I2S_CLK_DIV_MCLK_EN             BIT(7)
+-#define SUN4I_I2S_CLK_DIV_BCLK_MASK           GENMASK(6, 4)
+ #define SUN4I_I2S_CLK_DIV_BCLK(bclk)                  ((bclk) << 4)
+ #define SUN4I_I2S_CLK_DIV_MCLK_MASK           GENMASK(3, 0)
+ #define SUN4I_I2S_CLK_DIV_MCLK(mclk)                  ((mclk) << 0)
+diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
+index ecbe8e51b9a5..e2a8aaaf53dd 100644
+--- a/sound/soc/sunxi/sun4i-spdif.c
++++ b/sound/soc/sunxi/sun4i-spdif.c
+@@ -53,6 +53,8 @@
+ #define SUN4I_SPDIF_TXFIFO    (0x0C)
++#define SUN8I_SPDIF_ISTA      (0x0C)
++
+ #define SUN4I_SPDIF_RXFIFO    (0x10)
+ #define SUN4I_SPDIF_FCTL      (0x14)
+@@ -81,9 +83,14 @@
+ #define SUN4I_SPDIF_FSTA      (0x18)
+       #define SUN4I_SPDIF_FSTA_TXE                    BIT(14)
+-      #define SUN4I_SPDIF_FSTA_TXECNTSHT              (8)
++      #define SUN4I_SPDIF_FSTA_TXE_CNT                (8)
+       #define SUN4I_SPDIF_FSTA_RXA                    BIT(6)
+-      #define SUN4I_SPDIF_FSTA_RXACNTSHT              (0)
++      #define SUN4I_SPDIF_FSTA_RXA_CNT                (0)
++
++      #define SUN8I_SPDIF_FSTA_TXE                    BIT(31)
++      #define SUN8I_SPDIF_FSTA_TXE_CNT                (16)
++      #define SUN8I_SPDIF_FSTA_RXA                    BIT(15)
++      #define SUN8I_SPDIF_FSTA_RXA_CNT                (0)
+ #define SUN4I_SPDIF_INT               (0x1C)
+       #define SUN4I_SPDIF_INT_RXLOCKEN                BIT(18)
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0122-pinctrl-sunxi-sunxi_pinctrl_irq_ack-avoid-build-warn.patch b/target/linux/sunxid1/patches-5.15/0122-pinctrl-sunxi-sunxi_pinctrl_irq_ack-avoid-build-warn.patch
new file mode 100644 (file)
index 0000000..70ba5f1
--- /dev/null
@@ -0,0 +1,47 @@
+From b63fd7efd835bb7a1603ba821c6cb9db14a6fb06 Mon Sep 17 00:00:00 2001
+From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+Date: Tue, 12 Oct 2021 10:41:58 +0200
+Subject: [PATCH 122/124] pinctrl: sunxi: sunxi_pinctrl_irq_ack avoid build
+ warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Avoid a build warning
+
+drivers/pinctrl/sunxi/pinctrl-sunxi.c:
+In function â€˜sunxi_pinctrl_irq_ack’:
+drivers/pinctrl/sunxi/pinctrl-sunxi.c:1035:2: warning:
+ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
+ 1035 |  u32 new = readl(pctl->membase + status_reg);
+      |  ^~~
+
+Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index d5814eaac183..5f3410f92e4a 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -1026,13 +1026,14 @@ static void sunxi_pinctrl_irq_ack(struct irq_data *d)
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq);
+       u8 status_idx = sunxi_irq_status_offset(d->hwirq);
++      u32 new, old;
+-      u32 old = readl(pctl->membase + status_reg);
++      old = readl(pctl->membase + status_reg);
+       /* Clear the IRQ */
+       writel(1 << status_idx, pctl->membase + status_reg);
+-      u32 new = readl(pctl->membase + status_reg);
++      new = readl(pctl->membase + status_reg);
+       pr_err("acked %ld in 0x%08x, was 0x%08x, now 0x%08x\n",
+               d->hwirq, status_reg, old, new);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0123-Add-a-defconfig-for-the-Nezha.patch b/target/linux/sunxid1/patches-5.15/0123-Add-a-defconfig-for-the-Nezha.patch
new file mode 100644 (file)
index 0000000..41071b0
--- /dev/null
@@ -0,0 +1,256 @@
+From 4423494ac9e059965dfb62d3080d3947a0691770 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 8 Aug 2021 21:27:43 -0500
+Subject: [PATCH 123/124] Add a defconfig for the Nezha
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/configs/nezha_defconfig | 236 +++++++++++++++++++++++++++++
+ 1 file changed, 236 insertions(+)
+ create mode 100644 arch/riscv/configs/nezha_defconfig
+
+diff --git a/arch/riscv/configs/nezha_defconfig b/arch/riscv/configs/nezha_defconfig
+new file mode 100644
+index 000000000000..f846fe210744
+--- /dev/null
++++ b/arch/riscv/configs/nezha_defconfig
+@@ -0,0 +1,236 @@
++CONFIG_DEFAULT_HOSTNAME="nezha"
++# CONFIG_SWAP is not set
++# CONFIG_CROSS_MEMORY_ATTACH is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_PREEMPT=y
++CONFIG_EXPERT=y
++# CONFIG_SYSFS_SYSCALL is not set
++# CONFIG_VM_EVENT_COUNTERS is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB_MERGE_DEFAULT is not set
++CONFIG_ARCH_SUNXI=y
++# CONFIG_RISCV_ERRATA_ALTERNATIVE is not set
++# CONFIG_RISCV_ISA_C is not set
++# CONFIG_EFI is not set
++CONFIG_PM_AUTOSLEEP=y
++CONFIG_PM_WAKELOCKS=y
++CONFIG_PM_DEBUG=y
++CONFIG_PM_ADVANCED_DEBUG=y
++CONFIG_PM_TEST_SUSPEND=y
++CONFIG_JUMP_LABEL=y
++# CONFIG_SECCOMP is not set
++# CONFIG_STACKPROTECTOR is not set
++# CONFIG_GCC_PLUGINS is not set
++# CONFIG_MQ_IOSCHED_DEADLINE is not set
++# CONFIG_MQ_IOSCHED_KYBER is not set
++# CONFIG_COREDUMP is not set
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_INET_DIAG is not set
++# CONFIG_IPV6_SIT is not set
++# CONFIG_WIRELESS is not set
++# CONFIG_ETHTOOL_NETLINK is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++# CONFIG_ALLOW_DEV_COREDUMP is not set
++CONFIG_MTD=y
++CONFIG_MTD_BLOCK=y
++CONFIG_MTD_PARTITIONED_MASTER=y
++CONFIG_MTD_SPI_NAND=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_FASTMAP=y
++CONFIG_MTD_UBI_BLOCK=y
++# CONFIG_BLK_DEV is not set
++CONFIG_SCSI=y
++# CONFIG_SCSI_PROC_FS is not set
++CONFIG_BLK_DEV_SD=y
++CONFIG_CHR_DEV_SG=y
++# CONFIG_BLK_DEV_BSG is not set
++CONFIG_SCSI_SCAN_ASYNC=y
++# CONFIG_SCSI_LOWLEVEL is not set
++CONFIG_NETDEVICES=y
++# CONFIG_NET_CORE is not set
++# CONFIG_NET_VENDOR_ALACRITECH is not set
++# CONFIG_NET_VENDOR_AMAZON is not set
++# CONFIG_NET_VENDOR_AQUANTIA is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CADENCE is not set
++# CONFIG_NET_VENDOR_CAVIUM is not set
++# CONFIG_NET_VENDOR_CORTINA is not set
++# CONFIG_NET_VENDOR_EZCHIP is not set
++# CONFIG_NET_VENDOR_GOOGLE is not set
++# CONFIG_NET_VENDOR_HUAWEI is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MICROSOFT is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MELLANOX is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_MICROSEMI is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_NET_VENDOR_NETRONOME is not set
++# CONFIG_NET_VENDOR_NI is not set
++# CONFIG_NET_VENDOR_PENSANDO is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_RENESAS is not set
++# CONFIG_NET_VENDOR_ROCKER is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SOLARFLARE is not set
++# CONFIG_NET_VENDOR_SOCIONEXT is not set
++CONFIG_STMMAC_ETH=y
++# CONFIG_DWMAC_GENERIC is not set
++# CONFIG_NET_VENDOR_SYNOPSYS is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++# CONFIG_NET_VENDOR_XILINX is not set
++CONFIG_REALTEK_PHY=y
++# CONFIG_USB_NET_DRIVERS is not set
++# CONFIG_WLAN is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_KEYBOARD_SUN4I_LRADC=y
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_SERIO is not set
++# CONFIG_VT is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_LDISC_AUTOLOAD is not set
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=6
++CONFIG_SERIAL_8250_RUNTIME_UARTS=6
++CONFIG_SERIAL_8250_DW=y
++CONFIG_SERIAL_OF_PLATFORM=y
++CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
++CONFIG_HVC_RISCV_SBI=y
++CONFIG_I2C=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO is not set
++CONFIG_I2C_MV64XXX=y
++CONFIG_SPI=y
++CONFIG_SPI_SUN6I=y
++CONFIG_SPI_SPIDEV=y
++# CONFIG_PTP_1588_CLOCK is not set
++CONFIG_PINCTRL=y
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_PCF857X=y
++CONFIG_POWER_SUPPLY=y
++CONFIG_THERMAL=y
++CONFIG_THERMAL_STATISTICS=y
++CONFIG_THERMAL_WRITABLE_TRIPS=y
++CONFIG_THERMAL_GOV_BANG_BANG=y
++CONFIG_THERMAL_GOV_USER_SPACE=y
++CONFIG_CPU_THERMAL=y
++CONFIG_THERMAL_EMULATION=y
++CONFIG_SUN8I_THERMAL=y
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_SYSFS=y
++CONFIG_SUNXI_WATCHDOG=y
++CONFIG_REGULATOR=y
++CONFIG_REGULATOR_FIXED_VOLTAGE=y
++CONFIG_REGULATOR_PWM=y
++CONFIG_SOUND=y
++CONFIG_SND=y
++CONFIG_SND_HRTIMER=y
++CONFIG_SND_DYNAMIC_MINORS=y
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB_AUDIO=y
++CONFIG_SND_SOC=y
++CONFIG_SND_SUN20I_CODEC=y
++CONFIG_SND_SUN4I_I2S=y
++CONFIG_SND_SUN4I_SPDIF=y
++# CONFIG_USB_HID is not set
++CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_DYNAMIC_MINORS=y
++CONFIG_USB_OTG=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB_UAS=y
++CONFIG_USB_MUSB_HDRC=y
++CONFIG_USB_MUSB_SUNXI=y
++CONFIG_USB_SERIAL=y
++CONFIG_USB_SERIAL_CH341=y
++CONFIG_NOP_USB_XCEIV=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_ETH=y
++# CONFIG_USB_ETH_RNDIS is not set
++CONFIG_USB_ETH_EEM=y
++CONFIG_MMC=y
++CONFIG_MMC_SUNXI=y
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_CLASS_MULTICOLOR=y
++CONFIG_LEDS_SUN50I_R329=y
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_ONESHOT=y
++CONFIG_LEDS_TRIGGER_MTD=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_LEDS_TRIGGER_CPU=y
++CONFIG_LEDS_TRIGGER_ACTIVITY=y
++CONFIG_LEDS_TRIGGER_PANIC=y
++CONFIG_LEDS_TRIGGER_NETDEV=y
++CONFIG_RTC_CLASS=y
++CONFIG_DMADEVICES=y
++CONFIG_DMA_SUN6I=y
++# CONFIG_VIRTIO_MENU is not set
++# CONFIG_VHOST_MENU is not set
++CONFIG_SUN8I_DE2_CCU=y
++CONFIG_HWSPINLOCK=y
++CONFIG_HWSPINLOCK_SUN6I=y
++CONFIG_MAILBOX=y
++CONFIG_SUN50I_IOMMU=y
++CONFIG_REMOTEPROC=y
++CONFIG_REMOTEPROC_CDEV=y
++CONFIG_SUN8I_DSP_REMOTEPROC=y
++CONFIG_RPMSG_CHAR=y
++CONFIG_RPMSG_VIRTIO=y
++CONFIG_PWM=y
++CONFIG_PWM_SUN8I_V536=y
++CONFIG_PHY_SUN4I_USB=y
++CONFIG_NVMEM_SUNXI_SID=y
++CONFIG_EXT4_FS=y
++# CONFIG_DNOTIFY is not set
++CONFIG_FANOTIFY=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_XATTR=y
++CONFIG_TMPFS_INODE64=y
++# CONFIG_MISC_FILESYSTEMS is not set
++# CONFIG_NETWORK_FILESYSTEMS is not set
++CONFIG_CRYPTO_USER_API_HASH=y
++CONFIG_CRYPTO_USER_API_SKCIPHER=y
++CONFIG_CRYPTO_USER_API_RNG=y
++CONFIG_CRYPTO_USER_API_AEAD=y
++# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set
++CONFIG_CRYPTO_DEV_SUN8I_CE=y
++CONFIG_CRYPTO_DEV_SUN8I_CE_HASH=y
++CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG=y
++CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG=y
++CONFIG_PRINTK_TIME=y
++# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
++# CONFIG_FRAME_POINTER is not set
++CONFIG_VMLINUX_MAP=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_MAGIC_SYSRQ_SERIAL is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_DEBUG_MISC is not set
++# CONFIG_SCHED_DEBUG is not set
++CONFIG_DEBUG_ATOMIC_SLEEP=y
++CONFIG_STACKTRACE=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_FTRACE is not set
++# CONFIG_RUNTIME_TESTING_MENU is not set
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0124-watchdog-sunxi_wdt-Add-support-for-D1.patch b/target/linux/sunxid1/patches-5.15/0124-watchdog-sunxi_wdt-Add-support-for-D1.patch
new file mode 100644 (file)
index 0000000..557ca53
--- /dev/null
@@ -0,0 +1,106 @@
+From 533f0a9a782e90ba8b30aa4deed0146f3133610e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 May 2021 21:49:39 -0500
+Subject: [PATCH 124/124] watchdog: sunxi_wdt: Add support for D1
+
+D1 adds a key field to the "CFG" and "MODE" registers, that must be set
+to change the other bits. Add logic to set the key when updating those
+registers.
+
+Acked-by: Maxime Ripard <maxime@cerno.tech>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/watchdog/sunxi_wdt.c | 20 +++++++++++++++++++-
+ 1 file changed, 19 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
+index b50757882a98..6cf82922d3fb 100644
+--- a/drivers/watchdog/sunxi_wdt.c
++++ b/drivers/watchdog/sunxi_wdt.c
+@@ -48,6 +48,7 @@ struct sunxi_wdt_reg {
+       u8 wdt_timeout_shift;
+       u8 wdt_reset_mask;
+       u8 wdt_reset_val;
++      u32 wdt_key_val;
+ };
+ struct sunxi_wdt_dev {
+@@ -91,12 +92,14 @@ static int sunxi_wdt_restart(struct watchdog_device *wdt_dev,
+       val = readl(wdt_base + regs->wdt_cfg);
+       val &= ~(regs->wdt_reset_mask);
+       val |= regs->wdt_reset_val;
++      val |= regs->wdt_key_val;
+       writel(val, wdt_base + regs->wdt_cfg);
+       /* Set lowest timeout and enable watchdog */
+       val = readl(wdt_base + regs->wdt_mode);
+       val &= ~(WDT_TIMEOUT_MASK << regs->wdt_timeout_shift);
+       val |= WDT_MODE_EN;
++      val |= regs->wdt_key_val;
+       writel(val, wdt_base + regs->wdt_mode);
+       /*
+@@ -109,6 +112,7 @@ static int sunxi_wdt_restart(struct watchdog_device *wdt_dev,
+               mdelay(5);
+               val = readl(wdt_base + regs->wdt_mode);
+               val |= WDT_MODE_EN;
++              val |= regs->wdt_key_val;
+               writel(val, wdt_base + regs->wdt_mode);
+       }
+       return 0;
+@@ -141,6 +145,7 @@ static int sunxi_wdt_set_timeout(struct watchdog_device *wdt_dev,
+       reg = readl(wdt_base + regs->wdt_mode);
+       reg &= ~(WDT_TIMEOUT_MASK << regs->wdt_timeout_shift);
+       reg |= wdt_timeout_map[timeout] << regs->wdt_timeout_shift;
++      reg |= regs->wdt_key_val;
+       writel(reg, wdt_base + regs->wdt_mode);
+       sunxi_wdt_ping(wdt_dev);
+@@ -154,7 +159,7 @@ static int sunxi_wdt_stop(struct watchdog_device *wdt_dev)
+       void __iomem *wdt_base = sunxi_wdt->wdt_base;
+       const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs;
+-      writel(0, wdt_base + regs->wdt_mode);
++      writel(regs->wdt_key_val, wdt_base + regs->wdt_mode);
+       return 0;
+ }
+@@ -176,11 +181,13 @@ static int sunxi_wdt_start(struct watchdog_device *wdt_dev)
+       reg = readl(wdt_base + regs->wdt_cfg);
+       reg &= ~(regs->wdt_reset_mask);
+       reg |= regs->wdt_reset_val;
++      reg |= regs->wdt_key_val;
+       writel(reg, wdt_base + regs->wdt_cfg);
+       /* Enable watchdog */
+       reg = readl(wdt_base + regs->wdt_mode);
+       reg |= WDT_MODE_EN;
++      reg |= regs->wdt_key_val;
+       writel(reg, wdt_base + regs->wdt_mode);
+       return 0;
+@@ -220,9 +227,20 @@ static const struct sunxi_wdt_reg sun6i_wdt_reg = {
+       .wdt_reset_val = 0x01,
+ };
++static const struct sunxi_wdt_reg sun20i_wdt_reg = {
++      .wdt_ctrl = 0x10,
++      .wdt_cfg = 0x14,
++      .wdt_mode = 0x18,
++      .wdt_timeout_shift = 4,
++      .wdt_reset_mask = 0x03,
++      .wdt_reset_val = 0x01,
++      .wdt_key_val = 0x16aa0000,
++};
++
+ static const struct of_device_id sunxi_wdt_dt_ids[] = {
+       { .compatible = "allwinner,sun4i-a10-wdt", .data = &sun4i_wdt_reg },
+       { .compatible = "allwinner,sun6i-a31-wdt", .data = &sun6i_wdt_reg },
++      { .compatible = "allwinner,sun20i-d1-wdt", .data = &sun20i_wdt_reg },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
+-- 
+2.20.1
+
diff --git a/target/linux/sunxid1/patches-5.15/0125-dt-bindings-clk-Add-compatibles-for-D1-CCUs.patch b/target/linux/sunxid1/patches-5.15/0125-dt-bindings-clk-Add-compatibles-for-D1-CCUs.patch
new file mode 100644 (file)
index 0000000..6aae525
--- /dev/null
@@ -0,0 +1,328 @@
+From aa7c2a299b211120e4fcdc66afe130cd6cda571d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 6 Jun 2021 10:52:16 -0500
+Subject: [PATCH 060/136] dt-bindings: clk: Add compatibles for D1 CCUs
+
+The D1 has a CCU and a R_CCU (PRCM CCU) like most other sunxi SoCs, with
+3 and 4 clock inputs, respectively. Add the compatibles for them.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ .../clock/allwinner,sun4i-a10-ccu.yaml        |   4 +
+ include/dt-bindings/clock/sun20i-d1-ccu.h     | 156 ++++++++++++++++++
+ include/dt-bindings/clock/sun20i-d1-r-ccu.h   |  19 +++
+ include/dt-bindings/reset/sun20i-d1-ccu.h     |  77 +++++++++
+ include/dt-bindings/reset/sun20i-d1-r-ccu.h   |  16 ++
+ 5 files changed, 272 insertions(+)
+ create mode 100644 include/dt-bindings/clock/sun20i-d1-ccu.h
+ create mode 100644 include/dt-bindings/clock/sun20i-d1-r-ccu.h
+ create mode 100644 include/dt-bindings/reset/sun20i-d1-ccu.h
+ create mode 100644 include/dt-bindings/reset/sun20i-d1-r-ccu.h
+
+--- a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
++++ b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
+@@ -34,6 +34,8 @@ properties:
+       - allwinner,sun8i-v3-ccu
+       - allwinner,sun8i-v3s-ccu
+       - allwinner,sun9i-a80-ccu
++      - allwinner,sun20i-d1-ccu
++      - allwinner,sun20i-d1-r-ccu
+       - allwinner,sun50i-a64-ccu
+       - allwinner,sun50i-a64-r-ccu
+       - allwinner,sun50i-a100-ccu
+@@ -79,6 +81,7 @@ if:
+       enum:
+         - allwinner,sun8i-a83t-r-ccu
+         - allwinner,sun8i-h3-r-ccu
++        - allwinner,sun20i-d1-r-ccu
+         - allwinner,sun50i-a64-r-ccu
+         - allwinner,sun50i-a100-r-ccu
+         - allwinner,sun50i-h6-r-ccu
+@@ -99,6 +102,7 @@ else:
+     properties:
+       compatible:
+         enum:
++          - allwinner,sun20i-d1-ccu
+           - allwinner,sun50i-a100-ccu
+           - allwinner,sun50i-h6-ccu
+           - allwinner,sun50i-h616-ccu
+--- /dev/null
++++ b/include/dt-bindings/clock/sun20i-d1-ccu.h
+@@ -0,0 +1,156 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++/*
++ * Copyright (C) 2020 huangzhenwei@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_
++#define _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_
++
++#define CLK_PLL_CPUX          0
++#define CLK_PLL_DDR0          1
++#define CLK_PLL_PERIPH0_4X    2
++#define CLK_PLL_PERIPH0_2X    3
++#define CLK_PLL_PERIPH0_800M  4
++#define CLK_PLL_PERIPH0               5
++#define CLK_PLL_PERIPH0_DIV3  6
++#define CLK_PLL_VIDEO0_4X     7
++#define CLK_PLL_VIDEO0_2X     8
++#define CLK_PLL_VIDEO0                9
++#define CLK_PLL_VIDEO1_4X     10
++#define CLK_PLL_VIDEO1_2X     11
++#define CLK_PLL_VIDEO1                12
++#define CLK_PLL_VE            13
++#define CLK_PLL_AUDIO0_4X     14
++#define CLK_PLL_AUDIO0_2X     15
++#define CLK_PLL_AUDIO0                16
++#define CLK_PLL_AUDIO1                17
++#define CLK_PLL_AUDIO1_DIV2   18
++#define CLK_PLL_AUDIO1_DIV5   19
++#define CLK_CPUX              20
++#define CLK_CPUX_AXI          21
++#define CLK_CPUX_APB          22
++#define CLK_PSI_AHB           23
++#define CLK_APB0              24
++#define CLK_APB1              25
++#define CLK_MBUS              26
++#define CLK_DE                        27
++#define CLK_BUS_DE            28
++#define CLK_DI                        29
++#define CLK_BUS_DI            30
++#define CLK_G2D                       31
++#define CLK_BUS_G2D           32
++#define CLK_CE                        33
++#define CLK_BUS_CE            34
++#define CLK_VE                        35
++#define CLK_BUS_VE            36
++#define CLK_BUS_DMA           37
++#define CLK_BUS_MSGBOX0               38
++#define CLK_BUS_MSGBOX1               39
++#define CLK_BUS_MSGBOX2               40
++#define CLK_BUS_SPINLOCK      41
++#define CLK_BUS_HSTIMER               42
++#define CLK_AVS                       43
++#define CLK_BUS_DBG           44
++#define CLK_BUS_PWM           45
++#define CLK_BUS_IOMMU         46
++#define CLK_DRAM              47
++#define CLK_MBUS_DMA          48
++#define CLK_MBUS_VE           49
++#define CLK_MBUS_CE           50
++#define CLK_MBUS_TVIN         51
++#define CLK_MBUS_CSI          52
++#define CLK_MBUS_G2D          53
++#define CLK_MBUS_RISCV                54
++#define CLK_BUS_DRAM          55
++#define CLK_MMC0              56
++#define CLK_MMC1              57
++#define CLK_MMC2              58
++#define CLK_BUS_MMC0          59
++#define CLK_BUS_MMC1          60
++#define CLK_BUS_MMC2          61
++#define CLK_BUS_UART0         62
++#define CLK_BUS_UART1         63
++#define CLK_BUS_UART2         64
++#define CLK_BUS_UART3         65
++#define CLK_BUS_UART4         66
++#define CLK_BUS_UART5         67
++#define CLK_BUS_I2C0          68
++#define CLK_BUS_I2C1          69
++#define CLK_BUS_I2C2          70
++#define CLK_BUS_I2C3          71
++#define CLK_SPI0              72
++#define CLK_SPI1              73
++#define CLK_BUS_SPI0          74
++#define CLK_BUS_SPI1          75
++#define CLK_EMAC_25M          76
++#define CLK_BUS_EMAC          77
++#define CLK_IR_TX             78
++#define CLK_BUS_IR_TX         79
++#define CLK_BUS_GPADC         80
++#define CLK_BUS_THS           81
++#define CLK_I2S0              82
++#define CLK_I2S1              83
++#define CLK_I2S2              84
++#define CLK_I2S2_ASRC         85
++#define CLK_BUS_I2S0          86
++#define CLK_BUS_I2S1          87
++#define CLK_BUS_I2S2          88
++#define CLK_SPDIF_TX          89
++#define CLK_SPDIF_RX          90
++#define CLK_BUS_SPDIF         91
++#define CLK_DMIC              92
++#define CLK_BUS_DMIC          93
++#define CLK_AUDIO_DAC         94
++#define CLK_AUDIO_ADC         95
++#define CLK_BUS_AUDIO         96
++#define CLK_USB_OHCI0         97
++#define CLK_USB_OHCI1         98
++#define CLK_BUS_OHCI0         99
++#define CLK_BUS_OHCI1         100
++#define CLK_BUS_EHCI0         101
++#define CLK_BUS_EHCI1         102
++#define CLK_BUS_OTG           103
++#define CLK_BUS_LRADC         104
++#define CLK_BUS_DPSS_TOP      105
++#define CLK_HDMI_24M          106
++#define CLK_HDMI_CEC_32K      107
++#define CLK_HDMI_CEC          108
++#define CLK_BUS_HDMI          109
++#define CLK_MIPI_DSI          110
++#define CLK_BUS_MIPI_DSI      111
++#define CLK_TCON_LCD0         112
++#define CLK_BUS_TCON_LCD0     113
++#define CLK_TCON_TV           114
++#define CLK_BUS_TCON_TV               115
++#define CLK_TVE                       116
++#define CLK_BUS_TVE_TOP               117
++#define CLK_BUS_TVE           118
++#define CLK_TVD                       119
++#define CLK_BUS_TVD_TOP               120
++#define CLK_BUS_TVD           121
++#define CLK_LEDC              122
++#define CLK_BUS_LEDC          123
++#define CLK_CSI_TOP           124
++#define CLK_CSI_MCLK          125
++#define CLK_BUS_CSI           126
++#define CLK_TPADC             127
++#define CLK_BUS_TPADC         128
++#define CLK_BUS_TZMA          129
++#define CLK_DSP                       130
++#define CLK_BUS_DSP_CFG               131
++#define CLK_RISCV             132
++#define CLK_RISCV_AXI         133
++#define CLK_BUS_RISCV_CFG     134
++#define CLK_FANOUT_24M                135
++#define CLK_FANOUT_12M                136
++#define CLK_FANOUT_16M                137
++#define CLK_FANOUT_25M                138
++#define CLK_FANOUT_32K                139
++#define CLK_FANOUT_27M                140
++#define CLK_FANOUT_PCLK               141
++#define CLK_FANOUT0           142
++#define CLK_FANOUT1           143
++#define CLK_FANOUT2           144
++
++#endif /* _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_ */
+--- /dev/null
++++ b/include/dt-bindings/clock/sun20i-d1-r-ccu.h
+@@ -0,0 +1,19 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++/*
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_
++#define _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_
++
++#define CLK_R_AHB             0
++
++#define CLK_BUS_R_TIMER               2
++#define CLK_BUS_R_TWD         3
++#define CLK_BUS_R_PPU         4
++#define CLK_R_IR_RX           5
++#define CLK_BUS_R_IR_RX               6
++#define CLK_BUS_R_RTC         7
++#define CLK_BUS_R_CPUCFG      8
++
++#endif /* _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_ */
+--- /dev/null
++++ b/include/dt-bindings/reset/sun20i-d1-ccu.h
+@@ -0,0 +1,77 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++/*
++ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_RST_SUN20I_D1_CCU_H_
++#define _DT_BINDINGS_RST_SUN20I_D1_CCU_H_
++
++#define RST_MBUS              0
++#define RST_BUS_DE            1
++#define RST_BUS_DI            2
++#define RST_BUS_G2D           3
++#define RST_BUS_CE            4
++#define RST_BUS_VE            5
++#define RST_BUS_DMA           6
++#define RST_BUS_MSGBOX0               7
++#define RST_BUS_MSGBOX1               8
++#define RST_BUS_MSGBOX2               9
++#define RST_BUS_SPINLOCK      10
++#define RST_BUS_HSTIMER               11
++#define RST_BUS_DBG           12
++#define RST_BUS_PWM           13
++#define RST_BUS_DRAM          14
++#define RST_BUS_MMC0          15
++#define RST_BUS_MMC1          16
++#define RST_BUS_MMC2          17
++#define RST_BUS_UART0         18
++#define RST_BUS_UART1         19
++#define RST_BUS_UART2         20
++#define RST_BUS_UART3         21
++#define RST_BUS_UART4         22
++#define RST_BUS_UART5         23
++#define RST_BUS_I2C0          24
++#define RST_BUS_I2C1          25
++#define RST_BUS_I2C2          26
++#define RST_BUS_I2C3          27
++#define RST_BUS_SPI0          28
++#define RST_BUS_SPI1          29
++#define RST_BUS_EMAC          30
++#define RST_BUS_IR_TX         31
++#define RST_BUS_GPADC         32
++#define RST_BUS_THS           33
++#define RST_BUS_I2S0          34
++#define RST_BUS_I2S1          35
++#define RST_BUS_I2S2          36
++#define RST_BUS_SPDIF         37
++#define RST_BUS_DMIC          38
++#define RST_BUS_AUDIO         39
++#define RST_USB_PHY0          40
++#define RST_USB_PHY1          41
++#define RST_BUS_OHCI0         42
++#define RST_BUS_OHCI1         43
++#define RST_BUS_EHCI0         44
++#define RST_BUS_EHCI1         45
++#define RST_BUS_OTG           46
++#define RST_BUS_LRADC         47
++#define RST_BUS_DPSS_TOP      48
++#define RST_BUS_HDMI_SUB      49
++#define RST_BUS_HDMI_MAIN     50
++#define RST_BUS_MIPI_DSI      51
++#define RST_BUS_TCON_LCD0     52
++#define RST_BUS_TCON_TV               53
++#define RST_BUS_LVDS0         54
++#define RST_BUS_TVE           55
++#define RST_BUS_TVE_TOP               56
++#define RST_BUS_TVD           57
++#define RST_BUS_TVD_TOP               58
++#define RST_BUS_LEDC          59
++#define RST_BUS_CSI           60
++#define RST_BUS_TPADC         61
++#define RST_DSP                       62
++#define RST_BUS_DSP_CFG               63
++#define RST_BUS_DSP_DBG               64
++#define RST_BUS_RISCV_CFG     65
++
++#endif /* _DT_BINDINGS_RST_SUN20I_D1_CCU_H_ */
+--- /dev/null
++++ b/include/dt-bindings/reset/sun20i-d1-r-ccu.h
+@@ -0,0 +1,16 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++/*
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_
++#define _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_
++
++#define RST_BUS_R_TIMER               0
++#define RST_BUS_R_TWD         1
++#define RST_BUS_R_PPU         2
++#define RST_BUS_R_IR_RX               3
++#define RST_BUS_R_RTC         4
++#define RST_BUS_R_CPUCFG      5
++
++#endif /* _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_ */
diff --git a/target/linux/sunxid1/patches-5.15/0126-dt-bindings-rtc-sun6i-Add-H616-R329-and-D1-support.patch b/target/linux/sunxid1/patches-5.15/0126-dt-bindings-rtc-sun6i-Add-H616-R329-and-D1-support.patch
new file mode 100644 (file)
index 0000000..57621fa
--- /dev/null
@@ -0,0 +1,42 @@
+From 80ee04e4cc1fcdcd46c2a67e841fae1532f2ed69 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Tue, 31 Aug 2021 23:37:55 -0500
+Subject: [PATCH 041/136] dt-bindings: rtc: sun6i: Add H616, R329, and D1
+ support
+
+These new RTC variants all have a single alarm, like the R40 variant.
+
+For the new SoCs, start requiring a complete list of input clocks. The
+H616 has three required clocks. The R329 also has three required clocks
+(but one is different), plus an optional crystal oscillator input. The
+D1 RTC is identical to the one in the R329.
+
+And since these new SoCs will have a well-defined output clock order as
+well, they do not need the clock-output-names property.
+
+Series-changes: 2
+ - Properly update the DT binding clocks and clock-names properties.
+
+Series-changes: 3
+ - Add/fix several maxItems attributes for clocks and clock-items
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 76 ++++++++++++++++++-
+ include/dt-bindings/clock/sun6i-rtc.h         | 10 +++
+ 2 files changed, 83 insertions(+), 3 deletions(-)
+ create mode 100644 include/dt-bindings/clock/sun6i-rtc.h
+
+--- /dev/null
++++ b/include/dt-bindings/clock/sun6i-rtc.h
+@@ -0,0 +1,10 @@
++/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
++
++#ifndef _DT_BINDINGS_CLK_SUN6I_RTC_H_
++#define _DT_BINDINGS_CLK_SUN6I_RTC_H_
++
++#define CLK_OSC32K            0
++#define CLK_OSC32K_FANOUT     1
++#define CLK_IOSC              2
++
++#endif /* _DT_BINDINGS_CLK_SUN6I_RTC_H_ */