From 55f7492bbf5cf8507b78055c3194ca28a37c807c Mon Sep 17 00:00:00 2001 From: Zoltan HERPAI Date: Tue, 16 Nov 2021 16:44:56 +0100 Subject: [PATCH] sunxid1: add new target 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 --- target/linux/sunxid1/Makefile | 24 + .../sunxid1/base-files/etc/board.d/02_network | 18 + target/linux/sunxid1/base-files/etc/inittab | 6 + .../sunxid1/base-files/lib/preinit/80_debug | 9 + target/linux/sunxid1/config-5.15 | 441 +++++ target/linux/sunxid1/image/Config.in | 5 + target/linux/sunxid1/image/Makefile | 69 + .../sunxid1/image/gen_sunxi_sdcard_img.sh | 43 + ...egister-clocks-resets-when-unbinding.patch | 492 +++++ ...-ng-Prevent-unbinding-CCUs-via-sysfs.patch | 126 ++ ...-a-separate-lock-for-each-CCU-instan.patch | 65 + ...probing-without-an-early-clock-provi.patch | 46 + ...text-section-size-limitation-for-XIP.patch | 148 ++ ...-irq-simplify-handle_domain_-irq-nmi.patch | 76 + ...07-5.16-irq-unexport-handle_irq_desc.patch | 31 + ...ary-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTR.patch | 193 ++ ...ve-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY.patch | 63 + ...5.16-irq-add-generic_handle_arch_irq.patch | 76 + ...riscv-perform-irqentry-in-entry-code.patch | 96 + ...16-irq-remove-handle_domain_-irq-nmi.patch | 221 +++ ...ake-use-of-the-helper-function-devm_.patch | 42 + ...t-sun4i-lradc-keys-Add-wakup-support.patch | 74 + ...mal-sun8i-Document-the-unknown-field.patch | 63 + ...i-Set-the-event-type-for-new-samples.patch | 29 + ...n8i-Use-optional-clock-reset-getters.patch | 114 ++ ...thermal-sun8i-Ensure-vref-is-powered.patch | 81 + ...sun8i-Add-support-for-the-D1-variant.patch | 46 + ...-Assert-reset-when-removing-the-devi.patch | 35 + ...-Simplify-code-around-optional-reset.patch | 83 + ...-Add-support-for-separate-RX-TX-cloc.patch | 121 ++ ...spdif-Add-support-for-the-D1-variant.patch | 45 + ...sunxi_sid-Add-support-for-D1-variant.patch | 40 + ...c-keys-Add-optional-clock-reset-supp.patch | 101 + ...adc-keys-Add-support-for-R329-and-D1.patch | 30 + ...river-for-the-R329-D1-LED-controller.patch | 611 ++++++ ...s-Update-registers-for-more-channels.patch | 99 + ...-Add-support-for-the-R329-D1-variant.patch | 98 + ...ck-sun6i-Clarify-bank-counting-logic.patch | 69 + ...ck-sun6i-Fix-driver-to-match-binding.patch | 42 + ...engine-sun6i-Do-not-use-virt_to_phys.patch | 116 ++ ...Add-support-for-34-bit-physical-addr.patch | 157 ++ ...8i-ce-Add-support-for-the-D1-variant.patch | 76 + ...e2-Prevent-driver-from-being-unbound.patch | 44 + ...g-Export-symbols-used-by-CCU-drivers.patch | 342 ++++ ...Allow-drivers-to-be-built-as-modules.patch | 387 ++++ ...vert-early-providers-to-platform-dri.patch | 891 +++++++++ ...ow-the-CCU-core-to-be-built-as-a-mod.patch | 176 ++ ...unxi-ng-mux-Allow-muxes-to-have-keys.patch | 63 + ...e-interrupts-extended-to-find-parent.patch | 59 + ...se-SBI-SRST-extension-when-available.patch | 134 ++ .../0043-RISC-V-Enable-CPU_IDLE-drivers.patch | 119 ++ ...V-Rename-relocate-and-make-it-global.patch | 53 + ...functions-for-non-retentive-suspend-.patch | 394 ++++ ...-Add-SBI-HSM-suspend-related-defines.patch | 72 + ...ut-power-domain-related-code-from-PS.patch | 548 ++++++ ...uidle-Add-RISC-V-SBI-CPU-idle-driver.patch | 725 ++++++++ ...SC-V-SBI-CPU-Idle-driver-for-QEMU-vi.patch | 57 + ...-bit-only-when-using-SBI-IPI-operati.patch | 53 + ...SC-V-Treat-IPIs-as-normal-Linux-IRQs.patch | 843 +++++++++ ...t-Add-support-for-ACLINT-MTIMER-devi.patch | 138 ++ ...Add-Allwinner-D1-stacked-INTC-driver.patch | 156 ++ ...-Add-macros-using-clk_parent_data-an.patch | 115 ++ ...Add-macros-using-clk_parent_data-and.patch | 79 + ...-Add-macros-using-clk_parent_data-an.patch | 63 + ...e-Add-macros-for-gates-with-fixed-di.patch | 75 + ...ng-Add-support-for-the-D1-SoC-clocks.patch | 1653 +++++++++++++++++ ...Add-support-for-the-sun6i-RTC-clocks.patch | 518 ++++++ ...unxi-ng-sun6i-rtc-Add-support-for-H6.patch | 91 + ...sun6i-Add-support-for-the-D1-variant.patch | 41 + ...v-pgtable-Fixup-_PAGE_CHG_MASK-usage.patch | 85 + ...table-Add-custom-protection_map-init.patch | 105 ++ ...d-DMA_COHERENT-with-custom-PTE-attri.patch | 200 ++ .../0065-riscv-fixup-PAGE_NONE.patch | 26 + ...scv-cmo-Add-dma-noncoherency-support.patch | 253 +++ ...cv-cmo-Add-vendor-custom-icache-sync.patch | 182 ++ ...UB-which-lead-to-cache-coherence-bug.patch | 25 + ...-HEAD-MMU-extensions-unconditionally.patch | 26 + .../0070-riscv-Allow-suspend.patch | 27 + ...-cacheinfo-Remind-myself-to-fix-this.patch | 25 + ...scv-Prefer-it-over-MMIO-clocksources.patch | 26 + .../0073-riscv-Enable-cpufreq.patch | 26 + ...add-efuse_xlate-to-get-efuse-version.patch | 162 ++ ...freq-sun50i-add-A100-cpufreq-support.patch | 90 + ...50i-Move-out-of-ARM-specific-section.patch | 98 + ...pufreq-sun50i-Add-D1-cpufreq-support.patch | 61 + ...078-dmaengine-sun6i-Changes-from-BSP.patch | 59 + ...ommu-sun50i-Add-support-for-D1-IOMMU.patch | 75 + ...five-plic-Add-T-HEAD-PLIC-compatible.patch | 22 + .../0081-mailbox-Add-v2-mailbox.patch | 145 ++ .../0082-media-cedrus-Add-D1-variant.patch | 43 + ...mc-Correct-the-maximum-transfer-size.patch | 59 + ...mc-Fix-DMA-descriptors-above-32-bits.patch | 29 + ...-mmc-sunxi-mmc-Add-D1-MMC-compatible.patch | 40 + ...086-mmc-sunxi-mmc-Add-more-registers.patch | 104 ++ ...ework-HCI-PHY-aka.-pmu_unk1-handling.patch | 164 ++ ...move-disc_thresh-where-not-applicabl.patch | 26 + .../0089-phy-sun4i-usb-Add-D1-variant.patch | 44 + ...sunxi-Support-new-2.5V-I-O-bias-mode.patch | 68 + ...l-sunxi-Adapt-for-D1-register-layout.patch | 51 + ...nxi-Add-support-for-Allwinner-D1-SoC.patch | 886 +++++++++ ...i-v536-document-device-tree-bindings.patch | 46 + ...-Allwinner-SoC-PWM-controller-driver.patch | 478 +++++ ...-Add-Allwinner-SoC-PWM-controller-dr.patch | 50 + ...536-Add-support-for-the-Allwinner-D1.patch | 38 + ...-dsp-Add-a-driver-for-the-DSPs-in-su.patch | 321 ++++ ...i-Add-support-for-linear-day-storage.patch | 126 ++ ...rtc-sun6i-Add-Allwinner-H616-support.patch | 30 + ...0-rtc-sun6i-Add-Allwinner-D1-support.patch | 26 + ...ctually-marked-claimed-regions-as-cl.patch | 26 + ...sram-Map-SRAM-back-to-CPU-on-release.patch | 45 + ...soc-sunxi-sram-Fix-debugfs-file-leak.patch | 71 + ...i-sram-Use-devm_of_platform_populate.patch | 45 + ...c-sunxi-sram-Add-support-for-D1-LDOs.patch | 148 ++ ...unxi-sram-Fix-debugfs-for-A64-SRAM-C.patch | 28 + .../0107-soc-sunxi-sram-Add-D1-DSP-SRAM.patch | 41 + ...soc-sunxi-sram-Add-D1-syscon-variant.patch | 28 + ...pi-spi-sun6i-Use-a-struct-for-quirks.patch | 114 ++ ...spi-sun6i-Add-Allwinner-R329-support.patch | 151 ++ ...1-spi-spi-sun6i-Dual-Quad-RX-Support.patch | 55 + ...ermal-of-Remove-duplicate-null-check.patch | 28 + ...sun4i-i2s-Also-set-capture-DMA-width.patch | 25 + ...pdif-Add-support-for-separate-resets.patch | 39 + ...dec-New-driver-for-D1-internal-codec.patch | 990 ++++++++++ ...sun20i-codec-What-is-this-ramp-thing.patch | 28 + ...17-Disable-broken-ARCH_SUNXI-drivers.patch | 44 + ...8-riscv-Add-Allwinner-D1-SoC-support.patch | 52 + ...scv-Add-Allwinner-D1-SoC-device-tree.patch | 1179 ++++++++++++ ...riscv-Add-D1-Nezha-board-device-tree.patch | 405 ++++ .../patches-5.15/0121-misc-changes.patch | 272 +++ ...nxi_pinctrl_irq_ack-avoid-build-warn.patch | 47 + .../0123-Add-a-defconfig-for-the-Nezha.patch | 256 +++ ...atchdog-sunxi_wdt-Add-support-for-D1.patch | 106 ++ ...ings-clk-Add-compatibles-for-D1-CCUs.patch | 328 ++++ ...c-sun6i-Add-H616-R329-and-D1-support.patch | 42 + 134 files changed, 21249 insertions(+) create mode 100644 target/linux/sunxid1/Makefile create mode 100644 target/linux/sunxid1/base-files/etc/board.d/02_network create mode 100644 target/linux/sunxid1/base-files/etc/inittab create mode 100644 target/linux/sunxid1/base-files/lib/preinit/80_debug create mode 100644 target/linux/sunxid1/config-5.15 create mode 100644 target/linux/sunxid1/image/Config.in create mode 100644 target/linux/sunxid1/image/Makefile create mode 100755 target/linux/sunxid1/image/gen_sunxi_sdcard_img.sh create mode 100644 target/linux/sunxid1/patches-5.15/0001-5.16-clk-sunxi-ng-Unregister-clocks-resets-when-unbinding.patch create mode 100644 target/linux/sunxid1/patches-5.15/0002-5.16-clk-sunxi-ng-Prevent-unbinding-CCUs-via-sysfs.patch create mode 100644 target/linux/sunxid1/patches-5.15/0003-5.16-clk-sunxi-ng-Use-a-separate-lock-for-each-CCU-instan.patch create mode 100644 target/linux/sunxid1/patches-5.15/0004-5.16-rtc-sun6i-Allow-probing-without-an-early-clock-provi.patch create mode 100644 target/linux/sunxid1/patches-5.15/0005-5.16-riscv-remove-.text-section-size-limitation-for-XIP.patch create mode 100644 target/linux/sunxid1/patches-5.15/0006-5.16-irq-simplify-handle_domain_-irq-nmi.patch create mode 100644 target/linux/sunxid1/patches-5.15/0007-5.16-irq-unexport-handle_irq_desc.patch create mode 100644 target/linux/sunxid1/patches-5.15/0008-5.16-irq-add-a-temporary-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTR.patch create mode 100644 target/linux/sunxid1/patches-5.15/0009-5.16-irq-remove-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY.patch create mode 100644 target/linux/sunxid1/patches-5.15/0010-5.16-irq-add-generic_handle_arch_irq.patch create mode 100644 target/linux/sunxid1/patches-5.15/0011-5.16-irq-riscv-perform-irqentry-in-entry-code.patch create mode 100644 target/linux/sunxid1/patches-5.15/0012-5.16-irq-remove-handle_domain_-irq-nmi.patch create mode 100644 target/linux/sunxid1/patches-5.15/0013-5.16-soc-sunxi_sram-Make-use-of-the-helper-function-devm_.patch create mode 100644 target/linux/sunxid1/patches-5.15/0014-input-sun4i-lradc-keys-Add-wakup-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0015-thermal-sun8i-Document-the-unknown-field.patch create mode 100644 target/linux/sunxid1/patches-5.15/0016-thermal-sun8i-Set-the-event-type-for-new-samples.patch create mode 100644 target/linux/sunxid1/patches-5.15/0017-thermal-sun8i-Use-optional-clock-reset-getters.patch create mode 100644 target/linux/sunxid1/patches-5.15/0018-thermal-sun8i-Ensure-vref-is-powered.patch create mode 100644 target/linux/sunxid1/patches-5.15/0019-thermal-sun8i-Add-support-for-the-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0020-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch create mode 100644 target/linux/sunxid1/patches-5.15/0021-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch create mode 100644 target/linux/sunxid1/patches-5.15/0022-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch create mode 100644 target/linux/sunxid1/patches-5.15/0023-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0024-nvmem-sunxi_sid-Add-support-for-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0025-Input-sun4i-lradc-keys-Add-optional-clock-reset-supp.patch create mode 100644 target/linux/sunxid1/patches-5.15/0026-Input-sun4i-lradc-keys-Add-support-for-R329-and-D1.patch create mode 100644 target/linux/sunxid1/patches-5.15/0027-leds-sunxi-New-driver-for-the-R329-D1-LED-controller.patch create mode 100644 target/linux/sunxid1/patches-5.15/0028-ASoC-sun4i-i2s-Update-registers-for-more-channels.patch create mode 100644 target/linux/sunxid1/patches-5.15/0029-ASoC-sun4i-i2s-Add-support-for-the-R329-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0030-hwspinlock-sun6i-Clarify-bank-counting-logic.patch create mode 100644 target/linux/sunxid1/patches-5.15/0031-hwspinlock-sun6i-Fix-driver-to-match-binding.patch create mode 100644 target/linux/sunxid1/patches-5.15/0032-dmaengine-sun6i-Do-not-use-virt_to_phys.patch create mode 100644 target/linux/sunxid1/patches-5.15/0033-dmaengine-sun6i-Add-support-for-34-bit-physical-addr.patch create mode 100644 target/linux/sunxid1/patches-5.15/0034-crypto-sun8i-ce-Add-support-for-the-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0035-bus-sun50i-de2-Prevent-driver-from-being-unbound.patch create mode 100644 target/linux/sunxid1/patches-5.15/0036-clk-sunxi-ng-Export-symbols-used-by-CCU-drivers.patch create mode 100644 target/linux/sunxid1/patches-5.15/0037-clk-sunxi-ng-Allow-drivers-to-be-built-as-modules.patch create mode 100644 target/linux/sunxid1/patches-5.15/0038-clk-sunxi-ng-Convert-early-providers-to-platform-dri.patch create mode 100644 target/linux/sunxid1/patches-5.15/0039-clk-sunxi-ng-Allow-the-CCU-core-to-be-built-as-a-mod.patch create mode 100644 target/linux/sunxid1/patches-5.15/0040-clk-sunxi-ng-mux-Allow-muxes-to-have-keys.patch create mode 100644 target/linux/sunxid1/patches-5.15/0041-of-irq-Use-interrupts-extended-to-find-parent.patch create mode 100644 target/linux/sunxid1/patches-5.15/0042-RISC-V-Use-SBI-SRST-extension-when-available.patch create mode 100644 target/linux/sunxid1/patches-5.15/0043-RISC-V-Enable-CPU_IDLE-drivers.patch create mode 100644 target/linux/sunxid1/patches-5.15/0044-RISC-V-Rename-relocate-and-make-it-global.patch create mode 100644 target/linux/sunxid1/patches-5.15/0045-RISC-V-Add-arch-functions-for-non-retentive-suspend-.patch create mode 100644 target/linux/sunxid1/patches-5.15/0046-RISC-V-Add-SBI-HSM-suspend-related-defines.patch create mode 100644 target/linux/sunxid1/patches-5.15/0047-cpuidle-Factor-out-power-domain-related-code-from-PS.patch create mode 100644 target/linux/sunxid1/patches-5.15/0048-cpuidle-Add-RISC-V-SBI-CPU-idle-driver.patch create mode 100644 target/linux/sunxid1/patches-5.15/0049-RISC-V-Enable-RISC-V-SBI-CPU-Idle-driver-for-QEMU-vi.patch create mode 100644 target/linux/sunxid1/patches-5.15/0050-RISC-V-Clear-SIP-bit-only-when-using-SBI-IPI-operati.patch create mode 100644 target/linux/sunxid1/patches-5.15/0051-RISC-V-Treat-IPIs-as-normal-Linux-IRQs.patch create mode 100644 target/linux/sunxid1/patches-5.15/0052-clocksource-clint-Add-support-for-ACLINT-MTIMER-devi.patch create mode 100644 target/linux/sunxid1/patches-5.15/0053-irqchip-sun20i-Add-Allwinner-D1-stacked-INTC-driver.patch create mode 100644 target/linux/sunxid1/patches-5.15/0054-clk-sunxi-ng-div-Add-macros-using-clk_parent_data-an.patch create mode 100644 target/linux/sunxid1/patches-5.15/0055-clk-sunxi-ng-mp-Add-macros-using-clk_parent_data-and.patch create mode 100644 target/linux/sunxid1/patches-5.15/0056-clk-sunxi-ng-mux-Add-macros-using-clk_parent_data-an.patch create mode 100644 target/linux/sunxid1/patches-5.15/0057-clk-sunxi-ng-gate-Add-macros-for-gates-with-fixed-di.patch create mode 100644 target/linux/sunxid1/patches-5.15/0058-clk-sunxi-ng-Add-support-for-the-D1-SoC-clocks.patch create mode 100644 target/linux/sunxid1/patches-5.15/0059-clk-sunxi-ng-Add-support-for-the-sun6i-RTC-clocks.patch create mode 100644 target/linux/sunxid1/patches-5.15/0060-clk-sunxi-ng-sun6i-rtc-Add-support-for-H6.patch create mode 100644 target/linux/sunxid1/patches-5.15/0061-dmaengine-sun6i-Add-support-for-the-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0062-riscv-pgtable-Fixup-_PAGE_CHG_MASK-usage.patch create mode 100644 target/linux/sunxid1/patches-5.15/0063-riscv-pgtable-Add-custom-protection_map-init.patch create mode 100644 target/linux/sunxid1/patches-5.15/0064-riscv-pgtable-Add-DMA_COHERENT-with-custom-PTE-attri.patch create mode 100644 target/linux/sunxid1/patches-5.15/0065-riscv-fixup-PAGE_NONE.patch create mode 100644 target/linux/sunxid1/patches-5.15/0066-riscv-cmo-Add-dma-noncoherency-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0067-riscv-cmo-Add-vendor-custom-icache-sync.patch create mode 100644 target/linux/sunxid1/patches-5.15/0068-fixed-UB-which-lead-to-cache-coherence-bug.patch create mode 100644 target/linux/sunxid1/patches-5.15/0069-Enable-T-HEAD-MMU-extensions-unconditionally.patch create mode 100644 target/linux/sunxid1/patches-5.15/0070-riscv-Allow-suspend.patch create mode 100644 target/linux/sunxid1/patches-5.15/0071-riscv-cacheinfo-Remind-myself-to-fix-this.patch create mode 100644 target/linux/sunxid1/patches-5.15/0072-clocksource-riscv-Prefer-it-over-MMIO-clocksources.patch create mode 100644 target/linux/sunxid1/patches-5.15/0073-riscv-Enable-cpufreq.patch create mode 100644 target/linux/sunxid1/patches-5.15/0074-cpufreq-sun50i-add-efuse_xlate-to-get-efuse-version.patch create mode 100644 target/linux/sunxid1/patches-5.15/0075-cpufreq-sun50i-add-A100-cpufreq-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0076-cpufreq-sun50i-Move-out-of-ARM-specific-section.patch create mode 100644 target/linux/sunxid1/patches-5.15/0077-cpufreq-sun50i-Add-D1-cpufreq-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0078-dmaengine-sun6i-Changes-from-BSP.patch create mode 100644 target/linux/sunxid1/patches-5.15/0079-iommu-sun50i-Add-support-for-D1-IOMMU.patch create mode 100644 target/linux/sunxid1/patches-5.15/0080-irqchip-sifive-plic-Add-T-HEAD-PLIC-compatible.patch create mode 100644 target/linux/sunxid1/patches-5.15/0081-mailbox-Add-v2-mailbox.patch create mode 100644 target/linux/sunxid1/patches-5.15/0082-media-cedrus-Add-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0083-mmc-sunxi-mmc-Correct-the-maximum-transfer-size.patch create mode 100644 target/linux/sunxid1/patches-5.15/0084-mmc-sunxi-mmc-Fix-DMA-descriptors-above-32-bits.patch create mode 100644 target/linux/sunxid1/patches-5.15/0085-mmc-sunxi-mmc-Add-D1-MMC-compatible.patch create mode 100644 target/linux/sunxid1/patches-5.15/0086-mmc-sunxi-mmc-Add-more-registers.patch create mode 100644 target/linux/sunxid1/patches-5.15/0087-phy-sun4i-usb-Rework-HCI-PHY-aka.-pmu_unk1-handling.patch create mode 100644 target/linux/sunxid1/patches-5.15/0088-phy-sun4i-usb-Remove-disc_thresh-where-not-applicabl.patch create mode 100644 target/linux/sunxid1/patches-5.15/0089-phy-sun4i-usb-Add-D1-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0090-pinctrl-sunxi-Support-new-2.5V-I-O-bias-mode.patch create mode 100644 target/linux/sunxid1/patches-5.15/0091-pinctrl-sunxi-Adapt-for-D1-register-layout.patch create mode 100644 target/linux/sunxid1/patches-5.15/0092-pinctrl-sunxi-Add-support-for-Allwinner-D1-SoC.patch create mode 100644 target/linux/sunxid1/patches-5.15/0093-pwm-sun8i-v536-document-device-tree-bindings.patch create mode 100644 target/linux/sunxid1/patches-5.15/0094-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch create mode 100644 target/linux/sunxid1/patches-5.15/0095-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch create mode 100644 target/linux/sunxid1/patches-5.15/0096-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch create mode 100644 target/linux/sunxid1/patches-5.15/0097-remoteproc-sun8i-dsp-Add-a-driver-for-the-DSPs-in-su.patch create mode 100644 target/linux/sunxid1/patches-5.15/0098-rtc-sun6i-Add-support-for-linear-day-storage.patch create mode 100644 target/linux/sunxid1/patches-5.15/0099-rtc-sun6i-Add-Allwinner-H616-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0100-rtc-sun6i-Add-Allwinner-D1-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0101-soc-sunxi-sram-Actually-marked-claimed-regions-as-cl.patch create mode 100644 target/linux/sunxid1/patches-5.15/0102-soc-sunxi-sram-Map-SRAM-back-to-CPU-on-release.patch create mode 100644 target/linux/sunxid1/patches-5.15/0103-soc-sunxi-sram-Fix-debugfs-file-leak.patch create mode 100644 target/linux/sunxid1/patches-5.15/0104-soc-sunxi-sram-Use-devm_of_platform_populate.patch create mode 100644 target/linux/sunxid1/patches-5.15/0105-soc-sunxi-sram-Add-support-for-D1-LDOs.patch create mode 100644 target/linux/sunxid1/patches-5.15/0106-soc-sunxi-sram-Fix-debugfs-for-A64-SRAM-C.patch create mode 100644 target/linux/sunxid1/patches-5.15/0107-soc-sunxi-sram-Add-D1-DSP-SRAM.patch create mode 100644 target/linux/sunxid1/patches-5.15/0108-soc-sunxi-sram-Add-D1-syscon-variant.patch create mode 100644 target/linux/sunxid1/patches-5.15/0109-spi-spi-sun6i-Use-a-struct-for-quirks.patch create mode 100644 target/linux/sunxid1/patches-5.15/0110-spi-spi-sun6i-Add-Allwinner-R329-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0111-spi-spi-sun6i-Dual-Quad-RX-Support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0112-thermal-of-Remove-duplicate-null-check.patch create mode 100644 target/linux/sunxid1/patches-5.15/0113-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch create mode 100644 target/linux/sunxid1/patches-5.15/0114-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch create mode 100644 target/linux/sunxid1/patches-5.15/0115-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch create mode 100644 target/linux/sunxid1/patches-5.15/0116-ASoC-sun20i-codec-What-is-this-ramp-thing.patch create mode 100644 target/linux/sunxid1/patches-5.15/0117-Disable-broken-ARCH_SUNXI-drivers.patch create mode 100644 target/linux/sunxid1/patches-5.15/0118-riscv-Add-Allwinner-D1-SoC-support.patch create mode 100644 target/linux/sunxid1/patches-5.15/0119-riscv-Add-Allwinner-D1-SoC-device-tree.patch create mode 100644 target/linux/sunxid1/patches-5.15/0120-riscv-Add-D1-Nezha-board-device-tree.patch create mode 100644 target/linux/sunxid1/patches-5.15/0121-misc-changes.patch create mode 100644 target/linux/sunxid1/patches-5.15/0122-pinctrl-sunxi-sunxi_pinctrl_irq_ack-avoid-build-warn.patch create mode 100644 target/linux/sunxid1/patches-5.15/0123-Add-a-defconfig-for-the-Nezha.patch create mode 100644 target/linux/sunxid1/patches-5.15/0124-watchdog-sunxi_wdt-Add-support-for-D1.patch create mode 100644 target/linux/sunxid1/patches-5.15/0125-dt-bindings-clk-Add-compatibles-for-D1-CCUs.patch create mode 100644 target/linux/sunxid1/patches-5.15/0126-dt-bindings-rtc-sun6i-Add-H616-R329-and-D1-support.patch diff --git a/target/linux/sunxid1/Makefile b/target/linux/sunxid1/Makefile new file mode 100644 index 0000000000..7d801076d9 --- /dev/null +++ b/target/linux/sunxid1/Makefile @@ -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 + +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 index 0000000000..df48b431af --- /dev/null +++ b/target/linux/sunxid1/base-files/etc/board.d/02_network @@ -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 index 0000000000..93cb94860d --- /dev/null +++ b/target/linux/sunxid1/base-files/etc/inittab @@ -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 index 0000000000..087e86e0c3 --- /dev/null +++ b/target/linux/sunxid1/base-files/lib/preinit/80_debug @@ -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 index 0000000000..91bf02c646 --- /dev/null +++ b/target/linux/sunxid1/config-5.15 @@ -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 index 0000000000..6d54195e8b --- /dev/null +++ b/target/linux/sunxid1/image/Config.in @@ -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 index 0000000000..75d4e5ee28 --- /dev/null +++ b/target/linux/sunxid1/image/Makefile @@ -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 index 0000000000..08cecc09ff --- /dev/null +++ b/target/linux/sunxid1/image/gen_sunxi_sdcard_img.sh @@ -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 " + 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 index 0000000000..c785711925 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0001-5.16-clk-sunxi-ng-Unregister-clocks-resets-when-unbinding.patch @@ -0,0 +1,492 @@ +From 7599e32a45d303268886ba6b4a08c37e877e42a2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +Signed-off-by: Maxime Ripard +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 + #include ++#include + #include + #include + +@@ -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 index 0000000000..ed66c08fa6 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0002-5.16-clk-sunxi-ng-Prevent-unbinding-CCUs-via-sysfs.patch @@ -0,0 +1,126 @@ +From 98249d575dc3956e61214da83098cab4983aebd3 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +Signed-off-by: Maxime Ripard +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 index 0000000000..c91ac1f86c --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0003-5.16-clk-sunxi-ng-Use-a-separate-lock-for-each-CCU-instan.patch @@ -0,0 +1,65 @@ +From 93395c038bc0a1750fec54eec531c5d36eec1aaf Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +Signed-off-by: Maxime Ripard +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 index 0000000000..69044fb170 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0004-5.16-rtc-sun6i-Allow-probing-without-an-early-clock-provi.patch @@ -0,0 +1,46 @@ +From 0dfc140602711a3d2a72cdc9bd24f2937b14ef01 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +Signed-off-by: Alexandre Belloni +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 index 0000000000..2be08e728f --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0005-5.16-riscv-remove-.text-section-size-limitation-for-XIP.patch @@ -0,0 +1,148 @@ +From cdbe9f3ed5fd2fa0395f317b81e653781c768d7e Mon Sep 17 00:00:00 2001 +From: Vitaly Wool +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 +Signed-off-by: Palmer Dabbelt +--- + 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 index 0000000000..9b40fdb137 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0006-5.16-irq-simplify-handle_domain_-irq-nmi.patch @@ -0,0 +1,76 @@ +From 2f0335228bf4bf224f5535464a940753c18af8f9 Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Reviewed-by: Marc Zyngier +Cc: Thomas Gleixner +--- + 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 index 0000000000..49e6c2c2e7 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0007-5.16-irq-unexport-handle_irq_desc.patch @@ -0,0 +1,31 @@ +From 5066cc5deaca0171b8b27079f81a924471be0e78 Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Suggested-by: Marc Zyngier +Reviewed-by: Marc Zyngier +Cc: Thomas Gleixner +--- + 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 index 0000000000..2b4745e89f --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0008-5.16-irq-add-a-temporary-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTR.patch @@ -0,0 +1,193 @@ +From 48f86fb2e394a3daf227faaf2ada4b130d0da6ca Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Reviewed-by: Marc Zyngier +Cc: Thomas Gleixner +--- + 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 index 0000000000..ad28c833f9 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0009-5.16-irq-remove-CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY.patch @@ -0,0 +1,63 @@ +From 0a7b76c9ec957c83a5b2f4b06ec66220b4804c03 Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Reviewed-by: Marc Zyngier +Cc: Thomas Gleixner +--- + 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 index 0000000000..2320921e2c --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0010-5.16-irq-add-generic_handle_arch_irq.patch @@ -0,0 +1,76 @@ +From 226328e72b232a1702e29f8f6747c4d889d4425c Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Reviewed-by: Marc Zyngier +Reviewed-by: Guo Ren +Cc: Thomas Gleixner +--- + 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 + #include + ++#include ++ + #include + + #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 index 0000000000..14904687e3 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0011-5.16-irq-riscv-perform-irqentry-in-entry-code.patch @@ -0,0 +1,96 @@ +From ef1f47034f47324dfdb12e97253401438a9ff18d Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Reviewed-by: Guo Ren +Reviewed-by: Marc Zyngier +Cc: Albert Ou +Cc: Palmer Dabbelt +Cc: Paul Walmsley +Cc: Thomas Gleixner +--- + 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 index 0000000000..e1a5052795 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0012-5.16-irq-remove-handle_domain_-irq-nmi.patch @@ -0,0 +1,221 @@ +From 1c0b62a931ffc5ef35421dc8410dcf5213a135f0 Mon Sep 17 00:00:00 2001 +From: Mark Rutland +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 +Reviewed-by: Marc Zyngier +Cc: Thomas Gleixner +--- + 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 index 0000000000..3fcf4bb4ba --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0013-5.16-soc-sunxi_sram-Make-use-of-the-helper-function-devm_.patch @@ -0,0 +1,42 @@ +From cbb36ef09be83f9e0fdd97d33d28e90292860814 Mon Sep 17 00:00:00 2001 +From: Cai Huoqing +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 +Signed-off-by: Maxime Ripard +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 index 0000000000..3f2b09d9ba --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0014-input-sun4i-lradc-keys-Add-wakup-support.patch @@ -0,0 +1,74 @@ +From cacc7b781648cdcfe9866a0709143e05789b6555 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +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 +Reviewed-by: Hans de Goede +Signed-off-by: Ondrej Jirman +Signed-off-by: Samuel Holland +--- + 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 + #include + #include ++#include ++#include + #include + #include + +@@ -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 index 0000000000..045c9c526c --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0015-thermal-sun8i-Document-the-unknown-field.patch @@ -0,0 +1,63 @@ +From 9dec9d2aec1607dffe516c901d137adb0e8839e1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..c3a6a5bddf --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0016-thermal-sun8i-Set-the-event-type-for-new-samples.patch @@ -0,0 +1,29 @@ +From 307dad7755974e3712d87b08972bff67ac9ce652 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..405458b985 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0017-thermal-sun8i-Use-optional-clock-reset-getters.patch @@ -0,0 +1,114 @@ +From 02ca2ba7daef709e1271dc5176c6efe7c635b15a Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..cfa5a6180e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0018-thermal-sun8i-Ensure-vref-is-powered.patch @@ -0,0 +1,81 @@ +From 8bd42cf0216141eee71e303895a9e011f9951286 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..d5a776738d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0019-thermal-sun8i-Add-support-for-the-D1-variant.patch @@ -0,0 +1,46 @@ +From 9e6cbc170439341082c5dfc36ac2d47a621152f2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..59e455eb71 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0020-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch @@ -0,0 +1,35 @@ +From 617298fc711e9f5611dbfb44622cef4b330c66f0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..3b6711bcf3 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0021-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch @@ -0,0 +1,83 @@ +From 5ca31032fb45e99ead74963601492fce57a261b6 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..8ff9beb52f --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0022-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch @@ -0,0 +1,121 @@ +From 3153907498e377c97f0eb3026a87b6834e48b166 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..9f6f61e008 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0023-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch @@ -0,0 +1,45 @@ +From 1fb53b6fb639f45d2ba4bf2a885e3fd5fbe95d8c Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..e0d608321c --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0024-nvmem-sunxi_sid-Add-support-for-D1-variant.patch @@ -0,0 +1,40 @@ +From d69154525ee615f7f24b772658416f3a1093df23 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..2a5a7f905e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0025-Input-sun4i-lradc-keys-Add-optional-clock-reset-supp.patch @@ -0,0 +1,101 @@ +From 92e9840b41f64e5f98bb846b8db061276898e791 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 + #include + #include + #include +@@ -25,6 +26,7 @@ + #include + #include + #include ++#include + #include + + #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 index 0000000000..d8ccdb4216 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0026-Input-sun4i-lradc-keys-Add-support-for-R329-and-D1.patch @@ -0,0 +1,30 @@ +From a592f18da0fa6a1cdcc3b06302c78d0b32f20d62 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..ae667e617c --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0027-leds-sunxi-New-driver-for-the-R329-D1-LED-controller.patch @@ -0,0 +1,611 @@ +From 929bb1c60474dc25b8c8f2d855ee704e16fe97b9 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++// ++// Partly based on drivers/leds/leds-turris-omnia.c, which is: ++// Copyright (c) 2020 by Marek Behún ++// ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 index 0000000000..e8ec6a5827 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0028-ASoC-sun4i-i2s-Update-registers-for-more-channels.patch @@ -0,0 +1,99 @@ +From 8a568791d2dcb2f81df3e0664418dddc71d42500 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..a905037e5f --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0029-ASoC-sun4i-i2s-Add-support-for-the-R329-D1-variant.patch @@ -0,0 +1,98 @@ +From 8da658ca3f0aa0b4727333d544518bf985c72e8f Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..95ca5f0b90 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0030-hwspinlock-sun6i-Clarify-bank-counting-logic.patch @@ -0,0 +1,69 @@ +From 2040266a0a941ec34949f049a2245f88a0b58ebc Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..6ae488b3ff --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0031-hwspinlock-sun6i-Fix-driver-to-match-binding.patch @@ -0,0 +1,42 @@ +From d9e58fa4c5704d94f3fec0d73eb018e7684b634b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..7a83d2b9c7 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0032-dmaengine-sun6i-Do-not-use-virt_to_phys.patch @@ -0,0 +1,116 @@ +From a79bb5d39c26fa96ceb3e306ab2b1a418ec96541 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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, ®, ++ 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 index 0000000000..f59212dae1 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0033-dmaengine-sun6i-Add-support-for-34-bit-physical-addr.patch @@ -0,0 +1,157 @@ +From c14eb7526a01f87568c5f063eff3e628299b09e4 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..d1d6e63610 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0034-crypto-sun8i-ce-Add-support-for-the-D1-variant.patch @@ -0,0 +1,76 @@ +From 2d56be1a7b337a5b73afbf5bb762a314835e9ed4 Mon Sep 17 00:00:00 2001 +From: Corentin Labbe +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 +Signed-off-by: Samuel Holland +--- + .../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 index 0000000000..83eb86601b --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0035-bus-sun50i-de2-Prevent-driver-from-being-unbound.patch @@ -0,0 +1,44 @@ +From 692f382f2d8e87d65e19ef44f7c1794ceac14126 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..4192a12d8d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0036-clk-sunxi-ng-Export-symbols-used-by-CCU-drivers.patch @@ -0,0 +1,342 @@ +From 6ff4e726d98f36bcd5669cf5dac3f84cb9f8f9cf Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..2d03d09156 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0037-clk-sunxi-ng-Allow-drivers-to-be-built-as-modules.patch @@ -0,0 +1,387 @@ +From de552526eb4e1add4a2d4b616c46435e01650022 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 - 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 +--- + 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 + #include +-#include + #include + + #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 + #include + #include +-#include + #include + + #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 + #include +-#include ++#include + #include + + #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 + #include +-#include ++#include + #include + + #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 + #include +-#include ++#include + #include + + #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 + #include +-#include +-#include ++#include ++#include + #include + #include + +@@ -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 + #include ++#include + #include + #include + +@@ -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 + #include +-#include ++#include + #include + #include + +@@ -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 + #include +-#include ++#include + #include + + #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 + #include +-#include ++#include + #include + + #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 index 0000000000..72a53634ee --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0038-clk-sunxi-ng-Convert-early-providers-to-platform-dri.patch @@ -0,0 +1,891 @@ +From f5fb7ccecb5c4404eeb96d6d5662d1e4d84f80ba Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 + #include +-#include ++#include ++#include ++#include + + #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 +-#include ++#include ++#include + #include + + #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 + #include +-#include ++#include + #include + + #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 + #include +-#include ++#include ++#include + + #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 + #include +-#include ++#include ++#include + + #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 + #include +-#include ++#include ++#include + + #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 + #include +-#include ++#include ++#include ++#include + + #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 +-#include ++#include ++#include + #include + + #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 + #include +-#include ++#include ++#include ++#include + + #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 + #include +-#include ++#include ++#include + + #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 index 0000000000..265195cf0b --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0039-clk-sunxi-ng-Allow-the-CCU-core-to-be-built-as-a-mod.patch @@ -0,0 +1,176 @@ +From c1ddd74ba3ddff59352333477f66a85bbfb414eb Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 + #include + #include ++#include + #include + + #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 +- +-#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 index 0000000000..eb58ba4852 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0040-clk-sunxi-ng-mux-Allow-muxes-to-have-keys.patch @@ -0,0 +1,63 @@ +From 88f4f9b057dda3d521fb13d7a7fbd09cf95fda41 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..1db738bf69 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0041-of-irq-Use-interrupts-extended-to-find-parent.patch @@ -0,0 +1,59 @@ +From 442fb5f5b81fbf5535d77859af73d2c05c930956 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..cede184957 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0042-RISC-V-Use-SBI-SRST-extension-when-available.patch @@ -0,0 +1,134 @@ +From 10c33c9b9734fc0c93d4766c1c7bfa87739ef712 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +Reviewed-by: Atish Patra +--- + 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 + #include ++#include + #include + #include + +@@ -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 index 0000000000..208aa1f7f4 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0043-RISC-V-Enable-CPU_IDLE-drivers.patch @@ -0,0 +1,119 @@ +From 1efcd21929800a5435e6f6cfcf8397f7fe621a33 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +Signed-off-by: Samuel Holland +--- + 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 ++#include ++ ++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 + #include + #include ++#include + + 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 index 0000000000..b259064b5b --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0044-RISC-V-Rename-relocate-and-make-it-global.patch @@ -0,0 +1,53 @@ +From 10b6c02d5a9baadfeb9b1d16ef2c62de35d8bfa5 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +--- + 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 index 0000000000..130c41f241 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0045-RISC-V-Add-arch-functions-for-non-retentive-suspend-.patch @@ -0,0 +1,394 @@ +From c79b186f87c991b22271451520d211de26e5fd7d Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +Signed-off-by: Samuel Holland +--- + 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 ++ ++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 + #include + #include ++#include + + 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 + #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 ++#include ++#include ++ ++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 ++#include ++#include ++#include ++ ++ .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 index 0000000000..193e150011 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0046-RISC-V-Add-SBI-HSM-suspend-related-defines.patch @@ -0,0 +1,72 @@ +From 6a6733ae3666b12d2288e8f75e4406c3e2137cf4 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +--- + 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 index 0000000000..e7f0783769 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0047-cpuidle-Factor-out-power-domain-related-code-from-PS.patch @@ -0,0 +1,548 @@ +From 21cdb37bf5cdf1b4466b2a5f9fb1494adc55feac Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +Reviewed-by: Ulf Hansson +--- + 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 ++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 + 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 ++ * ++ * Copyright (c) 2021 Western Digital Corporation or its affiliates. ++ */ ++ ++#define pr_fmt(fmt) "dt-idle-genpd: " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 index 0000000000..ddd2c1d76b --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0048-cpuidle-Add-RISC-V-SBI-CPU-idle-driver.patch @@ -0,0 +1,725 @@ +From 583adf3464089e7f164d45bbddae08fc2e60fe2a Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +--- + 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 ++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 + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 index 0000000000..426f19795e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0049-RISC-V-Enable-RISC-V-SBI-CPU-Idle-driver-for-QEMU-vi.patch @@ -0,0 +1,57 @@ +From 908cff58b3a2185c8fa22adfc96a5a7ce33c3387 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +--- + 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 index 0000000000..ffe7cce828 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0050-RISC-V-Clear-SIP-bit-only-when-using-SBI-IPI-operati.patch @@ -0,0 +1,53 @@ +From 65fb9bd8dc188403f9f922542ee2faae64f96a54 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +Reviewed-by: Bin Meng +--- + 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 index 0000000000..60a8e794d2 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0051-RISC-V-Treat-IPIs-as-normal-Linux-IRQs.patch @@ -0,0 +1,843 @@ +From b3977c0e4c7396a190e8d9636573a76bd7868656 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +--- + 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 + #include + #include +-#include ++#include + + 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 + #include + #include +-#include ++#include + + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 + #include + #include ++#include + #include + +-#include + #include + #include + +@@ -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 + #include + #include +-#include + #include + #include + +@@ -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 index 0000000000..1e4669c7c9 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0052-clocksource-clint-Add-support-for-ACLINT-MTIMER-devi.patch @@ -0,0 +1,138 @@ +From 3877938e9a34e561cb6564ea033454d7d5615ca8 Mon Sep 17 00:00:00 2001 +From: Anup Patel +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 +Reviewed-by: Bin Meng +--- + 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 + #include + #include ++#include + #include + #include + #include + +-#ifndef CONFIG_RISCV_M_MODE ++#ifdef CONFIG_RISCV_M_MODE + #include ++ ++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 index 0000000000..739a3c61a0 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0053-irqchip-sun20i-Add-Allwinner-D1-stacked-INTC-driver.patch @@ -0,0 +1,156 @@ +From 41c15354d89edf12be64f19ababdaaee0cccaef2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 index 0000000000..d6ff0fb887 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0054-clk-sunxi-ng-div-Add-macros-using-clk_parent_data-an.patch @@ -0,0 +1,115 @@ +From 020c708867842e41e96d6a73081a7d32415b2301 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..96a2e989ec --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0055-clk-sunxi-ng-mp-Add-macros-using-clk_parent_data-and.patch @@ -0,0 +1,79 @@ +From 3ae434b57e6db1761db9403512a21cac890a8856 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..92a7799eb4 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0056-clk-sunxi-ng-mux-Add-macros-using-clk_parent_data-an.patch @@ -0,0 +1,63 @@ +From 916bf0d78efdb771692043170aceaa87ebd29617 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..fe6aa87d74 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0057-clk-sunxi-ng-gate-Add-macros-for-gates-with-fixed-di.patch @@ -0,0 +1,75 @@ +From 6420720c7f1c456341f71a0a9da3b79f26d89f30 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..4221012409 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0058-clk-sunxi-ng-Add-support-for-the-D1-SoC-clocks.patch @@ -0,0 +1,1653 @@ +From 78feeb7c1c73da8480ca503812f289e0265a9345 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++ */ ++ ++#include ++#include ++#include ++ ++#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 ++ */ ++ ++#ifndef _CCU_SUN20I_D1_R_H ++#define _CCU_SUN20I_D1_R_H ++ ++#include ++#include ++ ++#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 ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#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 ++ */ ++ ++#ifndef _CCU_SUN20I_D1_H_ ++#define _CCU_SUN20I_D1_H_ ++ ++#include ++#include ++ ++#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 index 0000000000..b5d12ad0ce --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0059-clk-sunxi-ng-Add-support-for-the-sun6i-RTC-clocks.patch @@ -0,0 +1,518 @@ +From b3692a02024482ac18f684a4c38cfd4be2a2a12b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++// ++ ++#include ++#include ++#include ++#include ++ ++#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 ++ ++#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 + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..f6a23e430c --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0060-clk-sunxi-ng-sun6i-rtc-Add-support-for-H6.patch @@ -0,0 +1,91 @@ +From 026ed9ed88c6cb6b2ae8f005f7b83304800a6171 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..cc6742507f --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0061-dmaengine-sun6i-Add-support-for-the-D1-variant.patch @@ -0,0 +1,41 @@ +From 739535112738d67cfeada06baea94fbc40f84328 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..e8b2269438 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0062-riscv-pgtable-Fixup-_PAGE_CHG_MASK-usage.patch @@ -0,0 +1,85 @@ +From db0b9488559ef01603ff9bc5799d41d7bd346b39 Mon Sep 17 00:00:00 2001 +From: Guo Ren +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 +Signed-off-by: Liu Shaohua +Cc: Anup Patel +Cc: Arnd Bergmann +Cc: Chen-Yu Tsai +Cc: Christoph Hellwig +Cc: Drew Fustini +Cc: Maxime Ripard +Cc: Palmer Dabbelt +Cc: Wei Fu +Cc: Wei Wu +--- + 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 index 0000000000..38686e9d9b --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0063-riscv-pgtable-Add-custom-protection_map-init.patch @@ -0,0 +1,105 @@ +From 65bf9a94eed354bb356e61573b0a011e305e6fda Mon Sep 17 00:00:00 2001 +From: Guo Ren +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 +Cc: Andrew Morton +Cc: Arnd Bergmann +Cc: Palmer Dabbelt +--- + 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 index 0000000000..fe8a54df57 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0064-riscv-pgtable-Add-DMA_COHERENT-with-custom-PTE-attri.patch @@ -0,0 +1,200 @@ +From d2579d2b8552501662320fbc57875f83f0d91a4f Mon Sep 17 00:00:00 2001 +From: Guo Ren +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 +Signed-off-by: Liu Shaohua +Cc: Palmer Dabbelt +Cc: Christoph Hellwig +Cc: Anup Patel +Cc: Arnd Bergmann +Cc: Drew Fustini +Cc: Wei Fu +Cc: Wei Wu +Cc: Chen-Yu Tsai +Cc: Maxime Ripard +--- + 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 ++#include + #include + #include ++#include + #include + + /* +@@ -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 index 0000000000..3bc529ff8e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0065-riscv-fixup-PAGE_NONE.patch @@ -0,0 +1,26 @@ +From 43e3d184609e4a46d17a5c897e7e1da113233ca2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 15 Nov 2021 23:37:41 -0600 +Subject: [PATCH 065/124] riscv: fixup PAGE_NONE + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..976b25b763 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0066-riscv-cmo-Add-dma-noncoherency-support.patch @@ -0,0 +1,253 @@ +From 346b9731f8704f684aa1e74b7ced812864d78da2 Mon Sep 17 00:00:00 2001 +From: Guo Ren +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 +Signed-off-by: Liu Shaohua +Cc: Palmer Dabbelt +Cc: Christoph Hellwig +Cc: Anup Patel +Cc: Arnd Bergmann +Cc: Drew Fustini +Cc: Wei Fu +Cc: Wei Wu +Cc: Chen-Yu Tsai +Cc: Maxime Ripard +--- + 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 ++#include ++ ++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 index 0000000000..b4a94dbeee --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0067-riscv-cmo-Add-vendor-custom-icache-sync.patch @@ -0,0 +1,182 @@ +From 23c539154e9c3ef77bfa17398121eaa3ef26eee5 Mon Sep 17 00:00:00 2001 +From: Guo Ren +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 +Signed-off-by: Liu Shaohua +Cc: Anup Patel +Cc: Atish Patra +Cc: Palmer Dabbelt +Cc: Chen-Yu Tsai +Cc: Drew Fustini +Cc: Maxime Ripard +Cc: Palmer Dabbelt +Cc: Wei Fu +Cc: Wei Wu +--- + 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 + #include ++#include ++ ++/* ++ * 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 + #include + + #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 index 0000000000..54b35a5fb6 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0068-fixed-UB-which-lead-to-cache-coherence-bug.patch @@ -0,0 +1,25 @@ +From 933ba1cb66d124454889c8c2b844fee2b0e0960b Mon Sep 17 00:00:00 2001 +From: Yangyu Chen +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 index 0000000000..83fa0c28fe --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0069-Enable-T-HEAD-MMU-extensions-unconditionally.patch @@ -0,0 +1,26 @@ +From c35eeb146ba1a615b686951a6a89794ee5682148 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 6 Jun 2021 14:17:30 -0500 +Subject: [PATCH 069/124] Enable T-HEAD MMU extensions unconditionally + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..ab4d25964d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0070-riscv-Allow-suspend.patch @@ -0,0 +1,27 @@ +From 8255fd9e0ea6e7c0d621f401fc6fbc7fdfc73ab2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 15 Nov 2021 23:38:00 -0600 +Subject: [PATCH 070/124] riscv: Allow suspend + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..0ccfe3efcc --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0071-riscv-cacheinfo-Remind-myself-to-fix-this.patch @@ -0,0 +1,25 @@ +From 751def916449fd13685e28c913032c51266b6d10 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..95be929fa4 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0072-clocksource-riscv-Prefer-it-over-MMIO-clocksources.patch @@ -0,0 +1,26 @@ +From bab6179fa6b0f3f819968c4034c1517283eb3dc7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..7828276104 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0073-riscv-Enable-cpufreq.patch @@ -0,0 +1,26 @@ +From 71f14616158d3a2bc1ffb726b05d4aa6bec0f459 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 6 Jun 2021 15:02:27 -0500 +Subject: [PATCH 073/124] riscv: Enable cpufreq + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..8b48626feb --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0074-cpufreq-sun50i-add-efuse_xlate-to-get-efuse-version.patch @@ -0,0 +1,162 @@ +From 48836972991b23a270f5505e1ee42de7466ac9c1 Mon Sep 17 00:00:00 2001 +From: Shuosheng Huang +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 +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..e11c2a962d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0075-cpufreq-sun50i-add-A100-cpufreq-support.patch @@ -0,0 +1,90 @@ +From cd8725b4b8e7f00a06c5256162d499dff50ec3b8 Mon Sep 17 00:00:00 2001 +From: Shuosheng Huang +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 +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..820736fc8f --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0076-cpufreq-sun50i-Move-out-of-ARM-specific-section.patch @@ -0,0 +1,98 @@ +From d1645eeec1f5361067b04213ffc9ab5ae6ba773b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..769447ef51 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0077-cpufreq-sun50i-Add-D1-cpufreq-support.patch @@ -0,0 +1,61 @@ +From 2b483c0072cc28b59bafa7fe9c4250b4f32dd5e0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 16 May 2021 22:10:05 -0500 +Subject: [PATCH 077/124] cpufreq: sun50i: Add D1 cpufreq support + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..992e6a85f4 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0078-dmaengine-sun6i-Changes-from-BSP.patch @@ -0,0 +1,59 @@ +From e3547799347f60c1b177406849bddec867fad343 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 13 Jun 2021 14:51:23 -0500 +Subject: [PATCH 078/124] dmaengine: sun6i: Changes from BSP + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..72aec64572 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0079-iommu-sun50i-Add-support-for-D1-IOMMU.patch @@ -0,0 +1,75 @@ +From c32597907fa4dfdbdf96424f930b6b288acc1ee0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..0ac7c2d522 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0080-irqchip-sifive-plic-Add-T-HEAD-PLIC-compatible.patch @@ -0,0 +1,22 @@ +From e18f604236129fd20868c53e5dc32f119e469be9 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..7feeecb68e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0081-mailbox-Add-v2-mailbox.patch @@ -0,0 +1,145 @@ +From f0e764625b5bcfc260f74ede0a9d4ed497609211 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 ++ ++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 ++ #include ++ #include ++ ++ 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 index 0000000000..bfb8f2b624 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0082-media-cedrus-Add-D1-variant.patch @@ -0,0 +1,43 @@ +From 0d13a0d00a53d70b8a45437dadec46c42be7b56a Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 13 Jun 2021 23:47:22 -0500 +Subject: [PATCH 082/124] media: cedrus: Add D1 variant + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..8f60ff0d12 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0083-mmc-sunxi-mmc-Correct-the-maximum-transfer-size.patch @@ -0,0 +1,59 @@ +From 7be2c5fed24014995642b24f14d414c4471b79e4 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..609d866f81 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0084-mmc-sunxi-mmc-Fix-DMA-descriptors-above-32-bits.patch @@ -0,0 +1,29 @@ +From 24c1d741a49938258a8664959e0dbb17e151cae3 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..26b360ebb4 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0085-mmc-sunxi-mmc-Add-D1-MMC-compatible.patch @@ -0,0 +1,40 @@ +From 8d2fd59f8a638745eabd207d3db9fa02d2f9ba98 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..1e3cc9e887 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0086-mmc-sunxi-mmc-Add-more-registers.patch @@ -0,0 +1,104 @@ +From 22fa62f3cad1d1a053760e32d2de7cf1209a4a91 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 13 Jun 2021 23:40:49 -0500 +Subject: [PATCH 086/124] mmc: sunxi-mmc: Add more registers + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..833092502b --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0087-phy-sun4i-usb-Rework-HCI-PHY-aka.-pmu_unk1-handling.patch @@ -0,0 +1,164 @@ +From 0f84a1ffd2d5e74c17bf50642e137f5f356567df Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + 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 index 0000000000..ab51419dfb --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0088-phy-sun4i-usb-Remove-disc_thresh-where-not-applicabl.patch @@ -0,0 +1,26 @@ +From 7aff4d9c913586d7d4ffe33f88c17d8d4d8302bd Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..28726ab0da --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0089-phy-sun4i-usb-Add-D1-variant.patch @@ -0,0 +1,44 @@ +From b3518c170a136e9c3ec605d89a944203324cee1b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 13 Jun 2021 23:45:25 -0500 +Subject: [PATCH 089/124] phy: sun4i-usb: Add D1 variant + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..3932cf92c3 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0090-pinctrl-sunxi-Support-new-2.5V-I-O-bias-mode.patch @@ -0,0 +1,68 @@ +From fa878b2c67b76258b85b00af41e46ec205720be0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..f70f9d44fc --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0091-pinctrl-sunxi-Adapt-for-D1-register-layout.patch @@ -0,0 +1,51 @@ +From 0d32a8415787d2833c67d4710bba4eb264abd13c Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..dab6833796 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0092-pinctrl-sunxi-Add-support-for-Allwinner-D1-SoC.patch @@ -0,0 +1,886 @@ +From 80a49483f4354770415223ffdcb46ad5f4c3f73a Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#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 index 0000000000..374fd54b4d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0093-pwm-sun8i-v536-document-device-tree-bindings.patch @@ -0,0 +1,46 @@ +From c19eb2d30c0af0add66346252b9f2c742aa02f47 Mon Sep 17 00:00:00 2001 +From: Ban Tao +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 +--- + .../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,-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 index 0000000000..6b593e068a --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0094-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch @@ -0,0 +1,478 @@ +From 042d00b1479f3f1ad314ac2f3f0041dc806b9c5b Mon Sep 17 00:00:00 2001 +From: Ban Tao +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 +--- + 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 ++L: linux-pwm@vger.kernel.org ++S: Maintained ++F: drivers/pwm/pwm-sun8i-v536.c ++ + ALPHA PORT + M: Richard Henderson + M: Ivan Kokshaysky +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 ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 index 0000000000..6bd9773b9d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0095-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch @@ -0,0 +1,50 @@ +From 526751701c01331fb898334df5f491a2b10bc9b1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 index 0000000000..d13398fca5 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0096-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch @@ -0,0 +1,38 @@ +From 75fe896da6096919effe9d00cfa21dbb0c6b367e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..0019d382fe --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0097-remoteproc-sun8i-dsp-Add-a-driver-for-the-DSPs-in-su.patch @@ -0,0 +1,321 @@ +From 52c9bd03a8e25ee0de97ade64ebfd8f0b40eaa2d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 index 0000000000..1409ce529e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0098-rtc-sun6i-Add-support-for-linear-day-storage.patch @@ -0,0 +1,126 @@ +From 6d3665651113e11ec7f8e6e24f471376064d23d2 Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + 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 index 0000000000..cdd3e59af9 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0099-rtc-sun6i-Add-Allwinner-H616-support.patch @@ -0,0 +1,30 @@ +From a502296b25fd6244b196f49409aecdf5050304e5 Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..b5c2478821 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0100-rtc-sun6i-Add-Allwinner-D1-support.patch @@ -0,0 +1,26 @@ +From 121b5566f4642b44b396a3221b6a3cfdfdf46f7d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 31 May 2021 21:51:03 -0500 +Subject: [PATCH 100/124] rtc: sun6i: Add Allwinner D1 support + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..352f325edd --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0101-soc-sunxi-sram-Actually-marked-claimed-regions-as-cl.patch @@ -0,0 +1,26 @@ +From 233da064f08769f760c7ceaa708791ec7687f8c8 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..b1f3e9a186 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0102-soc-sunxi-sram-Map-SRAM-back-to-CPU-on-release.patch @@ -0,0 +1,45 @@ +From 08c2a7e1ffff8ff09f7159e8eeab246a6ee1220b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..3b72b41154 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0103-soc-sunxi-sram-Fix-debugfs-file-leak.patch @@ -0,0 +1,71 @@ +From 16e90c44a87be00a2727d745f8dfe1b29dd93300 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..42213fd6f8 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0104-soc-sunxi-sram-Use-devm_of_platform_populate.patch @@ -0,0 +1,45 @@ +From acd63d88d3461bacd505de88dc66c5ae2f313de2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..c9ea1fec8e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0105-soc-sunxi-sram-Add-support-for-D1-LDOs.patch @@ -0,0 +1,148 @@ +From 16cf89f5a45d680974614ec3847f3609e15de9ab Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 + #include + #include ++#include + + #include + ++#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 index 0000000000..96e679eff4 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0106-soc-sunxi-sram-Fix-debugfs-for-A64-SRAM-C.patch @@ -0,0 +1,28 @@ +From 8278aabd7e8a85327973e770aafdffb7e767f32e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..038aa44c89 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0107-soc-sunxi-sram-Add-D1-DSP-SRAM.patch @@ -0,0 +1,41 @@ +From d7dcb35564295be22f4cffb5cab335d6b75ad49d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..5b36ac5f92 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0108-soc-sunxi-sram-Add-D1-syscon-variant.patch @@ -0,0 +1,28 @@ +From a456c9424e9a3b092e2c8ad6e41b6f41c1a89b4f Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..53b37c5d53 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0109-spi-spi-sun6i-Use-a-struct-for-quirks.patch @@ -0,0 +1,114 @@ +From 548fbde3da6fc700ec040e78a763470f5b844865 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..1f9b98a9e5 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0110-spi-spi-sun6i-Add-Allwinner-R329-support.patch @@ -0,0 +1,151 @@ +From da1ec11ed9fe9d7239506b84d06c48e31238e10e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..50502a62b0 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0111-spi-spi-sun6i-Dual-Quad-RX-Support.patch @@ -0,0 +1,55 @@ +From f45398824024d393f28667e96ad8c4203add0770 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..8f89890275 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0112-thermal-of-Remove-duplicate-null-check.patch @@ -0,0 +1,28 @@ +From 3b46883dc7c1f51aeca6b189121eef5f43560e82 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Wed, 23 Jun 2021 20:25:05 -0500 +Subject: [PATCH 112/124] thermal/of: Remove duplicate null check + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..5ad45750ee --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0113-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch @@ -0,0 +1,25 @@ +From 875adee436d43269aa11d98c0396dc298407975a Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..c128805a8d --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0114-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch @@ -0,0 +1,39 @@ +From 7794f47389db9147af69e4a7aa07902d25547827 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 + + #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 index 0000000000..f22d64471a --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0115-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch @@ -0,0 +1,990 @@ +From bcf8b842b5cfeeccb52acade92c4b0318a9eaf68 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 index 0000000000..226d18c031 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0116-ASoC-sun20i-codec-What-is-this-ramp-thing.patch @@ -0,0 +1,28 @@ +From fa221fe84aced5348277f372b327b4362b2123f8 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 index 0000000000..c811d7eeaa --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0117-Disable-broken-ARCH_SUNXI-drivers.patch @@ -0,0 +1,44 @@ +From 837e54cc6396950ad0ca852aff40a3c7c9e03fe1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 15 Nov 2021 00:48:47 -0600 +Subject: [PATCH 117/124] Disable broken ARCH_SUNXI drivers + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..4e7a4b3de8 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0118-riscv-Add-Allwinner-D1-SoC-support.patch @@ -0,0 +1,52 @@ +From 9e923b083e3c46b02c67a00ea9c973d66fcb5fa2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 16 May 2021 14:17:45 -0500 +Subject: [PATCH 118/124] riscv: Add Allwinner D1 SoC support + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..24a2483f6e --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0119-riscv-Add-Allwinner-D1-SoC-device-tree.patch @@ -0,0 +1,1179 @@ +From df2ef356052fd89dda0d44e374dc423be773a6a1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/ { ++ #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 index 0000000000..cc1a2a91ea --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0120-riscv-Add-D1-Nezha-board-device-tree.patch @@ -0,0 +1,405 @@ +From 5ff65d483cc6aa18f21900a72ab3e78eb2308031 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + 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 ++ ++/dts-v1/; ++ ++#include "sun20i-d1.dtsi" ++ ++#include ++#include ++#include ++#include ++ ++/ { ++ 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 = <®_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 = <®_vcc>; ++ }; ++ ++ reg_vdd_cpu: vdd-cpu { ++ compatible = "pwm-regulator"; ++ pwms = <&pwm 0 50000 0>; ++ pwm-supply = <®_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 = <®_aldo>; ++ hpvcc-supply = <®_hpldo>; ++ vdd33-supply = <®_vcc_3v3>; ++ status = "okay"; ++}; ++ ++&cpu0 { ++ cpu-supply = <®_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 = <®_vcc_3v3>; ++ status = "okay"; ++}; ++ ++&gpio { ++ vcc-pa-supply = <®_vcc_3v3>; ++ vcc-pb-supply = <®_vcc_3v3>; ++ vcc-pc-supply = <®_vcc_3v3>; ++ vcc-pd-supply = <®_vcc_3v3>; ++ vcc-pe-supply = <®_vcc_3v3>; ++ vcc-pf-supply = <®_vcc_3v3>; ++ vcc-pg-supply = <®_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 = ; ++ function = LED_FUNCTION_INDICATOR; ++ }; ++}; ++ ++&lradc { ++ vref-supply = <®_aldo>; ++ wakeup-source; ++ status = "okay"; ++ ++ button-160 { ++ label = "OK"; ++ linux,code = ; ++ 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 = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&mmc1 { ++ bus-width = <4>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_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"; ++}; ++ ++®_aldo { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vdd33-supply = <®_vcc_3v3>; ++}; ++ ++®_hpldo { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ hpldoin-supply = <®_vcc_3v3>; ++}; ++ ++®_ldoa { ++ regulator-always-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ ldo-in-supply = <®_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 = <®_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 = <®_usbvbus>; ++ usb1_vbus-supply = <®_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 index 0000000000..77417d65e1 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0121-misc-changes.patch @@ -0,0 +1,272 @@ +From bbac293092123341e0eaa3905508e2264f6b1cec Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 13 Jun 2021 23:54:42 -0500 +Subject: [PATCH 121/124] misc changes + +Signed-off-by: Samuel Holland +--- + 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 + #include + #include +@@ -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 + #include + #include +@@ -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 index 0000000000..70ba5f1910 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0122-pinctrl-sunxi-sunxi_pinctrl_irq_ack-avoid-build-warn.patch @@ -0,0 +1,47 @@ +From b63fd7efd835bb7a1603ba821c6cb9db14a6fb06 Mon Sep 17 00:00:00 2001 +From: Heinrich Schuchardt +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 +--- + 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 index 0000000000..41071b00ea --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0123-Add-a-defconfig-for-the-Nezha.patch @@ -0,0 +1,256 @@ +From 4423494ac9e059965dfb62d3080d3947a0691770 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 8 Aug 2021 21:27:43 -0500 +Subject: [PATCH 123/124] Add a defconfig for the Nezha + +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..557ca53b44 --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0124-watchdog-sunxi_wdt-Add-support-for-D1.patch @@ -0,0 +1,106 @@ +From 533f0a9a782e90ba8b30aa4deed0146f3133610e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +Reviewed-by: Guenter Roeck +Signed-off-by: Samuel Holland +--- + 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 index 0000000000..6aae5256fb --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0125-dt-bindings-clk-Add-compatibles-for-D1-CCUs.patch @@ -0,0 +1,328 @@ +From aa7c2a299b211120e4fcdc66afe130cd6cda571d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + .../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 ++ */ ++ ++#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 ++ */ ++ ++#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 ++ */ ++ ++#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 ++ */ ++ ++#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 index 0000000000..57621fa90a --- /dev/null +++ b/target/linux/sunxid1/patches-5.15/0126-dt-bindings-rtc-sun6i-Add-H616-R329-and-D1-support.patch @@ -0,0 +1,42 @@ +From 80ee04e4cc1fcdcd46c2a67e841fae1532f2ed69 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +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 +--- + .../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_ */ -- 2.30.2