]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
kernel/starfive: restore files for v6.12
authorZhihao Xu <ngc7331@outlook.com>
Tue, 17 Feb 2026 12:11:40 +0000 (20:11 +0800)
committerZoltan HERPAI <wigyori@uid0.hu>
Tue, 21 Apr 2026 12:49:35 +0000 (14:49 +0200)
This is an automatically generated commit which aids following Kernel patch
history, as git will see the move and copy as a rename thus defeating the
purpose.

For the original discussion see:
https://lists.openwrt.org/pipermail/openwrt-devel/2023-October/041673.html

Signed-off-by: Zhihao Xu <ngc7331@outlook.com>
57 files changed:
target/linux/starfive/config-6.12 [new file with mode: 0644]
target/linux/starfive/patches-6.12/0001-riscv-dts-starfive-Add-full-support-except-VIN-and-V.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0002-clocksource-Add-JH7110-timer-driver.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0003-pwm-opencores-Add-PWM-driver-support.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0004-spi-spl022-Get-and-deassert-reset-in-probe.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0005-i2c-designware-Delete-SMBus-functionalities.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0006-drivers-mtd-gigadevice-add-gd25lq256d-32M-flash-supp.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0007-driver-mailbox-Add-mailbox-driver.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0008-driver-rtc-Add-StarFive-JH7110-rtc-driver.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0009-uart-8250-Add-dw-auto-flow-ctrl-support.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0010-uart-8250-add-reset-operation-in-runtime-PM.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0011-CAN-starfive-Add-CAN-engine-support.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0012-ipms-CAN-Solve-CAN-packet-leakage-problem.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0013-drivers-nvme-Add-precheck-and-delay-for-CQE-pending-.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0014-riscv-Optimize-memcpy-with-aligned-version.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0015-riscv-purgatory-Change-memcpy-to-the-aligned-version.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0016-riscv-Fix-__memcpy_aligned-alias.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0017-plic-irq-Set-IRQCHIP_EOI_THREADED-in-PREEMPT_RT-case.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0018-driver-e24-add-e24-driver.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0019-net-stmmac-Extend-waiting-time-of-dma-reset.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0020-spi-pl022-starfive-Add-platform-bus-register-to-adap.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0021-spi-pl022-starfive-Avoid-power-device-error-when-CON.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0022-spi-pl022-starfive-fix-the-problem-of-spi-overlay-re.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0023-spi-pl022-starfive-Enable-spi-to-be-compiled-into-mo.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0024-spi-pl022-Prompt-warning-when-frequency-does-not-sup.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0025-spi-pl022-Fix-spi-overlay-falut.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0026-RISC-V-Added-generic-pmu-events-mapfile.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0027-RISC-V-Create-unique-identification-for-SoC-PMU.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0028-RISC-V-Support-CPUID-for-risc-v-in-perf.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0029-dmaengine-dw-axi-dmac-Drop-unused-print-message.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/0030-riscv-dts-starfive-vf2-add-reserved-memory-for-E24.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1000-riscv-dts-starfive-Add-JH7100-high-speed-UARTs.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1001-riscv-dts-starfive-Enable-Bluetooth-on-JH7100-boards.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1003-drivers-tty-serial-8250-update-driver-for-JH7100.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1004-power-reset-tps65086-Allow-building-as-a-module.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1005-riscv-dts-starfive-Add-StarFive-JH7100-audio-clock-n.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1006-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1007-reset-starfive-Add-JH7100-audio-reset-driver.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1008-riscv-dts-starfive-Add-StarFive-JH7100-audio-reset-n.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1009-clk-starfive-jh7100-Keep-more-clocks-alive.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1010-pinctrl-starfive-Reset-pinmux-settings.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1011-net-stmmac-use-GFP_DMA32.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1012-dt-bindings-dma-dw-axi-dmac-Increase-DMA-channel-lim.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1013-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1014-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1015-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1016-usb-cdns3-starfive-Simplify-mode-init.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1017-usb-cdns3-starfive-Don-t-store-device-backpointer.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1018-usb-cdns3-starfive-Add-StarFive-JH7100-support.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1019-riscv-dts-starfive-Add-JH7100-USB-node.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1020-usb-cdns3-starfive-Initialize-JH7100-host-mode.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1021-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1022-riscv-dts-starfive-vf1-add-LED-aliases-and-stop-hear.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1023-riscv-dts-starfive-visionfive2-add-SYSLED-support.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1024-riscv-dts-starfive-visionfive2-add-LED-aliases-and-s.patch [new file with mode: 0644]
target/linux/starfive/patches-6.12/1025-riscv-dts-starfive-visionfive2-add-dma-pool-entry.patch [new file with mode: 0644]

diff --git a/target/linux/starfive/config-6.12 b/target/linux/starfive/config-6.12
new file mode 100644 (file)
index 0000000..7bb86ec
--- /dev/null
@@ -0,0 +1,641 @@
+CONFIG_64BIT=y
+# CONFIG_ACPI is not set
+CONFIG_AMBA_PL08X=y
+# CONFIG_ARCH_CANAAN is not set
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_DEFAULT_COHERENT=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
+# CONFIG_ARCH_MICROCHIP is not set
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=24
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+# CONFIG_ARCH_RV32I is not set
+CONFIG_ARCH_RV64I=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SIFIVE=y
+# CONFIG_ARCH_SOPHGO is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_STACKWALK=y
+CONFIG_ARCH_STARFIVE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARCH_THEAD is not set
+CONFIG_ARCH_WANTS_NO_INSTR=y
+CONFIG_ARCH_WANTS_THP_SWAP=y
+CONFIG_ARM_AMBA=y
+# CONFIG_ARM_MHU_V2 is not set
+CONFIG_ASN1=y
+CONFIG_AUXILIARY_BUS=y
+# CONFIG_AX45MP_L2_CACHE is not set
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_BLK_PM=y
+CONFIG_BUFFER_HEAD=y
+# CONFIG_BUILTIN_DTB is not set
+CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC=y
+CONFIG_CLK_SIFIVE=y
+CONFIG_CLK_SIFIVE_PRCI=y
+CONFIG_CLK_STARFIVE_JH7100=y
+CONFIG_CLK_STARFIVE_JH7100_AUDIO=y
+CONFIG_CLK_STARFIVE_JH7110_AON=y
+CONFIG_CLK_STARFIVE_JH7110_ISP=y
+CONFIG_CLK_STARFIVE_JH7110_PLL=y
+CONFIG_CLK_STARFIVE_JH7110_STG=y
+CONFIG_CLK_STARFIVE_JH7110_SYS=y
+CONFIG_CLK_STARFIVE_JH7110_VOUT=y
+CONFIG_CLK_STARFIVE_JH71X0=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CLZ_TAB=y
+CONFIG_CMODEL_MEDANY=y
+# CONFIG_CMODEL_MEDLOW is not set
+CONFIG_COMMON_CLK=y
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+# CONFIG_COMPAT_32BIT_TIME is not set
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONTEXT_TRACKING=y
+CONFIG_CONTEXT_TRACKING_IDLE=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_CPUFREQ_DT_PLATDEV=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
+CONFIG_CPU_MITIGATIONS=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CRC16=y
+CONFIG_CRC7=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRYPTO_BLAKE2B=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_DEV_JH7110 is not set
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_ECC=y
+CONFIG_CRYPTO_ECDH=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS=64
+CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE=32
+CONFIG_CRYPTO_JITTERENTROPY_OSR=1
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_LIB_GF128MUL=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
+CONFIG_CRYPTO_LIB_SHA256=y
+CONFIG_CRYPTO_LIB_UTILS=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA3=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_SM3=y
+CONFIG_CRYPTO_SM3_GENERIC=y
+CONFIG_CRYPTO_USER=y
+CONFIG_CRYPTO_USER_API=y
+CONFIG_CRYPTO_USER_API_AEAD=y
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_RNG=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+CONFIG_CRYPTO_XXHASH=y
+CONFIG_CRYPTO_ZSTD=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DEBUG_RODATA_TEST=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_WX=y
+CONFIG_DECOMPRESS_GZIP=y
+# CONFIG_DEVFREQ_GOV_PASSIVE is not set
+# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
+# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
+# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set
+# CONFIG_DEVFREQ_GOV_USERSPACE is not set
+# CONFIG_DEVFREQ_THERMAL is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMADEVICES=y
+CONFIG_DMADEVICES_DEBUG=y
+CONFIG_DMADEVICES_VDEBUG=y
+CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_GLOBAL_POOL=y
+CONFIG_DMA_NEED_SYNC=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DMI=y
+CONFIG_DMIID=y
+# CONFIG_DMI_SYSFS is not set
+CONFIG_DTC=y
+CONFIG_DT_IDLE_GENPD=y
+CONFIG_DT_IDLE_STATES=y
+CONFIG_DWMAC_DWC_QOS_ETH=y
+# CONFIG_DWMAC_GENERIC is not set
+CONFIG_DWMAC_STARFIVE=y
+CONFIG_DW_AXI_DMAC=y
+CONFIG_E24=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EEPROM_AT24=y
+CONFIG_EFI=y
+CONFIG_EFIVAR_FS=y
+# CONFIG_EFI_BOOTLOADER_CONTROL is not set
+# CONFIG_EFI_CAPSULE_LOADER is not set
+# CONFIG_EFI_COCO_SECRET is not set
+# CONFIG_EFI_DISABLE_PCI_DMA is not set
+CONFIG_EFI_DISABLE_RUNTIME=y
+CONFIG_EFI_EARLYCON=y
+CONFIG_EFI_ESRT=y
+CONFIG_EFI_GENERIC_STUB=y
+CONFIG_EFI_PARAMS_FROM_FDT=y
+CONFIG_EFI_RUNTIME_WRAPPERS=y
+CONFIG_EFI_STUB=y
+# CONFIG_EFI_TEST is not set
+# CONFIG_EFI_ZBOOT is not set
+# CONFIG_ERRATA_ANDES is not set
+CONFIG_ERRATA_SIFIVE=y
+CONFIG_ERRATA_SIFIVE_CIP_1200=y
+CONFIG_ERRATA_SIFIVE_CIP_453=y
+CONFIG_ERRATA_STARFIVE_JH7100=y
+# CONFIG_ERRATA_THEAD is not set
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_EXT4_FS=y
+CONFIG_EXTCON=y
+CONFIG_FAILOVER=y
+CONFIG_FANOTIFY=y
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-15"
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_FAT_FS=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_AUTOSELECT=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_FPU=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FS_IOMAP=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FUNCTION_ALIGNMENT=0
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CPU_DEVICES=y
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_ENTRY=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IOREMAP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_IPI_MUX=y
+CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
+CONFIG_GENERIC_IRQ_MIGRATION=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_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PHY_MIPI_DPHY=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_GPIOLIB_FASTPATH_LIMIT=128
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_TPS65086=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HOTPLUG_CORE_SYNC=y
+CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING=y
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_RISCV_SBI=y
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_JH7110=y
+CONFIG_HW_RANDOM_STARFIVE_VIC=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_DESIGNWARE_CORE=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_IPMS_CAN is not set
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_STACKS=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_JH71XX_PMU=y
+CONFIG_JUMP_LABEL=y
+CONFIG_KCMP=y
+# CONFIG_KERNEL_UNCOMPRESSED is not set
+CONFIG_LEGACY_DIRECT_IO=y
+CONFIG_LIBFDT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LSM=""
+CONFIG_MAILBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_MARVELL_PHY=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+CONFIG_MEMTEST=y
+CONFIG_MFD_AXP20X=y
+CONFIG_MFD_AXP20X_I2C=y
+CONFIG_MFD_CORE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TPS65086=y
+CONFIG_MICREL_PHY=y
+CONFIG_MICROCHIP_PHY=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DW=y
+# CONFIG_MMC_DW_BLUEFIELD is not set
+# CONFIG_MMC_DW_EXYNOS is not set
+# CONFIG_MMC_DW_HI3798CV200 is not set
+# CONFIG_MMC_DW_HI3798MV200 is not set
+# CONFIG_MMC_DW_K3 is not set
+# CONFIG_MMC_DW_PCI is not set
+CONFIG_MMC_DW_PLTFM=y
+CONFIG_MMC_DW_STARFIVE=y
+CONFIG_MMIOWB=y
+CONFIG_MMU_LAZY_TLB_REFCOUNT=y
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MOTORCOMM_PHY=y
+CONFIG_MPILIB=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NAMESPACES=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_DEVMEM=y
+CONFIG_NET_EGRESS=y
+CONFIG_NET_FAILOVER=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_INGRESS=y
+CONFIG_NET_NS=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_XGRESS=y
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_DEFAULT="iso8859-15"
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NONPORTABLE=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=8
+# CONFIG_NSM is not set
+CONFIG_NVMEM=y
+CONFIG_NVMEM_LAYOUTS=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_DYNAMIC=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_OVERLAY=y
+CONFIG_OF_RESOLVE=y
+CONFIG_OID_REGISTRY=y
+CONFIG_OVERLAY_FS_INDEX=y
+CONFIG_OVERLAY_FS_METACOPY=y
+CONFIG_OVERLAY_FS_REDIRECT_DIR=y
+CONFIG_PADATA=y
+CONFIG_PAGE_EXTENSION=y
+CONFIG_PAGE_OFFSET=0xff60000000000000
+CONFIG_PAGE_POOL=y
+CONFIG_PAGE_REPORTING=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+CONFIG_PCI=y
+CONFIG_PCIE_CADENCE=y
+CONFIG_PCIE_CADENCE_HOST=y
+CONFIG_PCIE_CADENCE_PLAT=y
+CONFIG_PCIE_CADENCE_PLAT_HOST=y
+# CONFIG_PCIE_FU740 is not set
+CONFIG_PCIE_PLDA_HOST=y
+CONFIG_PCIE_STARFIVE_HOST=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_MSI=y
+CONFIG_PCS_XPCS=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PER_VMA_LOCK=y
+CONFIG_PGTABLE_HAS_HUGE_LEAVES=y
+CONFIG_PGTABLE_LEVELS=5
+CONFIG_PHYLIB=y
+CONFIG_PHYLIB_LEDS=y
+CONFIG_PHYLINK=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PHYS_RAM_BASE_FIXED is not set
+CONFIG_PHY_STARFIVE_JH7110_DPHY_RX=y
+# CONFIG_PHY_STARFIVE_JH7110_DPHY_TX is not set
+CONFIG_PHY_STARFIVE_JH7110_PCIE=y
+CONFIG_PHY_STARFIVE_JH7110_USB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_STARFIVE_JH7100=y
+CONFIG_PINCTRL_STARFIVE_JH7110=y
+CONFIG_PINCTRL_STARFIVE_JH7110_AON=y
+CONFIG_PINCTRL_STARFIVE_JH7110_SYS=y
+CONFIG_PM=y
+CONFIG_PM_ADVANCED_DEBUG=y
+CONFIG_PM_CLK=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_DEVFREQ=y
+# CONFIG_PM_DEVFREQ_EVENT is not set
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_OPP=y
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_POWER_RESET_TPS65086 is not set
+CONFIG_PPS=y
+CONFIG_PREEMPT_COUNT=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_CHILDREN=y
+CONFIG_PROC_KCORE=y
+CONFIG_PTDUMP_CORE=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_PWM=y
+CONFIG_PWM_OCORES=y
+# CONFIG_PWM_SIFIVE is not set
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RATIONAL=y
+CONFIG_RCU_EQS_DEBUG=y
+CONFIG_RD_GZIP=y
+CONFIG_REALTEK_PHY=y
+# CONFIG_REALTEK_PHY_HWMON is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_AXP20X=y
+CONFIG_REGULATOR_TPS65086=y
+# CONFIG_RESET_ATTACK_MITIGATION is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESET_SIMPLE=y
+CONFIG_RESET_STARFIVE_JH7100=y
+CONFIG_RESET_STARFIVE_JH7100_AUDIO=m
+CONFIG_RESET_STARFIVE_JH7110=y
+CONFIG_RESET_STARFIVE_JH71X0=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RISCV=y
+CONFIG_RISCV_ALTERNATIVE=y
+CONFIG_RISCV_APLIC=y
+CONFIG_RISCV_APLIC_MSI=y
+CONFIG_RISCV_BOOT_SPINWAIT=y
+CONFIG_RISCV_DMA_NONCOHERENT=y
+# CONFIG_RISCV_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_RISCV_EMULATED_UNALIGNED_ACCESS is not set
+CONFIG_RISCV_IMSIC=y
+CONFIG_RISCV_IMSIC_PCI=y
+CONFIG_RISCV_INTC=y
+CONFIG_RISCV_ISA_C=y
+CONFIG_RISCV_ISA_FALLBACK=y
+CONFIG_RISCV_ISA_SVNAPOT=y
+# CONFIG_RISCV_ISA_SVPBMT is not set
+# CONFIG_RISCV_ISA_V is not set
+# CONFIG_RISCV_ISA_VENDOR_EXT_ANDES is not set
+CONFIG_RISCV_ISA_ZAWRS=y
+CONFIG_RISCV_ISA_ZBA=y
+CONFIG_RISCV_ISA_ZBB=y
+CONFIG_RISCV_ISA_ZBC=y
+# CONFIG_RISCV_ISA_ZICBOM is not set
+CONFIG_RISCV_ISA_ZICBOZ=y
+CONFIG_RISCV_MISALIGNED=y
+CONFIG_RISCV_NONSTANDARD_CACHE_OPS=y
+CONFIG_RISCV_PMU=y
+CONFIG_RISCV_PMU_LEGACY=y
+CONFIG_RISCV_PMU_SBI=y
+CONFIG_RISCV_PROBE_UNALIGNED_ACCESS=y
+CONFIG_RISCV_SBI=y
+CONFIG_RISCV_SBI_CPUIDLE=y
+CONFIG_RISCV_SBI_V01=y
+# CONFIG_RISCV_SLOW_UNALIGNED_ACCESS is not set
+CONFIG_RISCV_TIMER=y
+CONFIG_RISCV_USE_LINKER_RELAXATION=y
+CONFIG_RPMSG=y
+CONFIG_RPMSG_CHAR=y
+# CONFIG_RPMSG_CTRL is not set
+CONFIG_RPMSG_NS=y
+# CONFIG_RPMSG_TTY is not set
+CONFIG_RPMSG_VIRTIO=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_HYM8563=y
+CONFIG_RTC_DRV_STARFIVE=y
+CONFIG_RTC_I2C_AND_SPI=y
+# CONFIG_RUNTIME_KERNEL_TESTING_MENU is not set
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_SCSI=y
+CONFIG_SCSI_COMMON=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_SENSORS_SFCTEMP=y
+# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_DWLIB=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_RUNTIME_UARTS=6
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_SIFIVE=y
+CONFIG_SERIAL_SIFIVE_CONSOLE=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SG_POOL=y
+CONFIG_SIFIVE_CCACHE=y
+CONFIG_SIFIVE_PLIC=y
+CONFIG_SMP=y
+# CONFIG_SND_SOC_STARFIVE is not set
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+CONFIG_SOC_STARFIVE=y
+CONFIG_SOFTIRQ_ON_OWN_STACK=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_SOUND=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_CADENCE_QUADSPI=y
+CONFIG_SPI_DYNAMIC=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_PL022=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPLIT_PMD_PTLOCKS=y
+CONFIG_SPLIT_PTE_PTLOCKS=y
+CONFIG_STARFIVE_JH7110_TIMER=y
+CONFIG_STARFIVE_JH8100_INTC=y
+CONFIG_STARFIVE_MBOX=y
+# CONFIG_STARFIVE_MBOX_TEST is not set
+CONFIG_STARFIVE_STARLINK_CACHE=y
+# CONFIG_STARFIVE_STARLINK_PMU is not set
+CONFIG_STARFIVE_WATCHDOG=y
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+CONFIG_STMMAC_SELFTESTS=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SYNC_FILE=y
+CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+# CONFIG_SYSFB_SIMPLEFB is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_THREAD_SIZE_ORDER=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TOOLCHAIN_HAS_V=y
+CONFIG_TOOLCHAIN_HAS_VECTOR_CRYPTO=y
+CONFIG_TOOLCHAIN_HAS_ZBB=y
+CONFIG_TOOLCHAIN_HAS_ZBC=y
+CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_TTY_PRINTK=y
+CONFIG_TTY_PRINTK_LEVEL=6
+CONFIG_TUNE_GENERIC=y
+CONFIG_UCS2_STRING=y
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USB=y
+CONFIG_USB_CDNS3=y
+CONFIG_USB_CDNS3_GADGET=y
+CONFIG_USB_CDNS3_HOST=y
+CONFIG_USB_CDNS3_STARFIVE=y
+CONFIG_USB_CDNS_HOST=y
+CONFIG_USB_CDNS_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_CONFIGFS=y
+# CONFIG_USB_CONFIGFS_ACM is not set
+# CONFIG_USB_CONFIGFS_ECM is not set
+# CONFIG_USB_CONFIGFS_ECM_SUBSET is not set
+# CONFIG_USB_CONFIGFS_EEM is not set
+CONFIG_USB_CONFIGFS_F_FS=y
+# CONFIG_USB_CONFIGFS_F_HID is not set
+# CONFIG_USB_CONFIGFS_F_LB_SS is not set
+# CONFIG_USB_CONFIGFS_F_MIDI is not set
+# CONFIG_USB_CONFIGFS_F_MIDI2 is not set
+# CONFIG_USB_CONFIGFS_F_PRINTER is not set
+# CONFIG_USB_CONFIGFS_F_UAC1 is not set
+# CONFIG_USB_CONFIGFS_F_UAC1_LEGACY is not set
+# CONFIG_USB_CONFIGFS_F_UAC2 is not set
+# CONFIG_USB_CONFIGFS_F_UVC is not set
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+# CONFIG_USB_CONFIGFS_NCM is not set
+# CONFIG_USB_CONFIGFS_OBEX is not set
+# CONFIG_USB_CONFIGFS_RNDIS is not set
+# CONFIG_USB_CONFIGFS_SERIAL is not set
+CONFIG_USB_F_FS=y
+CONFIG_USB_F_MASS_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_LIBCOMPOSITE=y
+CONFIG_USB_PCI=y
+CONFIG_USB_ROLE_SWITCH=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=y
+CONFIG_USELIB=y
+CONFIG_USER_NS=y
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_VFAT_FS=y
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_ANCHOR=y
+# CONFIG_VIRTIO_BLK is not set
+# CONFIG_VIRTIO_DEBUG is not set
+# CONFIG_VIRTIO_NET is not set
+CONFIG_VMAP_STACK=y
+CONFIG_VMCORE_INFO=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_WERROR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_XARRAY_MULTI=y
+CONFIG_XPS=y
+CONFIG_XXHASH=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA32=y
+CONFIG_ZSTD_COMMON=y
+CONFIG_ZSTD_COMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y
diff --git a/target/linux/starfive/patches-6.12/0001-riscv-dts-starfive-Add-full-support-except-VIN-and-V.patch b/target/linux/starfive/patches-6.12/0001-riscv-dts-starfive-Add-full-support-except-VIN-and-V.patch
new file mode 100644 (file)
index 0000000..78b6a10
--- /dev/null
@@ -0,0 +1,176 @@
+From 5605ebdd7f7033da8f1bcb77cb180ef16235d5c8 Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Tue, 11 Apr 2023 16:31:15 +0800
+Subject: [PATCH 01/55] riscv: dts: starfive: Add full support (except VIN and
+ VOUT) for JH7110 and VisionFive 2 board
+
+Merge all StarFive dts patches together except VIN and VOUT.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ .../boot/dts/starfive/jh7110-common.dtsi      |   2 +
+ .../jh7110-starfive-visionfive-2.dtsi         | 100 ++++++++++++++++++
+ arch/riscv/boot/dts/starfive/jh7110.dtsi      |  21 ++++
+ 3 files changed, 123 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
+@@ -18,6 +18,8 @@
+               i2c6 = &i2c6;
+               mmc0 = &mmc0;
+               mmc1 = &mmc1;
++              pcie0 = &pcie0;
++              pcie1 = &pcie1;
+               serial0 = &uart0;
+       };
+--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+@@ -29,6 +29,24 @@
+       };
+ };
++&i2srx {
++      pinctrl-names = "default";
++      pinctrl-0 = <&i2srx_pins>;
++      status = "okay";
++};
++
++&i2stx0 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&mclk_ext_pins>;
++      status = "okay";
++};
++
++&i2stx1 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&i2stx1_pins>;
++      status = "okay";
++};
++
+ &mmc0 {
+       non-removable;
+ };
+@@ -40,3 +58,85 @@
+ &pcie1 {
+       status = "okay";
+ };
++
++&sysgpio {
++      i2srx_pins: i2srx-0 {
++              clk-sd-pins {
++                      pinmux = <GPIOMUX(38, GPOUT_LOW,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_I2SRX_BCLK)>,
++                               <GPIOMUX(63, GPOUT_LOW,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_I2SRX_LRCK)>,
++                               <GPIOMUX(38, GPOUT_LOW,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_I2STX1_BCLK)>,
++                               <GPIOMUX(63, GPOUT_LOW,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_I2STX1_LRCK)>,
++                               <GPIOMUX(61, GPOUT_LOW,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_I2SRX_SDIN0)>;
++                      input-enable;
++              };
++      };
++
++      i2stx1_pins: i2stx1-0 {
++              sd-pins {
++                      pinmux = <GPIOMUX(44, GPOUT_SYS_I2STX1_SDO0,
++                                            GPOEN_ENABLE,
++                                            GPI_NONE)>;
++                      bias-disable;
++                      input-disable;
++              };
++      };
++
++      mclk_ext_pins: mclk-ext-0 {
++              mclk-ext-pins {
++                      pinmux = <GPIOMUX(4, GPOUT_LOW,
++                                           GPOEN_DISABLE,
++                                           GPI_SYS_MCLK_EXT)>;
++                      input-enable;
++              };
++      };
++
++      tdm_pins: tdm-0 {
++              tx-pins {
++                      pinmux = <GPIOMUX(44, GPOUT_SYS_TDM_TXD,
++                                            GPOEN_ENABLE,
++                                            GPI_NONE)>;
++                      bias-pull-up;
++                      drive-strength = <2>;
++                      input-disable;
++                      input-schmitt-disable;
++                      slew-rate = <0>;
++              };
++
++              rx-pins {
++                      pinmux = <GPIOMUX(61, GPOUT_HIGH,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_TDM_RXD)>;
++                      input-enable;
++              };
++
++              sync-pins {
++                      pinmux = <GPIOMUX(63, GPOUT_HIGH,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_TDM_SYNC)>;
++                      input-enable;
++              };
++
++              pcmclk-pins {
++                      pinmux = <GPIOMUX(38, GPOUT_HIGH,
++                                            GPOEN_DISABLE,
++                                            GPI_SYS_TDM_CLK)>;
++                      input-enable;
++              };
++      };
++};
++
++&tdm {
++      pinctrl-names = "default";
++      pinctrl-0 = <&tdm_pins>;
++      status = "okay";
++};
+--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
+@@ -259,6 +259,7 @@
+               clock-output-names = "dvp_clk";
+               #clock-cells = <0>;
+       };
++
+       gmac0_rgmii_rxin: gmac0-rgmii-rxin-clock {
+               compatible = "fixed-clock";
+               clock-output-names = "gmac0_rgmii_rxin";
+@@ -919,6 +920,26 @@
+                       #gpio-cells = <2>;
+               };
++              timer@13050000 {
++                      compatible = "starfive,jh7110-timer";
++                      reg = <0x0 0x13050000 0x0 0x10000>;
++                      interrupts = <69>, <70>, <71>, <72>;
++                      clocks = <&syscrg JH7110_SYSCLK_TIMER_APB>,
++                               <&syscrg JH7110_SYSCLK_TIMER0>,
++                               <&syscrg JH7110_SYSCLK_TIMER1>,
++                               <&syscrg JH7110_SYSCLK_TIMER2>,
++                               <&syscrg JH7110_SYSCLK_TIMER3>;
++                      clock-names = "apb", "ch0", "ch1",
++                                    "ch2", "ch3";
++                      resets = <&syscrg JH7110_SYSRST_TIMER_APB>,
++                               <&syscrg JH7110_SYSRST_TIMER0>,
++                               <&syscrg JH7110_SYSRST_TIMER1>,
++                               <&syscrg JH7110_SYSRST_TIMER2>,
++                               <&syscrg JH7110_SYSRST_TIMER3>;
++                      reset-names = "apb", "ch0", "ch1",
++                                    "ch2", "ch3";
++              };
++
+               watchdog@13070000 {
+                       compatible = "starfive,jh7110-wdt";
+                       reg = <0x0 0x13070000 0x0 0x10000>;
diff --git a/target/linux/starfive/patches-6.12/0002-clocksource-Add-JH7110-timer-driver.patch b/target/linux/starfive/patches-6.12/0002-clocksource-Add-JH7110-timer-driver.patch
new file mode 100644 (file)
index 0000000..1b96bd3
--- /dev/null
@@ -0,0 +1,428 @@
+From 9e8b51600e4b0ea28c599303b87f6b1b8585eee4 Mon Sep 17 00:00:00 2001
+From: Xingyu Wu <xingyu.wu@starfivetech.com>
+Date: Thu, 19 Oct 2023 13:35:00 +0800
+Subject: [PATCH 02/55] clocksource: Add JH7110 timer driver
+
+Add timer driver for the StarFive JH7110 SoC.
+
+Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
+---
+ drivers/clocksource/Kconfig        |  11 +
+ drivers/clocksource/Makefile       |   1 +
+ drivers/clocksource/timer-jh7110.c | 380 +++++++++++++++++++++++++++++
+ 3 files changed, 392 insertions(+)
+ create mode 100644 drivers/clocksource/timer-jh7110.c
+
+--- a/drivers/clocksource/Kconfig
++++ b/drivers/clocksource/Kconfig
+@@ -653,6 +653,17 @@ config RISCV_TIMER
+         is accessed via both the SBI and the rdcycle instruction.  This is
+         required for all RISC-V systems.
++config STARFIVE_JH7110_TIMER
++      bool "Timer for the STARFIVE JH7110 SoC"
++      depends on ARCH_STARFIVE || COMPILE_TEST
++      select TIMER_OF
++      select CLKSRC_MMIO
++      default ARCH_STARFIVE
++      help
++        This enables the timer for StarFive JH7110 SoC. On RISC-V platform,
++        the system has started RISCV_TIMER, but you can also use this timer
++        which can provide four channels to do a lot more things on JH7110 SoC.
++
+ config CLINT_TIMER
+       bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST
+       depends on GENERIC_SCHED_CLOCK && RISCV
+--- a/drivers/clocksource/Makefile
++++ b/drivers/clocksource/Makefile
+@@ -81,6 +81,7 @@ obj-$(CONFIG_INGENIC_TIMER)          += ingenic-
+ obj-$(CONFIG_CLKSRC_ST_LPC)           += clksrc_st_lpc.o
+ obj-$(CONFIG_X86_NUMACHIP)            += numachip.o
+ obj-$(CONFIG_RISCV_TIMER)             += timer-riscv.o
++obj-$(CONFIG_STARFIVE_JH7110_TIMER)   += timer-jh7110.o
+ obj-$(CONFIG_CLINT_TIMER)             += timer-clint.o
+ obj-$(CONFIG_CSKY_MP_TIMER)           += timer-mp-csky.o
+ obj-$(CONFIG_GX6605S_TIMER)           += timer-gx6605s.o
+--- /dev/null
++++ b/drivers/clocksource/timer-jh7110.c
+@@ -0,0 +1,380 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Starfive JH7110 Timer driver
++ *
++ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
++ *
++ * Author:
++ * Xingyu Wu <xingyu.wu@starfivetech.com>
++ * Samin Guo <samin.guo@starfivetech.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/sched_clock.h>
++
++/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */
++#define JH7110_TIMER_CH_LEN           0x40
++#define JH7110_TIMER_CH_BASE(x)               ((x) * JH7110_TIMER_CH_LEN)
++#define JH7110_TIMER_CH_MAX           4
++
++#define JH7110_CLOCK_SOURCE_RATING    200
++#define JH7110_VALID_BITS             32
++#define JH7110_DELAY_US                       0
++#define JH7110_TIMEOUT_US             10000
++#define JH7110_CLOCKEVENT_RATING      300
++#define JH7110_TIMER_MAX_TICKS                0xffffffff
++#define JH7110_TIMER_MIN_TICKS                0xf
++#define JH7110_TIMER_RELOAD_VALUE     0
++
++#define JH7110_TIMER_INT_STATUS               0x00 /* RO[0:4]: Interrupt Status for channel0~4 */
++#define JH7110_TIMER_CTL              0x04 /* RW[0]: 0-continuous run, 1-single run */
++#define JH7110_TIMER_LOAD             0x08 /* RW: load value to counter */
++#define JH7110_TIMER_ENABLE           0x10 /* RW[0]: timer enable register */
++#define JH7110_TIMER_RELOAD           0x14 /* RW: write 1 or 0 both reload counter */
++#define JH7110_TIMER_VALUE            0x18 /* RO: timer value register */
++#define JH7110_TIMER_INT_CLR          0x20 /* RW: timer interrupt clear register */
++#define JH7110_TIMER_INT_MASK         0x24 /* RW[0]: timer interrupt mask register */
++
++#define JH7110_TIMER_INT_CLR_ENA      BIT(0)
++#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1)
++
++struct jh7110_clkevt {
++      struct clock_event_device evt;
++      struct clocksource cs;
++      bool cs_is_valid;
++      struct clk *clk;
++      struct reset_control *rst;
++      u32 rate;
++      u32 reload_val;
++      void __iomem *base;
++      char name[sizeof("jh7110-timer.chX")];
++};
++
++struct jh7110_timer_priv {
++      struct clk *pclk;
++      struct reset_control *prst;
++      struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX];
++};
++
++/* 0:continuous-run mode, 1:single-run mode */
++enum jh7110_timer_mode {
++      JH7110_TIMER_MODE_CONTIN,
++      JH7110_TIMER_MODE_SINGLE,
++};
++
++/* Interrupt Mask, 0:Unmask, 1:Mask */
++enum jh7110_timer_int_mask {
++      JH7110_TIMER_INT_ENA,
++      JH7110_TIMER_INT_DIS,
++};
++
++enum jh7110_timer_enable {
++      JH7110_TIMER_DIS,
++      JH7110_TIMER_ENA,
++};
++
++static inline struct jh7110_clkevt *to_jh7110_clkevt(struct clock_event_device *evt)
++{
++      return container_of(evt, struct jh7110_clkevt, evt);
++}
++
++/*
++ * BIT(0): Read value represent channel int status.
++ * Write 1 to this bit to clear interrupt. Write 0 has no effects.
++ * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written.
++ */
++static inline int jh7110_timer_int_clear(struct jh7110_clkevt *clkevt)
++{
++      u32 value;
++      int ret;
++
++      /* Waiting interrupt can be cleared */
++      ret = readl_poll_timeout_atomic(clkevt->base + JH7110_TIMER_INT_CLR, value,
++                                      !(value & JH7110_TIMER_INT_CLR_AVA_MASK),
++                                      JH7110_DELAY_US, JH7110_TIMEOUT_US);
++      if (!ret)
++              writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + JH7110_TIMER_INT_CLR);
++
++      return ret;
++}
++
++static int jh7110_timer_start(struct jh7110_clkevt *clkevt)
++{
++      int ret;
++
++      /* Disable and clear interrupt first */
++      writel(JH7110_TIMER_INT_DIS, clkevt->base + JH7110_TIMER_INT_MASK);
++      ret = jh7110_timer_int_clear(clkevt);
++      if (ret)
++              return ret;
++
++      writel(JH7110_TIMER_INT_ENA, clkevt->base + JH7110_TIMER_INT_MASK);
++      writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE);
++
++      return 0;
++}
++
++static int jh7110_timer_shutdown(struct clock_event_device *evt)
++{
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++
++      writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE);
++      return jh7110_timer_int_clear(clkevt);
++}
++
++static void jh7110_timer_suspend(struct clock_event_device *evt)
++{
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++
++      clkevt->reload_val = readl(clkevt->base + JH7110_TIMER_LOAD);
++      jh7110_timer_shutdown(evt);
++}
++
++static void jh7110_timer_resume(struct clock_event_device *evt)
++{
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++
++      writel(clkevt->reload_val, clkevt->base + JH7110_TIMER_LOAD);
++      writel(JH7110_TIMER_RELOAD_VALUE, clkevt->base + JH7110_TIMER_RELOAD);
++      jh7110_timer_start(clkevt);
++}
++
++static int jh7110_timer_tick_resume(struct clock_event_device *evt)
++{
++      jh7110_timer_resume(evt);
++
++      return 0;
++}
++
++/* IRQ handler for the timer */
++static irqreturn_t jh7110_timer_interrupt(int irq, void *priv)
++{
++      struct clock_event_device *evt = (struct clock_event_device *)priv;
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++
++      if (jh7110_timer_int_clear(clkevt))
++              return IRQ_NONE;
++
++      if (evt->event_handler)
++              evt->event_handler(evt);
++
++      return IRQ_HANDLED;
++}
++
++static int jh7110_timer_set_periodic(struct clock_event_device *evt)
++{
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++      u32 periodic = DIV_ROUND_CLOSEST(clkevt->rate, HZ);
++
++      writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL);
++      writel(periodic, clkevt->base + JH7110_TIMER_LOAD);
++
++      return jh7110_timer_start(clkevt);
++}
++
++static int jh7110_timer_set_oneshot(struct clock_event_device *evt)
++{
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++
++      writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL);
++      writel(JH7110_TIMER_MAX_TICKS, clkevt->base + JH7110_TIMER_LOAD);
++
++      return jh7110_timer_start(clkevt);
++}
++
++static int jh7110_timer_set_next_event(unsigned long next,
++                                     struct clock_event_device *evt)
++{
++      struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
++
++      writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL);
++      writel(next, clkevt->base + JH7110_TIMER_LOAD);
++
++      return jh7110_timer_start(clkevt);
++}
++
++static void jh7110_set_clockevent(struct clock_event_device *evt)
++{
++      evt->features = CLOCK_EVT_FEAT_PERIODIC |
++                      CLOCK_EVT_FEAT_ONESHOT |
++                      CLOCK_EVT_FEAT_DYNIRQ;
++      evt->set_state_shutdown = jh7110_timer_shutdown;
++      evt->set_state_periodic = jh7110_timer_set_periodic;
++      evt->set_state_oneshot = jh7110_timer_set_oneshot;
++      evt->set_state_oneshot_stopped = jh7110_timer_shutdown;
++      evt->tick_resume = jh7110_timer_tick_resume;
++      evt->set_next_event = jh7110_timer_set_next_event;
++      evt->suspend = jh7110_timer_suspend;
++      evt->resume = jh7110_timer_resume;
++      evt->rating = JH7110_CLOCKEVENT_RATING;
++}
++
++static u64 jh7110_timer_clocksource_read(struct clocksource *cs)
++{
++      struct jh7110_clkevt *clkevt = container_of(cs, struct jh7110_clkevt, cs);
++
++      return (u64)readl(clkevt->base + JH7110_TIMER_VALUE);
++}
++
++static int jh7110_clocksource_init(struct jh7110_clkevt *clkevt)
++{
++      int ret;
++
++      clkevt->cs.name = clkevt->name;
++      clkevt->cs.rating = JH7110_CLOCK_SOURCE_RATING;
++      clkevt->cs.read = jh7110_timer_clocksource_read;
++      clkevt->cs.mask = CLOCKSOURCE_MASK(JH7110_VALID_BITS);
++      clkevt->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
++
++      ret = clocksource_register_hz(&clkevt->cs, clkevt->rate);
++      if (ret)
++              return ret;
++
++      clkevt->cs_is_valid = true; /* clocksource register done */
++      writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL);
++      writel(JH7110_TIMER_MAX_TICKS, clkevt->base + JH7110_TIMER_LOAD);
++
++      return jh7110_timer_start(clkevt);
++}
++
++static void jh7110_clockevents_register(struct jh7110_clkevt *clkevt)
++{
++      clkevt->rate = clk_get_rate(clkevt->clk);
++
++      jh7110_set_clockevent(&clkevt->evt);
++      clkevt->evt.name = clkevt->name;
++      clkevt->evt.cpumask = cpu_possible_mask;
++
++      clockevents_config_and_register(&clkevt->evt, clkevt->rate,
++                                      JH7110_TIMER_MIN_TICKS, JH7110_TIMER_MAX_TICKS);
++}
++
++static void jh7110_timer_release(void *data)
++{
++      struct jh7110_timer_priv *priv = data;
++      int i;
++
++      for (i = 0; i < JH7110_TIMER_CH_MAX; i++) {
++              /* Disable each channel of timer */
++              if (priv->clkevt[i].base)
++                      writel(JH7110_TIMER_DIS, priv->clkevt[i].base + JH7110_TIMER_ENABLE);
++
++              /* Avoid no initialization in the loop of the probe */
++              if (!IS_ERR_OR_NULL(priv->clkevt[i].rst))
++                      reset_control_assert(priv->clkevt[i].rst);
++
++              if (priv->clkevt[i].cs_is_valid)
++                      clocksource_unregister(&priv->clkevt[i].cs);
++      }
++
++      reset_control_assert(priv->prst);
++}
++
++static int jh7110_timer_probe(struct platform_device *pdev)
++{
++      struct jh7110_timer_priv *priv;
++      struct jh7110_clkevt *clkevt;
++      char name[sizeof("chX")];
++      int ch;
++      int ret;
++      void __iomem *base;
++
++      priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      base = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(base))
++              return dev_err_probe(&pdev->dev, PTR_ERR(base),
++                                   "failed to map registers\n");
++
++      priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb");
++      if (IS_ERR(priv->prst))
++              return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst),
++                                   "failed to get apb reset\n");
++
++      priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb");
++      if (IS_ERR(priv->pclk))
++              return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk),
++                                   "failed to get & enable apb clock\n");
++
++      ret = reset_control_deassert(priv->prst);
++      if (ret)
++              return dev_err_probe(&pdev->dev, ret, "failed to deassert apb reset\n");
++
++      ret = devm_add_action_or_reset(&pdev->dev, jh7110_timer_release, priv);
++      if (ret)
++              return ret;
++
++      for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) {
++              clkevt = &priv->clkevt[ch];
++              snprintf(name, sizeof(name), "ch%d", ch);
++
++              clkevt->base = base + JH7110_TIMER_CH_BASE(ch);
++              /* Ensure timer is disabled */
++              writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE);
++
++              clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, name);
++              if (IS_ERR(clkevt->rst))
++                      return PTR_ERR(clkevt->rst);
++
++              clkevt->clk = devm_clk_get_enabled(&pdev->dev, name);
++              if (IS_ERR(clkevt->clk))
++                      return PTR_ERR(clkevt->clk);
++
++              ret = reset_control_deassert(clkevt->rst);
++              if (ret)
++                      return ret;
++
++              clkevt->evt.irq = platform_get_irq(pdev, ch);
++              if (clkevt->evt.irq < 0)
++                      return clkevt->evt.irq;
++
++              snprintf(clkevt->name, sizeof(clkevt->name), "jh7110-timer.ch%d", ch);
++              jh7110_clockevents_register(clkevt);
++
++              ret = devm_request_irq(&pdev->dev, clkevt->evt.irq, jh7110_timer_interrupt,
++                                     IRQF_TIMER | IRQF_IRQPOLL,
++                                     clkevt->name, &clkevt->evt);
++              if (ret)
++                      return ret;
++
++              ret = jh7110_clocksource_init(clkevt);
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static const struct of_device_id jh7110_timer_match[] = {
++      { .compatible = "starfive,jh7110-timer", },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, jh7110_timer_match);
++
++static struct platform_driver jh7110_timer_driver = {
++      .probe = jh7110_timer_probe,
++      .driver = {
++              .name = "jh7110-timer",
++              .of_match_table = jh7110_timer_match,
++      },
++};
++module_platform_driver(jh7110_timer_driver);
++
++MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
++MODULE_DESCRIPTION("StarFive JH7110 timer driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/starfive/patches-6.12/0003-pwm-opencores-Add-PWM-driver-support.patch b/target/linux/starfive/patches-6.12/0003-pwm-opencores-Add-PWM-driver-support.patch
new file mode 100644 (file)
index 0000000..0cb7004
--- /dev/null
@@ -0,0 +1,277 @@
+From 4afaa19bcf6eac558a38468417520b65801e0cfd Mon Sep 17 00:00:00 2001
+From: William Qiu <william.qiu@starfivetech.com>
+Date: Fri, 22 Dec 2023 17:45:46 +0800
+Subject: [PATCH 03/55] pwm: opencores: Add PWM driver support
+
+Add driver for OpenCores PWM Controller. And add compatibility code
+which based on StarFive SoC.
+
+Co-developed-by: Hal Feng <hal.feng@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+Signed-off-by: William Qiu <william.qiu@starfivetech.com>
+---
+ drivers/pwm/Kconfig      |  12 ++
+ drivers/pwm/Makefile     |   1 +
+ drivers/pwm/pwm-ocores.c | 230 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 243 insertions(+)
+ create mode 100644 drivers/pwm/pwm-ocores.c
+
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -471,6 +471,18 @@ config PWM_NTXEC
+         controller found in certain e-book readers designed by the original
+         design manufacturer Netronix.
++config PWM_OCORES
++      tristate "OpenCores PWM support"
++      depends on HAS_IOMEM && OF
++      depends on COMMON_CLK
++      depends on ARCH_STARFIVE || COMPILE_TEST
++      help
++        If you say yes to this option, support will be included for the
++        OpenCores PWM. For details see https://opencores.org/projects/ptc.
++
++        To compile this driver as a module, choose M here: the module
++        will be called pwm-ocores.
++
+ config PWM_OMAP_DMTIMER
+       tristate "OMAP Dual-Mode Timer PWM support"
+       depends on OF
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -42,6 +42,7 @@ obj-$(CONFIG_PWM_MICROCHIP_CORE)     += pwm-
+ obj-$(CONFIG_PWM_MTK_DISP)    += pwm-mtk-disp.o
+ obj-$(CONFIG_PWM_MXS)         += pwm-mxs.o
+ obj-$(CONFIG_PWM_NTXEC)               += pwm-ntxec.o
++obj-$(CONFIG_PWM_OCORES)      += pwm-ocores.o
+ obj-$(CONFIG_PWM_OMAP_DMTIMER)        += pwm-omap-dmtimer.o
+ obj-$(CONFIG_PWM_PCA9685)     += pwm-pca9685.o
+ obj-$(CONFIG_PWM_PXA)         += pwm-pxa.o
+--- /dev/null
++++ b/drivers/pwm/pwm-ocores.c
+@@ -0,0 +1,225 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * OpenCores PWM Driver
++ *
++ * https://opencores.org/projects/ptc
++ *
++ * Copyright (C) 2018-2023 StarFive Technology Co., Ltd.
++ *
++ * Limitations:
++ * - The hardware only do inverted polarity.
++ * - The hardware minimum period / duty_cycle is (1 / pwm_apb clock frequency) ns.
++ * - The hardware maximum period / duty_cycle is (U32_MAX / pwm_apb clock frequency) ns.
++ */
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/reset.h>
++#include <linux/slab.h>
++
++/* OCPWM_CTRL register bits*/
++#define REG_OCPWM_EN      BIT(0)
++#define REG_OCPWM_ECLK    BIT(1)
++#define REG_OCPWM_NEC     BIT(2)
++#define REG_OCPWM_OE      BIT(3)
++#define REG_OCPWM_SIGNLE  BIT(4)
++#define REG_OCPWM_INTE    BIT(5)
++#define REG_OCPWM_INT     BIT(6)
++#define REG_OCPWM_CNTRRST BIT(7)
++#define REG_OCPWM_CAPTE   BIT(8)
++
++struct ocores_pwm_device {
++      struct clk *clk;
++      struct reset_control *rst;
++      const struct ocores_pwm_data *data;
++      void __iomem *regs;
++      u32 clk_rate; /* PWM APB clock frequency */
++};
++
++struct ocores_pwm_data {
++      void __iomem *(*get_ch_base)(void __iomem *base, unsigned int channel);
++};
++
++static inline u32 ocores_readl(struct ocores_pwm_device *ddata,
++                             unsigned int channel,
++                             unsigned int offset)
++{
++      void __iomem *base = ddata->data->get_ch_base ?
++                           ddata->data->get_ch_base(ddata->regs, channel) : ddata->regs;
++
++      return readl(base + offset);
++}
++
++static inline void ocores_writel(struct ocores_pwm_device *ddata,
++                               unsigned int channel,
++                               unsigned int offset, u32 val)
++{
++      void __iomem *base = ddata->data->get_ch_base ?
++                           ddata->data->get_ch_base(ddata->regs, channel) : ddata->regs;
++
++      writel(val, base + offset);
++}
++
++static inline struct ocores_pwm_device *chip_to_ocores(struct pwm_chip *chip)
++{
++      return pwmchip_get_drvdata(chip);
++}
++
++static void __iomem *starfive_jh71x0_get_ch_base(void __iomem *base,
++                                               unsigned int channel)
++{
++      unsigned int offset = (channel > 3 ? 1 << 15 : 0) + (channel & 3) * 0x10;
++
++      return base + offset;
++}
++
++static int ocores_pwm_get_state(struct pwm_chip *chip,
++                              struct pwm_device *pwm,
++                              struct pwm_state *state)
++{
++      struct ocores_pwm_device *ddata = chip_to_ocores(chip);
++      u32 period_data, duty_data, ctrl_data;
++
++      period_data = ocores_readl(ddata, pwm->hwpwm, 0x8);
++      duty_data = ocores_readl(ddata, pwm->hwpwm, 0x4);
++      ctrl_data = ocores_readl(ddata, pwm->hwpwm, 0xC);
++
++      state->period = DIV_ROUND_UP_ULL((u64)period_data * NSEC_PER_SEC, ddata->clk_rate);
++      state->duty_cycle = DIV_ROUND_UP_ULL((u64)duty_data * NSEC_PER_SEC, ddata->clk_rate);
++      state->polarity = PWM_POLARITY_INVERSED;
++      state->enabled = (ctrl_data & REG_OCPWM_EN) ? true : false;
++
++      return 0;
++}
++
++static int ocores_pwm_apply(struct pwm_chip *chip,
++                          struct pwm_device *pwm,
++                          const struct pwm_state *state)
++{
++      struct ocores_pwm_device *ddata = chip_to_ocores(chip);
++      u32 ctrl_data = 0;
++      u64 period_data, duty_data;
++
++      if (state->polarity != PWM_POLARITY_INVERSED)
++              return -EINVAL;
++
++      ctrl_data = ocores_readl(ddata, pwm->hwpwm, 0xC);
++      ocores_writel(ddata, pwm->hwpwm, 0xC, 0);
++
++      period_data = DIV_ROUND_DOWN_ULL(state->period * ddata->clk_rate, NSEC_PER_SEC);
++      if (period_data <= U32_MAX)
++              ocores_writel(ddata, pwm->hwpwm, 0x8, (u32)period_data);
++      else
++              return -EINVAL;
++
++      duty_data = DIV_ROUND_DOWN_ULL(state->duty_cycle * ddata->clk_rate, NSEC_PER_SEC);
++      if (duty_data <= U32_MAX)
++              ocores_writel(ddata, pwm->hwpwm, 0x4, (u32)duty_data);
++      else
++              return -EINVAL;
++
++      ocores_writel(ddata, pwm->hwpwm, 0xC, 0);
++
++      if (state->enabled) {
++              ctrl_data = ocores_readl(ddata, pwm->hwpwm, 0xC);
++              ocores_writel(ddata, pwm->hwpwm, 0xC, ctrl_data | REG_OCPWM_EN | REG_OCPWM_OE);
++      }
++
++      return 0;
++}
++
++static const struct pwm_ops ocores_pwm_ops = {
++      .get_state      = ocores_pwm_get_state,
++      .apply          = ocores_pwm_apply,
++};
++
++static const struct ocores_pwm_data jh7100_pwm_data = {
++      .get_ch_base = starfive_jh71x0_get_ch_base,
++};
++
++static const struct ocores_pwm_data jh7110_pwm_data = {
++      .get_ch_base = starfive_jh71x0_get_ch_base,
++};
++
++static const struct of_device_id ocores_pwm_of_match[] = {
++      { .compatible = "opencores,pwm-v1" },
++      { .compatible = "starfive,jh7100-pwm", .data = &jh7100_pwm_data},
++      { .compatible = "starfive,jh7110-pwm", .data = &jh7110_pwm_data},
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, ocores_pwm_of_match);
++
++static void ocores_reset_control_assert(void *data)
++{
++      reset_control_assert(data);
++}
++
++static int ocores_pwm_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct ocores_pwm_device *ddata;
++      struct pwm_chip *chip;
++      int ret;
++
++      chip = devm_pwmchip_alloc(dev, 8, sizeof(*ddata));
++      if (IS_ERR(chip))
++              return PTR_ERR(chip);
++
++      chip->ops = &ocores_pwm_ops;
++
++      ddata = chip_to_ocores(chip);
++      ddata->data = of_device_get_match_data(dev);
++
++      ddata->regs = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(ddata->regs))
++              return dev_err_probe(dev, PTR_ERR(ddata->regs),
++                                   "Unable to map IO resources\n");
++
++      ddata->clk = devm_clk_get_enabled(dev, NULL);
++      if (IS_ERR(ddata->clk))
++              return dev_err_probe(dev, PTR_ERR(ddata->clk),
++                                   "Unable to get pwm's clock\n");
++
++      ddata->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
++      if (IS_ERR(ddata->rst))
++              return dev_err_probe(dev, PTR_ERR(ddata->rst),
++                                   "Unable to get pwm's reset\n");
++
++      reset_control_deassert(ddata->rst);
++
++      ret = devm_add_action_or_reset(dev, ocores_reset_control_assert, ddata->rst);
++      if (ret)
++              return ret;
++
++      ddata->clk_rate = clk_get_rate(ddata->clk);
++      if (ddata->clk_rate <= 0)
++              return dev_err_probe(dev, ddata->clk_rate,
++                                   "Unable to get clock's rate\n");
++
++      ret = devm_pwmchip_add(dev, chip);
++      if (ret < 0)
++              return dev_err_probe(dev, ret, "Could not register PWM chip\n");
++
++      platform_set_drvdata(pdev, ddata);
++
++      return ret;
++}
++
++static struct platform_driver ocores_pwm_driver = {
++      .probe = ocores_pwm_probe,
++      .driver = {
++              .name = "ocores-pwm",
++              .of_match_table = ocores_pwm_of_match,
++      },
++};
++module_platform_driver(ocores_pwm_driver);
++
++MODULE_AUTHOR("Jieqin Chen");
++MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
++MODULE_DESCRIPTION("OpenCores PWM PTC driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/starfive/patches-6.12/0004-spi-spl022-Get-and-deassert-reset-in-probe.patch b/target/linux/starfive/patches-6.12/0004-spi-spl022-Get-and-deassert-reset-in-probe.patch
new file mode 100644 (file)
index 0000000..68b1810
--- /dev/null
@@ -0,0 +1,60 @@
+From c0d35bd6e76ccabfbbbddc41a0d77ecdfbb4ee31 Mon Sep 17 00:00:00 2001
+From: "ziv.xu" <ziv.xu@starfivetech.com>
+Date: Sun, 4 Feb 2024 10:35:24 +0800
+Subject: [PATCH 04/55] spi: spl022: Get and deassert reset in probe()
+
+This fix spi1~6 communication time out.
+
+Signed-off-by: ziv.xu <ziv.xu@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -33,6 +33,7 @@
+ #include <linux/pm_runtime.h>
+ #include <linux/of.h>
+ #include <linux/pinctrl/consumer.h>
++#include <linux/reset.h>
+ /*
+  * This macro is used to define some register default values.
+@@ -363,6 +364,7 @@ struct pl022 {
+       resource_size_t                 phybase;
+       void __iomem                    *virtbase;
+       struct clk                      *clk;
++      struct reset_control            *rst;
+       struct spi_controller           *host;
+       struct pl022_ssp_controller     *host_info;
+       struct spi_transfer             *cur_transfer;
+@@ -1930,6 +1932,19 @@ static int pl022_probe(struct amba_devic
+               goto err_no_clk;
+       }
++      pl022->rst = devm_reset_control_get(&adev->dev, NULL);
++      if (IS_ERR(pl022->rst)) {
++              status = PTR_ERR(pl022->rst);
++              dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n");
++              goto err_no_rst;
++      }
++
++      status = reset_control_deassert(pl022->rst);
++      if (status) {
++              dev_err(&adev->dev, "could not deassert SSP/SPI bus reset\n");
++              goto err_no_rst_de;
++      }
++
+       /* Disable SSP */
+       writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
+              SSP_CR1(pl022->virtbase));
+@@ -1985,6 +2000,8 @@ static int pl022_probe(struct amba_devic
+       if (platform_info->enable_dma)
+               pl022_dma_remove(pl022);
+  err_no_irq:
++ err_no_rst_de:
++ err_no_rst:
+  err_no_clk:
+  err_no_ioremap:
+       amba_release_regions(adev);
diff --git a/target/linux/starfive/patches-6.12/0005-i2c-designware-Delete-SMBus-functionalities.patch b/target/linux/starfive/patches-6.12/0005-i2c-designware-Delete-SMBus-functionalities.patch
new file mode 100644 (file)
index 0000000..de4a013
--- /dev/null
@@ -0,0 +1,33 @@
+From a37f1f4370af69644c512e5e296a10357338c310 Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Fri, 12 May 2023 17:33:20 +0800
+Subject: [PATCH 05/55] i2c: designware: Delete SMBus functionalities
+
+The driver didn't implement the smbus interface,
+so replace the SMBus functionalities with
+I2C_FUNC_SMBUS_EMUL.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/i2c/busses/i2c-designware-core.h | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -17,12 +17,10 @@
+ #include <linux/regmap.h>
+ #include <linux/types.h>
+-#define DW_IC_DEFAULT_FUNCTIONALITY           (I2C_FUNC_I2C | \
+-                                               I2C_FUNC_SMBUS_BYTE | \
+-                                               I2C_FUNC_SMBUS_BYTE_DATA | \
+-                                               I2C_FUNC_SMBUS_WORD_DATA | \
+-                                               I2C_FUNC_SMBUS_BLOCK_DATA | \
+-                                               I2C_FUNC_SMBUS_I2C_BLOCK)
++#define DW_IC_DEFAULT_FUNCTIONALITY   (I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL \
++                                      & ~I2C_FUNC_SMBUS_QUICK \
++                                      & ~I2C_FUNC_SMBUS_PROC_CALL \
++                                      & ~I2C_FUNC_SMBUS_PEC))
+ #define DW_IC_CON_MASTER                      BIT(0)
+ #define DW_IC_CON_SPEED_STD                   (1 << 1)
diff --git a/target/linux/starfive/patches-6.12/0006-drivers-mtd-gigadevice-add-gd25lq256d-32M-flash-supp.patch b/target/linux/starfive/patches-6.12/0006-drivers-mtd-gigadevice-add-gd25lq256d-32M-flash-supp.patch
new file mode 100644 (file)
index 0000000..4ef6b78
--- /dev/null
@@ -0,0 +1,29 @@
+From 8850887a7b71b55250be2a15802963d6b32ea8ab Mon Sep 17 00:00:00 2001
+From: Ziv Xu <ziv.xu@starfivetech.com>
+Date: Fri, 19 Jan 2024 15:22:55 +0800
+Subject: [PATCH 06/55] drivers: mtd: gigadevice: add gd25lq256d 32M flash
+ support
+
+add gd25lq256d 32M flash support
+
+Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/mtd/spi-nor/gigadevice.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/mtd/spi-nor/gigadevice.c
++++ b/drivers/mtd/spi-nor/gigadevice.c
+@@ -95,6 +95,12 @@ static const struct flash_info gigadevic
+               .size = SZ_16M,
+               .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB,
+               .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
++      }, {
++              .id = SNOR_ID(0xc8, 0x60, 0x19),
++              .name = "gd25lq256d",
++              .size = SZ_32M,
++              .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_QUAD_PP,
++              .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+       },
+ };
diff --git a/target/linux/starfive/patches-6.12/0007-driver-mailbox-Add-mailbox-driver.patch b/target/linux/starfive/patches-6.12/0007-driver-mailbox-Add-mailbox-driver.patch
new file mode 100644 (file)
index 0000000..e8a81d1
--- /dev/null
@@ -0,0 +1,804 @@
+From f7db05ea5fffebed6db6693333a6877aa707b16d Mon Sep 17 00:00:00 2001
+From: "shanlong.li" <shanlong.li@starfivetech.com>
+Date: Thu, 8 Jun 2023 00:07:15 -0700
+Subject: [PATCH 07/55] driver: mailbox: Add mailbox driver
+
+Add mailbox driver.
+
+Signed-off-by: shanlong.li <shanlong.li@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/mailbox/Kconfig                 |  13 +
+ drivers/mailbox/Makefile                |   4 +
+ drivers/mailbox/starfive_mailbox-test.c | 405 ++++++++++++++++++++++++
+ drivers/mailbox/starfive_mailbox.c      | 345 ++++++++++++++++++++
+ 4 files changed, 767 insertions(+)
+ create mode 100644 drivers/mailbox/starfive_mailbox-test.c
+ create mode 100644 drivers/mailbox/starfive_mailbox.c
+
+--- a/drivers/mailbox/Kconfig
++++ b/drivers/mailbox/Kconfig
+@@ -295,4 +295,17 @@ config QCOM_IPCC
+         acts as an interrupt controller for receiving interrupts from clients.
+         Say Y here if you want to build this driver.
++config STARFIVE_MBOX
++      tristate "Platform Starfive Mailbox"
++      depends on OF
++      help
++        Say Y here if you want to build a platform specific variant RISCV
++        controller driver.
++
++config STARFIVE_MBOX_TEST
++      tristate "Starfive Mailbox Test Client"
++      depends on OF
++      depends on HAS_IOMEM
++      help
++        Test client to help with testing new Controller driver implementations.
+ endif
+--- a/drivers/mailbox/Makefile
++++ b/drivers/mailbox/Makefile
+@@ -64,3 +64,7 @@ obj-$(CONFIG_SPRD_MBOX)              += sprd-mailbox
+ obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o
+ obj-$(CONFIG_QCOM_IPCC)               += qcom-ipcc.o
++
++obj-$(CONFIG_STARFIVE_MBOX)    += starfive_mailbox.o
++ccflags-$(CONFIG_STARFIVE_MBOX) := -Wno-error=missing-prototypes
++obj-$(CONFIG_STARFIVE_MBOX_TEST)    += starfive_mailbox-test.o
+--- /dev/null
++++ b/drivers/mailbox/starfive_mailbox-test.c
+@@ -0,0 +1,405 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2015 ST Microelectronics
++ *
++ * Author: Lee Jones <lee.jones@linaro.org>
++ */
++
++#include <linux/debugfs.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/mailbox_client.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/sched/signal.h>
++
++#include <linux/mailbox_controller.h>
++
++#define MBOX_MAX_SIG_LEN      8
++#define MBOX_MAX_MSG_LEN      16
++#define MBOX_BYTES_PER_LINE   16
++#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2)
++#define MBOX_HEXDUMP_MAX_LEN  (MBOX_HEXDUMP_LINE_LEN * (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
++
++static bool mbox_data_ready;
++
++struct mbox_test_device {
++      struct device           *dev;
++      void __iomem            *tx_mmio;
++      void __iomem            *rx_mmio;
++      struct mbox_chan        *tx_channel;
++      struct mbox_chan        *rx_channel;
++      char                    *rx_buffer;
++      char                    *signal;
++      char                    *message;
++      spinlock_t              lock;
++      wait_queue_head_t       waitq;
++      struct fasync_struct    *async_queue;
++      struct dentry           *root_debugfs_dir;
++};
++
++static ssize_t mbox_test_signal_write(struct file *filp,
++              const char __user *userbuf,
++              size_t count, loff_t *ppos)
++{
++      struct mbox_test_device *tdev = filp->private_data;
++
++      if (!tdev->tx_channel) {
++              dev_err(tdev->dev, "Channel cannot do Tx\n");
++              return -EINVAL;
++      }
++
++      if (count > MBOX_MAX_SIG_LEN) {
++              dev_err(tdev->dev,
++                      "Signal length %zd greater than max allowed %d\n",
++                      count, MBOX_MAX_SIG_LEN);
++              return -EINVAL;
++      }
++
++      /* Only allocate memory if we need to */
++      if (!tdev->signal) {
++              tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
++              if (!tdev->signal)
++                      return -ENOMEM;
++      }
++
++      if (copy_from_user(tdev->signal, userbuf, count)) {
++              kfree(tdev->signal);
++              tdev->signal = NULL;
++              return -EFAULT;
++      }
++
++      return count;
++}
++
++static const struct file_operations mbox_test_signal_ops = {
++      .write = mbox_test_signal_write,
++      .open = simple_open,
++      .llseek = generic_file_llseek,
++};
++
++static int mbox_test_message_fasync(int fd, struct file *filp, int on)
++{
++      struct mbox_test_device *tdev = filp->private_data;
++
++      return fasync_helper(fd, filp, on, &tdev->async_queue);
++}
++
++static ssize_t mbox_test_message_write(struct file *filp,
++              const char __user *userbuf,
++              size_t count, loff_t *ppos)
++{
++      struct mbox_test_device *tdev = filp->private_data;
++      void *data;
++      int ret;
++
++      if (!tdev->tx_channel) {
++              dev_err(tdev->dev, "Channel cannot do Tx\n");
++              return -EINVAL;
++      }
++
++      if (count > MBOX_MAX_MSG_LEN) {
++              dev_err(tdev->dev,
++                      "Message length %zd greater than max allowed %d\n",
++                      count, MBOX_MAX_MSG_LEN);
++              return -EINVAL;
++      }
++
++      tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
++      if (!tdev->message)
++              return -ENOMEM;
++
++      ret = copy_from_user(tdev->message, userbuf, count);
++      if (ret) {
++              ret = -EFAULT;
++              goto out;
++      }
++
++      if (tdev->tx_mmio && tdev->signal) {
++              print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
++                      tdev->signal, MBOX_MAX_SIG_LEN);
++
++              data = tdev->signal;
++      } else
++              data = tdev->message;
++
++      print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
++              tdev->message, MBOX_MAX_MSG_LEN);
++
++      ret = mbox_send_message(tdev->tx_channel, data);
++      mbox_chan_txdone(tdev->tx_channel, ret);
++      if (ret < 0)
++              dev_err(tdev->dev, "Failed to send message via mailbox\n");
++
++out:
++      kfree(tdev->signal);
++      kfree(tdev->message);
++      tdev->signal = NULL;
++
++      return ret < 0 ? ret : count;
++}
++
++static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
++{
++      bool data_ready;
++      unsigned long flags;
++
++      spin_lock_irqsave(&tdev->lock, flags);
++      data_ready = mbox_data_ready;
++      spin_unlock_irqrestore(&tdev->lock, flags);
++
++      return data_ready;
++}
++
++static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
++              size_t count, loff_t *ppos)
++{
++      struct mbox_test_device *tdev = filp->private_data;
++      unsigned long flags;
++      char *touser, *ptr;
++      int ret;
++
++      touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
++      if (!touser)
++              return -ENOMEM;
++
++      if (!tdev->rx_channel) {
++              ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
++              ret = simple_read_from_buffer(userbuf, count, ppos,
++                      touser, ret);
++              goto kfree_err;
++      }
++
++      do {
++              if (mbox_test_message_data_ready(tdev))
++                      break;
++
++              if (filp->f_flags & O_NONBLOCK) {
++                      ret = -EAGAIN;
++                      goto waitq_err;
++              }
++
++              if (signal_pending(current)) {
++                      ret = -ERESTARTSYS;
++                      goto waitq_err;
++              }
++              schedule();
++
++      } while (1);
++
++      spin_lock_irqsave(&tdev->lock, flags);
++
++      ptr = tdev->rx_buffer;
++
++      mbox_data_ready = false;
++
++      spin_unlock_irqrestore(&tdev->lock, flags);
++      if (copy_to_user((void __user *)userbuf, ptr, 4))
++              ret = -EFAULT;
++
++waitq_err:
++      __set_current_state(TASK_RUNNING);
++kfree_err:
++      kfree(touser);
++      return ret;
++}
++
++static __poll_t
++mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
++{
++      struct mbox_test_device *tdev = filp->private_data;
++
++      poll_wait(filp, &tdev->waitq, wait);
++
++      if (mbox_test_message_data_ready(tdev))
++              return EPOLLIN | EPOLLRDNORM;
++      return 0;
++}
++
++static const struct file_operations mbox_test_message_ops = {
++      .write = mbox_test_message_write,
++      .read = mbox_test_message_read,
++      .fasync = mbox_test_message_fasync,
++      .poll = mbox_test_message_poll,
++      .open = simple_open,
++      .llseek = generic_file_llseek,
++};
++
++static int mbox_test_add_debugfs(struct platform_device *pdev,
++              struct mbox_test_device *tdev)
++{
++      if (!debugfs_initialized())
++              return 0;
++
++      tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
++      if (!tdev->root_debugfs_dir) {
++              dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
++              return -EINVAL;
++      }
++
++      debugfs_create_file("message", 0600, tdev->root_debugfs_dir,
++              tdev, &mbox_test_message_ops);
++
++      debugfs_create_file("signal", 0200, tdev->root_debugfs_dir,
++              tdev, &mbox_test_signal_ops);
++
++      return 0;
++}
++
++static void mbox_test_receive_message(struct mbox_client *client, void *message)
++{
++      struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
++      unsigned long flags;
++
++      spin_lock_irqsave(&tdev->lock, flags);
++      if (tdev->rx_mmio) {
++              memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);
++              print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS,
++                      tdev->rx_buffer, MBOX_MAX_MSG_LEN);
++      } else if (message) {
++              print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS,
++                      message, MBOX_MAX_MSG_LEN);
++              memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
++      }
++      mbox_data_ready = true;
++      spin_unlock_irqrestore(&tdev->lock, flags);
++}
++
++static void mbox_test_prepare_message(struct mbox_client *client, void *message)
++{
++      struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
++
++      if (tdev->tx_mmio) {
++              if (tdev->signal)
++                      memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);
++              else
++                      memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);
++      }
++}
++
++static struct mbox_chan *
++mbox_test_request_channel(struct platform_device *pdev, const char *name)
++{
++      struct mbox_client *client;
++      struct mbox_chan *channel;
++
++      client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
++      if (!client)
++              return ERR_PTR(-ENOMEM);
++
++      client->dev        = &pdev->dev;
++      client->rx_callback    = mbox_test_receive_message;
++      client->tx_prepare    = mbox_test_prepare_message;
++      client->tx_block    = false;
++      client->knows_txdone    = false;
++      client->tx_tout        = 500;
++
++      channel = mbox_request_channel_byname(client, name);
++      if (IS_ERR(channel)) {
++              dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
++              return NULL;
++      }
++
++      return channel;
++}
++
++static int mbox_test_probe(struct platform_device *pdev)
++{
++      struct mbox_test_device *tdev;
++      struct resource *res;
++      resource_size_t size;
++      int ret;
++
++      tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
++      if (!tdev)
++              return -ENOMEM;
++
++      /* It's okay for MMIO to be NULL */
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
++      if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
++              /* if reserved area in SRAM, try just ioremap */
++              size = resource_size(res);
++              tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
++      } else if (IS_ERR(tdev->tx_mmio)) {
++              tdev->tx_mmio = NULL;
++      }
++
++      /* If specified, second reg entry is Rx MMIO */
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
++      if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
++              size = resource_size(res);
++              tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
++      } else if (IS_ERR(tdev->rx_mmio)) {
++              tdev->rx_mmio = tdev->tx_mmio;
++      }
++
++      tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
++      tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
++
++      if (!tdev->tx_channel && !tdev->rx_channel)
++              return -EPROBE_DEFER;
++
++      /* If Rx is not specified but has Rx MMIO, then Rx = Tx */
++      if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
++              tdev->rx_channel = tdev->tx_channel;
++
++      tdev->dev = &pdev->dev;
++      platform_set_drvdata(pdev, tdev);
++
++      spin_lock_init(&tdev->lock);
++
++      if (tdev->rx_channel) {
++              tdev->rx_buffer = devm_kzalloc(&pdev->dev,
++                      MBOX_MAX_MSG_LEN, GFP_KERNEL);
++              if (!tdev->rx_buffer)
++                      return -ENOMEM;
++      }
++
++      ret = mbox_test_add_debugfs(pdev, tdev);
++      if (ret)
++              return ret;
++
++      dev_info(&pdev->dev, "Successfully registered\n");
++
++      return 0;
++}
++
++static void mbox_test_remove(struct platform_device *pdev)
++{
++      struct mbox_test_device *tdev = platform_get_drvdata(pdev);
++
++      debugfs_remove_recursive(tdev->root_debugfs_dir);
++
++      if (tdev->tx_channel)
++              mbox_free_channel(tdev->tx_channel);
++      if (tdev->rx_channel)
++              mbox_free_channel(tdev->rx_channel);
++}
++
++static const struct of_device_id mbox_test_match[] = {
++      { .compatible = "starfive,mailbox-test" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mbox_test_match);
++
++static struct platform_driver mbox_test_driver = {
++      .driver = {
++              .name = "mailbox_test",
++              .of_match_table = mbox_test_match,
++      },
++      .probe  = mbox_test_probe,
++      .remove = mbox_test_remove,
++};
++module_platform_driver(mbox_test_driver);
++
++MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
++MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/mailbox/starfive_mailbox.c
+@@ -0,0 +1,345 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * mailbox driver for StarFive JH7110 SoC
++ *
++ * Copyright (c) 2021 StarFive Technology Co., Ltd.
++ * Author: Shanlong Li <shanlong.li@starfivetech.com>
++ */
++
++#include <linux/bitops.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/mailbox_controller.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/pm_runtime.h>
++
++#include "mailbox.h"
++
++#define MBOX_CHAN_MAX         4
++
++#define MBOX_BASE(mbox, ch)   ((mbox)->base + ((ch) * 0x10))
++#define MBOX_IRQ_REG          0x00
++#define MBOX_SET_REG          0x04
++#define MBOX_CLR_REG          0x08
++#define MBOX_CMD_REG          0x0c
++#define MBC_PEND_SMRY         0x100
++
++typedef enum {
++      MAILBOX_CORE_U7 = 0,
++      MAILBOX_CORE_HIFI4,
++      MAILBOX_CORE_E2,
++      MAILBOX_CORE_RSVD0,
++      MAILBOX_CORE_NUM,
++} mailbox_core_t;
++
++struct mailbox_irq_name_c{
++      int id;
++      char name[16];
++};
++
++static const struct mailbox_irq_name_c irq_peer_name[MBOX_CHAN_MAX] = {
++      {MAILBOX_CORE_U7,    "u74_core"},
++      {MAILBOX_CORE_HIFI4, "hifi4_core"},
++      {MAILBOX_CORE_E2,    "e24_core"},
++      {MAILBOX_CORE_RSVD0, "" },
++};
++
++/**
++ * starfive mailbox channel information
++ *
++ * A channel can be used for TX or RX, it can trigger remote
++ * processor interrupt to notify remote processor and can receive
++ * interrupt if has incoming message.
++ *
++ * @dst_irq:    Interrupt vector for remote processor
++ * @core_id:    id for remote processor
++ */
++struct starfive_chan_info {
++      unsigned int dst_irq;
++      mailbox_core_t core_id;
++};
++
++/**
++ * starfive mailbox controller data
++ *
++ * Mailbox controller includes 4 channels and can allocate
++ * channel for message transferring.
++ *
++ * @dev:    Device to which it is attached
++ * @base:    Base address of the register mapping region
++ * @chan:    Representation of channels in mailbox controller
++ * @mchan:    Representation of channel info
++ * @controller:    Representation of a communication channel controller
++ */
++struct starfive_mbox {
++      struct device *dev;
++      void __iomem *base;
++      struct mbox_chan chan[MBOX_CHAN_MAX];
++      struct starfive_chan_info mchan[MBOX_CHAN_MAX];
++      struct mbox_controller controller;
++      struct clk *clk;
++      struct reset_control *rst_rresetn;
++};
++
++static struct starfive_mbox *to_starfive_mbox(struct mbox_controller *mbox)
++{
++      return container_of(mbox, struct starfive_mbox, controller);
++}
++
++static struct mbox_chan *
++starfive_of_mbox_index_xlate(struct mbox_controller *mbox,
++                      const struct of_phandle_args *sp)
++{
++      struct starfive_mbox *sbox;
++
++      int ind = sp->args[0];
++      int core_id = sp->args[1];
++
++      if (ind >= mbox->num_chans || core_id >= MAILBOX_CORE_NUM)
++              return ERR_PTR(-EINVAL);
++
++      sbox = to_starfive_mbox(mbox);
++
++      sbox->mchan[ind].core_id = core_id;
++
++      return &mbox->chans[ind];
++}
++
++static irqreturn_t starfive_rx_irq_handler(int irq, void *p)
++{
++      struct mbox_chan *chan = p;
++      unsigned long ch = (unsigned long)chan->con_priv;
++      struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
++      void __iomem *base = MBOX_BASE(mbox, ch);
++      u32 val;
++
++      val = readl(base + MBOX_CMD_REG);
++      if (!val)
++              return IRQ_NONE;
++
++      mbox_chan_received_data(chan, (void *)&val);
++      writel(val, base + MBOX_CLR_REG);
++      return IRQ_HANDLED;
++}
++
++static int starfive_mbox_check_state(struct mbox_chan *chan)
++{
++      unsigned long ch = (unsigned long)chan->con_priv;
++      struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
++      unsigned long irq_flag = IRQF_SHARED;
++      long ret = 0;
++
++      pm_runtime_get_sync(mbox->dev);
++      /* MAILBOX should be with IRQF_NO_SUSPEND set */
++      if (!mbox->dev->pm_domain)
++              irq_flag |= IRQF_NO_SUSPEND;
++
++      /* Mailbox is idle so directly bail out */
++      if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch))
++              return -EBUSY;
++
++      if (mbox->mchan[ch].dst_irq > 0) {
++              dev_dbg(mbox->dev, "%s: host IRQ = %d, ch:%ld", __func__, mbox->mchan[ch].dst_irq, ch);
++              ret = devm_request_irq(mbox->dev, mbox->mchan[ch].dst_irq, starfive_rx_irq_handler,
++                      irq_flag, irq_peer_name[ch].name, chan);
++              if (ret < 0)
++                      dev_err(mbox->dev, "request_irq %d failed\n", mbox->mchan[ch].dst_irq);
++      }
++
++      return ret;
++}
++
++static int starfive_mbox_startup(struct mbox_chan *chan)
++{
++      return starfive_mbox_check_state(chan);
++}
++
++static void starfive_mbox_shutdown(struct mbox_chan *chan)
++{
++      struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
++      unsigned long ch = (unsigned long)chan->con_priv;
++      void __iomem *base = MBOX_BASE(mbox, ch);
++
++      writel(0x0, base + MBOX_IRQ_REG);
++      writel(0x0, base + MBOX_CLR_REG);
++
++      if (mbox->mchan[ch].dst_irq > 0)
++              devm_free_irq(mbox->dev, mbox->mchan[ch].dst_irq, chan);
++      pm_runtime_put_sync(mbox->dev);
++}
++
++static int starfive_mbox_send_data(struct mbox_chan *chan, void *msg)
++{
++      unsigned long ch = (unsigned long)chan->con_priv;
++      struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
++      struct starfive_chan_info *mchan = &mbox->mchan[ch];
++      void __iomem *base = MBOX_BASE(mbox, ch);
++      u32 *buf = msg;
++
++      /* Ensure channel is released */
++      if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) {
++              pr_debug("%s:%d. busy\n", __func__, __LINE__);
++              return -EBUSY;
++      }
++
++      /* Clear mask for destination interrupt */
++      writel(BIT(mchan->core_id), base + MBOX_IRQ_REG);
++
++      /* Fill message data */
++      writel(*buf, base + MBOX_SET_REG);
++      return 0;
++}
++
++static struct mbox_chan_ops starfive_mbox_ops = {
++      .startup = starfive_mbox_startup,
++      .send_data = starfive_mbox_send_data,
++      .shutdown = starfive_mbox_shutdown,
++};
++
++static const struct of_device_id starfive_mbox_of_match[] = {
++      { .compatible = "starfive,mail_box",},
++      {},
++};
++
++MODULE_DEVICE_TABLE(of, starfive_mbox_of_match);
++
++void starfive_mailbox_init(struct starfive_mbox *mbox)
++{
++      mbox->clk = devm_clk_get_optional(mbox->dev, "clk_apb");
++      if (IS_ERR(mbox->clk)) {
++              dev_err(mbox->dev, "failed to get mailbox\n");
++              return;
++      }
++
++      mbox->rst_rresetn = devm_reset_control_get_exclusive(mbox->dev, "mbx_rre");
++      if (IS_ERR(mbox->rst_rresetn)) {
++              dev_err(mbox->dev, "failed to get mailbox reset\n");
++              return;
++      }
++
++      clk_prepare_enable(mbox->clk);
++      reset_control_deassert(mbox->rst_rresetn);
++}
++
++static int starfive_mbox_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct starfive_mbox *mbox;
++      struct mbox_chan *chan;
++      struct resource *res;
++      unsigned long ch;
++      int err;
++
++      mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
++      if (!mbox)
++              return -ENOMEM;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      mbox->base = devm_ioremap_resource(dev, res);
++      mbox->dev = dev;
++
++      if (IS_ERR(mbox->base))
++              return PTR_ERR(mbox->base);
++
++      starfive_mailbox_init(mbox);
++
++      mbox->controller.dev = dev;
++      mbox->controller.chans = mbox->chan;
++      mbox->controller.num_chans = MBOX_CHAN_MAX;
++      mbox->controller.ops = &starfive_mbox_ops;
++      mbox->controller.of_xlate = starfive_of_mbox_index_xlate;
++      mbox->controller.txdone_irq = true;
++      mbox->controller.txdone_poll = false;
++
++      /* Initialize mailbox channel data */
++      chan = mbox->chan;
++      for (ch = 0; ch < MBOX_CHAN_MAX; ch++) {
++              mbox->mchan[ch].dst_irq = 0;
++              mbox->mchan[ch].core_id = (mailbox_core_t)ch;
++              chan[ch].con_priv = (void *)ch;
++      }
++      mbox->mchan[MAILBOX_CORE_HIFI4].dst_irq = platform_get_irq(pdev, 0);
++      mbox->mchan[MAILBOX_CORE_E2].dst_irq = platform_get_irq(pdev, 1);
++
++      err = mbox_controller_register(&mbox->controller);
++      if (err) {
++              dev_err(dev, "Failed to register mailbox %d\n", err);
++              return err;
++      }
++
++      platform_set_drvdata(pdev, mbox);
++      dev_info(dev, "Mailbox enabled\n");
++      pm_runtime_set_active(dev);
++      pm_runtime_enable(dev);
++
++      return 0;
++}
++
++static void starfive_mbox_remove(struct platform_device *pdev)
++{
++      struct starfive_mbox *mbox = platform_get_drvdata(pdev);
++
++      mbox_controller_unregister(&mbox->controller);
++      devm_clk_put(mbox->dev, mbox->clk);
++      pm_runtime_disable(mbox->dev);
++}
++
++static int __maybe_unused starfive_mbox_suspend(struct device *dev)
++{
++      struct starfive_mbox *mbox = dev_get_drvdata(dev);
++
++      clk_disable_unprepare(mbox->clk);
++
++      return 0;
++}
++
++static int __maybe_unused starfive_mbox_resume(struct device *dev)
++{
++      struct starfive_mbox *mbox = dev_get_drvdata(dev);
++      int ret;
++
++      ret = clk_prepare_enable(mbox->clk);
++      if (ret)
++              dev_err(dev, "failed to enable clock\n");
++
++      return ret;
++}
++
++static const struct dev_pm_ops starfive_mbox_pm_ops = {
++      .suspend = starfive_mbox_suspend,
++      .resume = starfive_mbox_resume,
++      SET_RUNTIME_PM_OPS(starfive_mbox_suspend, starfive_mbox_resume, NULL)
++};
++static struct platform_driver starfive_mbox_driver = {
++      .probe  = starfive_mbox_probe,
++      .remove = starfive_mbox_remove,
++      .driver = {
++      .name = "mailbox",
++              .of_match_table = starfive_mbox_of_match,
++              .pm = &starfive_mbox_pm_ops,
++      },
++};
++
++static int __init starfive_mbox_init(void)
++{
++      return platform_driver_register(&starfive_mbox_driver);
++}
++core_initcall(starfive_mbox_init);
++
++static void __exit starfive_mbox_exit(void)
++{
++      platform_driver_unregister(&starfive_mbox_driver);
++}
++module_exit(starfive_mbox_exit);
++
++MODULE_DESCRIPTION("StarFive Mailbox Controller driver");
++MODULE_AUTHOR("Shanlong Li <shanlong.li@starfivetech.com>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/starfive/patches-6.12/0008-driver-rtc-Add-StarFive-JH7110-rtc-driver.patch b/target/linux/starfive/patches-6.12/0008-driver-rtc-Add-StarFive-JH7110-rtc-driver.patch
new file mode 100644 (file)
index 0000000..c4d4449
--- /dev/null
@@ -0,0 +1,787 @@
+From 5969d5b6f7cac455f6f9afc0fe64ac706002e5b5 Mon Sep 17 00:00:00 2001
+From: "ziv.xu" <ziv.xu@starfivetech.com>
+Date: Fri, 9 Jun 2023 15:31:53 +0800
+Subject: [PATCH 08/55] driver: rtc: Add StarFive JH7110 rtc driver
+
+Add RTC driver and support for StarFive JH7110 SoC.
+
+Signed-off-by: ziv.xu <ziv.xu@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/rtc/Kconfig        |   8 +
+ drivers/rtc/Makefile       |   1 +
+ drivers/rtc/rtc-starfive.c | 741 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 750 insertions(+)
+ create mode 100644 drivers/rtc/rtc-starfive.c
+
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -1372,6 +1372,14 @@ config RTC_DRV_NTXEC
+         embedded controller found in certain e-book readers designed by the
+         original design manufacturer Netronix.
++config RTC_DRV_STARFIVE
++      tristate "StarFive 32.768k-RTC"
++      depends on ARCH_STARFIVE
++      depends on OF
++      help
++        If you say Y here you will get support for the RTC found on
++        StarFive SOCS.
++
+ comment "on-CPU RTC drivers"
+ config RTC_DRV_ASM9260
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -169,6 +169,7 @@ obj-$(CONFIG_RTC_DRV_SH)   += rtc-sh.o
+ obj-$(CONFIG_RTC_DRV_SNVS)    += rtc-snvs.o
+ obj-$(CONFIG_RTC_DRV_SPEAR)   += rtc-spear.o
+ obj-$(CONFIG_RTC_DRV_STARFIRE)        += rtc-starfire.o
++obj-$(CONFIG_RTC_DRV_STARFIVE)        += rtc-starfive.o
+ obj-$(CONFIG_RTC_DRV_STK17TA8)        += rtc-stk17ta8.o
+ obj-$(CONFIG_RTC_DRV_ST_LPC)  += rtc-st-lpc.o
+ obj-$(CONFIG_RTC_DRV_STM32)   += rtc-stm32.o
+--- /dev/null
++++ b/drivers/rtc/rtc-starfive.c
+@@ -0,0 +1,741 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * RTC driver for the StarFive JH7110 SoC
++ *
++ * Copyright (C) 2021 StarFive Technology Co., Ltd.
++ */
++
++#include <asm/delay.h>
++#include <linux/bcd.h>
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/completion.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/iopoll.h>
++#include <linux/platform_device.h>
++#include <linux/rtc.h>
++
++/* Registers */
++#define SFT_RTC_CFG           0x00
++#define SFT_RTC_SW_CAL_VALUE  0x04
++#define SFT_RTC_HW_CAL_CFG    0x08
++#define SFT_RTC_CMP_CFG               0x0C
++#define SFT_RTC_IRQ_EN                0x10
++#define SFT_RTC_IRQ_EVEVT     0x14
++#define SFT_RTC_IRQ_STATUS    0x18
++#define SFT_RTC_CAL_VALUE     0x24
++#define SFT_RTC_CFG_TIME      0x28
++#define SFT_RTC_CFG_DATE      0x2C
++#define SFT_RTC_ACT_TIME      0x34
++#define SFT_RTC_ACT_DATE      0x38
++#define SFT_RTC_TIME          0x3C
++#define SFT_RTC_DATE          0x40
++#define SFT_RTC_TIME_LATCH    0x44
++#define SFT_RTC_DATE_LATCH    0x48
++
++/* RTC_CFG */
++#define RTC_CFG_ENABLE_SHIFT  0  /* RW: RTC Enable. */
++#define RTC_CFG_CAL_EN_HW_SHIFT       1  /* RW: Enable of hardware calibretion. */
++#define RTC_CFG_CAL_SEL_SHIFT 2  /* RW: select the hw/sw calibretion mode.*/
++#define RTC_CFG_HOUR_MODE_SHIFT       3  /* RW: time hour mode. 24h|12h */
++
++/* RTC_SW_CAL_VALUE */
++#define RTC_SW_CAL_VALUE_MASK GENMASK(15, 0)
++#define RTC_SW_CAL_MAX                RTC_SW_CAL_VALUE_MASK
++#define RTC_SW_CAL_MIN                0
++#define RTC_TICKS_PER_SEC     32768           /* Number of ticks per second */
++#define RTC_PPB_MULT          1000000000LL    /* Multiplier for ppb conversions */
++
++/* RTC_HW_CAL_CFG */
++#define RTC_HW_CAL_REF_SEL_SHIFT      0
++#define RTC_HW_CAL_FRQ_SEL_SHIFT      1
++
++/* IRQ_EN/IRQ_EVEVT/IRQ_STATUS */
++#define RTC_IRQ_CAL_START     BIT(0)
++#define RTC_IRQ_CAL_FINISH    BIT(1)
++#define RTC_IRQ_CMP           BIT(2)
++#define RTC_IRQ_1SEC          BIT(3)
++#define RTC_IRQ_ALAEM         BIT(4)
++#define RTC_IRQ_EVT_UPDATE_PSE        BIT(31) /* WO: Enable of update time&&date, IRQ_EVEVT only */
++#define RTC_IRQ_ALL           (RTC_IRQ_CAL_START \
++                              | RTC_IRQ_CAL_FINISH \
++                              | RTC_IRQ_CMP \
++                              | RTC_IRQ_1SEC \
++                              | RTC_IRQ_ALAEM)
++
++/* CAL_VALUE */
++#define RTC_CAL_VALUE_MASK    GENMASK(15, 0)
++
++/* CFG_TIME/ACT_TIME/RTC_TIME */
++#define TIME_SEC_MASK         GENMASK(6, 0)
++#define TIME_MIN_MASK         GENMASK(13, 7)
++#define TIME_HOUR_MASK                GENMASK(20, 14)
++
++/* CFG_DATE/ACT_DATE/RTC_DATE */
++#define DATE_DAY_MASK         GENMASK(5, 0)
++#define DATE_MON_MASK         GENMASK(10, 6)
++#define DATE_YEAR_MASK                GENMASK(18, 11)
++
++#define INT_TIMEOUT_US                180
++
++enum RTC_HOUR_MODE {
++      RTC_HOUR_MODE_12H = 0,
++      RTC_HOUR_MODE_24H = 1
++};
++
++enum RTC_CAL_MODE {
++      RTC_CAL_MODE_SW = 0,
++      RTC_CAL_MODE_HW = 1
++};
++
++enum RTC_HW_CAL_REF_MODE {
++      RTC_CAL_CLK_REF = 0,
++      RTC_CAL_CLK_MARK = 1
++};
++
++static const unsigned long refclk_list[] = {
++      1000000,
++      2000000,
++      4000000,
++      5927000,
++      6000000,
++      7200000,
++      8000000,
++      10250000,
++      11059200,
++      12000000,
++      12288000,
++      13560000,
++      16000000,
++      19200000,
++      20000000,
++      22118000,
++      24000000,
++      24567000,
++      25000000,
++      26000000,
++      27000000,
++      30000000,
++      32000000,
++      33868800,
++      36000000,
++      36860000,
++      40000000,
++      44000000,
++      50000000,
++      54000000,
++      28224000,
++      28000000,
++};
++
++struct sft_rtc {
++      struct rtc_device *rtc_dev;
++      struct completion cal_done;
++      struct completion onesec_done;
++      struct clk *pclk;
++      struct clk *cal_clk;
++      struct reset_control *rst_array;
++      int hw_cal_map;
++      void __iomem *regs;
++      int rtc_irq;
++      int ms_pulse_irq;
++      int one_sec_pulse_irq;
++};
++
++static inline void sft_rtc_set_enabled(struct sft_rtc *srtc, bool enabled)
++{
++      u32 val;
++
++      if (enabled) {
++              val = readl(srtc->regs + SFT_RTC_CFG);
++              val |= BIT(RTC_CFG_ENABLE_SHIFT);
++              writel(val, srtc->regs + SFT_RTC_CFG);
++      } else {
++              val = readl(srtc->regs + SFT_RTC_CFG);
++              val &= ~BIT(RTC_CFG_ENABLE_SHIFT);
++              writel(val, srtc->regs + SFT_RTC_CFG);
++      }
++}
++
++static inline bool sft_rtc_get_enabled(struct sft_rtc *srtc)
++{
++      return !!(readl(srtc->regs + SFT_RTC_CFG) & BIT(RTC_CFG_ENABLE_SHIFT));
++}
++
++static inline void sft_rtc_set_mode(struct sft_rtc *srtc, enum RTC_HOUR_MODE mode)
++{
++      u32 val;
++
++      val = readl(srtc->regs + SFT_RTC_CFG);
++      val |= mode << RTC_CFG_HOUR_MODE_SHIFT;
++      writel(val, srtc->regs + SFT_RTC_CFG);
++}
++
++static inline int sft_rtc_irq_enable(struct sft_rtc *srtc, u32 irq, bool enable)
++{
++      u32 val;
++
++      if (!(irq & RTC_IRQ_ALL))
++              return -EINVAL;
++
++      if (enable) {
++              val = readl(srtc->regs + SFT_RTC_IRQ_EN);
++              val |= irq;
++              writel(val, srtc->regs + SFT_RTC_IRQ_EN);
++      } else {
++              val = readl(srtc->regs + SFT_RTC_IRQ_EN);
++              val &= ~irq;
++              writel(val, srtc->regs + SFT_RTC_IRQ_EN);
++      }
++      return 0;
++}
++
++static inline void
++sft_rtc_set_cal_hw_enable(struct sft_rtc *srtc, bool enable)
++{
++      u32 val;
++
++      if (enable) {
++              val = readl(srtc->regs + SFT_RTC_CFG);
++              val |= BIT(RTC_CFG_CAL_EN_HW_SHIFT);
++              writel(val, srtc->regs + SFT_RTC_CFG);
++      } else {
++              val = readl(srtc->regs + SFT_RTC_CFG);
++              val &= ~BIT(RTC_CFG_CAL_EN_HW_SHIFT);
++              writel(val, srtc->regs + SFT_RTC_CFG);
++      }
++}
++
++static inline void
++sft_rtc_set_cal_mode(struct sft_rtc *srtc, enum RTC_CAL_MODE mode)
++{
++      u32 val;
++
++      val = readl(srtc->regs + SFT_RTC_CFG);
++      val |= mode << RTC_CFG_CAL_SEL_SHIFT;
++      writel(val, srtc->regs + SFT_RTC_CFG);
++}
++
++static int sft_rtc_get_hw_calclk(struct device *dev, unsigned long freq)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(refclk_list); i++)
++              if (refclk_list[i] == freq)
++                      return i;
++
++      dev_err(dev, "refclk: %ldHz do not support.\n", freq);
++      return -EINVAL;
++}
++
++static inline void sft_rtc_reg2time(struct rtc_time *tm, u32 reg)
++{
++      tm->tm_hour = bcd2bin(FIELD_GET(TIME_HOUR_MASK, reg));
++      tm->tm_min = bcd2bin(FIELD_GET(TIME_MIN_MASK, reg));
++      tm->tm_sec = bcd2bin(FIELD_GET(TIME_SEC_MASK, reg));
++}
++
++static inline void sft_rtc_reg2date(struct rtc_time *tm, u32 reg)
++{
++      tm->tm_year = bcd2bin(FIELD_GET(DATE_YEAR_MASK, reg)) + 100;
++      tm->tm_mon = bcd2bin(FIELD_GET(DATE_MON_MASK, reg)) - 1;
++      tm->tm_mday = bcd2bin(FIELD_GET(DATE_DAY_MASK, reg));
++}
++
++static inline u32 sft_rtc_time2reg(struct rtc_time *tm)
++{
++      return  FIELD_PREP(TIME_HOUR_MASK, bin2bcd(tm->tm_hour)) |
++              FIELD_PREP(TIME_MIN_MASK, bin2bcd(tm->tm_min)) |
++              FIELD_PREP(TIME_SEC_MASK, bin2bcd(tm->tm_sec));
++}
++
++static inline u32 sft_rtc_date2reg(struct rtc_time *tm)
++{
++      return  FIELD_PREP(DATE_YEAR_MASK, bin2bcd(tm->tm_year - 100)) |
++              FIELD_PREP(DATE_MON_MASK, bin2bcd(tm->tm_mon + 1)) |
++              FIELD_PREP(DATE_DAY_MASK, bin2bcd(tm->tm_mday));
++}
++
++static inline void sft_rtc_update_pulse(struct sft_rtc *srtc)
++{
++      u32 val;
++
++      val = readl(srtc->regs + SFT_RTC_IRQ_EVEVT);
++      val |= RTC_IRQ_EVT_UPDATE_PSE;
++      writel(val, srtc->regs + SFT_RTC_IRQ_EVEVT);
++}
++
++static irqreturn_t sft_rtc_irq_handler(int irq, void *data)
++{
++      struct sft_rtc *srtc = data;
++      struct timerqueue_node *next;
++      u32 irq_flags = 0;
++      u32 irq_mask = 0;
++      u32 val;
++      int ret = 0;
++
++      val = readl(srtc->regs + SFT_RTC_IRQ_EVEVT);
++      if (val & RTC_IRQ_CAL_START)
++              irq_mask |= RTC_IRQ_CAL_START;
++
++      if (val & RTC_IRQ_CAL_FINISH) {
++              irq_mask |= RTC_IRQ_CAL_FINISH;
++              complete(&srtc->cal_done);
++      }
++
++      if (val & RTC_IRQ_CMP)
++              irq_mask |= RTC_IRQ_CMP;
++
++      if (val & RTC_IRQ_1SEC) {
++              irq_flags |= RTC_PF;
++              irq_mask |= RTC_IRQ_1SEC;
++              complete(&srtc->onesec_done);
++      }
++
++      if (val & RTC_IRQ_ALAEM) {
++              irq_flags |= RTC_AF;
++              irq_mask |= RTC_IRQ_ALAEM;
++
++              next = timerqueue_getnext(&srtc->rtc_dev->timerqueue);
++              if (next == &srtc->rtc_dev->aie_timer.node)
++                      dev_info(&srtc->rtc_dev->dev, "alarm expires");
++      }
++
++      writel(irq_mask, srtc->regs + SFT_RTC_IRQ_EVEVT);
++
++      /* Wait interrupt flag clear */
++      ret = readl_poll_timeout_atomic(srtc->regs + SFT_RTC_IRQ_EVEVT, val,
++                                      (val & irq_mask) == 0, 0, INT_TIMEOUT_US);
++      if (ret)
++              dev_warn(&srtc->rtc_dev->dev, "fail to clear rtc interrupt flag\n");
++
++      if (irq_flags)
++              rtc_update_irq(srtc->rtc_dev, 1, irq_flags | RTC_IRQF);
++
++      return IRQ_HANDLED;
++}
++
++static int sft_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      u32 val;
++      int irq_1sec_state_start, irq_1sec_state_end;
++
++      /* If the RTC is disabled, assume the values are invalid */
++      if (!sft_rtc_get_enabled(srtc))
++              return -EINVAL;
++
++      irq_1sec_state_start =
++              (readl(srtc->regs + SFT_RTC_IRQ_STATUS) & RTC_IRQ_1SEC) == 0 ? 0 : 1;
++
++read_again:
++      val = readl(srtc->regs + SFT_RTC_TIME);
++      sft_rtc_reg2time(tm, val);
++
++      val = readl(srtc->regs + SFT_RTC_DATE);
++      sft_rtc_reg2date(tm, val);
++
++      if (irq_1sec_state_start == 0) {
++              irq_1sec_state_end =
++                      (readl(srtc->regs + SFT_RTC_IRQ_STATUS) & RTC_IRQ_1SEC) == 0 ? 0 : 1;
++              if (irq_1sec_state_end == 1) {
++                      irq_1sec_state_start = 1;
++                      goto read_again;
++              }
++      }
++
++      return 0;
++}
++
++static int sft_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      u32 val;
++      int ret;
++
++      val = sft_rtc_time2reg(tm);
++      writel(val, srtc->regs + SFT_RTC_CFG_TIME);
++
++      val = sft_rtc_date2reg(tm);
++      writel(val, srtc->regs + SFT_RTC_CFG_DATE);
++
++      /* Update pulse */
++      sft_rtc_update_pulse(srtc);
++
++      /* Ensure that data is fully written */
++      ret = wait_for_completion_interruptible_timeout(&srtc->onesec_done,
++                                                      usecs_to_jiffies(120));
++      if (ret) {
++              dev_warn(dev,
++                       "rtc wait for completion interruptible timeout.\n");
++      }
++      return 0;
++}
++
++static int sft_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++
++      return sft_rtc_irq_enable(srtc, RTC_IRQ_ALAEM, enabled);
++}
++
++static int sft_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      u32 val;
++
++      val = readl(srtc->regs + SFT_RTC_ACT_TIME);
++      sft_rtc_reg2time(&alarm->time, val);
++
++      val = readl(srtc->regs + SFT_RTC_ACT_DATE);
++      sft_rtc_reg2date(&alarm->time, val);
++
++      return 0;
++}
++
++static int sft_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      u32 val;
++
++      sft_rtc_alarm_irq_enable(dev, 0);
++
++      val = sft_rtc_time2reg(&alarm->time);
++      writel(val, srtc->regs + SFT_RTC_ACT_TIME);
++
++      val = sft_rtc_date2reg(&alarm->time);
++      writel(val, srtc->regs + SFT_RTC_ACT_DATE);
++
++      sft_rtc_alarm_irq_enable(dev, alarm->enabled);
++
++      return 0;
++}
++
++static int sft_rtc_get_offset(struct device *dev, long *offset)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      s64 tmp;
++      u32 val;
++
++      val = readl(srtc->regs + SFT_RTC_CAL_VALUE)
++                      & RTC_SW_CAL_VALUE_MASK;
++      val += 1;
++      /*
++       * the adjust val range is [0x0000-0xffff],
++       * the default val is 0x7fff (32768-1),mapping offset=0 ;
++       */
++      tmp = (s64)val - RTC_TICKS_PER_SEC;
++      tmp *= RTC_PPB_MULT;
++      tmp = div_s64(tmp, RTC_TICKS_PER_SEC);
++
++      /* Offset value operates in negative way, so swap sign */
++      *offset = -tmp;
++
++      return 0;
++}
++
++static int sft_rtc_set_offset(struct device *dev, long offset)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      s64 tmp;
++      u32 val;
++
++      tmp = offset * RTC_TICKS_PER_SEC;
++      tmp = div_s64(tmp, RTC_PPB_MULT);
++
++      tmp = RTC_TICKS_PER_SEC - tmp;
++      tmp -= 1;
++      if (tmp > RTC_SW_CAL_MAX || tmp < RTC_SW_CAL_MIN) {
++              dev_err(dev, "offset is out of range.\n");
++              return -EINVAL;
++      }
++
++      val = tmp & RTC_SW_CAL_VALUE_MASK;
++      /* set software calibration value */
++      writel(val, srtc->regs + SFT_RTC_SW_CAL_VALUE);
++
++      /* set CFG_RTC-cal_sel to select calibretion by software. */
++      sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_SW);
++
++      return 0;
++}
++
++static __maybe_unused int
++sft_rtc_hw_adjustment(struct device *dev, unsigned int enable)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++      u32 val;
++
++      if (srtc->hw_cal_map <= 0) {
++              dev_err(dev, "fail to get cal-clock-freq.\n");
++              return -EFAULT;
++      }
++
++      if (enable) {
++              sft_rtc_irq_enable(srtc, RTC_IRQ_CAL_FINISH, true);
++
++              /* Set reference clock frequency value */
++              val = readl(srtc->regs + SFT_RTC_HW_CAL_CFG);
++              val |= (srtc->hw_cal_map << RTC_HW_CAL_FRQ_SEL_SHIFT);
++              writel(val, srtc->regs + SFT_RTC_HW_CAL_CFG);
++
++              /* Set CFG_RTC-cal_sel to select calibretion by hardware. */
++              sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_HW);
++
++              /* Set CFG_RTC-cal_en_hw to launch hardware calibretion.*/
++              sft_rtc_set_cal_hw_enable(srtc, true);
++
++              wait_for_completion_interruptible_timeout(&srtc->cal_done,
++                                                        usecs_to_jiffies(100));
++
++              sft_rtc_irq_enable(srtc, RTC_IRQ_CAL_FINISH, false);
++      } else {
++              sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_SW);
++              sft_rtc_set_cal_hw_enable(srtc, false);
++      }
++
++      return 0;
++}
++
++static int sft_rtc_get_cal_clk(struct device *dev, struct sft_rtc *srtc)
++{
++      struct device_node *np = dev->of_node;
++      unsigned long cal_clk_freq;
++      u32 freq;
++      int ret;
++
++      srtc->cal_clk = devm_clk_get(dev, "cal_clk");
++      if (IS_ERR(srtc->cal_clk))
++              return PTR_ERR(srtc->cal_clk);
++
++      clk_prepare_enable(srtc->cal_clk);
++
++      cal_clk_freq = clk_get_rate(srtc->cal_clk);
++      if (!cal_clk_freq) {
++              dev_warn(dev,
++                       "get rate failed, next try to get from dts.\n");
++              ret = of_property_read_u32(np, "rtc,cal-clock-freq", &freq);
++              if (!ret) {
++                      cal_clk_freq = (u64)freq;
++              } else {
++                      dev_err(dev,
++                              "Need rtc,cal-clock-freq define in dts.\n");
++                      goto err_disable_cal_clk;
++              }
++      }
++
++      srtc->hw_cal_map = sft_rtc_get_hw_calclk(dev, cal_clk_freq);
++      if (srtc->hw_cal_map < 0) {
++              ret = srtc->hw_cal_map;
++              goto err_disable_cal_clk;
++      }
++
++      return 0;
++
++err_disable_cal_clk:
++      clk_disable_unprepare(srtc->cal_clk);
++
++      return ret;
++}
++
++static int sft_rtc_get_irq(struct platform_device *pdev, struct sft_rtc *srtc)
++{
++      int ret;
++
++      srtc->rtc_irq = platform_get_irq_byname(pdev, "rtc");
++      if (srtc->rtc_irq < 0)
++              return -EINVAL;
++
++      ret = devm_request_irq(&pdev->dev, srtc->rtc_irq,
++                             sft_rtc_irq_handler, 0,
++                              KBUILD_MODNAME, srtc);
++      if (ret)
++              dev_err(&pdev->dev, "Failed to request interrupt, %d\n", ret);
++
++      return ret;
++}
++
++static const struct rtc_class_ops starfive_rtc_ops = {
++      .read_time              = sft_rtc_read_time,
++      .set_time               = sft_rtc_set_time,
++      .read_alarm             = sft_rtc_read_alarm,
++      .set_alarm              = sft_rtc_set_alarm,
++      .alarm_irq_enable       = sft_rtc_alarm_irq_enable,
++      .set_offset             = sft_rtc_set_offset,
++      .read_offset            = sft_rtc_get_offset,
++};
++
++static int sft_rtc_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct sft_rtc *srtc;
++      struct rtc_time tm;
++      struct irq_desc *desc;
++      int ret;
++
++      srtc = devm_kzalloc(dev, sizeof(*srtc), GFP_KERNEL);
++      if (!srtc)
++              return -ENOMEM;
++
++      srtc->regs = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(srtc->regs))
++              return PTR_ERR(srtc->regs);
++
++      srtc->pclk = devm_clk_get(dev, "pclk");
++      if (IS_ERR(srtc->pclk)) {
++              ret = PTR_ERR(srtc->pclk);
++              dev_err(dev,
++                      "Failed to retrieve the peripheral clock, %d\n", ret);
++              return ret;
++      }
++
++      srtc->rst_array = devm_reset_control_array_get_exclusive(dev);
++      if (IS_ERR(srtc->rst_array)) {
++              ret = PTR_ERR(srtc->rst_array);
++              dev_err(dev,
++                      "Failed to retrieve the rtc reset, %d\n", ret);
++              return ret;
++      }
++
++      init_completion(&srtc->cal_done);
++      init_completion(&srtc->onesec_done);
++
++      ret = clk_prepare_enable(srtc->pclk);
++      if (ret) {
++              dev_err(dev,
++                      "Failed to enable the peripheral clock, %d\n", ret);
++              return ret;
++      }
++
++      ret = sft_rtc_get_cal_clk(dev, srtc);
++      if (ret)
++              goto err_disable_pclk;
++
++      ret = reset_control_deassert(srtc->rst_array);
++      if (ret) {
++              dev_err(dev,
++                      "Failed to deassert rtc resets, %d\n", ret);
++              goto err_disable_cal_clk;
++      }
++
++      ret = sft_rtc_get_irq(pdev, srtc);
++      if (ret)
++              goto err_disable_cal_clk;
++
++      srtc->rtc_dev = devm_rtc_allocate_device(dev);
++      if (IS_ERR(srtc->rtc_dev))
++              return PTR_ERR(srtc->rtc_dev);
++
++      platform_set_drvdata(pdev, srtc);
++
++      /* The RTC supports 01.01.2001 - 31.12.2099 */
++      srtc->rtc_dev->range_min = mktime64(2001,  1,  1,  0,  0,  0);
++      srtc->rtc_dev->range_max = mktime64(2099, 12, 31, 23, 59, 59);
++
++      srtc->rtc_dev->ops = &starfive_rtc_ops;
++      device_init_wakeup(dev, true);
++
++      desc = irq_to_desc(srtc->rtc_irq);
++      irq_desc_get_chip(desc)->flags = IRQCHIP_SKIP_SET_WAKE;
++
++      /* Always use 24-hour mode and keep the RTC values */
++      sft_rtc_set_mode(srtc, RTC_HOUR_MODE_24H);
++
++      sft_rtc_set_enabled(srtc, true);
++
++      if (device_property_read_bool(dev, "rtc,hw-adjustment"))
++              sft_rtc_hw_adjustment(dev, true);
++
++      /*
++       * If rtc time is out of supported range, reset it to the minimum time.
++       * notice that, actual year = 1900 + tm.tm_year
++       *              actual month = 1 + tm.tm_mon
++       */
++      sft_rtc_read_time(dev, &tm);
++      if (tm.tm_year < 101 || tm.tm_year > 199 || tm.tm_mon < 0 || tm.tm_mon > 11 ||
++          tm.tm_mday < 1 || tm.tm_mday > 31 || tm.tm_hour < 0 || tm.tm_hour > 23 ||
++          tm.tm_min < 0 || tm.tm_min > 59 || tm.tm_sec < 0 || tm.tm_sec > 59) {
++              rtc_time64_to_tm(srtc->rtc_dev->range_min, &tm);
++              sft_rtc_set_time(dev, &tm);
++      }
++
++      ret = devm_rtc_register_device(srtc->rtc_dev);
++      if (ret)
++              goto err_disable_wakeup;
++
++      return 0;
++
++err_disable_wakeup:
++      device_init_wakeup(dev, false);
++
++err_disable_cal_clk:
++      clk_disable_unprepare(srtc->cal_clk);
++
++err_disable_pclk:
++      clk_disable_unprepare(srtc->pclk);
++
++      return ret;
++}
++
++static void sft_rtc_remove(struct platform_device *pdev)
++{
++      struct sft_rtc *srtc = platform_get_drvdata(pdev);
++
++      sft_rtc_alarm_irq_enable(&pdev->dev, 0);
++      device_init_wakeup(&pdev->dev, 0);
++
++      clk_disable_unprepare(srtc->pclk);
++      clk_disable_unprepare(srtc->cal_clk);
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int sft_rtc_suspend(struct device *dev)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++
++      if (device_may_wakeup(dev))
++              enable_irq_wake(srtc->rtc_irq);
++
++      return 0;
++}
++
++static int sft_rtc_resume(struct device *dev)
++{
++      struct sft_rtc *srtc = dev_get_drvdata(dev);
++
++      if (device_may_wakeup(dev))
++              disable_irq_wake(srtc->rtc_irq);
++
++      return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(sft_rtc_pm_ops, sft_rtc_suspend, sft_rtc_resume);
++
++static const struct of_device_id sft_rtc_of_match[] = {
++      { .compatible = "starfive,jh7110-rtc" },
++      { },
++};
++MODULE_DEVICE_TABLE(of, sft_rtc_of_match);
++
++static struct platform_driver starfive_rtc_driver = {
++      .driver = {
++              .name = "starfive-rtc",
++              .of_match_table = sft_rtc_of_match,
++              .pm   = &sft_rtc_pm_ops,
++      },
++      .probe = sft_rtc_probe,
++      .remove = sft_rtc_remove,
++};
++module_platform_driver(starfive_rtc_driver);
++
++MODULE_AUTHOR("Samin Guo <samin.guo@starfivetech.com>");
++MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
++MODULE_DESCRIPTION("StarFive RTC driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:starfive-rtc");
diff --git a/target/linux/starfive/patches-6.12/0009-uart-8250-Add-dw-auto-flow-ctrl-support.patch b/target/linux/starfive/patches-6.12/0009-uart-8250-Add-dw-auto-flow-ctrl-support.patch
new file mode 100644 (file)
index 0000000..9251558
--- /dev/null
@@ -0,0 +1,98 @@
+From 20c14bbdff9e3be2ddbeffa266f08bae04216e63 Mon Sep 17 00:00:00 2001
+From: Minda Chen <minda.chen@starfivetech.com>
+Date: Sun, 25 Jun 2023 09:40:29 +0800
+Subject: [PATCH 09/55] uart: 8250: Add dw auto flow ctrl support
+
+Add designeware 8250 auto flow ctrl support. Enable
+it by add auto-flow-control in dts.
+
+Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
+---
+ drivers/tty/serial/8250/8250_core.c |  2 ++
+ drivers/tty/serial/8250/8250_dw.c   |  3 +++
+ drivers/tty/serial/8250/8250_port.c | 14 +++++++++++++-
+ include/linux/serial_8250.h         |  1 +
+ include/uapi/linux/serial_core.h    |  2 ++
+ 5 files changed, 21 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/8250/8250_core.c
++++ b/drivers/tty/serial/8250/8250_core.c
+@@ -810,6 +810,8 @@ int serial8250_register_8250_port(const
+                       uart->dl_read = up->dl_read;
+               if (up->dl_write)
+                       uart->dl_write = up->dl_write;
++              if (up->probe)
++                      uart->probe = up->probe;
+               if (uart->port.type != PORT_8250_CIR) {
+                       if (uart_console_registered(&uart->port))
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -594,6 +594,9 @@ static int dw8250_probe(struct platform_
+               data->msr_mask_off |= UART_MSR_TERI;
+       }
++      if (device_property_read_bool(dev, "auto-flow-control"))
++              up->probe |= UART_PROBE_AFE;
++
+       /* If there is separate baudclk, get the rate from it. */
+       data->clk = devm_clk_get_optional_enabled(dev, "baudclk");
+       if (data->clk == NULL)
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -319,6 +319,14 @@ static const struct serial8250_config ua
+               .rxtrig_bytes   = {1, 8, 16, 30},
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
++      [PORT_16550A_AFE] = {
++              .name           = "16550A_AFE",
++              .fifo_size      = 16,
++              .tx_loadsz      = 16,
++              .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
++              .rxtrig_bytes   = {1, 4, 8, 14},
++              .flags          = UART_CAP_FIFO | UART_CAP_AFE,
++      },
+ };
+ /* Uart divisor latch read */
+@@ -1124,6 +1132,11 @@ static void autoconfig_16550a(struct uar
+               up->port.type = PORT_U6_16550A;
+               up->capabilities |= UART_CAP_AFE;
+       }
++
++      if ((up->port.type == PORT_16550A) && (up->probe & UART_PROBE_AFE)) {
++              up->port.type = PORT_16550A_AFE;
++              up->capabilities |= UART_CAP_AFE;
++      }
+ }
+ /*
+@@ -2774,7 +2787,6 @@ serial8250_do_set_termios(struct uart_po
+               if (termios->c_cflag & CRTSCTS)
+                       up->mcr |= UART_MCR_AFE;
+       }
+-
+       /*
+        * Update the per-port timeout.
+        */
+--- a/include/linux/serial_8250.h
++++ b/include/linux/serial_8250.h
+@@ -141,6 +141,7 @@ struct uart_8250_port {
+       unsigned char           probe;
+       struct mctrl_gpios      *gpios;
+ #define UART_PROBE_RSA        (1 << 0)
++#define UART_PROBE_AFE  (1 << 1)
+       /*
+        * Some bits in registers are cleared on a read, so they must
+--- a/include/uapi/linux/serial_core.h
++++ b/include/uapi/linux/serial_core.h
+@@ -231,6 +231,8 @@
+ /* Sunplus UART */
+ #define PORT_SUNPLUS  123
++#define PORT_16550A_AFE       124
++
+ /* Generic type identifier for ports which type is not important to userspace. */
+ #define PORT_GENERIC  (-1)
diff --git a/target/linux/starfive/patches-6.12/0010-uart-8250-add-reset-operation-in-runtime-PM.patch b/target/linux/starfive/patches-6.12/0010-uart-8250-add-reset-operation-in-runtime-PM.patch
new file mode 100644 (file)
index 0000000..452dfad
--- /dev/null
@@ -0,0 +1,32 @@
+From ee5aab642d8a99a7a48d9b30f098ca2a97f463c4 Mon Sep 17 00:00:00 2001
+From: William Qiu <william.qiu@starfivetech.com>
+Date: Wed, 20 Sep 2023 17:19:59 +0800
+Subject: [PATCH 10/55] uart: 8250: add reset operation in runtime PM
+
+add reset operation in runtime PM
+
+Signed-off-by: William Qiu <william.qiu@starfivetech.com>
+---
+ drivers/tty/serial/8250/8250_dw.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -712,6 +712,8 @@ static int dw8250_runtime_suspend(struct
+ {
+       struct dw8250_data *data = dev_get_drvdata(dev);
++      reset_control_assert(data->rst);
++
+       clk_disable_unprepare(data->clk);
+       clk_disable_unprepare(data->pclk);
+@@ -734,6 +736,8 @@ static int dw8250_runtime_resume(struct
+               return ret;
+       }
++      reset_control_deassert(data->rst);
++
+       return 0;
+ }
diff --git a/target/linux/starfive/patches-6.12/0011-CAN-starfive-Add-CAN-engine-support.patch b/target/linux/starfive/patches-6.12/0011-CAN-starfive-Add-CAN-engine-support.patch
new file mode 100644 (file)
index 0000000..a581e47
--- /dev/null
@@ -0,0 +1,1316 @@
+From 94de8add412dffdfa0389c6ae0f6aaad64d34fcd Mon Sep 17 00:00:00 2001
+From: William Qiu <william.qiu@starfivetech.com>
+Date: Thu, 15 Jun 2023 20:15:25 +0800
+Subject: [PATCH 11/55] CAN: starfive - Add CAN engine support
+
+Adding device probe StarFive CAN module.
+
+Signed-off-by: William Qiu <william.qiu@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/net/can/Kconfig      |    5 +
+ drivers/net/can/Makefile     |    2 +
+ drivers/net/can/ipms_canfd.c | 1273 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 1280 insertions(+)
+ create mode 100644 drivers/net/can/ipms_canfd.c
+
+--- a/drivers/net/can/Kconfig
++++ b/drivers/net/can/Kconfig
+@@ -216,6 +216,11 @@ config CAN_XILINXCAN
+         Xilinx CAN driver. This driver supports both soft AXI CAN IP and
+         Zynq CANPS IP.
++config IPMS_CAN
++      tristate "IPMS CAN"
++      help
++        IPMS CANFD driver. This driver supports IPMS CANFD IP.
++
+ source "drivers/net/can/c_can/Kconfig"
+ source "drivers/net/can/cc770/Kconfig"
+ source "drivers/net/can/ctucanfd/Kconfig"
+--- a/drivers/net/can/Makefile
++++ b/drivers/net/can/Makefile
+@@ -33,5 +33,7 @@ obj-$(CONFIG_CAN_SJA1000)    += sja1000/
+ obj-$(CONFIG_CAN_SUN4I)               += sun4i_can.o
+ obj-$(CONFIG_CAN_TI_HECC)     += ti_hecc.o
+ obj-$(CONFIG_CAN_XILINXCAN)   += xilinx_can.o
++obj-$(CONFIG_IPMS_CAN)                += ipms_canfd.o
++ccflags-$(CONFIG_IPMS_CAN) := -Wno-error=missing-prototypes
+ subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
+--- /dev/null
++++ b/drivers/net/can/ipms_canfd.c
+@@ -0,0 +1,1273 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * StarFive Controller Area Network Host Controller Driver
++ *
++ * Copyright (c) 2022 StarFive Technology Co., Ltd.
++ */
++
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/can/dev.h>
++#include <linux/can/error.h>
++#include <linux/pm_runtime.h>
++#include <linux/of_device.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
++
++#define DRIVER_NAME "ipms_canfd"
++
++/* CAN registers set */
++enum canfd_device_reg {
++      CANFD_RUBF_OFFSET           =   0x00,   /* Receive Buffer Registers 0x00-0x4f */
++      CANFD_RUBF_ID_OFFSET        =   0x00,
++      CANFD_RBUF_CTL_OFFSET       =   0x04,
++      CANFD_RBUF_DATA_OFFSET      =   0x08,
++      CANFD_TBUF_OFFSET           =   0x50,   /* Transmit Buffer Registers 0x50-0x97 */
++      CANFD_TBUF_ID_OFFSET        =   0x50,
++      CANFD_TBUF_CTL_OFFSET       =   0x54,
++      CANFD_TBUF_DATA_OFFSET      =   0x58,
++      CANFD_TTS_OFFSET            =   0x98,   /* Transmission Time Stamp 0x98-0x9f */
++      CANFD_CFG_STAT_OFFSET       =   0xa0,
++      CANFD_TCMD_OFFSET           =   0xa1,
++      CANFD_TCTRL_OFFSET          =   0xa2,
++      CANFD_RCTRL_OFFSET          =   0xa3,
++      CANFD_RTIE_OFFSET           =   0xa4,
++      CANFD_RTIF_OFFSET           =   0xa5,
++      CANFD_ERRINT_OFFSET         =   0xa6,
++      CANFD_LIMIT_OFFSET          =   0xa7,
++      CANFD_S_SEG_1_OFFSET        =   0xa8,
++      CANFD_S_SEG_2_OFFSET        =   0xa9,
++      CANFD_S_SJW_OFFSET          =   0xaa,
++      CANFD_S_PRESC_OFFSET        =   0xab,
++      CANFD_F_SEG_1_OFFSET        =   0xac,
++      CANFD_F_SEG_2_OFFSET        =   0xad,
++      CANFD_F_SJW_OFFSET          =   0xae,
++      CANFD_F_PRESC_OFFSET        =   0xaf,
++      CANFD_EALCAP_OFFSET         =   0xb0,
++      CANFD_RECNT_OFFSET          =   0xb2,
++      CANFD_TECNT_OFFSET          =   0xb3,
++};
++
++enum canfd_reg_bitchange {
++      CAN_FD_SET_RST_MASK         =   0x80,   /* Set Reset Bit */
++      CAN_FD_OFF_RST_MASK         =   0x7f,   /* Reset Off Bit */
++      CAN_FD_SET_FULLCAN_MASK     =   0x10,   /* set TTTBM as 1->full TTCAN mode */
++      CAN_FD_OFF_FULLCAN_MASK     =   0xef,   /* set TTTBM as 0->separate PTB and STB mode */
++      CAN_FD_SET_FIFO_MASK        =   0x20,   /* set TSMODE as 1->FIFO mode */
++      CAN_FD_OFF_FIFO_MASK        =   0xdf,   /* set TSMODE as 0->Priority mode */
++      CAN_FD_SET_TSONE_MASK       =   0x04,
++      CAN_FD_OFF_TSONE_MASK       =   0xfb,
++      CAN_FD_SET_TSALL_MASK       =   0x02,
++      CAN_FD_OFF_TSALL_MASK       =   0xfd,
++      CAN_FD_LBMEMOD_MASK         =   0x40,   /* set loop back mode, external */
++      CAN_FD_LBMIMOD_MASK         =   0x20,   /* set loopback internal mode */
++      CAN_FD_SET_BUSOFF_MASK      =   0x01,
++      CAN_FD_OFF_BUSOFF_MASK      =   0xfe,
++      CAN_FD_SET_TTSEN_MASK       =   0x80,   /* set ttsen, tts update enable */
++      CAN_FD_SET_BRS_MASK         =   0x10,   /* can fd Bit Rate Switch mask */
++      CAN_FD_OFF_BRS_MASK         =   0xef,
++      CAN_FD_SET_EDL_MASK         =   0x20,   /* Extended Data Length */
++      CAN_FD_OFF_EDL_MASK         =   0xdf,
++      CAN_FD_SET_DLC_MASK         =   0x0f,
++      CAN_FD_SET_TENEXT_MASK      =   0x40,
++      CAN_FD_SET_IDE_MASK         =   0x80,
++      CAN_FD_OFF_IDE_MASK         =   0x7f,
++      CAN_FD_SET_RTR_MASK         =   0x40,
++      CAN_FD_OFF_RTR_MASK         =   0xbf,
++      CAN_FD_INTR_ALL_MASK        =   0xff,   /* all interrupts enable mask */
++      CAN_FD_SET_RIE_MASK         =   0x80,
++      CAN_FD_OFF_RIE_MASK         =   0x7f,
++      CAN_FD_SET_RFIE_MASK        =   0x20,
++      CAN_FD_OFF_RFIE_MASK        =   0xdf,
++      CAN_FD_SET_RAFIE_MASK       =   0x10,
++      CAN_FD_OFF_RAFIE_MASK       =   0xef,
++      CAN_FD_SET_EIE_MASK         =   0x02,
++      CAN_FD_OFF_EIE_MASK         =   0xfd,
++      CAN_FD_TASCTIVE_MASK        =   0x02,
++      CAN_FD_RASCTIVE_MASK        =   0x04,
++      CAN_FD_SET_TBSEL_MASK       =   0x80,   /* message writen in STB */
++      CAN_FD_OFF_TBSEL_MASK       =   0x7f,   /* message writen in PTB */
++      CAN_FD_SET_STBY_MASK        =   0x20,
++      CAN_FD_OFF_STBY_MASK        =   0xdf,
++      CAN_FD_SET_TPE_MASK         =   0x10,   /* Transmit primary enable */
++      CAN_FD_SET_TPA_MASK         =   0x08,
++      CAN_FD_SET_SACK_MASK        =   0x80,
++      CAN_FD_SET_RREL_MASK        =   0x10,
++      CAN_FD_RSTAT_NOT_EMPTY_MASK =   0x03,
++      CAN_FD_SET_RIF_MASK         =   0x80,
++      CAN_FD_OFF_RIF_MASK         =   0x7f,
++      CAN_FD_SET_RAFIF_MASK       =   0x10,
++      CAN_FD_SET_RFIF_MASK        =   0x20,
++      CAN_FD_SET_TPIF_MASK        =   0x08,   /* Transmission Primary Interrupt Flag */
++      CAN_FD_SET_TSIF_MASK        =   0x04,
++      CAN_FD_SET_EIF_MASK         =   0x02,
++      CAN_FD_SET_AIF_MASK         =   0x01,
++      CAN_FD_SET_EWARN_MASK       =   0x80,
++      CAN_FD_SET_EPASS_MASK       =   0x40,
++      CAN_FD_SET_EPIE_MASK        =   0x20,
++      CAN_FD_SET_EPIF_MASK        =   0x10,
++      CAN_FD_SET_ALIE_MASK        =   0x08,
++      CAN_FD_SET_ALIF_MASK        =   0x04,
++      CAN_FD_SET_BEIE_MASK        =   0x02,
++      CAN_FD_SET_BEIF_MASK        =   0x01,
++      CAN_FD_OFF_EPIE_MASK        =   0xdf,
++      CAN_FD_OFF_BEIE_MASK        =   0xfd,
++      CAN_FD_SET_AFWL_MASK        =   0x40,
++      CAN_FD_SET_EWL_MASK         =   0x0b,
++      CAN_FD_SET_KOER_MASK        =   0xe0,
++      CAN_FD_SET_BIT_ERROR_MASK   =   0x20,
++      CAN_FD_SET_FORM_ERROR_MASK  =   0x40,
++      CAN_FD_SET_STUFF_ERROR_MASK =   0x60,
++      CAN_FD_SET_ACK_ERROR_MASK   =   0x80,
++      CAN_FD_SET_CRC_ERROR_MASK   =   0xa0,
++      CAN_FD_SET_OTH_ERROR_MASK   =   0xc0,
++};
++
++/* seg1,seg2,sjw,prescaler all have 8 bits */
++#define BITS_OF_BITTIMING_REG         8
++
++/* in can_bittiming strucure every field has 32 bits---->u32 */
++#define FBITS_IN_BITTIMING_STR                32
++#define SEG_1_SHIFT                   0
++#define SEG_2_SHIFT                   8
++#define SJW_SHIFT                     16
++#define PRESC_SHIFT                   24
++
++/* TTSEN bit used for 32 bit register read or write */
++#define TTSEN_8_32_SHIFT              24
++#define RTR_32_8_SHIFT                        24
++
++/* transmit mode */
++#define XMIT_FULL                     0
++#define XMIT_SEP_FIFO                 1
++#define XMIT_SEP_PRIO                 2
++#define XMIT_PTB_MODE                 3
++
++enum  IPMS_CAN_TYPE {
++      IPMS_CAN_TYPY_CAN       = 0,
++      IPMS_CAN_TYPE_CANFD,
++};
++
++struct ipms_canfd_priv {
++      struct can_priv can;
++      struct napi_struct napi;
++      struct device *dev;
++      struct regmap *reg_syscon;
++      void __iomem *reg_base;
++      u32 (*read_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg);
++      void (*write_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg, u32 val);
++      struct clk *can_clk;
++      u32 tx_mode;
++      struct reset_control *resets;
++      struct clk_bulk_data *clks;
++      int nr_clks;
++      u32 can_or_canfd;
++};
++
++static struct can_bittiming_const canfd_bittiming_const = {
++      .name = DRIVER_NAME,
++      .tseg1_min = 2,
++      .tseg1_max = 16,
++      .tseg2_min = 2,
++      .tseg2_max = 8,
++      .sjw_max = 4,
++      .brp_min = 1,
++      .brp_max = 512,
++      .brp_inc = 1,
++
++};
++
++static struct can_bittiming_const canfd_data_bittiming_const = {
++      .name = DRIVER_NAME,
++      .tseg1_min = 1,
++      .tseg1_max = 16,
++      .tseg2_min = 2,
++      .tseg2_max = 8,
++      .sjw_max = 8,
++      .brp_min = 1,
++      .brp_max = 512,
++      .brp_inc = 1,
++};
++
++static void canfd_write_reg_le(const struct ipms_canfd_priv *priv,
++                              enum canfd_device_reg reg, u32 val)
++{
++      iowrite32(val, priv->reg_base + reg);
++}
++
++static u32 canfd_read_reg_le(const struct ipms_canfd_priv *priv,
++                              enum canfd_device_reg reg)
++{
++      return ioread32(priv->reg_base + reg);
++}
++
++static inline unsigned char can_ioread8(const void  *addr)
++{
++      void  *addr_down;
++      union val {
++              u8 val_8[4];
++              u32 val_32;
++      } val;
++      u32 offset = 0;
++
++      addr_down = (void  *)ALIGN_DOWN((unsigned long)addr, 4);
++      offset = addr - addr_down;
++      val.val_32 = ioread32(addr_down);
++      return val.val_8[offset];
++}
++
++static inline void can_iowrite8(unsigned char value, void  *addr)
++{
++      void  *addr_down;
++      union val {
++              u8 val_8[4];
++              u32 val_32;
++      } val;
++      u8 offset = 0;
++
++      addr_down = (void *)ALIGN_DOWN((unsigned long)addr, 4);
++      offset = addr - addr_down;
++      val.val_32 = ioread32(addr_down);
++      val.val_8[offset] = value;
++      iowrite32(val.val_32, addr_down);
++}
++
++static void canfd_reigister_set_bit(const struct ipms_canfd_priv *priv,
++                                      enum canfd_device_reg reg,
++                                      enum canfd_reg_bitchange set_mask)
++{
++      void  *addr_down;
++      union val {
++              u8 val_8[4];
++              u32 val_32;
++      } val;
++      u8 offset = 0;
++
++      addr_down = (void *)ALIGN_DOWN((unsigned long)(priv->reg_base + reg), 4);
++      offset = (priv->reg_base + reg) - addr_down;
++      val.val_32 = ioread32(addr_down);
++      val.val_8[offset] |= set_mask;
++      iowrite32(val.val_32, addr_down);
++}
++
++static void canfd_reigister_off_bit(const struct ipms_canfd_priv *priv,
++                                      enum canfd_device_reg reg,
++                                      enum canfd_reg_bitchange set_mask)
++{
++      void  *addr_down;
++      union val {
++              u8 val_8[4];
++              u32 val_32;
++      } val;
++      u8 offset = 0;
++
++      addr_down = (void *)ALIGN_DOWN((unsigned long)(priv->reg_base + reg), 4);
++      offset = (priv->reg_base + reg) - addr_down;
++      val.val_32 = ioread32(addr_down);
++      val.val_8[offset] &= set_mask;
++      iowrite32(val.val_32, addr_down);
++}
++
++static int canfd_device_driver_bittime_configuration(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      struct can_bittiming *bt = &priv->can.bittiming;
++      struct can_bittiming *dbt = &priv->can.data_bittiming;
++      u32 reset_test, bittiming_temp, dat_bittiming;
++
++      reset_test = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
++
++      if (!(reset_test & CAN_FD_SET_RST_MASK)) {
++              netdev_alert(ndev, "Not in reset mode, cannot set bit timing\n");
++              return -EPERM;
++      }
++
++      bittiming_temp = ((bt->phase_seg1 + bt->prop_seg + 1 - 2) << SEG_1_SHIFT) |
++                       ((bt->phase_seg2 - 1) << SEG_2_SHIFT) |
++                       ((bt->sjw - 1) << SJW_SHIFT) |
++                       ((bt->brp - 1) << PRESC_SHIFT);
++
++      /* Check the bittime parameter */
++      if ((((int)(bt->phase_seg1 + bt->prop_seg + 1) - 2) < 0) ||
++              (((int)(bt->phase_seg2) - 1) < 0) ||
++              (((int)(bt->sjw) - 1) < 0) ||
++              (((int)(bt->brp) - 1) < 0))
++              return -EINVAL;
++
++      priv->write_reg(priv, CANFD_S_SEG_1_OFFSET, bittiming_temp);
++
++      if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) {
++              dat_bittiming = ((dbt->phase_seg1 + dbt->prop_seg + 1 - 2) << SEG_1_SHIFT) |
++                              ((dbt->phase_seg2 - 1) << SEG_2_SHIFT) |
++                              ((dbt->sjw - 1) << SJW_SHIFT) |
++                              ((dbt->brp - 1) << PRESC_SHIFT);
++
++              if ((((int)(dbt->phase_seg1 + dbt->prop_seg + 1) - 2) < 0) ||
++                      (((int)(dbt->phase_seg2) - 1) < 0) ||
++                      (((int)(dbt->sjw) - 1) < 0) ||
++                      (((int)(dbt->brp) - 1) < 0))
++                      return -EINVAL;
++
++              priv->write_reg(priv, CANFD_F_SEG_1_OFFSET, dat_bittiming);
++      }
++
++      canfd_reigister_off_bit(priv, CANFD_CFG_STAT_OFFSET, CAN_FD_OFF_RST_MASK);
++
++      netdev_dbg(ndev, "Slow bit rate: %08x\n", priv->read_reg(priv, CANFD_S_SEG_1_OFFSET));
++      netdev_dbg(ndev, "Fast bit rate: %08x\n", priv->read_reg(priv, CANFD_F_SEG_1_OFFSET));
++
++      return 0;
++}
++
++int canfd_get_freebuffer(struct ipms_canfd_priv *priv)
++{
++      /* Get next transmit buffer */
++      canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_TENEXT_MASK);
++
++      if (can_ioread8(priv->reg_base + CANFD_TCTRL_OFFSET) & CAN_FD_SET_TENEXT_MASK)
++              return -1;
++
++      return 0;
++}
++
++static void canfd_tx_interrupt(struct net_device *ndev, u8 isr)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++
++      /* wait till transmission of the PTB or STB finished */
++      while (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
++              if (isr & CAN_FD_SET_TPIF_MASK)
++                      canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_TPIF_MASK);
++
++              if (isr & CAN_FD_SET_TSIF_MASK)
++                      canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_TSIF_MASK);
++
++              isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
++      }
++      netif_wake_queue(ndev);
++}
++
++static int can_rx(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      struct net_device_stats *stats = &ndev->stats;
++      struct can_frame *cf;
++      struct sk_buff *skb;
++      u32 can_id;
++      u8  dlc, control, rx_status;
++
++      rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++
++      if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
++              return 0;
++      control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
++      can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
++      dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
++
++      skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
++      if (!skb) {
++              stats->rx_dropped++;
++              return 0;
++      }
++      cf->can_dlc = can_cc_dlc2len(dlc);
++
++      /* change the CANFD id into socketcan id format */
++      if (control & CAN_FD_SET_IDE_MASK) {
++              cf->can_id = can_id;
++              cf->can_id |= CAN_EFF_FLAG;
++      } else {
++              cf->can_id = can_id;
++              cf->can_id &= (~CAN_EFF_FLAG);
++      }
++
++      if (control & CAN_FD_SET_RTR_MASK)
++              cf->can_id |= CAN_RTR_FLAG;
++
++      if (!(control & CAN_FD_SET_RTR_MASK)) {
++              *((u32 *)(cf->data + 0)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET);
++              *((u32 *)(cf->data + 4)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + 4);
++      }
++
++      canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK);
++      stats->rx_bytes += can_fd_dlc2len(cf->can_dlc);
++      stats->rx_packets++;
++      netif_receive_skb(skb);
++
++      return 1;
++}
++
++static int canfd_rx(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      struct net_device_stats *stats = &ndev->stats;
++      struct canfd_frame *cf;
++      struct sk_buff *skb;
++      u32 can_id;
++      u8  dlc, control, rx_status;
++      int i;
++
++      rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++
++      if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
++              return 0;
++      control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
++      can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
++      dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
++
++      if (control & CAN_FD_SET_EDL_MASK)
++              /* allocate sk_buffer for canfd frame */
++              skb = alloc_canfd_skb(ndev, &cf);
++      else
++              /* allocate sk_buffer for can frame */
++              skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
++
++      if (!skb) {
++              stats->rx_dropped++;
++              return 0;
++      }
++
++      /* change the CANFD or CAN2.0 data into socketcan data format */
++      if (control & CAN_FD_SET_EDL_MASK)
++              cf->len = can_fd_dlc2len(dlc);
++      else
++              cf->len = can_cc_dlc2len(dlc);
++
++      /* change the CANFD id into socketcan id format */
++      if (control & CAN_FD_SET_EDL_MASK) {
++              cf->can_id = can_id;
++              if (control & CAN_FD_SET_IDE_MASK)
++                      cf->can_id |= CAN_EFF_FLAG;
++              else
++                      cf->can_id &= (~CAN_EFF_FLAG);
++      } else {
++              cf->can_id = can_id;
++              if (control & CAN_FD_SET_IDE_MASK)
++                      cf->can_id |= CAN_EFF_FLAG;
++              else
++                      cf->can_id &= (~CAN_EFF_FLAG);
++
++              if (control & CAN_FD_SET_RTR_MASK)
++                      cf->can_id |= CAN_RTR_FLAG;
++      }
++
++      /* CANFD frames handed over to SKB */
++      if (control & CAN_FD_SET_EDL_MASK) {
++              for (i = 0; i < cf->len; i += 4)
++                      *((u32 *)(cf->data + i)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + i);
++      } else {
++              /* skb reads the received datas, if the RTR bit not set */
++              if (!(control & CAN_FD_SET_RTR_MASK)) {
++                      *((u32 *)(cf->data + 0)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET);
++                      *((u32 *)(cf->data + 4)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + 4);
++              }
++      }
++
++      canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK);
++
++      stats->rx_bytes += cf->len;
++      stats->rx_packets++;
++      netif_receive_skb(skb);
++
++      return 1;
++}
++
++static int canfd_rx_poll(struct napi_struct *napi, int quota)
++{
++      struct net_device *ndev = napi->dev;
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      int work_done = 0;
++      u8 rx_status = 0, control = 0;
++
++      control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
++      rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++
++      /* clear receive interrupt and deal with all the received frames */
++      while ((rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK) && (work_done < quota)) {
++              (control & CAN_FD_SET_EDL_MASK) ? (work_done += canfd_rx(ndev)) : (work_done += can_rx(ndev));
++
++              control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
++              rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++      }
++      napi_complete(napi);
++      canfd_reigister_set_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_SET_RIE_MASK);
++      return work_done;
++}
++
++static void canfd_rxfull_interrupt(struct net_device *ndev, u8 isr)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++
++      if (isr & CAN_FD_SET_RAFIF_MASK)
++              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RAFIF_MASK);
++
++      if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK))
++              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
++                                      (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK));
++}
++
++static int set_canfd_xmit_mode(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++
++      switch (priv->tx_mode) {
++      case XMIT_FULL:
++              canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_FULLCAN_MASK);
++              break;
++      case XMIT_SEP_FIFO:
++              canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FULLCAN_MASK);
++              canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_FIFO_MASK);
++              canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TBSEL_MASK);
++              break;
++      case XMIT_SEP_PRIO:
++              canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FULLCAN_MASK);
++              canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FIFO_MASK);
++              canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TBSEL_MASK);
++              break;
++      case XMIT_PTB_MODE:
++              canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_OFF_TBSEL_MASK);
++              break;
++      default:
++              break;
++      }
++      return 0;
++}
++
++static netdev_tx_t canfd_driver_start_xmit(struct sk_buff *skb, struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      struct canfd_frame *cf = (struct canfd_frame *)skb->data;
++      struct net_device_stats *stats = &ndev->stats;
++      u32 ttsen, id, ctl, addr_off;
++      int i;
++
++      priv->tx_mode = XMIT_PTB_MODE;
++
++      if (can_dropped_invalid_skb(ndev, skb))
++              return NETDEV_TX_OK;
++
++      switch (priv->tx_mode) {
++      case XMIT_FULL:
++              return NETDEV_TX_BUSY;
++      case XMIT_PTB_MODE:
++              set_canfd_xmit_mode(ndev);
++              canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_OFF_STBY_MASK);
++
++              if (cf->can_id & CAN_EFF_FLAG) {
++                      id = (cf->can_id & CAN_EFF_MASK);
++                      ttsen = 0 << TTSEN_8_32_SHIFT;
++                      id |= ttsen;
++              } else {
++                      id = (cf->can_id & CAN_SFF_MASK);
++                      ttsen = 0 << TTSEN_8_32_SHIFT;
++                      id |= ttsen;
++              }
++
++              ctl = can_fd_len2dlc(cf->len);
++
++              /* transmit can fd frame */
++              if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) {
++                      if (can_is_canfd_skb(skb)) {
++                              if (cf->can_id & CAN_EFF_FLAG)
++                                      ctl |= CAN_FD_SET_IDE_MASK;
++                              else
++                                      ctl &= CAN_FD_OFF_IDE_MASK;
++
++                              if (cf->flags & CANFD_BRS)
++                                      ctl |= CAN_FD_SET_BRS_MASK;
++
++                              ctl |= CAN_FD_SET_EDL_MASK;
++
++                              addr_off = CANFD_TBUF_DATA_OFFSET;
++
++                              for (i = 0; i < cf->len; i += 4) {
++                                      priv->write_reg(priv, addr_off,
++                                                      *((u32 *)(cf->data + i)));
++                                      addr_off += 4;
++                              }
++                      } else {
++                              ctl &= CAN_FD_OFF_EDL_MASK;
++                              ctl &= CAN_FD_OFF_BRS_MASK;
++
++                              if (cf->can_id & CAN_EFF_FLAG)
++                                      ctl |= CAN_FD_SET_IDE_MASK;
++                              else
++                                      ctl &= CAN_FD_OFF_IDE_MASK;
++
++                              if (cf->can_id & CAN_RTR_FLAG) {
++                                      ctl |= CAN_FD_SET_RTR_MASK;
++                                      priv->write_reg(priv,
++                                              CANFD_TBUF_ID_OFFSET, id);
++                                      priv->write_reg(priv,
++                                              CANFD_TBUF_CTL_OFFSET, ctl);
++                              } else {
++                                      ctl &= CAN_FD_OFF_RTR_MASK;
++                                      addr_off = CANFD_TBUF_DATA_OFFSET;
++                                      priv->write_reg(priv, addr_off,
++                                                      *((u32 *)(cf->data + 0)));
++                                      priv->write_reg(priv, addr_off + 4,
++                                                      *((u32 *)(cf->data + 4)));
++                              }
++                      }
++                      priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id);
++                      priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl);
++                      addr_off = CANFD_TBUF_DATA_OFFSET;
++              } else {
++                      ctl &= CAN_FD_OFF_EDL_MASK;
++                      ctl &= CAN_FD_OFF_BRS_MASK;
++
++                      if (cf->can_id & CAN_EFF_FLAG)
++                              ctl |= CAN_FD_SET_IDE_MASK;
++                      else
++                              ctl &= CAN_FD_OFF_IDE_MASK;
++
++                      if (cf->can_id & CAN_RTR_FLAG) {
++                              ctl |= CAN_FD_SET_RTR_MASK;
++                              priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id);
++                              priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl);
++                      } else {
++                              ctl &= CAN_FD_OFF_RTR_MASK;
++                              priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id);
++                              priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl);
++                              addr_off = CANFD_TBUF_DATA_OFFSET;
++                              priv->write_reg(priv, addr_off,
++                                              *((u32 *)(cf->data + 0)));
++                              priv->write_reg(priv, addr_off + 4,
++                                              *((u32 *)(cf->data + 4)));
++                      }
++              }
++              canfd_reigister_set_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TPE_MASK);
++              stats->tx_bytes += cf->len;
++              break;
++      default:
++              break;
++      }
++
++      /*Due to cache blocking, we need call dev_kfree_skb() here to free the socket
++      buffer and return NETDEV_TX_OK */
++      dev_kfree_skb(skb);
++
++      return NETDEV_TX_OK;
++}
++
++static int set_reset_mode(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      u8 ret;
++
++      ret = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
++      ret |= CAN_FD_SET_RST_MASK;
++      can_iowrite8(ret, priv->reg_base + CANFD_CFG_STAT_OFFSET);
++
++      return 0;
++}
++
++static void canfd_driver_stop(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      int ret;
++
++      ret = set_reset_mode(ndev);
++      if (ret)
++              netdev_err(ndev, "Mode Resetting Failed!\n");
++
++      priv->can.state = CAN_STATE_STOPPED;
++}
++
++static int canfd_driver_close(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++
++      netif_stop_queue(ndev);
++      napi_disable(&priv->napi);
++      canfd_driver_stop(ndev);
++
++      free_irq(ndev->irq, ndev);
++      close_candev(ndev);
++
++      pm_runtime_put(priv->dev);
++
++      return 0;
++}
++
++static enum can_state get_of_chip_status(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      u8 can_stat, eir;
++
++      can_stat = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
++      eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
++
++      if (can_stat & CAN_FD_SET_BUSOFF_MASK)
++              return CAN_STATE_BUS_OFF;
++
++      if ((eir & CAN_FD_SET_EPASS_MASK) && ~(can_stat & CAN_FD_SET_BUSOFF_MASK))
++              return CAN_STATE_ERROR_PASSIVE;
++
++      if (eir & CAN_FD_SET_EWARN_MASK && ~(eir & CAN_FD_SET_EPASS_MASK))
++              return CAN_STATE_ERROR_WARNING;
++
++      if (~(eir & CAN_FD_SET_EPASS_MASK))
++              return CAN_STATE_ERROR_ACTIVE;
++
++      return CAN_STATE_ERROR_ACTIVE;
++}
++
++static void canfd_error_interrupt(struct net_device *ndev, u8 isr, u8 eir)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      struct net_device_stats *stats = &ndev->stats;
++      struct can_frame *cf;
++      struct sk_buff *skb;
++      u8 koer, recnt = 0, tecnt = 0, can_stat = 0;
++
++      skb = alloc_can_err_skb(ndev, &cf);
++
++      koer = can_ioread8(priv->reg_base + CANFD_EALCAP_OFFSET) & CAN_FD_SET_KOER_MASK;
++      recnt = can_ioread8(priv->reg_base + CANFD_RECNT_OFFSET);
++      tecnt = can_ioread8(priv->reg_base + CANFD_TECNT_OFFSET);
++
++      /*Read can status*/
++      can_stat = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
++
++      /* Bus off --->active error mode */
++      if ((isr & CAN_FD_SET_EIF_MASK) && priv->can.state == CAN_STATE_BUS_OFF)
++              priv->can.state = get_of_chip_status(ndev);
++
++      /* State selection */
++      if (can_stat & CAN_FD_SET_BUSOFF_MASK) {
++              priv->can.state = get_of_chip_status(ndev);
++              priv->can.can_stats.bus_off++;
++              canfd_reigister_set_bit(priv, CANFD_CFG_STAT_OFFSET, CAN_FD_SET_BUSOFF_MASK);
++              can_bus_off(ndev);
++              if (skb)
++                      cf->can_id |= CAN_ERR_BUSOFF;
++
++      } else if ((eir & CAN_FD_SET_EPASS_MASK) && ~(can_stat & CAN_FD_SET_BUSOFF_MASK)) {
++              priv->can.state = get_of_chip_status(ndev);
++              priv->can.can_stats.error_passive++;
++              if (skb) {
++                      cf->can_id |= CAN_ERR_CRTL;
++                      cf->data[1] |= (recnt > 127) ? CAN_ERR_CRTL_RX_PASSIVE : 0;
++                      cf->data[1] |= (tecnt > 127) ? CAN_ERR_CRTL_TX_PASSIVE : 0;
++                      cf->data[6] = tecnt;
++                      cf->data[7] = recnt;
++              }
++      } else if (eir & CAN_FD_SET_EWARN_MASK && ~(eir & CAN_FD_SET_EPASS_MASK)) {
++              priv->can.state = get_of_chip_status(ndev);
++              priv->can.can_stats.error_warning++;
++              if (skb) {
++                      cf->can_id |= CAN_ERR_CRTL;
++                      cf->data[1] |= (recnt > 95) ? CAN_ERR_CRTL_RX_WARNING : 0;
++                      cf->data[1] |= (tecnt > 95) ? CAN_ERR_CRTL_TX_WARNING : 0;
++                      cf->data[6] = tecnt;
++                      cf->data[7] = recnt;
++              }
++      }
++
++      /* Check for in protocol defined error interrupt */
++      if (eir & CAN_FD_SET_BEIF_MASK) {
++              if (skb)
++                      cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
++
++              /* bit error interrupt */
++              if (koer == CAN_FD_SET_BIT_ERROR_MASK) {
++                      stats->tx_errors++;
++                      if (skb) {
++                              cf->can_id |= CAN_ERR_PROT;
++                              cf->data[2] = CAN_ERR_PROT_BIT;
++                      }
++              }
++              /* format error interrupt */
++              if (koer == CAN_FD_SET_FORM_ERROR_MASK) {
++                      stats->rx_errors++;
++                      if (skb) {
++                              cf->can_id |= CAN_ERR_PROT;
++                              cf->data[2] = CAN_ERR_PROT_FORM;
++                      }
++              }
++              /* stuffing error interrupt */
++              if (koer == CAN_FD_SET_STUFF_ERROR_MASK) {
++                      stats->rx_errors++;
++                      if (skb) {
++                              cf->can_id |= CAN_ERR_PROT;
++                              cf->data[3] = CAN_ERR_PROT_STUFF;
++                      }
++              }
++              /* ack error interrupt */
++              if (koer == CAN_FD_SET_ACK_ERROR_MASK) {
++                      stats->tx_errors++;
++                      if (skb) {
++                              cf->can_id |= CAN_ERR_PROT;
++                              cf->data[2] = CAN_ERR_PROT_LOC_ACK;
++                      }
++              }
++              /* crc error interrupt */
++              if (koer == CAN_FD_SET_CRC_ERROR_MASK) {
++                      stats->rx_errors++;
++                      if (skb) {
++                              cf->can_id |= CAN_ERR_PROT;
++                              cf->data[2] = CAN_ERR_PROT_LOC_CRC_SEQ;
++                      }
++              }
++              priv->can.can_stats.bus_error++;
++      }
++      if (skb) {
++              stats->rx_packets++;
++              stats->rx_bytes += cf->can_dlc;
++              netif_rx(skb);
++      }
++
++      netdev_dbg(ndev, "Recnt is 0x%02x", can_ioread8(priv->reg_base + CANFD_RECNT_OFFSET));
++      netdev_dbg(ndev, "Tecnt is 0x%02x", can_ioread8(priv->reg_base + CANFD_TECNT_OFFSET));
++}
++
++static irqreturn_t canfd_interrupt(int irq, void *dev_id)
++{
++      struct net_device *ndev = (struct net_device *)dev_id;
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      u8 isr, eir;
++      u8 isr_handled = 0, eir_handled = 0;
++
++      /* read the value of interrupt status register */
++      isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
++
++      /* read the value of error interrupt register */
++      eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
++
++      /* Check for Tx interrupt and Processing it */
++      if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
++              canfd_tx_interrupt(ndev, isr);
++              isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK);
++      }
++      if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) {
++              canfd_rxfull_interrupt(ndev, isr);
++              isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK);
++      }
++      /* Check Rx interrupt and Processing the receive interrupt routine */
++      if (isr & CAN_FD_SET_RIF_MASK) {
++              canfd_reigister_off_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_OFF_RIE_MASK);
++              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RIF_MASK);
++
++              napi_schedule(&priv->napi);
++              isr_handled |= CAN_FD_SET_RIF_MASK;
++      }
++      if ((isr & CAN_FD_SET_EIF_MASK) | (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK))) {
++              /* reset EPIF and BEIF. Reset EIF */
++              canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET,
++                                      eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK));
++              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
++                                      isr & CAN_FD_SET_EIF_MASK);
++
++              canfd_error_interrupt(ndev, isr, eir);
++
++              isr_handled |= CAN_FD_SET_EIF_MASK;
++              eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK);
++      }
++      if ((isr_handled == 0) && (eir_handled == 0)) {
++              netdev_err(ndev, "Unhandled interrupt!\n");
++              return IRQ_NONE;
++      }
++
++      return IRQ_HANDLED;
++}
++
++static int canfd_chip_start(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      int err;
++      u8 ret;
++
++      err = set_reset_mode(ndev);
++      if (err) {
++              netdev_err(ndev, "Mode Resetting Failed!\n");
++              return err;
++      }
++
++      err = canfd_device_driver_bittime_configuration(ndev);
++      if (err) {
++              netdev_err(ndev, "Bittime Setting Failed!\n");
++              return err;
++      }
++
++      /* Set Almost Full Warning Limit */
++      canfd_reigister_set_bit(priv, CANFD_LIMIT_OFFSET, CAN_FD_SET_AFWL_MASK);
++
++      /* Programmable Error Warning Limit = (EWL+1)*8. Set EWL=11->Error Warning=96 */
++      canfd_reigister_set_bit(priv, CANFD_LIMIT_OFFSET, CAN_FD_SET_EWL_MASK);
++
++      /* Interrupts enable */
++      can_iowrite8(CAN_FD_INTR_ALL_MASK, priv->reg_base + CANFD_RTIE_OFFSET);
++
++      /* Error Interrupts enable(Error Passive and Bus Error) */
++      canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET, CAN_FD_SET_EPIE_MASK);
++
++      ret = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
++
++      /* Check whether it is loopback mode or normal mode */
++      if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
++              ret |= CAN_FD_LBMIMOD_MASK;
++      } else {
++              ret &= ~CAN_FD_LBMEMOD_MASK;
++              ret &= ~CAN_FD_LBMIMOD_MASK;
++      }
++
++      can_iowrite8(ret, priv->reg_base + CANFD_CFG_STAT_OFFSET);
++
++      priv->can.state = CAN_STATE_ERROR_ACTIVE;
++
++      return 0;
++}
++
++static int  canfd_do_set_mode(struct net_device *ndev, enum can_mode mode)
++{
++      int ret;
++
++      switch (mode) {
++      case CAN_MODE_START:
++              ret = canfd_chip_start(ndev);
++              if (ret) {
++                      netdev_err(ndev, "Could Not Start CAN device !!\n");
++                      return ret;
++              }
++              netif_wake_queue(ndev);
++              break;
++      default:
++              ret = -EOPNOTSUPP;
++              break;
++      }
++
++      return ret;
++}
++
++static int canfd_driver_open(struct net_device *ndev)
++{
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      int ret;
++
++      ret = pm_runtime_get_sync(priv->dev);
++      if (ret < 0) {
++              netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
++                         __func__, ret);
++              goto err;
++      }
++
++      /* Set chip into reset mode */
++      ret = set_reset_mode(ndev);
++      if (ret) {
++              netdev_err(ndev, "Mode Resetting Failed!\n");
++              return ret;
++      }
++
++      /* Common open */
++      ret = open_candev(ndev);
++      if (ret)
++              return ret;
++
++      /* Register interrupt handler */
++      ret = request_irq(ndev->irq, canfd_interrupt, IRQF_SHARED, ndev->name, ndev);
++      if (ret) {
++              netdev_err(ndev, "Request_irq err: %d\n", ret);
++              goto exit_irq;
++      }
++
++      ret = canfd_chip_start(ndev);
++      if (ret) {
++              netdev_err(ndev, "Could Not Start CAN device !\n");
++              goto exit_can_start;
++      }
++
++      napi_enable(&priv->napi);
++      netif_start_queue(ndev);
++
++      return 0;
++
++exit_can_start:
++      free_irq(ndev->irq, ndev);
++err:
++      pm_runtime_put(priv->dev);
++exit_irq:
++      close_candev(ndev);
++      return ret;
++}
++
++static int canfd_control_parse_dt(struct ipms_canfd_priv *priv)
++{
++      struct of_phandle_args args;
++      u32 syscon_mask, syscon_shift;
++      u32 can_or_canfd;
++      u32 syscon_offset, regval;
++      int ret;
++
++      ret = of_parse_phandle_with_fixed_args(priv->dev->of_node,
++                                              "starfive,sys-syscon", 3, 0, &args);
++      if (ret) {
++              dev_err(priv->dev, "Failed to parse starfive,sys-syscon\n");
++              return -EINVAL;
++      }
++
++      priv->reg_syscon = syscon_node_to_regmap(args.np);
++      of_node_put(args.np);
++      if (IS_ERR(priv->reg_syscon))
++              return PTR_ERR(priv->reg_syscon);
++
++      syscon_offset = args.args[0];
++      syscon_shift  = args.args[1];
++      syscon_mask   = args.args[2];
++
++      ret = device_property_read_u32(priv->dev, "syscon,can_or_canfd", &can_or_canfd);
++      if (ret)
++              goto exit_parse;
++
++      priv->can_or_canfd = can_or_canfd;
++
++      /* enable can2.0/canfd function */
++      regval = can_or_canfd << syscon_shift;
++      ret = regmap_update_bits(priv->reg_syscon, syscon_offset, syscon_mask, regval);
++      if (ret)
++              return ret;
++      return 0;
++exit_parse:
++      return ret;
++}
++
++static const struct net_device_ops canfd_netdev_ops = {
++      .ndo_open = canfd_driver_open,
++      .ndo_stop = canfd_driver_close,
++      .ndo_start_xmit = canfd_driver_start_xmit,
++      .ndo_change_mtu = can_change_mtu,
++};
++
++static int canfd_driver_probe(struct platform_device *pdev)
++{
++      struct net_device *ndev;
++      struct ipms_canfd_priv *priv;
++      void __iomem *addr;
++      int ret;
++      u32 frq;
++
++      addr = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(addr)) {
++              ret = PTR_ERR(addr);
++              goto exit;
++      }
++
++      ndev = alloc_candev(sizeof(struct ipms_canfd_priv), 1);
++      if (!ndev) {
++              ret = -ENOMEM;
++              goto exit;
++      }
++
++      priv = netdev_priv(ndev);
++      priv->dev = &pdev->dev;
++
++      ret = canfd_control_parse_dt(priv);
++      if (ret)
++              goto free_exit;
++
++      priv->nr_clks = devm_clk_bulk_get_all(priv->dev, &priv->clks);
++      if (priv->nr_clks < 0) {
++              dev_err(priv->dev, "Failed to get can clocks\n");
++              ret = -ENODEV;
++              goto free_exit;
++      }
++
++      ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
++      if (ret) {
++              dev_err(priv->dev, "Failed to enable clocks\n");
++              goto free_exit;
++      }
++
++      priv->resets = devm_reset_control_array_get_exclusive(priv->dev);
++      if (IS_ERR(priv->resets)) {
++              ret = PTR_ERR(priv->resets);
++              dev_err(priv->dev, "Failed to get can resets");
++              goto clk_exit;
++      }
++
++      ret = reset_control_deassert(priv->resets);
++      if (ret)
++              goto clk_exit;
++      priv->can.bittiming_const = &canfd_bittiming_const;
++      priv->can.data_bittiming_const = &canfd_data_bittiming_const;
++      priv->can.do_set_mode = canfd_do_set_mode;
++
++      /* in user space the execution mode can be chosen */
++      if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD)
++              priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_FD;
++      else
++              priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK;
++      priv->reg_base = addr;
++      priv->write_reg = canfd_write_reg_le;
++      priv->read_reg = canfd_read_reg_le;
++
++      pm_runtime_enable(&pdev->dev);
++
++      priv->can_clk = devm_clk_get(&pdev->dev, "core_clk");
++      if (IS_ERR(priv->can_clk)) {
++              dev_err(&pdev->dev, "Device clock not found.\n");
++              ret = PTR_ERR(priv->can_clk);
++              goto reset_exit;
++      }
++
++      device_property_read_u32(priv->dev, "frequency", &frq);
++      clk_set_rate(priv->can_clk, frq);
++
++      priv->can.clock.freq = clk_get_rate(priv->can_clk);
++      ndev->irq = platform_get_irq(pdev, 0);
++
++      /* we support local echo */
++      ndev->flags |= IFF_ECHO;
++      ndev->netdev_ops = &canfd_netdev_ops;
++
++      platform_set_drvdata(pdev, ndev);
++      SET_NETDEV_DEV(ndev, &pdev->dev);
++
++      netif_napi_add(ndev, &priv->napi, canfd_rx_poll);
++      ret = register_candev(ndev);
++      if (ret) {
++              dev_err(&pdev->dev, "Fail to register failed (err=%d)\n", ret);
++              goto reset_exit;
++      }
++
++      dev_dbg(&pdev->dev, "Driver registered: regs=%p, irp=%d, clock=%d\n",
++              priv->reg_base, ndev->irq, priv->can.clock.freq);
++
++      return 0;
++
++reset_exit:
++      reset_control_assert(priv->resets);
++clk_exit:
++      clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
++free_exit:
++      free_candev(ndev);
++exit:
++      return ret;
++}
++
++static void canfd_driver_remove(struct platform_device *pdev)
++{
++      struct net_device *ndev = platform_get_drvdata(pdev);
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++
++      reset_control_assert(priv->resets);
++      clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
++      pm_runtime_disable(&pdev->dev);
++
++      unregister_candev(ndev);
++      netif_napi_del(&priv->napi);
++      free_candev(ndev);
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int __maybe_unused canfd_suspend(struct device *dev)
++{
++      struct net_device *ndev = dev_get_drvdata(dev);
++
++      if (netif_running(ndev)) {
++              netif_stop_queue(ndev);
++              netif_device_detach(ndev);
++              canfd_driver_stop(ndev);
++      }
++
++      return pm_runtime_force_suspend(dev);
++}
++
++static int __maybe_unused canfd_resume(struct device *dev)
++{
++      struct net_device *ndev = dev_get_drvdata(dev);
++      int ret;
++
++      ret = pm_runtime_force_resume(dev);
++      if (ret) {
++              dev_err(dev, "pm_runtime_force_resume failed on resume\n");
++              return ret;
++      }
++
++      if (netif_running(ndev)) {
++              ret = canfd_chip_start(ndev);
++              if (ret) {
++                      dev_err(dev, "canfd_chip_start failed on resume\n");
++                      return ret;
++              }
++
++              netif_device_attach(ndev);
++              netif_start_queue(ndev);
++      }
++
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_PM
++static int canfd_runtime_suspend(struct device *dev)
++{
++      struct net_device *ndev = dev_get_drvdata(dev);
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++
++      reset_control_assert(priv->resets);
++      clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
++
++      return 0;
++}
++
++static int canfd_runtime_resume(struct device *dev)
++{
++      struct net_device *ndev = dev_get_drvdata(dev);
++      struct ipms_canfd_priv *priv = netdev_priv(ndev);
++      int ret;
++
++      ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
++      if (ret) {
++              dev_err(dev, "Failed to  prepare_enable clk\n");
++              return ret;
++      }
++
++      ret = reset_control_deassert(priv->resets);
++      if (ret) {
++              dev_err(dev, "Failed to deassert reset\n");
++              return ret;
++      }
++
++      return 0;
++}
++#endif
++
++static const struct dev_pm_ops canfd_pm_ops = {
++      SET_SYSTEM_SLEEP_PM_OPS(canfd_suspend, canfd_resume)
++      SET_RUNTIME_PM_OPS(canfd_runtime_suspend,
++                         canfd_runtime_resume, NULL)
++};
++
++static const struct of_device_id canfd_of_match[] = {
++      { .compatible = "ipms,can" },
++      { }
++};
++MODULE_DEVICE_TABLE(of, canfd_of_match);
++
++static struct platform_driver can_driver = {
++      .probe          = canfd_driver_probe,
++      .remove         = canfd_driver_remove,
++      .driver = {
++              .name  = DRIVER_NAME,
++              .pm    = &canfd_pm_ops,
++              .of_match_table = canfd_of_match,
++      },
++};
++
++module_platform_driver(can_driver);
++
++MODULE_DESCRIPTION("ipms can controller driver for StarFive jh7110 SoC");
++MODULE_AUTHOR("William Qiu<william.qiu@starfivetech.com");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/starfive/patches-6.12/0012-ipms-CAN-Solve-CAN-packet-leakage-problem.patch b/target/linux/starfive/patches-6.12/0012-ipms-CAN-Solve-CAN-packet-leakage-problem.patch
new file mode 100644 (file)
index 0000000..2e7db60
--- /dev/null
@@ -0,0 +1,196 @@
+From 356774301b12dbdfe4682e12c57bddb8058014a2 Mon Sep 17 00:00:00 2001
+From: William Qiu <william.qiu@starfivetech.com>
+Date: Sat, 12 Oct 2024 17:56:00 +0800
+Subject: [PATCH 12/55] ipms: CAN: Solve CAN packet leakage problem
+
+Improve RX interrupt trigger mechanism, reduce buffer trigger condition,
+and increase polling value to solve the problem of CAN packet leakage.
+
+Signed-off-by: William Qiu <william.qiu@starfivetech.com>
+---
+ drivers/net/can/ipms_canfd.c | 108 +++++++++++++++++++----------------
+ 1 file changed, 59 insertions(+), 49 deletions(-)
+
+--- a/drivers/net/can/ipms_canfd.c
++++ b/drivers/net/can/ipms_canfd.c
+@@ -5,28 +5,30 @@
+  * Copyright (c) 2022 StarFive Technology Co., Ltd.
+  */
++#include <linux/can/dev.h>
++#include <linux/can/error.h>
+ #include <linux/clk.h>
+-#include <linux/reset.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
++#include <linux/jiffies.h>
+ #include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/of.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
+ #include <linux/skbuff.h>
+ #include <linux/string.h>
+ #include <linux/types.h>
+-#include <linux/can/dev.h>
+-#include <linux/can/error.h>
+-#include <linux/pm_runtime.h>
+-#include <linux/of_device.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/regmap.h>
+ #define DRIVER_NAME "ipms_canfd"
++#define MAX_IRQ 16
+ /* CAN registers set */
+ enum canfd_device_reg {
+@@ -124,7 +126,7 @@ enum canfd_reg_bitchange {
+       CAN_FD_SET_BEIF_MASK        =   0x01,
+       CAN_FD_OFF_EPIE_MASK        =   0xdf,
+       CAN_FD_OFF_BEIE_MASK        =   0xfd,
+-      CAN_FD_SET_AFWL_MASK        =   0x40,
++      CAN_FD_SET_AFWL_MASK        =   0x20,
+       CAN_FD_SET_EWL_MASK         =   0x0b,
+       CAN_FD_SET_KOER_MASK        =   0xe0,
+       CAN_FD_SET_BIT_ERROR_MASK   =   0x20,
+@@ -366,12 +368,8 @@ static int can_rx(struct net_device *nde
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       u32 can_id;
+-      u8  dlc, control, rx_status;
+-
+-      rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++      u8 dlc, control;
+-      if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
+-              return 0;
+       control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
+       can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
+       dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
+@@ -403,7 +401,7 @@ static int can_rx(struct net_device *nde
+       canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK);
+       stats->rx_bytes += can_fd_dlc2len(cf->can_dlc);
+       stats->rx_packets++;
+-      netif_receive_skb(skb);
++      netif_rx(skb);
+       return 1;
+ }
+@@ -419,9 +417,9 @@ static int canfd_rx(struct net_device *n
+       int i;
+       rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
+-
+       if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
+               return 0;
++
+       control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
+       can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
+       dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
+@@ -557,6 +555,8 @@ static netdev_tx_t canfd_driver_start_xm
+       if (can_dropped_invalid_skb(ndev, skb))
+               return NETDEV_TX_OK;
++      netif_stop_queue(ndev);
++
+       switch (priv->tx_mode) {
+       case XMIT_FULL:
+               return NETDEV_TX_BUSY;
+@@ -837,46 +837,56 @@ static irqreturn_t canfd_interrupt(int i
+ {
+       struct net_device *ndev = (struct net_device *)dev_id;
+       struct ipms_canfd_priv *priv = netdev_priv(ndev);
+-      u8 isr, eir;
++      u8 isr, eir, rx_status;
+       u8 isr_handled = 0, eir_handled = 0;
++      int num = 0;
+-      /* read the value of interrupt status register */
+-      isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
+-
+-      /* read the value of error interrupt register */
+-      eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
++      while (((isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET)) ||
++              (eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET))) &&
++              num < MAX_IRQ) {
++              num++;
++
++              /* Check for Tx interrupt and Processing it */
++              if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
++                      canfd_tx_interrupt(ndev, isr);
++                      isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK);
++                      break;
++              }
+-      /* Check for Tx interrupt and Processing it */
+-      if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
+-              canfd_tx_interrupt(ndev, isr);
+-              isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK);
+-      }
+-      if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) {
+-              canfd_rxfull_interrupt(ndev, isr);
+-              isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK);
+-      }
+-      /* Check Rx interrupt and Processing the receive interrupt routine */
+-      if (isr & CAN_FD_SET_RIF_MASK) {
+-              canfd_reigister_off_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_OFF_RIE_MASK);
+-              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RIF_MASK);
+-
+-              napi_schedule(&priv->napi);
+-              isr_handled |= CAN_FD_SET_RIF_MASK;
+-      }
+-      if ((isr & CAN_FD_SET_EIF_MASK) | (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK))) {
+-              /* reset EPIF and BEIF. Reset EIF */
+-              canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET,
+-                                      eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK));
+-              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
+-                                      isr & CAN_FD_SET_EIF_MASK);
++              if (unlikely(isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK))) {
++                      canfd_rxfull_interrupt(ndev, isr);
++                      isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK);
++              }
+-              canfd_error_interrupt(ndev, isr, eir);
++              /* Check Rx interrupt and Processing the receive interrupt routine */
++              if (isr & CAN_FD_SET_RIF_MASK) {
++                      rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++                      while (rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK) {
++                              can_rx(ndev);
++                              rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
++                      }
++                      isr_handled |= CAN_FD_SET_RIF_MASK;
++              }
+-              isr_handled |= CAN_FD_SET_EIF_MASK;
+-              eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK);
++              if (unlikely((isr & CAN_FD_SET_EIF_MASK) |
++                  (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK)))) {
++                      /* reset EPIF and BEIF. Reset EIF */
++                      canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET,
++                                              eir & (CAN_FD_SET_EPIF_MASK |
++                                                     CAN_FD_SET_BEIF_MASK));
++                      canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
++                                              isr & CAN_FD_SET_EIF_MASK);
++                      canfd_error_interrupt(ndev, isr, eir);
++                      isr_handled |= CAN_FD_SET_EIF_MASK;
++                      eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK);
++              }
++              canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, isr);
+       }
+-      if ((isr_handled == 0) && (eir_handled == 0)) {
+-              netdev_err(ndev, "Unhandled interrupt!\n");
++
++      if (num == 0) {
++              isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
++              eir  = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
++              netdev_err(ndev, "Unhandled interrupt!isr:%x,eir:%x\n", isr, eir);
+               return IRQ_NONE;
+       }
diff --git a/target/linux/starfive/patches-6.12/0013-drivers-nvme-Add-precheck-and-delay-for-CQE-pending-.patch b/target/linux/starfive/patches-6.12/0013-drivers-nvme-Add-precheck-and-delay-for-CQE-pending-.patch
new file mode 100644 (file)
index 0000000..ef84c85
--- /dev/null
@@ -0,0 +1,40 @@
+From 63ebc39891f7b292197f653f8f3aa9dfe35135ee Mon Sep 17 00:00:00 2001
+From: "Kevin.xie" <kevin.xie@starfivetech.com>
+Date: Thu, 24 Nov 2022 16:59:12 +0800
+Subject: [PATCH 13/55] drivers: nvme: Add precheck and delay for CQE pending
+ status.
+
+To workaroud the NVMe I/O timeout problem in bootup S10udev case
+which caused by the CQE update lantancy.
+
+Signed-off-by: Kevin.xie <kevin.xie@starfivetech.com>
+---
+ drivers/nvme/host/pci.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/nvme/host/pci.c
++++ b/drivers/nvme/host/pci.c
+@@ -28,6 +28,7 @@
+ #include <linux/io-64-nonatomic-hi-lo.h>
+ #include <linux/sed-opal.h>
+ #include <linux/pci-p2pdma.h>
++#include <linux/delay.h>
+ #include "trace.h"
+ #include "nvme.h"
+@@ -1156,6 +1157,15 @@ static inline int nvme_poll_cq(struct nv
+ {
+       int found = 0;
++      /*
++       * In some cases, such as udev trigger, cqe status may update
++       * a little bit later than MSI, which cause an irq handle missing.
++       * To workaound, here we will prefetch the status first, and wait
++       * 1us if we get nothing.
++       */
++      if (!nvme_cqe_pending(nvmeq))
++              udelay(1);
++
+       while (nvme_cqe_pending(nvmeq)) {
+               found++;
+               /*
diff --git a/target/linux/starfive/patches-6.12/0014-riscv-Optimize-memcpy-with-aligned-version.patch b/target/linux/starfive/patches-6.12/0014-riscv-Optimize-memcpy-with-aligned-version.patch
new file mode 100644 (file)
index 0000000..6b690ae
--- /dev/null
@@ -0,0 +1,508 @@
+From 16fef31de538ce55e286b630d0b33d872707420d Mon Sep 17 00:00:00 2001
+From: Mason Huo <mason.huo@starfivetech.com>
+Date: Tue, 20 Jun 2023 13:37:52 +0800
+Subject: [PATCH 14/55] riscv: Optimize memcpy with aligned version
+
+Optimizing the 128 byte align case, this will improve the
+performance of large block memcpy.
+
+Here we combine the memcpy of glibc and kernel.
+
+Signed-off-by: Mason Huo <mason.huo@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ arch/riscv/lib/Makefile                       |   3 +-
+ arch/riscv/lib/{memcpy.S => memcpy_aligned.S} |  37 +--
+ arch/riscv/lib/string.c                       | 266 ++++++++++++++++++
+ 3 files changed, 274 insertions(+), 32 deletions(-)
+ rename arch/riscv/lib/{memcpy.S => memcpy_aligned.S} (65%)
+ create mode 100644 arch/riscv/lib/string.c
+
+--- a/arch/riscv/lib/Makefile
++++ b/arch/riscv/lib/Makefile
+@@ -1,6 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ lib-y                 += delay.o
+-lib-y                 += memcpy.o
+ lib-y                 += memset.o
+ lib-y                 += memmove.o
+ ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),)
+@@ -16,6 +15,8 @@ lib-$(CONFIG_MMU)    += uaccess.o
+ lib-$(CONFIG_64BIT)   += tishift.o
+ lib-$(CONFIG_RISCV_ISA_ZICBOZ)        += clear_page.o
+ lib-$(CONFIG_RISCV_ISA_ZBC)   += crc32.o
++lib-y                 += string.o
++lib-y                 += memcpy_aligned.o
+ obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+ lib-$(CONFIG_RISCV_ISA_V)     += xor.o
+--- a/arch/riscv/lib/memcpy.S
++++ /dev/null
+@@ -1,110 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-only */
+-/*
+- * Copyright (C) 2013 Regents of the University of California
+- */
+-
+-#include <linux/linkage.h>
+-#include <asm/asm.h>
+-
+-/* void *memcpy(void *, const void *, size_t) */
+-SYM_FUNC_START(__memcpy)
+-      move t6, a0  /* Preserve return value */
+-
+-      /* Defer to byte-oriented copy for small sizes */
+-      sltiu a3, a2, 128
+-      bnez a3, 4f
+-      /* Use word-oriented copy only if low-order bits match */
+-      andi a3, t6, SZREG-1
+-      andi a4, a1, SZREG-1
+-      bne a3, a4, 4f
+-
+-      beqz a3, 2f  /* Skip if already aligned */
+-      /*
+-       * Round to nearest double word-aligned address
+-       * greater than or equal to start address
+-       */
+-      andi a3, a1, ~(SZREG-1)
+-      addi a3, a3, SZREG
+-      /* Handle initial misalignment */
+-      sub a4, a3, a1
+-1:
+-      lb a5, 0(a1)
+-      addi a1, a1, 1
+-      sb a5, 0(t6)
+-      addi t6, t6, 1
+-      bltu a1, a3, 1b
+-      sub a2, a2, a4  /* Update count */
+-
+-2:
+-      andi a4, a2, ~((16*SZREG)-1)
+-      beqz a4, 4f
+-      add a3, a1, a4
+-3:
+-      REG_L a4,       0(a1)
+-      REG_L a5,   SZREG(a1)
+-      REG_L a6, 2*SZREG(a1)
+-      REG_L a7, 3*SZREG(a1)
+-      REG_L t0, 4*SZREG(a1)
+-      REG_L t1, 5*SZREG(a1)
+-      REG_L t2, 6*SZREG(a1)
+-      REG_L t3, 7*SZREG(a1)
+-      REG_L t4, 8*SZREG(a1)
+-      REG_L t5, 9*SZREG(a1)
+-      REG_S a4,       0(t6)
+-      REG_S a5,   SZREG(t6)
+-      REG_S a6, 2*SZREG(t6)
+-      REG_S a7, 3*SZREG(t6)
+-      REG_S t0, 4*SZREG(t6)
+-      REG_S t1, 5*SZREG(t6)
+-      REG_S t2, 6*SZREG(t6)
+-      REG_S t3, 7*SZREG(t6)
+-      REG_S t4, 8*SZREG(t6)
+-      REG_S t5, 9*SZREG(t6)
+-      REG_L a4, 10*SZREG(a1)
+-      REG_L a5, 11*SZREG(a1)
+-      REG_L a6, 12*SZREG(a1)
+-      REG_L a7, 13*SZREG(a1)
+-      REG_L t0, 14*SZREG(a1)
+-      REG_L t1, 15*SZREG(a1)
+-      addi a1, a1, 16*SZREG
+-      REG_S a4, 10*SZREG(t6)
+-      REG_S a5, 11*SZREG(t6)
+-      REG_S a6, 12*SZREG(t6)
+-      REG_S a7, 13*SZREG(t6)
+-      REG_S t0, 14*SZREG(t6)
+-      REG_S t1, 15*SZREG(t6)
+-      addi t6, t6, 16*SZREG
+-      bltu a1, a3, 3b
+-      andi a2, a2, (16*SZREG)-1  /* Update count */
+-
+-4:
+-      /* Handle trailing misalignment */
+-      beqz a2, 6f
+-      add a3, a1, a2
+-
+-      /* Use word-oriented copy if co-aligned to word boundary */
+-      or a5, a1, t6
+-      or a5, a5, a3
+-      andi a5, a5, 3
+-      bnez a5, 5f
+-7:
+-      lw a4, 0(a1)
+-      addi a1, a1, 4
+-      sw a4, 0(t6)
+-      addi t6, t6, 4
+-      bltu a1, a3, 7b
+-
+-      ret
+-
+-5:
+-      lb a4, 0(a1)
+-      addi a1, a1, 1
+-      sb a4, 0(t6)
+-      addi t6, t6, 1
+-      bltu a1, a3, 5b
+-6:
+-      ret
+-SYM_FUNC_END(__memcpy)
+-SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy)
+-SYM_FUNC_ALIAS(__pi_memcpy, __memcpy)
+-SYM_FUNC_ALIAS(__pi___memcpy, __memcpy)
+--- /dev/null
++++ b/arch/riscv/lib/memcpy_aligned.S
+@@ -0,0 +1,85 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2013 Regents of the University of California
++ */
++
++#include <linux/linkage.h>
++#include <asm/asm.h>
++
++/* void *__memcpy_aligned(void *, const void *, size_t) */
++SYM_FUNC_START(__memcpy_aligned)
++      move t6, a0  /* Preserve return value */
++
++2:
++      andi a4, a2, ~((16*SZREG)-1)
++      beqz a4, 4f
++      add a3, a1, a4
++3:
++      REG_L a4,       0(a1)
++      REG_L a5,   SZREG(a1)
++      REG_L a6, 2*SZREG(a1)
++      REG_L a7, 3*SZREG(a1)
++      REG_L t0, 4*SZREG(a1)
++      REG_L t1, 5*SZREG(a1)
++      REG_L t2, 6*SZREG(a1)
++      REG_L t3, 7*SZREG(a1)
++      REG_L t4, 8*SZREG(a1)
++      REG_L t5, 9*SZREG(a1)
++      REG_S a4,       0(t6)
++      REG_S a5,   SZREG(t6)
++      REG_S a6, 2*SZREG(t6)
++      REG_S a7, 3*SZREG(t6)
++      REG_S t0, 4*SZREG(t6)
++      REG_S t1, 5*SZREG(t6)
++      REG_S t2, 6*SZREG(t6)
++      REG_S t3, 7*SZREG(t6)
++      REG_S t4, 8*SZREG(t6)
++      REG_S t5, 9*SZREG(t6)
++      REG_L a4, 10*SZREG(a1)
++      REG_L a5, 11*SZREG(a1)
++      REG_L a6, 12*SZREG(a1)
++      REG_L a7, 13*SZREG(a1)
++      REG_L t0, 14*SZREG(a1)
++      REG_L t1, 15*SZREG(a1)
++      addi a1, a1, 16*SZREG
++      REG_S a4, 10*SZREG(t6)
++      REG_S a5, 11*SZREG(t6)
++      REG_S a6, 12*SZREG(t6)
++      REG_S a7, 13*SZREG(t6)
++      REG_S t0, 14*SZREG(t6)
++      REG_S t1, 15*SZREG(t6)
++      addi t6, t6, 16*SZREG
++      bltu a1, a3, 3b
++      andi a2, a2, (16*SZREG)-1  /* Update count */
++
++4:
++      /* Handle trailing misalignment */
++      beqz a2, 6f
++      add a3, a1, a2
++
++      /* Use word-oriented copy if co-aligned to word boundary */
++      or a5, a1, t6
++      or a5, a5, a3
++      andi a5, a5, 3
++      bnez a5, 5f
++7:
++      lw a4, 0(a1)
++      addi a1, a1, 4
++      sw a4, 0(t6)
++      addi t6, t6, 4
++      bltu a1, a3, 7b
++
++      ret
++
++5:
++      lb a4, 0(a1)
++      addi a1, a1, 1
++      sb a4, 0(t6)
++      addi t6, t6, 1
++      bltu a1, a3, 5b
++6:
++      ret
++SYM_FUNC_END(__memcpy_aligned)
++SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy_aligned)
++SYM_FUNC_ALIAS(__pi_memcpy, __memcpy_aligned)
++SYM_FUNC_ALIAS(__pi___memcpy, __memcpy_aligned)
+--- /dev/null
++++ b/arch/riscv/lib/string.c
+@@ -0,0 +1,266 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copy memory to memory until the specified number of bytes
++ * has been copied.  Overlap is NOT handled correctly.
++ * Copyright (C) 1991-2020 Free Software Foundation, Inc.
++ * This file is part of the GNU C Library.
++ * Contributed by Torbjorn Granlund (tege@sics.se).
++ *
++ * The GNU C Library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * The GNU C Library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with the GNU C Library; if not, see
++ * <https://www.gnu.org/licenses/>.
++ *
++ */
++
++#define __NO_FORTIFY
++#include <linux/types.h>
++#include <linux/module.h>
++
++#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
++#define OP_T_THRES      16
++#define op_t    unsigned long
++#define OPSIZ   (sizeof(op_t))
++#define OPSIZ_MASK   (sizeof(op_t) - 1)
++#define FAST_COPY_THRES  (128)
++#define byte    unsigned char
++
++static void _wordcopy_fwd_aligned(long dstp, long srcp, size_t len)
++{
++      op_t a0, a1;
++
++      switch (len % 8) {
++      case 2:
++              a0 = ((op_t *) srcp)[0];
++              srcp -= 6 * OPSIZ;
++              dstp -= 7 * OPSIZ;
++              len += 6;
++              goto do1;
++      case 3:
++              a1 = ((op_t *) srcp)[0];
++              srcp -= 5 * OPSIZ;
++              dstp -= 6 * OPSIZ;
++              len += 5;
++              goto do2;
++      case 4:
++              a0 = ((op_t *) srcp)[0];
++              srcp -= 4 * OPSIZ;
++              dstp -= 5 * OPSIZ;
++              len += 4;
++              goto do3;
++      case 5:
++              a1 = ((op_t *) srcp)[0];
++              srcp -= 3 * OPSIZ;
++              dstp -= 4 * OPSIZ;
++              len += 3;
++              goto do4;
++      case 6:
++              a0 = ((op_t *) srcp)[0];
++              srcp -= 2 * OPSIZ;
++              dstp -= 3 * OPSIZ;
++              len += 2;
++              goto do5;
++      case 7:
++              a1 = ((op_t *) srcp)[0];
++              srcp -= 1 * OPSIZ;
++              dstp -= 2 * OPSIZ;
++              len += 1;
++              goto do6;
++
++      case 0:
++              if (OP_T_THRES <= 3 * OPSIZ && len == 0)
++                      return;
++              a0 = ((op_t *) srcp)[0];
++              srcp -= 0 * OPSIZ;
++              dstp -= 1 * OPSIZ;
++              goto do7;
++      case 1:
++              a1 = ((op_t *) srcp)[0];
++              srcp -= -1 * OPSIZ;
++              dstp -= 0 * OPSIZ;
++              len -= 1;
++              if (OP_T_THRES <= 3 * OPSIZ && len == 0)
++                      goto do0;
++              goto do8;                 /* No-op.  */
++      }
++
++      do {
++do8:
++              a0 = ((op_t *) srcp)[0];
++              ((op_t *) dstp)[0] = a1;
++do7:
++              a1 = ((op_t *) srcp)[1];
++              ((op_t *) dstp)[1] = a0;
++do6:
++              a0 = ((op_t *) srcp)[2];
++              ((op_t *) dstp)[2] = a1;
++do5:
++              a1 = ((op_t *) srcp)[3];
++              ((op_t *) dstp)[3] = a0;
++do4:
++              a0 = ((op_t *) srcp)[4];
++              ((op_t *) dstp)[4] = a1;
++do3:
++              a1 = ((op_t *) srcp)[5];
++              ((op_t *) dstp)[5] = a0;
++do2:
++              a0 = ((op_t *) srcp)[6];
++              ((op_t *) dstp)[6] = a1;
++do1:
++              a1 = ((op_t *) srcp)[7];
++              ((op_t *) dstp)[7] = a0;
++
++              srcp += 8 * OPSIZ;
++              dstp += 8 * OPSIZ;
++              len -= 8;
++      } while (len != 0);
++
++      /* This is the right position for do0.  Please don't move
++       * it into the loop.
++       */
++do0:
++      ((op_t *) dstp)[0] = a1;
++}
++
++static void _wordcopy_fwd_dest_aligned(long dstp, long srcp, size_t len)
++{
++      op_t a0, a1, a2, a3;
++      int sh_1, sh_2;
++
++      /* Calculate how to shift a word read at the memory operation
++       * aligned srcp to make it aligned for copy.
++       */
++
++      sh_1 = 8 * (srcp % OPSIZ);
++      sh_2 = 8 * OPSIZ - sh_1;
++
++      /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
++       * it points in the middle of.
++       */
++      srcp &= -OPSIZ;
++
++      switch (len % 4) {
++      case 2:
++              a1 = ((op_t *) srcp)[0];
++              a2 = ((op_t *) srcp)[1];
++              srcp -= 1 * OPSIZ;
++              dstp -= 3 * OPSIZ;
++              len += 2;
++              goto do1;
++      case 3:
++              a0 = ((op_t *) srcp)[0];
++              a1 = ((op_t *) srcp)[1];
++              srcp -= 0 * OPSIZ;
++              dstp -= 2 * OPSIZ;
++              len += 1;
++              goto do2;
++      case 0:
++              if (OP_T_THRES <= 3 * OPSIZ && len == 0)
++                      return;
++              a3 = ((op_t *) srcp)[0];
++              a0 = ((op_t *) srcp)[1];
++              srcp -= -1 * OPSIZ;
++              dstp -= 1 * OPSIZ;
++              len += 0;
++              goto do3;
++      case 1:
++              a2 = ((op_t *) srcp)[0];
++              a3 = ((op_t *) srcp)[1];
++              srcp -= -2 * OPSIZ;
++              dstp -= 0 * OPSIZ;
++              len -= 1;
++              if (OP_T_THRES <= 3 * OPSIZ && len == 0)
++                      goto do0;
++              goto do4;                 /* No-op.  */
++      }
++
++      do {
++do4:
++              a0 = ((op_t *) srcp)[0];
++              ((op_t *) dstp)[0] = MERGE(a2, sh_1, a3, sh_2);
++do3:
++              a1 = ((op_t *) srcp)[1];
++              ((op_t *) dstp)[1] = MERGE(a3, sh_1, a0, sh_2);
++do2:
++              a2 = ((op_t *) srcp)[2];
++              ((op_t *) dstp)[2] = MERGE(a0, sh_1, a1, sh_2);
++do1:
++              a3 = ((op_t *) srcp)[3];
++              ((op_t *) dstp)[3] = MERGE(a1, sh_1, a2, sh_2);
++
++              srcp += 4 * OPSIZ;
++              dstp += 4 * OPSIZ;
++              len -= 4;
++      } while (len != 0);
++
++      /* This is the right position for do0.  Please don't move
++       * it into the loop.
++       */
++do0:
++      ((op_t *) dstp)[0] = MERGE(a2, sh_1, a3, sh_2);
++}
++
++#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes)         \
++do {                                                  \
++      size_t __nbytes = (nbytes);                     \
++      while (__nbytes > 0) {                                          \
++              byte __x = ((byte *) src_bp)[0];                \
++              src_bp += 1;                            \
++              __nbytes -= 1;                          \
++              ((byte *) dst_bp)[0] = __x;             \
++              dst_bp += 1;                            \
++      }                                               \
++} while (0)
++
++#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes)                    \
++do {                                                                          \
++      if (src_bp % OPSIZ == 0)                                                \
++              _wordcopy_fwd_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);        \
++      else                                                                    \
++              _wordcopy_fwd_dest_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);   \
++      src_bp += (nbytes) & -OPSIZ;                                            \
++      dst_bp += (nbytes) & -OPSIZ;                                            \
++      (nbytes_left) = (nbytes) % OPSIZ;                                       \
++} while (0)
++
++extern void *__memcpy_aligned(void *dest, const void *src, size_t len);
++void *__memcpy(void *dest, const void *src, size_t len)
++{
++      unsigned long dstp = (long) dest;
++      unsigned long srcp = (long) src;
++
++      /* If there not too few bytes to copy, use word copy.  */
++      if (len >= OP_T_THRES) {
++              if ((len >= FAST_COPY_THRES) && ((dstp & OPSIZ_MASK) == 0) &&
++                      ((srcp & OPSIZ_MASK) == 0)) {
++                      __memcpy_aligned(dest, src, len);
++                      return dest;
++              }
++              /* Copy just a few bytes to make DSTP aligned.  */
++              len -= (-dstp) % OPSIZ;
++              BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);
++
++              /* Copy from SRCP to DSTP taking advantage of the known alignment of
++               * DSTP.  Number of bytes remaining is put in the third argument,
++               * i.e. in LEN.  This number may vary from machine to machine.
++               */
++              WORD_COPY_FWD(dstp, srcp, len, len);
++      /* Fall out and copy the tail.  */
++      }
++
++      /* There are just a few bytes to copy.  Use byte memory operations.  */
++      BYTE_COPY_FWD(dstp, srcp, len);
++
++      return dest;
++}
++
++void *memcpy(void *dest, const void *src, size_t len) __weak __alias(__memcpy);
diff --git a/target/linux/starfive/patches-6.12/0015-riscv-purgatory-Change-memcpy-to-the-aligned-version.patch b/target/linux/starfive/patches-6.12/0015-riscv-purgatory-Change-memcpy-to-the-aligned-version.patch
new file mode 100644 (file)
index 0000000..090d85d
--- /dev/null
@@ -0,0 +1,36 @@
+From a0eaebc3b3ae079772c1022c47d704c887c375d0 Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Sun, 4 Feb 2024 15:27:09 +0800
+Subject: [PATCH 15/55] riscv/purgatory: Change memcpy to the aligned version
+
+Change memcpy to the aligned version, for purgatory.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ arch/riscv/purgatory/Makefile | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/arch/riscv/purgatory/Makefile
++++ b/arch/riscv/purgatory/Makefile
+@@ -1,6 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+-purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy.o memset.o
++purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy_aligned.o memcpy.o memset.o
+ ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),)
+ purgatory-y += strcmp.o strlen.o strncmp.o
+ endif
+@@ -14,9 +14,12 @@ $(obj)/string.o: $(srctree)/lib/string.c
+ $(obj)/ctype.o: $(srctree)/lib/ctype.c FORCE
+       $(call if_changed_rule,cc_o_c)
+-$(obj)/memcpy.o: $(srctree)/arch/riscv/lib/memcpy.S FORCE
++$(obj)/memcpy_aligned.o: $(srctree)/arch/riscv/lib/memcpy_aligned.S FORCE
+       $(call if_changed_rule,as_o_S)
++$(obj)/memcpy.o: $(srctree)/arch/riscv/lib/string.c FORCE
++      $(call if_changed_rule,cc_o_c)
++
+ $(obj)/memset.o: $(srctree)/arch/riscv/lib/memset.S FORCE
+       $(call if_changed_rule,as_o_S)
diff --git a/target/linux/starfive/patches-6.12/0016-riscv-Fix-__memcpy_aligned-alias.patch b/target/linux/starfive/patches-6.12/0016-riscv-Fix-__memcpy_aligned-alias.patch
new file mode 100644 (file)
index 0000000..ad35ee0
--- /dev/null
@@ -0,0 +1,22 @@
+From 9b8ac2217743a522f0c4f3e360f089b434fcd04b Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Tue, 21 Jan 2025 11:42:35 +0800
+Subject: [PATCH 16/55] riscv: Fix __memcpy_aligned alias
+
+Don't set the weak global alias of memcpy_aligned to memcpy.
+This affected iperf3 test.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ arch/riscv/lib/memcpy_aligned.S | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/riscv/lib/memcpy_aligned.S
++++ b/arch/riscv/lib/memcpy_aligned.S
+@@ -80,6 +80,5 @@ SYM_FUNC_START(__memcpy_aligned)
+ 6:
+       ret
+ SYM_FUNC_END(__memcpy_aligned)
+-SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy_aligned)
+ SYM_FUNC_ALIAS(__pi_memcpy, __memcpy_aligned)
+ SYM_FUNC_ALIAS(__pi___memcpy, __memcpy_aligned)
diff --git a/target/linux/starfive/patches-6.12/0017-plic-irq-Set-IRQCHIP_EOI_THREADED-in-PREEMPT_RT-case.patch b/target/linux/starfive/patches-6.12/0017-plic-irq-Set-IRQCHIP_EOI_THREADED-in-PREEMPT_RT-case.patch
new file mode 100644 (file)
index 0000000..b114c90
--- /dev/null
@@ -0,0 +1,39 @@
+From 8ea9ae21bde99c2c1832f364f973895e108a4851 Mon Sep 17 00:00:00 2001
+From: Minda Chen <minda.chen@starfivetech.com>
+Date: Thu, 18 Jul 2024 17:22:53 +0800
+Subject: [PATCH 17/55] plic: irq: Set IRQCHIP_EOI_THREADED in PREEMPT_RT case
+
+In ipms can device or other device, interrupt is trigger by level.
+in PREEMPT_RT case. irq handle is in thread, If not set
+IRQCHIP_EOI_THREADED, device irq in PLIC is cleared first, but
+device irq reg is not clear, So the interrupt will be triggered
+again, IRQCHIP_EOI_THREADED will clear device PLIC IRQ status
+after clear device irq reg.
+
+Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
+---
+ drivers/irqchip/irq-sifive-plic.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/irqchip/irq-sifive-plic.c
++++ b/drivers/irqchip/irq-sifive-plic.c
+@@ -209,6 +209,9 @@ static struct irq_chip plic_edge_chip =
+ #endif
+       .irq_set_type   = plic_irq_set_type,
+       .flags          = IRQCHIP_SKIP_SET_WAKE |
++#ifdef CONFIG_PREEMPT_RT
++                        IRQCHIP_EOI_THREADED |
++#endif
+                         IRQCHIP_AFFINITY_PRE_STARTUP,
+ };
+@@ -224,6 +227,9 @@ static struct irq_chip plic_chip = {
+ #endif
+       .irq_set_type   = plic_irq_set_type,
+       .flags          = IRQCHIP_SKIP_SET_WAKE |
++#ifdef CONFIG_PREEMPT_RT
++                        IRQCHIP_EOI_THREADED |
++#endif
+                         IRQCHIP_AFFINITY_PRE_STARTUP,
+ };
diff --git a/target/linux/starfive/patches-6.12/0018-driver-e24-add-e24-driver.patch b/target/linux/starfive/patches-6.12/0018-driver-e24-add-e24-driver.patch
new file mode 100644 (file)
index 0000000..ca61b46
--- /dev/null
@@ -0,0 +1,2294 @@
+From b37b26232ebb6c0a61b530f11ccd6eefdf782c04 Mon Sep 17 00:00:00 2001
+From: "shanlong.li" <shanlong.li@starfivetech.com>
+Date: Fri, 16 Jun 2023 03:02:14 -0700
+Subject: [PATCH 18/55] driver:e24: add e24 driver
+
+add e24 driver
+
+Signed-off-by: shanlong.li <shanlong.li@starfivetech.com>
+---
+ drivers/Kconfig               |    1 +
+ drivers/Makefile              |    1 +
+ drivers/e24/Kconfig           |    5 +
+ drivers/e24/Makefile          |   12 +
+ drivers/e24/e24_alloc.c       |  241 ++++++
+ drivers/e24/e24_alloc.h       |   59 ++
+ drivers/e24/starfive_e24.c    | 1524 +++++++++++++++++++++++++++++++++
+ drivers/e24/starfive_e24.h    |  159 ++++
+ drivers/e24/starfive_e24_hw.c |  134 +++
+ drivers/e24/starfive_e24_hw.h |   94 ++
+ 10 files changed, 2230 insertions(+)
+ create mode 100644 drivers/e24/Kconfig
+ create mode 100644 drivers/e24/Makefile
+ create mode 100644 drivers/e24/e24_alloc.c
+ create mode 100644 drivers/e24/e24_alloc.h
+ create mode 100644 drivers/e24/starfive_e24.c
+ create mode 100644 drivers/e24/starfive_e24.h
+ create mode 100644 drivers/e24/starfive_e24_hw.c
+ create mode 100644 drivers/e24/starfive_e24_hw.h
+
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -245,4 +245,5 @@ source "drivers/cdx/Kconfig"
+ source "drivers/dpll/Kconfig"
++source "drivers/e24/Kconfig"
+ endmenu
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -195,3 +195,4 @@ obj-$(CONFIG_CDX_BUS)              += cdx/
+ obj-$(CONFIG_DPLL)            += dpll/
+ obj-$(CONFIG_S390)            += s390/
++obj-$(CONFIG_E24)             += e24/
+--- /dev/null
++++ b/drivers/e24/Kconfig
+@@ -0,0 +1,5 @@
++config E24
++      tristate  "E24 support"
++      default m
++      help
++      This module provides the function of E24 device.
+--- /dev/null
++++ b/drivers/e24/Makefile
+@@ -0,0 +1,12 @@
++# SPDX-License-Identifier: GPL-2.0
++# Copyright(c) 1999 - 2018 Intel Corporation.
++#
++# Makefile for the E24 driver
++#
++ccflags-y += -I$(srctree)/drivers/e24
++#ccflags-y += -DDEBUG
++ccflags-y += -Wunused-variable -Wno-error=missing-prototypes
++
++obj-$(CONFIG_E24) += e24.o
++
++e24-y := starfive_e24.o starfive_e24_hw.o e24_alloc.o
+--- /dev/null
++++ b/drivers/e24/e24_alloc.c
+@@ -0,0 +1,241 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <linux/atomic.h>
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++#include "e24_alloc.h"
++
++struct e24_private_pool {
++      struct e24_allocation_pool pool;
++      struct mutex free_list_lock;
++      phys_addr_t start;
++      u32 size;
++      struct e24_allocation *free_list;
++};
++
++static void e24_private_free(struct e24_allocation *e24_allocation)
++{
++      struct e24_private_pool *pool = container_of(e24_allocation->pool,
++                                                   struct e24_private_pool,
++                                                   pool);
++      struct e24_allocation **pcur;
++
++      pr_debug("%s: %pap x %d\n", __func__,
++               &e24_allocation->start, e24_allocation->size);
++
++      mutex_lock(&pool->free_list_lock);
++
++      for (pcur = &pool->free_list; ; pcur = &(*pcur)->next) {
++              struct e24_allocation *cur = *pcur;
++
++              if (cur && cur->start + cur->size == e24_allocation->start) {
++                      struct e24_allocation *next = cur->next;
++
++                      pr_debug("merging block tail: %pap x 0x%x ->\n",
++                               &cur->start, cur->size);
++                      cur->size += e24_allocation->size;
++                      pr_debug("... -> %pap x 0x%x\n",
++                               &cur->start, cur->size);
++                      kfree(e24_allocation);
++
++                      if (next && cur->start + cur->size == next->start) {
++                              pr_debug("merging with next block: %pap x 0x%x ->\n",
++                                       &cur->start, cur->size);
++                              cur->size += next->size;
++                              cur->next = next->next;
++                              pr_debug("... -> %pap x 0x%x\n",
++                                       &cur->start, cur->size);
++                              kfree(next);
++                      }
++                      break;
++              }
++
++              if (!cur || e24_allocation->start < cur->start) {
++                      if (cur && e24_allocation->start + e24_allocation->size ==
++                          cur->start) {
++                              pr_debug("merging block head: %pap x 0x%x ->\n",
++                                       &cur->start, cur->size);
++                              cur->size += e24_allocation->size;
++                              cur->start = e24_allocation->start;
++                              pr_debug("... -> %pap x 0x%x\n",
++                                       &cur->start, cur->size);
++                              kfree(e24_allocation);
++                      } else {
++                              pr_debug("inserting new free block\n");
++                              e24_allocation->next = cur;
++                              *pcur = e24_allocation;
++                      }
++                      break;
++              }
++      }
++
++      mutex_unlock(&pool->free_list_lock);
++}
++
++static long e24_private_alloc(struct e24_allocation_pool *pool,
++                            u32 size, u32 align,
++                            struct e24_allocation **alloc)
++{
++      struct e24_private_pool *ppool = container_of(pool,
++                                                    struct e24_private_pool,
++                                                    pool);
++      struct e24_allocation **pcur;
++      struct e24_allocation *cur = NULL;
++      struct e24_allocation *new;
++      phys_addr_t aligned_start = 0;
++      bool found = false;
++
++      if (!size || (align & (align - 1)))
++              return -EINVAL;
++      if (!align)
++              align = 1;
++
++      new = kzalloc(sizeof(struct e24_allocation), GFP_KERNEL);
++      if (!new)
++              return -ENOMEM;
++
++      align = ALIGN(align, PAGE_SIZE);
++      size = ALIGN(size, PAGE_SIZE);
++
++      mutex_lock(&ppool->free_list_lock);
++
++      /* on exit free list is fixed */
++      for (pcur = &ppool->free_list; *pcur; pcur = &(*pcur)->next) {
++              cur = *pcur;
++              aligned_start = ALIGN(cur->start, align);
++
++              if (aligned_start >= cur->start &&
++                  aligned_start - cur->start + size <= cur->size) {
++                      if (aligned_start == cur->start) {
++                              if (aligned_start + size == cur->start + cur->size) {
++                                      pr_debug("reusing complete block: %pap x %x\n",
++                                               &cur->start, cur->size);
++                                      *pcur = cur->next;
++                              } else {
++                                      pr_debug("cutting block head: %pap x %x ->\n",
++                                               &cur->start, cur->size);
++                                      cur->size -= aligned_start + size - cur->start;
++                                      cur->start = aligned_start + size;
++                                      pr_debug("... -> %pap x %x\n",
++                                               &cur->start, cur->size);
++                                      cur = NULL;
++                              }
++                      } else {
++                              if (aligned_start + size == cur->start + cur->size) {
++                                      pr_debug("cutting block tail: %pap x %x ->\n",
++                                               &cur->start, cur->size);
++                                      cur->size = aligned_start - cur->start;
++                                      pr_debug("... -> %pap x %x\n",
++                                               &cur->start, cur->size);
++                                      cur = NULL;
++                              } else {
++                                      pr_debug("splitting block into two: %pap x %x ->\n",
++                                               &cur->start, cur->size);
++                                      new->start = aligned_start + size;
++                                      new->size = cur->start +
++                                              cur->size - new->start;
++
++                                      cur->size = aligned_start - cur->start;
++
++                                      new->next = cur->next;
++                                      cur->next = new;
++                                      pr_debug("... -> %pap x %x + %pap x %x\n",
++                                               &cur->start, cur->size,
++                                               &new->start, new->size);
++
++                                      cur = NULL;
++                                      new = NULL;
++                              }
++                      }
++                      found = true;
++                      break;
++              } else {
++                      cur = NULL;
++              }
++      }
++
++      mutex_unlock(&ppool->free_list_lock);
++
++      if (!found) {
++              kfree(cur);
++              kfree(new);
++              return -ENOMEM;
++      }
++
++      if (!cur) {
++              cur = new;
++              new = NULL;
++      }
++      if (!cur) {
++              cur = kzalloc(sizeof(struct e24_allocation), GFP_KERNEL);
++              if (!cur)
++                      return -ENOMEM;
++      }
++
++      kfree(new);
++      pr_debug("returning: %pap x %x\n", &aligned_start, size);
++      cur->start = aligned_start;
++      cur->size = size;
++      cur->pool = pool;
++      atomic_set(&cur->ref, 0);
++      atomic_inc(&cur->ref);
++      *alloc = cur;
++
++      return 0;
++}
++
++static void e24_private_free_pool(struct e24_allocation_pool *pool)
++{
++      struct e24_private_pool *ppool = container_of(pool,
++                                                    struct e24_private_pool,
++                                                    pool);
++      kfree(ppool->free_list);
++      kfree(ppool);
++}
++
++static phys_addr_t e24_private_offset(const struct e24_allocation *allocation)
++{
++      struct e24_private_pool *ppool = container_of(allocation->pool,
++                                                    struct e24_private_pool,
++                                                    pool);
++      return allocation->start - ppool->start;
++}
++
++static const struct e24_allocation_ops e24_private_pool_ops = {
++      .alloc = e24_private_alloc,
++      .free = e24_private_free,
++      .free_pool = e24_private_free_pool,
++      .offset = e24_private_offset,
++};
++
++long e24_init_private_pool(struct e24_allocation_pool **ppool,
++                         phys_addr_t start, u32 size)
++{
++      struct e24_private_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
++      struct e24_allocation *allocation = kmalloc(sizeof(*allocation),
++                                                  GFP_KERNEL);
++
++      if (!pool || !allocation) {
++              kfree(pool);
++              kfree(allocation);
++              return -ENOMEM;
++      }
++
++      *allocation = (struct e24_allocation){
++              .pool = &pool->pool,
++              .start = start,
++              .size = size,
++      };
++      *pool = (struct e24_private_pool){
++              .pool = {
++                      .ops = &e24_private_pool_ops,
++              },
++              .start = start,
++              .size = size,
++              .free_list = allocation,
++      };
++      mutex_init(&pool->free_list_lock);
++      *ppool = &pool->pool;
++      return 0;
++}
+--- /dev/null
++++ b/drivers/e24/e24_alloc.h
+@@ -0,0 +1,59 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef E24_ALLOC_H
++#define E24_ALLOC_H
++
++struct e24_allocation_pool;
++struct e24_allocation;
++
++struct e24_allocation_ops {
++      long (*alloc)(struct e24_allocation_pool *allocation_pool,
++                    u32 size, u32 align, struct e24_allocation **alloc);
++      void (*free)(struct e24_allocation *allocation);
++      void (*free_pool)(struct e24_allocation_pool *allocation_pool);
++      phys_addr_t (*offset)(const struct e24_allocation *allocation);
++};
++
++struct e24_allocation_pool {
++      const struct e24_allocation_ops *ops;
++};
++
++struct e24_allocation {
++      struct e24_allocation_pool *pool;
++      struct e24_allocation *next;
++      phys_addr_t start;
++      u32 size;
++      atomic_t ref;
++};
++
++static inline void e24_free_pool(struct e24_allocation_pool *allocation_pool)
++{
++      allocation_pool->ops->free_pool(allocation_pool);
++}
++
++static inline void e24_free(struct e24_allocation *allocation)
++{
++      return allocation->pool->ops->free(allocation);
++}
++
++static inline long e24_allocate(struct e24_allocation_pool *allocation_pool,
++                              u32 size, u32 align,
++                              struct e24_allocation **alloc)
++{
++      return allocation_pool->ops->alloc(allocation_pool,
++                                         size, align, alloc);
++}
++
++static inline void e24_allocation_put(struct e24_allocation *e24_allocation)
++{
++      if (atomic_dec_and_test(&e24_allocation->ref))
++              e24_allocation->pool->ops->free(e24_allocation);
++}
++
++static inline phys_addr_t e24_allocation_offset(const struct e24_allocation *allocation)
++{
++      return allocation->pool->ops->offset(allocation);
++}
++
++long e24_init_private_pool(struct e24_allocation_pool **ppool, phys_addr_t start, u32 size);
++
++#endif
+--- /dev/null
++++ b/drivers/e24/starfive_e24.c
+@@ -0,0 +1,1522 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * e24 driver for StarFive JH7110 SoC
++ *
++ * Copyright (c) 2021 StarFive Technology Co., Ltd.
++ * Author: Shanlong Li <shanlong.li@starfivetech.com>
++ */
++#include <linux/version.h>
++#include <linux/atomic.h>
++#include <linux/acpi.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)
++#include <linux/dma-mapping.h>
++#else
++#include <linux/dma-direct.h>
++#endif
++#include <linux/firmware.h>
++#include <linux/fs.h>
++#include <linux/hashtable.h>
++#include <linux/highmem.h>
++#include <linux/idr.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/of_reserved_mem.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/property.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/mman.h>
++#include <linux/uaccess.h>
++#include <linux/mailbox_controller.h>
++#include <linux/mailbox_client.h>
++
++#include <linux/bsearch.h>
++
++#include "e24_alloc.h"
++#include "starfive_e24.h"
++#include "starfive_e24_hw.h"
++
++#define EMBOX_MAX_MSG_LEN     4
++
++static DEFINE_IDA(e24_nodeid);
++
++struct e24_dsp_cmd {
++      __u32 flags;
++      __u32 in_data_size;
++      __u32 out_data_size;
++      union {
++              __u32 in_data_addr;
++              __u8 in_data[E24_DSP_CMD_INLINE_DATA_SIZE];
++      };
++      union {
++              __u32 out_data_addr;
++              __u8 out_data[E24_DSP_CMD_INLINE_DATA_SIZE];
++      };
++};
++
++struct e24_ioctl_user {
++      u32 flags;
++      u32 in_data_size;
++      u32 out_data_size;
++      u64 in_data_addr;
++      u64 out_data_addr;
++};
++
++struct e24_ioctl_request {
++      struct e24_ioctl_user ioctl_data;
++      phys_addr_t in_data_phys;
++      phys_addr_t out_data_phys;
++      struct e24_mapping *buffer_mapping;
++
++      union {
++              struct e24_mapping in_data_mapping;
++              u8 in_data[E24_DSP_CMD_INLINE_DATA_SIZE];
++      };
++      union {
++              struct e24_mapping out_data_mapping;
++              u8 out_data[E24_DSP_CMD_INLINE_DATA_SIZE];
++      };
++};
++
++static int firmware_command_timeout = 10;
++
++static inline void e24_comm_read(volatile void __iomem *addr, void *p,
++                                size_t sz)
++{
++      size_t sz32 = sz & ~3;
++      u32 v;
++
++      while (sz32) {
++              v = __raw_readl(addr);
++              memcpy(p, &v, sizeof(v));
++              p += 4;
++              addr += 4;
++              sz32 -= 4;
++      }
++      sz &= 3;
++      if (sz) {
++              v = __raw_readl(addr);
++              memcpy(p, &v, sz);
++      }
++}
++
++static inline void e24_comm_write(volatile void __iomem *addr, const void *p,
++                                size_t sz)
++{
++      size_t sz32 = sz & ~3;
++      u32 v;
++
++      while (sz32) {
++              memcpy(&v, p, sizeof(v));
++              __raw_writel(v, addr);
++              p += 4;
++              addr += 4;
++              sz32 -= 4;
++      }
++      sz &= 3;
++      if (sz) {
++              v = 0;
++              memcpy(&v, p, sz);
++              __raw_writel(v, addr);
++      }
++}
++
++static bool e24_cacheable(struct e24_device *e24_dat, unsigned long pfn,
++                        unsigned long n_pages)
++{
++      if (e24_dat->hw_ops->cacheable) {
++              return e24_dat->hw_ops->cacheable(e24_dat->hw_arg, pfn, n_pages);
++      } else {
++              unsigned long i;
++
++              for (i = 0; i < n_pages; ++i)
++                      if (!pfn_valid(pfn + i))
++                              return false;
++              return true;
++      }
++}
++
++static int e24_compare_address_sort(const void *a, const void *b)
++{
++      const struct e24_address_map_entry *pa = a;
++      const struct e24_address_map_entry *pb = b;
++
++      if (pa->src_addr < pb->src_addr &&
++              pb->src_addr - pa->src_addr >= pa->size)
++              return -1;
++      if (pa->src_addr > pb->src_addr &&
++              pa->src_addr - pb->src_addr >= pb->size)
++              return 1;
++
++      return 0;
++}
++
++static int e24_compare_address_search(const void *a, const void *b)
++{
++      const phys_addr_t *pa = a;
++
++      return e24_compare_address(*pa, b);
++}
++
++struct e24_address_map_entry *
++e24_get_address_mapping(const struct e24_address_map *map, phys_addr_t addr)
++{
++      return bsearch(&addr, map->entry, map->n, sizeof(*map->entry),
++                      e24_compare_address_search);
++}
++
++u32 e24_translate_to_dsp(const struct e24_address_map *map, phys_addr_t addr)
++{
++#ifdef E24_MEM_MAP
++      return addr;
++#else
++      struct e24_address_map_entry *entry = e24_get_address_mapping(map, addr);
++
++      if (!entry)
++              return E24_NO_TRANSLATION;
++      return entry->dst_addr + addr - entry->src_addr;
++#endif
++}
++
++static int e24_dma_direction(unsigned int flags)
++{
++      static const enum dma_data_direction e24_dma_direction[] = {
++              [0] = DMA_NONE,
++              [E24_FLAG_READ] = DMA_TO_DEVICE,
++              [E24_FLAG_WRITE] = DMA_FROM_DEVICE,
++              [E24_FLAG_READ_WRITE] = DMA_BIDIRECTIONAL,
++      };
++      return e24_dma_direction[flags & E24_FLAG_READ_WRITE];
++}
++
++static void e24_dma_sync_for_cpu(struct e24_device *e24_dat,
++                               unsigned long virt,
++                               phys_addr_t phys,
++                               unsigned long size,
++                               unsigned long flags)
++{
++      if (e24_dat->hw_ops->dma_sync_for_cpu)
++              e24_dat->hw_ops->dma_sync_for_cpu(e24_dat->hw_arg,
++                                            (void *)virt, phys, size,
++                                            flags);
++      else
++              dma_sync_single_for_cpu(e24_dat->dev, phys_to_dma(e24_dat->dev, phys), size,
++                      e24_dma_direction(flags));
++}
++
++static void starfive_mbox_receive_message(struct mbox_client *client, void *message)
++{
++      struct e24_device *e24_dat = dev_get_drvdata(client->dev);
++
++      complete(&e24_dat->tx_channel->tx_complete);
++}
++
++static struct mbox_chan *
++starfive_mbox_request_channel(struct device *dev, const char *name)
++{
++      struct mbox_client *client;
++      struct mbox_chan *channel;
++
++      client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL);
++      if (!client)
++              return ERR_PTR(-ENOMEM);
++
++      client->dev             = dev;
++      client->rx_callback     = starfive_mbox_receive_message;
++      client->tx_prepare      = NULL;
++      client->tx_done         = NULL;
++      client->tx_block        = true;
++      client->knows_txdone    = false;
++      client->tx_tout         = 3000;
++
++      channel = mbox_request_channel_byname(client, name);
++      if (IS_ERR(channel)) {
++              dev_warn(dev, "Failed to request %s channel\n", name);
++              return NULL;
++      }
++
++      return channel;
++}
++
++static void e24_vm_open(struct vm_area_struct *vma)
++{
++      struct e24_allocation *cur = vma->vm_private_data;
++
++      atomic_inc(&cur->ref);
++}
++
++static void e24_vm_close(struct vm_area_struct *vma)
++{
++      e24_allocation_put(vma->vm_private_data);
++}
++
++static const struct vm_operations_struct e24_vm_ops = {
++      .open = e24_vm_open,
++      .close = e24_vm_close,
++};
++
++static long e24_synchronize(struct e24_device *dev)
++{
++
++      struct e24_comm *queue = dev->queue;
++      struct e24_dsp_cmd __iomem *cmd = queue->comm;
++      u32 flags;
++      unsigned long deadline = jiffies + 10 * HZ;
++
++      do {
++              flags = __raw_readl(&cmd->flags);
++              /* memory barrier */
++              rmb();
++              if (flags == 0x104)
++                      return 0;
++
++              schedule();
++      } while (time_before(jiffies, deadline));
++
++      return -1;
++}
++
++static int e24_open(struct inode *inode, struct file *filp)
++{
++      struct e24_device *e24_dev = container_of(filp->private_data,
++                                      struct e24_device, miscdev);
++      int rc = 0;
++
++      rc = pm_runtime_get_sync(e24_dev->dev);
++      if (rc < 0)
++              return rc;
++
++      spin_lock_init(&e24_dev->busy_list_lock);
++      filp->private_data = e24_dev;
++      mdelay(1);
++
++      return 0;
++}
++
++int e24_release(struct inode *inode, struct file *filp)
++{
++      struct e24_device *e24_dev = (struct e24_device *)filp->private_data;
++      int rc = 0;
++
++      rc = pm_runtime_put_sync(e24_dev->dev);
++      if (rc < 0)
++              return rc;
++
++      return 0;
++}
++
++static ssize_t mbox_e24_message_write(struct file *filp,
++                                     const char __user *userbuf,
++                                     size_t count, loff_t *ppos)
++{
++      struct e24_device *edev = filp->private_data;
++      void *data;
++      int ret;
++
++      if (!edev->tx_channel) {
++              dev_err(edev->dev, "Channel cannot do Tx\n");
++              return -EINVAL;
++      }
++
++      if (count > EMBOX_MAX_MSG_LEN) {
++              dev_err(edev->dev,
++                      "Message length %zd greater than max allowed %d\n",
++                      count, EMBOX_MAX_MSG_LEN);
++              return -EINVAL;
++      }
++
++      edev->message = kzalloc(EMBOX_MAX_MSG_LEN, GFP_KERNEL);
++      if (!edev->message)
++              return -ENOMEM;
++
++      ret = copy_from_user(edev->message, userbuf, count);
++      if (ret) {
++              ret = -EFAULT;
++              goto out;
++      }
++
++      print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
++                           edev->message, EMBOX_MAX_MSG_LEN);
++      data = edev->message;
++      pr_debug("%s:%d, %d\n", __func__, __LINE__, *((int *)data));
++      ret = mbox_send_message(edev->tx_channel, data);
++
++      if (ret < 0 || !edev->tx_channel->active_req)
++              dev_err(edev->dev, "Failed to send message via mailbox:%d\n", ret);
++
++out:
++      kfree(edev->message);
++      edev->tx_channel->active_req =  NULL;
++
++      return ret < 0 ? ret : count;
++}
++
++static long _e24_copy_user_phys(struct e24_device *edev,
++                              unsigned long vaddr, unsigned long size,
++                              phys_addr_t paddr, unsigned long flags,
++                              bool to_phys)
++{
++      void __iomem *p = ioremap(paddr, size);
++      unsigned long rc;
++
++      if (!p) {
++              dev_err(edev->dev,
++                      "couldn't ioremap %pap x 0x%08x\n",
++                      &paddr, (u32)size);
++              return -EINVAL;
++      }
++      if (to_phys)
++              rc = raw_copy_from_user(__io_virt(p),
++                                      (void __user *)vaddr, size);
++      else
++              rc = copy_to_user((void __user *)vaddr,
++                                      __io_virt(p), size);
++      iounmap(p);
++      if (rc)
++              return -EFAULT;
++      return 0;
++}
++
++static long e24_copy_user_to_phys(struct e24_device *edev,
++                              unsigned long vaddr, unsigned long size,
++                              phys_addr_t paddr, unsigned long flags)
++{
++      return _e24_copy_user_phys(edev, vaddr, size, paddr, flags, true);
++}
++
++static long e24_copy_user_from_phys(struct e24_device *edev,
++                              unsigned long vaddr, unsigned long size,
++                              phys_addr_t paddr, unsigned long flags)
++{
++      return _e24_copy_user_phys(edev, vaddr, size, paddr, flags, false);
++}
++
++static long e24_copy_virt_to_phys(struct e24_device *edev,
++                              unsigned long flags,
++                              unsigned long vaddr, unsigned long size,
++                              phys_addr_t *paddr,
++                              struct e24_alien_mapping *mapping)
++{
++      phys_addr_t phys;
++      unsigned long align = clamp(vaddr & -vaddr, 16ul, PAGE_SIZE);
++      unsigned long offset = vaddr & (align - 1);
++      struct e24_allocation *allocation;
++      long rc;
++
++      rc = e24_allocate(edev->pool,
++                        size + align, align, &allocation);
++      if (rc < 0)
++              return rc;
++
++      phys = (allocation->start & -align) | offset;
++      if (phys < allocation->start)
++              phys += align;
++
++      if (flags & E24_FLAG_READ) {
++              if (e24_copy_user_to_phys(edev, vaddr,
++                                      size, phys, flags)) {
++                      e24_allocation_put(allocation);
++                      return -EFAULT;
++              }
++      }
++
++      *paddr = phys;
++      *mapping = (struct e24_alien_mapping){
++              .vaddr = vaddr,
++              .size = size,
++              .paddr = *paddr,
++              .allocation = allocation,
++              .type = ALIEN_COPY,
++      };
++      pr_debug("%s: copying to pa: %pap\n", __func__, paddr);
++
++      return 0;
++}
++
++static long e24_writeback_alien_mapping(struct e24_device *edev,
++                                      struct e24_alien_mapping *alien_mapping,
++                                      unsigned long flags)
++{
++      struct page *page;
++      size_t nr_pages;
++      size_t i;
++      long ret = 0;
++
++      switch (alien_mapping->type) {
++      case ALIEN_GUP:
++              e24_dma_sync_for_cpu(edev,
++                                   alien_mapping->vaddr,
++                                   alien_mapping->paddr,
++                                   alien_mapping->size,
++                                   flags);
++              pr_debug("%s: dirtying alien GUP @va = %p, pa = %pap\n",
++                       __func__, (void __user *)alien_mapping->vaddr,
++                       &alien_mapping->paddr);
++              page = pfn_to_page(__phys_to_pfn(alien_mapping->paddr));
++              nr_pages = PFN_UP(alien_mapping->vaddr + alien_mapping->size) -
++                      PFN_DOWN(alien_mapping->vaddr);
++              for (i = 0; i < nr_pages; ++i)
++                      SetPageDirty(page + i);
++              break;
++
++      case ALIEN_COPY:
++              pr_debug("%s: synchronizing alien copy @pa = %pap back to %p\n",
++                       __func__, &alien_mapping->paddr,
++                       (void __user *)alien_mapping->vaddr);
++              if (e24_copy_user_from_phys(edev,
++                                          alien_mapping->vaddr,
++                                          alien_mapping->size,
++                                          alien_mapping->paddr,
++                                          flags))
++                      ret = -EINVAL;
++              break;
++
++      default:
++              break;
++      }
++      return ret;
++}
++
++static bool vma_needs_cache_ops(struct vm_area_struct *vma)
++{
++      pgprot_t prot = vma->vm_page_prot;
++
++      return pgprot_val(prot) != pgprot_val(pgprot_noncached(prot)) &&
++              pgprot_val(prot) != pgprot_val(pgprot_writecombine(prot));
++}
++
++static void e24_alien_mapping_destroy(struct e24_alien_mapping *alien_mapping)
++{
++      switch (alien_mapping->type) {
++      case ALIEN_COPY:
++              e24_allocation_put(alien_mapping->allocation);
++              break;
++      default:
++              break;
++      }
++}
++
++static long __e24_unshare_block(struct file *filp, struct e24_mapping *mapping,
++                              unsigned long flags)
++{
++      long ret = 0;
++      struct e24_device *edev = filp->private_data;
++
++      switch (mapping->type & ~E24_MAPPING_KERNEL) {
++      case E24_MAPPING_NATIVE:
++              if (flags & E24_FLAG_WRITE) {
++                      e24_dma_sync_for_cpu(edev,
++                                   mapping->native.vaddr,
++                                   mapping->native.m_allocation->start,
++                                   mapping->native.m_allocation->size,
++                                   flags);
++              }
++              e24_allocation_put(mapping->native.m_allocation);
++              break;
++
++      case E24_MAPPING_ALIEN:
++              if (flags & E24_FLAG_WRITE) {
++                      ret = e24_writeback_alien_mapping(edev,
++                                                        &mapping->alien_mapping,
++                                                        flags);
++              }
++              e24_alien_mapping_destroy(&mapping->alien_mapping);
++              break;
++
++      case E24_MAPPING_KERNEL:
++              break;
++
++      default:
++              break;
++      }
++
++      mapping->type = E24_MAPPING_NONE;
++
++      return ret;
++}
++
++static long __e24_share_block(struct file *filp,
++                            unsigned long virt, unsigned long size,
++                            unsigned long flags, phys_addr_t *paddr,
++                            struct e24_mapping *mapping)
++{
++      phys_addr_t phys = ~0ul;
++      struct e24_device *edev = filp->private_data;
++      struct mm_struct *mm = current->mm;
++      struct vm_area_struct *vma = find_vma(mm, virt);
++      bool do_cache = true;
++      long rc = -EINVAL;
++
++      if (!vma) {
++              pr_debug("%s: no vma for vaddr/size = 0x%08lx/0x%08lx\n",
++                       __func__, virt, size);
++              return -EINVAL;
++      }
++
++      if (virt + size < virt || vma->vm_start > virt)
++              return -EINVAL;
++
++      if (vma && (vma->vm_file == filp)) {
++              struct e24_device *vm_file = vma->vm_file->private_data;
++              struct e24_allocation *e24_user_allocation = vma->vm_private_data;
++
++              phys = vm_file->shared_mem + (vma->vm_pgoff << PAGE_SHIFT) +
++                      virt - vma->vm_start;
++              pr_debug("%s: E24 allocation at 0x%08lx, paddr: %pap\n",
++                       __func__, virt, &phys);
++
++              rc = 0;
++              mapping->type = E24_MAPPING_NATIVE;
++              mapping->native.m_allocation = e24_user_allocation;
++              mapping->native.vaddr = virt;
++              atomic_inc(&e24_user_allocation->ref);
++              do_cache = vma_needs_cache_ops(vma);
++      }
++      if (rc < 0) {
++              struct e24_alien_mapping *alien_mapping =
++                      &mapping->alien_mapping;
++
++              /* Otherwise this is alien allocation. */
++              pr_debug("%s: non-E24 allocation at 0x%08lx\n",
++                       __func__, virt);
++
++              rc = e24_copy_virt_to_phys(edev, flags,
++                                         virt, size, &phys,
++                                         alien_mapping);
++
++              if (rc < 0) {
++                      pr_debug("%s: couldn't map virt to phys\n",
++                               __func__);
++                      return -EINVAL;
++              }
++
++              phys = alien_mapping->paddr +
++                      virt - alien_mapping->vaddr;
++
++              mapping->type = E24_MAPPING_ALIEN;
++      }
++
++      *paddr = phys;
++      pr_debug("%s: mapping = %p, mapping->type = %d\n",
++               __func__, mapping, mapping->type);
++
++      return 0;
++}
++
++
++static void e24_unmap_request_nowb(struct file *filp, struct e24_ioctl_request *rq)
++{
++      if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE)
++              __e24_unshare_block(filp, &rq->in_data_mapping, 0);
++      if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE)
++              __e24_unshare_block(filp, &rq->out_data_mapping, 0);
++}
++
++static long e24_unmap_request(struct file *filp, struct e24_ioctl_request *rq)
++{
++      long ret = 0;
++
++      if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE)
++              __e24_unshare_block(filp, &rq->in_data_mapping, E24_FLAG_READ);
++
++      if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) {
++              ret = __e24_unshare_block(filp, &rq->out_data_mapping,
++                                       E24_FLAG_WRITE);
++              if (ret < 0)
++                      pr_debug("%s: out_data could not be unshared\n", __func__);
++
++      } else {
++              if (copy_to_user((void __user *)(unsigned long)rq->ioctl_data.out_data_addr,
++                               rq->out_data,
++                               rq->ioctl_data.out_data_size)) {
++                      pr_debug("%s: out_data could not be copied\n", __func__);
++                      ret = -EFAULT;
++              }
++      }
++
++      return ret;
++}
++
++static bool e24_cmd_complete(struct e24_comm *share_com)
++{
++      struct e24_dsp_cmd __iomem *cmd = share_com->comm;
++      u32 flags = __raw_readl(&cmd->flags);
++
++      rmb();
++      return (flags & (E24_CMD_FLAG_REQUEST_VALID |
++                       E24_CMD_FLAG_RESPONSE_VALID)) ==
++              (E24_CMD_FLAG_REQUEST_VALID |
++               E24_CMD_FLAG_RESPONSE_VALID);
++}
++
++static long e24_complete_poll(struct e24_device *edev, struct e24_comm *comm,
++                                bool (*cmd_complete)(struct e24_comm *p), struct e24_ioctl_request *rq)
++{
++      unsigned long deadline = jiffies + firmware_command_timeout * HZ;
++
++      do {
++              if (cmd_complete(comm)) {
++                      pr_debug("%s: poll complete.\n", __func__);
++                      return 0;
++              }
++              schedule();
++      } while (time_before(jiffies, deadline));
++
++      pr_debug("%s: poll complete cmd timeout.\n", __func__);
++
++      return -EBUSY;
++}
++
++static long e24_map_request(struct file *filp, struct e24_ioctl_request *rq, struct mm_struct *mm)
++{
++      long ret = 0;
++
++      mmap_read_lock(mm);
++      if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) {
++              ret = __e24_share_block(filp, rq->ioctl_data.in_data_addr,
++                                      rq->ioctl_data.in_data_size,
++                                      E24_FLAG_READ, &rq->in_data_phys,
++                                      &rq->in_data_mapping);
++              if (ret < 0) {
++                      pr_debug("%s: in_data could not be shared\n", __func__);
++                      goto share_err;
++              }
++      } else {
++              if (copy_from_user(rq->in_data,
++                                 (void __user *)(unsigned long)rq->ioctl_data.in_data_addr,
++                                 rq->ioctl_data.in_data_size)) {
++                      pr_debug("%s: in_data could not be copied\n",
++                               __func__);
++                      ret = -EFAULT;
++                      goto share_err;
++              }
++      }
++
++      if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) {
++              ret = __e24_share_block(filp, rq->ioctl_data.out_data_addr,
++                                      rq->ioctl_data.out_data_size,
++                                      E24_FLAG_WRITE, &rq->out_data_phys,
++                                      &rq->out_data_mapping);
++              if (ret < 0) {
++                      pr_debug("%s: out_data could not be shared\n",
++                               __func__);
++                      goto share_err;
++              }
++      }
++share_err:
++      mmap_read_unlock(mm);
++      if (ret < 0)
++              e24_unmap_request_nowb(filp, rq);
++      return ret;
++
++}
++
++static void e24_fill_hw_request(struct e24_dsp_cmd __iomem *cmd,
++                              struct e24_ioctl_request *rq,
++                              const struct e24_address_map *map)
++{
++      __raw_writel(rq->ioctl_data.in_data_size, &cmd->in_data_size);
++      __raw_writel(rq->ioctl_data.out_data_size, &cmd->out_data_size);
++
++      if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE)
++              __raw_writel(e24_translate_to_dsp(map, rq->in_data_phys),
++                              &cmd->in_data_addr);
++      else
++              e24_comm_write(&cmd->in_data, rq->in_data,
++                             rq->ioctl_data.in_data_size);
++
++      if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE)
++              __raw_writel(e24_translate_to_dsp(map, rq->out_data_phys),
++                              &cmd->out_data_addr);
++
++      wmb();
++      /* update flags */
++      __raw_writel(rq->ioctl_data.flags, &cmd->flags);
++}
++
++static long e24_complete_hw_request(struct e24_dsp_cmd __iomem *cmd,
++                                  struct e24_ioctl_request *rq)
++{
++      u32 flags = __raw_readl(&cmd->flags);
++
++      if (rq->ioctl_data.out_data_size <= E24_DSP_CMD_INLINE_DATA_SIZE)
++              e24_comm_read(&cmd->out_data, rq->out_data,
++                            rq->ioctl_data.out_data_size);
++
++      __raw_writel(0, &cmd->flags);
++
++      return (flags & E24_QUEUE_VALID_FLAGS) ? -ENXIO : 0;
++}
++
++static long e24_ioctl_submit_task(struct file *filp,
++                                struct e24_ioctl_user __user *msg)
++{
++      struct e24_device *edev = filp->private_data;
++      struct e24_comm *queue = edev->queue;
++      struct e24_ioctl_request rq_data, *vrq = &rq_data;
++      void *data = &edev->mbox_data;
++      int ret = -ENOMEM;
++      int irq_mode = edev->irq_mode;
++
++      if (copy_from_user(&vrq->ioctl_data, msg, sizeof(*msg)))
++              return -EFAULT;
++
++      if (vrq->ioctl_data.flags & ~E24_QUEUE_VALID_FLAGS) {
++              dev_dbg(edev->dev, "%s: invalid flags 0x%08x\n",
++                      __func__, vrq->ioctl_data.flags);
++              return -EINVAL;
++      }
++
++      ret = e24_map_request(filp, vrq, current->mm);
++      if (ret < 0)
++              return ret;
++
++      mutex_lock(&queue->lock);
++      e24_fill_hw_request(queue->comm, vrq, &edev->address_map);
++
++      if (irq_mode) {
++              ret = mbox_send_message(edev->tx_channel, data);
++              mbox_chan_txdone(edev->tx_channel, ret);
++      } else {
++              ret = e24_complete_poll(edev, queue, e24_cmd_complete, vrq);
++      }
++
++      ret = e24_complete_hw_request(queue->comm, vrq);
++      mutex_unlock(&queue->lock);
++
++      if (ret == 0)
++              ret = e24_unmap_request(filp, vrq);
++
++      return ret;
++}
++
++static long e24_ioctl_get_channel(struct file *filp,
++                              void __user *msg)
++{
++      struct e24_device *edev = filp->private_data;
++
++      if (edev->tx_channel == NULL)
++              edev->tx_channel = starfive_mbox_request_channel(edev->dev, "tx");
++      if (edev->rx_channel == NULL)
++              edev->rx_channel = starfive_mbox_request_channel(edev->dev, "rx");
++
++      return 0;
++}
++
++static long e24_ioctl_free_channel(struct file *filp,
++                              void __user *msg)
++{
++      struct e24_device *edev = filp->private_data;
++
++      if (edev->rx_channel)
++              mbox_free_channel(edev->rx_channel);
++      if (edev->tx_channel)
++              mbox_free_channel(edev->tx_channel);
++
++      edev->rx_channel = NULL;
++      edev->tx_channel = NULL;
++      return 0;
++}
++
++static void e24_allocation_queue(struct e24_device *edev,
++                               struct e24_allocation *e24_pool_allocation)
++{
++      spin_lock(&edev->busy_list_lock);
++
++      e24_pool_allocation->next = edev->busy_list;
++      edev->busy_list = e24_pool_allocation;
++
++      spin_unlock(&edev->busy_list_lock);
++}
++
++static struct e24_allocation *e24_allocation_dequeue(struct e24_device *edev,
++                                                   phys_addr_t paddr, u32 size)
++{
++      struct e24_allocation **pcur;
++      struct e24_allocation *cur;
++
++      spin_lock(&edev->busy_list_lock);
++
++      for (pcur = &edev->busy_list; (cur = *pcur); pcur = &((*pcur)->next)) {
++              pr_debug("%s: %pap / %pap x %d\n", __func__, &paddr, &cur->start, cur->size);
++              if (paddr >= cur->start && paddr + size - cur->start <= cur->size) {
++                      *pcur = cur->next;
++                      break;
++              }
++      }
++
++      spin_unlock(&edev->busy_list_lock);
++      return cur;
++}
++
++static int e24_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++      int err;
++      struct e24_device *edev = filp->private_data;
++      unsigned long pfn = vma->vm_pgoff + PFN_DOWN(edev->shared_mem);
++      struct e24_allocation *e24_user_allocation;
++
++      e24_user_allocation = e24_allocation_dequeue(filp->private_data,
++                                              pfn << PAGE_SHIFT,
++                                              vma->vm_end - vma->vm_start);
++      if (e24_user_allocation) {
++              pgprot_t prot = vma->vm_page_prot;
++
++              if (!e24_cacheable(edev, pfn,
++                                 PFN_DOWN(vma->vm_end - vma->vm_start))) {
++                      prot = pgprot_writecombine(prot);
++                      vma->vm_page_prot = prot;
++              }
++
++              err = remap_pfn_range(vma, vma->vm_start, pfn,
++                                    vma->vm_end - vma->vm_start,
++                                    prot);
++
++              vma->vm_private_data = e24_user_allocation;
++              vma->vm_ops = &e24_vm_ops;
++      } else {
++              err = -EINVAL;
++      }
++
++      return err;
++}
++
++static long e24_ioctl_free(struct file *filp,
++                         struct e24_ioctl_alloc __user *p)
++{
++      struct mm_struct *mm = current->mm;
++      struct e24_ioctl_alloc user_ioctl_alloc;
++      struct vm_area_struct *vma;
++      unsigned long start;
++
++      if (copy_from_user(&user_ioctl_alloc, p, sizeof(*p)))
++              return -EFAULT;
++
++      start = user_ioctl_alloc.addr;
++      pr_debug("%s: virt_addr = 0x%08lx\n", __func__, start);
++
++      mmap_read_lock(mm);
++      vma = find_vma(mm, start);
++
++      if (vma && vma->vm_file == filp &&
++          vma->vm_start <= start && start < vma->vm_end) {
++              size_t size;
++
++              start = vma->vm_start;
++              size = vma->vm_end - vma->vm_start;
++              mmap_read_unlock(mm);
++              pr_debug("%s: 0x%lx x %zu\n", __func__, start, size);
++              return vm_munmap(start, size);
++      }
++      pr_debug("%s: no vma/bad vma for vaddr = 0x%08lx\n", __func__, start);
++      mmap_read_unlock(mm);
++
++      return -EINVAL;
++}
++
++static long e24_ioctl_alloc(struct file *filp,
++                          struct e24_ioctl_alloc __user *p)
++{
++      struct e24_device *edev = filp->private_data;
++      struct e24_allocation *e24_pool_allocation;
++      unsigned long vaddr;
++      struct e24_ioctl_alloc user_ioctl_alloc;
++      long err;
++
++      if (copy_from_user(&user_ioctl_alloc, p, sizeof(*p)))
++              return -EFAULT;
++
++      pr_debug("%s: size = %d, align = %x\n", __func__,
++               user_ioctl_alloc.size, user_ioctl_alloc.align);
++
++      err = e24_allocate(edev->pool,
++                         user_ioctl_alloc.size,
++                         user_ioctl_alloc.align,
++                         &e24_pool_allocation);
++      if (err)
++              return err;
++
++      e24_allocation_queue(edev, e24_pool_allocation);
++
++      vaddr = vm_mmap(filp, 0, e24_pool_allocation->size,
++                      PROT_READ | PROT_WRITE, MAP_SHARED,
++                      e24_allocation_offset(e24_pool_allocation));
++
++      user_ioctl_alloc.addr = vaddr;
++
++      if (copy_to_user(p, &user_ioctl_alloc, sizeof(*p))) {
++              vm_munmap(vaddr, user_ioctl_alloc.size);
++              return -EFAULT;
++      }
++      return 0;
++}
++
++static long e24_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++      long retval;
++
++      switch (cmd) {
++      case E24_IOCTL_SEND:
++              retval = e24_ioctl_submit_task(filp, (struct e24_ioctl_user *)arg);
++              break;
++      case E24_IOCTL_GET_CHANNEL:
++              retval = e24_ioctl_get_channel(filp, NULL);
++              break;
++      case E24_IOCTL_FREE_CHANNEL:
++              retval = e24_ioctl_free_channel(filp, NULL);
++              break;
++      case E24_IOCTL_ALLOC:
++              retval = e24_ioctl_alloc(filp, (struct e24_ioctl_alloc __user *)arg);
++              break;
++      case E24_IOCTL_FREE:
++              retval = e24_ioctl_free(filp, (struct e24_ioctl_alloc __user *)arg);
++              break;
++      default:
++              retval = -EINVAL;
++              break;
++      }
++      return retval;
++}
++
++static const struct file_operations e24_fops = {
++      .owner  = THIS_MODULE,
++      .unlocked_ioctl = e24_ioctl,
++#ifdef CONFIG_COMPAT
++      .compat_ioctl = e24_ioctl,
++#endif
++      .open = e24_open,
++      .release = e24_release,
++      .write = mbox_e24_message_write,
++      .mmap = e24_mmap,
++};
++
++void mailbox_task(struct platform_device *pdev)
++{
++      struct e24_device *e24_dev = platform_get_drvdata(pdev);
++
++      e24_dev->tx_channel = starfive_mbox_request_channel(e24_dev->dev, "tx");
++      e24_dev->rx_channel = starfive_mbox_request_channel(e24_dev->dev, "rx");
++      pr_debug("%s:%d.%#llx\n", __func__, __LINE__, (u64)e24_dev->rx_channel);
++}
++
++static long e24_init_mem_pool(struct platform_device *pdev, struct e24_device *devs)
++{
++      struct resource *mem;
++
++      mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecmd");
++      if (!mem)
++              return -ENODEV;
++
++      devs->comm_phys = mem->start;
++      devs->comm = devm_ioremap(&pdev->dev, mem->start, mem->end - mem->start);
++      mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "espace");
++      if (!mem)
++              return -ENODEV;
++
++      devs->shared_mem = mem->start;
++      devs->shared_size = resource_size(mem);
++      pr_debug("%s:%d.%llx,%llx\n", __func__, __LINE__, devs->comm_phys, devs->shared_mem);
++      return e24_init_private_pool(&devs->pool, devs->shared_mem, devs->shared_size);
++}
++
++static int e24_init_address_map(struct device *dev,
++                       struct e24_address_map *map)
++{
++#if IS_ENABLED(CONFIG_OF)
++      struct device_node *pnode = dev->of_node;
++      struct device_node *node;
++      int rlen, off;
++      const __be32 *ranges = of_get_property(pnode, "ranges", &rlen);
++      int na, pna, ns;
++      int i;
++
++      if (!ranges) {
++              dev_dbg(dev, "%s: no 'ranges' property in the device tree, no translation at that level\n",
++                      __func__);
++              goto empty;
++      }
++
++      node = of_get_next_child(pnode, NULL);
++      if (!node) {
++              dev_warn(dev, "%s: no child node found in the device tree, no translation at that level\n",
++                       __func__);
++              goto empty;
++      }
++
++      na = of_n_addr_cells(node);
++      ns = of_n_size_cells(node);
++      pna = of_n_addr_cells(pnode);
++
++      rlen /= 4;
++      map->n = rlen / (na + pna + ns);
++      map->entry = kmalloc_array(map->n, sizeof(*map->entry), GFP_KERNEL);
++      if (!map->entry)
++              return -ENOMEM;
++
++      dev_dbg(dev,
++              "%s: na = %d, pna = %d, ns = %d, rlen = %d cells, n = %d\n",
++              __func__, na, pna, ns, rlen, map->n);
++
++      for (off = 0, i = 0; off < rlen; off += na + pna + ns, ++i) {
++              map->entry[i].src_addr = of_translate_address(node,
++                                                            ranges + off);
++              map->entry[i].dst_addr = of_read_number(ranges + off, na);
++              map->entry[i].size = of_read_number(ranges + off + na + pna, ns);
++              dev_dbg(dev,
++                      "  src_addr = 0x%llx, dst_addr = 0x%lx, size = 0x%lx\n",
++                      (unsigned long long)map->entry[i].src_addr,
++                      (unsigned long)map->entry[i].dst_addr,
++                      (unsigned long)map->entry[i].size);
++      }
++      sort(map->entry, map->n, sizeof(*map->entry), e24_compare_address_sort, NULL);
++
++      of_node_put(node);
++      return 0;
++
++empty:
++#endif
++      map->n = 1;
++      map->entry = kmalloc(sizeof(*map->entry), GFP_KERNEL);
++      map->entry->src_addr = 0;
++      map->entry->dst_addr = 0;
++      map->entry->size = ~0u;
++      return -ENOMEM;
++}
++
++typedef long e24_init_function(struct platform_device *pdev);
++
++static inline void e24_init(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->init)
++              e24_hw->hw_ops->init(e24_hw->hw_arg);
++}
++
++static inline void e24_release_e24(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->reset)
++              e24_hw->hw_ops->release(e24_hw->hw_arg);
++}
++
++static inline void e24_halt_e24(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->halt)
++              e24_hw->hw_ops->halt(e24_hw->hw_arg);
++}
++
++static inline int e24_enable_e24(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->enable)
++              return e24_hw->hw_ops->enable(e24_hw->hw_arg);
++      else
++              return -EINVAL;
++}
++
++static inline void e24_reset_e24(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->reset)
++              e24_hw->hw_ops->reset(e24_hw->hw_arg);
++}
++
++static inline void e24_disable_e24(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->disable)
++              e24_hw->hw_ops->disable(e24_hw->hw_arg);
++}
++
++static inline void e24_sendirq_e24(struct e24_device *e24_hw)
++{
++      if (e24_hw->hw_ops->send_irq)
++              e24_hw->hw_ops->send_irq(e24_hw->hw_arg);
++}
++
++irqreturn_t e24_irq_handler(int irq, struct e24_device *e24_hw)
++{
++      dev_dbg(e24_hw->dev, "%s\n", __func__);
++      complete(&e24_hw->completion);
++
++      return IRQ_HANDLED;
++}
++EXPORT_SYMBOL(e24_irq_handler);
++
++static phys_addr_t e24_translate_to_cpu(struct e24_device *mail, Elf32_Phdr *phdr)
++{
++      phys_addr_t res;
++      __be32 addr = cpu_to_be32((u32)phdr->p_paddr);
++      struct device_node *node =
++              of_get_next_child(mail->dev->of_node, NULL);
++
++      if (!node)
++              node = mail->dev->of_node;
++
++      res = of_translate_address(node, &addr);
++
++      if (node != mail->dev->of_node)
++              of_node_put(node);
++      return res;
++}
++
++static int e24_load_segment_to_sysmem(struct e24_device *e24, Elf32_Phdr *phdr)
++{
++      phys_addr_t pa = e24_translate_to_cpu(e24, phdr);
++      struct page *page = pfn_to_page(__phys_to_pfn(pa));
++      size_t page_offs = pa & ~PAGE_MASK;
++      size_t offs;
++
++      for (offs = 0; offs < phdr->p_memsz; ++page) {
++              void *p = kmap(page);
++              size_t sz;
++
++              if (!p)
++                      return -ENOMEM;
++
++              page_offs &= ~PAGE_MASK;
++              sz = PAGE_SIZE - page_offs;
++
++              if (offs < phdr->p_filesz) {
++                      size_t copy_sz = sz;
++
++                      if (phdr->p_filesz - offs < copy_sz)
++                              copy_sz = phdr->p_filesz - offs;
++
++                      copy_sz = ALIGN(copy_sz, 4);
++                      memcpy(p + page_offs,
++                             (void *)e24->firmware->data +
++                             phdr->p_offset + offs,
++                             copy_sz);
++                      page_offs += copy_sz;
++                      offs += copy_sz;
++                      sz -= copy_sz;
++              }
++
++              if (offs < phdr->p_memsz && sz) {
++                      if (phdr->p_memsz - offs < sz)
++                              sz = phdr->p_memsz - offs;
++
++                      sz = ALIGN(sz, 4);
++                      memset(p + page_offs, 0, sz);
++                      page_offs += sz;
++                      offs += sz;
++              }
++              kunmap(page);
++      }
++      dma_sync_single_for_device(e24->dev, pa, phdr->p_memsz, DMA_TO_DEVICE);
++      return 0;
++}
++
++static int e24_load_segment_to_iomem(struct e24_device *e24, Elf32_Phdr *phdr)
++{
++      phys_addr_t pa = e24_translate_to_cpu(e24, phdr);
++      void __iomem *p = ioremap(pa, phdr->p_memsz);
++
++      if (!p) {
++              dev_err(e24->dev, "couldn't ioremap %pap x 0x%08x\n",
++                      &pa, (u32)phdr->p_memsz);
++              return -EINVAL;
++      }
++      if (e24->hw_ops->memcpy_tohw)
++              e24->hw_ops->memcpy_tohw(p, (void *)e24->firmware->data +
++                                       phdr->p_offset, phdr->p_filesz);
++      else
++              memcpy_toio(p, (void *)e24->firmware->data + phdr->p_offset,
++                          ALIGN(phdr->p_filesz, 4));
++
++      if (e24->hw_ops->memset_hw)
++              e24->hw_ops->memset_hw(p + phdr->p_filesz, 0,
++                                     phdr->p_memsz - phdr->p_filesz);
++      else
++              memset_io(p + ALIGN(phdr->p_filesz, 4), 0,
++                      ALIGN(phdr->p_memsz - ALIGN(phdr->p_filesz, 4), 4));
++
++      iounmap(p);
++      return 0;
++}
++
++static int e24_load_firmware(struct e24_device *e24_dev)
++{
++      Elf32_Ehdr *ehdr = (Elf32_Ehdr *)e24_dev->firmware->data;
++      u32 *dai = (u32 *)e24_dev->firmware->data;
++      int i;
++
++      pr_debug("elf size:%ld,%x,%x\n", e24_dev->firmware->size, dai[0], dai[1]);
++      if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
++              dev_err(e24_dev->dev, "bad firmware ELF magic\n");
++              return -EINVAL;
++      }
++
++      if (ehdr->e_type != ET_EXEC) {
++              dev_err(e24_dev->dev, "bad firmware ELF type\n");
++              return -EINVAL;
++      }
++
++      if (ehdr->e_machine != EM_RISCV) {
++              dev_err(e24_dev->dev, "bad firmware ELF machine\n");
++              return -EINVAL;
++      }
++
++      if (ehdr->e_phoff >= e24_dev->firmware->size ||
++          ehdr->e_phoff +
++          ehdr->e_phentsize * ehdr->e_phnum > e24_dev->firmware->size) {
++              dev_err(e24_dev->dev, "bad firmware ELF PHDR information\n");
++              return -EINVAL;
++      }
++
++      for (i = ehdr->e_phnum; i >= 0 ; i--) {
++              Elf32_Phdr *phdr = (void *)e24_dev->firmware->data +
++                      ehdr->e_phoff + i * ehdr->e_phentsize;
++              phys_addr_t pa;
++              int rc;
++
++              /* Only load non-empty loadable segments, R/W/X */
++              if (!(phdr->p_type == PT_LOAD &&
++                    (phdr->p_flags & (PF_X | PF_R | PF_W)) &&
++                    phdr->p_memsz > 0))
++                      continue;
++
++              if (phdr->p_offset >= e24_dev->firmware->size ||
++                  phdr->p_offset + phdr->p_filesz > e24_dev->firmware->size) {
++                      dev_err(e24_dev->dev, "bad firmware ELF program header entry %d\n", i);
++                      return -EINVAL;
++              }
++
++              pa = e24_translate_to_cpu(e24_dev, phdr);
++              if (pa == (phys_addr_t)OF_BAD_ADDR) {
++                      dev_err(e24_dev->dev,
++                              "device address 0x%08x could not be mapped to host physical address",
++                              (u32)phdr->p_paddr);
++                      return -EINVAL;
++              }
++              dev_dbg(e24_dev->dev, "loading segment %d (device 0x%08x) to physical %pap\n",
++                      i, (u32)phdr->p_paddr, &pa);
++
++              if (pfn_valid(__phys_to_pfn(pa)))
++                      rc = e24_load_segment_to_sysmem(e24_dev, phdr);
++              else
++                      rc = e24_load_segment_to_iomem(e24_dev, phdr);
++
++              if (rc < 0)
++                      return rc;
++      }
++      return 0;
++}
++
++static int e24_boot_firmware(struct device *dev)
++{
++      int ret;
++      struct e24_device *e24_dev = dev_get_drvdata(dev);
++
++      if (e24_dev->firmware_name) {
++              ret = request_firmware(&e24_dev->firmware, e24_dev->firmware_name, e24_dev->dev);
++
++              if (ret < 0)
++                      return ret;
++
++              ret = e24_load_firmware(e24_dev);
++              if (ret < 0) {
++                      release_firmware(e24_dev->firmware);
++                      return ret;
++              }
++
++      }
++
++      release_firmware(e24_dev->firmware);
++      ret = e24_enable_e24(e24_dev);
++      if (ret < 0)
++              return ret;
++
++      e24_reset_e24(e24_dev);
++      e24_release_e24(e24_dev);
++      e24_synchronize(e24_dev);
++
++      return ret;
++}
++
++int e24_runtime_suspend(struct device *dev)
++{
++      struct e24_device *e24_dev = dev_get_drvdata(dev);
++
++      e24_halt_e24(e24_dev);
++      e24_disable_e24(e24_dev);
++
++      return 0;
++}
++
++long e24_init_v0(struct platform_device *pdev)
++{
++      long ret = -EINVAL;
++      int nodeid, i;
++      struct e24_hw_arg *hw_arg;
++      struct e24_device *e24_dev;
++      char nodename[sizeof("eboot") + 2 * sizeof(int)];
++
++      e24_dev = devm_kzalloc(&pdev->dev, sizeof(*e24_dev), GFP_KERNEL);
++      if (e24_dev == NULL) {
++              ret = -ENOMEM;
++              return ret;
++      }
++
++      hw_arg = devm_kzalloc(&pdev->dev, sizeof(*hw_arg), GFP_KERNEL);
++      if (hw_arg == NULL)
++              return ret;
++
++      platform_set_drvdata(pdev, e24_dev);
++      e24_dev->dev = &pdev->dev;
++      e24_dev->hw_arg = hw_arg;
++      e24_dev->hw_ops = e24_get_hw_ops();
++      e24_dev->nodeid = -1;
++      hw_arg->e24 = e24_dev;
++
++      ret = e24_init_mem_pool(pdev, e24_dev);
++      if (ret < 0)
++              goto err;
++
++      ret = e24_init_address_map(e24_dev->dev, &e24_dev->address_map);
++      if (ret < 0)
++              goto err_free_pool;
++
++      e24_dev->n_queues = 1;
++      e24_dev->queue = devm_kmalloc(&pdev->dev,
++                                e24_dev->n_queues * sizeof(*e24_dev->queue),
++                                GFP_KERNEL);
++      if (e24_dev->queue == NULL)
++              goto err_free_map;
++
++      for (i = 0; i < e24_dev->n_queues; i++) {
++              mutex_init(&e24_dev->queue[i].lock);
++              e24_dev->queue[i].comm = e24_dev->comm + E24_CMD_STRIDE * i;
++      }
++
++      ret = of_property_read_u32(pdev->dev.of_node, "irq-mode",
++              &hw_arg->irq_mode);
++      e24_dev->irq_mode = hw_arg->irq_mode;
++      if (hw_arg->irq_mode == 0)
++              dev_info(&pdev->dev, "using polling mode on the device side\n");
++
++      e24_dev->mbox_data = e24_translate_to_dsp(&e24_dev->address_map, e24_dev->comm_phys);
++      ret = device_property_read_string(e24_dev->dev, "firmware-name",
++                                        &e24_dev->firmware_name);
++      if (ret == -EINVAL || ret == -ENODATA) {
++              dev_dbg(e24_dev->dev,
++                      "no firmware-name property, not loading firmware");
++      } else if (ret < 0) {
++              dev_err(e24_dev->dev, "invalid firmware name (%ld)", ret);
++              goto err_free_map;
++      }
++
++      e24_init(e24_dev);
++      pm_runtime_set_active(e24_dev->dev);
++      pm_runtime_enable(e24_dev->dev);
++      if (!pm_runtime_enabled(e24_dev->dev)) {
++              ret = e24_boot_firmware(e24_dev->dev);
++              if (ret)
++                      goto err_pm_disable;
++      }
++      nodeid = ida_simple_get(&e24_nodeid, 0, 0, GFP_KERNEL);
++      if (nodeid < 0) {
++              ret = nodeid;
++              goto err_pm_disable;
++      }
++
++      e24_dev->nodeid = nodeid;
++      sprintf(nodename, "eboot%u", nodeid);
++
++      e24_dev->miscdev = (struct miscdevice){
++              .minor = MISC_DYNAMIC_MINOR,
++              .name = devm_kstrdup(&pdev->dev, nodename, GFP_KERNEL),
++              .nodename = devm_kstrdup(&pdev->dev, nodename, GFP_KERNEL),
++              .fops = &e24_fops,
++      };
++
++      ret = misc_register(&e24_dev->miscdev);
++      if (ret < 0)
++              goto err_free_id;
++
++      return PTR_ERR(e24_dev);
++err_free_id:
++      ida_simple_remove(&e24_nodeid, nodeid);
++
++err_pm_disable:
++      pm_runtime_disable(e24_dev->dev);
++err_free_map:
++      kfree(e24_dev->address_map.entry);
++err_free_pool:
++      e24_free_pool(e24_dev->pool);
++err:
++      dev_err(&pdev->dev, "%s: ret = %ld\n", __func__, ret);
++      return ret;
++}
++
++static const struct of_device_id e24_of_match[] = {
++      {
++              .compatible = "starfive,e24",
++              .data = e24_init_v0,
++      },
++      {
++      },
++};
++MODULE_DEVICE_TABLE(of, e24_of_match);
++
++int e24_deinit(struct platform_device *pdev)
++{
++      struct e24_device *e24_dev = platform_get_drvdata(pdev);
++
++      pm_runtime_disable(&pdev->dev);
++      if (!pm_runtime_status_suspended(e24_dev->dev))
++              e24_runtime_suspend(e24_dev->dev);
++
++      misc_deregister(&e24_dev->miscdev);
++      e24_free_pool(e24_dev->pool);
++      kfree(e24_dev->address_map.entry);
++      ida_simple_remove(&e24_nodeid, e24_dev->nodeid);
++
++      if (e24_dev->rx_channel)
++              mbox_free_channel(e24_dev->rx_channel);
++      if (e24_dev->tx_channel)
++              mbox_free_channel(e24_dev->tx_channel);
++      return 0;
++}
++
++static int e24_probe(struct platform_device *pdev)
++{
++      long ret = -EINVAL;
++      const e24_init_function *init;
++
++      init = of_device_get_match_data(&pdev->dev);
++      ret = init(pdev);
++
++      return IS_ERR_VALUE(ret) ? ret : 0;
++}
++
++static void e24_remove(struct platform_device *pdev)
++{
++      e24_deinit(pdev);
++}
++
++static const struct dev_pm_ops e24_runtime_pm_ops = {
++      SET_RUNTIME_PM_OPS(e24_runtime_suspend,
++                 e24_boot_firmware, NULL)
++};
++
++static struct platform_driver e24_driver = {
++      .probe = e24_probe,
++      .remove = e24_remove,
++      .driver = {
++              .name = "e24_boot",
++              .of_match_table = of_match_ptr(e24_of_match),
++              .pm = &e24_runtime_pm_ops,
++      },
++};
++
++module_platform_driver(e24_driver);
++
++MODULE_DESCRIPTION("StarFive e24 driver");
++MODULE_AUTHOR("Shanlong Li <shanlong.li@starfivetech.com>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/e24/starfive_e24.h
+@@ -0,0 +1,159 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __STARFIVE_E24_H__
++#define __STARFIVE_E24_H__
++
++#include <linux/types.h>
++#include <linux/completion.h>
++#include <linux/miscdevice.h>
++#include <linux/mutex.h>
++#include <linux/irqreturn.h>
++#include <linux/platform_device.h>
++
++#define E24_IOCTL_MAGIC 'e'
++#define E24_IOCTL_SEND                        _IO(E24_IOCTL_MAGIC, 1)
++#define E24_IOCTL_RECV                        _IO(E24_IOCTL_MAGIC, 2)
++#define E24_IOCTL_GET_CHANNEL         _IO(E24_IOCTL_MAGIC, 3)
++#define E24_IOCTL_FREE_CHANNEL                _IO(E24_IOCTL_MAGIC, 4)
++#define E24_IOCTL_ALLOC                       _IO(E24_IOCTL_MAGIC, 5)
++#define E24_IOCTL_FREE                        _IO(E24_IOCTL_MAGIC, 6)
++
++#define E24_DSP_CMD_INLINE_DATA_SIZE  16
++#define E24_NO_TRANSLATION            ((u32)~0ul)
++#define E24_CMD_STRIDE                        256
++
++#define E24_MEM_MAP
++enum e24_irq_mode {
++      MAIL_IRQ_NONE,
++      MAIL_IRQ_LEVEL,
++      MAIL_IRQ_MAX
++};
++
++enum {
++      E24_FLAG_READ = 0x1,
++      E24_FLAG_WRITE = 0x2,
++      E24_FLAG_READ_WRITE = 0x3,
++};
++
++enum {
++      E24_QUEUE_FLAG_VALID = 0x4,
++      E24_QUEUE_FLAG_PRIO = 0xff00,
++      E24_QUEUE_FLAG_PRIO_SHIFT = 8,
++
++      E24_QUEUE_VALID_FLAGS =
++              E24_QUEUE_FLAG_VALID |
++              E24_QUEUE_FLAG_PRIO,
++};
++
++enum {
++      E24_CMD_FLAG_REQUEST_VALID = 0x00000001,
++      E24_CMD_FLAG_RESPONSE_VALID = 0x00000002,
++      E24_CMD_FLAG_REQUEST_NSID = 0x00000004,
++      E24_CMD_FLAG_RESPONSE_DELIVERY_FAIL = 0x00000008,
++};
++
++struct e24_address_map_entry {
++      phys_addr_t src_addr;
++      u32 dst_addr;
++      u32 size;
++};
++
++struct e24_address_map {
++      unsigned int n;
++      struct e24_address_map_entry *entry;
++};
++
++struct e24_alien_mapping {
++      unsigned long vaddr;
++      unsigned long size;
++      phys_addr_t paddr;
++      void *allocation;
++      enum {
++              ALIEN_GUP,
++              ALIEN_PFN_MAP,
++              ALIEN_COPY,
++      } type;
++};
++
++struct e24_mapping {
++      enum {
++              E24_MAPPING_NONE,
++              E24_MAPPING_NATIVE,
++              E24_MAPPING_ALIEN,
++              E24_MAPPING_KERNEL = 0x4,
++      } type;
++      union {
++              struct {
++                      struct e24_allocation *m_allocation;
++                      unsigned long vaddr;
++              } native;
++              struct e24_alien_mapping alien_mapping;
++      };
++};
++
++struct e24_ioctl_alloc {
++      u32 size;
++      u32 align;
++      u64 addr;
++};
++
++struct e24_comm {
++      struct mutex lock;
++      void __iomem *comm;
++      struct completion completion;
++      u32 priority;
++};
++
++struct e24_device {
++      struct device *dev;
++      const char *firmware_name;
++      const struct firmware *firmware;
++      struct miscdevice miscdev;
++      const struct e24_hw_ops *hw_ops;
++      void *hw_arg;
++      int irq_mode;
++
++      u32 n_queues;
++      struct completion completion;
++      struct e24_address_map address_map;
++      struct e24_comm *queue;
++      void __iomem *comm;
++      phys_addr_t comm_phys;
++      phys_addr_t shared_mem;
++      phys_addr_t shared_size;
++
++      u32 mbox_data;
++      int nodeid;
++      spinlock_t busy_list_lock;
++
++      struct mbox_chan        *tx_channel;
++      struct mbox_chan        *rx_channel;
++      void                    *rx_buffer;
++      void                    *message;
++      struct e24_allocation_pool *pool;
++      struct e24_allocation *busy_list;
++};
++
++struct e24_hw_arg {
++      struct e24_device *e24;
++      phys_addr_t regs_phys;
++      struct clk *clk_rtc;
++      struct clk *clk_core;
++      struct clk *clk_dbg;
++      struct reset_control *rst_core;
++      struct regmap *reg_syscon;
++      enum e24_irq_mode irq_mode;
++};
++
++static inline int e24_compare_address(phys_addr_t addr,
++                                    const struct e24_address_map_entry *entry)
++{
++      if (addr < entry->src_addr)
++              return -1;
++      if (addr - entry->src_addr < entry->size)
++              return 0;
++      return 1;
++}
++
++irqreturn_t e24_irq_handler(int irq, struct e24_device *e24_hw);
++
++#endif
+--- /dev/null
++++ b/drivers/e24/starfive_e24_hw.c
+@@ -0,0 +1,134 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/idr.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/module.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
++#include "starfive_e24.h"
++#include "starfive_e24_hw.h"
++
++#define RET_E24_VECTOR_ADDR   0x6CE00000
++
++static void halt(void *hw_arg)
++{
++      struct e24_hw_arg *mail_arg = hw_arg;
++
++      reset_control_assert(mail_arg->rst_core);
++      pr_debug("e24 halt.\n");
++}
++
++static void release(void *hw_arg)
++{
++      struct e24_hw_arg *mail_arg = hw_arg;
++
++      reset_control_deassert(mail_arg->rst_core);
++      pr_debug("e24 begin run.\n");
++}
++
++static void reset(void *hw_arg)
++{
++      struct e24_hw_arg *mail_arg = hw_arg;
++
++      regmap_update_bits(mail_arg->reg_syscon, 0x24, 0xFFFFFFFF, RET_E24_VECTOR_ADDR);
++      pr_debug("e24 reset vector.\n");
++}
++
++static void disable(void *hw_arg)
++{
++      struct e24_hw_arg *mail_arg = hw_arg;
++
++      clk_disable_unprepare(mail_arg->clk_core);
++      clk_disable_unprepare(mail_arg->clk_dbg);
++      clk_disable_unprepare(mail_arg->clk_rtc);
++
++      pr_debug("e24 disable ...\n");
++
++}
++
++static int enable(void *hw_arg)
++{
++      struct e24_hw_arg *mail_arg = hw_arg;
++      int ret = 0;
++
++      ret = clk_prepare_enable(mail_arg->clk_core);
++      if (ret)
++              return -EAGAIN;
++
++      ret = clk_prepare_enable(mail_arg->clk_dbg);
++      if (ret) {
++              clk_disable_unprepare(mail_arg->clk_core);
++              return -EAGAIN;
++      }
++
++      ret = clk_prepare_enable(mail_arg->clk_rtc);
++      if (ret) {
++              clk_disable_unprepare(mail_arg->clk_core);
++              clk_disable_unprepare(mail_arg->clk_dbg);
++              return -EAGAIN;
++      }
++
++      pr_debug("e24_enable clk ...\n");
++      return 0;
++}
++
++
++static int init(void *hw_arg)
++{
++      struct e24_hw_arg *mail_arg = hw_arg;
++
++      mail_arg->reg_syscon = syscon_regmap_lookup_by_phandle(
++                                      mail_arg->e24->dev->of_node,
++                                      "starfive,stg-syscon");
++      if (IS_ERR(mail_arg->reg_syscon)) {
++              dev_err(mail_arg->e24->dev, "No starfive,stg-syscon\n");
++              return PTR_ERR(mail_arg->reg_syscon);
++      }
++
++      mail_arg->clk_core = devm_clk_get_optional(mail_arg->e24->dev, "clk_core");
++      if (IS_ERR(mail_arg->clk_core)) {
++              dev_err(mail_arg->e24->dev, "failed to get e24 clk core\n");
++              return -ENOMEM;
++      }
++
++      mail_arg->clk_dbg = devm_clk_get_optional(mail_arg->e24->dev, "clk_dbg");
++      if (IS_ERR(mail_arg->clk_dbg)) {
++              dev_err(mail_arg->e24->dev, "failed to get e24 clk dbg\n");
++              return -ENOMEM;
++      }
++
++      mail_arg->clk_rtc = devm_clk_get_optional(mail_arg->e24->dev, "clk_rtc");
++      if (IS_ERR(mail_arg->clk_rtc)) {
++              dev_err(mail_arg->e24->dev, "failed to get e24 clk rtc\n");
++              return -ENOMEM;
++      }
++
++      mail_arg->rst_core = devm_reset_control_get_exclusive(mail_arg->e24->dev, "e24_core");
++      if (IS_ERR(mail_arg->rst_core)) {
++              dev_err(mail_arg->e24->dev, "failed to get e24 reset\n");
++              return -ENOMEM;
++      }
++
++      enable(hw_arg);
++
++      return 0;
++}
++
++static struct e24_hw_ops e24_hw_ops = {
++      .init = init,
++      .enable = enable,
++      .reset = reset,
++      .halt = halt,
++      .release = release,
++      .disable = disable,
++};
++
++struct e24_hw_ops *e24_get_hw_ops(void)
++{
++      return &e24_hw_ops;
++}
+--- /dev/null
++++ b/drivers/e24/starfive_e24_hw.h
+@@ -0,0 +1,94 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __STARFIVE_E24_HW_H__
++#define __STARFIVE_E24_HW_H__
++/*
++ * Hardware-specific operation entry points.
++ */
++struct e24_hw_ops {
++      /*
++       * Gets the clock for E24.
++       */
++      int (*init)(void *hw_arg);
++      /*
++       * Enable power/clock, but keep the core stalled.
++       */
++      int (*enable)(void *hw_arg);
++      /*
++       * Diable power/clock.
++       */
++      void (*disable)(void *hw_arg);
++      /*
++       * Reset the core.
++       */
++      void (*reset)(void *hw_arg);
++      /*
++       * Unstall the core.
++       */
++      void (*release)(void *hw_arg);
++      /*
++       * Stall the core.
++       */
++      void (*halt)(void *hw_arg);
++
++      /* Get HW-specific data to pass to the DSP on synchronization
++       *
++       *  param hw_arg: opaque parameter passed to DSP at initialization
++       *  param sz: return size of sync data here
++       *  return a buffer allocated with kmalloc that the caller will free
++       */
++      void *(*get_hw_sync_data)(void *hw_arg, size_t *sz);
++
++      /*
++       * Send IRQ to the core.
++       */
++      void (*send_irq)(void *hw_arg);
++
++      /*
++       * Check whether region of physical memory may be handled by
++       * dma_sync_* operations
++       *
++       * \param hw_arg: opaque parameter passed to DSP at initialization
++       *                time
++       */
++      bool (*cacheable)(void *hw_arg, unsigned long pfn, unsigned long n_pages);
++      /*
++       * Synchronize region of memory for DSP access.
++       *
++       * \param hw_arg: opaque parameter passed to DSP at initialization
++       *                time
++       */
++      void (*dma_sync_for_device)(void *hw_arg,
++                                  void *vaddr, phys_addr_t paddr,
++                                  unsigned long sz, unsigned int flags);
++      /*
++       * Synchronize region of memory for host access.
++       *
++       * \param hw_arg: opaque parameter passed to DSP at initialization
++       *                time
++       */
++      void (*dma_sync_for_cpu)(void *hw_arg,
++                               void *vaddr, phys_addr_t paddr,
++                               unsigned long sz, unsigned int flags);
++
++      /*
++       * memcpy data/code to device-specific memory.
++       */
++      void (*memcpy_tohw)(void __iomem *dst, const void *src, size_t sz);
++      /*
++       * memset device-specific memory.
++       */
++      void (*memset_hw)(void __iomem *dst, int c, size_t sz);
++
++      /*
++       * Check DSP status.
++       *
++       * \param hw_arg: opaque parameter passed to DSP at initialization
++       *                time
++       * \return whether the core has crashed and needs to be restarted
++       */
++      bool (*panic_check)(void *hw_arg);
++};
++
++long e24_init_hw(struct platform_device *pdev, void *hw_arg);
++struct e24_hw_ops *e24_get_hw_ops(void);
++#endif
diff --git a/target/linux/starfive/patches-6.12/0019-net-stmmac-Extend-waiting-time-of-dma-reset.patch b/target/linux/starfive/patches-6.12/0019-net-stmmac-Extend-waiting-time-of-dma-reset.patch
new file mode 100644 (file)
index 0000000..3814cfb
--- /dev/null
@@ -0,0 +1,23 @@
+From 0eaf04ef4963db173428da176f52320754b0574c Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Thu, 10 Oct 2024 11:05:20 +0800
+Subject: [PATCH 19/55] net: stmmac: Extend waiting time of dma reset
+
+Fix dma reset failure happening when disabling network.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+@@ -23,7 +23,7 @@ int dwmac4_dma_reset(void __iomem *ioadd
+       return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
+                                !(value & DMA_BUS_MODE_SFT_RESET),
+-                               10000, 1000000);
++                               10000, 3000000);
+ }
+ void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
diff --git a/target/linux/starfive/patches-6.12/0020-spi-pl022-starfive-Add-platform-bus-register-to-adap.patch b/target/linux/starfive/patches-6.12/0020-spi-pl022-starfive-Add-platform-bus-register-to-adap.patch
new file mode 100644 (file)
index 0000000..6c0f51e
--- /dev/null
@@ -0,0 +1,235 @@
+From 714c99f993097e5c16822e73ba0a7945b86a20ea Mon Sep 17 00:00:00 2001
+From: "xingyu.wu" <xingyu.wu@starfivetech.com>
+Date: Tue, 28 Jun 2022 22:48:15 +0800
+Subject: [PATCH 20/55] spi-pl022:starfive:Add platform bus register to adapt
+ overlay
+
+Add platform bus register to adapt dtbo overlay.
+
+Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 143 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 137 insertions(+), 6 deletions(-)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -34,6 +34,7 @@
+ #include <linux/of.h>
+ #include <linux/pinctrl/consumer.h>
+ #include <linux/reset.h>
++#include <linux/platform_device.h>
+ /*
+  * This macro is used to define some register default values.
+@@ -1841,7 +1842,10 @@ pl022_platform_data_dt_get(struct device
+               return NULL;
+       }
+-      pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
++      if (strncmp(dev->bus->name, "platform", strlen("platform")))
++              pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
++      else
++              pd = kzalloc(sizeof(struct pl022_ssp_controller), GFP_KERNEL);
+       if (!pd)
+               return NULL;
+@@ -1861,6 +1865,14 @@ static int pl022_probe(struct amba_devic
+       struct spi_controller *host;
+       struct pl022 *pl022 = NULL;     /*Data for this driver */
+       int status = 0;
++      int platform_flag = 0;
++
++      if (strncmp(dev->bus->name, "platform", strlen("platform")))
++              platform_flag = 0;
++      else
++              platform_flag = 1;
++      dev_dbg(&adev->dev, "bus name:%s platform flag:%d",
++                      dev->bus->name, platform_flag);
+       dev_info(&adev->dev,
+                "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
+@@ -1916,7 +1928,11 @@ static int pl022_probe(struct amba_devic
+               goto err_no_ioregion;
+       pl022->phybase = adev->res.start;
+-      pl022->virtbase = devm_ioremap(dev, adev->res.start,
++      if (platform_flag)
++              pl022->virtbase = ioremap(adev->res.start,
++                                     resource_size(&adev->res));
++      else
++              pl022->virtbase = devm_ioremap(dev, adev->res.start,
+                                      resource_size(&adev->res));
+       if (pl022->virtbase == NULL) {
+               status = -ENOMEM;
+@@ -1925,14 +1941,28 @@ static int pl022_probe(struct amba_devic
+       dev_info(&adev->dev, "mapped registers from %pa to %p\n",
+               &adev->res.start, pl022->virtbase);
+-      pl022->clk = devm_clk_get_enabled(&adev->dev, NULL);
++      if (platform_flag)
++              pl022->clk = clk_get(&adev->dev, NULL);
++      else
++              pl022->clk = devm_clk_get_enabled(&adev->dev, NULL);
+       if (IS_ERR(pl022->clk)) {
+               status = PTR_ERR(pl022->clk);
+               dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
+               goto err_no_clk;
+       }
+-      pl022->rst = devm_reset_control_get(&adev->dev, NULL);
++      if (platform_flag) {
++              status = clk_prepare_enable(pl022->clk);
++              if (status) {
++                      dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
++                      goto err_no_clk_en;
++              }
++      }
++
++      if (platform_flag)
++              pl022->rst = reset_control_get_exclusive(&adev->dev, NULL);
++      else
++              pl022->rst = devm_reset_control_get(&adev->dev, NULL);
+       if (IS_ERR(pl022->rst)) {
+               status = PTR_ERR(pl022->rst);
+               dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n");
+@@ -1950,7 +1980,11 @@ static int pl022_probe(struct amba_devic
+              SSP_CR1(pl022->virtbase));
+       load_ssp_default_config(pl022);
+-      status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
++      if (platform_flag)
++              status = request_irq(adev->irq[0], pl022_interrupt_handler,
++                                0, "pl022", pl022);
++      else
++              status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
+                                 0, "pl022", pl022);
+       if (status < 0) {
+               dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
+@@ -1975,7 +2009,10 @@ static int pl022_probe(struct amba_devic
+       /* Register with the SPI framework */
+       amba_set_drvdata(adev, pl022);
+-      status = devm_spi_register_controller(&adev->dev, host);
++      if (platform_flag)
++              status = spi_register_controller(host);
++      else
++              status = devm_spi_register_controller(&adev->dev, host);
+       if (status != 0) {
+               dev_err_probe(&adev->dev, status,
+                             "problem registering spi host\n");
+@@ -2000,13 +2037,24 @@ static int pl022_probe(struct amba_devic
+       if (platform_info->enable_dma)
+               pl022_dma_remove(pl022);
+  err_no_irq:
++      if (platform_flag)
++              free_irq(adev->irq[0], pl022);
++      reset_control_assert(pl022->rst);
+  err_no_rst_de:
++      if (platform_flag)
++              reset_control_put(pl022->rst);
+  err_no_rst:
++      if (platform_flag)
++              clk_put(pl022->clk);
+  err_no_clk:
++      if (platform_flag)
++              iounmap(pl022->virtbase);
+  err_no_ioremap:
+       amba_release_regions(adev);
+  err_no_ioregion:
+       spi_controller_put(host);
++      if (platform_flag)
++              kfree(platform_info);
+       return status;
+ }
+@@ -2205,6 +2253,89 @@ static void __exit pl022_exit(void)
+ }
+ module_exit(pl022_exit);
++/*
++ * Register PL022 in platform bus to accommodate overlay use.
++ * Because overlay only trigger response from the platform bus
++ * not amba bus.
++ */
++static int starfive_of_pl022_probe(struct platform_device *pdev)
++{
++      int ret;
++      const struct amba_id id = {
++              .id = 0x00041022,
++              .mask = 0x000fffff,
++              .data = &vendor_arm
++      };
++      struct amba_device *pcdev;
++      struct device *dev = &pdev->dev;
++
++      pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
++      if (!pcdev)
++              return -ENOMEM;
++
++      pcdev->dev = pdev->dev;
++      pcdev->periphid = id.id;
++      pcdev->res = *(pdev->resource);
++
++      pcdev->irq[0] = platform_get_irq(pdev, 0);
++      if (pcdev->irq[0] < 0) {
++              dev_err(dev, "failed to get irq\n");
++              ret = -EINVAL;
++      }
++
++      ret = pl022_probe(pcdev, &id);
++
++      return ret;
++}
++
++static void starfive_of_pl022_remove(struct platform_device *pdev)
++{
++      u32 size;
++      int irq;
++      struct pl022 *pl022 = dev_get_drvdata(&pdev->dev);
++
++      if (!pl022)
++              return;
++
++      pm_runtime_get_noresume(&pdev->dev);
++
++      load_ssp_default_config(pl022);
++      if (pl022->host_info->enable_dma)
++              pl022_dma_remove(pl022);
++
++      irq = platform_get_irq(pdev, 0);
++      free_irq(irq, pl022);
++      reset_control_assert(pl022->rst);
++      reset_control_put(pl022->rst);
++      clk_disable_unprepare(pl022->clk);
++      clk_put(pl022->clk);
++      iounmap(pl022->virtbase);
++      kfree(pl022->host_info);
++
++      size = resource_size(pdev->resource);
++      release_mem_region(pdev->resource->start, size);
++}
++
++static const struct of_device_id starfive_of_pl022_match[] = {
++      { .compatible = "starfive,jh7110-spi-pl022" },
++      { },
++};
++MODULE_DEVICE_TABLE(of, starfive_of_pl022_match);
++
++static struct platform_driver starfive_of_pl022_driver = {
++      .driver = {
++              .name = "starfive-spi-pl022",
++              .of_match_table = starfive_of_pl022_match,
++              .pm     = &pl022_dev_pm_ops,
++      },
++      .probe = starfive_of_pl022_probe,
++      .remove = starfive_of_pl022_remove,
++};
++
++module_platform_driver(starfive_of_pl022_driver);
++/* platform register end */
++
++MODULE_AUTHOR("xingyu.wu <xingyu.wu@starfivetech.com>");
+ MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+ MODULE_DESCRIPTION("PL022 SSP Controller Driver");
+ MODULE_LICENSE("GPL");
diff --git a/target/linux/starfive/patches-6.12/0021-spi-pl022-starfive-Avoid-power-device-error-when-CON.patch b/target/linux/starfive/patches-6.12/0021-spi-pl022-starfive-Avoid-power-device-error-when-CON.patch
new file mode 100644 (file)
index 0000000..a2ec871
--- /dev/null
@@ -0,0 +1,92 @@
+From 8063cc5e813c3a5f86a4f17e3681cda3dbebcb1a Mon Sep 17 00:00:00 2001
+From: "xingyu.wu" <xingyu.wu@starfivetech.com>
+Date: Tue, 19 Jul 2022 14:49:20 +0800
+Subject: [PATCH 21/55] spi:pl022-starfive:Avoid power device error when
+ CONFIG_PM enable
+
+It would be error when CONFIG_PM enable and use overlay by of-platform to register.
+
+Add some power manager operation in platform probe function.
+
+Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
+Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 36 ++++++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -35,6 +35,8 @@
+ #include <linux/pinctrl/consumer.h>
+ #include <linux/reset.h>
+ #include <linux/platform_device.h>
++#include <linux/clk/clk-conf.h>
++#include <linux/pm_domain.h>
+ /*
+  * This macro is used to define some register default values.
+@@ -2019,7 +2021,8 @@ static int pl022_probe(struct amba_devic
+               goto err_spi_register;
+       }
+       dev_dbg(dev, "probe succeeded\n");
+-
++      if (!platform_flag)
++              platform_info->autosuspend_delay = 100;
+       /* let runtime pm put suspend */
+       if (platform_info->autosuspend_delay > 0) {
+               dev_info(&adev->dev,
+@@ -2029,7 +2032,10 @@ static int pl022_probe(struct amba_devic
+                       platform_info->autosuspend_delay);
+               pm_runtime_use_autosuspend(dev);
+       }
+-      pm_runtime_put(dev);
++      if (platform_flag)
++              clk_disable_unprepare(pl022->clk);
++      else
++              pm_runtime_put(dev);
+       return 0;
+@@ -2283,8 +2289,33 @@ static int starfive_of_pl022_probe(struc
+               ret = -EINVAL;
+       }
++      ret = of_clk_set_defaults(dev->of_node, false);
++      if (ret < 0)
++              goto err_probe;
++
++      ret = dev_pm_domain_attach(dev, true);
++      if (ret)
++              goto err_probe;
++
+       ret = pl022_probe(pcdev, &id);
++      struct pl022 *pl022 = amba_get_drvdata(pcdev);
++
++      pl022->host->dev.parent = &pdev->dev;
++      platform_set_drvdata(pdev, pl022);
++
++      pm_runtime_enable(&pdev->dev);
++      pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
++      pm_runtime_use_autosuspend(&pdev->dev);
++
++      if (ret) {
++              pm_runtime_disable(dev);
++              pm_runtime_set_suspended(dev);
++              pm_runtime_put_noidle(dev);
++              dev_pm_domain_detach(dev, true);
++      }
++
++err_probe:
+       return ret;
+ }
+@@ -2314,6 +2345,7 @@ static void starfive_of_pl022_remove(str
+       size = resource_size(pdev->resource);
+       release_mem_region(pdev->resource->start, size);
++      pm_runtime_disable(&pdev->dev);
+ }
+ static const struct of_device_id starfive_of_pl022_match[] = {
diff --git a/target/linux/starfive/patches-6.12/0022-spi-pl022-starfive-fix-the-problem-of-spi-overlay-re.patch b/target/linux/starfive/patches-6.12/0022-spi-pl022-starfive-fix-the-problem-of-spi-overlay-re.patch
new file mode 100644 (file)
index 0000000..15b84ad
--- /dev/null
@@ -0,0 +1,396 @@
+From 7a98fafdc544b85694db5d99cdf933a4640058f9 Mon Sep 17 00:00:00 2001
+From: "ziv.xu" <ziv.xu@starfive.com>
+Date: Wed, 23 Nov 2022 14:53:58 +0800
+Subject: [PATCH 22/55] spi-pl022-starfive:fix the problem of spi overlay
+ reload
+
+fix the problem of spi overlay reload
+
+Signed-off-by: ziv.xu <ziv.xu@starfive.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 266 ++++++++++++++++++++++++++--------------
+ 1 file changed, 177 insertions(+), 89 deletions(-)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -1859,6 +1859,163 @@ pl022_platform_data_dt_get(struct device
+       return pd;
+ }
++static int pl022_platform_probe(struct platform_device *pdev, const struct amba_id *id)
++{
++      struct device *dev = &pdev->dev;
++      struct spi_controller *host;
++      struct pl022_ssp_controller *platform_info;
++      struct amba_device *adev;
++      struct pl022 *pl022 = NULL;
++      struct resource *res;
++      int status = 0;
++      int irq;
++
++      dev_info(dev,
++              "ARM PL022 driver for StarFive SoC platform, device ID: 0x%08x\n",
++              id->id);
++
++      adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
++      adev->dev = pdev->dev;
++      platform_info = pl022_platform_data_dt_get(dev);
++      if (!platform_info) {
++              dev_err(dev, "probe: no platform data defined\n");
++              return -ENODEV;
++      }
++      /* Allocate host with space for data */
++      host = spi_alloc_host(dev, sizeof(struct pl022));
++      if (host == NULL) {
++              dev_err(dev, "probe - cannot alloc SPI host\n");
++              return -ENOMEM;
++      }
++
++      pl022 = spi_controller_get_devdata(host);
++      pl022->host = host;
++      pl022->host_info = platform_info;
++      pl022->adev = adev;
++      pl022->vendor = id->data;
++      pl022->host->dev.parent = &pdev->dev;
++      /*
++       * Bus Number Which has been Assigned to this SSP controller
++       * on this board
++       */
++      host->bus_num = platform_info->bus_id;
++      host->cleanup = pl022_cleanup;
++      host->setup = pl022_setup;
++      /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/
++      host->auto_runtime_pm = true;
++      host->transfer_one = pl022_transfer_one;
++      host->set_cs = pl022_cs_control;
++      host->handle_err = pl022_handle_err;
++      host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
++      host->rt = platform_info->rt;
++      host->dev.of_node = dev->of_node;
++      host->use_gpio_descriptors = true;
++
++      /*
++       * Supports mode 0-3, loopback, and active low CS. Transfers are
++       * always MS bit first on the original pl022.
++       */
++      host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
++      if (pl022->vendor->extended_cr)
++              host->mode_bits |= SPI_LSB_FIRST;
++
++      dev_dbg(dev, "BUSNO: %d\n", host->bus_num);
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pl022->phybase = res->start;
++      pl022->virtbase = devm_ioremap_resource(dev, res);
++      if (pl022->virtbase == NULL) {
++              status = -ENOMEM;
++              goto err_no_ioremap;
++      }
++      dev_info(dev, "mapped registers from %llx to %llx\n",
++               pdev->resource->start, pdev->resource->end);
++
++      pl022->clk = devm_clk_get_enabled(dev, NULL);
++      if (IS_ERR(pl022->clk)) {
++              status = PTR_ERR(pl022->clk);
++              dev_err(dev, "could not retrieve SSP/SPI bus clock\n");
++              goto err_no_clk;
++      }
++
++      pl022->rst = devm_reset_control_get_exclusive(dev, NULL);
++      if (IS_ERR(pl022->rst)) {
++              status = PTR_ERR(pl022->rst);
++              dev_err(dev, "could not retrieve SSP/SPI bus reset\n");
++              goto err_no_rst;
++      }
++
++      status = reset_control_deassert(pl022->rst);
++      if (status) {
++              dev_err(dev, "could not deassert SSP/SPI bus reset\n");
++              goto err_no_rst_de;
++      }
++
++      /* Disable SSP */
++      writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
++             SSP_CR1(pl022->virtbase));
++      load_ssp_default_config(pl022);
++
++      /* Obtain IRQ line. */
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0) {
++              status = -ENXIO;
++              goto err_no_irq;
++      }
++      status = devm_request_irq(dev, irq, pl022_interrupt_handler,
++                                0, "pl022", pl022);
++      if (status < 0) {
++              dev_err(dev, "probe - cannot get IRQ (%d)\n", status);
++              goto err_no_irq;
++      }
++
++      /* Get DMA channels, try autoconfiguration first */
++      status = pl022_dma_autoprobe(pl022);
++      if (status == -EPROBE_DEFER) {
++              dev_dbg(dev, "deferring probe to get DMA channel\n");
++              goto err_no_irq;
++      }
++
++      /* dma is not used unless configured in the device tree */
++      platform_info->enable_dma = 0;
++
++      /* If that failed, use channels from platform_info */
++      if (status == 0)
++              platform_info->enable_dma = 1;
++      else if (platform_info->enable_dma) {
++              status = pl022_dma_probe(pl022);
++              if (status != 0)
++                      platform_info->enable_dma = 0;
++      }
++
++      /* Register with the SPI framework */
++      dev_set_drvdata(dev, pl022);
++
++      status = devm_spi_register_controller(dev, host);
++      if (status != 0) {
++              dev_err(dev,
++                      "probe - problem registering spi host\n");
++              goto err_spi_register;
++      }
++      dev_dbg(dev, "probe succeeded\n");
++
++      clk_disable_unprepare(pl022->clk);
++
++      return 0;
++ err_spi_register:
++      if (platform_info->enable_dma)
++              pl022_dma_remove(pl022);
++ err_no_irq:
++      reset_control_assert(pl022->rst);
++ err_no_rst_de:
++ err_no_rst:
++ err_no_clk:
++ err_no_ioremap:
++      release_mem_region(pdev->resource->start, resource_size(pdev->resource));
++      spi_controller_put(host);
++      return status;
++}
++
+ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
+ {
+       struct device *dev = &adev->dev;
+@@ -1867,14 +2024,6 @@ static int pl022_probe(struct amba_devic
+       struct spi_controller *host;
+       struct pl022 *pl022 = NULL;     /*Data for this driver */
+       int status = 0;
+-      int platform_flag = 0;
+-
+-      if (strncmp(dev->bus->name, "platform", strlen("platform")))
+-              platform_flag = 0;
+-      else
+-              platform_flag = 1;
+-      dev_dbg(&adev->dev, "bus name:%s platform flag:%d",
+-                      dev->bus->name, platform_flag);
+       dev_info(&adev->dev,
+                "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
+@@ -1930,11 +2079,7 @@ static int pl022_probe(struct amba_devic
+               goto err_no_ioregion;
+       pl022->phybase = adev->res.start;
+-      if (platform_flag)
+-              pl022->virtbase = ioremap(adev->res.start,
+-                                     resource_size(&adev->res));
+-      else
+-              pl022->virtbase = devm_ioremap(dev, adev->res.start,
++      pl022->virtbase = devm_ioremap(dev, adev->res.start,
+                                      resource_size(&adev->res));
+       if (pl022->virtbase == NULL) {
+               status = -ENOMEM;
+@@ -1943,28 +2088,14 @@ static int pl022_probe(struct amba_devic
+       dev_info(&adev->dev, "mapped registers from %pa to %p\n",
+               &adev->res.start, pl022->virtbase);
+-      if (platform_flag)
+-              pl022->clk = clk_get(&adev->dev, NULL);
+-      else
+-              pl022->clk = devm_clk_get_enabled(&adev->dev, NULL);
++      pl022->clk = devm_clk_get_enabled(&adev->dev, NULL);
+       if (IS_ERR(pl022->clk)) {
+               status = PTR_ERR(pl022->clk);
+               dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
+               goto err_no_clk;
+       }
+-      if (platform_flag) {
+-              status = clk_prepare_enable(pl022->clk);
+-              if (status) {
+-                      dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
+-                      goto err_no_clk_en;
+-              }
+-      }
+-
+-      if (platform_flag)
+-              pl022->rst = reset_control_get_exclusive(&adev->dev, NULL);
+-      else
+-              pl022->rst = devm_reset_control_get(&adev->dev, NULL);
++      pl022->rst = devm_reset_control_get(&adev->dev, NULL);
+       if (IS_ERR(pl022->rst)) {
+               status = PTR_ERR(pl022->rst);
+               dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n");
+@@ -1982,11 +2113,7 @@ static int pl022_probe(struct amba_devic
+              SSP_CR1(pl022->virtbase));
+       load_ssp_default_config(pl022);
+-      if (platform_flag)
+-              status = request_irq(adev->irq[0], pl022_interrupt_handler,
+-                                0, "pl022", pl022);
+-      else
+-              status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
++      status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
+                                 0, "pl022", pl022);
+       if (status < 0) {
+               dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
+@@ -2011,18 +2138,16 @@ static int pl022_probe(struct amba_devic
+       /* Register with the SPI framework */
+       amba_set_drvdata(adev, pl022);
+-      if (platform_flag)
+-              status = spi_register_controller(host);
+-      else
+-              status = devm_spi_register_controller(&adev->dev, host);
++
++      status = devm_spi_register_controller(&adev->dev, host);
+       if (status != 0) {
+               dev_err_probe(&adev->dev, status,
+                             "problem registering spi host\n");
+               goto err_spi_register;
+       }
+       dev_dbg(dev, "probe succeeded\n");
+-      if (!platform_flag)
+-              platform_info->autosuspend_delay = 100;
++
++      platform_info->autosuspend_delay = 100;
+       /* let runtime pm put suspend */
+       if (platform_info->autosuspend_delay > 0) {
+               dev_info(&adev->dev,
+@@ -2032,10 +2157,8 @@ static int pl022_probe(struct amba_devic
+                       platform_info->autosuspend_delay);
+               pm_runtime_use_autosuspend(dev);
+       }
+-      if (platform_flag)
+-              clk_disable_unprepare(pl022->clk);
+-      else
+-              pm_runtime_put(dev);
++
++      pm_runtime_put(dev);
+       return 0;
+@@ -2043,24 +2166,15 @@ static int pl022_probe(struct amba_devic
+       if (platform_info->enable_dma)
+               pl022_dma_remove(pl022);
+  err_no_irq:
+-      if (platform_flag)
+-              free_irq(adev->irq[0], pl022);
+       reset_control_assert(pl022->rst);
+  err_no_rst_de:
+-      if (platform_flag)
+-              reset_control_put(pl022->rst);
+  err_no_rst:
+-      if (platform_flag)
+-              clk_put(pl022->clk);
+  err_no_clk:
+-      if (platform_flag)
+-              iounmap(pl022->virtbase);
+  err_no_ioremap:
+       amba_release_regions(adev);
+  err_no_ioregion:
+       spi_controller_put(host);
+-      if (platform_flag)
+-              kfree(platform_info);
++
+       return status;
+ }
+@@ -2272,23 +2386,8 @@ static int starfive_of_pl022_probe(struc
+               .mask = 0x000fffff,
+               .data = &vendor_arm
+       };
+-      struct amba_device *pcdev;
+       struct device *dev = &pdev->dev;
+-      pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
+-      if (!pcdev)
+-              return -ENOMEM;
+-
+-      pcdev->dev = pdev->dev;
+-      pcdev->periphid = id.id;
+-      pcdev->res = *(pdev->resource);
+-
+-      pcdev->irq[0] = platform_get_irq(pdev, 0);
+-      if (pcdev->irq[0] < 0) {
+-              dev_err(dev, "failed to get irq\n");
+-              ret = -EINVAL;
+-      }
+-
+       ret = of_clk_set_defaults(dev->of_node, false);
+       if (ret < 0)
+               goto err_probe;
+@@ -2297,16 +2396,11 @@ static int starfive_of_pl022_probe(struc
+       if (ret)
+               goto err_probe;
+-      ret = pl022_probe(pcdev, &id);
+-
+-      struct pl022 *pl022 = amba_get_drvdata(pcdev);
+-
+-      pl022->host->dev.parent = &pdev->dev;
+-      platform_set_drvdata(pdev, pl022);
++      ret = pl022_platform_probe(pdev, &id);
+-      pm_runtime_enable(&pdev->dev);
+-      pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
+-      pm_runtime_use_autosuspend(&pdev->dev);
++      pm_runtime_enable(dev);
++      pm_runtime_set_autosuspend_delay(dev, 100);
++      pm_runtime_use_autosuspend(dev);
+       if (ret) {
+               pm_runtime_disable(dev);
+@@ -2321,31 +2415,25 @@ err_probe:
+ static void starfive_of_pl022_remove(struct platform_device *pdev)
+ {
+-      u32 size;
+-      int irq;
+       struct pl022 *pl022 = dev_get_drvdata(&pdev->dev);
+       if (!pl022)
+               return;
++      pm_runtime_get_sync(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+       load_ssp_default_config(pl022);
+       if (pl022->host_info->enable_dma)
+               pl022_dma_remove(pl022);
+-      irq = platform_get_irq(pdev, 0);
+-      free_irq(irq, pl022);
+-      reset_control_assert(pl022->rst);
+-      reset_control_put(pl022->rst);
+       clk_disable_unprepare(pl022->clk);
+-      clk_put(pl022->clk);
+-      iounmap(pl022->virtbase);
+-      kfree(pl022->host_info);
+-      size = resource_size(pdev->resource);
+-      release_mem_region(pdev->resource->start, size);
++      pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
++      pm_runtime_set_suspended(&pdev->dev);
++      pm_runtime_put_noidle(&pdev->dev);
++      dev_pm_domain_detach(&pdev->dev, true);
+ }
+ static const struct of_device_id starfive_of_pl022_match[] = {
diff --git a/target/linux/starfive/patches-6.12/0023-spi-pl022-starfive-Enable-spi-to-be-compiled-into-mo.patch b/target/linux/starfive/patches-6.12/0023-spi-pl022-starfive-Enable-spi-to-be-compiled-into-mo.patch
new file mode 100644 (file)
index 0000000..661a2ea
--- /dev/null
@@ -0,0 +1,38 @@
+From 4ed44e07a80ef61932b1b5012fc7f8a5a7767e41 Mon Sep 17 00:00:00 2001
+From: "ziv.xu" <ziv.xu@starfive.com>
+Date: Wed, 18 Jan 2023 15:50:47 +0800
+Subject: [PATCH 23/55] spi-pl022-starfive:Enable spi to be compiled into
+ modules
+
+Enable spi to be compiled into modules
+
+Signed-off-by: ziv.xu <ziv.xu@starfive.com>
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -2365,7 +2365,11 @@ static int __init pl022_init(void)
+ {
+       return amba_driver_register(&pl022_driver);
+ }
++#if !IS_MODULE(CONFIG_SPI_PL022)
+ subsys_initcall(pl022_init);
++#else
++module_init(pl022_init);
++#endif
+ static void __exit pl022_exit(void)
+ {
+@@ -2452,7 +2456,9 @@ static struct platform_driver starfive_o
+       .remove = starfive_of_pl022_remove,
+ };
++#if !IS_MODULE(CONFIG_SPI_PL022)
+ module_platform_driver(starfive_of_pl022_driver);
++#endif
+ /* platform register end */
+ MODULE_AUTHOR("xingyu.wu <xingyu.wu@starfivetech.com>");
diff --git a/target/linux/starfive/patches-6.12/0024-spi-pl022-Prompt-warning-when-frequency-does-not-sup.patch b/target/linux/starfive/patches-6.12/0024-spi-pl022-Prompt-warning-when-frequency-does-not-sup.patch
new file mode 100644 (file)
index 0000000..b455e92
--- /dev/null
@@ -0,0 +1,26 @@
+From 1944de0e9d9c23f071ec1a75177ea7adbb87ba26 Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Thu, 6 Jun 2024 11:01:58 +0800
+Subject: [PATCH 24/55] spi: pl022: Prompt warning when frequency does not
+ support
+
+Prompt warning when the frequency does not support.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -1556,6 +1556,10 @@ static int calculate_effective_freq(stru
+       WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate \n",
+                       freq);
++      if (best_freq != freq)
++              dev_warn(&pl022->adev->dev,
++                       "Requested frequency: %d Hz is unsupported,select by default %d Hz\n",
++                       freq, best_freq);
+       clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
+       clk_freq->scr = (u8) (best_scr & 0xFF);
+       dev_dbg(&pl022->adev->dev,
diff --git a/target/linux/starfive/patches-6.12/0025-spi-pl022-Fix-spi-overlay-falut.patch b/target/linux/starfive/patches-6.12/0025-spi-pl022-Fix-spi-overlay-falut.patch
new file mode 100644 (file)
index 0000000..4d0f276
--- /dev/null
@@ -0,0 +1,33 @@
+From 1b818a33e3cd20250b72306946789d09d2c7b2c8 Mon Sep 17 00:00:00 2001
+From: Hal Feng <hal.feng@starfivetech.com>
+Date: Sun, 26 Jan 2025 16:56:05 +0800
+Subject: [PATCH 25/55] spi: pl022: Fix spi overlay falut
+
+set_cs() should not be set for spi controller when using overlay.
+clk_disable_unprepare() is not needed after using
+devm_clk_get_enabled() to get and enable clocks.
+
+Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
+---
+ drivers/spi/spi-pl022.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/spi/spi-pl022.c
++++ b/drivers/spi/spi-pl022.c
+@@ -1908,7 +1908,6 @@ static int pl022_platform_probe(struct p
+       /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/
+       host->auto_runtime_pm = true;
+       host->transfer_one = pl022_transfer_one;
+-      host->set_cs = pl022_cs_control;
+       host->handle_err = pl022_handle_err;
+       host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
+       host->rt = platform_info->rt;
+@@ -2435,8 +2434,6 @@ static void starfive_of_pl022_remove(str
+       if (pl022->host_info->enable_dma)
+               pl022_dma_remove(pl022);
+-      clk_disable_unprepare(pl022->clk);
+-
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
diff --git a/target/linux/starfive/patches-6.12/0026-RISC-V-Added-generic-pmu-events-mapfile.patch b/target/linux/starfive/patches-6.12/0026-RISC-V-Added-generic-pmu-events-mapfile.patch
new file mode 100644 (file)
index 0000000..ec6fab5
--- /dev/null
@@ -0,0 +1,42 @@
+From 7e21305a33876bb56294389d5ecd6f497800e2fb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?=
+ <joao.mario@tecnico.ulisboa.pt>
+Date: Tue, 16 Nov 2021 15:48:11 +0000
+Subject: [PATCH 26/55] RISC-V: Added generic pmu-events mapfile
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The pmu-events now supports custom events for RISC-V, plus the cycle,
+time and instret events were defined.
+
+Signed-off-by: João Mário Domingos <joao.mario@tecnico.ulisboa.pt>
+---
+ .../pmu-events/arch/riscv/riscv-generic.json  | 20 +++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+ create mode 100644 tools/perf/pmu-events/arch/riscv/riscv-generic.json
+
+--- /dev/null
++++ b/tools/perf/pmu-events/arch/riscv/riscv-generic.json
+@@ -0,0 +1,20 @@
++[
++  {
++    "PublicDescription": "CPU Cycles",
++    "EventCode": "0x00",
++    "EventName": "riscv_cycles",
++    "BriefDescription": "CPU cycles RISC-V generic counter"
++  },
++  {
++    "PublicDescription": "CPU Time",
++      "EventCode": "0x01",
++      "EventName": "riscv_time",
++      "BriefDescription": "CPU time RISC-V generic counter"
++  },
++  {
++    "PublicDescription": "CPU Instructions",
++      "EventCode": "0x02",
++      "EventName": "riscv_instret",
++      "BriefDescription": "CPU retired instructions RISC-V generic counter"
++  }
++]
+\ No newline at end of file
diff --git a/target/linux/starfive/patches-6.12/0027-RISC-V-Create-unique-identification-for-SoC-PMU.patch b/target/linux/starfive/patches-6.12/0027-RISC-V-Create-unique-identification-for-SoC-PMU.patch
new file mode 100644 (file)
index 0000000..b18e10f
--- /dev/null
@@ -0,0 +1,93 @@
+From f0b0e5392bd7bce16c86d4ed3fc66394db16eb7d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?=
+ <joao.mario@tecnico.ulisboa.pt>
+Date: Tue, 16 Nov 2021 15:48:09 +0000
+Subject: [PATCH 27/55] RISC-V: Create unique identification for SoC PMU
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The SBI PMU platform driver did not provide any identification for
+perf events matching. This patch introduces a new sysfs file inside the
+platform device (soc:pmu/id) for pmu identification.
+
+The identification is a 64-bit value generated as:
+[63-32]: mvendorid;
+[31]: marchid[MSB];
+[30-16]: marchid[15-0];
+[15-0]: mimpid[15MSBs];
+
+The CSRs are detailed in the RISC-V privileged spec [1].
+The marchid is split in MSB + 15LSBs, due to the MSB being used for
+open-source architecture identification.
+
+[1] https://github.com/riscv/riscv-isa-manual
+
+Signed-off-by: João Mário Domingos <joao.mario@tecnico.ulisboa.pt>
+---
+ drivers/perf/riscv_pmu_sbi.c | 47 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
+
+--- a/drivers/perf/riscv_pmu_sbi.c
++++ b/drivers/perf/riscv_pmu_sbi.c
+@@ -1326,6 +1326,46 @@ static struct ctl_table sbi_pmu_sysctl_t
+       },
+ };
++static uint64_t pmu_sbi_get_pmu_id(void)
++{
++      union sbi_pmu_id {
++              uint64_t value;
++              struct {
++                      uint16_t imp:16;
++                      uint16_t arch:16;
++                      uint32_t vendor:32;
++              };
++      } pmuid;
++
++      pmuid.value = 0;
++      pmuid.vendor = (uint32_t) sbi_get_mvendorid();
++      pmuid.arch = (sbi_get_marchid() >> (63 - 15) & (1 << 15)) | (sbi_get_marchid() & 0x7FFF);
++      pmuid.imp = (sbi_get_mimpid() >> 16);
++
++      return pmuid.value;
++}
++
++static ssize_t pmu_sbi_id_show(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      int len;
++
++      len = sprintf(buf, "0x%llx\n", pmu_sbi_get_pmu_id());
++      if (len <= 0)
++              dev_err(dev, "mydrv: Invalid sprintf len: %dn", len);
++
++      return len;
++}
++
++static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, pmu_sbi_id_show, 0);
++
++static struct attribute *pmu_sbi_attrs[] = {
++      &dev_attr_id.attr,
++      NULL
++};
++
++ATTRIBUTE_GROUPS(pmu_sbi);
++
+ static int pmu_sbi_device_probe(struct platform_device *pdev)
+ {
+       struct riscv_pmu *pmu = NULL;
+@@ -1375,6 +1415,13 @@ static int pmu_sbi_device_probe(struct p
+       pmu->event_unmapped = pmu_sbi_event_unmapped;
+       pmu->csr_index = pmu_sbi_csr_index;
++      ret = sysfs_create_group(&pdev->dev.kobj, &pmu_sbi_group);
++      if (ret) {
++              dev_err(&pdev->dev, "sysfs creation failed\n");
++              return ret;
++      }
++      pdev->dev.groups = pmu_sbi_groups;
++
+       ret = riscv_pm_pmu_register(pmu);
+       if (ret)
+               goto out_unregister;
diff --git a/target/linux/starfive/patches-6.12/0028-RISC-V-Support-CPUID-for-risc-v-in-perf.patch b/target/linux/starfive/patches-6.12/0028-RISC-V-Support-CPUID-for-risc-v-in-perf.patch
new file mode 100644 (file)
index 0000000..6b51326
--- /dev/null
@@ -0,0 +1,55 @@
+From 81ab7f42a1153d6d93b3d429ae0c779e97b0d3d6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?=
+ <joao.mario@tecnico.ulisboa.pt>
+Date: Tue, 16 Nov 2021 15:48:10 +0000
+Subject: [PATCH 28/55] RISC-V: Support CPUID for risc-v in perf
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch creates the header.c file for the risc-v architecture and introduces support for
+PMU identification through sysfs.
+It is now possible to configure pmu-events in risc-v.
+
+Depends on patch [1], that introduces the id sysfs file.
+
+Signed-off-by: João Mário Domingos <joao.mario@tecnico.ulisboa.pt>
+Signed-off-by: minda.chen <minda.chen@starfivetech.com>
+---
+ drivers/perf/riscv_pmu.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/drivers/perf/riscv_pmu.c
++++ b/drivers/perf/riscv_pmu.c
+@@ -18,6 +18,23 @@
+ #include <asm/sbi.h>
++PMU_FORMAT_ATTR(event, "config:0-63");
++
++static struct attribute *riscv_arch_formats_attr[] = {
++      &format_attr_event.attr,
++      NULL,
++};
++
++static struct attribute_group riscv_pmu_format_group = {
++      .name = "format",
++      .attrs = riscv_arch_formats_attr,
++};
++
++static const struct attribute_group *riscv_pmu_attr_groups[] = {
++      &riscv_pmu_format_group,
++      NULL,
++};
++
+ static bool riscv_perf_user_access(struct perf_event *event)
+ {
+       return ((event->attr.type == PERF_TYPE_HARDWARE) ||
+@@ -407,6 +424,7 @@ struct riscv_pmu *riscv_pmu_alloc(void)
+               cpuc->snapshot_addr = NULL;
+       }
+       pmu->pmu = (struct pmu) {
++              .attr_groups    = riscv_pmu_attr_groups,
+               .event_init     = riscv_pmu_event_init,
+               .event_mapped   = riscv_pmu_event_mapped,
+               .event_unmapped = riscv_pmu_event_unmapped,
diff --git a/target/linux/starfive/patches-6.12/0029-dmaengine-dw-axi-dmac-Drop-unused-print-message.patch b/target/linux/starfive/patches-6.12/0029-dmaengine-dw-axi-dmac-Drop-unused-print-message.patch
new file mode 100644 (file)
index 0000000..0b5d770
--- /dev/null
@@ -0,0 +1,24 @@
+From 1664fcade482724f09a4e0cf25018b6ccebaed84 Mon Sep 17 00:00:00 2001
+From: Walker Chen <walker.chen@starfivetech.com>
+Date: Mon, 12 Jun 2023 21:21:45 +0800
+Subject: [PATCH 29/55] dmaengine: dw-axi-dmac: Drop unused print message
+
+Removed printing information which is not related to StarFive
+platform.
+
+Signed-off-by: Walker Chen <walker.chen@starfivetech.com>
+---
+ drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+@@ -569,7 +569,7 @@ static void dw_axi_dma_set_hw_channel(st
+       unsigned long reg_value, val;
+       if (!chip->apb_regs) {
+-              dev_err(chip->dev, "apb_regs not initialized\n");
++              dev_dbg(chip->dev, "apb_regs not initialized\n");
+               return;
+       }
diff --git a/target/linux/starfive/patches-6.12/0030-riscv-dts-starfive-vf2-add-reserved-memory-for-E24.patch b/target/linux/starfive/patches-6.12/0030-riscv-dts-starfive-vf2-add-reserved-memory-for-E24.patch
new file mode 100644 (file)
index 0000000..dcc3dc1
--- /dev/null
@@ -0,0 +1,32 @@
+From 8339ccc47af05298612b7f01b8609f9081e9b081 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 31 May 2025 13:59:30 +0000
+Subject: [PATCH 30/55] riscv: dts: starfive: vf2: add reserved-memory for E24
+
+E24 is an rv32 RISC-V core in the JH7110 package. As the driver is now
+available for it, add reserved memory as required.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ .../dts/starfive/jh7110-starfive-visionfive-2.dtsi     | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+@@ -11,6 +11,16 @@
+       aliases {
+               ethernet1 = &gmac1;
+       };
++
++      reserved-memory {
++              #address-cells = <2>;
++              #size-cells = <2>;
++              ranges;
++
++              e24_mem: e24@c0000000 {
++                      reg = <0x0 0x6ce00000 0x0 0x1600000>;
++              };
++      };
+ };
+ &gmac1 {
diff --git a/target/linux/starfive/patches-6.12/1000-riscv-dts-starfive-Add-JH7100-high-speed-UARTs.patch b/target/linux/starfive/patches-6.12/1000-riscv-dts-starfive-Add-JH7100-high-speed-UARTs.patch
new file mode 100644 (file)
index 0000000..57133a2
--- /dev/null
@@ -0,0 +1,49 @@
+From 907f68f5000522e3c78e9a5dca194f52f2ac54d3 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sun, 31 Oct 2021 17:15:58 +0100
+Subject: [PATCH 1000/1021] riscv: dts: starfive: Add JH7100 high speed UARTs
+
+Add missing device tree nodes for UART0 and UART1 on the StarFive JH7100
+SoC. UART0 is used for Bluetooth on the BeagleV Starlight and StarFive
+VisionFive V1 boards.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ arch/riscv/boot/dts/starfive/jh7100.dtsi | 26 ++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
+@@ -258,6 +258,32 @@
+                       reg = <0x0 0x11850000 0x0 0x10000>;
+               };
++              uart0: serial@11870000 {
++                      compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart";
++                      reg = <0x0 0x11870000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_UART0_CORE>,
++                               <&clkgen JH7100_CLK_UART0_APB>;
++                      clock-names = "baudclk", "apb_pclk";
++                      resets = <&rstgen JH7100_RSTN_UART0_APB>;
++                      interrupts = <92>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      status = "disabled";
++              };
++
++              uart1: serial@11880000 {
++                      compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart";
++                      reg = <0x0 0x11880000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_UART1_CORE>,
++                               <&clkgen JH7100_CLK_UART1_APB>;
++                      clock-names = "baudclk", "apb_pclk";
++                      resets = <&rstgen JH7100_RSTN_UART1_APB>;
++                      interrupts = <93>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      status = "disabled";
++              };
++
+               i2c0: i2c@118b0000 {
+                       compatible = "snps,designware-i2c";
+                       reg = <0x0 0x118b0000 0x0 0x10000>;
diff --git a/target/linux/starfive/patches-6.12/1001-riscv-dts-starfive-Enable-Bluetooth-on-JH7100-boards.patch b/target/linux/starfive/patches-6.12/1001-riscv-dts-starfive-Enable-Bluetooth-on-JH7100-boards.patch
new file mode 100644 (file)
index 0000000..b2c3e51
--- /dev/null
@@ -0,0 +1,79 @@
+From 920915a0d5495b1185391cceb92f9d5b26a875e4 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Mon, 13 Sep 2021 01:18:01 +0200
+Subject: [PATCH 1001/1021] riscv: dts: starfive: Enable Bluetooth on JH7100
+ boards
+
+Add pinctrl and UART nodes for the Broadcom Wifi/Bluetooth module on the
+BeagleV Starlight and StarFive VisionFive V1 boards.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ .../boot/dts/starfive/jh7100-common.dtsi      | 49 +++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
+@@ -289,6 +289,41 @@
+               };
+       };
++      uart0_pins: uart0-0 {
++              rx-pins {
++                      pinmux = <GPIOMUX(40, GPO_LOW, GPO_DISABLE,
++                                GPI_UART0_PAD_SIN)>;
++                      bias-pull-up;
++                      drive-strength = <14>;
++                      input-enable;
++                      input-schmitt-enable;
++              };
++              tx-pins {
++                      pinmux = <GPIOMUX(41, GPO_UART0_PAD_SOUT,
++                                GPO_ENABLE, GPI_NONE)>;
++                      bias-disable;
++                      drive-strength = <35>;
++                      input-disable;
++                      input-schmitt-disable;
++              };
++              cts-pins {
++                      pinmux = <GPIOMUX(39, GPO_LOW, GPO_DISABLE,
++                                GPI_UART0_PAD_CTSN)>;
++                      bias-pull-down;
++                      drive-strength = <14>;
++                      input-enable;
++                      input-schmitt-enable;
++              };
++              rts-pins {
++                      pinmux = <GPIOMUX(42, GPO_UART0_PAD_RTSN,
++                                GPO_ENABLE, GPI_NONE)>;
++                      bias-disable;
++                      drive-strength = <35>;
++                      input-disable;
++                      input-schmitt-disable;
++              };
++      };
++
+       uart3_pins: uart3-0 {
+               rx-pins {
+                       pinmux = <GPIOMUX(13, GPO_LOW, GPO_DISABLE,
+@@ -393,6 +428,20 @@
+       };
+ };
++&uart0 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&uart0_pins>;
++      uart-has-rtscts;
++      status = "okay";
++
++      bluetooth {
++              compatible = "brcm,bcm4330-bt";
++              max-speed = <4000000>;
++              device-wakeup-gpios = <&gpio 38 GPIO_ACTIVE_HIGH>;
++              reset-gpios = <&gpio 35 GPIO_ACTIVE_LOW>;
++      };
++};
++
+ &uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart3_pins>;
diff --git a/target/linux/starfive/patches-6.12/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch b/target/linux/starfive/patches-6.12/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch
new file mode 100644 (file)
index 0000000..db83fe9
--- /dev/null
@@ -0,0 +1,25 @@
+From 48358693ffb4bc661996d14adcd3942a318cdb79 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Thu, 14 Oct 2021 20:56:54 +0200
+Subject: [PATCH 1002/1021] serial: 8250_dw: Add starfive,jh7100-hsuart
+ compatible
+
+This adds a compatible for the high speed UARTs on the StarFive JH7100
+RISC-V SoC. Just like the regular uarts we also need to keep the input
+clocks at their default rate and rely only on the divisor in the UART.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ drivers/tty/serial/8250/8250_dw.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -777,6 +777,7 @@ static const struct of_device_id dw8250_
+       { .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
+       { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
+       { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data },
++      { .compatible = "starfive,jh7100-hsuart", .data = &dw8250_skip_set_rate_data },
+       { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data },
+       { /* Sentinel */ }
+ };
diff --git a/target/linux/starfive/patches-6.12/1003-drivers-tty-serial-8250-update-driver-for-JH7100.patch b/target/linux/starfive/patches-6.12/1003-drivers-tty-serial-8250-update-driver-for-JH7100.patch
new file mode 100644 (file)
index 0000000..6d41247
--- /dev/null
@@ -0,0 +1,28 @@
+From bb3c832bd58bd2bca5f7f99bd19a0fe6ad3cf1a4 Mon Sep 17 00:00:00 2001
+From: Samin Guo <samin.guo@starfivetech.com>
+Date: Fri, 8 Jan 2021 03:11:04 +0800
+Subject: [PATCH 1003/1021] drivers/tty/serial/8250: update driver for JH7100
+
+---
+ drivers/tty/serial/8250/8250_port.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -68,8 +68,16 @@ static const struct serial8250_config ua
+       },
+       [PORT_16550] = {
+               .name           = "16550",
++#ifdef CONFIG_SOC_STARFIVE
++              .fifo_size      = 16,
++              .tx_loadsz      = 16,
++              .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
++              .rxtrig_bytes   = {1, 4, 8, 14},
++              .flags          = UART_CAP_FIFO,
++#else
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
++#endif
+       },
+       [PORT_16550A] = {
+               .name           = "16550A",
diff --git a/target/linux/starfive/patches-6.12/1004-power-reset-tps65086-Allow-building-as-a-module.patch b/target/linux/starfive/patches-6.12/1004-power-reset-tps65086-Allow-building-as-a-module.patch
new file mode 100644 (file)
index 0000000..b8dd18f
--- /dev/null
@@ -0,0 +1,29 @@
+From 995a9b41dd4e29d02ec549170f917b301d8a6d36 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sun, 3 Jul 2022 21:01:11 +0200
+Subject: [PATCH 1004/1021] power: reset: tps65086: Allow building as a module
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ drivers/power/reset/Kconfig            | 2 +-
+ drivers/power/reset/tps65086-restart.c | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/power/reset/Kconfig
++++ b/drivers/power/reset/Kconfig
+@@ -217,7 +217,7 @@ config POWER_RESET_ST
+         Reset support for STMicroelectronics boards.
+ config POWER_RESET_TPS65086
+-      bool "TPS65086 restart driver"
++      tristate "TPS65086 restart driver"
+       depends on MFD_TPS65086
+       help
+         This driver adds support for resetting the TPS65086 PMIC on restart.
+--- a/drivers/power/reset/tps65086-restart.c
++++ b/drivers/power/reset/tps65086-restart.c
+@@ -57,3 +57,4 @@ module_platform_driver(tps65086_restart_
+ MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>");
+ MODULE_DESCRIPTION("TPS65086 restart driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/starfive/patches-6.12/1005-riscv-dts-starfive-Add-StarFive-JH7100-audio-clock-n.patch b/target/linux/starfive/patches-6.12/1005-riscv-dts-starfive-Add-StarFive-JH7100-audio-clock-n.patch
new file mode 100644 (file)
index 0000000..2f7ed82
--- /dev/null
@@ -0,0 +1,33 @@
+From bedd1e49a138fc532712ae3e889af17a0dbc9417 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sat, 20 Nov 2021 17:13:22 +0100
+Subject: [PATCH 1005/1021] riscv: dts: starfive: Add StarFive JH7100 audio
+ clock node
+
+Add device tree node for the audio clocks on the StarFive JH7100 RISC-V
+SoC.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ arch/riscv/boot/dts/starfive/jh7100.dtsi | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
+@@ -239,6 +239,16 @@
+                       };
+               };
++              audclk: clock-controller@10480000 {
++                      compatible = "starfive,jh7100-audclk";
++                      reg = <0x0 0x10480000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_AUDIO_SRC>,
++                               <&clkgen JH7100_CLK_AUDIO_12288>,
++                               <&clkgen JH7100_CLK_DOM7AHB_BUS>;
++                      clock-names = "audio_src", "audio_12288", "dom7ahb_bus";
++                      #clock-cells = <1>;
++              };
++
+               clkgen: clock-controller@11800000 {
+                       compatible = "starfive,jh7100-clkgen";
+                       reg = <0x0 0x11800000 0x0 0x10000>;
diff --git a/target/linux/starfive/patches-6.12/1006-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch b/target/linux/starfive/patches-6.12/1006-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch
new file mode 100644 (file)
index 0000000..7739a7d
--- /dev/null
@@ -0,0 +1,48 @@
+From 052732a9fb44ab63e522a9b2949d64e2d2f2d4fc Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sat, 20 Nov 2021 19:29:25 +0100
+Subject: [PATCH 1006/1021] dt-bindings: reset: Add StarFive JH7100 audio reset
+ definitions
+
+Add all resets for the StarFive JH7100 audio reset controller.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ .../dt-bindings/reset/starfive-jh7100-audio.h | 31 +++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+ create mode 100644 include/dt-bindings/reset/starfive-jh7100-audio.h
+
+--- /dev/null
++++ b/include/dt-bindings/reset/starfive-jh7100-audio.h
+@@ -0,0 +1,31 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++/*
++ * Copyright (C) 2021 Emil Renner Berthing
++ */
++
++#ifndef __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__
++#define __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__
++
++#define JH7100_AUDRSTN_APB_BUS                0
++#define JH7100_AUDRSTN_I2SADC_APB     1
++#define JH7100_AUDRSTN_I2SADC_SRST    2
++#define JH7100_AUDRSTN_PDM_APB                3
++#define JH7100_AUDRSTN_I2SVAD_APB     4
++#define JH7100_AUDRSTN_I2SVAD_SRST    5
++#define JH7100_AUDRSTN_SPDIF_APB      6
++#define JH7100_AUDRSTN_PWMDAC_APB     7
++#define JH7100_AUDRSTN_I2SDAC_APB     8
++#define JH7100_AUDRSTN_I2SDAC_SRST    9
++#define JH7100_AUDRSTN_I2S1_APB               10
++#define JH7100_AUDRSTN_I2S1_SRST      11
++#define JH7100_AUDRSTN_I2SDAC16K_APB  12
++#define JH7100_AUDRSTN_I2SDAC16K_SRST 13
++#define JH7100_AUDRSTN_DMA1P_AHB      14
++#define JH7100_AUDRSTN_USB_APB                15
++#define JH7100_AUDRST_USB_AXI         16
++#define JH7100_AUDRST_USB_PWRUP_RST_N 17
++#define JH7100_AUDRST_USB_PONRST      18
++
++#define JH7100_AUDRSTN_END            19
++
++#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__ */
diff --git a/target/linux/starfive/patches-6.12/1007-reset-starfive-Add-JH7100-audio-reset-driver.patch b/target/linux/starfive/patches-6.12/1007-reset-starfive-Add-JH7100-audio-reset-driver.patch
new file mode 100644 (file)
index 0000000..5954e58
--- /dev/null
@@ -0,0 +1,144 @@
+From 2828a23364ab4a55af817b7ab370e6fc225f025d Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sat, 20 Nov 2021 19:30:49 +0100
+Subject: [PATCH 1007/1021] reset: starfive: Add JH7100 audio reset driver
+
+The audio resets are almost identical to the system resets, there are
+just fewer of them. So factor out and export a generic probe function,
+so most of the reset controller implementation can be shared.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ MAINTAINERS                                   |  2 +-
+ drivers/reset/starfive/Kconfig                |  7 ++
+ drivers/reset/starfive/Makefile               |  2 +
+ .../starfive/reset-starfive-jh7100-audio.c    | 66 +++++++++++++++++++
+ .../reset/starfive/reset-starfive-jh7100.h    | 16 +++++
+ 5 files changed, 92 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/reset/starfive/reset-starfive-jh7100-audio.c
+ create mode 100644 drivers/reset/starfive/reset-starfive-jh7100.h
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -22078,7 +22078,7 @@ STARFIVE JH71X0 RESET CONTROLLER DRIVERS
+ M:    Emil Renner Berthing <kernel@esmil.dk>
+ M:    Hal Feng <hal.feng@starfivetech.com>
+ S:    Maintained
+-F:    Documentation/devicetree/bindings/reset/starfive,jh7100-reset.yaml
++F:    Documentation/devicetree/bindings/reset/starfive,jh7100-*.yaml
+ F:    drivers/reset/starfive/reset-starfive-jh71*
+ F:    include/dt-bindings/reset/starfive?jh71*.h
+--- a/drivers/reset/starfive/Kconfig
++++ b/drivers/reset/starfive/Kconfig
+@@ -11,6 +11,13 @@ config RESET_STARFIVE_JH7100
+       help
+         This enables the reset controller driver for the StarFive JH7100 SoC.
++config RESET_STARFIVE_JH7100_AUDIO
++      tristate "StarFive JH7100 Audio Reset Driver"
++      depends on RESET_STARFIVE_JH7100
++      default m if SOC_STARFIVE
++      help
++        This enables the audio reset driver for the StarFive JH7100 SoC.
++
+ config RESET_STARFIVE_JH7110
+       bool "StarFive JH7110 Reset Driver"
+       depends on CLK_STARFIVE_JH7110_SYS
+--- a/drivers/reset/starfive/Makefile
++++ b/drivers/reset/starfive/Makefile
+@@ -2,4 +2,6 @@
+ obj-$(CONFIG_RESET_STARFIVE_JH71X0)           += reset-starfive-jh71x0.o
+ obj-$(CONFIG_RESET_STARFIVE_JH7100)           += reset-starfive-jh7100.o
++obj-$(CONFIG_RESET_STARFIVE_JH7100_AUDIO)     += reset-starfive-jh7100-audio.o
++
+ obj-$(CONFIG_RESET_STARFIVE_JH7110)           += reset-starfive-jh7110.o
+--- /dev/null
++++ b/drivers/reset/starfive/reset-starfive-jh7100-audio.c
+@@ -0,0 +1,66 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Audio reset driver for the StarFive JH7100 SoC
++ *
++ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
++ */
++
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include "reset-starfive-jh71x0.h"
++
++#include <dt-bindings/reset/starfive-jh7100-audio.h>
++
++/* register offsets */
++#define JH7100_AUDRST_ASSERT0 0x00
++#define JH7100_AUDRST_STATUS0 0x04
++
++/*
++ * Writing a 1 to the n'th bit of the ASSERT register asserts
++ * line n, and writing a 0 deasserts the same line.
++ * Most reset lines have their status inverted so a 0 bit in the STATUS
++ * register means the line is asserted and a 1 means it's deasserted. A few
++ * lines don't though, so store the expected value of the status registers when
++ * all lines are asserted.
++ */
++static const u32 jh7100_audrst_asserted[1] = {
++      BIT(JH7100_AUDRST_USB_AXI) |
++      BIT(JH7100_AUDRST_USB_PWRUP_RST_N) |
++      BIT(JH7100_AUDRST_USB_PONRST)
++};
++
++static int jh7100_audrst_probe(struct platform_device *pdev)
++{
++      void __iomem *base = devm_platform_ioremap_resource(pdev, 0);
++
++      if (IS_ERR(base))
++              return PTR_ERR(base);
++
++      return reset_starfive_jh71x0_register(&pdev->dev, pdev->dev.of_node,
++                                            base + JH7100_AUDRST_ASSERT0,
++                                            base + JH7100_AUDRST_STATUS0,
++                                            jh7100_audrst_asserted,
++                                            JH7100_AUDRSTN_END,
++                                            THIS_MODULE);
++}
++
++static const struct of_device_id jh7100_audrst_dt_ids[] = {
++      { .compatible = "starfive,jh7100-audrst" },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, jh7100_audrst_dt_ids);
++
++static struct platform_driver jh7100_audrst_driver = {
++      .probe = jh7100_audrst_probe,
++      .driver = {
++              .name = "jh7100-reset-audio",
++              .of_match_table = jh7100_audrst_dt_ids,
++      },
++};
++module_platform_driver(jh7100_audrst_driver);
++
++MODULE_AUTHOR("Emil Renner Berthing");
++MODULE_DESCRIPTION("StarFive JH7100 audio reset driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/reset/starfive/reset-starfive-jh7100.h
+@@ -0,0 +1,16 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
++ */
++
++#ifndef _RESET_STARFIVE_JH7100_H_
++#define _RESET_STARFIVE_JH7100_H_
++
++#include <linux/platform_device.h>
++
++int reset_starfive_jh7100_generic_probe(struct platform_device *pdev,
++                                      const u32 *asserted,
++                                      unsigned int status_offset,
++                                      unsigned int nr_resets);
++
++#endif
diff --git a/target/linux/starfive/patches-6.12/1008-riscv-dts-starfive-Add-StarFive-JH7100-audio-reset-n.patch b/target/linux/starfive/patches-6.12/1008-riscv-dts-starfive-Add-StarFive-JH7100-audio-reset-n.patch
new file mode 100644 (file)
index 0000000..0c93f88
--- /dev/null
@@ -0,0 +1,29 @@
+From a806acd4f507764123838c9620d4e581585f2099 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sat, 20 Nov 2021 21:33:08 +0100
+Subject: [PATCH 1008/1021] riscv: dts: starfive: Add StarFive JH7100 audio
+ reset node
+
+Add device tree node for the audio resets on the StarFive JH7100 RISC-V
+SoC.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ arch/riscv/boot/dts/starfive/jh7100.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
+@@ -249,6 +249,12 @@
+                       #clock-cells = <1>;
+               };
++              audrst: reset-controller@10490000 {
++                      compatible = "starfive,jh7100-audrst";
++                      reg = <0x0 0x10490000 0x0 0x10000>;
++                      #reset-cells = <1>;
++              };
++
+               clkgen: clock-controller@11800000 {
+                       compatible = "starfive,jh7100-clkgen";
+                       reg = <0x0 0x11800000 0x0 0x10000>;
diff --git a/target/linux/starfive/patches-6.12/1009-clk-starfive-jh7100-Keep-more-clocks-alive.patch b/target/linux/starfive/patches-6.12/1009-clk-starfive-jh7100-Keep-more-clocks-alive.patch
new file mode 100644 (file)
index 0000000..4f527ec
--- /dev/null
@@ -0,0 +1,61 @@
+From 174c73330839bad688b9fb2e9b6b9a2e5d74021f Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Thu, 14 Oct 2021 20:35:43 +0200
+Subject: [PATCH 1009/1021] clk: starfive: jh7100: Keep more clocks alive
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ drivers/clk/starfive/clk-starfive-jh7100.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+--- a/drivers/clk/starfive/clk-starfive-jh7100.c
++++ b/drivers/clk/starfive/clk-starfive-jh7100.c
+@@ -94,9 +94,9 @@ static const struct jh71x0_clk_data jh71
+       JH71X0_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI),
+       JH71X0_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS),
+       JH71X0__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT),
+-      JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS),
+-      JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS),
+-      JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS),
++      JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DLA_BUS),
++      JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DLA_BUS),
++      JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", CLK_IGNORE_UNUSED, JH7100_CLK_APB1_BUS),
+       JH71X0_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV),
+       JH71X0__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT),
+       JH71X0_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC),
+@@ -163,8 +163,9 @@ static const struct jh71x0_clk_data jh71
+       JH71X0_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS),
+       JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS),
+       JH71X0__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT),
+-      JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV),
+-      JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32,
++      JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", CLK_IGNORE_UNUSED, 8,
++                  JH7100_CLK_USBPHY_ROOTDIV),
++      JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", CLK_IGNORE_UNUSED, 32,
+                   JH7100_CLK_USBPHY_ROOTDIV),
+       JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2,
+                   JH7100_CLK_OSC_SYS,
+@@ -183,11 +184,11 @@ static const struct jh71x0_clk_data jh71
+       JH71X0__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC),
+       JH71X0_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS),
+       JH71X0_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS),
+-      JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT),
++      JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", CLK_IGNORE_UNUSED, 4, JH7100_CLK_VOUT_ROOT),
+       JH71X0__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT),
+       JH71X0__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC),
+-      JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS),
+-      JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS),
++      JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DISP_BUS),
++      JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DISP_BUS),
+       JH71X0_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS),
+       JH71X0_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC),
+       JH71X0__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT),
+@@ -223,7 +224,7 @@ static const struct jh71x0_clk_data jh71
+       JH71X0_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB),
+       JH71X0_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB),
+       JH71X0_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB),
+-      JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS),
++      JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", CLK_IGNORE_UNUSED, JH7100_CLK_APB1_BUS),
+       JH71X0_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS),
+       JH71X0_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS),
+       JH71X0_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC),
diff --git a/target/linux/starfive/patches-6.12/1010-pinctrl-starfive-Reset-pinmux-settings.patch b/target/linux/starfive/patches-6.12/1010-pinctrl-starfive-Reset-pinmux-settings.patch
new file mode 100644 (file)
index 0000000..bf1c2d8
--- /dev/null
@@ -0,0 +1,127 @@
+From f3e66db46e8c849e154042c35bfa22fedc03c3df Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sat, 17 Jul 2021 21:50:38 +0200
+Subject: [PATCH 1010/1021] pinctrl: starfive: Reset pinmux settings
+
+Current u-boot doesn't seem to take into account that some GPIOs are
+configured as inputs/outputs of certain peripherals on power-up. This
+means it ends up configuring some GPIOs as inputs to more than one
+peripheral which the documentation explicitly says is illegal. Similarly
+it also ends up configuring more than one GPIO as output of the same
+peripheral. While not explicitly mentioned by the documentation this
+also seems like a bad idea.
+
+The easiest way to remedy this mess is to just disconnect all GPIOs from
+peripherals and have our pinmux configuration set everything up
+properly. This, however, means that we'd disconnect the serial console
+from its pins for a while, so add a device tree property to keep
+certain GPIOs from being reset.
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ .../pinctrl/starfive,jh7100-pinctrl.yaml      |  4 ++
+ .../starfive/pinctrl-starfive-jh7100.c        | 66 +++++++++++++++++++
+ 2 files changed, 70 insertions(+)
+
+--- a/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml
++++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml
+@@ -88,6 +88,10 @@ properties:
+     $ref: /schemas/types.yaml#/definitions/uint32
+     enum: [0, 1, 2, 3, 4, 5, 6]
++  starfive,keep-gpiomux:
++    description: Keep pinmux for these GPIOs from being reset at boot.
++    $ref: /schemas/types.yaml#/definitions/uint32-array
++
+ required:
+   - compatible
+   - reg
+--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
++++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
+@@ -203,6 +203,10 @@ static u16 starfive_drive_strength_from_
+       return (clamp(i, 14U, 63U) - 14) / 7;
+ }
++static bool keepmux;
++module_param(keepmux, bool, 0644);
++MODULE_PARM_DESC(keepmux, "Keep pinmux settings from previous boot stage");
++
+ struct starfive_pinctrl {
+       struct gpio_chip gc;
+       struct pinctrl_gpio_range gpios;
+@@ -1210,6 +1214,65 @@ static void starfive_disable_clock(void
+       clk_disable_unprepare(data);
+ }
++#define GPI_END (GPI_USB_OVER_CURRENT + 1)
++static void starfive_pinmux_reset(struct starfive_pinctrl *sfp)
++{
++      static const DECLARE_BITMAP(defaults, GPI_END) = {
++              BIT_MASK(GPI_I2C0_PAD_SCK_IN) |
++              BIT_MASK(GPI_I2C0_PAD_SDA_IN) |
++              BIT_MASK(GPI_I2C1_PAD_SCK_IN) |
++              BIT_MASK(GPI_I2C1_PAD_SDA_IN) |
++              BIT_MASK(GPI_I2C2_PAD_SCK_IN) |
++              BIT_MASK(GPI_I2C2_PAD_SDA_IN) |
++              BIT_MASK(GPI_I2C3_PAD_SCK_IN) |
++              BIT_MASK(GPI_I2C3_PAD_SDA_IN) |
++              BIT_MASK(GPI_SDIO0_PAD_CARD_DETECT_N) |
++
++              BIT_MASK(GPI_SDIO1_PAD_CARD_DETECT_N) |
++              BIT_MASK(GPI_SPI0_PAD_SS_IN_N) |
++              BIT_MASK(GPI_SPI1_PAD_SS_IN_N) |
++              BIT_MASK(GPI_SPI2_PAD_SS_IN_N) |
++              BIT_MASK(GPI_SPI2AHB_PAD_SS_N) |
++              BIT_MASK(GPI_SPI3_PAD_SS_IN_N),
++
++              BIT_MASK(GPI_UART0_PAD_SIN) |
++              BIT_MASK(GPI_UART1_PAD_SIN) |
++              BIT_MASK(GPI_UART2_PAD_SIN) |
++              BIT_MASK(GPI_UART3_PAD_SIN) |
++              BIT_MASK(GPI_USB_OVER_CURRENT)
++      };
++      DECLARE_BITMAP(keep, NR_GPIOS) = {};
++      struct device_node *np = sfp->gc.parent->of_node;
++      int len = of_property_count_u32_elems(np, "starfive,keep-gpiomux");
++      int i;
++
++      for (i = 0; i < len; i++) {
++              u32 gpio;
++
++              of_property_read_u32_index(np, "starfive,keep-gpiomux", i, &gpio);
++              if (gpio < NR_GPIOS)
++                      set_bit(gpio, keep);
++      }
++
++      for (i = 0; i < NR_GPIOS; i++) {
++              if (test_bit(i, keep))
++                      continue;
++
++              writel_relaxed(GPO_DISABLE, sfp->base + GPON_DOEN_CFG + 8 * i);
++              writel_relaxed(GPO_LOW,     sfp->base + GPON_DOUT_CFG + 8 * i);
++      }
++
++      for (i = 0; i < GPI_END; i++) {
++              void __iomem *reg = sfp->base + GPI_CFG_OFFSET + 4 * i;
++              u32 din = readl_relaxed(reg);
++
++              if (din >= 2 && din < (NR_GPIOS + 2) && test_bit(din - 2, keep))
++                      continue;
++
++              writel_relaxed(test_bit(i, defaults), reg);
++      }
++}
++
+ static int starfive_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+@@ -1271,6 +1334,9 @@ static int starfive_probe(struct platfor
+               writel(value, sfp->padctl + IO_PADSHARE_SEL);
+       }
++      if (!keepmux)
++              starfive_pinmux_reset(sfp);
++
+       value = readl(sfp->padctl + IO_PADSHARE_SEL);
+       switch (value) {
+       case 0:
diff --git a/target/linux/starfive/patches-6.12/1011-net-stmmac-use-GFP_DMA32.patch b/target/linux/starfive/patches-6.12/1011-net-stmmac-use-GFP_DMA32.patch
new file mode 100644 (file)
index 0000000..7ddad83
--- /dev/null
@@ -0,0 +1,30 @@
+From 690e2d40fe645e86dcd0ac265038426676473e19 Mon Sep 17 00:00:00 2001
+From: Matteo Croce <technoboy85@gmail.com>
+Date: Fri, 21 May 2021 03:26:38 +0200
+Subject: [PATCH 1011/1021] net: stmmac: use GFP_DMA32
+
+Signed-off-by: Matteo Croce <mcroce@microsoft.com>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -1460,7 +1460,7 @@ static int stmmac_init_rx_buffers(struct
+ {
+       struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
+       struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+-      gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
++      gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32);
+       if (priv->dma_cap.host_dma_width <= 32)
+               gfp |= GFP_DMA32;
+@@ -4756,7 +4756,7 @@ static inline void stmmac_rx_refill(stru
+       struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
+       int dirty = stmmac_rx_dirty(priv, queue);
+       unsigned int entry = rx_q->dirty_rx;
+-      gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
++      gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32);
+       if (priv->dma_cap.host_dma_width <= 32)
+               gfp |= GFP_DMA32;
diff --git a/target/linux/starfive/patches-6.12/1012-dt-bindings-dma-dw-axi-dmac-Increase-DMA-channel-lim.patch b/target/linux/starfive/patches-6.12/1012-dt-bindings-dma-dw-axi-dmac-Increase-DMA-channel-lim.patch
new file mode 100644 (file)
index 0000000..047fb94
--- /dev/null
@@ -0,0 +1,45 @@
+From e941dae591d8cd24f6758ecded9cc9741082e76d Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert@linux-m68k.org>
+Date: Thu, 27 May 2021 20:13:43 +0200
+Subject: [PATCH 1012/1021] dt-bindings: dma: dw-axi-dmac: Increase DMA channel
+ limit to 16
+
+The first DMAC instance in the StarFive JH7100 SoC supports 16 DMA
+channels.
+
+FIXME Given there are more changes to the driver than just increasing
+      DMAC_MAX_CHANNELS, we probably need a new compatible value, too.
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
++++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
+@@ -57,7 +57,7 @@ properties:
+   dma-channels:
+     minimum: 1
+-    maximum: 8
++    maximum: 16
+   resets:
+     minItems: 1
+@@ -81,14 +81,14 @@ properties:
+       Channel priority specifier associated with the DMA channels.
+     $ref: /schemas/types.yaml#/definitions/uint32-array
+     minItems: 1
+-    maxItems: 8
++    maxItems: 16
+   snps,block-size:
+     description: |
+       Channel block size specifier associated with the DMA channels.
+     $ref: /schemas/types.yaml#/definitions/uint32-array
+     minItems: 1
+-    maxItems: 8
++    maxItems: 16
+   snps,axi-max-burst-len:
+     description: |
diff --git a/target/linux/starfive/patches-6.12/1013-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch b/target/linux/starfive/patches-6.12/1013-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch
new file mode 100644 (file)
index 0000000..a4a84ee
--- /dev/null
@@ -0,0 +1,55 @@
+From 38bf6380d873ebf247dde54a1b93dcfbf3ea19f6 Mon Sep 17 00:00:00 2001
+From: Samin Guo <samin.guo@starfivetech.com>
+Date: Wed, 17 Nov 2021 14:50:45 +0800
+Subject: [PATCH 1013/1021] dmaengine: dw-axi-dmac: Handle xfer start while
+ non-idle
+
+Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
+Signed-off-by: Curry Zhang <curry.zhang@starfivetech.com>
+---
+ drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 12 +++++++++++-
+ drivers/dma/dw-axi-dmac/dw-axi-dmac.h          |  1 +
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+@@ -428,11 +428,13 @@ static void axi_chan_block_xfer_start(st
+       u32 irq_mask;
+       u8 lms = 0; /* Select AXI0 master for LLI fetching */
++      chan->is_err = false;
+       if (unlikely(axi_chan_is_hw_enable(chan))) {
+               dev_err(chan2dev(chan), "%s is non-idle!\n",
+                       axi_chan_name(chan));
+-              return;
++              axi_chan_disable(chan);
++              chan->is_err = true;
+       }
+       axi_dma_enable(chan->chip);
+@@ -1074,6 +1076,14 @@ static noinline void axi_chan_handle_err
+                       axi_chan_name(chan));
+               goto out;
+       }
++      if (chan->is_err) {
++              struct axi_dma_desc *desc = vd_to_axi_desc(vd);
++
++              axi_chan_block_xfer_start(chan, desc);
++              chan->is_err = false;
++              goto out;
++      }
++
+       /* Remove the completed descriptor from issued list */
+       list_del(&vd->node);
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+@@ -50,6 +50,7 @@ struct axi_dma_chan {
+       struct dma_slave_config         config;
+       enum dma_transfer_direction     direction;
+       bool                            cyclic;
++      bool                            is_err;
+       /* these other elements are all protected by vc.lock */
+       bool                            is_paused;
+ };
diff --git a/target/linux/starfive/patches-6.12/1014-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch b/target/linux/starfive/patches-6.12/1014-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch
new file mode 100644 (file)
index 0000000..426f3c0
--- /dev/null
@@ -0,0 +1,64 @@
+From 43048e7698e0a2c0870112168ed138de4aa937cc Mon Sep 17 00:00:00 2001
+From: Samin Guo <samin.guo@starfivetech.com>
+Date: Wed, 17 Nov 2021 14:50:45 +0800
+Subject: [PATCH 1014/1021] dmaengine: dw-axi-dmac: Add StarFive JH7100 support
+
+Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 12 ++++++++++++
+ drivers/dma/dw-axi-dmac/dw-axi-dmac.h          |  4 ++++
+ 2 files changed, 16 insertions(+)
+
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+@@ -723,8 +723,13 @@ static int dw_axi_dma_set_hw_desc(struct
+       hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
++#ifdef CONFIG_SOC_STARFIVE
++      ctllo |= DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_DST_MSIZE_POS |
++               DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_SRC_MSIZE_POS;
++#else
+       ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
+                DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
++#endif
+       hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
+       set_desc_src_master(hw_desc);
+@@ -1589,7 +1594,11 @@ static int dw_probe(struct platform_devi
+        * Therefore, set constraint to 1024 * 4.
+        */
+       dw->dma.dev->dma_parms = &dw->dma_parms;
++#ifdef CONFIG_SOC_STARFIVE
++      dma_set_max_seg_size(&pdev->dev, DMAC_MAX_BLK_SIZE);
++#else
+       dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE);
++#endif
+       platform_set_drvdata(pdev, chip);
+       pm_runtime_enable(chip->dev);
+@@ -1674,6 +1683,9 @@ static const struct of_device_id dw_dma_
+               .compatible = "intel,kmb-axi-dma",
+               .data = (void *)AXI_DMA_FLAG_HAS_APB_REGS,
+       }, {
++              .compatible = "starfive,jh7100-axi-dma",
++              .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2),
++      }, {
+               .compatible = "starfive,jh7110-axi-dma",
+               .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2),
+       }, {
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+@@ -288,7 +288,11 @@ enum {
+ #define CH_CTL_L_SRC_MAST             BIT(0)
+ /* CH_CFG_H */
++#ifdef CONFIG_SOC_STARFIVE
++#define CH_CFG_H_PRIORITY_POS         15
++#else
+ #define CH_CFG_H_PRIORITY_POS         17
++#endif
+ #define CH_CFG_H_DST_PER_POS          12
+ #define CH_CFG_H_SRC_PER_POS          7
+ #define CH_CFG_H_HS_SEL_DST_POS               4
diff --git a/target/linux/starfive/patches-6.12/1015-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch b/target/linux/starfive/patches-6.12/1015-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch
new file mode 100644 (file)
index 0000000..549f7f8
--- /dev/null
@@ -0,0 +1,477 @@
+From 4a5a14f6cce89d12efa90dd8e2a82e36df2ee179 Mon Sep 17 00:00:00 2001
+From: Huan Feng <huan.feng@starfivetech.com>
+Date: Fri, 8 Jan 2021 03:35:42 +0800
+Subject: [PATCH 1015/1021] hwrng: Add StarFive JH7100 Random Number Generator
+ driver
+
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ drivers/char/hw_random/Kconfig            |  13 ++
+ drivers/char/hw_random/Makefile           |   1 +
+ drivers/char/hw_random/starfive-vic-rng.c | 256 ++++++++++++++++++++++
+ drivers/char/hw_random/starfive-vic-rng.h | 167 ++++++++++++++
+ 4 files changed, 437 insertions(+)
+ create mode 100644 drivers/char/hw_random/starfive-vic-rng.c
+ create mode 100644 drivers/char/hw_random/starfive-vic-rng.h
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -323,6 +323,19 @@ config HW_RANDOM_POWERNV
+         If unsure, say Y.
++config HW_RANDOM_STARFIVE_VIC
++      tristate "Starfive VIC Random Number Generator support"
++      depends on HW_RANDOM && (SOC_STARFIVE || COMPILE_TEST)
++      default SOC_STARFIVE
++      help
++        This driver provides kernel-side support for the Random Number
++        Generator hardware found on Starfive VIC SoC.
++
++        To compile this driver as a module, choose M here: the
++        module will be called starfive-vic-rng.
++
++        If unsure, say Y.
++
+ config HW_RANDOM_HISI
+       tristate "Hisilicon Random Number Generator support"
+       depends on ARCH_HISI || COMPILE_TEST
+--- a/drivers/char/hw_random/Makefile
++++ b/drivers/char/hw_random/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon
+ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
+ obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
+ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
++obj-$(CONFIG_HW_RANDOM_STARFIVE_VIC)  += starfive-vic-rng.o
+ obj-$(CONFIG_HW_RANDOM_HISI)  += hisi-rng.o
+ obj-$(CONFIG_HW_RANDOM_HISTB) += histb-rng.o
+ obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+--- /dev/null
++++ b/drivers/char/hw_random/starfive-vic-rng.c
+@@ -0,0 +1,256 @@
++/*
++ ******************************************************************************
++ * @file  starfive-vic-rng.c
++ * @author  StarFive Technology
++ * @version  V1.0
++ * @date  08/13/2020
++ * @brief
++ ******************************************************************************
++ * @copy
++ *
++ * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
++ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
++ * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
++ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
++ * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
++ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
++ *
++ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
++ */
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/hw_random.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/random.h>
++
++#include "starfive-vic-rng.h"
++
++#define to_vic_rng(p) container_of(p, struct vic_rng, rng)
++
++struct vic_rng {
++      struct device   *dev;
++      void __iomem    *base;
++      struct hwrng    rng;
++};
++
++static inline void vic_wait_till_idle(struct vic_rng *hrng)
++{
++      while(readl(hrng->base + VIC_STAT) & VIC_STAT_BUSY)
++              ;
++}
++
++static inline void vic_rng_irq_mask_clear(struct vic_rng *hrng)
++{
++      // clear register: ISTAT
++      u32 data = readl(hrng->base + VIC_ISTAT);
++      writel(data, hrng->base + VIC_ISTAT);
++      writel(0, hrng->base + VIC_ALARM);
++}
++
++static int vic_trng_cmd(struct vic_rng *hrng, u32 cmd) {
++      int res = 0;
++      // wait till idle
++      vic_wait_till_idle(hrng);
++      switch (cmd) {
++      case VIC_CTRL_CMD_NOP:
++      case VIC_CTRL_CMD_GEN_NOISE:
++      case VIC_CTRL_CMD_GEN_NONCE:
++      case VIC_CTRL_CMD_CREATE_STATE:
++      case VIC_CTRL_CMD_RENEW_STATE:
++      case VIC_CTRL_CMD_REFRESH_ADDIN:
++      case VIC_CTRL_CMD_GEN_RANDOM:
++      case VIC_CTRL_CMD_ADVANCE_STATE:
++      case VIC_CTRL_CMD_KAT:
++      case VIC_CTRL_CMD_ZEROIZE:
++              writel(cmd, hrng->base + VIC_CTRL);
++              break;
++      default:
++              res = -1;
++              break;
++      }
++
++      return res;
++}
++
++static int vic_rng_init(struct hwrng *rng)
++{
++      struct vic_rng *hrng = to_vic_rng(rng);
++
++      // wait till idle
++
++      // clear register: ISTAT
++      vic_rng_irq_mask_clear(hrng);
++
++      // set mission mode
++      writel(VIC_SMODE_SECURE_EN(1), hrng->base + VIC_SMODE);
++
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE);
++      vic_wait_till_idle(hrng);
++
++      // set interrupt
++      writel(VIC_IE_ALL, hrng->base + VIC_IE);
++
++      // zeroize
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
++
++      vic_wait_till_idle(hrng);
++
++      return 0;
++}
++
++static irqreturn_t vic_rng_irq(int irq, void *priv)
++{
++      u32 status, val;
++      struct vic_rng *hrng = (struct vic_rng *)priv;
++
++      /*
++       * clearing the interrupt will also clear the error register
++       * read error and status before clearing
++       */
++      status = readl(hrng->base + VIC_ISTAT);
++
++      if (status & VIC_ISTAT_ALARMS) {
++              writel(VIC_ISTAT_ALARMS, hrng->base + VIC_ISTAT);
++              val = readl(hrng->base + VIC_ALARM);
++              if (val & VIC_ALARM_ILLEGAL_CMD_SEQ) {
++                      writel(VIC_ALARM_ILLEGAL_CMD_SEQ, hrng->base + VIC_ALARM);
++                      //dev_info(hrng->dev, "ILLEGAL CMD SEQ: LAST_CMD=0x%x\r\n",
++                      //VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT)));
++              } else {
++                      dev_info(hrng->dev, "Failed test: %x\r\n", val);
++              }
++      }
++
++      if (status & VIC_ISTAT_ZEROIZE) {
++              writel(VIC_ISTAT_ZEROIZE, hrng->base + VIC_ISTAT);
++              //dev_info(hrng->dev, "zeroized\r\n");
++      }
++
++      if (status & VIC_ISTAT_KAT_COMPLETE) {
++              writel(VIC_ISTAT_KAT_COMPLETE, hrng->base + VIC_ISTAT);
++              //dev_info(hrng->dev, "kat_completed\r\n");
++      }
++
++      if (status & VIC_ISTAT_NOISE_RDY) {
++              writel(VIC_ISTAT_NOISE_RDY, hrng->base + VIC_ISTAT);
++              //dev_info(hrng->dev, "noise_rdy\r\n");
++      }
++
++      if (status & VIC_ISTAT_DONE) {
++              writel(VIC_ISTAT_DONE, hrng->base + VIC_ISTAT);
++              //dev_info(hrng->dev, "done\r\n");
++              /*
++              if (VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT)) ==
++                  VIC_CTRL_CMD_GEN_RANDOM) {
++                      dev_info(hrng->dev, "Need Update Buffer\r\n");
++              }
++              */
++      }
++      vic_rng_irq_mask_clear(hrng);
++
++      return IRQ_HANDLED;
++}
++
++static void vic_rng_cleanup(struct hwrng *rng)
++{
++      struct vic_rng *hrng = to_vic_rng(rng);
++
++      writel(0, hrng->base + VIC_CTRL);
++}
++
++static int vic_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
++{
++      struct vic_rng *hrng = to_vic_rng(rng);
++
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE);
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_CREATE_STATE);
++
++      vic_wait_till_idle(hrng);
++      max = min_t(size_t, max, (VIC_RAND_LEN * 4));
++
++      writel(0x0, hrng->base + VIC_MODE);
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_RANDOM);
++
++      vic_wait_till_idle(hrng);
++      memcpy_fromio(buf, hrng->base + VIC_RAND0, max);
++      vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
++
++      vic_wait_till_idle(hrng);
++      return max;
++}
++
++static int vic_rng_probe(struct platform_device *pdev)
++{
++      int ret;
++      int irq;
++      struct vic_rng *rng;
++      struct resource *res;
++
++      rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
++      if (!rng){
++              return -ENOMEM;
++      }
++
++      platform_set_drvdata(pdev, rng);
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      rng->base = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(rng->base)){
++              return PTR_ERR(rng->base);
++      }
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq <= 0) {
++              dev_err(&pdev->dev, "Couldn't get irq %d\n", irq);
++              return irq;
++      }
++
++      ret = devm_request_irq(&pdev->dev, irq, vic_rng_irq, 0, pdev->name,
++                              (void *)rng);
++      if (ret) {
++              dev_err(&pdev->dev, "Can't get interrupt working.\n");
++              return ret;
++      }
++
++      rng->rng.name = pdev->name;
++      rng->rng.init = vic_rng_init;
++      rng->rng.cleanup = vic_rng_cleanup;
++      rng->rng.read = vic_rng_read;
++
++      rng->dev = &pdev->dev;
++
++      ret = devm_hwrng_register(&pdev->dev, &rng->rng);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to register hwrng\n");
++              return ret;
++      }
++
++      dev_info(&pdev->dev, "Initialized\n");
++
++      return 0;
++}
++
++static const struct of_device_id vic_rng_dt_ids[] = {
++      { .compatible = "starfive,vic-rng" },
++      { }
++};
++MODULE_DEVICE_TABLE(of, vic_rng_dt_ids);
++
++static struct platform_driver vic_rng_driver = {
++      .probe          = vic_rng_probe,
++      .driver         = {
++              .name           = "vic-rng",
++              .of_match_table = vic_rng_dt_ids,
++      },
++};
++
++module_platform_driver(vic_rng_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
++MODULE_DESCRIPTION("Starfive VIC random number generator driver");
+--- /dev/null
++++ b/drivers/char/hw_random/starfive-vic-rng.h
+@@ -0,0 +1,167 @@
++/*
++ ******************************************************************************
++ * @file  starfive-vic-rng.h
++ * @author  StarFive Technology
++ * @version  V1.0
++ * @date  08/13/2020
++ * @brief
++ ******************************************************************************
++ * @copy
++ *
++ * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
++ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
++ * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
++ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
++ * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
++ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
++ *
++ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
++ */
++
++#define VIC_CTRL              0x00
++#define VIC_MODE              0x04
++#define VIC_SMODE             0x08
++#define VIC_STAT              0x0C
++#define VIC_IE                        0x10
++#define VIC_ISTAT             0x14
++#define VIC_ALARM             0x18
++#define VIC_BUILD_ID          0x1C
++#define VIC_FEATURES          0x20
++#define VIC_RAND0             0x24
++#define VIC_NPA_DATA0         0x34
++#define VIC_SEED0             0x74
++#define VIC_IA_RDATA          0xA4
++#define VIC_IA_WDATA          0xA8
++#define VIC_IA_ADDR           0xAC
++#define VIC_IA_CMD            0xB0
++
++/* CTRL */
++#define VIC_CTRL_CMD_NOP              0
++#define VIC_CTRL_CMD_GEN_NOISE                1
++#define VIC_CTRL_CMD_GEN_NONCE                2
++#define VIC_CTRL_CMD_CREATE_STATE     3
++#define VIC_CTRL_CMD_RENEW_STATE      4
++#define VIC_CTRL_CMD_REFRESH_ADDIN    5
++#define VIC_CTRL_CMD_GEN_RANDOM               6
++#define VIC_CTRL_CMD_ADVANCE_STATE    7
++#define VIC_CTRL_CMD_KAT              8
++#define VIC_CTRL_CMD_ZEROIZE          15
++
++/* MODE */
++#define _VIC_MODE_ADDIN_PRESENT               4
++#define _VIC_MODE_PRED_RESIST         3
++#define _VIC_MODE_KAT_SEL             2
++#define _VIC_MODE_KAT_VEC             1
++#define _VIC_MODE_SEC_ALG             0
++
++#define VIC_MODE_ADDIN_PRESENT        (1UL << _VIC_MODE_ADDIN_PRESENT)
++#define VIC_MODE_PRED_RESIST  (1UL << _VIC_MODE_PRED_RESIST)
++#define VIC_MODE_KAT_SEL      (1UL << _VIC_MODE_KAT_SEL)
++#define VIC_MODE_KAT_VEC      (1UL << _VIC_MODE_KAT_VEC)
++#define VIC_MODE_SEC_ALG      (1UL << _VIC_MODE_SEC_ALG)
++
++/* SMODE */
++#define _VIC_SMODE_MAX_REJECTS        2
++#define _VIC_SMODE_SECURE_EN  1
++#define _VIC_SMODE_NONCE      0
++
++#define VIC_SMODE_MAX_REJECTS(x)      ((x) << _VIC_SMODE_MAX_REJECTS)
++#define VIC_SMODE_SECURE_EN(x)                ((x) << _VIC_SMODE_SECURE_EN)
++#define VIC_SMODE_NONCE                       (1UL << _VIC_SMODE_NONCE)
++
++/* STAT */
++#define _VIC_STAT_BUSY                31
++#define _VIC_STAT_DRBG_STATE  7
++#define _VIC_STAT_SECURE      6
++#define _VIC_STAT_NONCE_MODE  5
++#define _VIC_STAT_SEC_ALG     4
++#define _VIC_STAT_LAST_CMD    0
++
++#define VIC_STAT_BUSY         (1UL << _VIC_STAT_BUSY)
++#define VIC_STAT_DRBG_STATE   (1UL << _VIC_STAT_DRBG_STATE)
++#define VIC_STAT_SECURE               (1UL << _VIC_STAT_SECURE)
++#define VIC_STAT_NONCE_MODE   (1UL << _VIC_STAT_NONCE_MODE)
++#define VIC_STAT_SEC_ALG      (1UL << _VIC_STAT_SEC_ALG)
++#define VIC_STAT_LAST_CMD(x)  (((x) >> _VIC_STAT_LAST_CMD) & 0xF)
++
++/* IE */
++#define _VIC_IE_GLBL          31
++#define _VIC_IE_DONE          4
++#define _VIC_IE_ALARMS                3
++#define _VIC_IE_NOISE_RDY     2
++#define _VIC_IE_KAT_COMPLETE  1
++#define _VIC_IE_ZEROIZE               0
++
++#define VIC_IE_GLBL           (1UL << _VIC_IE_GLBL)
++#define VIC_IE_DONE           (1UL << _VIC_IE_DONE)
++#define VIC_IE_ALARMS         (1UL << _VIC_IE_ALARMS)
++#define VIC_IE_NOISE_RDY      (1UL << _VIC_IE_NOISE_RDY)
++#define VIC_IE_KAT_COMPLETE   (1UL << _VIC_IE_KAT_COMPLETE)
++#define VIC_IE_ZEROIZE                (1UL << _VIC_IE_ZEROIZE)
++#define VIC_IE_ALL            (VIC_IE_GLBL | VIC_IE_DONE | VIC_IE_ALARMS | \
++                               VIC_IE_NOISE_RDY | VIC_IE_KAT_COMPLETE | VIC_IE_ZEROIZE)
++
++/* ISTAT */
++#define _VIC_ISTAT_DONE               4
++#define _VIC_ISTAT_ALARMS     3
++#define _VIC_ISTAT_NOISE_RDY  2
++#define _VIC_ISTAT_KAT_COMPLETE       1
++#define _VIC_ISTAT_ZEROIZE    0
++
++#define VIC_ISTAT_DONE                (1UL << _VIC_ISTAT_DONE)
++#define VIC_ISTAT_ALARMS      (1UL << _VIC_ISTAT_ALARMS)
++#define VIC_ISTAT_NOISE_RDY   (1UL << _VIC_ISTAT_NOISE_RDY)
++#define VIC_ISTAT_KAT_COMPLETE        (1UL << _VIC_ISTAT_KAT_COMPLETE)
++#define VIC_ISTAT_ZEROIZE     (1UL << _VIC_ISTAT_ZEROIZE)
++
++/* ALARMS */
++#define VIC_ALARM_ILLEGAL_CMD_SEQ                     (1UL << 4)
++#define VIC_ALARM_FAILED_TEST_ID_OK                   0
++#define VIC_ALARM_FAILED_TEST_ID_KAT_STAT             1
++#define VIC_ALARM_FAILED_TEST_ID_KAT                  2
++#define VIC_ALARM_FAILED_TEST_ID_MONOBIT              3
++#define VIC_ALARM_FAILED_TEST_ID_RUN                  4
++#define VIC_ALARM_FAILED_TEST_ID_LONGRUN              5
++#define VIC_ALARM_FAILED_TEST_ID_AUTOCORRELATION      6
++#define VIC_ALARM_FAILED_TEST_ID_POKER                        7
++#define VIC_ALARM_FAILED_TEST_ID_REPETITION_COUNT     8
++#define VIC_ALARM_FAILED_TEST_ID_ADAPATIVE_PROPORTION 9
++
++/* BUILD_ID */
++#define VIC_BUILD_ID_STEPPING(x)              (((x) >> 28) & 0xF)
++#define VIC_BUILD_ID_EPN(x)                   ((x) & 0xFFFF)
++
++/* FEATURES */
++#define VIC_FEATURES_AES_256(x)                       (((x) >> 9) & 1)
++#define VIC_FEATURES_EXTRA_PS_PRESENT(x)      (((x) >> 8) & 1)
++#define VIC_FEATURES_DIAG_LEVEL_NS(x)         (((x) >> 7) & 1)
++#define VIC_FEATURES_DIAG_LEVEL_CLP800(x)     (((x) >> 4) & 7)
++#define VIC_FEATURES_DIAG_LEVEL_ST_HLT(x)     (((x) >> 1) & 7)
++#define VIC_FEATURES_SECURE_RST_STATE(x)      ((x) & 1)
++
++/* IA_CMD */
++#define VIC_IA_CMD_GO                 (1UL << 31)
++#define VIC_IA_CMD_WR                 (1)
++
++#define _VIC_SMODE_MAX_REJECTS_MASK   255UL
++#define _VIC_SMODE_SECURE_EN_MASK     1UL
++#define _VIC_SMODE_NONCE_MASK         1UL
++#define _VIC_MODE_SEC_ALG_MASK                1UL
++#define _VIC_MODE_ADDIN_PRESENT_MASK  1UL
++#define _VIC_MODE_PRED_RESIST_MASK    1UL
++
++#define VIC_SMODE_SET_MAX_REJECTS(y, x)       (((y) & ~(_VIC_SMODE_MAX_REJECTS_MASK << _VIC_SMODE_MAX_REJECTS)) | ((x) << _VIC_SMODE_MAX_REJECTS))
++#define VIC_SMODE_SET_SECURE_EN(y, x) (((y) & ~(_VIC_SMODE_SECURE_EN_MASK   << _VIC_SMODE_SECURE_EN))   | ((x) << _VIC_SMODE_SECURE_EN))
++#define VIC_SMODE_SET_NONCE(y, x)     (((y) & ~(_VIC_SMODE_NONCE_MASK       << _VIC_SMODE_NONCE))       | ((x) << _VIC_SMODE_NONCE))
++#define VIC_SMODE_GET_MAX_REJECTS(x)  (((x) >> _VIC_SMODE_MAX_REJECTS) & _VIC_SMODE_MAX_REJECTS_MASK)
++#define VIC_SMODE_GET_SECURE_EN(x)    (((x) >> _VIC_SMODE_SECURE_EN)   & _VIC_SMODE_SECURE_EN_MASK)
++#define VIC_SMODE_GET_NONCE(x)                (((x) >> _VIC_SMODE_NONCE)       & _VIC_SMODE_NONCE_MASK)
++
++#define VIC_MODE_SET_SEC_ALG(y, x)    (((y) & ~(_VIC_MODE_SEC_ALG_MASK       << _VIC_MODE_SEC_ALG))   | ((x) << _VIC_MODE_SEC_ALG))
++#define VIC_MODE_SET_PRED_RESIST(y, x)        (((y) & ~(_VIC_MODE_PRED_RESIST_MASK   << _VIC_MODE_PRED_RESIST))    | ((x) << _VIC_MODE_PRED_RESIST))
++#define VIC_MODE_SET_ADDIN_PRESENT(y, x) (((y) & ~(_VIC_MODE_ADDIN_PRESENT_MASK << _VIC_MODE_ADDIN_PRESENT))  | ((x) << _VIC_MODE_ADDIN_PRESENT))
++#define VIC_MODE_GET_SEC_ALG(x)               (((x) >> _VIC_MODE_SEC_ALG)       & _VIC_MODE_SEC_ALG_MASK)
++#define VIC_MODE_GET_PRED_RESIST(x)   (((x) >> _VIC_MODE_PRED_RESIST)   & _VIC_MODE_PRED_RESIST_MASK)
++#define VIC_MODE_GET_ADDIN_PRESENT(x) (((x) >> _VIC_MODE_ADDIN_PRESENT) & _VIC_MODE_ADDIN_PRESENT_MASK)
++
++#define VIC_RAND_LEN 4
diff --git a/target/linux/starfive/patches-6.12/1016-usb-cdns3-starfive-Simplify-mode-init.patch b/target/linux/starfive/patches-6.12/1016-usb-cdns3-starfive-Simplify-mode-init.patch
new file mode 100644 (file)
index 0000000..fabb8fb
--- /dev/null
@@ -0,0 +1,119 @@
+From d3bef81bd427caf4cbf7ecef64f0268a6ac8ce52 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+Date: Sat, 22 Jul 2023 15:59:02 +0200
+Subject: [PATCH 1016/1021] usb: cdns3: starfive: Simplify mode init
+
+The syscon regmap and offset to the USB mode register is only used at
+probe time, so there is no need to store it in the device data. Just get
+the regmap pointer in the cdns_mode_init() function where it is needed.
+Also this function never uses the platform device, so just pass the
+device pointer directly.
+
+Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+---
+ drivers/usb/cdns3/cdns3-starfive.c | 51 ++++++++++++------------------
+ 1 file changed, 21 insertions(+), 30 deletions(-)
+
+--- a/drivers/usb/cdns3/cdns3-starfive.c
++++ b/drivers/usb/cdns3/cdns3-starfive.c
+@@ -34,46 +34,45 @@
+ struct cdns_starfive {
+       struct device *dev;
+-      struct regmap *stg_syscon;
+       struct reset_control *resets;
+       struct clk_bulk_data *clks;
+       int num_clks;
+-      u32 stg_usb_mode;
+ };
+-static void cdns_mode_init(struct platform_device *pdev,
+-                         struct cdns_starfive *data)
++static int cdns_mode_init(struct device *dev, struct cdns_starfive *data)
+ {
++      struct regmap *syscon;
++      unsigned int usb_mode;
+       enum usb_dr_mode mode;
+-      regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
++      syscon = syscon_regmap_lookup_by_phandle_args(dev->of_node,
++                                                    "starfive,stg-syscon", 1, &usb_mode);
++      if (IS_ERR(syscon))
++              return dev_err_probe(dev, PTR_ERR(syscon),
++                                   "Failed to parse starfive,stg-syscon\n");
++
++      regmap_update_bits(syscon, usb_mode,
+                          USB_MISC_CFG_MASK,
+                          USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE);
+       /* dr mode setting */
+-      mode = usb_get_dr_mode(&pdev->dev);
++      mode = usb_get_dr_mode(dev);
+       switch (mode) {
+       case USB_DR_MODE_HOST:
+-              regmap_update_bits(data->stg_syscon,
+-                                 data->stg_usb_mode,
+-                                 USB_STRAP_MASK,
+-                                 USB_STRAP_HOST);
+-              regmap_update_bits(data->stg_syscon,
+-                                 data->stg_usb_mode,
+-                                 USB_SUSPENDM_MASK,
+-                                 USB_SUSPENDM_HOST);
++              regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_HOST);
++              regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, USB_SUSPENDM_HOST);
+               break;
+       case USB_DR_MODE_PERIPHERAL:
+-              regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
+-                                 USB_STRAP_MASK, USB_STRAP_DEVICE);
+-              regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
+-                                 USB_SUSPENDM_MASK, 0);
++              regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_DEVICE);
++              regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, 0);
+               break;
+       default:
+               break;
+       }
++
++      return 0;
+ }
+ static int cdns_clk_rst_init(struct cdns_starfive *data)
+@@ -108,7 +107,6 @@ static int cdns_starfive_probe(struct pl
+ {
+       struct device *dev = &pdev->dev;
+       struct cdns_starfive *data;
+-      unsigned int args;
+       int ret;
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+@@ -117,16 +115,6 @@ static int cdns_starfive_probe(struct pl
+       data->dev = dev;
+-      data->stg_syscon =
+-              syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node,
+-                                                   "starfive,stg-syscon", 1, &args);
+-
+-      if (IS_ERR(data->stg_syscon))
+-              return dev_err_probe(dev, PTR_ERR(data->stg_syscon),
+-                                   "Failed to parse starfive,stg-syscon\n");
+-
+-      data->stg_usb_mode = args;
+-
+       data->num_clks = devm_clk_bulk_get_all(data->dev, &data->clks);
+       if (data->num_clks < 0)
+               return dev_err_probe(data->dev, -ENODEV,
+@@ -137,7 +125,10 @@ static int cdns_starfive_probe(struct pl
+               return dev_err_probe(data->dev, PTR_ERR(data->resets),
+                                    "Failed to get resets");
+-      cdns_mode_init(pdev, data);
++      ret = cdns_mode_init(dev, data);
++      if (ret)
++              return ret;
++
+       ret = cdns_clk_rst_init(data);
+       if (ret)
+               return ret;
diff --git a/target/linux/starfive/patches-6.12/1017-usb-cdns3-starfive-Don-t-store-device-backpointer.patch b/target/linux/starfive/patches-6.12/1017-usb-cdns3-starfive-Don-t-store-device-backpointer.patch
new file mode 100644 (file)
index 0000000..e286812
--- /dev/null
@@ -0,0 +1,126 @@
+From 38b62b73015e3c843ff05400cd972683a7f3af04 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+Date: Sat, 22 Jul 2023 16:18:24 +0200
+Subject: [PATCH 1017/1021] usb: cdns3: starfive: Don't store device
+ backpointer
+
+Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+---
+ drivers/usb/cdns3/cdns3-starfive.c | 37 ++++++++++++------------------
+ 1 file changed, 15 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/cdns3/cdns3-starfive.c
++++ b/drivers/usb/cdns3/cdns3-starfive.c
+@@ -33,7 +33,6 @@
+ #define USB_REFCLK_MODE                       BIT(23)
+ struct cdns_starfive {
+-      struct device *dev;
+       struct reset_control *resets;
+       struct clk_bulk_data *clks;
+       int num_clks;
+@@ -49,7 +48,7 @@ static int cdns_mode_init(struct device
+                                                     "starfive,stg-syscon", 1, &usb_mode);
+       if (IS_ERR(syscon))
+               return dev_err_probe(dev, PTR_ERR(syscon),
+-                                   "Failed to parse starfive,stg-syscon\n");
++                                   "failed to parse starfive,stg-syscon\n");
+       regmap_update_bits(syscon, usb_mode,
+                          USB_MISC_CFG_MASK,
+@@ -75,18 +74,17 @@ static int cdns_mode_init(struct device
+       return 0;
+ }
+-static int cdns_clk_rst_init(struct cdns_starfive *data)
++static int cdns_clk_rst_init(struct device *dev, struct cdns_starfive *data)
+ {
+       int ret;
+       ret = clk_bulk_prepare_enable(data->num_clks, data->clks);
+       if (ret)
+-              return dev_err_probe(data->dev, ret,
+-                                   "failed to enable clocks\n");
++              return dev_err_probe(dev, ret, "failed to enable clocks\n");
+       ret = reset_control_deassert(data->resets);
+       if (ret) {
+-              dev_err(data->dev, "failed to reset clocks\n");
++              dev_err(dev, "failed to reset clocks\n");
+               goto err_clk_init;
+       }
+@@ -97,7 +95,7 @@ err_clk_init:
+       return ret;
+ }
+-static void cdns_clk_rst_deinit(struct cdns_starfive *data)
++static void cdns_clk_rst_deinit(struct device *dev, struct cdns_starfive *data)
+ {
+       reset_control_assert(data->resets);
+       clk_bulk_disable_unprepare(data->num_clks, data->clks);
+@@ -113,31 +111,26 @@ static int cdns_starfive_probe(struct pl
+       if (!data)
+               return -ENOMEM;
+-      data->dev = dev;
+-
+-      data->num_clks = devm_clk_bulk_get_all(data->dev, &data->clks);
++      data->num_clks = devm_clk_bulk_get_all(dev, &data->clks);
+       if (data->num_clks < 0)
+-              return dev_err_probe(data->dev, -ENODEV,
+-                                   "Failed to get clocks\n");
++              return dev_err_probe(dev, -ENODEV, "failed to get clocks\n");
+-      data->resets = devm_reset_control_array_get_exclusive(data->dev);
++      data->resets = devm_reset_control_array_get_exclusive(dev);
+       if (IS_ERR(data->resets))
+-              return dev_err_probe(data->dev, PTR_ERR(data->resets),
+-                                   "Failed to get resets");
++              return dev_err_probe(dev, PTR_ERR(data->resets), "failed to get resets\n");
+       ret = cdns_mode_init(dev, data);
+       if (ret)
+               return ret;
+-      ret = cdns_clk_rst_init(data);
++      ret = cdns_clk_rst_init(dev, data);
+       if (ret)
+               return ret;
+       ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+       if (ret) {
+-              dev_err(dev, "Failed to create children\n");
+-              cdns_clk_rst_deinit(data);
+-              return ret;
++              cdns_clk_rst_deinit(dev, data);
++              return dev_err_probe(dev, ret, "failed to create children\n");
+       }
+       device_set_wakeup_capable(dev, true);
+@@ -167,7 +160,7 @@ static void cdns_starfive_remove(struct
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
+-      cdns_clk_rst_deinit(data);
++      cdns_clk_rst_deinit(dev, data);
+       platform_set_drvdata(pdev, NULL);
+ }
+@@ -193,14 +186,14 @@ static int cdns_starfive_resume(struct d
+ {
+       struct cdns_starfive *data = dev_get_drvdata(dev);
+-      return cdns_clk_rst_init(data);
++      return cdns_clk_rst_init(dev, data);
+ }
+ static int cdns_starfive_suspend(struct device *dev)
+ {
+       struct cdns_starfive *data = dev_get_drvdata(dev);
+-      cdns_clk_rst_deinit(data);
++      cdns_clk_rst_deinit(dev, data);
+       return 0;
+ }
diff --git a/target/linux/starfive/patches-6.12/1018-usb-cdns3-starfive-Add-StarFive-JH7100-support.patch b/target/linux/starfive/patches-6.12/1018-usb-cdns3-starfive-Add-StarFive-JH7100-support.patch
new file mode 100644 (file)
index 0000000..496a0de
--- /dev/null
@@ -0,0 +1,113 @@
+From eae127ccbe02ba20e4eb86081268205f7f40b8fc Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+Date: Sat, 22 Jul 2023 16:21:04 +0200
+Subject: [PATCH 1018/1021] usb: cdns3: starfive: Add StarFive JH7100 support
+
+Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+---
+ drivers/usb/cdns3/cdns3-starfive.c | 46 ++++++++++++++++++------------
+ 1 file changed, 28 insertions(+), 18 deletions(-)
+
+--- a/drivers/usb/cdns3/cdns3-starfive.c
++++ b/drivers/usb/cdns3/cdns3-starfive.c
+@@ -20,17 +20,17 @@
+ #include <linux/usb/otg.h>
+ #include "core.h"
+-#define USB_STRAP_HOST                        BIT(17)
+-#define USB_STRAP_DEVICE              BIT(18)
+-#define USB_STRAP_MASK                        GENMASK(18, 16)
+-
+-#define USB_SUSPENDM_HOST             BIT(19)
+-#define USB_SUSPENDM_MASK             BIT(19)
+-
+-#define USB_MISC_CFG_MASK             GENMASK(23, 20)
+-#define USB_SUSPENDM_BYPS             BIT(20)
+-#define USB_PLL_EN                    BIT(22)
+-#define USB_REFCLK_MODE                       BIT(23)
++#define JH7110_STRAP_HOST             BIT(17)
++#define JH7110_STRAP_DEVICE           BIT(18)
++#define JH7110_STRAP_MASK             GENMASK(18, 16)
++
++#define JH7110_SUSPENDM_HOST          BIT(19)
++#define JH7110_SUSPENDM_MASK          BIT(19)
++
++#define JH7110_MISC_CFG_MASK          GENMASK(23, 20)
++#define JH7110_SUSPENDM_BYPS          BIT(20)
++#define JH7110_PLL_EN                 BIT(22)
++#define JH7110_REFCLK_MODE            BIT(23)
+ struct cdns_starfive {
+       struct reset_control *resets;
+@@ -38,7 +38,14 @@ struct cdns_starfive {
+       int num_clks;
+ };
+-static int cdns_mode_init(struct device *dev, struct cdns_starfive *data)
++typedef int (cdns_starfive_mode_init_t)(struct device *dev, struct cdns_starfive *data);
++
++static int cdns_jh7100_mode_init(struct device *dev, struct cdns_starfive *data)
++{
++      return 0;
++}
++
++static int cdns_jh7110_mode_init(struct device *dev, struct cdns_starfive *data)
+ {
+       struct regmap *syscon;
+       unsigned int usb_mode;
+@@ -51,21 +58,21 @@ static int cdns_mode_init(struct device
+                                    "failed to parse starfive,stg-syscon\n");
+       regmap_update_bits(syscon, usb_mode,
+-                         USB_MISC_CFG_MASK,
+-                         USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE);
++                         JH7110_MISC_CFG_MASK,
++                         JH7110_SUSPENDM_BYPS | JH7110_PLL_EN | JH7110_REFCLK_MODE);
+       /* dr mode setting */
+       mode = usb_get_dr_mode(dev);
+       switch (mode) {
+       case USB_DR_MODE_HOST:
+-              regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_HOST);
+-              regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, USB_SUSPENDM_HOST);
++              regmap_update_bits(syscon, usb_mode, JH7110_STRAP_MASK, JH7110_STRAP_HOST);
++              regmap_update_bits(syscon, usb_mode, JH7110_SUSPENDM_MASK, JH7110_SUSPENDM_HOST);
+               break;
+       case USB_DR_MODE_PERIPHERAL:
+-              regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_DEVICE);
+-              regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, 0);
++              regmap_update_bits(syscon, usb_mode, JH7110_STRAP_MASK, JH7110_STRAP_DEVICE);
++              regmap_update_bits(syscon, usb_mode, JH7110_SUSPENDM_MASK, 0);
+               break;
+       default:
+               break;
+@@ -105,6 +112,7 @@ static int cdns_starfive_probe(struct pl
+ {
+       struct device *dev = &pdev->dev;
+       struct cdns_starfive *data;
++      cdns_starfive_mode_init_t *mode_init;
+       int ret;
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+@@ -119,7 +127,8 @@ static int cdns_starfive_probe(struct pl
+       if (IS_ERR(data->resets))
+               return dev_err_probe(dev, PTR_ERR(data->resets), "failed to get resets\n");
+-      ret = cdns_mode_init(dev, data);
++      mode_init = device_get_match_data(dev);
++      ret = mode_init(dev, data);
+       if (ret)
+               return ret;
+@@ -207,7 +216,8 @@ static const struct dev_pm_ops cdns_star
+ };
+ static const struct of_device_id cdns_starfive_of_match[] = {
+-      { .compatible = "starfive,jh7110-usb", },
++      { .compatible = "starfive,jh7100-usb", .data = cdns_jh7100_mode_init },
++      { .compatible = "starfive,jh7110-usb", .data = cdns_jh7110_mode_init },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, cdns_starfive_of_match);
diff --git a/target/linux/starfive/patches-6.12/1019-riscv-dts-starfive-Add-JH7100-USB-node.patch b/target/linux/starfive/patches-6.12/1019-riscv-dts-starfive-Add-JH7100-USB-node.patch
new file mode 100644 (file)
index 0000000..15e88bb
--- /dev/null
@@ -0,0 +1,60 @@
+From e73da6a4dc3f127d45e26d68ee051199c1fc2bb9 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+Date: Sat, 22 Jul 2023 16:36:17 +0200
+Subject: [PATCH 1019/1021] riscv: dts: starfive: Add JH7100 USB node
+
+Add the device tree node for the USB 3.0 peripheral on the
+StarFive JH7100 SoC.
+
+Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+---
+ .../boot/dts/starfive/jh7100-common.dtsi      |  5 ++++
+ arch/riscv/boot/dts/starfive/jh7100.dtsi      | 26 +++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
+@@ -447,3 +447,8 @@
+       pinctrl-0 = <&uart3_pins>;
+       status = "okay";
+ };
++
++&usb3 {
++      dr_mode = "host";
++      status = "okay";
++};
+--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
+@@ -255,6 +255,32 @@
+                       #reset-cells = <1>;
+               };
++              usb3: usb@104c0000 {
++                      compatible = "starfive,jh7100-usb";
++                      ranges = <0x0 0x0 0x104c0000 0x100000>;
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++                      clocks = <&audclk JH7100_AUDCLK_USB_LPM>,
++                               <&audclk JH7100_AUDCLK_USB_STB>,
++                               <&clkgen JH7100_CLK_USB_AXI>,
++                               <&clkgen JH7100_CLK_USBNOC_AXI>;
++                      clock-names = "lpm", "stb", "axi", "nocaxi";
++                      resets = <&rstgen JH7100_RSTN_USB_AXI>,
++                               <&rstgen JH7100_RSTN_USBNOC_AXI>;
++                      reset-names = "axi", "nocaxi";
++                      status = "disabled";
++
++                      usb_cdns3: usb@0 {
++                              compatible = "cdns,usb3";
++                              reg = <0x00000 0x10000>,
++                                    <0x10000 0x10000>,
++                                    <0x20000 0x10000>;
++                              reg-names = "otg", "xhci", "dev";
++                              interrupts = <44>, <52>, <43>;
++                              interrupt-names = "host", "peripheral", "otg";
++                      };
++              };
++
+               clkgen: clock-controller@11800000 {
+                       compatible = "starfive,jh7100-clkgen";
+                       reg = <0x0 0x11800000 0x0 0x10000>;
diff --git a/target/linux/starfive/patches-6.12/1020-usb-cdns3-starfive-Initialize-JH7100-host-mode.patch b/target/linux/starfive/patches-6.12/1020-usb-cdns3-starfive-Initialize-JH7100-host-mode.patch
new file mode 100644 (file)
index 0000000..03afdf2
--- /dev/null
@@ -0,0 +1,103 @@
+From 8deff65d2d7ffea00231ec592d956aebf7de0852 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+Date: Sat, 22 Jul 2023 18:50:49 +0200
+Subject: [PATCH 1020/1021] usb: cdns3: starfive: Initialize JH7100 host mode
+
+These settings are directly copied from StarFive's port of u-boot
+for the JH7100:
+
+  /* config strap */
+  _SET_SYSCON_REG_SCFG_usb0_mode_strap(0x2);
+  _SET_SYSCON_REG_SCFG_usb7_PLL_EN(0x1);
+  _SET_SYSCON_REG_SCFG_usb7_U3_EQ_EN(0x1);
+  _SET_SYSCON_REG_SCFG_usb7_U3_SSRX_SEL(0x1);
+  _SET_SYSCON_REG_SCFG_usb7_U3_SSTX_SEL(0x1);
+  _SET_SYSCON_REG_SCFG_usb3_utmi_iddig(0x1);
+
+Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+---
+ arch/riscv/boot/dts/starfive/jh7100.dtsi |  6 ++++
+ drivers/usb/cdns3/cdns3-starfive.c       | 43 ++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
+@@ -255,6 +255,11 @@
+                       #reset-cells = <1>;
+               };
++              sysaudio: syscon@104a0000 {
++                      compatible = "starfive,jh7100-sysaudio", "syscon";
++                      reg = <0x0 0x104a0000 0x0 0x10000>;
++              };
++
+               usb3: usb@104c0000 {
+                       compatible = "starfive,jh7100-usb";
+                       ranges = <0x0 0x0 0x104c0000 0x100000>;
+@@ -268,6 +273,7 @@
+                       resets = <&rstgen JH7100_RSTN_USB_AXI>,
+                                <&rstgen JH7100_RSTN_USBNOC_AXI>;
+                       reset-names = "axi", "nocaxi";
++                      starfive,syscon = <&sysaudio>;
+                       status = "disabled";
+                       usb_cdns3: usb@0 {
+--- a/drivers/usb/cdns3/cdns3-starfive.c
++++ b/drivers/usb/cdns3/cdns3-starfive.c
+@@ -20,6 +20,19 @@
+ #include <linux/usb/otg.h>
+ #include "core.h"
++#define JH7100_USB0                   0x20
++#define JH7100_USB0_MODE_STRAP_MASK   GENMASK(2, 0)
++#define JH7100_USB0_MODE_STRAP_HOST   2
++
++#define JH7100_USB3                   0x2c
++#define JH7100_USB3_UTMI_IDDIG                BIT(21)
++
++#define JH7100_USB7                   0x3c
++#define JH7100_USB7_SSRX_SEL          BIT(18)
++#define JH7100_USB7_SSTX_SEL          BIT(19)
++#define JH7100_USB7_PLL_EN            BIT(23)
++#define JH7100_USB7_EQ_EN             BIT(25)
++
+ #define JH7110_STRAP_HOST             BIT(17)
+ #define JH7110_STRAP_DEVICE           BIT(18)
+ #define JH7110_STRAP_MASK             GENMASK(18, 16)
+@@ -42,6 +55,36 @@ typedef int (cdns_starfive_mode_init_t)(
+ static int cdns_jh7100_mode_init(struct device *dev, struct cdns_starfive *data)
+ {
++      struct regmap *syscon;
++      enum usb_dr_mode mode;
++
++      syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "starfive,syscon");
++      if (IS_ERR(syscon))
++              return dev_err_probe(dev, PTR_ERR(syscon),
++                                   "failed to get starfive,syscon\n");
++
++      /* dr mode setting */
++      mode = usb_get_dr_mode(dev);
++
++      switch (mode) {
++      case USB_DR_MODE_HOST:
++              regmap_update_bits(syscon, JH7100_USB0,
++                                 JH7100_USB0_MODE_STRAP_MASK, JH7100_USB0_MODE_STRAP_HOST);
++              regmap_update_bits(syscon, JH7100_USB7,
++                                 JH7100_USB7_PLL_EN, JH7100_USB7_PLL_EN);
++              regmap_update_bits(syscon, JH7100_USB7,
++                                 JH7100_USB7_EQ_EN, JH7100_USB7_EQ_EN);
++              regmap_update_bits(syscon, JH7100_USB7,
++                                 JH7100_USB7_SSRX_SEL, JH7100_USB7_SSRX_SEL);
++              regmap_update_bits(syscon, JH7100_USB7,
++                                 JH7100_USB7_SSTX_SEL, JH7100_USB7_SSTX_SEL);
++              regmap_update_bits(syscon, JH7100_USB3,
++                                 JH7100_USB3_UTMI_IDDIG, JH7100_USB3_UTMI_IDDIG);
++              break;
++      default:
++              break;
++      }
++
+       return 0;
+ }
diff --git a/target/linux/starfive/patches-6.12/1021-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch b/target/linux/starfive/patches-6.12/1021-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch
new file mode 100644 (file)
index 0000000..211dc75
--- /dev/null
@@ -0,0 +1,848 @@
+From a861bf8cf26216da57b4886ecf48222e01e4fba9 Mon Sep 17 00:00:00 2001
+From: Emil Renner Berthing <kernel@esmil.dk>
+Date: Sun, 31 Oct 2021 17:15:58 +0100
+Subject: [PATCH 1021/1021] riscv: dts: Add full JH7100, Starlight and
+ VisionFive support
+
+Based on the device tree in https://github.com/starfive-tech/u-boot/
+with contributions from:
+yanhong.wang <yanhong.wang@starfivetech.com>
+Huan.Feng <huan.feng@starfivetech.com>
+ke.zhu <ke.zhu@starfivetech.com>
+yiming.li <yiming.li@starfivetech.com>
+jack.zhu <jack.zhu@starfivetech.com>
+Samin Guo <samin.guo@starfivetech.com>
+Chenjieqin <Jessica.Chen@starfivetech.com>
+bo.li <bo.li@starfivetech.com>
+
+Rearranged, cleanups, fixes, pins and resets added by Emil.
+Cleanups, fixes, clocks added by Geert.
+Cleanups and GPIO fixes from Drew.
+Thermal zone added by Stephen.
+PWM pins added by Jianlong.
+cpu-map added by Jonas.
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Signed-off-by: Stephen L Arnold <nerdboy@gentoo.org>
+Signed-off-by: Drew Fustini <drew@beagleboard.org>
+Signed-off-by: Jianlong Huang <jianlong.huang@starfivetech.com>
+Signed-off-by: Jonas Hahnfeld <hahnjo@hahnjo.de>
+Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
+---
+ arch/riscv/boot/dts/starfive/Makefile         |   2 +
+ .../starfive/jh7100-beaglev-starlight-a1.dts  |  24 ++
+ .../dts/starfive/jh7100-beaglev-starlight.dts |   6 +
+ .../boot/dts/starfive/jh7100-common.dtsi      | 177 ++++++++
+ .../jh7100-starfive-visionfive-v1.dts         |  13 +
+ arch/riscv/boot/dts/starfive/jh7100.dtsi      | 389 ++++++++++++++++++
+ 6 files changed, 611 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts
+
+--- a/arch/riscv/boot/dts/starfive/Makefile
++++ b/arch/riscv/boot/dts/starfive/Makefile
+@@ -1,10 +1,12 @@
+ # SPDX-License-Identifier: GPL-2.0
+ # Enables support for device-tree overlays
++DTC_FLAGS_jh7100-beaglev-starlight-a1 := -@
+ DTC_FLAGS_jh7100-beaglev-starlight := -@
+ DTC_FLAGS_jh7100-starfive-visionfive-v1 := -@
+ DTC_FLAGS_jh7110-starfive-visionfive-2-v1.2a := -@
+ DTC_FLAGS_jh7110-starfive-visionfive-2-v1.3b := -@
++dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight-a1.dtb
+ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb
+ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb
+--- /dev/null
++++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts
+@@ -0,0 +1,24 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
++ */
++
++/dts-v1/;
++#include "jh7100-common.dtsi"
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++      model = "BeagleV Starlight Beta A1";
++      compatible = "beagle,beaglev-starlight-jh7100-a1", "starfive,jh7100";
++
++      gpio-restart {
++              compatible = "gpio-restart";
++              gpios = <&gpio 63 GPIO_ACTIVE_HIGH>;
++              priority = <224>;
++      };
++};
++
++&gpio {
++      /* don't reset gpio mux for serial console and reset gpio */
++      starfive,keep-gpiomux = <13 14 63>;
++};
+--- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
++++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
+@@ -6,6 +6,7 @@
+ /dts-v1/;
+ #include "jh7100-common.dtsi"
++#include <dt-bindings/gpio/gpio.h>
+ / {
+       model = "BeagleV Starlight Beta";
+@@ -16,6 +17,11 @@
+       phy-handle = <&phy>;
+ };
++&gpio {
++      /* don't reset gpio mux for serial console on uart3 */
++      starfive,keep-gpiomux = <13 14>;
++};
++
+ &mdio {
+       phy: ethernet-phy@7 {
+               reg = <7>;
+--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
+@@ -15,6 +15,7 @@
+               mmc0 = &sdio0;
+               mmc1 = &sdio1;
+               serial0 = &uart3;
++              serial1 = &uart0;
+       };
+       chosen {
+@@ -47,11 +48,41 @@
+               #size-cells = <2>;
+               ranges;
++              linux,cma {
++                      compatible = "shared-dma-pool";
++                      alloc-ranges = <0x0 0xa0000000 0x0 0x28000000>;
++                      size = <0x0 0x28000000>;
++                      alignment = <0x0 0x1000>;
++                      reusable;
++                      linux,cma-default;
++              };
++
++              jpu_reserved: framebuffer@c9000000 {
++                      reg = <0x0 0xc9000000 0x0 0x4000000>;
++              };
++
++              nvdla_reserved: framebuffer@d0000000 {
++                      reg = <0x0 0xd0000000 0x0 0x28000000>;
++                      no-map;
++              };
++
++              vin_reserved: framebuffer@f9000000 {
++                      compatible = "shared-dma-pool";
++                      reg = <0x0 0xf9000000 0x0 0x1000000>;
++                      no-map;
++              };
++
+               dma-reserved@fa000000 {
+                       reg = <0x0 0xfa000000 0x0 0x1000000>;
+                       no-map;
+               };
++              sffb_reserved: framebuffer@fb000000 {
++                      compatible = "shared-dma-pool";
++                      reg = <0x0 0xfb000000 0x0 0x2000000>;
++                      no-map;
++              };
++
+               linux,dma@107a000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x10 0x7a000000 0x0 0x1000000>;
+@@ -72,6 +103,44 @@
+       };
+ };
++&display {
++      memory-region = <&sffb_reserved>;
++      status = "okay";
++};
++
++&crtc {
++      ddr-format = <4>; //<WIN_FMT_RGB565>;
++      status = "okay";
++
++      port: port@0 {
++              reg = <0>;
++
++              crtc_0_out: endpoint {
++                      remote-endpoint = <&hdmi_input0>;
++              };
++      };
++};
++
++&encoder {
++      encoder-type = <2>; // 2-TMDS, 3-LVDS, 6-DSI, 8-DPI
++      status = "okay";
++
++      ports {
++              port@0 {
++                      hdmi_out: endpoint {
++                              remote-endpoint = <&tda998x_0_input>;
++                      };
++              };
++
++              port@1 {
++                      hdmi_input0: endpoint {
++                              remote-endpoint = <&crtc_0_out>;
++                      };
++              };
++
++      };
++};
++
+ &gmac {
+       pinctrl-names = "default";
+       pinctrl-0 = <&gmac_pins>;
+@@ -199,6 +268,20 @@
+               };
+       };
++      pwmdac_pins: pwmdac-0 {
++              pwmdac-pins {
++                      pinmux = <GPIOMUX(23, GPO_PWMDAC_LEFT_OUT,
++                                GPO_ENABLE, GPI_NONE)>,
++                               <GPIOMUX(24, GPO_PWMDAC_RIGHT_OUT,
++                                GPO_ENABLE, GPI_NONE)>;
++                      bias-disable;
++                      drive-strength = <35>;
++                      input-disable;
++                      input-schmitt-disable;
++                      slew-rate = <0>;
++              };
++      };
++
+       pwm_pins: pwm-0 {
+               pwm-pins {
+                       pinmux = <GPIOMUX(7,
+@@ -289,6 +372,39 @@
+               };
+       };
++      spi2_pins: spi2-0 {
++              mosi-pins {
++                      pinmux = <GPIOMUX(18, GPO_SPI2_PAD_TXD,
++                                GPO_ENABLE, GPI_NONE)>;
++                      bias-disable;
++                      input-disable;
++                      input-schmitt-disable;
++              };
++              miso-pins {
++                      pinmux = <GPIOMUX(16, GPO_LOW, GPO_DISABLE,
++                                GPI_SPI2_PAD_RXD)>;
++                      bias-pull-up;
++                      input-enable;
++                      input-schmitt-enable;
++              };
++              sck-pins {
++                      pinmux = <GPIOMUX(12, GPO_SPI2_PAD_SCK_OUT,
++                                GPO_ENABLE, GPI_NONE)>;
++                      bias-disable;
++                      input-disable;
++                      input-schmitt-disable;
++              };
++              ss-pins {
++                      pinmux = <GPIOMUX(15, GPO_SPI2_PAD_SS_0_N,
++                                GPO_ENABLE, GPI_NONE)>,
++                               <GPIOMUX(11, GPO_SPI2_PAD_SS_1_N,
++                                GPO_ENABLE, GPI_NONE)>;
++                      bias-disable;
++                      input-disable;
++                      input-schmitt-disable;
++              };
++      };
++
+       uart0_pins: uart0-0 {
+               rx-pins {
+                       pinmux = <GPIOMUX(40, GPO_LOW, GPO_DISABLE,
+@@ -364,6 +480,17 @@
+               regulators {
+               };
+       };
++
++      tda998x@70 {
++              compatible = "nxp,tda998x";
++              reg = <0x70>;
++
++              port {
++                      tda998x_0_input: endpoint {
++                              remote-endpoint = <&hdmi_out>;
++                      };
++              };
++      };
+ };
+ &i2c1 {
+@@ -400,6 +527,44 @@
+       status = "okay";
+ };
++&pwmdac {
++      pinctrl-names = "default";
++      pinctrl-0 = <&pwmdac_pins>;
++      status = "okay";
++};
++
++&qspi {
++      nor_flash: nor-flash@0 {
++              compatible = "spi-flash";
++              reg = <0>;
++              spi-max-frequency = <31250000>;
++              page-size = <256>;
++              block-size = <16>;
++              cdns,read-delay = <4>;
++              cdns,tshsl-ns = <1>;
++              cdns,tsd2d-ns = <1>;
++              cdns,tchsh-ns = <1>;
++              cdns,tslch-ns = <1>;
++              spi-tx-bus-width = <1>;
++              spi-rx-bus-width = <1>;
++      };
++
++      nand_flash: nand-flash@1 {
++              compatible = "spi-flash-nand";
++              reg = <1>;
++              spi-max-frequency = <31250000>;
++              page-size = <2048>;
++              block-size = <17>;
++              cdns,read-delay = <4>;
++              cdns,tshsl-ns = <1>;
++              cdns,tsd2d-ns = <1>;
++              cdns,tchsh-ns = <1>;
++              cdns,tslch-ns = <1>;
++              spi-tx-bus-width = <1>;
++              spi-rx-bus-width = <1>;
++      };
++};
++
+ &sdio0 {
+       broken-cd;
+       bus-width = <4>;
+@@ -428,6 +593,18 @@
+       };
+ };
++&spi2 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&spi2_pins>;
++      status = "okay";
++
++      spi_dev0: spi@0 {
++              compatible = "rohm,dh2228fv";
++              spi-max-frequency = <10000000>;
++              reg = <0>;
++      };
++};
++
+ &uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pins>;
+--- a/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
++++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
+@@ -22,6 +22,19 @@
+       phy-handle = <&phy>;
+ };
++&gpio {
++      /* don't reset gpio mux for serial console and reset gpio */
++      starfive,keep-gpiomux = <13 14 63>;
++};
++
++&i2c0 {
++      eeprom@50 {
++              compatible = "atmel,24c04";
++              reg = <0x50>;
++              pagesize = <16>;
++      };
++};
++
+ /*
+  * The board uses a Motorcomm YT8521 PHY supporting RGMII-ID, but requires
+  * manual adjustment of the RX internal delay to work properly.  The default
+--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
+@@ -6,7 +6,9 @@
+ /dts-v1/;
+ #include <dt-bindings/clock/starfive-jh7100.h>
++#include <dt-bindings/clock/starfive-jh7100-audio.h>
+ #include <dt-bindings/reset/starfive-jh7100.h>
++#include <dt-bindings/reset/starfive-jh7100-audio.h>
+ / {
+       compatible = "starfive,jh7100";
+@@ -37,6 +39,7 @@
+                       riscv,isa-base = "rv64i";
+                       riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr",
+                                              "zifencei", "zihpm";
++                      starfive,itim = <&itim0>;
+                       tlb-split;
+                       cpu0_intc: interrupt-controller {
+@@ -66,6 +69,7 @@
+                       riscv,isa-base = "rv64i";
+                       riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr",
+                                              "zifencei", "zihpm";
++                      starfive,itim = <&itim1>;
+                       tlb-split;
+                       cpu1_intc: interrupt-controller {
+@@ -153,6 +157,24 @@
+               dma-noncoherent;
+               ranges;
++              dtim: dtim@1000000 {
++                      compatible = "starfive,dtim0";
++                      reg = <0x0 0x1000000 0x0 0x2000>;
++                      reg-names = "mem";
++              };
++
++              itim0: itim@1808000 {
++                      compatible = "starfive,itim0";
++                      reg = <0x0 0x1808000 0x0 0x8000>;
++                      reg-names = "mem";
++              };
++
++              itim1: itim@1820000 {
++                      compatible = "starfive,itim0";
++                      reg = <0x0 0x1820000 0x0 0x8000>;
++                      reg-names = "mem";
++              };
++
+               clint: clint@2000000 {
+                       compatible = "starfive,jh7100-clint", "sifive,clint0";
+                       reg = <0x0 0x2000000 0x0 0x10000>;
+@@ -239,6 +261,124 @@
+                       };
+               };
++              dma2p: dma-controller@100b0000 {
++                      compatible = "starfive,jh7100-axi-dma";
++                      reg = <0x0 0x100b0000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_SGDMA2P_AXI>,
++                               <&clkgen JH7100_CLK_SGDMA2P_AHB>;
++                      clock-names = "core-clk", "cfgr-clk";
++                      resets = <&rstgen JH7100_RSTN_SGDMA2P_AXI>,
++                               <&rstgen JH7100_RSTN_SGDMA2P_AHB>;
++                      reset-names = "axi", "ahb";
++                      interrupts = <2>;
++                      #dma-cells = <1>;
++                      dma-channels = <4>;
++                      snps,dma-masters = <1>;
++                      snps,data-width = <4>;
++                      snps,block-size = <4096 4096 4096 4096>;
++                      snps,priority = <0 1 2 3>;
++                      snps,axi-max-burst-len = <128>;
++                      dma-coherent;
++              };
++
++              crypto: crypto@100d0000 {
++                      compatible = "starfive,vic-sec";
++                      reg = <0x0 0x100d0000 0x0 0x20000>,
++                            <0x0 0x11800234 0x0 0xc>;
++                      reg-names = "secmem", "secclk";
++                      clocks = <&clkgen JH7100_CLK_SEC_AHB>;
++                      interrupts = <31>;
++              };
++
++              i2sadc0: i2sadc0@10400000 {
++                      compatible = "snps,designware-i2sadc0";
++                      reg = <0x0 0x10400000 0x0 0x1000>;
++                      clocks = <&clkgen JH7100_CLK_APB1_BUS>;
++                      clock-names = "i2sclk";
++                      interrupt-parent = <&plic>;
++                      #sound-dai-cells = <0>;
++                      dmas = <&dma2p 28>;
++                      dma-names = "rx";
++              };
++
++              i2svad: i2svad@10420000 {
++                      compatible = "starfive,sf-i2svad";
++                      reg = <0x0 0x10420000 0x0 0x1000> ;
++                      clocks = <&audclk JH7100_AUDCLK_I2SVAD_APB>;
++                      clock-names = "i2svad_apb";
++                      resets = <&audrst JH7100_AUDRSTN_I2SVAD_APB>,
++                               <&audrst JH7100_AUDRSTN_I2SVAD_SRST>;
++                      reset-names = "apb_i2svad", "i2svad_srst";
++                      interrupts = <60>, <61>;
++                      interrupt-names = "spintr", "slintr";
++                      #sound-dai-cells = <0>;
++              };
++
++              pwmdac: pwmdac@10440000 {
++                      compatible = "starfive,pwmdac";
++                      reg = <0x0 0x10440000 0x0 0x1000>;
++                      clocks = <&clkgen JH7100_CLK_AUDIO_ROOT>,
++                               <&clkgen JH7100_CLK_AUDIO_SRC>,
++                               <&clkgen JH7100_CLK_AUDIO_12288>,
++                               <&audclk JH7100_AUDCLK_DMA1P_AHB>,
++                               <&audclk JH7100_AUDCLK_PWMDAC_APB>,
++                               <&audclk JH7100_AUDCLK_DAC_MCLK>;
++                      clock-names = "audio_root",
++                                    "audio_src",
++                                    "audio_12288",
++                                    "dma1p_ahb",
++                                    "pwmdac_apb",
++                                    "dac_mclk";
++                      resets = <&audrst JH7100_AUDRSTN_APB_BUS>,
++                               <&audrst JH7100_AUDRSTN_DMA1P_AHB>,
++                               <&audrst JH7100_AUDRSTN_PWMDAC_APB>;
++                      reset-names = "apb_bus", "dma1p_ahb", "apb_pwmdac";
++                      dmas = <&dma2p 23>;
++                      dma-names = "tx";
++                      #sound-dai-cells = <0>;
++              };
++
++              i2sdac0: i2sdac0@10450000 {
++                      compatible = "snps,designware-i2sdac0";
++                      reg = <0x0 0x10450000 0x0 0x1000>;
++                      clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
++                               <&audclk JH7100_AUDCLK_I2SDAC_BCLK>,
++                               <&audclk JH7100_AUDCLK_I2SDAC_LRCLK>,
++                               <&audclk JH7100_AUDCLK_I2SDAC_APB>;
++                      clock-names = "dac_mclk", "i2sdac0_bclk", "i2sdac0_lrclk", "i2sdac_apb";
++                      resets = <&audrst JH7100_AUDRSTN_I2SDAC_APB>,
++                               <&audrst JH7100_AUDRSTN_I2SDAC_SRST>;
++                      reset-names = "apb_i2sdac", "i2sdac_srst";
++                      #sound-dai-cells = <0>;
++                      dmas = <&dma2p 30>;
++                      dma-names = "tx";
++              };
++
++              i2sdac1: i2sdac1@10460000 {
++                      compatible = "snps,designware-i2sdac1";
++                      reg = <0x0 0x10460000 0x0 0x1000>;
++                      clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
++                               <&audclk JH7100_AUDCLK_I2S1_BCLK>,
++                               <&audclk JH7100_AUDCLK_I2S1_LRCLK>,
++                               <&audclk JH7100_AUDCLK_I2S1_APB>;
++                      clock-names = "dac_mclk", "i2sdac1_bclk", "i2sdac1_lrclk", "i2s1_apb";
++                      resets = <&audrst JH7100_AUDRSTN_I2S1_APB>,
++                               <&audrst JH7100_AUDRSTN_I2S1_SRST>;
++                      #sound-dai-cells = <0>;
++                      dmas = <&dma2p 31>;
++                      dma-names = "tx";
++              };
++
++              i2sdac16k: i2sdac16k@10470000 {
++                      compatible = "snps,designware-i2sdac16k";
++                      reg = <0x0 0x10470000 0x0 0x1000>;
++                      clocks = <&clkgen JH7100_CLK_APB1_BUS>;
++                      clock-names = "i2sclk";
++                      #sound-dai-cells = <0>;
++                      dmas = <&dma2p 29>;
++                      dma-names = "tx";
++              };
++
+               audclk: clock-controller@10480000 {
+                       compatible = "starfive,jh7100-audclk";
+                       reg = <0x0 0x10480000 0x0 0x10000>;
+@@ -255,6 +395,50 @@
+                       #reset-cells = <1>;
+               };
++              spdif_transmitter: spdif-transmitter {
++                      compatible = "linux,spdif-dit";
++                      #sound-dai-cells = <0>;
++              };
++
++              spdif_receiver: spdif-receiver {
++                      compatible = "linux,spdif-dir";
++                      #sound-dai-cells = <0>;
++              };
++
++              pwmdac_codec: pwmdac-transmitter {
++                      compatible = "linux,pwmdac-dit";
++                      #sound-dai-cells = <0>;
++              };
++
++              dmic_codec: dmic {
++                      compatible = "dmic-codec";
++                      #sound-dai-cells = <0>;
++              };
++
++              sound: snd-card {
++                      compatible = "simple-audio-card";
++                      simple-audio-card,name = "Starfive-Multi-Sound-Card";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* pwmdac */
++                      simple-audio-card,dai-link@0 {
++                              reg = <0>;
++                              status = "okay";
++                              format = "left_j";
++                              bitclock-master = <&sndcpu0>;
++                              frame-master = <&sndcpu0>;
++
++                              sndcpu0: cpu {
++                                      sound-dai = <&pwmdac>;
++                              };
++
++                              codec {
++                                      sound-dai = <&pwmdac_codec>;
++                              };
++                      };
++              };
++
+               sysaudio: syscon@104a0000 {
+                       compatible = "starfive,jh7100-sysaudio", "syscon";
+                       reg = <0x0 0x104a0000 0x0 0x10000>;
+@@ -287,6 +471,25 @@
+                       };
+               };
++              dma1p: dma-controller@10500000 {
++                      compatible = "starfive,jh7100-axi-dma";
++                      reg = <0x0 0x10500000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_SGDMA1P_AXI>,
++                               <&clkgen JH7100_CLK_SGDMA1P_BUS>;
++                      clock-names = "core-clk", "cfgr-clk";
++                      resets = <&rstgen JH7100_RSTN_DMA1P_AXI>,
++                               <&rstgen JH7100_RSTN_SGDMA1P_AXI>;
++                      reset-names = "axi", "ahb";
++                      interrupts = <1>;
++                      #dma-cells = <1>;
++                      dma-channels = <16>;
++                      snps,dma-masters = <1>;
++                      snps,data-width = <3>;
++                      snps,block-size = <4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096>;
++                      snps,priority = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
++                      snps,axi-max-burst-len = <64>;
++              };
++
+               clkgen: clock-controller@11800000 {
+                       compatible = "starfive,jh7100-clkgen";
+                       reg = <0x0 0x11800000 0x0 0x10000>;
+@@ -295,6 +498,13 @@
+                       #clock-cells = <1>;
+               };
++              otp: otp@11810000 {
++                      compatible = "starfive,fu740-otp";
++                      reg = <0x0 0x11810000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_OTP_APB>;
++                      fuse-count = <0x200>;
++              };
++
+               rstgen: reset-controller@11840000 {
+                       compatible = "starfive,jh7100-reset";
+                       reg = <0x0 0x11840000 0x0 0x10000>;
+@@ -306,6 +516,21 @@
+                       reg = <0x0 0x11850000 0x0 0x10000>;
+               };
++              qspi: spi@11860000 {
++                      compatible = "cdns,qspi-nor";
++                      reg = <0x0 0x11860000 0x0 0x10000>,
++                            <0x0 0x20000000 0x0 0x20000000>;
++                      clocks = <&clkgen JH7100_CLK_QSPI_AHB>;
++                      interrupts = <3>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      cdns,fifo-depth = <256>;
++                      cdns,fifo-width = <4>;
++                      cdns,trigger-address = <0x0>;
++                      spi-max-frequency = <250000000>;
++                      status = "disabled";
++              };
++
+               uart0: serial@11870000 {
+                       compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart";
+                       reg = <0x0 0x11870000 0x0 0x10000>;
+@@ -332,6 +557,34 @@
+                       status = "disabled";
+               };
++              spi0: spi@11890000 {
++                      compatible = "snps,dw-apb-ssi";
++                      reg = <0x0 0x11890000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_SPI0_CORE>,
++                               <&clkgen JH7100_CLK_SPI0_APB>;
++                      clock-names = "ssi_clk", "pclk";
++                      resets = <&rstgen JH7100_RSTN_SPI0_APB>;
++                      reset-names = "spi";
++                      interrupts = <94>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++              };
++
++              spi1: spi@118a0000 {
++                      compatible = "snps,dw-apb-ssi";
++                      reg = <0x0 0x118a0000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_SPI1_CORE>,
++                               <&clkgen JH7100_CLK_SPI1_APB>;
++                      clock-names = "ssi_clk", "pclk";
++                      resets = <&rstgen JH7100_RSTN_SPI1_APB>;
++                      reset-names = "spi";
++                      interrupts = <95>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++              };
++
+               i2c0: i2c@118b0000 {
+                       compatible = "snps,designware-i2c";
+                       reg = <0x0 0x118b0000 0x0 0x10000>;
+@@ -358,6 +611,41 @@
+                       status = "disabled";
+               };
++              trng: trng@118d0000 {
++                      compatible = "starfive,vic-rng";
++                      reg = <0x0 0x118d0000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_TRNG_APB>;
++                      interrupts = <98>;
++              };
++
++              vpu_enc: vpu_enc@118e0000 {
++                      compatible = "cm,cm521-vpu";
++                      reg = <0x0 0x118e0000 0x0 0x4000>;
++                      reg-names = "control";
++                      clocks = <&clkgen JH7100_CLK_VP6_CORE>;
++                      clock-names = "vcodec";
++                      interrupts = <26>;
++              };
++
++              vpu_dec: vpu_dec@118f0000 {
++                      compatible = "c&m,cm511-vpu";
++                      reg = <0 0x118f0000 0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_VP6_CORE>;
++                      clock-names = "vcodec";
++                      interrupts = <23>;
++                      //memory-region = <&vpu_reserved>;
++              };
++
++              jpu: coadj12@11900000 {
++                      compatible = "cm,codaj12-jpu-1";
++                      reg = <0x0 0x11900000 0x0 0x300>;
++                      reg-names = "control";
++                      clocks = <&clkgen JH7100_CLK_JPEG_APB>;
++                      clock-names = "jpege";
++                      interrupts = <24>;
++                      memory-region = <&jpu_reserved>;
++              };
++
+               gpio: pinctrl@11910000 {
+                       compatible = "starfive,jh7100-pinctrl";
+                       reg = <0x0 0x11910000 0x0 0x10000>,
+@@ -372,6 +660,86 @@
+                       #interrupt-cells = <2>;
+               };
++              nvdla@11940000 {
++                      compatible = "nvidia,nvdla_os_initial";
++                      interrupts = <22>;
++                      memory-region = <&nvdla_reserved>;
++                      reg = <0x0 0x11940000 0x0 0x40000>;
++                      status = "okay";
++              };
++
++              display: display-subsystem {
++                      compatible = "starfive,display-subsystem";
++                      dma-coherent;
++                      status = "disabled";
++              };
++
++              encoder: display-encoder {
++                      compatible = "starfive,display-encoder";
++                      status = "disabled";
++              };
++
++              crtc: crtc@12000000 {
++                      compatible = "starfive,jh7100-crtc";
++                      reg = <0x0 0x12000000 0x0 0x10000>,
++                            <0x0 0x12040000 0x0 0x10000>,
++                            <0x0 0x12080000 0x0 0x10000>,
++                            <0x0 0x120c0000 0x0 0x10000>,
++                            <0x0 0x12240000 0x0 0x10000>,
++                            <0x0 0x12250000 0x0 0x10000>,
++                            <0x0 0x12260000 0x0 0x10000>;
++                      reg-names = "lcdc", "vpp0", "vpp1", "vpp2", "clk", "rst", "sys";
++                      clocks = <&clkgen JH7100_CLK_DISP_AXI>, <&clkgen JH7100_CLK_VOUT_SRC>;
++                      clock-names = "disp_axi", "vout_src";
++                      resets = <&rstgen JH7100_RSTN_DISP_AXI>, <&rstgen JH7100_RSTN_VOUT_SRC>;
++                      reset-names = "disp_axi", "vout_src";
++                      interrupts = <101>, <103>;
++                      interrupt-names = "lcdc_irq", "vpp1_irq";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      pp1 {
++                              pp-id = <1>;
++                              fifo-out;
++                              //sys-bus-out;
++                              src-format = <11>; //<COLOR_RGB565>;
++                              src-width = <1920>;
++                              src-height = <1080>;
++                              dst-format = <7>; //<COLOR_RGB888_ARGB>;
++                              dst-width = <1920>;
++                              dst-height = <1080>;
++                      };
++              };
++
++              spi2: spi@12410000 {
++                      compatible = "snps,dw-apb-ssi";
++                      reg = <0x0 0x12410000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_SPI2_CORE>,
++                               <&clkgen JH7100_CLK_SPI2_APB>;
++                      clock-names = "ssi_clk", "pclk";
++                      resets = <&rstgen JH7100_RSTN_SPI2_APB>;
++                      reset-names = "spi";
++                      interrupts = <70>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++              };
++
++              spi3: spi@12420000 {
++                      compatible = "snps,dw-apb-ssi";
++                      reg = <0x0 0x12420000 0x0 0x10000>;
++                      clocks = <&clkgen JH7100_CLK_SPI3_CORE>,
++                               <&clkgen JH7100_CLK_SPI3_APB>;
++                      clock-names = "ssi_clk", "pclk";
++                      resets = <&rstgen JH7100_RSTN_SPI3_APB>;
++                      reset-names = "spi";
++                      interrupts = <71>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++              };
++
+               uart2: serial@12430000 {
+                       compatible = "starfive,jh7100-uart", "snps,dw-apb-uart";
+                       reg = <0x0 0x12430000 0x0 0x10000>;
+@@ -454,5 +822,26 @@
+                       reset-names = "sense", "bus";
+                       #thermal-sensor-cells = <0>;
+               };
++
++              xrp@f0000000 {
++                      compatible = "cdns,xrp";
++                      reg = <0x0  0xf0000000 0x0 0x01ffffff>,
++                            <0x10 0x72000000 0x0 0x00001000>,
++                            <0x10 0x72001000 0x0 0x00fff000>,
++                            <0x0  0x124b0000 0x0 0x00010000>;
++                      clocks = <&clkgen JH7100_CLK_VP6_CORE>;
++                      interrupts = <27>, <28>;
++                      firmware-name = "vp6_elf";
++                      dsp-irq = <19 20>;
++                      dsp-irq-src = <0x20 0x21>;
++                      intc-irq-mode = <1>;
++                      intc-irq = <0 1>;
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++                      ranges = <0x40000000 0x0  0x40000000 0x01000000>,
++                               <0xb0000000 0x10 0x70000000 0x3000000>;
++                      dsp@0 {
++                      };
++              };
+       };
+ };
diff --git a/target/linux/starfive/patches-6.12/1022-riscv-dts-starfive-vf1-add-LED-aliases-and-stop-hear.patch b/target/linux/starfive/patches-6.12/1022-riscv-dts-starfive-vf1-add-LED-aliases-and-stop-hear.patch
new file mode 100644 (file)
index 0000000..354a481
--- /dev/null
@@ -0,0 +1,38 @@
+From ec25d5b3e4ac00b76dce3593b54062ee7826cbbd Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 31 May 2025 22:17:21 +0000
+Subject: [PATCH 1022/1022] riscv: dts: starfive: vf1: add LED aliases and stop
+ heartbeat
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/riscv/boot/dts/starfive/jh7100-common.dtsi | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
+@@ -16,6 +16,10 @@
+               mmc1 = &sdio1;
+               serial0 = &uart3;
+               serial1 = &uart0;
++              led-boot = &led_ack;
++              led-failsafe = &led_ack;
++              led-running = &led_ack;
++              led-upgrade = &led_ack;
+       };
+       chosen {
+@@ -34,11 +38,11 @@
+       leds {
+               compatible = "gpio-leds";
+-              led-ack {
++              led_ack: led-ack {
+                       gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_HEARTBEAT;
+-                      linux,default-trigger = "heartbeat";
++                      default-state = "on";
+                       label = "ack";
+               };
+       };
diff --git a/target/linux/starfive/patches-6.12/1023-riscv-dts-starfive-visionfive2-add-SYSLED-support.patch b/target/linux/starfive/patches-6.12/1023-riscv-dts-starfive-visionfive2-add-SYSLED-support.patch
new file mode 100644 (file)
index 0000000..c589847
--- /dev/null
@@ -0,0 +1,34 @@
+From 3a92ee5a97f030bdb1e88272a5d277ecb76836d6 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sun, 1 Jun 2025 14:03:30 +0000
+Subject: [PATCH 7/8] riscv: dts: starfive: visionfive2: add SYSLED support
+
+A SYS LED is available at aongpio-3. Add standard heartbeat
+support for it.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ .../dts/starfive/jh7110-starfive-visionfive-2.dtsi   | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+@@ -21,6 +21,18 @@
+                       reg = <0x0 0x6ce00000 0x0 0x1600000>;
+               };
+       };
++
++      leds {
++              compatible = "gpio-leds";
++
++              led-ack {
++                      gpios = <&aongpio 3 GPIO_ACTIVE_HIGH>;
++                      color = <LED_COLOR_ID_GREEN>;
++                      function = LED_FUNCTION_HEARTBEAT;
++                      linux,default-trigger = "heartbeat";
++                      label = "ack";
++              };
++      };
+ };
+ &gmac1 {
diff --git a/target/linux/starfive/patches-6.12/1024-riscv-dts-starfive-visionfive2-add-LED-aliases-and-s.patch b/target/linux/starfive/patches-6.12/1024-riscv-dts-starfive-visionfive2-add-LED-aliases-and-s.patch
new file mode 100644 (file)
index 0000000..cbb6c7e
--- /dev/null
@@ -0,0 +1,43 @@
+From d930d3d22dcca6946dbdc822d7b8681f0d6372e5 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sun, 1 Jun 2025 14:06:04 +0000
+Subject: [PATCH 8/8] riscv: dts: starfive: visionfive2: add LED aliases and
+ stop heartbeat
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ .../boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi   | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+@@ -6,10 +6,15 @@
+ /dts-v1/;
+ #include "jh7110-common.dtsi"
++#include <dt-bindings/leds/common.h>
+ / {
+       aliases {
+               ethernet1 = &gmac1;
++              led-boot = &led_ack;
++              led-failsafe = &led_ack;
++              led-running = &led_ack;
++              led-upgrade = &led_ack;
+       };
+       reserved-memory {
+@@ -25,11 +30,11 @@
+       leds {
+               compatible = "gpio-leds";
+-              led-ack {
++              led_ack: led-ack {
+                       gpios = <&aongpio 3 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_HEARTBEAT;
+-                      linux,default-trigger = "heartbeat";
++                      default-state = "on";
+                       label = "ack";
+               };
+       };
diff --git a/target/linux/starfive/patches-6.12/1025-riscv-dts-starfive-visionfive2-add-dma-pool-entry.patch b/target/linux/starfive/patches-6.12/1025-riscv-dts-starfive-visionfive2-add-dma-pool-entry.patch
new file mode 100644 (file)
index 0000000..437266c
--- /dev/null
@@ -0,0 +1,31 @@
+From 928a660ec1124853d2dae074e74ec7b20fe9bac2 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sun, 1 Jun 2025 16:02:38 +0000
+Subject: [PATCH] riscv: dts: starfive: visionfive2: add dma pool entry
+
+In the VF2 SDK there is a reserved memory for a shared dma pool, which is
+also updated by the SDK bootloader. Add this node here as well.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ .../boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi  | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+@@ -25,6 +25,15 @@
+               e24_mem: e24@c0000000 {
+                       reg = <0x0 0x6ce00000 0x0 0x1600000>;
+               };
++
++              linux,cma {
++                      compatible = "shared-dma-pool";
++                      reusable;
++                      size = <0x0 0x20000000>;
++                      alignment = <0x0 0x1000>;
++                      alloc-ranges = <0x0 0x70000000 0x0 0x20000000>;
++                      linux,cma-default;
++              };
+       };
+       leds {