From: Zoltan HERPAI Date: Sun, 28 May 2023 13:14:02 +0000 (+0200) Subject: starfive: add new target for StarFive JH7100/7110 SoC X-Git-Url: http://git.openwrt.org/ubox.git?a=commitdiff_plain;h=4070e2a64c524b1de38573700ba1c4fcc79de1bf;p=openwrt%2Fstaging%2F981213.git starfive: add new target for StarFive JH7100/7110 SoC This target adds support for the StarFive JH7100 and JH7110 SoCs, based on 6.1, as well as a couple boards equipped with these. Specifications: SoCs: JH7100: - StarFive JH7100 dual-core RISC-V (U74, RC64GC) - additional monitoring (S7) and control (E24) cores - 2Mb L2 cache JH7110: - StarFive JH7110 quad-core RISC-V (U74, RV64GC) - additional monitoring (S7) and control (E24) cores - 2Mb L2 cache Boards: VisionFive1: - JH7100 @ 1GHz - Memory: 8Gb LPDDR4 - 4x USB3.0 - 1x GBit ethernet - AMPak 6236 wifi / bluetooth - audio - powered via USB-C VisionFive2: - JH7110 @ 1.5GHz - Memory: 2/4/8Gb DDR4 - 2x Gbit ethernet - 2x USB3.0 / 2x USB2.0 - eMMC / SDIO - various multimedia input/outputs (MIPI CSI, HDMI, audio) - M.2 key M slot - PoE support - powered via USB-C Installation: Standard SD-card installation via dd-ing the generated image to an SD-card of at least 256Mb. Signed-off-by: Zoltan HERPAI --- diff --git a/target/linux/starfive/Makefile b/target/linux/starfive/Makefile new file mode 100644 index 0000000000..f71f57e7f7 --- /dev/null +++ b/target/linux/starfive/Makefile @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2024 Toco Technologies +# +include $(TOPDIR)/rules.mk + +ARCH:=riscv64 +BOARD:=starfive +BOARDNAME:=StarFive JH71x0 (7100/7110) +FEATURES:=ext4 +KERNELNAME:=Image dtbs + +KERNEL_PATCHVER:=6.1 + +include $(INCLUDE_DIR)/target.mk + +define Target/Description + Build firmware images for the StarFive JH71x0-based boards +endef + +$(eval $(call BuildTarget)) diff --git a/target/linux/starfive/base-files/etc/board.d/02_network b/target/linux/starfive/base-files/etc/board.d/02_network new file mode 100644 index 0000000000..bd9947ad49 --- /dev/null +++ b/target/linux/starfive/base-files/etc/board.d/02_network @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh + +board_config_update + +case "$(board_name)" in +starfive,visionfive-2-v1.3b|\ +starfive,visionfive-2-v1.2a) + ucidef_set_interfaces_lan_wan "eth0" "eth1" + ;; +*) + ucidef_set_interface_lan 'eth0' + ;; +esac + +board_config_flush + +exit 0 diff --git a/target/linux/starfive/base-files/etc/inittab b/target/linux/starfive/base-files/etc/inittab new file mode 100644 index 0000000000..d1b5a0fa22 --- /dev/null +++ b/target/linux/starfive/base-files/etc/inittab @@ -0,0 +1,4 @@ +::sysinit:/etc/init.d/rcS S boot +::shutdown:/etc/init.d/rcS K shutdown +ttyS0::askfirst:/usr/libexec/login.sh +tty1::askfirst:/usr/libexec/login.sh diff --git a/target/linux/starfive/base-files/lib/firmware/brcm/brcmfmac43430-sdio.txt b/target/linux/starfive/base-files/lib/firmware/brcm/brcmfmac43430-sdio.txt new file mode 100644 index 0000000000..9baa5c33bf --- /dev/null +++ b/target/linux/starfive/base-files/lib/firmware/brcm/brcmfmac43430-sdio.txt @@ -0,0 +1,53 @@ +#AP6212_NVRAM_V1.0_20140603 +# 2.4 GHz, 20 MHz BW mode + +# The following parameter values are just placeholders, need to be updated. +manfid=0x2d0 +prodid=0x0726 +vendid=0x14e4 +devid=0x43e2 +boardtype=0x0726 +boardrev=0x1101 +boardnum=22 +macaddr=00:90:4c:c5:12:38 +sromrev=11 +boardflags=0x00404201 +xtalfreq=26000 +nocrc=1 +ag0=255 +aa2g=1 +ccode=ALL + +pa0itssit=0x20 +extpagain2g=0 + +#PA parameters for 2.4GHz, measured at CHIP OUTPUT +pa2ga0=-168,7161,-820 +AvVmid_c0=0x0,0xc8 +cckpwroffset0=5 + +# PPR params +maxp2ga0=90 +txpwrbckof=6 +cckbw202gpo=0x5555 +legofdmbw202gpo=0x77777777 +mcsbw202gpo=0xaaaaaaaa + +# OFDM IIR : +ofdmdigfilttype=7 +# PAPD mode: +papdmode=2 + +il0macaddr=00:90:4c:c5:12:38 +wl0id=0x431b + +#OOB parameters +hostwake=0x40 +hostrdy=0x41 +usbrdy=0x03 +usbrdydelay=100 +deadman_to=0xffffffff +# muxenab: 0x1 for UART enable, 0x10 for Host awake +muxenab=0x10 +# CLDO PWM voltage settings - 0x4 - 1.1 volt +#cldo_pwm=0x4 diff --git a/target/linux/starfive/base-files/lib/firmware/brcm/brcmfmac43430a0-sdio.txt b/target/linux/starfive/base-files/lib/firmware/brcm/brcmfmac43430a0-sdio.txt new file mode 120000 index 0000000000..2ed6689828 --- /dev/null +++ b/target/linux/starfive/base-files/lib/firmware/brcm/brcmfmac43430a0-sdio.txt @@ -0,0 +1 @@ +brcmfmac43430-sdio.txt \ No newline at end of file diff --git a/target/linux/starfive/config-6.1 b/target/linux/starfive/config-6.1 new file mode 100644 index 0000000000..6da229ddb5 --- /dev/null +++ b/target/linux/starfive/config-6.1 @@ -0,0 +1,555 @@ +CONFIG_64BIT=y +CONFIG_AMBA_PL08X=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_RV64I=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SIFIVE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_STARFIVE=y +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_ARM_AMBA=y +# CONFIG_ARM_MHU_V2 is not set +CONFIG_ASN1=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_AUXILIARY_BUS=y +CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y +CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_CC_NO_ARRAY_BOUNDS=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_CONTIG_ALLOC=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_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CRASH_CORE=y +CONFIG_CRC16=y +CONFIG_CRC7=y +CONFIG_CRC_ITU_T=y +CONFIG_CRYPTO_BLAKE2B=y +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_DEV_JH7110=y +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_ENGINE=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 +CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LIB_UTILS=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_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_TIMEKEEPING=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_DEVTMPFS_SAFE is not set +CONFIG_DMADEVICES=y +CONFIG_DMADEVICES_DEBUG=y +CONFIG_DMADEVICES_VDEBUG=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +# CONFIG_DPM_WATCHDOG 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_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_SIFIVE=y +CONFIG_ERRATA_SIFIVE_CIP_1200=y +CONFIG_ERRATA_SIFIVE_CIP_453=y +# CONFIG_ERRATA_THEAD is not set +CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=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_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FWNODE_MDIO=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y +CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IOREMAP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=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_MSI_IRQ_DOMAIN=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_GLOB=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_MAP=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=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_INITRAMFS_SOURCE="" +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_JH71XX_PMU=y +CONFIG_JUMP_LABEL=y +CONFIG_LIBFDT=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LSM="" +CONFIG_MARVELL_PHY=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY_ISOLATION=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_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_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MODULE_SECTIONS=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_FAILOVER=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_NS=y +CONFIG_NET_SELFTESTS=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_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +# CONFIG_NONPORTABLE is not set +CONFIG_NR_CPUS=8 +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y +CONFIG_NVME_CORE=y +CONFIG_NVME_HWMON=y +# CONFIG_NVME_MULTIPATH is not set +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_DMA_DEFAULT_COHERENT=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_STARFIVE is not set +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCS_XPCS=y +CONFIG_PERF_EVENTS=y +CONFIG_PGTABLE_LEVELS=5 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PHY_STARFIVE_DPHY_RX=y +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_PORTABLE=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_PREEMPT_NONE_BUILD=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_SIFIVE is not set +CONFIG_PWM_SIFIVE_PTC=y +CONFIG_PWM_STARFIVE_PTC=y +CONFIG_PWM_SYSFS=y +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_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=y +CONFIG_RESET_STARFIVE_JH7110=y +CONFIG_RESET_STARFIVE_JH71X0=y +CONFIG_RFS_ACCEL=y +CONFIG_RISCV=y +CONFIG_RISCV_ALTERNATIVE=y +CONFIG_RISCV_BOOT_SPINWAIT=y +CONFIG_RISCV_DMA_NONCOHERENT=y +CONFIG_RISCV_INTC=y +CONFIG_RISCV_ISA_C=y +# CONFIG_RISCV_ISA_SVPBMT is not set +CONFIG_RISCV_ISA_ZICBOM=y +CONFIG_RISCV_PMU=y +CONFIG_RISCV_PMU_LEGACY=y +CONFIG_RISCV_PMU_SBI=y +CONFIG_RISCV_SBI=y +CONFIG_RISCV_SBI_CPUIDLE=y +CONFIG_RISCV_SBI_V01=y +CONFIG_RISCV_TIMER=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_EFI is not set +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_RTC_DRV_HYM8563=y +CONFIG_RTC_I2C_AND_SPI=y +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_DIAG=y +CONFIG_SOCK_RX_QUEUE_MAPPING=y +# CONFIG_SOC_MICROCHIP_POLARFIRE is not set +CONFIG_SOC_SIFIVE=y +CONFIG_SOC_STARFIVE=y +# CONFIG_SOC_VIRT is not set +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_SPIDEV=y +CONFIG_SRCU=y +CONFIG_STARFIVE_TIMER=y +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_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_OF=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TOOLCHAIN_HAS_ZICBOM=y +CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=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_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_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_PHY=y +CONFIG_USB_ROLE_SWITCH=y +CONFIG_USB_SUPPORT=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USELIB=y +CONFIG_USER_NS=y +CONFIG_VFAT_FS=y +# CONFIG_VIRTIO_BLK is not set +# CONFIG_VIRTIO_NET is not set +CONFIG_VMAP_STACK=y +CONFIG_WATCHDOG_CORE=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_WERROR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA32=y diff --git a/target/linux/starfive/generic/target.mk b/target/linux/starfive/generic/target.mk new file mode 100644 index 0000000000..f5cb1fb19b --- /dev/null +++ b/target/linux/starfive/generic/target.mk @@ -0,0 +1 @@ +BOARDNAME:=Generic diff --git a/target/linux/starfive/image/Config.in b/target/linux/starfive/image/Config.in new file mode 100644 index 0000000000..e8e44e066e --- /dev/null +++ b/target/linux/starfive/image/Config.in @@ -0,0 +1,5 @@ +config STARFIVE_SD_BOOT_PARTSIZE + int "Boot (SD Card) filesystem partition size (in MB)" + depends on TARGET_starfive + default 32 + diff --git a/target/linux/starfive/image/Makefile b/target/linux/starfive/image/Makefile new file mode 100644 index 0000000000..51bc9c3cc6 --- /dev/null +++ b/target/linux/starfive/image/Makefile @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2023 Toco Technologies +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +FAT32_BLOCK_SIZE=1024 +FAT32_BLOCKS=$(shell echo $$(($(CONFIG_STARFIVE_SD_BOOT_PARTSIZE)*1024*1024/$(FAT32_BLOCK_SIZE)))) + +define Build/boot-scr-jh7110 + rm -f $@-boot.scr + mkimage -A riscv -O linux -T script -C none -a 0 -e 0 -d mmc.bootscript.jh7110 $@-boot.scr +endef + +define Build/boot-scr-jh7100 + rm -f $@-boot.scr + mkimage -A riscv -O linux -T script -C none -a 0 -e 0 -d mmc.bootscript.jh7100 $@-boot.scr +endef + +define Build/riscv-sdcard + rm -f $@.boot #$(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img + mkfs.fat $@.boot -C $(FAT32_BLOCKS) + mcopy -i $@.boot $(LINUX_DIR)/arch/riscv/boot/dts/$(DEVICE_DTS).dtb ::dtb + mcopy -i $@.boot $@-boot.scr ::boot.scr.uimg + mcopy -i $@.boot $(IMAGE_KERNEL) ::Image + ./gen_starfive_sdcard_img.sh \ + $@ \ + $@.boot \ + $(IMAGE_ROOTFS) \ + $(CONFIG_STARFIVE_SD_BOOT_PARTSIZE) \ + $(CONFIG_TARGET_ROOTFS_PARTSIZE) +endef + +define Device/Default + PROFILES := Default + KERNEL_NAME := Image + KERNEL := kernel-bin + IMAGES := sdcard.img.gz + IMAGE/sdcard.img.gz := boot-scr-jh7110 | riscv-sdcard | append-metadata | gzip +endef + +define Device/JH7100 + PROFILES := Default + KERNEL_NAME := Image + KERNEL := kernel-bin + IMAGES := sdcard.img.gz + IMAGE/sdcard.img.gz := boot-scr-jh7100 | riscv-sdcard | append-metadata | gzip +endef + +define Device/visionfive2-v1.2a + DEVICE_VENDOR := StarFive + DEVICE_MODEL := VisionFive2 v1.2a + DEVICE_DTS := starfive/jh7110-starfive-visionfive-2-v1.2a + DEVICE_PACKAGES := kmod-eeprom-at24 kmod-pcie-starfive kmod-usb3 kmod-usb-cdns3-starfive +endef +TARGET_DEVICES += visionfive2-v1.2a + +define Device/visionfive2-v1.3b + DEVICE_VENDOR := StarFive + DEVICE_MODEL := VisionFive2 v1.3b + DEVICE_DTS := starfive/jh7110-starfive-visionfive-2-v1.3b + DEVICE_PACKAGES := kmod-eeprom-at24 kmod-pcie-starfive kmod-usb3 kmod-usb-cdns3-starfive +endef +TARGET_DEVICES += visionfive2-v1.3b + +define Device/beaglev-starlight + $(call Device/JH7100) + DEVICE_VENDOR := BeagleV + DEVICE_MODEL := Starlight + DEVICE_DTS := starfive/jh7100-beaglev-starlight +endef +TARGET_DEVICES += beaglev-starlight + +define Device/visionfive-v1 + $(call Device/JH7100) + DEVICE_VENDOR := StarFive + DEVICE_MODEL := VisionFive v1 + DEVICE_DTS := starfive/jh7100-starfive-visionfive-v1 + DEVICE_PACKAGES := kmod-eeprom-at24 kmod-brcmfmac cypress-firmware-43430-sdio wpad-basic-mbedtls \ + kmod-usb3 kmod-usb-cdns3-starfive +endef +TARGET_DEVICES += visionfive-v1 + +$(eval $(call BuildImage)) diff --git a/target/linux/starfive/image/gen_starfive_sdcard_img.sh b/target/linux/starfive/image/gen_starfive_sdcard_img.sh new file mode 100755 index 0000000000..ac0c30c5d9 --- /dev/null +++ b/target/linux/starfive/image/gen_starfive_sdcard_img.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2023 OpenWrt.org +# + +set -ex +[ $# -eq 5 ] || { + echo "SYNTAX: $0 " + exit 1 +} + +OUTPUT="$1" +BOOTFS="$2" +ROOTFS="$3" +BOOTFSSIZE="$4" +ROOTFSSIZE="$5" + +set $(ptgen -o $OUTPUT -v -g -T sifiveu_spl -N loader1 -p 1024 -T sifiveu_uboot -N loader2 -p 4096 -t ef -N boot -p ${BOOTFSSIZE}M -N rootfs -p ${ROOTFSSIZE}M) + +ROOTFSOFFSET=$(($7 / 512)) + +dd bs=512 if="$BOOTFS" of="$OUTPUT" seek=10274 conv=notrunc +dd bs=512 if="$ROOTFS" of="$OUTPUT" seek=${ROOTFSOFFSET} conv=notrunc diff --git a/target/linux/starfive/image/mmc.bootscript.jh7100 b/target/linux/starfive/image/mmc.bootscript.jh7100 new file mode 100644 index 0000000000..a6f19ae22e --- /dev/null +++ b/target/linux/starfive/image/mmc.bootscript.jh7100 @@ -0,0 +1,4 @@ +fatload mmc 0:3 0x84000000 Image +fatload mmc 0:3 0x88000000 dtb +setenv bootargs "earlyprintk console=ttyS0,115200 debug rootwait earlycon=sbi root=/dev/mmcblk0p4" +booti 0x84000000 - 0x88000000 diff --git a/target/linux/starfive/image/mmc.bootscript.jh7110 b/target/linux/starfive/image/mmc.bootscript.jh7110 new file mode 100644 index 0000000000..aeb2e82275 --- /dev/null +++ b/target/linux/starfive/image/mmc.bootscript.jh7110 @@ -0,0 +1,5 @@ +fatload mmc 1:3 0xa0000000 Image +fatload mmc 1:3 0x46000000 dtb +run chipa_set_linux +setenv bootargs "earlyprintk console=ttyS0,115200 debug rootwait earlycon=sbi root=/dev/mmcblk1p4" +booti 0xa0000000 - 0x46000000 diff --git a/target/linux/starfive/modules.mk b/target/linux/starfive/modules.mk new file mode 100644 index 0000000000..7aa559b9e5 --- /dev/null +++ b/target/linux/starfive/modules.mk @@ -0,0 +1,31 @@ +define KernelPackage/pcie-starfive + SUBMENU:=$(OTHER_MENU) + TITLE:=JH7110 PCIe controller support + DEPENDS:=@TARGET_starfive + KCONFIG:=CONFIG_PCIE_STARFIVE + FILES:=$(LINUX_DIR)/drivers/pci/controller/pcie-starfive.ko + AUTOLOAD:=$(call AutoLoad,41,pcie-starfive,1) +endef + +define KernelPackage/pcie-starfive/description + PCIe support for JH7110 +endef + +$(eval $(call KernelPackage,pcie-starfive)) + + +define KernelPackage/usb-cdns3-starfive + TITLE:=Cadence USB3 StarFive USB driver + DEPENDS:=@TARGET_starfive +kmod-usb-cdns3 + KCONFIG:= CONFIG_USB_CDNS3_STARFIVE + FILES:= $(LINUX_DIR)/drivers/usb/cdns3/cdns3-starfive.ko + AUTOLOAD:=$(call AutoLoad,53,cdns3-starfive,1) + $(call AddDepends/usb) +endef + +define KernelPackage/usb-cdns3-starfive/description + Add support for the Cadence USB3 controller found in StarFive SoCs. +endef + + +$(eval $(call KernelPackage,usb-cdns3-starfive)) diff --git a/target/linux/starfive/patches-6.1/0001-dt-bindings-clock-Add-StarFive-JH7110-system-clock-a.patch b/target/linux/starfive/patches-6.1/0001-dt-bindings-clock-Add-StarFive-JH7110-system-clock-a.patch new file mode 100644 index 0000000000..3e06d5a681 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0001-dt-bindings-clock-Add-StarFive-JH7110-system-clock-a.patch @@ -0,0 +1,482 @@ +From c960c73ee9fdaae51fcd8a14d44d576b1cf522b7 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:13 +0800 +Subject: [PATCH 001/122] dt-bindings: clock: Add StarFive JH7110 system clock + and reset generator + +Add bindings for the system clock and reset generator (SYSCRG) on the +JH7110 RISC-V SoC by StarFive Ltd. + +Reviewed-by: Conor Dooley +Reviewed-by: Rob Herring +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../clock/starfive,jh7110-syscrg.yaml | 104 +++++++++ + .../dt-bindings/clock/starfive,jh7110-crg.h | 203 ++++++++++++++++++ + .../dt-bindings/reset/starfive,jh7110-crg.h | 142 ++++++++++++ + 3 files changed, 449 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml + create mode 100644 include/dt-bindings/clock/starfive,jh7110-crg.h + create mode 100644 include/dt-bindings/reset/starfive,jh7110-crg.h + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml +@@ -0,0 +1,104 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/starfive,jh7110-syscrg.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 System Clock and Reset Generator ++ ++maintainers: ++ - Emil Renner Berthing ++ ++properties: ++ compatible: ++ const: starfive,jh7110-syscrg ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ oneOf: ++ - items: ++ - description: Main Oscillator (24 MHz) ++ - description: GMAC1 RMII reference or GMAC1 RGMII RX ++ - description: External I2S TX bit clock ++ - description: External I2S TX left/right channel clock ++ - description: External I2S RX bit clock ++ - description: External I2S RX left/right channel clock ++ - description: External TDM clock ++ - description: External audio master clock ++ ++ - items: ++ - description: Main Oscillator (24 MHz) ++ - description: GMAC1 RMII reference ++ - description: GMAC1 RGMII RX ++ - description: External I2S TX bit clock ++ - description: External I2S TX left/right channel clock ++ - description: External I2S RX bit clock ++ - description: External I2S RX left/right channel clock ++ - description: External TDM clock ++ - description: External audio master clock ++ ++ clock-names: ++ oneOf: ++ - items: ++ - const: osc ++ - enum: ++ - gmac1_rmii_refin ++ - gmac1_rgmii_rxin ++ - const: i2stx_bclk_ext ++ - const: i2stx_lrck_ext ++ - const: i2srx_bclk_ext ++ - const: i2srx_lrck_ext ++ - const: tdm_ext ++ - const: mclk_ext ++ ++ - items: ++ - const: osc ++ - const: gmac1_rmii_refin ++ - const: gmac1_rgmii_rxin ++ - const: i2stx_bclk_ext ++ - const: i2stx_lrck_ext ++ - const: i2srx_bclk_ext ++ - const: i2srx_lrck_ext ++ - const: tdm_ext ++ - const: mclk_ext ++ ++ '#clock-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ '#reset-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - '#clock-cells' ++ - '#reset-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ clock-controller@13020000 { ++ compatible = "starfive,jh7110-syscrg"; ++ reg = <0x13020000 0x10000>; ++ clocks = <&osc>, <&gmac1_rmii_refin>, ++ <&gmac1_rgmii_rxin>, ++ <&i2stx_bclk_ext>, <&i2stx_lrck_ext>, ++ <&i2srx_bclk_ext>, <&i2srx_lrck_ext>, ++ <&tdm_ext>, <&mclk_ext>; ++ clock-names = "osc", "gmac1_rmii_refin", ++ "gmac1_rgmii_rxin", ++ "i2stx_bclk_ext", "i2stx_lrck_ext", ++ "i2srx_bclk_ext", "i2srx_lrck_ext", ++ "tdm_ext", "mclk_ext"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; +--- /dev/null ++++ b/include/dt-bindings/clock/starfive,jh7110-crg.h +@@ -0,0 +1,203 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright 2022 Emil Renner Berthing ++ */ ++ ++#ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ ++#define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ ++ ++/* SYSCRG clocks */ ++#define JH7110_SYSCLK_CPU_ROOT 0 ++#define JH7110_SYSCLK_CPU_CORE 1 ++#define JH7110_SYSCLK_CPU_BUS 2 ++#define JH7110_SYSCLK_GPU_ROOT 3 ++#define JH7110_SYSCLK_PERH_ROOT 4 ++#define JH7110_SYSCLK_BUS_ROOT 5 ++#define JH7110_SYSCLK_NOCSTG_BUS 6 ++#define JH7110_SYSCLK_AXI_CFG0 7 ++#define JH7110_SYSCLK_STG_AXIAHB 8 ++#define JH7110_SYSCLK_AHB0 9 ++#define JH7110_SYSCLK_AHB1 10 ++#define JH7110_SYSCLK_APB_BUS 11 ++#define JH7110_SYSCLK_APB0 12 ++#define JH7110_SYSCLK_PLL0_DIV2 13 ++#define JH7110_SYSCLK_PLL1_DIV2 14 ++#define JH7110_SYSCLK_PLL2_DIV2 15 ++#define JH7110_SYSCLK_AUDIO_ROOT 16 ++#define JH7110_SYSCLK_MCLK_INNER 17 ++#define JH7110_SYSCLK_MCLK 18 ++#define JH7110_SYSCLK_MCLK_OUT 19 ++#define JH7110_SYSCLK_ISP_2X 20 ++#define JH7110_SYSCLK_ISP_AXI 21 ++#define JH7110_SYSCLK_GCLK0 22 ++#define JH7110_SYSCLK_GCLK1 23 ++#define JH7110_SYSCLK_GCLK2 24 ++#define JH7110_SYSCLK_CORE 25 ++#define JH7110_SYSCLK_CORE1 26 ++#define JH7110_SYSCLK_CORE2 27 ++#define JH7110_SYSCLK_CORE3 28 ++#define JH7110_SYSCLK_CORE4 29 ++#define JH7110_SYSCLK_DEBUG 30 ++#define JH7110_SYSCLK_RTC_TOGGLE 31 ++#define JH7110_SYSCLK_TRACE0 32 ++#define JH7110_SYSCLK_TRACE1 33 ++#define JH7110_SYSCLK_TRACE2 34 ++#define JH7110_SYSCLK_TRACE3 35 ++#define JH7110_SYSCLK_TRACE4 36 ++#define JH7110_SYSCLK_TRACE_COM 37 ++#define JH7110_SYSCLK_NOC_BUS_CPU_AXI 38 ++#define JH7110_SYSCLK_NOC_BUS_AXICFG0_AXI 39 ++#define JH7110_SYSCLK_OSC_DIV2 40 ++#define JH7110_SYSCLK_PLL1_DIV4 41 ++#define JH7110_SYSCLK_PLL1_DIV8 42 ++#define JH7110_SYSCLK_DDR_BUS 43 ++#define JH7110_SYSCLK_DDR_AXI 44 ++#define JH7110_SYSCLK_GPU_CORE 45 ++#define JH7110_SYSCLK_GPU_CORE_CLK 46 ++#define JH7110_SYSCLK_GPU_SYS_CLK 47 ++#define JH7110_SYSCLK_GPU_APB 48 ++#define JH7110_SYSCLK_GPU_RTC_TOGGLE 49 ++#define JH7110_SYSCLK_NOC_BUS_GPU_AXI 50 ++#define JH7110_SYSCLK_ISP_TOP_CORE 51 ++#define JH7110_SYSCLK_ISP_TOP_AXI 52 ++#define JH7110_SYSCLK_NOC_BUS_ISP_AXI 53 ++#define JH7110_SYSCLK_HIFI4_CORE 54 ++#define JH7110_SYSCLK_HIFI4_AXI 55 ++#define JH7110_SYSCLK_AXI_CFG1_MAIN 56 ++#define JH7110_SYSCLK_AXI_CFG1_AHB 57 ++#define JH7110_SYSCLK_VOUT_SRC 58 ++#define JH7110_SYSCLK_VOUT_AXI 59 ++#define JH7110_SYSCLK_NOC_BUS_DISP_AXI 60 ++#define JH7110_SYSCLK_VOUT_TOP_AHB 61 ++#define JH7110_SYSCLK_VOUT_TOP_AXI 62 ++#define JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK 63 ++#define JH7110_SYSCLK_VOUT_TOP_MIPIPHY_REF 64 ++#define JH7110_SYSCLK_JPEGC_AXI 65 ++#define JH7110_SYSCLK_CODAJ12_AXI 66 ++#define JH7110_SYSCLK_CODAJ12_CORE 67 ++#define JH7110_SYSCLK_CODAJ12_APB 68 ++#define JH7110_SYSCLK_VDEC_AXI 69 ++#define JH7110_SYSCLK_WAVE511_AXI 70 ++#define JH7110_SYSCLK_WAVE511_BPU 71 ++#define JH7110_SYSCLK_WAVE511_VCE 72 ++#define JH7110_SYSCLK_WAVE511_APB 73 ++#define JH7110_SYSCLK_VDEC_JPG 74 ++#define JH7110_SYSCLK_VDEC_MAIN 75 ++#define JH7110_SYSCLK_NOC_BUS_VDEC_AXI 76 ++#define JH7110_SYSCLK_VENC_AXI 77 ++#define JH7110_SYSCLK_WAVE420L_AXI 78 ++#define JH7110_SYSCLK_WAVE420L_BPU 79 ++#define JH7110_SYSCLK_WAVE420L_VCE 80 ++#define JH7110_SYSCLK_WAVE420L_APB 81 ++#define JH7110_SYSCLK_NOC_BUS_VENC_AXI 82 ++#define JH7110_SYSCLK_AXI_CFG0_MAIN_DIV 83 ++#define JH7110_SYSCLK_AXI_CFG0_MAIN 84 ++#define JH7110_SYSCLK_AXI_CFG0_HIFI4 85 ++#define JH7110_SYSCLK_AXIMEM2_AXI 86 ++#define JH7110_SYSCLK_QSPI_AHB 87 ++#define JH7110_SYSCLK_QSPI_APB 88 ++#define JH7110_SYSCLK_QSPI_REF_SRC 89 ++#define JH7110_SYSCLK_QSPI_REF 90 ++#define JH7110_SYSCLK_SDIO0_AHB 91 ++#define JH7110_SYSCLK_SDIO1_AHB 92 ++#define JH7110_SYSCLK_SDIO0_SDCARD 93 ++#define JH7110_SYSCLK_SDIO1_SDCARD 94 ++#define JH7110_SYSCLK_USB_125M 95 ++#define JH7110_SYSCLK_NOC_BUS_STG_AXI 96 ++#define JH7110_SYSCLK_GMAC1_AHB 97 ++#define JH7110_SYSCLK_GMAC1_AXI 98 ++#define JH7110_SYSCLK_GMAC_SRC 99 ++#define JH7110_SYSCLK_GMAC1_GTXCLK 100 ++#define JH7110_SYSCLK_GMAC1_RMII_RTX 101 ++#define JH7110_SYSCLK_GMAC1_PTP 102 ++#define JH7110_SYSCLK_GMAC1_RX 103 ++#define JH7110_SYSCLK_GMAC1_RX_INV 104 ++#define JH7110_SYSCLK_GMAC1_TX 105 ++#define JH7110_SYSCLK_GMAC1_TX_INV 106 ++#define JH7110_SYSCLK_GMAC1_GTXC 107 ++#define JH7110_SYSCLK_GMAC0_GTXCLK 108 ++#define JH7110_SYSCLK_GMAC0_PTP 109 ++#define JH7110_SYSCLK_GMAC_PHY 110 ++#define JH7110_SYSCLK_GMAC0_GTXC 111 ++#define JH7110_SYSCLK_IOMUX_APB 112 ++#define JH7110_SYSCLK_MAILBOX_APB 113 ++#define JH7110_SYSCLK_INT_CTRL_APB 114 ++#define JH7110_SYSCLK_CAN0_APB 115 ++#define JH7110_SYSCLK_CAN0_TIMER 116 ++#define JH7110_SYSCLK_CAN0_CAN 117 ++#define JH7110_SYSCLK_CAN1_APB 118 ++#define JH7110_SYSCLK_CAN1_TIMER 119 ++#define JH7110_SYSCLK_CAN1_CAN 120 ++#define JH7110_SYSCLK_PWM_APB 121 ++#define JH7110_SYSCLK_WDT_APB 122 ++#define JH7110_SYSCLK_WDT_CORE 123 ++#define JH7110_SYSCLK_TIMER_APB 124 ++#define JH7110_SYSCLK_TIMER0 125 ++#define JH7110_SYSCLK_TIMER1 126 ++#define JH7110_SYSCLK_TIMER2 127 ++#define JH7110_SYSCLK_TIMER3 128 ++#define JH7110_SYSCLK_TEMP_APB 129 ++#define JH7110_SYSCLK_TEMP_CORE 130 ++#define JH7110_SYSCLK_SPI0_APB 131 ++#define JH7110_SYSCLK_SPI1_APB 132 ++#define JH7110_SYSCLK_SPI2_APB 133 ++#define JH7110_SYSCLK_SPI3_APB 134 ++#define JH7110_SYSCLK_SPI4_APB 135 ++#define JH7110_SYSCLK_SPI5_APB 136 ++#define JH7110_SYSCLK_SPI6_APB 137 ++#define JH7110_SYSCLK_I2C0_APB 138 ++#define JH7110_SYSCLK_I2C1_APB 139 ++#define JH7110_SYSCLK_I2C2_APB 140 ++#define JH7110_SYSCLK_I2C3_APB 141 ++#define JH7110_SYSCLK_I2C4_APB 142 ++#define JH7110_SYSCLK_I2C5_APB 143 ++#define JH7110_SYSCLK_I2C6_APB 144 ++#define JH7110_SYSCLK_UART0_APB 145 ++#define JH7110_SYSCLK_UART0_CORE 146 ++#define JH7110_SYSCLK_UART1_APB 147 ++#define JH7110_SYSCLK_UART1_CORE 148 ++#define JH7110_SYSCLK_UART2_APB 149 ++#define JH7110_SYSCLK_UART2_CORE 150 ++#define JH7110_SYSCLK_UART3_APB 151 ++#define JH7110_SYSCLK_UART3_CORE 152 ++#define JH7110_SYSCLK_UART4_APB 153 ++#define JH7110_SYSCLK_UART4_CORE 154 ++#define JH7110_SYSCLK_UART5_APB 155 ++#define JH7110_SYSCLK_UART5_CORE 156 ++#define JH7110_SYSCLK_PWMDAC_APB 157 ++#define JH7110_SYSCLK_PWMDAC_CORE 158 ++#define JH7110_SYSCLK_SPDIF_APB 159 ++#define JH7110_SYSCLK_SPDIF_CORE 160 ++#define JH7110_SYSCLK_I2STX0_APB 161 ++#define JH7110_SYSCLK_I2STX0_BCLK_MST 162 ++#define JH7110_SYSCLK_I2STX0_BCLK_MST_INV 163 ++#define JH7110_SYSCLK_I2STX0_LRCK_MST 164 ++#define JH7110_SYSCLK_I2STX0_BCLK 165 ++#define JH7110_SYSCLK_I2STX0_BCLK_INV 166 ++#define JH7110_SYSCLK_I2STX0_LRCK 167 ++#define JH7110_SYSCLK_I2STX1_APB 168 ++#define JH7110_SYSCLK_I2STX1_BCLK_MST 169 ++#define JH7110_SYSCLK_I2STX1_BCLK_MST_INV 170 ++#define JH7110_SYSCLK_I2STX1_LRCK_MST 171 ++#define JH7110_SYSCLK_I2STX1_BCLK 172 ++#define JH7110_SYSCLK_I2STX1_BCLK_INV 173 ++#define JH7110_SYSCLK_I2STX1_LRCK 174 ++#define JH7110_SYSCLK_I2SRX_APB 175 ++#define JH7110_SYSCLK_I2SRX_BCLK_MST 176 ++#define JH7110_SYSCLK_I2SRX_BCLK_MST_INV 177 ++#define JH7110_SYSCLK_I2SRX_LRCK_MST 178 ++#define JH7110_SYSCLK_I2SRX_BCLK 179 ++#define JH7110_SYSCLK_I2SRX_BCLK_INV 180 ++#define JH7110_SYSCLK_I2SRX_LRCK 181 ++#define JH7110_SYSCLK_PDM_DMIC 182 ++#define JH7110_SYSCLK_PDM_APB 183 ++#define JH7110_SYSCLK_TDM_AHB 184 ++#define JH7110_SYSCLK_TDM_APB 185 ++#define JH7110_SYSCLK_TDM_INTERNAL 186 ++#define JH7110_SYSCLK_TDM_TDM 187 ++#define JH7110_SYSCLK_TDM_TDM_INV 188 ++#define JH7110_SYSCLK_JTAG_CERTIFICATION_TRNG 189 ++ ++#define JH7110_SYSCLK_END 190 ++ ++#endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ */ +--- /dev/null ++++ b/include/dt-bindings/reset/starfive,jh7110-crg.h +@@ -0,0 +1,142 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2022 Emil Renner Berthing ++ */ ++ ++#ifndef __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ ++#define __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ ++ ++/* SYSCRG resets */ ++#define JH7110_SYSRST_JTAG_APB 0 ++#define JH7110_SYSRST_SYSCON_APB 1 ++#define JH7110_SYSRST_IOMUX_APB 2 ++#define JH7110_SYSRST_BUS 3 ++#define JH7110_SYSRST_DEBUG 4 ++#define JH7110_SYSRST_CORE0 5 ++#define JH7110_SYSRST_CORE1 6 ++#define JH7110_SYSRST_CORE2 7 ++#define JH7110_SYSRST_CORE3 8 ++#define JH7110_SYSRST_CORE4 9 ++#define JH7110_SYSRST_CORE0_ST 10 ++#define JH7110_SYSRST_CORE1_ST 11 ++#define JH7110_SYSRST_CORE2_ST 12 ++#define JH7110_SYSRST_CORE3_ST 13 ++#define JH7110_SYSRST_CORE4_ST 14 ++#define JH7110_SYSRST_TRACE0 15 ++#define JH7110_SYSRST_TRACE1 16 ++#define JH7110_SYSRST_TRACE2 17 ++#define JH7110_SYSRST_TRACE3 18 ++#define JH7110_SYSRST_TRACE4 19 ++#define JH7110_SYSRST_TRACE_COM 20 ++#define JH7110_SYSRST_GPU_APB 21 ++#define JH7110_SYSRST_GPU_DOMA 22 ++#define JH7110_SYSRST_NOC_BUS_APB 23 ++#define JH7110_SYSRST_NOC_BUS_AXICFG0_AXI 24 ++#define JH7110_SYSRST_NOC_BUS_CPU_AXI 25 ++#define JH7110_SYSRST_NOC_BUS_DISP_AXI 26 ++#define JH7110_SYSRST_NOC_BUS_GPU_AXI 27 ++#define JH7110_SYSRST_NOC_BUS_ISP_AXI 28 ++#define JH7110_SYSRST_NOC_BUS_DDRC 29 ++#define JH7110_SYSRST_NOC_BUS_STG_AXI 30 ++#define JH7110_SYSRST_NOC_BUS_VDEC_AXI 31 ++ ++#define JH7110_SYSRST_NOC_BUS_VENC_AXI 32 ++#define JH7110_SYSRST_AXI_CFG1_AHB 33 ++#define JH7110_SYSRST_AXI_CFG1_MAIN 34 ++#define JH7110_SYSRST_AXI_CFG0_MAIN 35 ++#define JH7110_SYSRST_AXI_CFG0_MAIN_DIV 36 ++#define JH7110_SYSRST_AXI_CFG0_HIFI4 37 ++#define JH7110_SYSRST_DDR_AXI 38 ++#define JH7110_SYSRST_DDR_OSC 39 ++#define JH7110_SYSRST_DDR_APB 40 ++#define JH7110_SYSRST_ISP_TOP 41 ++#define JH7110_SYSRST_ISP_TOP_AXI 42 ++#define JH7110_SYSRST_VOUT_TOP_SRC 43 ++#define JH7110_SYSRST_CODAJ12_AXI 44 ++#define JH7110_SYSRST_CODAJ12_CORE 45 ++#define JH7110_SYSRST_CODAJ12_APB 46 ++#define JH7110_SYSRST_WAVE511_AXI 47 ++#define JH7110_SYSRST_WAVE511_BPU 48 ++#define JH7110_SYSRST_WAVE511_VCE 49 ++#define JH7110_SYSRST_WAVE511_APB 50 ++#define JH7110_SYSRST_VDEC_JPG 51 ++#define JH7110_SYSRST_VDEC_MAIN 52 ++#define JH7110_SYSRST_AXIMEM0_AXI 53 ++#define JH7110_SYSRST_WAVE420L_AXI 54 ++#define JH7110_SYSRST_WAVE420L_BPU 55 ++#define JH7110_SYSRST_WAVE420L_VCE 56 ++#define JH7110_SYSRST_WAVE420L_APB 57 ++#define JH7110_SYSRST_AXIMEM1_AXI 58 ++#define JH7110_SYSRST_AXIMEM2_AXI 59 ++#define JH7110_SYSRST_INTMEM 60 ++#define JH7110_SYSRST_QSPI_AHB 61 ++#define JH7110_SYSRST_QSPI_APB 62 ++#define JH7110_SYSRST_QSPI_REF 63 ++ ++#define JH7110_SYSRST_SDIO0_AHB 64 ++#define JH7110_SYSRST_SDIO1_AHB 65 ++#define JH7110_SYSRST_GMAC1_AXI 66 ++#define JH7110_SYSRST_GMAC1_AHB 67 ++#define JH7110_SYSRST_MAILBOX_APB 68 ++#define JH7110_SYSRST_SPI0_APB 69 ++#define JH7110_SYSRST_SPI1_APB 70 ++#define JH7110_SYSRST_SPI2_APB 71 ++#define JH7110_SYSRST_SPI3_APB 72 ++#define JH7110_SYSRST_SPI4_APB 73 ++#define JH7110_SYSRST_SPI5_APB 74 ++#define JH7110_SYSRST_SPI6_APB 75 ++#define JH7110_SYSRST_I2C0_APB 76 ++#define JH7110_SYSRST_I2C1_APB 77 ++#define JH7110_SYSRST_I2C2_APB 78 ++#define JH7110_SYSRST_I2C3_APB 79 ++#define JH7110_SYSRST_I2C4_APB 80 ++#define JH7110_SYSRST_I2C5_APB 81 ++#define JH7110_SYSRST_I2C6_APB 82 ++#define JH7110_SYSRST_UART0_APB 83 ++#define JH7110_SYSRST_UART0_CORE 84 ++#define JH7110_SYSRST_UART1_APB 85 ++#define JH7110_SYSRST_UART1_CORE 86 ++#define JH7110_SYSRST_UART2_APB 87 ++#define JH7110_SYSRST_UART2_CORE 88 ++#define JH7110_SYSRST_UART3_APB 89 ++#define JH7110_SYSRST_UART3_CORE 90 ++#define JH7110_SYSRST_UART4_APB 91 ++#define JH7110_SYSRST_UART4_CORE 92 ++#define JH7110_SYSRST_UART5_APB 93 ++#define JH7110_SYSRST_UART5_CORE 94 ++#define JH7110_SYSRST_SPDIF_APB 95 ++ ++#define JH7110_SYSRST_PWMDAC_APB 96 ++#define JH7110_SYSRST_PDM_DMIC 97 ++#define JH7110_SYSRST_PDM_APB 98 ++#define JH7110_SYSRST_I2SRX_APB 99 ++#define JH7110_SYSRST_I2SRX_BCLK 100 ++#define JH7110_SYSRST_I2STX0_APB 101 ++#define JH7110_SYSRST_I2STX0_BCLK 102 ++#define JH7110_SYSRST_I2STX1_APB 103 ++#define JH7110_SYSRST_I2STX1_BCLK 104 ++#define JH7110_SYSRST_TDM_AHB 105 ++#define JH7110_SYSRST_TDM_CORE 106 ++#define JH7110_SYSRST_TDM_APB 107 ++#define JH7110_SYSRST_PWM_APB 108 ++#define JH7110_SYSRST_WDT_APB 109 ++#define JH7110_SYSRST_WDT_CORE 110 ++#define JH7110_SYSRST_CAN0_APB 111 ++#define JH7110_SYSRST_CAN0_CORE 112 ++#define JH7110_SYSRST_CAN0_TIMER 113 ++#define JH7110_SYSRST_CAN1_APB 114 ++#define JH7110_SYSRST_CAN1_CORE 115 ++#define JH7110_SYSRST_CAN1_TIMER 116 ++#define JH7110_SYSRST_TIMER_APB 117 ++#define JH7110_SYSRST_TIMER0 118 ++#define JH7110_SYSRST_TIMER1 119 ++#define JH7110_SYSRST_TIMER2 120 ++#define JH7110_SYSRST_TIMER3 121 ++#define JH7110_SYSRST_INT_CTRL_APB 122 ++#define JH7110_SYSRST_TEMP_APB 123 ++#define JH7110_SYSRST_TEMP_CORE 124 ++#define JH7110_SYSRST_JTAG_CERTIFICATION 125 ++ ++#define JH7110_SYSRST_END 126 ++ ++#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ */ diff --git a/target/linux/starfive/patches-6.1/0002-dt-bindings-clock-Add-StarFive-JH7110-always-on-cloc.patch b/target/linux/starfive/patches-6.1/0002-dt-bindings-clock-Add-StarFive-JH7110-always-on-cloc.patch new file mode 100644 index 0000000000..94cb575a71 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0002-dt-bindings-clock-Add-StarFive-JH7110-always-on-cloc.patch @@ -0,0 +1,176 @@ +From cd833f484009f37be57a2aa09257af6e8c1b25b6 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:14 +0800 +Subject: [PATCH 002/122] dt-bindings: clock: Add StarFive JH7110 always-on + clock and reset generator + +Add bindings for the always-on clock and reset generator (AONCRG) on the +JH7110 RISC-V SoC by StarFive Ltd. + +Reviewed-by: Conor Dooley +Reviewed-by: Rob Herring +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../clock/starfive,jh7110-aoncrg.yaml | 107 ++++++++++++++++++ + .../dt-bindings/clock/starfive,jh7110-crg.h | 18 +++ + .../dt-bindings/reset/starfive,jh7110-crg.h | 12 ++ + 3 files changed, 137 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-aoncrg.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-aoncrg.yaml +@@ -0,0 +1,107 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/starfive,jh7110-aoncrg.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 Always-On Clock and Reset Generator ++ ++maintainers: ++ - Emil Renner Berthing ++ ++properties: ++ compatible: ++ const: starfive,jh7110-aoncrg ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ oneOf: ++ - items: ++ - description: Main Oscillator (24 MHz) ++ - description: GMAC0 RMII reference or GMAC0 RGMII RX ++ - description: STG AXI/AHB ++ - description: APB Bus ++ - description: GMAC0 GTX ++ ++ - items: ++ - description: Main Oscillator (24 MHz) ++ - description: GMAC0 RMII reference or GMAC0 RGMII RX ++ - description: STG AXI/AHB or GMAC0 RGMII RX ++ - description: APB Bus or STG AXI/AHB ++ - description: GMAC0 GTX or APB Bus ++ - description: RTC Oscillator (32.768 kHz) or GMAC0 GTX ++ ++ - items: ++ - description: Main Oscillator (24 MHz) ++ - description: GMAC0 RMII reference ++ - description: GMAC0 RGMII RX ++ - description: STG AXI/AHB ++ - description: APB Bus ++ - description: GMAC0 GTX ++ - description: RTC Oscillator (32.768 kHz) ++ ++ clock-names: ++ oneOf: ++ - minItems: 5 ++ items: ++ - const: osc ++ - enum: ++ - gmac0_rmii_refin ++ - gmac0_rgmii_rxin ++ - const: stg_axiahb ++ - const: apb_bus ++ - const: gmac0_gtxclk ++ - const: rtc_osc ++ ++ - minItems: 6 ++ items: ++ - const: osc ++ - const: gmac0_rmii_refin ++ - const: gmac0_rgmii_rxin ++ - const: stg_axiahb ++ - const: apb_bus ++ - const: gmac0_gtxclk ++ - const: rtc_osc ++ ++ '#clock-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ '#reset-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - '#clock-cells' ++ - '#reset-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ clock-controller@17000000 { ++ compatible = "starfive,jh7110-aoncrg"; ++ reg = <0x17000000 0x10000>; ++ clocks = <&osc>, <&gmac0_rmii_refin>, ++ <&gmac0_rgmii_rxin>, ++ <&syscrg JH7110_SYSCLK_STG_AXIAHB>, ++ <&syscrg JH7110_SYSCLK_APB_BUS>, ++ <&syscrg JH7110_SYSCLK_GMAC0_GTXCLK>, ++ <&rtc_osc>; ++ clock-names = "osc", "gmac0_rmii_refin", ++ "gmac0_rgmii_rxin", "stg_axiahb", ++ "apb_bus", "gmac0_gtxclk", ++ "rtc_osc"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; +--- a/include/dt-bindings/clock/starfive,jh7110-crg.h ++++ b/include/dt-bindings/clock/starfive,jh7110-crg.h +@@ -200,4 +200,22 @@ + + #define JH7110_SYSCLK_END 190 + ++/* AONCRG clocks */ ++#define JH7110_AONCLK_OSC_DIV4 0 ++#define JH7110_AONCLK_APB_FUNC 1 ++#define JH7110_AONCLK_GMAC0_AHB 2 ++#define JH7110_AONCLK_GMAC0_AXI 3 ++#define JH7110_AONCLK_GMAC0_RMII_RTX 4 ++#define JH7110_AONCLK_GMAC0_TX 5 ++#define JH7110_AONCLK_GMAC0_TX_INV 6 ++#define JH7110_AONCLK_GMAC0_RX 7 ++#define JH7110_AONCLK_GMAC0_RX_INV 8 ++#define JH7110_AONCLK_OTPC_APB 9 ++#define JH7110_AONCLK_RTC_APB 10 ++#define JH7110_AONCLK_RTC_INTERNAL 11 ++#define JH7110_AONCLK_RTC_32K 12 ++#define JH7110_AONCLK_RTC_CAL 13 ++ ++#define JH7110_AONCLK_END 14 ++ + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ */ +--- a/include/dt-bindings/reset/starfive,jh7110-crg.h ++++ b/include/dt-bindings/reset/starfive,jh7110-crg.h +@@ -139,4 +139,16 @@ + + #define JH7110_SYSRST_END 126 + ++/* AONCRG resets */ ++#define JH7110_AONRST_GMAC0_AXI 0 ++#define JH7110_AONRST_GMAC0_AHB 1 ++#define JH7110_AONRST_IOMUX 2 ++#define JH7110_AONRST_PMU_APB 3 ++#define JH7110_AONRST_PMU_WKUP 4 ++#define JH7110_AONRST_RTC_APB 5 ++#define JH7110_AONRST_RTC_CAL 6 ++#define JH7110_AONRST_RTC_32K 7 ++ ++#define JH7110_AONRST_END 8 ++ + #endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ */ diff --git a/target/linux/starfive/patches-6.1/0003-clk-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFIVE.patch b/target/linux/starfive/patches-6.1/0003-clk-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFIVE.patch new file mode 100644 index 0000000000..1cedd313d9 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0003-clk-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFIVE.patch @@ -0,0 +1,53 @@ +From 124f322d1c42232e439ea9a356d68caf1d0656f3 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Sat, 1 Apr 2023 19:19:15 +0800 +Subject: [PATCH 003/122] clk: starfive: Replace SOC_STARFIVE with + ARCH_STARFIVE + +Using ARCH_FOO symbol is preferred than SOC_FOO. +Set obj-y for starfive/ in Makefile, so the StarFive drivers +can be compiled with COMPILE_TEST=y but ARCH_STARFIVE=n. + +Reviewed-by: Conor Dooley +Reviewed-by: Heiko Stuebner +Reviewed-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/clk/Makefile | 2 +- + drivers/clk/starfive/Kconfig | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -117,7 +117,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ + obj-y += sprd/ + obj-$(CONFIG_ARCH_STI) += st/ + obj-$(CONFIG_ARCH_STM32) += stm32/ +-obj-$(CONFIG_SOC_STARFIVE) += starfive/ ++obj-y += starfive/ + obj-$(CONFIG_ARCH_SUNXI) += sunxi/ + obj-y += sunxi-ng/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -2,8 +2,8 @@ + + config CLK_STARFIVE_JH7100 + bool "StarFive JH7100 clock support" +- depends on SOC_STARFIVE || COMPILE_TEST +- default SOC_STARFIVE ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ default ARCH_STARFIVE + help + Say yes here to support the clock controller on the StarFive JH7100 + SoC. +@@ -11,7 +11,7 @@ config CLK_STARFIVE_JH7100 + config CLK_STARFIVE_JH7100_AUDIO + tristate "StarFive JH7100 audio clock support" + depends on CLK_STARFIVE_JH7100 +- default m if SOC_STARFIVE ++ default m if ARCH_STARFIVE + help + Say Y or M here to support the audio clocks on the StarFive JH7100 + SoC. diff --git a/target/linux/starfive/patches-6.1/0004-clk-starfive-Factor-out-common-JH7100-and-JH7110-cod.patch b/target/linux/starfive/patches-6.1/0004-clk-starfive-Factor-out-common-JH7100-and-JH7110-cod.patch new file mode 100644 index 0000000000..72375bb0d9 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0004-clk-starfive-Factor-out-common-JH7100-and-JH7110-cod.patch @@ -0,0 +1,749 @@ +From 6f14eb919e5b92076e17aec5388655348963eef7 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:16 +0800 +Subject: [PATCH 004/122] clk: starfive: Factor out common JH7100 and JH7110 + code + +The clock control registers on the StarFive JH7100 and JH7110 work +identically, so factor out the code then drivers for the two SoCs +can share it without depending on each other. No functional change. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/clk/starfive/Kconfig | 5 + + drivers/clk/starfive/Makefile | 3 +- + drivers/clk/starfive/clk-starfive-jh7100.c | 325 -------------------- + drivers/clk/starfive/clk-starfive-jh7100.h | 2 + + drivers/clk/starfive/clk-starfive-jh71x0.c | 333 +++++++++++++++++++++ + 5 files changed, 342 insertions(+), 326 deletions(-) + create mode 100644 drivers/clk/starfive/clk-starfive-jh71x0.c + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -1,8 +1,12 @@ + # SPDX-License-Identifier: GPL-2.0 + ++config CLK_STARFIVE_JH71X0 ++ bool ++ + config CLK_STARFIVE_JH7100 + bool "StarFive JH7100 clock support" + depends on ARCH_STARFIVE || COMPILE_TEST ++ select CLK_STARFIVE_JH71X0 + default ARCH_STARFIVE + help + Say yes here to support the clock controller on the StarFive JH7100 +@@ -11,6 +15,7 @@ config CLK_STARFIVE_JH7100 + config CLK_STARFIVE_JH7100_AUDIO + tristate "StarFive JH7100 audio clock support" + depends on CLK_STARFIVE_JH7100 ++ select CLK_STARFIVE_JH71X0 + default m if ARCH_STARFIVE + help + Say Y or M here to support the audio clocks on the StarFive JH7100 +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +-# StarFive Clock ++obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o ++ + obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o + obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o +--- a/drivers/clk/starfive/clk-starfive-jh7100.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100.c +@@ -7,15 +7,10 @@ + * Copyright (C) 2021 Emil Renner Berthing + */ + +-#include + #include +-#include + #include + #include +-#include +-#include + #include +-#include + #include + + #include +@@ -269,326 +264,6 @@ static const struct jh7100_clk_data jh71 + JH7100_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), + }; + +-static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw) +-{ +- return container_of(hw, struct jh7100_clk, hw); +-} +- +-static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk) +-{ +- return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]); +-} +- +-static u32 jh7100_clk_reg_get(struct jh7100_clk *clk) +-{ +- struct jh7100_clk_priv *priv = jh7100_priv_from(clk); +- void __iomem *reg = priv->base + 4 * clk->idx; +- +- return readl_relaxed(reg); +-} +- +-static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value) +-{ +- struct jh7100_clk_priv *priv = jh7100_priv_from(clk); +- void __iomem *reg = priv->base + 4 * clk->idx; +- unsigned long flags; +- +- spin_lock_irqsave(&priv->rmw_lock, flags); +- value |= readl_relaxed(reg) & ~mask; +- writel_relaxed(value, reg); +- spin_unlock_irqrestore(&priv->rmw_lock, flags); +-} +- +-static int jh7100_clk_enable(struct clk_hw *hw) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- +- jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE); +- return 0; +-} +- +-static void jh7100_clk_disable(struct clk_hw *hw) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- +- jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0); +-} +- +-static int jh7100_clk_is_enabled(struct clk_hw *hw) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- +- return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE); +-} +- +-static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK; +- +- return div ? parent_rate / div : 0; +-} +- +-static int jh7100_clk_determine_rate(struct clk_hw *hw, +- struct clk_rate_request *req) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- unsigned long parent = req->best_parent_rate; +- unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); +- unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); +- unsigned long result = parent / div; +- +- /* +- * we want the result clamped by min_rate and max_rate if possible: +- * case 1: div hits the max divider value, which means it's less than +- * parent / rate, so the result is greater than rate and min_rate in +- * particular. we can't do anything about result > max_rate because the +- * divider doesn't go any further. +- * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is +- * always lower or equal to rate and max_rate. however the result may +- * turn out lower than min_rate, but then the next higher rate is fine: +- * div - 1 = ceil(parent / rate) - 1 < parent / rate +- * and thus +- * min_rate <= rate < parent / (div - 1) +- */ +- if (result < req->min_rate && div > 1) +- result = parent / (div - 1); +- +- req->rate = result; +- return 0; +-} +- +-static int jh7100_clk_set_rate(struct clk_hw *hw, +- unsigned long rate, +- unsigned long parent_rate) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), +- 1UL, (unsigned long)clk->max_div); +- +- jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div); +- return 0; +-} +- +-static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 reg = jh7100_clk_reg_get(clk); +- unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) + +- ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT); +- +- return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; +-} +- +-static int jh7100_clk_frac_determine_rate(struct clk_hw *hw, +- struct clk_rate_request *req) +-{ +- unsigned long parent100 = 100 * req->best_parent_rate; +- unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); +- unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), +- JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); +- unsigned long result = parent100 / div100; +- +- /* clamp the result as in jh7100_clk_determine_rate() above */ +- if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX) +- result = parent100 / (div100 + 1); +- if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN) +- result = parent100 / (div100 - 1); +- +- req->rate = result; +- return 0; +-} +- +-static int jh7100_clk_frac_set_rate(struct clk_hw *hw, +- unsigned long rate, +- unsigned long parent_rate) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), +- JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); +- u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100); +- +- jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value); +- return 0; +-} +- +-static u8 jh7100_clk_get_parent(struct clk_hw *hw) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value = jh7100_clk_reg_get(clk); +- +- return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT; +-} +- +-static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value = (u32)index << JH7100_CLK_MUX_SHIFT; +- +- jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value); +- return 0; +-} +- +-static int jh7100_clk_mux_determine_rate(struct clk_hw *hw, +- struct clk_rate_request *req) +-{ +- return clk_mux_determine_rate_flags(hw, req, 0); +-} +- +-static int jh7100_clk_get_phase(struct clk_hw *hw) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value = jh7100_clk_reg_get(clk); +- +- return (value & JH7100_CLK_INVERT) ? 180 : 0; +-} +- +-static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees) +-{ +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value; +- +- if (degrees == 0) +- value = 0; +- else if (degrees == 180) +- value = JH7100_CLK_INVERT; +- else +- return -EINVAL; +- +- jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value); +- return 0; +-} +- +-#ifdef CONFIG_DEBUG_FS +-static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) +-{ +- static const struct debugfs_reg32 jh7100_clk_reg = { +- .name = "CTRL", +- .offset = 0, +- }; +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- struct jh7100_clk_priv *priv = jh7100_priv_from(clk); +- struct debugfs_regset32 *regset; +- +- regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); +- if (!regset) +- return; +- +- regset->regs = &jh7100_clk_reg; +- regset->nregs = 1; +- regset->base = priv->base + 4 * clk->idx; +- +- debugfs_create_regset32("registers", 0400, dentry, regset); +-} +-#else +-#define jh7100_clk_debug_init NULL +-#endif +- +-static const struct clk_ops jh7100_clk_gate_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_div_ops = { +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_fdiv_ops = { +- .recalc_rate = jh7100_clk_frac_recalc_rate, +- .determine_rate = jh7100_clk_frac_determine_rate, +- .set_rate = jh7100_clk_frac_set_rate, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_gdiv_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_mux_ops = { +- .determine_rate = jh7100_clk_mux_determine_rate, +- .set_parent = jh7100_clk_set_parent, +- .get_parent = jh7100_clk_get_parent, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_gmux_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .determine_rate = jh7100_clk_mux_determine_rate, +- .set_parent = jh7100_clk_set_parent, +- .get_parent = jh7100_clk_get_parent, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_mdiv_ops = { +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .get_parent = jh7100_clk_get_parent, +- .set_parent = jh7100_clk_set_parent, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_gmd_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .get_parent = jh7100_clk_get_parent, +- .set_parent = jh7100_clk_set_parent, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-static const struct clk_ops jh7100_clk_inv_ops = { +- .get_phase = jh7100_clk_get_phase, +- .set_phase = jh7100_clk_set_phase, +- .debug_init = jh7100_clk_debug_init, +-}; +- +-const struct clk_ops *starfive_jh7100_clk_ops(u32 max) +-{ +- if (max & JH7100_CLK_DIV_MASK) { +- if (max & JH7100_CLK_MUX_MASK) { +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gmd_ops; +- return &jh7100_clk_mdiv_ops; +- } +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gdiv_ops; +- if (max == JH7100_CLK_FRAC_MAX) +- return &jh7100_clk_fdiv_ops; +- return &jh7100_clk_div_ops; +- } +- +- if (max & JH7100_CLK_MUX_MASK) { +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gmux_ops; +- return &jh7100_clk_mux_ops; +- } +- +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gate_ops; +- +- return &jh7100_clk_inv_ops; +-} +-EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops); +- + static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data) + { + struct jh7100_clk_priv *priv = data; +--- a/drivers/clk/starfive/clk-starfive-jh7100.h ++++ b/drivers/clk/starfive/clk-starfive-jh7100.h +@@ -4,6 +4,8 @@ + + #include + #include ++#include ++#include + + /* register fields */ + #define JH7100_CLK_ENABLE BIT(31) +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.c +@@ -0,0 +1,333 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7100 Clock Generator Driver ++ * ++ * Copyright (C) 2021-2022 Emil Renner Berthing ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "clk-starfive-jh7100.h" ++ ++static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw) ++{ ++ return container_of(hw, struct jh7100_clk, hw); ++} ++ ++static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk) ++{ ++ return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]); ++} ++ ++static u32 jh7100_clk_reg_get(struct jh7100_clk *clk) ++{ ++ struct jh7100_clk_priv *priv = jh7100_priv_from(clk); ++ void __iomem *reg = priv->base + 4 * clk->idx; ++ ++ return readl_relaxed(reg); ++} ++ ++static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value) ++{ ++ struct jh7100_clk_priv *priv = jh7100_priv_from(clk); ++ void __iomem *reg = priv->base + 4 * clk->idx; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->rmw_lock, flags); ++ value |= readl_relaxed(reg) & ~mask; ++ writel_relaxed(value, reg); ++ spin_unlock_irqrestore(&priv->rmw_lock, flags); ++} ++ ++static int jh7100_clk_enable(struct clk_hw *hw) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ ++ jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE); ++ return 0; ++} ++ ++static void jh7100_clk_disable(struct clk_hw *hw) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ ++ jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0); ++} ++ ++static int jh7100_clk_is_enabled(struct clk_hw *hw) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ ++ return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE); ++} ++ ++static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK; ++ ++ return div ? parent_rate / div : 0; ++} ++ ++static int jh7100_clk_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ unsigned long parent = req->best_parent_rate; ++ unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); ++ unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); ++ unsigned long result = parent / div; ++ ++ /* ++ * we want the result clamped by min_rate and max_rate if possible: ++ * case 1: div hits the max divider value, which means it's less than ++ * parent / rate, so the result is greater than rate and min_rate in ++ * particular. we can't do anything about result > max_rate because the ++ * divider doesn't go any further. ++ * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is ++ * always lower or equal to rate and max_rate. however the result may ++ * turn out lower than min_rate, but then the next higher rate is fine: ++ * div - 1 = ceil(parent / rate) - 1 < parent / rate ++ * and thus ++ * min_rate <= rate < parent / (div - 1) ++ */ ++ if (result < req->min_rate && div > 1) ++ result = parent / (div - 1); ++ ++ req->rate = result; ++ return 0; ++} ++ ++static int jh7100_clk_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), ++ 1UL, (unsigned long)clk->max_div); ++ ++ jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div); ++ return 0; ++} ++ ++static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ u32 reg = jh7100_clk_reg_get(clk); ++ unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) + ++ ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT); ++ ++ return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; ++} ++ ++static int jh7100_clk_frac_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ unsigned long parent100 = 100 * req->best_parent_rate; ++ unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); ++ unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), ++ JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); ++ unsigned long result = parent100 / div100; ++ ++ /* clamp the result as in jh7100_clk_determine_rate() above */ ++ if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX) ++ result = parent100 / (div100 + 1); ++ if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN) ++ result = parent100 / (div100 - 1); ++ ++ req->rate = result; ++ return 0; ++} ++ ++static int jh7100_clk_frac_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), ++ JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); ++ u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100); ++ ++ jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value); ++ return 0; ++} ++ ++static u8 jh7100_clk_get_parent(struct clk_hw *hw) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ u32 value = jh7100_clk_reg_get(clk); ++ ++ return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT; ++} ++ ++static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ u32 value = (u32)index << JH7100_CLK_MUX_SHIFT; ++ ++ jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value); ++ return 0; ++} ++ ++static int jh7100_clk_mux_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ return clk_mux_determine_rate_flags(hw, req, 0); ++} ++ ++static int jh7100_clk_get_phase(struct clk_hw *hw) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ u32 value = jh7100_clk_reg_get(clk); ++ ++ return (value & JH7100_CLK_INVERT) ? 180 : 0; ++} ++ ++static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees) ++{ ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ u32 value; ++ ++ if (degrees == 0) ++ value = 0; ++ else if (degrees == 180) ++ value = JH7100_CLK_INVERT; ++ else ++ return -EINVAL; ++ ++ jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value); ++ return 0; ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ static const struct debugfs_reg32 jh7100_clk_reg = { ++ .name = "CTRL", ++ .offset = 0, ++ }; ++ struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh7100_clk_priv *priv = jh7100_priv_from(clk); ++ struct debugfs_regset32 *regset; ++ ++ regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); ++ if (!regset) ++ return; ++ ++ regset->regs = &jh7100_clk_reg; ++ regset->nregs = 1; ++ regset->base = priv->base + 4 * clk->idx; ++ ++ debugfs_create_regset32("registers", 0400, dentry, regset); ++} ++#else ++#define jh7100_clk_debug_init NULL ++#endif ++ ++static const struct clk_ops jh7100_clk_gate_ops = { ++ .enable = jh7100_clk_enable, ++ .disable = jh7100_clk_disable, ++ .is_enabled = jh7100_clk_is_enabled, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_div_ops = { ++ .recalc_rate = jh7100_clk_recalc_rate, ++ .determine_rate = jh7100_clk_determine_rate, ++ .set_rate = jh7100_clk_set_rate, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_fdiv_ops = { ++ .recalc_rate = jh7100_clk_frac_recalc_rate, ++ .determine_rate = jh7100_clk_frac_determine_rate, ++ .set_rate = jh7100_clk_frac_set_rate, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_gdiv_ops = { ++ .enable = jh7100_clk_enable, ++ .disable = jh7100_clk_disable, ++ .is_enabled = jh7100_clk_is_enabled, ++ .recalc_rate = jh7100_clk_recalc_rate, ++ .determine_rate = jh7100_clk_determine_rate, ++ .set_rate = jh7100_clk_set_rate, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_mux_ops = { ++ .determine_rate = jh7100_clk_mux_determine_rate, ++ .set_parent = jh7100_clk_set_parent, ++ .get_parent = jh7100_clk_get_parent, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_gmux_ops = { ++ .enable = jh7100_clk_enable, ++ .disable = jh7100_clk_disable, ++ .is_enabled = jh7100_clk_is_enabled, ++ .determine_rate = jh7100_clk_mux_determine_rate, ++ .set_parent = jh7100_clk_set_parent, ++ .get_parent = jh7100_clk_get_parent, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_mdiv_ops = { ++ .recalc_rate = jh7100_clk_recalc_rate, ++ .determine_rate = jh7100_clk_determine_rate, ++ .get_parent = jh7100_clk_get_parent, ++ .set_parent = jh7100_clk_set_parent, ++ .set_rate = jh7100_clk_set_rate, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_gmd_ops = { ++ .enable = jh7100_clk_enable, ++ .disable = jh7100_clk_disable, ++ .is_enabled = jh7100_clk_is_enabled, ++ .recalc_rate = jh7100_clk_recalc_rate, ++ .determine_rate = jh7100_clk_determine_rate, ++ .get_parent = jh7100_clk_get_parent, ++ .set_parent = jh7100_clk_set_parent, ++ .set_rate = jh7100_clk_set_rate, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++static const struct clk_ops jh7100_clk_inv_ops = { ++ .get_phase = jh7100_clk_get_phase, ++ .set_phase = jh7100_clk_set_phase, ++ .debug_init = jh7100_clk_debug_init, ++}; ++ ++const struct clk_ops *starfive_jh7100_clk_ops(u32 max) ++{ ++ if (max & JH7100_CLK_DIV_MASK) { ++ if (max & JH7100_CLK_MUX_MASK) { ++ if (max & JH7100_CLK_ENABLE) ++ return &jh7100_clk_gmd_ops; ++ return &jh7100_clk_mdiv_ops; ++ } ++ if (max & JH7100_CLK_ENABLE) ++ return &jh7100_clk_gdiv_ops; ++ if (max == JH7100_CLK_FRAC_MAX) ++ return &jh7100_clk_fdiv_ops; ++ return &jh7100_clk_div_ops; ++ } ++ ++ if (max & JH7100_CLK_MUX_MASK) { ++ if (max & JH7100_CLK_ENABLE) ++ return &jh7100_clk_gmux_ops; ++ return &jh7100_clk_mux_ops; ++ } ++ ++ if (max & JH7100_CLK_ENABLE) ++ return &jh7100_clk_gate_ops; ++ ++ return &jh7100_clk_inv_ops; ++} ++EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops); diff --git a/target/linux/starfive/patches-6.1/0005-clk-starfive-Rename-clk-starfive-jh7100.h-to-clk-sta.patch b/target/linux/starfive/patches-6.1/0005-clk-starfive-Rename-clk-starfive-jh7100.h-to-clk-sta.patch new file mode 100644 index 0000000000..e9d0e7a71f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0005-clk-starfive-Rename-clk-starfive-jh7100.h-to-clk-sta.patch @@ -0,0 +1,290 @@ +From 8daa4c812f3b32a4d56ab48945e552a137fca9b7 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:17 +0800 +Subject: [PATCH 005/122] clk: starfive: Rename clk-starfive-jh7100.h to + clk-starfive-jh71x0.h + +Rename clk-starfive-jh7100.h to clk-starfive-jh71x0.h for making +the code to be common. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/clk/starfive/clk-starfive-jh7100-audio.c | 2 +- + drivers/clk/starfive/clk-starfive-jh7100.c | 2 +- + drivers/clk/starfive/clk-starfive-jh71x0.c | 2 +- + .../starfive/{clk-starfive-jh7100.h => clk-starfive-jh71x0.h} | 0 + 4 files changed, 3 insertions(+), 3 deletions(-) + rename drivers/clk/starfive/{clk-starfive-jh7100.h => clk-starfive-jh71x0.h} (100%) + +--- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c +@@ -16,7 +16,7 @@ + + #include + +-#include "clk-starfive-jh7100.h" ++#include "clk-starfive-jh71x0.h" + + /* external clocks */ + #define JH7100_AUDCLK_AUDIO_SRC (JH7100_AUDCLK_END + 0) +--- a/drivers/clk/starfive/clk-starfive-jh7100.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100.c +@@ -15,7 +15,7 @@ + + #include + +-#include "clk-starfive-jh7100.h" ++#include "clk-starfive-jh71x0.h" + + /* external clocks */ + #define JH7100_CLK_OSC_SYS (JH7100_CLK_END + 0) +--- a/drivers/clk/starfive/clk-starfive-jh71x0.c ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.c +@@ -10,7 +10,7 @@ + #include + #include + +-#include "clk-starfive-jh7100.h" ++#include "clk-starfive-jh71x0.h" + + static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw) + { +--- a/drivers/clk/starfive/clk-starfive-jh7100.h ++++ /dev/null +@@ -1,114 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef __CLK_STARFIVE_JH7100_H +-#define __CLK_STARFIVE_JH7100_H +- +-#include +-#include +-#include +-#include +- +-/* register fields */ +-#define JH7100_CLK_ENABLE BIT(31) +-#define JH7100_CLK_INVERT BIT(30) +-#define JH7100_CLK_MUX_MASK GENMASK(27, 24) +-#define JH7100_CLK_MUX_SHIFT 24 +-#define JH7100_CLK_DIV_MASK GENMASK(23, 0) +-#define JH7100_CLK_FRAC_MASK GENMASK(15, 8) +-#define JH7100_CLK_FRAC_SHIFT 8 +-#define JH7100_CLK_INT_MASK GENMASK(7, 0) +- +-/* fractional divider min/max */ +-#define JH7100_CLK_FRAC_MIN 100UL +-#define JH7100_CLK_FRAC_MAX 25599UL +- +-/* clock data */ +-struct jh7100_clk_data { +- const char *name; +- unsigned long flags; +- u32 max; +- u8 parents[4]; +-}; +- +-#define JH7100_GATE(_idx, _name, _flags, _parent) [_idx] = { \ +- .name = _name, \ +- .flags = CLK_SET_RATE_PARENT | (_flags), \ +- .max = JH7100_CLK_ENABLE, \ +- .parents = { [0] = _parent }, \ +-} +- +-#define JH7100__DIV(_idx, _name, _max, _parent) [_idx] = { \ +- .name = _name, \ +- .flags = 0, \ +- .max = _max, \ +- .parents = { [0] = _parent }, \ +-} +- +-#define JH7100_GDIV(_idx, _name, _flags, _max, _parent) [_idx] = { \ +- .name = _name, \ +- .flags = _flags, \ +- .max = JH7100_CLK_ENABLE | (_max), \ +- .parents = { [0] = _parent }, \ +-} +- +-#define JH7100_FDIV(_idx, _name, _parent) [_idx] = { \ +- .name = _name, \ +- .flags = 0, \ +- .max = JH7100_CLK_FRAC_MAX, \ +- .parents = { [0] = _parent }, \ +-} +- +-#define JH7100__MUX(_idx, _name, _nparents, ...) [_idx] = { \ +- .name = _name, \ +- .flags = 0, \ +- .max = ((_nparents) - 1) << JH7100_CLK_MUX_SHIFT, \ +- .parents = { __VA_ARGS__ }, \ +-} +- +-#define JH7100_GMUX(_idx, _name, _flags, _nparents, ...) [_idx] = { \ +- .name = _name, \ +- .flags = _flags, \ +- .max = JH7100_CLK_ENABLE | \ +- (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT), \ +- .parents = { __VA_ARGS__ }, \ +-} +- +-#define JH7100_MDIV(_idx, _name, _max, _nparents, ...) [_idx] = { \ +- .name = _name, \ +- .flags = 0, \ +- .max = (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ +- .parents = { __VA_ARGS__ }, \ +-} +- +-#define JH7100__GMD(_idx, _name, _flags, _max, _nparents, ...) [_idx] = { \ +- .name = _name, \ +- .flags = _flags, \ +- .max = JH7100_CLK_ENABLE | \ +- (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ +- .parents = { __VA_ARGS__ }, \ +-} +- +-#define JH7100__INV(_idx, _name, _parent) [_idx] = { \ +- .name = _name, \ +- .flags = CLK_SET_RATE_PARENT, \ +- .max = JH7100_CLK_INVERT, \ +- .parents = { [0] = _parent }, \ +-} +- +-struct jh7100_clk { +- struct clk_hw hw; +- unsigned int idx; +- unsigned int max_div; +-}; +- +-struct jh7100_clk_priv { +- /* protect clk enable and set rate/parent from happening at the same time */ +- spinlock_t rmw_lock; +- struct device *dev; +- void __iomem *base; +- struct clk_hw *pll[3]; +- struct jh7100_clk reg[]; +-}; +- +-const struct clk_ops *starfive_jh7100_clk_ops(u32 max); +- +-#endif +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.h +@@ -0,0 +1,114 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __CLK_STARFIVE_JH7100_H ++#define __CLK_STARFIVE_JH7100_H ++ ++#include ++#include ++#include ++#include ++ ++/* register fields */ ++#define JH7100_CLK_ENABLE BIT(31) ++#define JH7100_CLK_INVERT BIT(30) ++#define JH7100_CLK_MUX_MASK GENMASK(27, 24) ++#define JH7100_CLK_MUX_SHIFT 24 ++#define JH7100_CLK_DIV_MASK GENMASK(23, 0) ++#define JH7100_CLK_FRAC_MASK GENMASK(15, 8) ++#define JH7100_CLK_FRAC_SHIFT 8 ++#define JH7100_CLK_INT_MASK GENMASK(7, 0) ++ ++/* fractional divider min/max */ ++#define JH7100_CLK_FRAC_MIN 100UL ++#define JH7100_CLK_FRAC_MAX 25599UL ++ ++/* clock data */ ++struct jh7100_clk_data { ++ const char *name; ++ unsigned long flags; ++ u32 max; ++ u8 parents[4]; ++}; ++ ++#define JH7100_GATE(_idx, _name, _flags, _parent) [_idx] = { \ ++ .name = _name, \ ++ .flags = CLK_SET_RATE_PARENT | (_flags), \ ++ .max = JH7100_CLK_ENABLE, \ ++ .parents = { [0] = _parent }, \ ++} ++ ++#define JH7100__DIV(_idx, _name, _max, _parent) [_idx] = { \ ++ .name = _name, \ ++ .flags = 0, \ ++ .max = _max, \ ++ .parents = { [0] = _parent }, \ ++} ++ ++#define JH7100_GDIV(_idx, _name, _flags, _max, _parent) [_idx] = { \ ++ .name = _name, \ ++ .flags = _flags, \ ++ .max = JH7100_CLK_ENABLE | (_max), \ ++ .parents = { [0] = _parent }, \ ++} ++ ++#define JH7100_FDIV(_idx, _name, _parent) [_idx] = { \ ++ .name = _name, \ ++ .flags = 0, \ ++ .max = JH7100_CLK_FRAC_MAX, \ ++ .parents = { [0] = _parent }, \ ++} ++ ++#define JH7100__MUX(_idx, _name, _nparents, ...) [_idx] = { \ ++ .name = _name, \ ++ .flags = 0, \ ++ .max = ((_nparents) - 1) << JH7100_CLK_MUX_SHIFT, \ ++ .parents = { __VA_ARGS__ }, \ ++} ++ ++#define JH7100_GMUX(_idx, _name, _flags, _nparents, ...) [_idx] = { \ ++ .name = _name, \ ++ .flags = _flags, \ ++ .max = JH7100_CLK_ENABLE | \ ++ (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT), \ ++ .parents = { __VA_ARGS__ }, \ ++} ++ ++#define JH7100_MDIV(_idx, _name, _max, _nparents, ...) [_idx] = { \ ++ .name = _name, \ ++ .flags = 0, \ ++ .max = (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ ++ .parents = { __VA_ARGS__ }, \ ++} ++ ++#define JH7100__GMD(_idx, _name, _flags, _max, _nparents, ...) [_idx] = { \ ++ .name = _name, \ ++ .flags = _flags, \ ++ .max = JH7100_CLK_ENABLE | \ ++ (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ ++ .parents = { __VA_ARGS__ }, \ ++} ++ ++#define JH7100__INV(_idx, _name, _parent) [_idx] = { \ ++ .name = _name, \ ++ .flags = CLK_SET_RATE_PARENT, \ ++ .max = JH7100_CLK_INVERT, \ ++ .parents = { [0] = _parent }, \ ++} ++ ++struct jh7100_clk { ++ struct clk_hw hw; ++ unsigned int idx; ++ unsigned int max_div; ++}; ++ ++struct jh7100_clk_priv { ++ /* protect clk enable and set rate/parent from happening at the same time */ ++ spinlock_t rmw_lock; ++ struct device *dev; ++ void __iomem *base; ++ struct clk_hw *pll[3]; ++ struct jh7100_clk reg[]; ++}; ++ ++const struct clk_ops *starfive_jh7100_clk_ops(u32 max); ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0006-clk-starfive-Rename-jh7100-to-jh71x0-for-the-common-.patch b/target/linux/starfive/patches-6.1/0006-clk-starfive-Rename-jh7100-to-jh71x0-for-the-common-.patch new file mode 100644 index 0000000000..60ebf2cc0a --- /dev/null +++ b/target/linux/starfive/patches-6.1/0006-clk-starfive-Rename-jh7100-to-jh71x0-for-the-common-.patch @@ -0,0 +1,1249 @@ +From 674fa25b207e4bef6c27af2acfbca3a0d765a45b Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:18 +0800 +Subject: [PATCH 006/122] clk: starfive: Rename "jh7100" to "jh71x0" for the + common code + +Rename some variables from "jh7100" or "JH7100" to "jh71x0" +or "JH71X0". + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../clk/starfive/clk-starfive-jh7100-audio.c | 72 ++-- + drivers/clk/starfive/clk-starfive-jh7100.c | 389 +++++++++--------- + drivers/clk/starfive/clk-starfive-jh71x0.c | 282 ++++++------- + drivers/clk/starfive/clk-starfive-jh71x0.h | 81 ++-- + 4 files changed, 418 insertions(+), 406 deletions(-) + +--- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c +@@ -28,66 +28,66 @@ + #define JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD (JH7100_AUDCLK_END + 6) + #define JH7100_AUDCLK_VAD_INTMEM (JH7100_AUDCLK_END + 7) + +-static const struct jh7100_clk_data jh7100_audclk_data[] = { +- JH7100__GMD(JH7100_AUDCLK_ADC_MCLK, "adc_mclk", 0, 15, 2, ++static const struct jh71x0_clk_data jh7100_audclk_data[] = { ++ JH71X0__GMD(JH7100_AUDCLK_ADC_MCLK, "adc_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), +- JH7100__GMD(JH7100_AUDCLK_I2S1_MCLK, "i2s1_mclk", 0, 15, 2, ++ JH71X0__GMD(JH7100_AUDCLK_I2S1_MCLK, "i2s1_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), +- JH7100_GATE(JH7100_AUDCLK_I2SADC_APB, "i2sadc_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100_MDIV(JH7100_AUDCLK_I2SADC_BCLK, "i2sadc_bclk", 31, 2, ++ JH71X0_GATE(JH7100_AUDCLK_I2SADC_APB, "i2sadc_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0_MDIV(JH7100_AUDCLK_I2SADC_BCLK, "i2sadc_bclk", 31, 2, + JH7100_AUDCLK_ADC_MCLK, + JH7100_AUDCLK_I2SADC_BCLK_IOPAD), +- JH7100__INV(JH7100_AUDCLK_I2SADC_BCLK_N, "i2sadc_bclk_n", JH7100_AUDCLK_I2SADC_BCLK), +- JH7100_MDIV(JH7100_AUDCLK_I2SADC_LRCLK, "i2sadc_lrclk", 63, 3, ++ JH71X0__INV(JH7100_AUDCLK_I2SADC_BCLK_N, "i2sadc_bclk_n", JH7100_AUDCLK_I2SADC_BCLK), ++ JH71X0_MDIV(JH7100_AUDCLK_I2SADC_LRCLK, "i2sadc_lrclk", 63, 3, + JH7100_AUDCLK_I2SADC_BCLK_N, + JH7100_AUDCLK_I2SADC_LRCLK_IOPAD, + JH7100_AUDCLK_I2SADC_BCLK), +- JH7100_GATE(JH7100_AUDCLK_PDM_APB, "pdm_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100__GMD(JH7100_AUDCLK_PDM_MCLK, "pdm_mclk", 0, 15, 2, ++ JH71X0_GATE(JH7100_AUDCLK_PDM_APB, "pdm_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0__GMD(JH7100_AUDCLK_PDM_MCLK, "pdm_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), +- JH7100_GATE(JH7100_AUDCLK_I2SVAD_APB, "i2svad_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100__GMD(JH7100_AUDCLK_SPDIF, "spdif", 0, 15, 2, ++ JH71X0_GATE(JH7100_AUDCLK_I2SVAD_APB, "i2svad_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0__GMD(JH7100_AUDCLK_SPDIF, "spdif", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), +- JH7100_GATE(JH7100_AUDCLK_SPDIF_APB, "spdif_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100_GATE(JH7100_AUDCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100__GMD(JH7100_AUDCLK_DAC_MCLK, "dac_mclk", 0, 15, 2, ++ JH71X0_GATE(JH7100_AUDCLK_SPDIF_APB, "spdif_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0_GATE(JH7100_AUDCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0__GMD(JH7100_AUDCLK_DAC_MCLK, "dac_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), +- JH7100_GATE(JH7100_AUDCLK_I2SDAC_APB, "i2sdac_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100_MDIV(JH7100_AUDCLK_I2SDAC_BCLK, "i2sdac_bclk", 31, 2, ++ JH71X0_GATE(JH7100_AUDCLK_I2SDAC_APB, "i2sdac_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0_MDIV(JH7100_AUDCLK_I2SDAC_BCLK, "i2sdac_bclk", 31, 2, + JH7100_AUDCLK_DAC_MCLK, + JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), +- JH7100__INV(JH7100_AUDCLK_I2SDAC_BCLK_N, "i2sdac_bclk_n", JH7100_AUDCLK_I2SDAC_BCLK), +- JH7100_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 31, 2, ++ JH71X0__INV(JH7100_AUDCLK_I2SDAC_BCLK_N, "i2sdac_bclk_n", JH7100_AUDCLK_I2SDAC_BCLK), ++ JH71X0_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 31, 2, + JH7100_AUDCLK_I2S1_MCLK, + JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), +- JH7100_GATE(JH7100_AUDCLK_I2S1_APB, "i2s1_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100_MDIV(JH7100_AUDCLK_I2S1_BCLK, "i2s1_bclk", 31, 2, ++ JH71X0_GATE(JH7100_AUDCLK_I2S1_APB, "i2s1_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0_MDIV(JH7100_AUDCLK_I2S1_BCLK, "i2s1_bclk", 31, 2, + JH7100_AUDCLK_I2S1_MCLK, + JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), +- JH7100__INV(JH7100_AUDCLK_I2S1_BCLK_N, "i2s1_bclk_n", JH7100_AUDCLK_I2S1_BCLK), +- JH7100_MDIV(JH7100_AUDCLK_I2S1_LRCLK, "i2s1_lrclk", 63, 3, ++ JH71X0__INV(JH7100_AUDCLK_I2S1_BCLK_N, "i2s1_bclk_n", JH7100_AUDCLK_I2S1_BCLK), ++ JH71X0_MDIV(JH7100_AUDCLK_I2S1_LRCLK, "i2s1_lrclk", 63, 3, + JH7100_AUDCLK_I2S1_BCLK_N, + JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD), +- JH7100_GATE(JH7100_AUDCLK_I2SDAC16K_APB, "i2s1dac16k_apb", 0, JH7100_AUDCLK_APB0_BUS), +- JH7100__DIV(JH7100_AUDCLK_APB0_BUS, "apb0_bus", 8, JH7100_AUDCLK_DOM7AHB_BUS), +- JH7100_GATE(JH7100_AUDCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7100_AUDCLK_DOM7AHB_BUS), +- JH7100_GATE(JH7100_AUDCLK_USB_APB, "usb_apb", CLK_IGNORE_UNUSED, JH7100_AUDCLK_APB_EN), +- JH7100_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), +- JH7100_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), +- JH7100__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), +- JH7100__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2, ++ JH71X0_GATE(JH7100_AUDCLK_I2SDAC16K_APB, "i2s1dac16k_apb", 0, JH7100_AUDCLK_APB0_BUS), ++ JH71X0__DIV(JH7100_AUDCLK_APB0_BUS, "apb0_bus", 8, JH7100_AUDCLK_DOM7AHB_BUS), ++ JH71X0_GATE(JH7100_AUDCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7100_AUDCLK_DOM7AHB_BUS), ++ JH71X0_GATE(JH7100_AUDCLK_USB_APB, "usb_apb", CLK_IGNORE_UNUSED, JH7100_AUDCLK_APB_EN), ++ JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), ++ JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), ++ JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), ++ JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2, + JH7100_AUDCLK_VAD_INTMEM, + JH7100_AUDCLK_AUDIO_12288), + }; + + static struct clk_hw *jh7100_audclk_get(struct of_phandle_args *clkspec, void *data) + { +- struct jh7100_clk_priv *priv = data; ++ struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7100_AUDCLK_END) +@@ -98,7 +98,7 @@ static struct clk_hw *jh7100_audclk_get( + + static int jh7100_audclk_probe(struct platform_device *pdev) + { +- struct jh7100_clk_priv *priv; ++ struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + +@@ -117,12 +117,12 @@ static int jh7100_audclk_probe(struct pl + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7100_audclk_data[idx].name, +- .ops = starfive_jh7100_clk_ops(max), ++ .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, +- .num_parents = ((max & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT) + 1, ++ .num_parents = ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7100_audclk_data[idx].flags, + }; +- struct jh7100_clk *clk = &priv->reg[idx]; ++ struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { +@@ -140,7 +140,7 @@ static int jh7100_audclk_probe(struct pl + + clk->hw.init = &init; + clk->idx = idx; +- clk->max_div = max & JH7100_CLK_DIV_MASK; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(priv->dev, &clk->hw); + if (ret) +--- a/drivers/clk/starfive/clk-starfive-jh7100.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100.c +@@ -23,250 +23,253 @@ + #define JH7100_CLK_GMAC_RMII_REF (JH7100_CLK_END + 2) + #define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3) + +-static const struct jh7100_clk_data jh7100_clk_data[] __initconst = { +- JH7100__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, ++static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { ++ JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, ++ JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, ++ JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, ++ JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, ++ JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT), +- JH7100__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, ++ JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, ++ JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, ++ JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, + JH7100_CLK_OSC_AUD, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), +- JH7100__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, ++ JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), ++ JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, ++ JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT), +- JH7100__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, ++ JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, + JH7100_CLK_OSC_AUD, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), +- JH7100__DIV(JH7100_CLK_CPUNBUS_ROOT_DIV, "cpunbus_root_div", 2, JH7100_CLK_CPUNDBUS_ROOT), +- JH7100__DIV(JH7100_CLK_DSP_ROOT_DIV, "dsp_root_div", 4, JH7100_CLK_DSP_ROOT), +- JH7100__DIV(JH7100_CLK_PERH0_SRC, "perh0_src", 4, JH7100_CLK_PERH0_ROOT), +- JH7100__DIV(JH7100_CLK_PERH1_SRC, "perh1_src", 4, JH7100_CLK_PERH1_ROOT), +- JH7100_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), +- JH7100_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), +- JH7100__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, ++ JH71X0__DIV(JH7100_CLK_CPUNBUS_ROOT_DIV, "cpunbus_root_div", 2, JH7100_CLK_CPUNDBUS_ROOT), ++ JH71X0__DIV(JH7100_CLK_DSP_ROOT_DIV, "dsp_root_div", 4, JH7100_CLK_DSP_ROOT), ++ JH71X0__DIV(JH7100_CLK_PERH0_SRC, "perh0_src", 4, JH7100_CLK_PERH0_ROOT), ++ JH71X0__DIV(JH7100_CLK_PERH1_SRC, "perh1_src", 4, JH7100_CLK_PERH1_ROOT), ++ JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), ++ JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), ++ JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_OSC_AUD), +- JH7100__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100__DIV(JH7100_CLK_CPU_AXI, "cpu_axi", 8, JH7100_CLK_CPU_CORE), +- JH7100__DIV(JH7100_CLK_AHB_BUS, "ahb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100__DIV(JH7100_CLK_APB1_BUS, "apb1_bus", 8, JH7100_CLK_AHB_BUS), +- JH7100__DIV(JH7100_CLK_APB2_BUS, "apb2_bus", 8, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_DOM3AHB_BUS, "dom3ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_DOM7AHB_BUS, "dom7ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_U74_CORE0, "u74_core0", CLK_IS_CRITICAL, JH7100_CLK_CPU_CORE), +- JH7100_GDIV(JH7100_CLK_U74_CORE1, "u74_core1", CLK_IS_CRITICAL, 8, JH7100_CLK_CPU_CORE), +- JH7100_GATE(JH7100_CLK_U74_AXI, "u74_axi", CLK_IS_CRITICAL, JH7100_CLK_CPU_AXI), +- JH7100_GATE(JH7100_CLK_U74RTC_TOGGLE, "u74rtc_toggle", CLK_IS_CRITICAL, JH7100_CLK_OSC_SYS), +- JH7100_GATE(JH7100_CLK_SGDMA2P_AXI, "sgdma2p_axi", 0, JH7100_CLK_CPU_AXI), +- JH7100_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI), +- JH7100_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT), +- JH7100_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS), +- JH7100_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS), +- JH7100_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV), +- JH7100__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT), +- JH7100_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC), +- JH7100__DIV(JH7100_CLK_VCDECBUS_SRC, "vcdecbus_src", 4, JH7100_CLK_CDECHIFI4_ROOT), +- JH7100__DIV(JH7100_CLK_VDEC_BUS, "vdec_bus", 8, JH7100_CLK_VCDECBUS_SRC), +- JH7100_GATE(JH7100_CLK_VDEC_AXI, "vdec_axi", 0, JH7100_CLK_VDEC_BUS), +- JH7100_GATE(JH7100_CLK_VDECBRG_MAIN, "vdecbrg_mainclk", 0, JH7100_CLK_VDEC_BUS), +- JH7100_GDIV(JH7100_CLK_VDEC_BCLK, "vdec_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), +- JH7100_GDIV(JH7100_CLK_VDEC_CCLK, "vdec_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), +- JH7100_GATE(JH7100_CLK_VDEC_APB, "vdec_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_JPEG_AXI, "jpeg_axi", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100_GDIV(JH7100_CLK_JPEG_CCLK, "jpeg_cclk", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100_GATE(JH7100_CLK_JPEG_APB, "jpeg_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_GC300_2X, "gc300_2x", 0, 8, JH7100_CLK_CDECHIFI4_ROOT), +- JH7100_GATE(JH7100_CLK_GC300_AHB, "gc300_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100__DIV(JH7100_CLK_JPCGC300_AXIBUS, "jpcgc300_axibus", 8, JH7100_CLK_VCDECBUS_SRC), +- JH7100_GATE(JH7100_CLK_GC300_AXI, "gc300_axi", 0, JH7100_CLK_JPCGC300_AXIBUS), +- JH7100_GATE(JH7100_CLK_JPCGC300_MAIN, "jpcgc300_mainclk", 0, JH7100_CLK_JPCGC300_AXIBUS), +- JH7100__DIV(JH7100_CLK_VENC_BUS, "venc_bus", 8, JH7100_CLK_VCDECBUS_SRC), +- JH7100_GATE(JH7100_CLK_VENC_AXI, "venc_axi", 0, JH7100_CLK_VENC_BUS), +- JH7100_GATE(JH7100_CLK_VENCBRG_MAIN, "vencbrg_mainclk", 0, JH7100_CLK_VENC_BUS), +- JH7100_GDIV(JH7100_CLK_VENC_BCLK, "venc_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), +- JH7100_GDIV(JH7100_CLK_VENC_CCLK, "venc_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), +- JH7100_GATE(JH7100_CLK_VENC_APB, "venc_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_DDRPLL_DIV2, "ddrpll_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_PLL1_OUT), +- JH7100_GDIV(JH7100_CLK_DDRPLL_DIV4, "ddrpll_div4", CLK_IS_CRITICAL, 2, JH7100_CLK_DDRPLL_DIV2), +- JH7100_GDIV(JH7100_CLK_DDRPLL_DIV8, "ddrpll_div8", CLK_IS_CRITICAL, 2, JH7100_CLK_DDRPLL_DIV4), +- JH7100_GDIV(JH7100_CLK_DDROSC_DIV2, "ddrosc_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_OSC_SYS), +- JH7100_GMUX(JH7100_CLK_DDRC0, "ddrc0", CLK_IS_CRITICAL, 4, ++ JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0__DIV(JH7100_CLK_CPU_AXI, "cpu_axi", 8, JH7100_CLK_CPU_CORE), ++ JH71X0__DIV(JH7100_CLK_AHB_BUS, "ahb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0__DIV(JH7100_CLK_APB1_BUS, "apb1_bus", 8, JH7100_CLK_AHB_BUS), ++ JH71X0__DIV(JH7100_CLK_APB2_BUS, "apb2_bus", 8, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_DOM3AHB_BUS, "dom3ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_DOM7AHB_BUS, "dom7ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_U74_CORE0, "u74_core0", CLK_IS_CRITICAL, JH7100_CLK_CPU_CORE), ++ JH71X0_GDIV(JH7100_CLK_U74_CORE1, "u74_core1", CLK_IS_CRITICAL, 8, JH7100_CLK_CPU_CORE), ++ JH71X0_GATE(JH7100_CLK_U74_AXI, "u74_axi", CLK_IS_CRITICAL, JH7100_CLK_CPU_AXI), ++ JH71X0_GATE(JH7100_CLK_U74RTC_TOGGLE, "u74rtc_toggle", CLK_IS_CRITICAL, JH7100_CLK_OSC_SYS), ++ JH71X0_GATE(JH7100_CLK_SGDMA2P_AXI, "sgdma2p_axi", 0, JH7100_CLK_CPU_AXI), ++ 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_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), ++ JH71X0__DIV(JH7100_CLK_VCDECBUS_SRC, "vcdecbus_src", 4, JH7100_CLK_CDECHIFI4_ROOT), ++ JH71X0__DIV(JH7100_CLK_VDEC_BUS, "vdec_bus", 8, JH7100_CLK_VCDECBUS_SRC), ++ JH71X0_GATE(JH7100_CLK_VDEC_AXI, "vdec_axi", 0, JH7100_CLK_VDEC_BUS), ++ JH71X0_GATE(JH7100_CLK_VDECBRG_MAIN, "vdecbrg_mainclk", 0, JH7100_CLK_VDEC_BUS), ++ JH71X0_GDIV(JH7100_CLK_VDEC_BCLK, "vdec_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), ++ JH71X0_GDIV(JH7100_CLK_VDEC_CCLK, "vdec_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), ++ JH71X0_GATE(JH7100_CLK_VDEC_APB, "vdec_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_JPEG_AXI, "jpeg_axi", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0_GDIV(JH7100_CLK_JPEG_CCLK, "jpeg_cclk", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0_GATE(JH7100_CLK_JPEG_APB, "jpeg_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_GC300_2X, "gc300_2x", 0, 8, JH7100_CLK_CDECHIFI4_ROOT), ++ JH71X0_GATE(JH7100_CLK_GC300_AHB, "gc300_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0__DIV(JH7100_CLK_JPCGC300_AXIBUS, "jpcgc300_axibus", 8, JH7100_CLK_VCDECBUS_SRC), ++ JH71X0_GATE(JH7100_CLK_GC300_AXI, "gc300_axi", 0, JH7100_CLK_JPCGC300_AXIBUS), ++ JH71X0_GATE(JH7100_CLK_JPCGC300_MAIN, "jpcgc300_mainclk", 0, JH7100_CLK_JPCGC300_AXIBUS), ++ JH71X0__DIV(JH7100_CLK_VENC_BUS, "venc_bus", 8, JH7100_CLK_VCDECBUS_SRC), ++ JH71X0_GATE(JH7100_CLK_VENC_AXI, "venc_axi", 0, JH7100_CLK_VENC_BUS), ++ JH71X0_GATE(JH7100_CLK_VENCBRG_MAIN, "vencbrg_mainclk", 0, JH7100_CLK_VENC_BUS), ++ JH71X0_GDIV(JH7100_CLK_VENC_BCLK, "venc_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), ++ JH71X0_GDIV(JH7100_CLK_VENC_CCLK, "venc_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), ++ JH71X0_GATE(JH7100_CLK_VENC_APB, "venc_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV2, "ddrpll_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_PLL1_OUT), ++ JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV4, "ddrpll_div4", CLK_IS_CRITICAL, 2, ++ JH7100_CLK_DDRPLL_DIV2), ++ JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV8, "ddrpll_div8", CLK_IS_CRITICAL, 2, ++ JH7100_CLK_DDRPLL_DIV4), ++ JH71X0_GDIV(JH7100_CLK_DDROSC_DIV2, "ddrosc_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_OSC_SYS), ++ JH71X0_GMUX(JH7100_CLK_DDRC0, "ddrc0", CLK_IS_CRITICAL, 4, + JH7100_CLK_DDROSC_DIV2, + JH7100_CLK_DDRPLL_DIV2, + JH7100_CLK_DDRPLL_DIV4, + JH7100_CLK_DDRPLL_DIV8), +- JH7100_GMUX(JH7100_CLK_DDRC1, "ddrc1", CLK_IS_CRITICAL, 4, ++ JH71X0_GMUX(JH7100_CLK_DDRC1, "ddrc1", CLK_IS_CRITICAL, 4, + JH7100_CLK_DDROSC_DIV2, + JH7100_CLK_DDRPLL_DIV2, + JH7100_CLK_DDRPLL_DIV4, + JH7100_CLK_DDRPLL_DIV8), +- JH7100_GATE(JH7100_CLK_DDRPHY_APB, "ddrphy_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100__DIV(JH7100_CLK_NOC_ROB, "noc_rob", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), +- JH7100_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), +- JH7100__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, ++ JH71X0_GATE(JH7100_CLK_DDRPHY_APB, "ddrphy_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0__DIV(JH7100_CLK_NOC_ROB, "noc_rob", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), ++ JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), ++ JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, + JH7100_CLK_CPU_AXI, + JH7100_CLK_NNEBUS_SRC1), +- JH7100_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), +- JH7100_GATE(JH7100_CLK_NNENOC_AXI, "nnenoc_axi", 0, JH7100_CLK_NNE_BUS), +- JH7100_GATE(JH7100_CLK_DLASLV_AXI, "dlaslv_axi", 0, JH7100_CLK_NNE_BUS), +- JH7100_GATE(JH7100_CLK_DSPX2C_AXI, "dspx2c_axi", CLK_IS_CRITICAL, JH7100_CLK_NNE_BUS), +- JH7100__DIV(JH7100_CLK_HIFI4_SRC, "hifi4_src", 4, JH7100_CLK_CDECHIFI4_ROOT), +- JH7100__DIV(JH7100_CLK_HIFI4_COREFREE, "hifi4_corefree", 8, JH7100_CLK_HIFI4_SRC), +- JH7100_GATE(JH7100_CLK_HIFI4_CORE, "hifi4_core", 0, JH7100_CLK_HIFI4_COREFREE), +- JH7100__DIV(JH7100_CLK_HIFI4_BUS, "hifi4_bus", 8, JH7100_CLK_HIFI4_COREFREE), +- JH7100_GATE(JH7100_CLK_HIFI4_AXI, "hifi4_axi", 0, JH7100_CLK_HIFI4_BUS), +- JH7100_GATE(JH7100_CLK_HIFI4NOC_AXI, "hifi4noc_axi", 0, JH7100_CLK_HIFI4_BUS), +- JH7100__DIV(JH7100_CLK_SGDMA1P_BUS, "sgdma1p_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100_GATE(JH7100_CLK_SGDMA1P_AXI, "sgdma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), +- JH7100_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), +- JH7100_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- JH7100_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS), +- JH7100_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS), +- JH7100__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT), +- JH7100_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), +- JH7100_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, JH7100_CLK_USBPHY_ROOTDIV), +- JH7100__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, ++ JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), ++ JH71X0_GATE(JH7100_CLK_NNENOC_AXI, "nnenoc_axi", 0, JH7100_CLK_NNE_BUS), ++ JH71X0_GATE(JH7100_CLK_DLASLV_AXI, "dlaslv_axi", 0, JH7100_CLK_NNE_BUS), ++ JH71X0_GATE(JH7100_CLK_DSPX2C_AXI, "dspx2c_axi", CLK_IS_CRITICAL, JH7100_CLK_NNE_BUS), ++ JH71X0__DIV(JH7100_CLK_HIFI4_SRC, "hifi4_src", 4, JH7100_CLK_CDECHIFI4_ROOT), ++ JH71X0__DIV(JH7100_CLK_HIFI4_COREFREE, "hifi4_corefree", 8, JH7100_CLK_HIFI4_SRC), ++ JH71X0_GATE(JH7100_CLK_HIFI4_CORE, "hifi4_core", 0, JH7100_CLK_HIFI4_COREFREE), ++ JH71X0__DIV(JH7100_CLK_HIFI4_BUS, "hifi4_bus", 8, JH7100_CLK_HIFI4_COREFREE), ++ JH71X0_GATE(JH7100_CLK_HIFI4_AXI, "hifi4_axi", 0, JH7100_CLK_HIFI4_BUS), ++ JH71X0_GATE(JH7100_CLK_HIFI4NOC_AXI, "hifi4noc_axi", 0, JH7100_CLK_HIFI4_BUS), ++ JH71X0__DIV(JH7100_CLK_SGDMA1P_BUS, "sgdma1p_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0_GATE(JH7100_CLK_SGDMA1P_AXI, "sgdma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), ++ JH71X0_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), ++ JH71X0_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ JH71X0__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), ++ 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, ++ JH7100_CLK_USBPHY_ROOTDIV), ++ JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_USBPHY_PLLDIV25M), +- JH7100_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), +- JH7100_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV), +- JH7100_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD), +- JH7100_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT), +- JH7100__DIV(JH7100_CLK_ISP0_BUS, "isp0_bus", 8, JH7100_CLK_VIN_SRC), +- JH7100_GATE(JH7100_CLK_ISP0_AXI, "isp0_axi", 0, JH7100_CLK_ISP0_BUS), +- JH7100_GATE(JH7100_CLK_ISP0NOC_AXI, "isp0noc_axi", 0, JH7100_CLK_ISP0_BUS), +- JH7100_GATE(JH7100_CLK_ISPSLV_AXI, "ispslv_axi", 0, JH7100_CLK_ISP0_BUS), +- JH7100__DIV(JH7100_CLK_ISP1_BUS, "isp1_bus", 8, JH7100_CLK_VIN_SRC), +- JH7100_GATE(JH7100_CLK_ISP1_AXI, "isp1_axi", 0, JH7100_CLK_ISP1_BUS), +- JH7100_GATE(JH7100_CLK_ISP1NOC_AXI, "isp1noc_axi", 0, JH7100_CLK_ISP1_BUS), +- JH7100__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC), +- JH7100_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS), +- JH7100_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS), +- JH7100_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT), +- JH7100__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT), +- JH7100__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC), +- JH7100_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS), +- JH7100_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS), +- JH7100_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC), +- JH7100__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT), +- JH7100_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), +- JH7100__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), +- JH7100_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), +- JH7100_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), +- JH7100_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), +- JH7100_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), +- JH7100_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), +- JH7100__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, ++ JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), ++ JH71X0_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV), ++ JH71X0_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD), ++ JH71X0_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT), ++ JH71X0__DIV(JH7100_CLK_ISP0_BUS, "isp0_bus", 8, JH7100_CLK_VIN_SRC), ++ JH71X0_GATE(JH7100_CLK_ISP0_AXI, "isp0_axi", 0, JH7100_CLK_ISP0_BUS), ++ JH71X0_GATE(JH7100_CLK_ISP0NOC_AXI, "isp0noc_axi", 0, JH7100_CLK_ISP0_BUS), ++ JH71X0_GATE(JH7100_CLK_ISPSLV_AXI, "ispslv_axi", 0, JH7100_CLK_ISP0_BUS), ++ JH71X0__DIV(JH7100_CLK_ISP1_BUS, "isp1_bus", 8, JH7100_CLK_VIN_SRC), ++ JH71X0_GATE(JH7100_CLK_ISP1_AXI, "isp1_axi", 0, JH7100_CLK_ISP1_BUS), ++ JH71X0_GATE(JH7100_CLK_ISP1NOC_AXI, "isp1noc_axi", 0, JH7100_CLK_ISP1_BUS), ++ 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__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_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), ++ JH71X0_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), ++ JH71X0__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), ++ JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), ++ JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), ++ JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), ++ JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), ++ JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), ++ JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, + JH7100_CLK_GMAC_GTX, + JH7100_CLK_GMAC_TX_INV, + JH7100_CLK_GMAC_RMII_TX), +- JH7100__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), +- JH7100__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, ++ JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), ++ JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, + JH7100_CLK_GMAC_GR_MII_RX, + JH7100_CLK_GMAC_RMII_RX), +- JH7100__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), +- JH7100_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), +- JH7100_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), +- JH7100_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_E24_AHB, "e24_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_E24RTC_TOGGLE, "e24rtc_toggle", 0, JH7100_CLK_OSC_SYS), +- JH7100_GATE(JH7100_CLK_QSPI_AHB, "qspi_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_QSPI_APB, "qspi_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_QSPI_REF, "qspi_refclk", 0, 31, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_SEC_AHB, "sec_ahb", 0, JH7100_CLK_AHB_BUS), +- JH7100_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB), +- JH7100_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB), +- JH7100_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB), +- JH7100_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC), +- JH7100_GATE(JH7100_CLK_UART1_APB, "uart1_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_UART1_CORE, "uart1_core", 0, 63, JH7100_CLK_PERH1_SRC), +- JH7100_GATE(JH7100_CLK_SPI0_APB, "spi0_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_SPI0_CORE, "spi0_core", 0, 63, JH7100_CLK_PERH1_SRC), +- JH7100_GATE(JH7100_CLK_SPI1_APB, "spi1_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_SPI1_CORE, "spi1_core", 0, 63, JH7100_CLK_PERH1_SRC), +- JH7100_GATE(JH7100_CLK_I2C0_APB, "i2c0_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_I2C0_CORE, "i2c0_core", 0, 63, JH7100_CLK_PERH1_SRC), +- JH7100_GATE(JH7100_CLK_I2C1_APB, "i2c1_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GDIV(JH7100_CLK_I2C1_CORE, "i2c1_core", 0, 63, JH7100_CLK_PERH1_SRC), +- JH7100_GATE(JH7100_CLK_GPIO_APB, "gpio_apb", 0, JH7100_CLK_APB1_BUS), +- JH7100_GATE(JH7100_CLK_UART2_APB, "uart2_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_UART2_CORE, "uart2_core", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_UART3_APB, "uart3_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_UART3_CORE, "uart3_core", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_SPI2_APB, "spi2_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_SPI2_CORE, "spi2_core", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_SPI3_APB, "spi3_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_SPI3_CORE, "spi3_core", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_I2C2_APB, "i2c2_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_I2C2_CORE, "i2c2_core", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_I2C3_APB, "i2c3_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_I2C3_CORE, "i2c3_core", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_WDTIMER_APB, "wdtimer_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_WDT_CORE, "wdt_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER0_CORE, "timer0_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER1_CORE, "timer1_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER2_CORE, "timer2_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER3_CORE, "timer3_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER4_CORE, "timer4_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER5_CORE, "timer5_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GDIV(JH7100_CLK_TIMER6_CORE, "timer6_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), +- JH7100_GATE(JH7100_CLK_VP6INTC_APB, "vp6intc_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GATE(JH7100_CLK_PWM_APB, "pwm_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GATE(JH7100_CLK_MSI_APB, "msi_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GATE(JH7100_CLK_TEMP_APB, "temp_apb", 0, JH7100_CLK_APB2_BUS), +- JH7100_GDIV(JH7100_CLK_TEMP_SENSE, "temp_sense", 0, 31, JH7100_CLK_OSC_SYS), +- JH7100_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), ++ JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), ++ JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), ++ JH71X0_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_E24_AHB, "e24_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_E24RTC_TOGGLE, "e24rtc_toggle", 0, JH7100_CLK_OSC_SYS), ++ JH71X0_GATE(JH7100_CLK_QSPI_AHB, "qspi_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_QSPI_APB, "qspi_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_QSPI_REF, "qspi_refclk", 0, 31, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_SEC_AHB, "sec_ahb", 0, JH7100_CLK_AHB_BUS), ++ 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_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), ++ JH71X0_GATE(JH7100_CLK_UART1_APB, "uart1_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_UART1_CORE, "uart1_core", 0, 63, JH7100_CLK_PERH1_SRC), ++ JH71X0_GATE(JH7100_CLK_SPI0_APB, "spi0_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_SPI0_CORE, "spi0_core", 0, 63, JH7100_CLK_PERH1_SRC), ++ JH71X0_GATE(JH7100_CLK_SPI1_APB, "spi1_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_SPI1_CORE, "spi1_core", 0, 63, JH7100_CLK_PERH1_SRC), ++ JH71X0_GATE(JH7100_CLK_I2C0_APB, "i2c0_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_I2C0_CORE, "i2c0_core", 0, 63, JH7100_CLK_PERH1_SRC), ++ JH71X0_GATE(JH7100_CLK_I2C1_APB, "i2c1_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GDIV(JH7100_CLK_I2C1_CORE, "i2c1_core", 0, 63, JH7100_CLK_PERH1_SRC), ++ JH71X0_GATE(JH7100_CLK_GPIO_APB, "gpio_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GATE(JH7100_CLK_UART2_APB, "uart2_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_UART2_CORE, "uart2_core", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_UART3_APB, "uart3_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_UART3_CORE, "uart3_core", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_SPI2_APB, "spi2_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_SPI2_CORE, "spi2_core", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_SPI3_APB, "spi3_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_SPI3_CORE, "spi3_core", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_I2C2_APB, "i2c2_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_I2C2_CORE, "i2c2_core", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_I2C3_APB, "i2c3_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_I2C3_CORE, "i2c3_core", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_WDTIMER_APB, "wdtimer_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_WDT_CORE, "wdt_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER0_CORE, "timer0_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER1_CORE, "timer1_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER2_CORE, "timer2_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER3_CORE, "timer3_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER4_CORE, "timer4_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER5_CORE, "timer5_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GDIV(JH7100_CLK_TIMER6_CORE, "timer6_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), ++ JH71X0_GATE(JH7100_CLK_VP6INTC_APB, "vp6intc_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GATE(JH7100_CLK_PWM_APB, "pwm_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GATE(JH7100_CLK_MSI_APB, "msi_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GATE(JH7100_CLK_TEMP_APB, "temp_apb", 0, JH7100_CLK_APB2_BUS), ++ JH71X0_GDIV(JH7100_CLK_TEMP_SENSE, "temp_sense", 0, 31, JH7100_CLK_OSC_SYS), ++ JH71X0_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), + }; + + static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data) + { +- struct jh7100_clk_priv *priv = data; ++ struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7100_CLK_PLL0_OUT) +@@ -280,7 +283,7 @@ static struct clk_hw *jh7100_clk_get(str + + static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) + { +- struct jh7100_clk_priv *priv; ++ struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + +@@ -314,12 +317,12 @@ static int __init clk_starfive_jh7100_pr + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7100_clk_data[idx].name, +- .ops = starfive_jh7100_clk_ops(max), ++ .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, +- .num_parents = ((max & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT) + 1, ++ .num_parents = ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7100_clk_data[idx].flags, + }; +- struct jh7100_clk *clk = &priv->reg[idx]; ++ struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { +@@ -341,7 +344,7 @@ static int __init clk_starfive_jh7100_pr + + clk->hw.init = &init; + clk->idx = idx; +- clk->max_div = max & JH7100_CLK_DIV_MASK; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(priv->dev, &clk->hw); + if (ret) +--- a/drivers/clk/starfive/clk-starfive-jh71x0.c ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * StarFive JH7100 Clock Generator Driver ++ * StarFive JH71X0 Clock Generator Driver + * + * Copyright (C) 2021-2022 Emil Renner Berthing + */ +@@ -12,27 +12,27 @@ + + #include "clk-starfive-jh71x0.h" + +-static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw) ++static struct jh71x0_clk *jh71x0_clk_from(struct clk_hw *hw) + { +- return container_of(hw, struct jh7100_clk, hw); ++ return container_of(hw, struct jh71x0_clk, hw); + } + +-static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk) ++static struct jh71x0_clk_priv *jh71x0_priv_from(struct jh71x0_clk *clk) + { +- return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]); ++ return container_of(clk, struct jh71x0_clk_priv, reg[clk->idx]); + } + +-static u32 jh7100_clk_reg_get(struct jh7100_clk *clk) ++static u32 jh71x0_clk_reg_get(struct jh71x0_clk *clk) + { +- struct jh7100_clk_priv *priv = jh7100_priv_from(clk); ++ struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + void __iomem *reg = priv->base + 4 * clk->idx; + + return readl_relaxed(reg); + } + +-static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value) ++static void jh71x0_clk_reg_rmw(struct jh71x0_clk *clk, u32 mask, u32 value) + { +- struct jh7100_clk_priv *priv = jh7100_priv_from(clk); ++ struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + void __iomem *reg = priv->base + 4 * clk->idx; + unsigned long flags; + +@@ -42,41 +42,41 @@ static void jh7100_clk_reg_rmw(struct jh + spin_unlock_irqrestore(&priv->rmw_lock, flags); + } + +-static int jh7100_clk_enable(struct clk_hw *hw) ++static int jh71x0_clk_enable(struct clk_hw *hw) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + +- jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE); ++ jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, JH71X0_CLK_ENABLE); + return 0; + } + +-static void jh7100_clk_disable(struct clk_hw *hw) ++static void jh71x0_clk_disable(struct clk_hw *hw) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + +- jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0); ++ jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, 0); + } + +-static int jh7100_clk_is_enabled(struct clk_hw *hw) ++static int jh71x0_clk_is_enabled(struct clk_hw *hw) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + +- return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE); ++ return !!(jh71x0_clk_reg_get(clk) & JH71X0_CLK_ENABLE); + } + +-static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw, ++static unsigned long jh71x0_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK; ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); ++ u32 div = jh71x0_clk_reg_get(clk) & JH71X0_CLK_DIV_MASK; + + return div ? parent_rate / div : 0; + } + +-static int jh7100_clk_determine_rate(struct clk_hw *hw, ++static int jh71x0_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long parent = req->best_parent_rate; + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); + unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); +@@ -102,232 +102,232 @@ static int jh7100_clk_determine_rate(str + return 0; + } + +-static int jh7100_clk_set_rate(struct clk_hw *hw, ++static int jh71x0_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), + 1UL, (unsigned long)clk->max_div); + +- jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div); ++ jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, div); + return 0; + } + +-static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw, ++static unsigned long jh71x0_clk_frac_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 reg = jh7100_clk_reg_get(clk); +- unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) + +- ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); ++ u32 reg = jh71x0_clk_reg_get(clk); ++ unsigned long div100 = 100 * (reg & JH71X0_CLK_INT_MASK) + ++ ((reg & JH71X0_CLK_FRAC_MASK) >> JH71X0_CLK_FRAC_SHIFT); + +- return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; ++ return (div100 >= JH71X0_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; + } + +-static int jh7100_clk_frac_determine_rate(struct clk_hw *hw, ++static int jh71x0_clk_frac_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + unsigned long parent100 = 100 * req->best_parent_rate; + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), +- JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); ++ JH71X0_CLK_FRAC_MIN, JH71X0_CLK_FRAC_MAX); + unsigned long result = parent100 / div100; + +- /* clamp the result as in jh7100_clk_determine_rate() above */ +- if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX) ++ /* clamp the result as in jh71x0_clk_determine_rate() above */ ++ if (result > req->max_rate && div100 < JH71X0_CLK_FRAC_MAX) + result = parent100 / (div100 + 1); +- if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN) ++ if (result < req->min_rate && div100 > JH71X0_CLK_FRAC_MIN) + result = parent100 / (div100 - 1); + + req->rate = result; + return 0; + } + +-static int jh7100_clk_frac_set_rate(struct clk_hw *hw, ++static int jh71x0_clk_frac_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), +- JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); +- u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100); ++ JH71X0_CLK_FRAC_MIN, JH71X0_CLK_FRAC_MAX); ++ u32 value = ((div100 % 100) << JH71X0_CLK_FRAC_SHIFT) | (div100 / 100); + +- jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value); ++ jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, value); + return 0; + } + +-static u8 jh7100_clk_get_parent(struct clk_hw *hw) ++static u8 jh71x0_clk_get_parent(struct clk_hw *hw) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value = jh7100_clk_reg_get(clk); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); ++ u32 value = jh71x0_clk_reg_get(clk); + +- return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT; ++ return (value & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT; + } + +-static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index) ++static int jh71x0_clk_set_parent(struct clk_hw *hw, u8 index) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value = (u32)index << JH7100_CLK_MUX_SHIFT; ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); ++ u32 value = (u32)index << JH71X0_CLK_MUX_SHIFT; + +- jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value); ++ jh71x0_clk_reg_rmw(clk, JH71X0_CLK_MUX_MASK, value); + return 0; + } + +-static int jh7100_clk_mux_determine_rate(struct clk_hw *hw, ++static int jh71x0_clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + return clk_mux_determine_rate_flags(hw, req, 0); + } + +-static int jh7100_clk_get_phase(struct clk_hw *hw) ++static int jh71x0_clk_get_phase(struct clk_hw *hw) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- u32 value = jh7100_clk_reg_get(clk); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); ++ u32 value = jh71x0_clk_reg_get(clk); + +- return (value & JH7100_CLK_INVERT) ? 180 : 0; ++ return (value & JH71X0_CLK_INVERT) ? 180 : 0; + } + +-static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees) ++static int jh71x0_clk_set_phase(struct clk_hw *hw, int degrees) + { +- struct jh7100_clk *clk = jh7100_clk_from(hw); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value; + + if (degrees == 0) + value = 0; + else if (degrees == 180) +- value = JH7100_CLK_INVERT; ++ value = JH71X0_CLK_INVERT; + else + return -EINVAL; + +- jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value); ++ jh71x0_clk_reg_rmw(clk, JH71X0_CLK_INVERT, value); + return 0; + } + + #ifdef CONFIG_DEBUG_FS +-static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) ++static void jh71x0_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) + { +- static const struct debugfs_reg32 jh7100_clk_reg = { ++ static const struct debugfs_reg32 jh71x0_clk_reg = { + .name = "CTRL", + .offset = 0, + }; +- struct jh7100_clk *clk = jh7100_clk_from(hw); +- struct jh7100_clk_priv *priv = jh7100_priv_from(clk); ++ struct jh71x0_clk *clk = jh71x0_clk_from(hw); ++ struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + struct debugfs_regset32 *regset; + + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return; + +- regset->regs = &jh7100_clk_reg; ++ regset->regs = &jh71x0_clk_reg; + regset->nregs = 1; + regset->base = priv->base + 4 * clk->idx; + + debugfs_create_regset32("registers", 0400, dentry, regset); + } + #else +-#define jh7100_clk_debug_init NULL ++#define jh71x0_clk_debug_init NULL + #endif + +-static const struct clk_ops jh7100_clk_gate_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_gate_ops = { ++ .enable = jh71x0_clk_enable, ++ .disable = jh71x0_clk_disable, ++ .is_enabled = jh71x0_clk_is_enabled, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_div_ops = { +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_div_ops = { ++ .recalc_rate = jh71x0_clk_recalc_rate, ++ .determine_rate = jh71x0_clk_determine_rate, ++ .set_rate = jh71x0_clk_set_rate, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_fdiv_ops = { +- .recalc_rate = jh7100_clk_frac_recalc_rate, +- .determine_rate = jh7100_clk_frac_determine_rate, +- .set_rate = jh7100_clk_frac_set_rate, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_fdiv_ops = { ++ .recalc_rate = jh71x0_clk_frac_recalc_rate, ++ .determine_rate = jh71x0_clk_frac_determine_rate, ++ .set_rate = jh71x0_clk_frac_set_rate, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_gdiv_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_gdiv_ops = { ++ .enable = jh71x0_clk_enable, ++ .disable = jh71x0_clk_disable, ++ .is_enabled = jh71x0_clk_is_enabled, ++ .recalc_rate = jh71x0_clk_recalc_rate, ++ .determine_rate = jh71x0_clk_determine_rate, ++ .set_rate = jh71x0_clk_set_rate, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_mux_ops = { +- .determine_rate = jh7100_clk_mux_determine_rate, +- .set_parent = jh7100_clk_set_parent, +- .get_parent = jh7100_clk_get_parent, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_mux_ops = { ++ .determine_rate = jh71x0_clk_mux_determine_rate, ++ .set_parent = jh71x0_clk_set_parent, ++ .get_parent = jh71x0_clk_get_parent, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_gmux_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .determine_rate = jh7100_clk_mux_determine_rate, +- .set_parent = jh7100_clk_set_parent, +- .get_parent = jh7100_clk_get_parent, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_gmux_ops = { ++ .enable = jh71x0_clk_enable, ++ .disable = jh71x0_clk_disable, ++ .is_enabled = jh71x0_clk_is_enabled, ++ .determine_rate = jh71x0_clk_mux_determine_rate, ++ .set_parent = jh71x0_clk_set_parent, ++ .get_parent = jh71x0_clk_get_parent, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_mdiv_ops = { +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .get_parent = jh7100_clk_get_parent, +- .set_parent = jh7100_clk_set_parent, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_mdiv_ops = { ++ .recalc_rate = jh71x0_clk_recalc_rate, ++ .determine_rate = jh71x0_clk_determine_rate, ++ .get_parent = jh71x0_clk_get_parent, ++ .set_parent = jh71x0_clk_set_parent, ++ .set_rate = jh71x0_clk_set_rate, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_gmd_ops = { +- .enable = jh7100_clk_enable, +- .disable = jh7100_clk_disable, +- .is_enabled = jh7100_clk_is_enabled, +- .recalc_rate = jh7100_clk_recalc_rate, +- .determine_rate = jh7100_clk_determine_rate, +- .get_parent = jh7100_clk_get_parent, +- .set_parent = jh7100_clk_set_parent, +- .set_rate = jh7100_clk_set_rate, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_gmd_ops = { ++ .enable = jh71x0_clk_enable, ++ .disable = jh71x0_clk_disable, ++ .is_enabled = jh71x0_clk_is_enabled, ++ .recalc_rate = jh71x0_clk_recalc_rate, ++ .determine_rate = jh71x0_clk_determine_rate, ++ .get_parent = jh71x0_clk_get_parent, ++ .set_parent = jh71x0_clk_set_parent, ++ .set_rate = jh71x0_clk_set_rate, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-static const struct clk_ops jh7100_clk_inv_ops = { +- .get_phase = jh7100_clk_get_phase, +- .set_phase = jh7100_clk_set_phase, +- .debug_init = jh7100_clk_debug_init, ++static const struct clk_ops jh71x0_clk_inv_ops = { ++ .get_phase = jh71x0_clk_get_phase, ++ .set_phase = jh71x0_clk_set_phase, ++ .debug_init = jh71x0_clk_debug_init, + }; + +-const struct clk_ops *starfive_jh7100_clk_ops(u32 max) ++const struct clk_ops *starfive_jh71x0_clk_ops(u32 max) + { +- if (max & JH7100_CLK_DIV_MASK) { +- if (max & JH7100_CLK_MUX_MASK) { +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gmd_ops; +- return &jh7100_clk_mdiv_ops; ++ if (max & JH71X0_CLK_DIV_MASK) { ++ if (max & JH71X0_CLK_MUX_MASK) { ++ if (max & JH71X0_CLK_ENABLE) ++ return &jh71x0_clk_gmd_ops; ++ return &jh71x0_clk_mdiv_ops; + } +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gdiv_ops; +- if (max == JH7100_CLK_FRAC_MAX) +- return &jh7100_clk_fdiv_ops; +- return &jh7100_clk_div_ops; ++ if (max & JH71X0_CLK_ENABLE) ++ return &jh71x0_clk_gdiv_ops; ++ if (max == JH71X0_CLK_FRAC_MAX) ++ return &jh71x0_clk_fdiv_ops; ++ return &jh71x0_clk_div_ops; + } + +- if (max & JH7100_CLK_MUX_MASK) { +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gmux_ops; +- return &jh7100_clk_mux_ops; ++ if (max & JH71X0_CLK_MUX_MASK) { ++ if (max & JH71X0_CLK_ENABLE) ++ return &jh71x0_clk_gmux_ops; ++ return &jh71x0_clk_mux_ops; + } + +- if (max & JH7100_CLK_ENABLE) +- return &jh7100_clk_gate_ops; ++ if (max & JH71X0_CLK_ENABLE) ++ return &jh71x0_clk_gate_ops; + +- return &jh7100_clk_inv_ops; ++ return &jh71x0_clk_inv_ops; + } +-EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops); ++EXPORT_SYMBOL_GPL(starfive_jh71x0_clk_ops); +--- a/drivers/clk/starfive/clk-starfive-jh71x0.h ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef __CLK_STARFIVE_JH7100_H +-#define __CLK_STARFIVE_JH7100_H ++#ifndef __CLK_STARFIVE_JH71X0_H ++#define __CLK_STARFIVE_JH71X0_H + + #include + #include +@@ -8,107 +8,116 @@ + #include + + /* register fields */ +-#define JH7100_CLK_ENABLE BIT(31) +-#define JH7100_CLK_INVERT BIT(30) +-#define JH7100_CLK_MUX_MASK GENMASK(27, 24) +-#define JH7100_CLK_MUX_SHIFT 24 +-#define JH7100_CLK_DIV_MASK GENMASK(23, 0) +-#define JH7100_CLK_FRAC_MASK GENMASK(15, 8) +-#define JH7100_CLK_FRAC_SHIFT 8 +-#define JH7100_CLK_INT_MASK GENMASK(7, 0) ++#define JH71X0_CLK_ENABLE BIT(31) ++#define JH71X0_CLK_INVERT BIT(30) ++#define JH71X0_CLK_MUX_MASK GENMASK(27, 24) ++#define JH71X0_CLK_MUX_SHIFT 24 ++#define JH71X0_CLK_DIV_MASK GENMASK(23, 0) ++#define JH71X0_CLK_FRAC_MASK GENMASK(15, 8) ++#define JH71X0_CLK_FRAC_SHIFT 8 ++#define JH71X0_CLK_INT_MASK GENMASK(7, 0) + + /* fractional divider min/max */ +-#define JH7100_CLK_FRAC_MIN 100UL +-#define JH7100_CLK_FRAC_MAX 25599UL ++#define JH71X0_CLK_FRAC_MIN 100UL ++#define JH71X0_CLK_FRAC_MAX 25599UL + + /* clock data */ +-struct jh7100_clk_data { ++struct jh71x0_clk_data { + const char *name; + unsigned long flags; + u32 max; + u8 parents[4]; + }; + +-#define JH7100_GATE(_idx, _name, _flags, _parent) [_idx] = { \ ++#define JH71X0_GATE(_idx, _name, _flags, _parent) \ ++[_idx] = { \ + .name = _name, \ + .flags = CLK_SET_RATE_PARENT | (_flags), \ +- .max = JH7100_CLK_ENABLE, \ ++ .max = JH71X0_CLK_ENABLE, \ + .parents = { [0] = _parent }, \ + } + +-#define JH7100__DIV(_idx, _name, _max, _parent) [_idx] = { \ ++#define JH71X0__DIV(_idx, _name, _max, _parent) \ ++[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = _max, \ + .parents = { [0] = _parent }, \ + } + +-#define JH7100_GDIV(_idx, _name, _flags, _max, _parent) [_idx] = { \ ++#define JH71X0_GDIV(_idx, _name, _flags, _max, _parent) \ ++[_idx] = { \ + .name = _name, \ + .flags = _flags, \ +- .max = JH7100_CLK_ENABLE | (_max), \ ++ .max = JH71X0_CLK_ENABLE | (_max), \ + .parents = { [0] = _parent }, \ + } + +-#define JH7100_FDIV(_idx, _name, _parent) [_idx] = { \ ++#define JH71X0_FDIV(_idx, _name, _parent) \ ++[_idx] = { \ + .name = _name, \ + .flags = 0, \ +- .max = JH7100_CLK_FRAC_MAX, \ ++ .max = JH71X0_CLK_FRAC_MAX, \ + .parents = { [0] = _parent }, \ + } + +-#define JH7100__MUX(_idx, _name, _nparents, ...) [_idx] = { \ ++#define JH71X0__MUX(_idx, _name, _nparents, ...) \ ++[_idx] = { \ + .name = _name, \ + .flags = 0, \ +- .max = ((_nparents) - 1) << JH7100_CLK_MUX_SHIFT, \ ++ .max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \ + .parents = { __VA_ARGS__ }, \ + } + +-#define JH7100_GMUX(_idx, _name, _flags, _nparents, ...) [_idx] = { \ ++#define JH71X0_GMUX(_idx, _name, _flags, _nparents, ...) \ ++[_idx] = { \ + .name = _name, \ + .flags = _flags, \ +- .max = JH7100_CLK_ENABLE | \ +- (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT), \ ++ .max = JH71X0_CLK_ENABLE | \ ++ (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT), \ + .parents = { __VA_ARGS__ }, \ + } + +-#define JH7100_MDIV(_idx, _name, _max, _nparents, ...) [_idx] = { \ ++#define JH71X0_MDIV(_idx, _name, _max, _nparents, ...) \ ++[_idx] = { \ + .name = _name, \ + .flags = 0, \ +- .max = (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ ++ .max = (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT) | (_max), \ + .parents = { __VA_ARGS__ }, \ + } + +-#define JH7100__GMD(_idx, _name, _flags, _max, _nparents, ...) [_idx] = { \ ++#define JH71X0__GMD(_idx, _name, _flags, _max, _nparents, ...) \ ++[_idx] = { \ + .name = _name, \ + .flags = _flags, \ +- .max = JH7100_CLK_ENABLE | \ +- (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ ++ .max = JH71X0_CLK_ENABLE | \ ++ (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT) | (_max), \ + .parents = { __VA_ARGS__ }, \ + } + +-#define JH7100__INV(_idx, _name, _parent) [_idx] = { \ ++#define JH71X0__INV(_idx, _name, _parent) \ ++[_idx] = { \ + .name = _name, \ + .flags = CLK_SET_RATE_PARENT, \ +- .max = JH7100_CLK_INVERT, \ ++ .max = JH71X0_CLK_INVERT, \ + .parents = { [0] = _parent }, \ + } + +-struct jh7100_clk { ++struct jh71x0_clk { + struct clk_hw hw; + unsigned int idx; + unsigned int max_div; + }; + +-struct jh7100_clk_priv { ++struct jh71x0_clk_priv { + /* protect clk enable and set rate/parent from happening at the same time */ + spinlock_t rmw_lock; + struct device *dev; + void __iomem *base; + struct clk_hw *pll[3]; +- struct jh7100_clk reg[]; ++ struct jh71x0_clk reg[]; + }; + +-const struct clk_ops *starfive_jh7100_clk_ops(u32 max); ++const struct clk_ops *starfive_jh71x0_clk_ops(u32 max); + + #endif diff --git a/target/linux/starfive/patches-6.1/0007-reset-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFI.patch b/target/linux/starfive/patches-6.1/0007-reset-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFI.patch new file mode 100644 index 0000000000..e5281b85e9 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0007-reset-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFI.patch @@ -0,0 +1,30 @@ +From 0ee5a7565601fa785d7e55c57f26ff5d79473eb2 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Sat, 1 Apr 2023 19:19:19 +0800 +Subject: [PATCH 007/122] reset: starfive: Replace SOC_STARFIVE with + ARCH_STARFIVE + +Using ARCH_FOO symbol is preferred than SOC_FOO. + +Reviewed-by: Philipp Zabel +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/reset/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -234,8 +234,8 @@ config RESET_SOCFPGA + + config RESET_STARFIVE_JH7100 + bool "StarFive JH7100 Reset Driver" +- depends on SOC_STARFIVE || COMPILE_TEST +- default SOC_STARFIVE ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ default ARCH_STARFIVE + help + This enables the reset controller driver for the StarFive JH7100 SoC. + diff --git a/target/linux/starfive/patches-6.1/0008-reset-Create-subdirectory-for-StarFive-drivers.patch b/target/linux/starfive/patches-6.1/0008-reset-Create-subdirectory-for-StarFive-drivers.patch new file mode 100644 index 0000000000..2e44f38e59 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0008-reset-Create-subdirectory-for-StarFive-drivers.patch @@ -0,0 +1,436 @@ +From ea9e5879793f9743fbfe613174900ab0c431ac0e Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:20 +0800 +Subject: [PATCH 008/122] reset: Create subdirectory for StarFive drivers + +This moves the StarFive JH7100 reset driver to a new subdirectory in +preparation for adding more StarFive reset drivers. + +Reviewed-by: Philipp Zabel +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/reset/Kconfig | 8 +------- + drivers/reset/Makefile | 2 +- + drivers/reset/starfive/Kconfig | 8 ++++++++ + drivers/reset/starfive/Makefile | 2 ++ + drivers/reset/{ => starfive}/reset-starfive-jh7100.c | 0 + 5 files changed, 12 insertions(+), 8 deletions(-) + create mode 100644 drivers/reset/starfive/Kconfig + create mode 100644 drivers/reset/starfive/Makefile + rename drivers/reset/{ => starfive}/reset-starfive-jh7100.c (100%) + +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -232,13 +232,6 @@ config RESET_SOCFPGA + This enables the reset driver for the SoCFPGA ARMv7 platforms. This + driver gets initialized early during platform init calls. + +-config RESET_STARFIVE_JH7100 +- bool "StarFive JH7100 Reset Driver" +- depends on ARCH_STARFIVE || COMPILE_TEST +- default ARCH_STARFIVE +- help +- This enables the reset controller driver for the StarFive JH7100 SoC. +- + config RESET_SUNPLUS + bool "Sunplus SoCs Reset Driver" if COMPILE_TEST + default ARCH_SUNPLUS +@@ -320,6 +313,7 @@ config RESET_ZYNQ + help + This enables the reset controller driver for Xilinx Zynq SoCs. + ++source "drivers/reset/starfive/Kconfig" + source "drivers/reset/sti/Kconfig" + source "drivers/reset/hisilicon/Kconfig" + source "drivers/reset/tegra/Kconfig" +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-y += core.o + obj-y += hisilicon/ ++obj-y += starfive/ + obj-$(CONFIG_ARCH_STI) += sti/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ + obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o +@@ -30,7 +31,6 @@ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += + obj-$(CONFIG_RESET_SCMI) += reset-scmi.o + obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o + obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o +-obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o + obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o + obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o + obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o +--- /dev/null ++++ b/drivers/reset/starfive/Kconfig +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++config RESET_STARFIVE_JH7100 ++ bool "StarFive JH7100 Reset Driver" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ default ARCH_STARFIVE ++ help ++ This enables the reset controller driver for the StarFive JH7100 SoC. +--- /dev/null ++++ b/drivers/reset/starfive/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o +--- a/drivers/reset/reset-starfive-jh7100.c ++++ /dev/null +@@ -1,173 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-or-later +-/* +- * Reset driver for the StarFive JH7100 SoC +- * +- * Copyright (C) 2021 Emil Renner Berthing +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-/* register offsets */ +-#define JH7100_RESET_ASSERT0 0x00 +-#define JH7100_RESET_ASSERT1 0x04 +-#define JH7100_RESET_ASSERT2 0x08 +-#define JH7100_RESET_ASSERT3 0x0c +-#define JH7100_RESET_STATUS0 0x10 +-#define JH7100_RESET_STATUS1 0x14 +-#define JH7100_RESET_STATUS2 0x18 +-#define JH7100_RESET_STATUS3 0x1c +- +-/* +- * Writing a 1 to the n'th bit of the m'th ASSERT register asserts +- * line 32m + 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 u64 jh7100_reset_asserted[2] = { +- /* STATUS0 */ +- BIT_ULL_MASK(JH7100_RST_U74) | +- BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | +- BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | +- /* STATUS1 */ +- BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | +- BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), +- /* STATUS2 */ +- BIT_ULL_MASK(JH7100_RST_E24) | +- /* STATUS3 */ +- 0, +-}; +- +-struct jh7100_reset { +- struct reset_controller_dev rcdev; +- /* protect registers against concurrent read-modify-write */ +- spinlock_t lock; +- void __iomem *base; +-}; +- +-static inline struct jh7100_reset * +-jh7100_reset_from(struct reset_controller_dev *rcdev) +-{ +- return container_of(rcdev, struct jh7100_reset, rcdev); +-} +- +-static int jh7100_reset_update(struct reset_controller_dev *rcdev, +- unsigned long id, bool assert) +-{ +- struct jh7100_reset *data = jh7100_reset_from(rcdev); +- unsigned long offset = BIT_ULL_WORD(id); +- u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(u64); +- void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); +- u64 done = jh7100_reset_asserted[offset] & mask; +- u64 value; +- unsigned long flags; +- int ret; +- +- if (!assert) +- done ^= mask; +- +- spin_lock_irqsave(&data->lock, flags); +- +- value = readq(reg_assert); +- if (assert) +- value |= mask; +- else +- value &= ~mask; +- writeq(value, reg_assert); +- +- /* if the associated clock is gated, deasserting might otherwise hang forever */ +- ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); +- +- spin_unlock_irqrestore(&data->lock, flags); +- return ret; +-} +- +-static int jh7100_reset_assert(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- return jh7100_reset_update(rcdev, id, true); +-} +- +-static int jh7100_reset_deassert(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- return jh7100_reset_update(rcdev, id, false); +-} +- +-static int jh7100_reset_reset(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- int ret; +- +- ret = jh7100_reset_assert(rcdev, id); +- if (ret) +- return ret; +- +- return jh7100_reset_deassert(rcdev, id); +-} +- +-static int jh7100_reset_status(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- struct jh7100_reset *data = jh7100_reset_from(rcdev); +- unsigned long offset = BIT_ULL_WORD(id); +- u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); +- u64 value = readq(reg_status); +- +- return !((value ^ jh7100_reset_asserted[offset]) & mask); +-} +- +-static const struct reset_control_ops jh7100_reset_ops = { +- .assert = jh7100_reset_assert, +- .deassert = jh7100_reset_deassert, +- .reset = jh7100_reset_reset, +- .status = jh7100_reset_status, +-}; +- +-static int __init jh7100_reset_probe(struct platform_device *pdev) +-{ +- struct jh7100_reset *data; +- +- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +- if (!data) +- return -ENOMEM; +- +- data->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(data->base)) +- return PTR_ERR(data->base); +- +- data->rcdev.ops = &jh7100_reset_ops; +- data->rcdev.owner = THIS_MODULE; +- data->rcdev.nr_resets = JH7100_RSTN_END; +- data->rcdev.dev = &pdev->dev; +- data->rcdev.of_node = pdev->dev.of_node; +- spin_lock_init(&data->lock); +- +- return devm_reset_controller_register(&pdev->dev, &data->rcdev); +-} +- +-static const struct of_device_id jh7100_reset_dt_ids[] = { +- { .compatible = "starfive,jh7100-reset" }, +- { /* sentinel */ } +-}; +- +-static struct platform_driver jh7100_reset_driver = { +- .driver = { +- .name = "jh7100-reset", +- .of_match_table = jh7100_reset_dt_ids, +- .suppress_bind_attrs = true, +- }, +-}; +-builtin_platform_driver_probe(jh7100_reset_driver, jh7100_reset_probe); +--- /dev/null ++++ b/drivers/reset/starfive/reset-starfive-jh7100.c +@@ -0,0 +1,173 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Reset driver for the StarFive JH7100 SoC ++ * ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* register offsets */ ++#define JH7100_RESET_ASSERT0 0x00 ++#define JH7100_RESET_ASSERT1 0x04 ++#define JH7100_RESET_ASSERT2 0x08 ++#define JH7100_RESET_ASSERT3 0x0c ++#define JH7100_RESET_STATUS0 0x10 ++#define JH7100_RESET_STATUS1 0x14 ++#define JH7100_RESET_STATUS2 0x18 ++#define JH7100_RESET_STATUS3 0x1c ++ ++/* ++ * Writing a 1 to the n'th bit of the m'th ASSERT register asserts ++ * line 32m + 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 u64 jh7100_reset_asserted[2] = { ++ /* STATUS0 */ ++ BIT_ULL_MASK(JH7100_RST_U74) | ++ BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | ++ BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | ++ /* STATUS1 */ ++ BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | ++ BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), ++ /* STATUS2 */ ++ BIT_ULL_MASK(JH7100_RST_E24) | ++ /* STATUS3 */ ++ 0, ++}; ++ ++struct jh7100_reset { ++ struct reset_controller_dev rcdev; ++ /* protect registers against concurrent read-modify-write */ ++ spinlock_t lock; ++ void __iomem *base; ++}; ++ ++static inline struct jh7100_reset * ++jh7100_reset_from(struct reset_controller_dev *rcdev) ++{ ++ return container_of(rcdev, struct jh7100_reset, rcdev); ++} ++ ++static int jh7100_reset_update(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct jh7100_reset *data = jh7100_reset_from(rcdev); ++ unsigned long offset = BIT_ULL_WORD(id); ++ u64 mask = BIT_ULL_MASK(id); ++ void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(u64); ++ void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); ++ u64 done = jh7100_reset_asserted[offset] & mask; ++ u64 value; ++ unsigned long flags; ++ int ret; ++ ++ if (!assert) ++ done ^= mask; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ value = readq(reg_assert); ++ if (assert) ++ value |= mask; ++ else ++ value &= ~mask; ++ writeq(value, reg_assert); ++ ++ /* if the associated clock is gated, deasserting might otherwise hang forever */ ++ ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ return ret; ++} ++ ++static int jh7100_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return jh7100_reset_update(rcdev, id, true); ++} ++ ++static int jh7100_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return jh7100_reset_update(rcdev, id, false); ++} ++ ++static int jh7100_reset_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ ++ ret = jh7100_reset_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return jh7100_reset_deassert(rcdev, id); ++} ++ ++static int jh7100_reset_status(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct jh7100_reset *data = jh7100_reset_from(rcdev); ++ unsigned long offset = BIT_ULL_WORD(id); ++ u64 mask = BIT_ULL_MASK(id); ++ void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); ++ u64 value = readq(reg_status); ++ ++ return !((value ^ jh7100_reset_asserted[offset]) & mask); ++} ++ ++static const struct reset_control_ops jh7100_reset_ops = { ++ .assert = jh7100_reset_assert, ++ .deassert = jh7100_reset_deassert, ++ .reset = jh7100_reset_reset, ++ .status = jh7100_reset_status, ++}; ++ ++static int __init jh7100_reset_probe(struct platform_device *pdev) ++{ ++ struct jh7100_reset *data; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(data->base)) ++ return PTR_ERR(data->base); ++ ++ data->rcdev.ops = &jh7100_reset_ops; ++ data->rcdev.owner = THIS_MODULE; ++ data->rcdev.nr_resets = JH7100_RSTN_END; ++ data->rcdev.dev = &pdev->dev; ++ data->rcdev.of_node = pdev->dev.of_node; ++ spin_lock_init(&data->lock); ++ ++ return devm_reset_controller_register(&pdev->dev, &data->rcdev); ++} ++ ++static const struct of_device_id jh7100_reset_dt_ids[] = { ++ { .compatible = "starfive,jh7100-reset" }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver jh7100_reset_driver = { ++ .driver = { ++ .name = "jh7100-reset", ++ .of_match_table = jh7100_reset_dt_ids, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver_probe(jh7100_reset_driver, jh7100_reset_probe); diff --git a/target/linux/starfive/patches-6.1/0009-reset-starfive-Factor-out-common-JH71X0-reset-code.patch b/target/linux/starfive/patches-6.1/0009-reset-starfive-Factor-out-common-JH71X0-reset-code.patch new file mode 100644 index 0000000000..cd192f80af --- /dev/null +++ b/target/linux/starfive/patches-6.1/0009-reset-starfive-Factor-out-common-JH71X0-reset-code.patch @@ -0,0 +1,390 @@ +From a8051a7daa45056f469686286886968bc62b94df Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:21 +0800 +Subject: [PATCH 009/122] reset: starfive: Factor out common JH71X0 reset code + +The StarFive JH7100 SoC has additional reset controllers for audio and +video, but the registers follow the same structure. On the JH7110 the +reset registers don't get their own memory range, but instead follow the +clock control registers. The registers still follow the same structure +though, so let's factor out the common code to handle all these cases. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/reset/starfive/Kconfig | 4 + + drivers/reset/starfive/Makefile | 2 + + .../reset/starfive/reset-starfive-jh7100.c | 150 +--------------- + .../reset/starfive/reset-starfive-jh71x0.c | 162 ++++++++++++++++++ + .../reset/starfive/reset-starfive-jh71x0.h | 11 ++ + 5 files changed, 180 insertions(+), 149 deletions(-) + create mode 100644 drivers/reset/starfive/reset-starfive-jh71x0.c + create mode 100644 drivers/reset/starfive/reset-starfive-jh71x0.h + +--- a/drivers/reset/starfive/Kconfig ++++ b/drivers/reset/starfive/Kconfig +@@ -1,8 +1,12 @@ + # SPDX-License-Identifier: GPL-2.0-only + ++config RESET_STARFIVE_JH71X0 ++ bool ++ + config RESET_STARFIVE_JH7100 + bool "StarFive JH7100 Reset Driver" + depends on ARCH_STARFIVE || COMPILE_TEST ++ select RESET_STARFIVE_JH71X0 + default ARCH_STARFIVE + help + This enables the reset controller driver for the StarFive JH7100 SoC. +--- a/drivers/reset/starfive/Makefile ++++ b/drivers/reset/starfive/Makefile +@@ -1,2 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_RESET_STARFIVE_JH71X0) += reset-starfive-jh71x0.o ++ + obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o +--- a/drivers/reset/starfive/reset-starfive-jh7100.c ++++ b/drivers/reset/starfive/reset-starfive-jh7100.c +@@ -5,158 +5,10 @@ + * Copyright (C) 2021 Emil Renner Berthing + */ + +-#include +-#include +-#include +-#include + #include + #include +-#include +-#include + +-#include +- +-/* register offsets */ +-#define JH7100_RESET_ASSERT0 0x00 +-#define JH7100_RESET_ASSERT1 0x04 +-#define JH7100_RESET_ASSERT2 0x08 +-#define JH7100_RESET_ASSERT3 0x0c +-#define JH7100_RESET_STATUS0 0x10 +-#define JH7100_RESET_STATUS1 0x14 +-#define JH7100_RESET_STATUS2 0x18 +-#define JH7100_RESET_STATUS3 0x1c +- +-/* +- * Writing a 1 to the n'th bit of the m'th ASSERT register asserts +- * line 32m + 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 u64 jh7100_reset_asserted[2] = { +- /* STATUS0 */ +- BIT_ULL_MASK(JH7100_RST_U74) | +- BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | +- BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | +- /* STATUS1 */ +- BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | +- BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), +- /* STATUS2 */ +- BIT_ULL_MASK(JH7100_RST_E24) | +- /* STATUS3 */ +- 0, +-}; +- +-struct jh7100_reset { +- struct reset_controller_dev rcdev; +- /* protect registers against concurrent read-modify-write */ +- spinlock_t lock; +- void __iomem *base; +-}; +- +-static inline struct jh7100_reset * +-jh7100_reset_from(struct reset_controller_dev *rcdev) +-{ +- return container_of(rcdev, struct jh7100_reset, rcdev); +-} +- +-static int jh7100_reset_update(struct reset_controller_dev *rcdev, +- unsigned long id, bool assert) +-{ +- struct jh7100_reset *data = jh7100_reset_from(rcdev); +- unsigned long offset = BIT_ULL_WORD(id); +- u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(u64); +- void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); +- u64 done = jh7100_reset_asserted[offset] & mask; +- u64 value; +- unsigned long flags; +- int ret; +- +- if (!assert) +- done ^= mask; +- +- spin_lock_irqsave(&data->lock, flags); +- +- value = readq(reg_assert); +- if (assert) +- value |= mask; +- else +- value &= ~mask; +- writeq(value, reg_assert); +- +- /* if the associated clock is gated, deasserting might otherwise hang forever */ +- ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); +- +- spin_unlock_irqrestore(&data->lock, flags); +- return ret; +-} +- +-static int jh7100_reset_assert(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- return jh7100_reset_update(rcdev, id, true); +-} +- +-static int jh7100_reset_deassert(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- return jh7100_reset_update(rcdev, id, false); +-} +- +-static int jh7100_reset_reset(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- int ret; +- +- ret = jh7100_reset_assert(rcdev, id); +- if (ret) +- return ret; +- +- return jh7100_reset_deassert(rcdev, id); +-} +- +-static int jh7100_reset_status(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- struct jh7100_reset *data = jh7100_reset_from(rcdev); +- unsigned long offset = BIT_ULL_WORD(id); +- u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); +- u64 value = readq(reg_status); +- +- return !((value ^ jh7100_reset_asserted[offset]) & mask); +-} +- +-static const struct reset_control_ops jh7100_reset_ops = { +- .assert = jh7100_reset_assert, +- .deassert = jh7100_reset_deassert, +- .reset = jh7100_reset_reset, +- .status = jh7100_reset_status, +-}; +- +-static int __init jh7100_reset_probe(struct platform_device *pdev) +-{ +- struct jh7100_reset *data; +- +- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +- if (!data) +- return -ENOMEM; +- +- data->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(data->base)) +- return PTR_ERR(data->base); +- +- data->rcdev.ops = &jh7100_reset_ops; +- data->rcdev.owner = THIS_MODULE; +- data->rcdev.nr_resets = JH7100_RSTN_END; +- data->rcdev.dev = &pdev->dev; +- data->rcdev.of_node = pdev->dev.of_node; +- spin_lock_init(&data->lock); +- +- return devm_reset_controller_register(&pdev->dev, &data->rcdev); +-} ++#include "reset-starfive-jh71x0.h" + + static const struct of_device_id jh7100_reset_dt_ids[] = { + { .compatible = "starfive,jh7100-reset" }, +--- /dev/null ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.c +@@ -0,0 +1,162 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Reset driver for the StarFive JH7100 SoC ++ * ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "reset-starfive-jh71x0.h" ++ ++#include ++ ++/* register offsets */ ++#define JH7100_RESET_ASSERT0 0x00 ++#define JH7100_RESET_ASSERT1 0x04 ++#define JH7100_RESET_ASSERT2 0x08 ++#define JH7100_RESET_ASSERT3 0x0c ++#define JH7100_RESET_STATUS0 0x10 ++#define JH7100_RESET_STATUS1 0x14 ++#define JH7100_RESET_STATUS2 0x18 ++#define JH7100_RESET_STATUS3 0x1c ++ ++/* ++ * Writing a 1 to the n'th bit of the m'th ASSERT register asserts ++ * line 32m + 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 u64 jh7100_reset_asserted[2] = { ++ /* STATUS0 */ ++ BIT_ULL_MASK(JH7100_RST_U74) | ++ BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | ++ BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | ++ /* STATUS1 */ ++ BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | ++ BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), ++ /* STATUS2 */ ++ BIT_ULL_MASK(JH7100_RST_E24) | ++ /* STATUS3 */ ++ 0, ++}; ++ ++struct jh7100_reset { ++ struct reset_controller_dev rcdev; ++ /* protect registers against concurrent read-modify-write */ ++ spinlock_t lock; ++ void __iomem *base; ++}; ++ ++static inline struct jh7100_reset * ++jh7100_reset_from(struct reset_controller_dev *rcdev) ++{ ++ return container_of(rcdev, struct jh7100_reset, rcdev); ++} ++ ++static int jh7100_reset_update(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct jh7100_reset *data = jh7100_reset_from(rcdev); ++ unsigned long offset = BIT_ULL_WORD(id); ++ u64 mask = BIT_ULL_MASK(id); ++ void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(u64); ++ void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); ++ u64 done = jh7100_reset_asserted[offset] & mask; ++ u64 value; ++ unsigned long flags; ++ int ret; ++ ++ if (!assert) ++ done ^= mask; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ value = readq(reg_assert); ++ if (assert) ++ value |= mask; ++ else ++ value &= ~mask; ++ writeq(value, reg_assert); ++ ++ /* if the associated clock is gated, deasserting might otherwise hang forever */ ++ ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ return ret; ++} ++ ++static int jh7100_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return jh7100_reset_update(rcdev, id, true); ++} ++ ++static int jh7100_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return jh7100_reset_update(rcdev, id, false); ++} ++ ++static int jh7100_reset_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ ++ ret = jh7100_reset_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return jh7100_reset_deassert(rcdev, id); ++} ++ ++static int jh7100_reset_status(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct jh7100_reset *data = jh7100_reset_from(rcdev); ++ unsigned long offset = BIT_ULL_WORD(id); ++ u64 mask = BIT_ULL_MASK(id); ++ void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); ++ u64 value = readq(reg_status); ++ ++ return !((value ^ jh7100_reset_asserted[offset]) & mask); ++} ++ ++static const struct reset_control_ops jh7100_reset_ops = { ++ .assert = jh7100_reset_assert, ++ .deassert = jh7100_reset_deassert, ++ .reset = jh7100_reset_reset, ++ .status = jh7100_reset_status, ++}; ++ ++int jh7100_reset_probe(struct platform_device *pdev) ++{ ++ struct jh7100_reset *data; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(data->base)) ++ return PTR_ERR(data->base); ++ ++ data->rcdev.ops = &jh7100_reset_ops; ++ data->rcdev.owner = THIS_MODULE; ++ data->rcdev.nr_resets = JH7100_RSTN_END; ++ data->rcdev.dev = &pdev->dev; ++ data->rcdev.of_node = pdev->dev.of_node; ++ spin_lock_init(&data->lock); ++ ++ return devm_reset_controller_register(&pdev->dev, &data->rcdev); ++} ++EXPORT_SYMBOL_GPL(jh7100_reset_probe); +--- /dev/null ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++#ifndef __RESET_STARFIVE_JH71X0_H ++#define __RESET_STARFIVE_JH71X0_H ++ ++int jh7100_reset_probe(struct platform_device *pdev); ++ ++#endif /* __RESET_STARFIVE_JH71X0_H */ diff --git a/target/linux/starfive/patches-6.1/0010-reset-starfive-Extract-the-common-JH71X0-reset-code.patch b/target/linux/starfive/patches-6.1/0010-reset-starfive-Extract-the-common-JH71X0-reset-code.patch new file mode 100644 index 0000000000..0a932f57b2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0010-reset-starfive-Extract-the-common-JH71X0-reset-code.patch @@ -0,0 +1,215 @@ +From dbee38aac9811a25e3e3204f813048bf64155248 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:22 +0800 +Subject: [PATCH 010/122] reset: starfive: Extract the common JH71X0 reset code + +Extract the common JH71X0 reset code for reusing them to +support JH7110 SoC. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../reset/starfive/reset-starfive-jh7100.c | 49 ++++++++++++ + .../reset/starfive/reset-starfive-jh71x0.c | 76 ++++++------------- + .../reset/starfive/reset-starfive-jh71x0.h | 5 +- + 3 files changed, 76 insertions(+), 54 deletions(-) + +--- a/drivers/reset/starfive/reset-starfive-jh7100.c ++++ b/drivers/reset/starfive/reset-starfive-jh7100.c +@@ -10,6 +10,55 @@ + + #include "reset-starfive-jh71x0.h" + ++#include ++ ++/* register offsets */ ++#define JH7100_RESET_ASSERT0 0x00 ++#define JH7100_RESET_ASSERT1 0x04 ++#define JH7100_RESET_ASSERT2 0x08 ++#define JH7100_RESET_ASSERT3 0x0c ++#define JH7100_RESET_STATUS0 0x10 ++#define JH7100_RESET_STATUS1 0x14 ++#define JH7100_RESET_STATUS2 0x18 ++#define JH7100_RESET_STATUS3 0x1c ++ ++/* ++ * Writing a 1 to the n'th bit of the m'th ASSERT register asserts ++ * line 32m + 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 u64 jh7100_reset_asserted[2] = { ++ /* STATUS0 */ ++ BIT_ULL_MASK(JH7100_RST_U74) | ++ BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | ++ BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | ++ /* STATUS1 */ ++ BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | ++ BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), ++ /* STATUS2 */ ++ BIT_ULL_MASK(JH7100_RST_E24) | ++ /* STATUS3 */ ++ 0, ++}; ++ ++static int __init jh7100_reset_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_jh7100_register(&pdev->dev, pdev->dev.of_node, ++ base + JH7100_RESET_ASSERT0, ++ base + JH7100_RESET_STATUS0, ++ jh7100_reset_asserted, ++ JH7100_RSTN_END, ++ THIS_MODULE); ++} ++ + static const struct of_device_id jh7100_reset_dt_ids[] = { + { .compatible = "starfive,jh7100-reset" }, + { /* sentinel */ } +--- a/drivers/reset/starfive/reset-starfive-jh71x0.c ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.c +@@ -10,51 +10,18 @@ + #include + #include + #include +-#include + #include + #include + + #include "reset-starfive-jh71x0.h" + +-#include +- +-/* register offsets */ +-#define JH7100_RESET_ASSERT0 0x00 +-#define JH7100_RESET_ASSERT1 0x04 +-#define JH7100_RESET_ASSERT2 0x08 +-#define JH7100_RESET_ASSERT3 0x0c +-#define JH7100_RESET_STATUS0 0x10 +-#define JH7100_RESET_STATUS1 0x14 +-#define JH7100_RESET_STATUS2 0x18 +-#define JH7100_RESET_STATUS3 0x1c +- +-/* +- * Writing a 1 to the n'th bit of the m'th ASSERT register asserts +- * line 32m + 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 u64 jh7100_reset_asserted[2] = { +- /* STATUS0 */ +- BIT_ULL_MASK(JH7100_RST_U74) | +- BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | +- BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | +- /* STATUS1 */ +- BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | +- BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), +- /* STATUS2 */ +- BIT_ULL_MASK(JH7100_RST_E24) | +- /* STATUS3 */ +- 0, +-}; +- + struct jh7100_reset { + struct reset_controller_dev rcdev; + /* protect registers against concurrent read-modify-write */ + spinlock_t lock; +- void __iomem *base; ++ void __iomem *assert; ++ void __iomem *status; ++ const u64 *asserted; + }; + + static inline struct jh7100_reset * +@@ -69,9 +36,9 @@ static int jh7100_reset_update(struct re + struct jh7100_reset *data = jh7100_reset_from(rcdev); + unsigned long offset = BIT_ULL_WORD(id); + u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(u64); +- void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); +- u64 done = jh7100_reset_asserted[offset] & mask; ++ void __iomem *reg_assert = data->assert + offset * sizeof(u64); ++ void __iomem *reg_status = data->status + offset * sizeof(u64); ++ u64 done = data->asserted ? data->asserted[offset] & mask : 0; + u64 value; + unsigned long flags; + int ret; +@@ -125,10 +92,10 @@ static int jh7100_reset_status(struct re + struct jh7100_reset *data = jh7100_reset_from(rcdev); + unsigned long offset = BIT_ULL_WORD(id); + u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); ++ void __iomem *reg_status = data->status + offset * sizeof(u64); + u64 value = readq(reg_status); + +- return !((value ^ jh7100_reset_asserted[offset]) & mask); ++ return !((value ^ data->asserted[offset]) & mask); + } + + static const struct reset_control_ops jh7100_reset_ops = { +@@ -138,25 +105,28 @@ static const struct reset_control_ops jh + .status = jh7100_reset_status, + }; + +-int jh7100_reset_probe(struct platform_device *pdev) ++int reset_starfive_jh7100_register(struct device *dev, struct device_node *of_node, ++ void __iomem *assert, void __iomem *status, ++ const u64 *asserted, unsigned int nr_resets, ++ struct module *owner) + { + struct jh7100_reset *data; + +- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + +- data->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(data->base)) +- return PTR_ERR(data->base); +- + data->rcdev.ops = &jh7100_reset_ops; +- data->rcdev.owner = THIS_MODULE; +- data->rcdev.nr_resets = JH7100_RSTN_END; +- data->rcdev.dev = &pdev->dev; +- data->rcdev.of_node = pdev->dev.of_node; ++ data->rcdev.owner = owner; ++ data->rcdev.nr_resets = nr_resets; ++ data->rcdev.dev = dev; ++ data->rcdev.of_node = of_node; ++ + spin_lock_init(&data->lock); ++ data->assert = assert; ++ data->status = status; ++ data->asserted = asserted; + +- return devm_reset_controller_register(&pdev->dev, &data->rcdev); ++ return devm_reset_controller_register(dev, &data->rcdev); + } +-EXPORT_SYMBOL_GPL(jh7100_reset_probe); ++EXPORT_SYMBOL_GPL(reset_starfive_jh7100_register); +--- a/drivers/reset/starfive/reset-starfive-jh71x0.h ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.h +@@ -6,6 +6,9 @@ + #ifndef __RESET_STARFIVE_JH71X0_H + #define __RESET_STARFIVE_JH71X0_H + +-int jh7100_reset_probe(struct platform_device *pdev); ++int reset_starfive_jh7100_register(struct device *dev, struct device_node *of_node, ++ void __iomem *assert, void __iomem *status, ++ const u64 *asserted, unsigned int nr_resets, ++ struct module *owner); + + #endif /* __RESET_STARFIVE_JH71X0_H */ diff --git a/target/linux/starfive/patches-6.1/0011-reset-starfive-Rename-jh7100-to-jh71x0-for-the-commo.patch b/target/linux/starfive/patches-6.1/0011-reset-starfive-Rename-jh7100-to-jh71x0-for-the-commo.patch new file mode 100644 index 0000000000..144d847725 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0011-reset-starfive-Rename-jh7100-to-jh71x0-for-the-commo.patch @@ -0,0 +1,167 @@ +From 798b9b4681be53ddbf1d8db8a88ff19aaaca500f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:23 +0800 +Subject: [PATCH 011/122] reset: starfive: Rename "jh7100" to "jh71x0" for the + common code + +For the common code will be shared with the StarFive JH7110 SoC. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../reset/starfive/reset-starfive-jh7100.c | 2 +- + .../reset/starfive/reset-starfive-jh71x0.c | 50 +++++++++---------- + .../reset/starfive/reset-starfive-jh71x0.h | 2 +- + 3 files changed, 27 insertions(+), 27 deletions(-) + +--- a/drivers/reset/starfive/reset-starfive-jh7100.c ++++ b/drivers/reset/starfive/reset-starfive-jh7100.c +@@ -51,7 +51,7 @@ static int __init jh7100_reset_probe(str + if (IS_ERR(base)) + return PTR_ERR(base); + +- return reset_starfive_jh7100_register(&pdev->dev, pdev->dev.of_node, ++ return reset_starfive_jh71x0_register(&pdev->dev, pdev->dev.of_node, + base + JH7100_RESET_ASSERT0, + base + JH7100_RESET_STATUS0, + jh7100_reset_asserted, +--- a/drivers/reset/starfive/reset-starfive-jh71x0.c ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-or-later + /* +- * Reset driver for the StarFive JH7100 SoC ++ * Reset driver for the StarFive JH71X0 SoCs + * + * Copyright (C) 2021 Emil Renner Berthing + */ +@@ -15,7 +15,7 @@ + + #include "reset-starfive-jh71x0.h" + +-struct jh7100_reset { ++struct jh71x0_reset { + struct reset_controller_dev rcdev; + /* protect registers against concurrent read-modify-write */ + spinlock_t lock; +@@ -24,16 +24,16 @@ struct jh7100_reset { + const u64 *asserted; + }; + +-static inline struct jh7100_reset * +-jh7100_reset_from(struct reset_controller_dev *rcdev) ++static inline struct jh71x0_reset * ++jh71x0_reset_from(struct reset_controller_dev *rcdev) + { +- return container_of(rcdev, struct jh7100_reset, rcdev); ++ return container_of(rcdev, struct jh71x0_reset, rcdev); + } + +-static int jh7100_reset_update(struct reset_controller_dev *rcdev, ++static int jh71x0_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) + { +- struct jh7100_reset *data = jh7100_reset_from(rcdev); ++ struct jh71x0_reset *data = jh71x0_reset_from(rcdev); + unsigned long offset = BIT_ULL_WORD(id); + u64 mask = BIT_ULL_MASK(id); + void __iomem *reg_assert = data->assert + offset * sizeof(u64); +@@ -62,34 +62,34 @@ static int jh7100_reset_update(struct re + return ret; + } + +-static int jh7100_reset_assert(struct reset_controller_dev *rcdev, ++static int jh71x0_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) + { +- return jh7100_reset_update(rcdev, id, true); ++ return jh71x0_reset_update(rcdev, id, true); + } + +-static int jh7100_reset_deassert(struct reset_controller_dev *rcdev, ++static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) + { +- return jh7100_reset_update(rcdev, id, false); ++ return jh71x0_reset_update(rcdev, id, false); + } + +-static int jh7100_reset_reset(struct reset_controller_dev *rcdev, ++static int jh71x0_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) + { + int ret; + +- ret = jh7100_reset_assert(rcdev, id); ++ ret = jh71x0_reset_assert(rcdev, id); + if (ret) + return ret; + +- return jh7100_reset_deassert(rcdev, id); ++ return jh71x0_reset_deassert(rcdev, id); + } + +-static int jh7100_reset_status(struct reset_controller_dev *rcdev, ++static int jh71x0_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) + { +- struct jh7100_reset *data = jh7100_reset_from(rcdev); ++ struct jh71x0_reset *data = jh71x0_reset_from(rcdev); + unsigned long offset = BIT_ULL_WORD(id); + u64 mask = BIT_ULL_MASK(id); + void __iomem *reg_status = data->status + offset * sizeof(u64); +@@ -98,25 +98,25 @@ static int jh7100_reset_status(struct re + return !((value ^ data->asserted[offset]) & mask); + } + +-static const struct reset_control_ops jh7100_reset_ops = { +- .assert = jh7100_reset_assert, +- .deassert = jh7100_reset_deassert, +- .reset = jh7100_reset_reset, +- .status = jh7100_reset_status, ++static const struct reset_control_ops jh71x0_reset_ops = { ++ .assert = jh71x0_reset_assert, ++ .deassert = jh71x0_reset_deassert, ++ .reset = jh71x0_reset_reset, ++ .status = jh71x0_reset_status, + }; + +-int reset_starfive_jh7100_register(struct device *dev, struct device_node *of_node, ++int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, + void __iomem *assert, void __iomem *status, + const u64 *asserted, unsigned int nr_resets, + struct module *owner) + { +- struct jh7100_reset *data; ++ struct jh71x0_reset *data; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + +- data->rcdev.ops = &jh7100_reset_ops; ++ data->rcdev.ops = &jh71x0_reset_ops; + data->rcdev.owner = owner; + data->rcdev.nr_resets = nr_resets; + data->rcdev.dev = dev; +@@ -129,4 +129,4 @@ int reset_starfive_jh7100_register(struc + + return devm_reset_controller_register(dev, &data->rcdev); + } +-EXPORT_SYMBOL_GPL(reset_starfive_jh7100_register); ++EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register); +--- a/drivers/reset/starfive/reset-starfive-jh71x0.h ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.h +@@ -6,7 +6,7 @@ + #ifndef __RESET_STARFIVE_JH71X0_H + #define __RESET_STARFIVE_JH71X0_H + +-int reset_starfive_jh7100_register(struct device *dev, struct device_node *of_node, ++int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, + void __iomem *assert, void __iomem *status, + const u64 *asserted, unsigned int nr_resets, + struct module *owner); diff --git a/target/linux/starfive/patches-6.1/0012-reset-starfive-jh71x0-Use-32bit-I-O-on-32bit-registe.patch b/target/linux/starfive/patches-6.1/0012-reset-starfive-jh71x0-Use-32bit-I-O-on-32bit-registe.patch new file mode 100644 index 0000000000..459ac5a3b6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0012-reset-starfive-jh71x0-Use-32bit-I-O-on-32bit-registe.patch @@ -0,0 +1,146 @@ +From 365bb978e5e11a16c362d9c2c64d7bf8d04999df Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:24 +0800 +Subject: [PATCH 012/122] reset: starfive: jh71x0: Use 32bit I/O on 32bit + registers + +We currently use 64bit I/O on the 32bit registers. This works because +there are an even number of assert and status registers, so they're only +ever accessed in pairs on 64bit boundaries. + +There are however other reset controllers for audio and video on the +JH7100 SoC with only one status register that isn't 64bit aligned so +64bit I/O results in an unaligned access exception. + +Switch to 32bit I/O in preparation for supporting these resets too. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../reset/starfive/reset-starfive-jh7100.c | 14 ++++----- + .../reset/starfive/reset-starfive-jh71x0.c | 31 +++++++++---------- + .../reset/starfive/reset-starfive-jh71x0.h | 2 +- + 3 files changed, 23 insertions(+), 24 deletions(-) + +--- a/drivers/reset/starfive/reset-starfive-jh7100.c ++++ b/drivers/reset/starfive/reset-starfive-jh7100.c +@@ -30,16 +30,16 @@ + * lines don't though, so store the expected value of the status registers when + * all lines are asserted. + */ +-static const u64 jh7100_reset_asserted[2] = { ++static const u32 jh7100_reset_asserted[4] = { + /* STATUS0 */ +- BIT_ULL_MASK(JH7100_RST_U74) | +- BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | +- BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | ++ BIT(JH7100_RST_U74 % 32) | ++ BIT(JH7100_RST_VP6_DRESET % 32) | ++ BIT(JH7100_RST_VP6_BRESET % 32), + /* STATUS1 */ +- BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | +- BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), ++ BIT(JH7100_RST_HIFI4_DRESET % 32) | ++ BIT(JH7100_RST_HIFI4_BRESET % 32), + /* STATUS2 */ +- BIT_ULL_MASK(JH7100_RST_E24) | ++ BIT(JH7100_RST_E24 % 32), + /* STATUS3 */ + 0, + }; +--- a/drivers/reset/starfive/reset-starfive-jh71x0.c ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.c +@@ -8,7 +8,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -21,7 +20,7 @@ struct jh71x0_reset { + spinlock_t lock; + void __iomem *assert; + void __iomem *status; +- const u64 *asserted; ++ const u32 *asserted; + }; + + static inline struct jh71x0_reset * +@@ -34,12 +33,12 @@ static int jh71x0_reset_update(struct re + unsigned long id, bool assert) + { + struct jh71x0_reset *data = jh71x0_reset_from(rcdev); +- unsigned long offset = BIT_ULL_WORD(id); +- u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_assert = data->assert + offset * sizeof(u64); +- void __iomem *reg_status = data->status + offset * sizeof(u64); +- u64 done = data->asserted ? data->asserted[offset] & mask : 0; +- u64 value; ++ unsigned long offset = id / 32; ++ u32 mask = BIT(id % 32); ++ void __iomem *reg_assert = data->assert + offset * sizeof(u32); ++ void __iomem *reg_status = data->status + offset * sizeof(u32); ++ u32 done = data->asserted ? data->asserted[offset] & mask : 0; ++ u32 value; + unsigned long flags; + int ret; + +@@ -48,15 +47,15 @@ static int jh71x0_reset_update(struct re + + spin_lock_irqsave(&data->lock, flags); + +- value = readq(reg_assert); ++ value = readl(reg_assert); + if (assert) + value |= mask; + else + value &= ~mask; +- writeq(value, reg_assert); ++ writel(value, reg_assert); + + /* if the associated clock is gated, deasserting might otherwise hang forever */ +- ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); ++ ret = readl_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); + + spin_unlock_irqrestore(&data->lock, flags); + return ret; +@@ -90,10 +89,10 @@ static int jh71x0_reset_status(struct re + unsigned long id) + { + struct jh71x0_reset *data = jh71x0_reset_from(rcdev); +- unsigned long offset = BIT_ULL_WORD(id); +- u64 mask = BIT_ULL_MASK(id); +- void __iomem *reg_status = data->status + offset * sizeof(u64); +- u64 value = readq(reg_status); ++ unsigned long offset = id / 32; ++ u32 mask = BIT(id % 32); ++ void __iomem *reg_status = data->status + offset * sizeof(u32); ++ u32 value = readl(reg_status); + + return !((value ^ data->asserted[offset]) & mask); + } +@@ -107,7 +106,7 @@ static const struct reset_control_ops jh + + int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, + void __iomem *assert, void __iomem *status, +- const u64 *asserted, unsigned int nr_resets, ++ const u32 *asserted, unsigned int nr_resets, + struct module *owner) + { + struct jh71x0_reset *data; +--- a/drivers/reset/starfive/reset-starfive-jh71x0.h ++++ b/drivers/reset/starfive/reset-starfive-jh71x0.h +@@ -8,7 +8,7 @@ + + int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, + void __iomem *assert, void __iomem *status, +- const u64 *asserted, unsigned int nr_resets, ++ const u32 *asserted, unsigned int nr_resets, + struct module *owner); + + #endif /* __RESET_STARFIVE_JH71X0_H */ diff --git a/target/linux/starfive/patches-6.1/0013-clk-starfive-Add-StarFive-JH7110-system-clock-driver.patch b/target/linux/starfive/patches-6.1/0013-clk-starfive-Add-StarFive-JH7110-system-clock-driver.patch new file mode 100644 index 0000000000..f272d5179b --- /dev/null +++ b/target/linux/starfive/patches-6.1/0013-clk-starfive-Add-StarFive-JH7110-system-clock-driver.patch @@ -0,0 +1,557 @@ +From eea853275c704f6c24a418a50715bc5ad68a6283 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:25 +0800 +Subject: [PATCH 013/122] clk: starfive: Add StarFive JH7110 system clock + driver + +Add driver for the StarFive JH7110 system clock controller and +register an auxiliary device for system reset controller which +is named as "rst-sys". + +Tested-by: Tommaso Merciai +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Co-developed-by: Hal Feng +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/clk/starfive/Kconfig | 11 + + drivers/clk/starfive/Makefile | 2 + + .../clk/starfive/clk-starfive-jh7110-sys.c | 490 ++++++++++++++++++ + drivers/clk/starfive/clk-starfive-jh7110.h | 11 + + 4 files changed, 514 insertions(+) + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-sys.c + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110.h + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -20,3 +20,14 @@ config CLK_STARFIVE_JH7100_AUDIO + help + Say Y or M here to support the audio clocks on the StarFive JH7100 + SoC. ++ ++config CLK_STARFIVE_JH7110_SYS ++ bool "StarFive JH7110 system clock support" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ select AUXILIARY_BUS ++ select CLK_STARFIVE_JH71X0 ++ select RESET_STARFIVE_JH7110 ++ default ARCH_STARFIVE ++ help ++ Say yes here to support the system clock controller on the ++ StarFive JH7110 SoC. +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -3,3 +3,5 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk + + obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o + obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o ++ ++obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +@@ -0,0 +1,490 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7110 System Clock Driver ++ * ++ * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-starfive-jh7110.h" ++ ++/* external clocks */ ++#define JH7110_SYSCLK_OSC (JH7110_SYSCLK_END + 0) ++#define JH7110_SYSCLK_GMAC1_RMII_REFIN (JH7110_SYSCLK_END + 1) ++#define JH7110_SYSCLK_GMAC1_RGMII_RXIN (JH7110_SYSCLK_END + 2) ++#define JH7110_SYSCLK_I2STX_BCLK_EXT (JH7110_SYSCLK_END + 3) ++#define JH7110_SYSCLK_I2STX_LRCK_EXT (JH7110_SYSCLK_END + 4) ++#define JH7110_SYSCLK_I2SRX_BCLK_EXT (JH7110_SYSCLK_END + 5) ++#define JH7110_SYSCLK_I2SRX_LRCK_EXT (JH7110_SYSCLK_END + 6) ++#define JH7110_SYSCLK_TDM_EXT (JH7110_SYSCLK_END + 7) ++#define JH7110_SYSCLK_MCLK_EXT (JH7110_SYSCLK_END + 8) ++#define JH7110_SYSCLK_PLL0_OUT (JH7110_SYSCLK_END + 9) ++#define JH7110_SYSCLK_PLL1_OUT (JH7110_SYSCLK_END + 10) ++#define JH7110_SYSCLK_PLL2_OUT (JH7110_SYSCLK_END + 11) ++ ++static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { ++ /* root */ ++ JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2, ++ JH7110_SYSCLK_OSC, ++ JH7110_SYSCLK_PLL0_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT), ++ JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE), ++ JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2, ++ JH7110_SYSCLK_PLL2_OUT, ++ JH7110_SYSCLK_PLL1_OUT), ++ JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2, ++ JH7110_SYSCLK_PLL0_OUT, ++ JH7110_SYSCLK_PLL2_OUT), ++ JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2, ++ JH7110_SYSCLK_OSC, ++ JH7110_SYSCLK_PLL2_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT), ++ JH71X0__DIV(JH7110_SYSCLK_AXI_CFG0, "axi_cfg0", 3, JH7110_SYSCLK_BUS_ROOT), ++ JH71X0__DIV(JH7110_SYSCLK_STG_AXIAHB, "stg_axiahb", 2, JH7110_SYSCLK_AXI_CFG0), ++ JH71X0_GATE(JH7110_SYSCLK_AHB0, "ahb0", CLK_IS_CRITICAL, JH7110_SYSCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_SYSCLK_AHB1, "ahb1", CLK_IS_CRITICAL, JH7110_SYSCLK_STG_AXIAHB), ++ JH71X0__DIV(JH7110_SYSCLK_APB_BUS, "apb_bus", 8, JH7110_SYSCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_SYSCLK_APB0, "apb0", CLK_IS_CRITICAL, JH7110_SYSCLK_APB_BUS), ++ JH71X0__DIV(JH7110_SYSCLK_PLL0_DIV2, "pll0_div2", 2, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV2, "pll1_div2", 2, JH7110_SYSCLK_PLL1_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT), ++ JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2, ++ JH7110_SYSCLK_MCLK_INNER, ++ JH7110_SYSCLK_MCLK_EXT), ++ JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER), ++ JH71X0_MDIV(JH7110_SYSCLK_ISP_2X, "isp_2x", 8, 2, ++ JH7110_SYSCLK_PLL2_OUT, ++ JH7110_SYSCLK_PLL1_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_ISP_AXI, "isp_axi", 4, JH7110_SYSCLK_ISP_2X), ++ JH71X0_GDIV(JH7110_SYSCLK_GCLK0, "gclk0", 0, 62, JH7110_SYSCLK_PLL0_DIV2), ++ JH71X0_GDIV(JH7110_SYSCLK_GCLK1, "gclk1", 0, 62, JH7110_SYSCLK_PLL1_DIV2), ++ JH71X0_GDIV(JH7110_SYSCLK_GCLK2, "gclk2", 0, 62, JH7110_SYSCLK_PLL2_DIV2), ++ /* cores */ ++ JH71X0_GATE(JH7110_SYSCLK_CORE, "core", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_CORE1, "core1", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_CORE2, "core2", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_CORE3, "core3", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_CORE4, "core4", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_DEBUG, "debug", 0, JH7110_SYSCLK_CPU_BUS), ++ JH71X0__DIV(JH7110_SYSCLK_RTC_TOGGLE, "rtc_toggle", 6, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_TRACE0, "trace0", 0, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_TRACE1, "trace1", 0, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_TRACE2, "trace2", 0, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_TRACE3, "trace3", 0, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_TRACE4, "trace4", 0, JH7110_SYSCLK_CPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_TRACE_COM, "trace_com", 0, JH7110_SYSCLK_CPU_BUS), ++ /* noc */ ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_CPU_AXI, "noc_bus_cpu_axi", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_CPU_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_AXICFG0_AXI, "noc_bus_axicfg0_axi", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_AXI_CFG0), ++ /* ddr */ ++ JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC), ++ JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2), ++ JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4), ++ JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4, ++ JH7110_SYSCLK_OSC_DIV2, ++ JH7110_SYSCLK_PLL1_DIV2, ++ JH7110_SYSCLK_PLL1_DIV4, ++ JH7110_SYSCLK_PLL1_DIV8), ++ JH71X0_GATE(JH7110_SYSCLK_DDR_AXI, "ddr_axi", CLK_IS_CRITICAL, JH7110_SYSCLK_DDR_BUS), ++ /* gpu */ ++ JH71X0__DIV(JH7110_SYSCLK_GPU_CORE, "gpu_core", 7, JH7110_SYSCLK_GPU_ROOT), ++ JH71X0_GATE(JH7110_SYSCLK_GPU_CORE_CLK, "gpu_core_clk", 0, JH7110_SYSCLK_GPU_CORE), ++ JH71X0_GATE(JH7110_SYSCLK_GPU_SYS_CLK, "gpu_sys_clk", 0, JH7110_SYSCLK_ISP_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_GPU_APB, "gpu_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GDIV(JH7110_SYSCLK_GPU_RTC_TOGGLE, "gpu_rtc_toggle", 0, 12, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_GPU_AXI, "noc_bus_gpu_axi", 0, JH7110_SYSCLK_GPU_CORE), ++ /* isp */ ++ JH71X0_GATE(JH7110_SYSCLK_ISP_TOP_CORE, "isp_top_core", 0, JH7110_SYSCLK_ISP_2X), ++ JH71X0_GATE(JH7110_SYSCLK_ISP_TOP_AXI, "isp_top_axi", 0, JH7110_SYSCLK_ISP_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_ISP_AXI, "noc_bus_isp_axi", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_ISP_AXI), ++ /* hifi4 */ ++ JH71X0__DIV(JH7110_SYSCLK_HIFI4_CORE, "hifi4_core", 15, JH7110_SYSCLK_BUS_ROOT), ++ JH71X0__DIV(JH7110_SYSCLK_HIFI4_AXI, "hifi4_axi", 2, JH7110_SYSCLK_HIFI4_CORE), ++ /* axi_cfg1 */ ++ JH71X0_GATE(JH7110_SYSCLK_AXI_CFG1_MAIN, "axi_cfg1_main", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_ISP_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_AXI_CFG1_AHB, "axi_cfg1_ahb", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_AHB0), ++ /* vout */ ++ JH71X0_GATE(JH7110_SYSCLK_VOUT_SRC, "vout_src", 0, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_VOUT_AXI, "vout_axi", 7, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_DISP_AXI, "noc_bus_disp_axi", 0, JH7110_SYSCLK_VOUT_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_AHB, "vout_top_ahb", 0, JH7110_SYSCLK_AHB1), ++ JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_AXI, "vout_top_axi", 0, JH7110_SYSCLK_VOUT_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK, "vout_top_hdmitx0_mclk", 0, ++ JH7110_SYSCLK_MCLK), ++ JH71X0__DIV(JH7110_SYSCLK_VOUT_TOP_MIPIPHY_REF, "vout_top_mipiphy_ref", 2, ++ JH7110_SYSCLK_OSC), ++ /* jpegc */ ++ JH71X0__DIV(JH7110_SYSCLK_JPEGC_AXI, "jpegc_axi", 16, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_CODAJ12_AXI, "codaj12_axi", 0, JH7110_SYSCLK_JPEGC_AXI), ++ JH71X0_GDIV(JH7110_SYSCLK_CODAJ12_CORE, "codaj12_core", 0, 16, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_CODAJ12_APB, "codaj12_apb", 0, JH7110_SYSCLK_APB_BUS), ++ /* vdec */ ++ JH71X0__DIV(JH7110_SYSCLK_VDEC_AXI, "vdec_axi", 7, JH7110_SYSCLK_BUS_ROOT), ++ JH71X0_GATE(JH7110_SYSCLK_WAVE511_AXI, "wave511_axi", 0, JH7110_SYSCLK_VDEC_AXI), ++ JH71X0_GDIV(JH7110_SYSCLK_WAVE511_BPU, "wave511_bpu", 0, 7, JH7110_SYSCLK_BUS_ROOT), ++ JH71X0_GDIV(JH7110_SYSCLK_WAVE511_VCE, "wave511_vce", 0, 7, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_WAVE511_APB, "wave511_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_VDEC_JPG, "vdec_jpg", 0, JH7110_SYSCLK_JPEGC_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_VDEC_MAIN, "vdec_main", 0, JH7110_SYSCLK_VDEC_AXI), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_VDEC_AXI, "noc_bus_vdec_axi", 0, JH7110_SYSCLK_VDEC_AXI), ++ /* venc */ ++ JH71X0__DIV(JH7110_SYSCLK_VENC_AXI, "venc_axi", 15, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_WAVE420L_AXI, "wave420l_axi", 0, JH7110_SYSCLK_VENC_AXI), ++ JH71X0_GDIV(JH7110_SYSCLK_WAVE420L_BPU, "wave420l_bpu", 0, 15, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0_GDIV(JH7110_SYSCLK_WAVE420L_VCE, "wave420l_vce", 0, 15, JH7110_SYSCLK_PLL2_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_WAVE420L_APB, "wave420l_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_VENC_AXI, "noc_bus_venc_axi", 0, JH7110_SYSCLK_VENC_AXI), ++ /* axi_cfg0 */ ++ JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_MAIN_DIV, "axi_cfg0_main_div", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_AHB1), ++ JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_MAIN, "axi_cfg0_main", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_AXI_CFG0), ++ JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_HIFI4, "axi_cfg0_hifi4", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_HIFI4_AXI), ++ /* intmem */ ++ JH71X0_GATE(JH7110_SYSCLK_AXIMEM2_AXI, "aximem2_axi", 0, JH7110_SYSCLK_AXI_CFG0), ++ /* qspi */ ++ JH71X0_GATE(JH7110_SYSCLK_QSPI_AHB, "qspi_ahb", 0, JH7110_SYSCLK_AHB1), ++ JH71X0_GATE(JH7110_SYSCLK_QSPI_APB, "qspi_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0__DIV(JH7110_SYSCLK_QSPI_REF_SRC, "qspi_ref_src", 16, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0_GMUX(JH7110_SYSCLK_QSPI_REF, "qspi_ref", 0, 2, ++ JH7110_SYSCLK_OSC, ++ JH7110_SYSCLK_QSPI_REF_SRC), ++ /* sdio */ ++ JH71X0_GATE(JH7110_SYSCLK_SDIO0_AHB, "sdio0_ahb", 0, JH7110_SYSCLK_AHB0), ++ JH71X0_GATE(JH7110_SYSCLK_SDIO1_AHB, "sdio1_ahb", 0, JH7110_SYSCLK_AHB0), ++ JH71X0_GDIV(JH7110_SYSCLK_SDIO0_SDCARD, "sdio0_sdcard", 0, 15, JH7110_SYSCLK_AXI_CFG0), ++ JH71X0_GDIV(JH7110_SYSCLK_SDIO1_SDCARD, "sdio1_sdcard", 0, 15, JH7110_SYSCLK_AXI_CFG0), ++ /* stg */ ++ JH71X0__DIV(JH7110_SYSCLK_USB_125M, "usb_125m", 15, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_STG_AXI, "noc_bus_stg_axi", CLK_IS_CRITICAL, ++ JH7110_SYSCLK_NOCSTG_BUS), ++ /* gmac1 */ ++ JH71X0_GATE(JH7110_SYSCLK_GMAC1_AHB, "gmac1_ahb", 0, JH7110_SYSCLK_AHB0), ++ JH71X0_GATE(JH7110_SYSCLK_GMAC1_AXI, "gmac1_axi", 0, JH7110_SYSCLK_STG_AXIAHB), ++ JH71X0__DIV(JH7110_SYSCLK_GMAC_SRC, "gmac_src", 7, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_GMAC1_GTXCLK, "gmac1_gtxclk", 15, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30, ++ JH7110_SYSCLK_GMAC1_RMII_REFIN), ++ JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), ++ JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2, ++ JH7110_SYSCLK_GMAC1_RGMII_RXIN, ++ JH7110_SYSCLK_GMAC1_RMII_RTX), ++ JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX), ++ JH71X0_GMUX(JH7110_SYSCLK_GMAC1_TX, "gmac1_tx", ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, ++ JH7110_SYSCLK_GMAC1_GTXCLK, ++ JH7110_SYSCLK_GMAC1_RMII_RTX), ++ JH71X0__INV(JH7110_SYSCLK_GMAC1_TX_INV, "gmac1_tx_inv", JH7110_SYSCLK_GMAC1_TX), ++ JH71X0_GATE(JH7110_SYSCLK_GMAC1_GTXC, "gmac1_gtxc", 0, JH7110_SYSCLK_GMAC1_GTXCLK), ++ /* gmac0 */ ++ JH71X0_GDIV(JH7110_SYSCLK_GMAC0_GTXCLK, "gmac0_gtxclk", 0, 15, JH7110_SYSCLK_PLL0_OUT), ++ JH71X0_GDIV(JH7110_SYSCLK_GMAC0_PTP, "gmac0_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), ++ JH71X0_GDIV(JH7110_SYSCLK_GMAC_PHY, "gmac_phy", 0, 31, JH7110_SYSCLK_GMAC_SRC), ++ JH71X0_GATE(JH7110_SYSCLK_GMAC0_GTXC, "gmac0_gtxc", 0, JH7110_SYSCLK_GMAC0_GTXCLK), ++ /* apb misc */ ++ JH71X0_GATE(JH7110_SYSCLK_IOMUX_APB, "iomux_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_MAILBOX_APB, "mailbox_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_INT_CTRL_APB, "int_ctrl_apb", 0, JH7110_SYSCLK_APB_BUS), ++ /* can0 */ ++ JH71X0_GATE(JH7110_SYSCLK_CAN0_APB, "can0_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GDIV(JH7110_SYSCLK_CAN0_TIMER, "can0_timer", 0, 24, JH7110_SYSCLK_OSC), ++ JH71X0_GDIV(JH7110_SYSCLK_CAN0_CAN, "can0_can", 0, 63, JH7110_SYSCLK_PERH_ROOT), ++ /* can1 */ ++ JH71X0_GATE(JH7110_SYSCLK_CAN1_APB, "can1_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GDIV(JH7110_SYSCLK_CAN1_TIMER, "can1_timer", 0, 24, JH7110_SYSCLK_OSC), ++ JH71X0_GDIV(JH7110_SYSCLK_CAN1_CAN, "can1_can", 0, 63, JH7110_SYSCLK_PERH_ROOT), ++ /* pwm */ ++ JH71X0_GATE(JH7110_SYSCLK_PWM_APB, "pwm_apb", 0, JH7110_SYSCLK_APB_BUS), ++ /* wdt */ ++ JH71X0_GATE(JH7110_SYSCLK_WDT_APB, "wdt_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_WDT_CORE, "wdt_core", 0, JH7110_SYSCLK_OSC), ++ /* timer */ ++ JH71X0_GATE(JH7110_SYSCLK_TIMER_APB, "timer_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_TIMER0, "timer0", 0, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_TIMER1, "timer1", 0, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_TIMER2, "timer2", 0, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_TIMER3, "timer3", 0, JH7110_SYSCLK_OSC), ++ /* temp sensor */ ++ JH71X0_GATE(JH7110_SYSCLK_TEMP_APB, "temp_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GDIV(JH7110_SYSCLK_TEMP_CORE, "temp_core", 0, 24, JH7110_SYSCLK_OSC), ++ /* spi */ ++ JH71X0_GATE(JH7110_SYSCLK_SPI0_APB, "spi0_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_SPI1_APB, "spi1_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_SPI2_APB, "spi2_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_SPI3_APB, "spi3_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_SPI4_APB, "spi4_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_SPI5_APB, "spi5_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_SPI6_APB, "spi6_apb", 0, JH7110_SYSCLK_APB_BUS), ++ /* i2c */ ++ JH71X0_GATE(JH7110_SYSCLK_I2C0_APB, "i2c0_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_I2C1_APB, "i2c1_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_I2C2_APB, "i2c2_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_I2C3_APB, "i2c3_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_I2C4_APB, "i2c4_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_I2C5_APB, "i2c5_apb", 0, JH7110_SYSCLK_APB_BUS), ++ JH71X0_GATE(JH7110_SYSCLK_I2C6_APB, "i2c6_apb", 0, JH7110_SYSCLK_APB_BUS), ++ /* uart */ ++ JH71X0_GATE(JH7110_SYSCLK_UART0_APB, "uart0_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_UART0_CORE, "uart0_core", 0, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_UART1_APB, "uart1_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_UART1_CORE, "uart1_core", 0, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_UART2_APB, "uart2_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_UART2_CORE, "uart2_core", 0, JH7110_SYSCLK_OSC), ++ JH71X0_GATE(JH7110_SYSCLK_UART3_APB, "uart3_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_UART3_CORE, "uart3_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), ++ JH71X0_GATE(JH7110_SYSCLK_UART4_APB, "uart4_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_UART4_CORE, "uart4_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), ++ JH71X0_GATE(JH7110_SYSCLK_UART5_APB, "uart5_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_UART5_CORE, "uart5_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), ++ /* pwmdac */ ++ JH71X0_GATE(JH7110_SYSCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_PWMDAC_CORE, "pwmdac_core", 0, 256, JH7110_SYSCLK_AUDIO_ROOT), ++ /* spdif */ ++ JH71X0_GATE(JH7110_SYSCLK_SPDIF_APB, "spdif_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GATE(JH7110_SYSCLK_SPDIF_CORE, "spdif_core", 0, JH7110_SYSCLK_MCLK), ++ /* i2stx0 */ ++ JH71X0_GATE(JH7110_SYSCLK_I2STX0_APB, "i2stx0_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_I2STX0_BCLK_MST, "i2stx0_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), ++ JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_MST_INV, "i2stx0_bclk_mst_inv", ++ JH7110_SYSCLK_I2STX0_BCLK_MST), ++ JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2, ++ JH7110_SYSCLK_I2STX0_BCLK_MST_INV, ++ JH7110_SYSCLK_I2STX0_BCLK_MST), ++ JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2, ++ JH7110_SYSCLK_I2STX0_BCLK_MST, ++ JH7110_SYSCLK_I2STX_BCLK_EXT), ++ JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK), ++ JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2, ++ JH7110_SYSCLK_I2STX0_LRCK_MST, ++ JH7110_SYSCLK_I2STX_LRCK_EXT), ++ /* i2stx1 */ ++ JH71X0_GATE(JH7110_SYSCLK_I2STX1_APB, "i2stx1_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_I2STX1_BCLK_MST, "i2stx1_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), ++ JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_MST_INV, "i2stx1_bclk_mst_inv", ++ JH7110_SYSCLK_I2STX1_BCLK_MST), ++ JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2, ++ JH7110_SYSCLK_I2STX1_BCLK_MST_INV, ++ JH7110_SYSCLK_I2STX1_BCLK_MST), ++ JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2, ++ JH7110_SYSCLK_I2STX1_BCLK_MST, ++ JH7110_SYSCLK_I2STX_BCLK_EXT), ++ JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK), ++ JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2, ++ JH7110_SYSCLK_I2STX1_LRCK_MST, ++ JH7110_SYSCLK_I2STX_LRCK_EXT), ++ /* i2srx */ ++ JH71X0_GATE(JH7110_SYSCLK_I2SRX_APB, "i2srx_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_I2SRX_BCLK_MST, "i2srx_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), ++ JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_MST_INV, "i2srx_bclk_mst_inv", ++ JH7110_SYSCLK_I2SRX_BCLK_MST), ++ JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2, ++ JH7110_SYSCLK_I2SRX_BCLK_MST_INV, ++ JH7110_SYSCLK_I2SRX_BCLK_MST), ++ JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2, ++ JH7110_SYSCLK_I2SRX_BCLK_MST, ++ JH7110_SYSCLK_I2SRX_BCLK_EXT), ++ JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK), ++ JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2, ++ JH7110_SYSCLK_I2SRX_LRCK_MST, ++ JH7110_SYSCLK_I2SRX_LRCK_EXT), ++ /* pdm */ ++ JH71X0_GDIV(JH7110_SYSCLK_PDM_DMIC, "pdm_dmic", 0, 64, JH7110_SYSCLK_MCLK), ++ JH71X0_GATE(JH7110_SYSCLK_PDM_APB, "pdm_apb", 0, JH7110_SYSCLK_APB0), ++ /* tdm */ ++ JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0), ++ JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0), ++ JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK), ++ JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2, ++ JH7110_SYSCLK_TDM_INTERNAL, ++ JH7110_SYSCLK_TDM_EXT), ++ JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM), ++ /* jtag */ ++ JH71X0__DIV(JH7110_SYSCLK_JTAG_CERTIFICATION_TRNG, "jtag_certification_trng", 4, ++ JH7110_SYSCLK_OSC), ++}; ++ ++static struct clk_hw *jh7110_sysclk_get(struct of_phandle_args *clkspec, void *data) ++{ ++ struct jh71x0_clk_priv *priv = data; ++ unsigned int idx = clkspec->args[0]; ++ ++ if (idx < JH7110_SYSCLK_END) ++ return &priv->reg[idx].hw; ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++static void jh7110_reset_unregister_adev(void *_adev) ++{ ++ struct auxiliary_device *adev = _adev; ++ ++ auxiliary_device_delete(adev); ++} ++ ++static void jh7110_reset_adev_release(struct device *dev) ++{ ++ struct auxiliary_device *adev = to_auxiliary_dev(dev); ++ ++ auxiliary_device_uninit(adev); ++} ++ ++int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, ++ const char *adev_name, ++ u32 adev_id) ++{ ++ struct auxiliary_device *adev; ++ int ret; ++ ++ adev = devm_kzalloc(priv->dev, sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return -ENOMEM; ++ ++ adev->name = adev_name; ++ adev->dev.parent = priv->dev; ++ adev->dev.release = jh7110_reset_adev_release; ++ adev->id = adev_id; ++ ++ ret = auxiliary_device_init(adev); ++ if (ret) ++ return ret; ++ ++ ret = auxiliary_device_add(adev); ++ if (ret) { ++ auxiliary_device_uninit(adev); ++ return ret; ++ } ++ ++ return devm_add_action_or_reset(priv->dev, ++ jh7110_reset_unregister_adev, adev); ++} ++EXPORT_SYMBOL_GPL(jh7110_reset_controller_register); ++ ++static int __init jh7110_syscrg_probe(struct platform_device *pdev) ++{ ++ struct jh71x0_clk_priv *priv; ++ unsigned int idx; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, ++ struct_size(priv, reg, JH7110_SYSCLK_END), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->rmw_lock); ++ priv->dev = &pdev->dev; ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ dev_set_drvdata(priv->dev, (void *)(&priv->base)); ++ ++ /* ++ * These PLL clocks are not actually fixed factor clocks and can be ++ * controlled by the syscon registers of JH7110. They will be dropped ++ * and registered in the PLL clock driver instead. ++ */ ++ /* 24MHz -> 1000.0MHz */ ++ priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out", ++ "osc", 0, 125, 3); ++ if (IS_ERR(priv->pll[0])) ++ return PTR_ERR(priv->pll[0]); ++ ++ /* 24MHz -> 1066.0MHz */ ++ priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out", ++ "osc", 0, 533, 12); ++ if (IS_ERR(priv->pll[1])) ++ return PTR_ERR(priv->pll[1]); ++ ++ /* 24MHz -> 1188.0MHz */ ++ priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out", ++ "osc", 0, 99, 2); ++ if (IS_ERR(priv->pll[2])) ++ return PTR_ERR(priv->pll[2]); ++ ++ for (idx = 0; idx < JH7110_SYSCLK_END; idx++) { ++ u32 max = jh7110_sysclk_data[idx].max; ++ struct clk_parent_data parents[4] = {}; ++ struct clk_init_data init = { ++ .name = jh7110_sysclk_data[idx].name, ++ .ops = starfive_jh71x0_clk_ops(max), ++ .parent_data = parents, ++ .num_parents = ++ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, ++ .flags = jh7110_sysclk_data[idx].flags, ++ }; ++ struct jh71x0_clk *clk = &priv->reg[idx]; ++ unsigned int i; ++ ++ for (i = 0; i < init.num_parents; i++) { ++ unsigned int pidx = jh7110_sysclk_data[idx].parents[i]; ++ ++ if (pidx < JH7110_SYSCLK_END) ++ parents[i].hw = &priv->reg[pidx].hw; ++ else if (pidx == JH7110_SYSCLK_OSC) ++ parents[i].fw_name = "osc"; ++ else if (pidx == JH7110_SYSCLK_GMAC1_RMII_REFIN) ++ parents[i].fw_name = "gmac1_rmii_refin"; ++ else if (pidx == JH7110_SYSCLK_GMAC1_RGMII_RXIN) ++ parents[i].fw_name = "gmac1_rgmii_rxin"; ++ else if (pidx == JH7110_SYSCLK_I2STX_BCLK_EXT) ++ parents[i].fw_name = "i2stx_bclk_ext"; ++ else if (pidx == JH7110_SYSCLK_I2STX_LRCK_EXT) ++ parents[i].fw_name = "i2stx_lrck_ext"; ++ else if (pidx == JH7110_SYSCLK_I2SRX_BCLK_EXT) ++ parents[i].fw_name = "i2srx_bclk_ext"; ++ else if (pidx == JH7110_SYSCLK_I2SRX_LRCK_EXT) ++ parents[i].fw_name = "i2srx_lrck_ext"; ++ else if (pidx == JH7110_SYSCLK_TDM_EXT) ++ parents[i].fw_name = "tdm_ext"; ++ else if (pidx == JH7110_SYSCLK_MCLK_EXT) ++ parents[i].fw_name = "mclk_ext"; ++ else ++ parents[i].hw = priv->pll[pidx - JH7110_SYSCLK_PLL0_OUT]; ++ } ++ ++ clk->hw.init = &init; ++ clk->idx = idx; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clk->hw); ++ if (ret) ++ return ret; ++ } ++ ++ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_sysclk_get, priv); ++ if (ret) ++ return ret; ++ ++ return jh7110_reset_controller_register(priv, "rst-sys", 0); ++} ++ ++static const struct of_device_id jh7110_syscrg_match[] = { ++ { .compatible = "starfive,jh7110-syscrg" }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver jh7110_syscrg_driver = { ++ .driver = { ++ .name = "clk-starfive-jh7110-sys", ++ .of_match_table = jh7110_syscrg_match, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver_probe(jh7110_syscrg_driver, jh7110_syscrg_probe); +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __CLK_STARFIVE_JH7110_H ++#define __CLK_STARFIVE_JH7110_H ++ ++#include "clk-starfive-jh71x0.h" ++ ++int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, ++ const char *adev_name, ++ u32 adev_id); ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0014-clk-starfive-Add-StarFive-JH7110-always-on-clock-dri.patch b/target/linux/starfive/patches-6.1/0014-clk-starfive-Add-StarFive-JH7110-always-on-clock-dri.patch new file mode 100644 index 0000000000..4986c110f7 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0014-clk-starfive-Add-StarFive-JH7110-always-on-clock-dri.patch @@ -0,0 +1,206 @@ +From 6b9f7a65cd2e9cc4bdc2ee3c3fb46bef4568af0a Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:26 +0800 +Subject: [PATCH 014/122] clk: starfive: Add StarFive JH7110 always-on clock + driver + +Add driver for the StarFive JH7110 always-on clock controller +and register an auxiliary device for always-on reset controller +which is named as "rst-aon". + +Tested-by: Tommaso Merciai +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Co-developed-by: Hal Feng +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/clk/starfive/Kconfig | 11 ++ + drivers/clk/starfive/Makefile | 1 + + .../clk/starfive/clk-starfive-jh7110-aon.c | 156 ++++++++++++++++++ + 3 files changed, 168 insertions(+) + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-aon.c + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -31,3 +31,14 @@ config CLK_STARFIVE_JH7110_SYS + help + Say yes here to support the system clock controller on the + StarFive JH7110 SoC. ++ ++config CLK_STARFIVE_JH7110_AON ++ tristate "StarFive JH7110 always-on clock support" ++ depends on CLK_STARFIVE_JH7110_SYS ++ select AUXILIARY_BUS ++ select CLK_STARFIVE_JH71X0 ++ select RESET_STARFIVE_JH7110 ++ default m if ARCH_STARFIVE ++ help ++ Say yes here to support the always-on clock controller on the ++ StarFive JH7110 SoC. +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -5,3 +5,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk + obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o + + obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o ++obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c +@@ -0,0 +1,156 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7110 Always-On Clock Driver ++ * ++ * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-starfive-jh7110.h" ++ ++/* external clocks */ ++#define JH7110_AONCLK_OSC (JH7110_AONCLK_END + 0) ++#define JH7110_AONCLK_GMAC0_RMII_REFIN (JH7110_AONCLK_END + 1) ++#define JH7110_AONCLK_GMAC0_RGMII_RXIN (JH7110_AONCLK_END + 2) ++#define JH7110_AONCLK_STG_AXIAHB (JH7110_AONCLK_END + 3) ++#define JH7110_AONCLK_APB_BUS (JH7110_AONCLK_END + 4) ++#define JH7110_AONCLK_GMAC0_GTXCLK (JH7110_AONCLK_END + 5) ++#define JH7110_AONCLK_RTC_OSC (JH7110_AONCLK_END + 6) ++ ++static const struct jh71x0_clk_data jh7110_aonclk_data[] = { ++ /* source */ ++ JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC), ++ JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 2, ++ JH7110_AONCLK_OSC_DIV4, ++ JH7110_AONCLK_OSC), ++ /* gmac0 */ ++ JH71X0_GATE(JH7110_AONCLK_GMAC0_AHB, "gmac0_ahb", 0, JH7110_AONCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_AONCLK_GMAC0_AXI, "gmac0_axi", 0, JH7110_AONCLK_STG_AXIAHB), ++ JH71X0__DIV(JH7110_AONCLK_GMAC0_RMII_RTX, "gmac0_rmii_rtx", 30, ++ JH7110_AONCLK_GMAC0_RMII_REFIN), ++ JH71X0_GMUX(JH7110_AONCLK_GMAC0_TX, "gmac0_tx", ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, ++ JH7110_AONCLK_GMAC0_GTXCLK, ++ JH7110_AONCLK_GMAC0_RMII_RTX), ++ JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX), ++ JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 2, ++ JH7110_AONCLK_GMAC0_RGMII_RXIN, ++ JH7110_AONCLK_GMAC0_RMII_RTX), ++ JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX), ++ /* otpc */ ++ JH71X0_GATE(JH7110_AONCLK_OTPC_APB, "otpc_apb", 0, JH7110_AONCLK_APB_BUS), ++ /* rtc */ ++ JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS), ++ JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC), ++ JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 2, ++ JH7110_AONCLK_RTC_OSC, ++ JH7110_AONCLK_RTC_INTERNAL), ++ JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC), ++}; ++ ++static struct clk_hw *jh7110_aonclk_get(struct of_phandle_args *clkspec, void *data) ++{ ++ struct jh71x0_clk_priv *priv = data; ++ unsigned int idx = clkspec->args[0]; ++ ++ if (idx < JH7110_AONCLK_END) ++ return &priv->reg[idx].hw; ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++static int jh7110_aoncrg_probe(struct platform_device *pdev) ++{ ++ struct jh71x0_clk_priv *priv; ++ unsigned int idx; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, ++ struct_size(priv, reg, JH7110_AONCLK_END), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->rmw_lock); ++ priv->dev = &pdev->dev; ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ dev_set_drvdata(priv->dev, (void *)(&priv->base)); ++ ++ for (idx = 0; idx < JH7110_AONCLK_END; idx++) { ++ u32 max = jh7110_aonclk_data[idx].max; ++ struct clk_parent_data parents[4] = {}; ++ struct clk_init_data init = { ++ .name = jh7110_aonclk_data[idx].name, ++ .ops = starfive_jh71x0_clk_ops(max), ++ .parent_data = parents, ++ .num_parents = ++ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, ++ .flags = jh7110_aonclk_data[idx].flags, ++ }; ++ struct jh71x0_clk *clk = &priv->reg[idx]; ++ unsigned int i; ++ ++ for (i = 0; i < init.num_parents; i++) { ++ unsigned int pidx = jh7110_aonclk_data[idx].parents[i]; ++ ++ if (pidx < JH7110_AONCLK_END) ++ parents[i].hw = &priv->reg[pidx].hw; ++ else if (pidx == JH7110_AONCLK_OSC) ++ parents[i].fw_name = "osc"; ++ else if (pidx == JH7110_AONCLK_GMAC0_RMII_REFIN) ++ parents[i].fw_name = "gmac0_rmii_refin"; ++ else if (pidx == JH7110_AONCLK_GMAC0_RGMII_RXIN) ++ parents[i].fw_name = "gmac0_rgmii_rxin"; ++ else if (pidx == JH7110_AONCLK_STG_AXIAHB) ++ parents[i].fw_name = "stg_axiahb"; ++ else if (pidx == JH7110_AONCLK_APB_BUS) ++ parents[i].fw_name = "apb_bus"; ++ else if (pidx == JH7110_AONCLK_GMAC0_GTXCLK) ++ parents[i].fw_name = "gmac0_gtxclk"; ++ else if (pidx == JH7110_AONCLK_RTC_OSC) ++ parents[i].fw_name = "rtc_osc"; ++ } ++ ++ clk->hw.init = &init; ++ clk->idx = idx; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clk->hw); ++ if (ret) ++ return ret; ++ } ++ ++ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_aonclk_get, priv); ++ if (ret) ++ return ret; ++ ++ return jh7110_reset_controller_register(priv, "rst-aon", 1); ++} ++ ++static const struct of_device_id jh7110_aoncrg_match[] = { ++ { .compatible = "starfive,jh7110-aoncrg" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_aoncrg_match); ++ ++static struct platform_driver jh7110_aoncrg_driver = { ++ .probe = jh7110_aoncrg_probe, ++ .driver = { ++ .name = "clk-starfive-jh7110-aon", ++ .of_match_table = jh7110_aoncrg_match, ++ }, ++}; ++module_platform_driver(jh7110_aoncrg_driver); ++ ++MODULE_AUTHOR("Emil Renner Berthing"); ++MODULE_DESCRIPTION("StarFive JH7110 always-on clock driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0015-reset-starfive-Add-StarFive-JH7110-reset-driver.patch b/target/linux/starfive/patches-6.1/0015-reset-starfive-Add-StarFive-JH7110-reset-driver.patch new file mode 100644 index 0000000000..1a2a9d9991 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0015-reset-starfive-Add-StarFive-JH7110-reset-driver.patch @@ -0,0 +1,113 @@ +From ea2f40c943f4a6d39a2f3ea4660266250d37c95a Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Sat, 1 Apr 2023 19:19:27 +0800 +Subject: [PATCH 015/122] reset: starfive: Add StarFive JH7110 reset driver + +Add auxiliary driver to support StarFive JH7110 system +and always-on resets. + +Tested-by: Tommaso Merciai +Reviewed-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + drivers/reset/starfive/Kconfig | 8 +++ + drivers/reset/starfive/Makefile | 1 + + .../reset/starfive/reset-starfive-jh7110.c | 70 +++++++++++++++++++ + 3 files changed, 79 insertions(+) + create mode 100644 drivers/reset/starfive/reset-starfive-jh7110.c + +--- a/drivers/reset/starfive/Kconfig ++++ b/drivers/reset/starfive/Kconfig +@@ -10,3 +10,11 @@ config RESET_STARFIVE_JH7100 + default ARCH_STARFIVE + help + This enables the reset controller driver for the StarFive JH7100 SoC. ++ ++config RESET_STARFIVE_JH7110 ++ bool "StarFive JH7110 Reset Driver" ++ depends on AUXILIARY_BUS && CLK_STARFIVE_JH7110_SYS ++ select RESET_STARFIVE_JH71X0 ++ default ARCH_STARFIVE ++ help ++ This enables the reset controller driver for the StarFive JH7110 SoC. +--- a/drivers/reset/starfive/Makefile ++++ b/drivers/reset/starfive/Makefile +@@ -2,3 +2,4 @@ + obj-$(CONFIG_RESET_STARFIVE_JH71X0) += reset-starfive-jh71x0.o + + obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o ++obj-$(CONFIG_RESET_STARFIVE_JH7110) += reset-starfive-jh7110.o +--- /dev/null ++++ b/drivers/reset/starfive/reset-starfive-jh7110.c +@@ -0,0 +1,70 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Reset driver for the StarFive JH7110 SoC ++ * ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++ ++#include "reset-starfive-jh71x0.h" ++ ++#include ++ ++struct jh7110_reset_info { ++ unsigned int nr_resets; ++ unsigned int assert_offset; ++ unsigned int status_offset; ++}; ++ ++static const struct jh7110_reset_info jh7110_sys_info = { ++ .nr_resets = JH7110_SYSRST_END, ++ .assert_offset = 0x2F8, ++ .status_offset = 0x308, ++}; ++ ++static const struct jh7110_reset_info jh7110_aon_info = { ++ .nr_resets = JH7110_AONRST_END, ++ .assert_offset = 0x38, ++ .status_offset = 0x3C, ++}; ++ ++static int jh7110_reset_probe(struct auxiliary_device *adev, ++ const struct auxiliary_device_id *id) ++{ ++ struct jh7110_reset_info *info = (struct jh7110_reset_info *)(id->driver_data); ++ void __iomem **base = (void __iomem **)dev_get_drvdata(adev->dev.parent); ++ ++ if (!info || !base) ++ return -ENODEV; ++ ++ return reset_starfive_jh71x0_register(&adev->dev, adev->dev.parent->of_node, ++ *base + info->assert_offset, ++ *base + info->status_offset, ++ NULL, ++ info->nr_resets, ++ NULL); ++} ++ ++static const struct auxiliary_device_id jh7110_reset_ids[] = { ++ { ++ .name = "clk_starfive_jh7110_sys.rst-sys", ++ .driver_data = (kernel_ulong_t)&jh7110_sys_info, ++ }, ++ { ++ .name = "clk_starfive_jh7110_sys.rst-aon", ++ .driver_data = (kernel_ulong_t)&jh7110_aon_info, ++ }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(auxiliary, jh7110_reset_ids); ++ ++static struct auxiliary_driver jh7110_reset_driver = { ++ .probe = jh7110_reset_probe, ++ .id_table = jh7110_reset_ids, ++}; ++module_auxiliary_driver(jh7110_reset_driver); ++ ++MODULE_AUTHOR("Hal Feng "); ++MODULE_DESCRIPTION("StarFive JH7110 reset driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0016-MAINTAINERS-generalise-StarFive-clk-reset-entries.patch b/target/linux/starfive/patches-6.1/0016-MAINTAINERS-generalise-StarFive-clk-reset-entries.patch new file mode 100644 index 0000000000..68b96fa388 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0016-MAINTAINERS-generalise-StarFive-clk-reset-entries.patch @@ -0,0 +1,50 @@ +From 17fecb06e9de3ae5bbf7aecc4d91e14517982f5c Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Wed, 17 May 2023 20:41:51 -0700 +Subject: [PATCH 016/122] MAINTAINERS: generalise StarFive clk/reset entries + +Update the MAINTAINERS entry for StarFive's clock and reset drivers to +account for the addition of JH7110 support and Hal's role in that. + +Signed-off-by: shanlong.li +--- + MAINTAINERS | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19650,12 +19650,13 @@ M: Emil Renner Berthing ++M: Hal Feng + S: Maintained +-F: Documentation/devicetree/bindings/clock/starfive,jh7100-*.yaml +-F: drivers/clk/starfive/clk-starfive-jh7100* +-F: include/dt-bindings/clock/starfive-jh7100*.h ++F: Documentation/devicetree/bindings/clock/starfive,jh71*.yaml ++F: drivers/clk/starfive/clk-starfive-jh71* ++F: include/dt-bindings/clock/starfive?jh71*.h + + STARFIVE JH7100 PINCTRL DRIVER + M: Emil Renner Berthing +@@ -19665,12 +19666,13 @@ F: Documentation/devicetree/bindings/pin + F: drivers/pinctrl/starfive/ + F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h + +-STARFIVE JH7100 RESET CONTROLLER DRIVER ++STARFIVE JH71X0 RESET CONTROLLER DRIVERS + M: Emil Renner Berthing ++M: Hal Feng + S: Maintained + F: Documentation/devicetree/bindings/reset/starfive,jh7100-reset.yaml +-F: drivers/reset/reset-starfive-jh7100.c +-F: include/dt-bindings/reset/starfive-jh7100.h ++F: drivers/reset/starfive/reset-starfive-jh71* ++F: include/dt-bindings/reset/starfive?jh71*.h + + STATIC BRANCH/CALL + M: Peter Zijlstra diff --git a/target/linux/starfive/patches-6.1/0017-clk-starfive-Avoid-casting-iomem-pointers.patch b/target/linux/starfive/patches-6.1/0017-clk-starfive-Avoid-casting-iomem-pointers.patch new file mode 100644 index 0000000000..9667f7256c --- /dev/null +++ b/target/linux/starfive/patches-6.1/0017-clk-starfive-Avoid-casting-iomem-pointers.patch @@ -0,0 +1,128 @@ +From d9d4e0fb44a50cace195e1639cfb23e518e17e88 Mon Sep 17 00:00:00 2001 +From: Stephen Boyd +Date: Thu, 13 Apr 2023 13:55:28 -0700 +Subject: [PATCH 017/122] clk: starfive: Avoid casting iomem pointers + +Let's use a wrapper struct for the auxiliary_device made in +jh7110_reset_controller_register() so that we can stop casting iomem +pointers. The casts trip up tools like sparse, and make for some awkward +casts that are largely unnecessary. While we're here, change the +allocation from devm and actually free the auxiliary_device memory in +the release function. This avoids any use after free problems where the +parent device driver is unbound from the device but the +auxiliuary_device is still in use accessing devm freed memory. + +Cc: Tommaso Merciai +Cc: Emil Renner Berthing +Cc: Hal Feng +Cc: Conor Dooley +Cc: Xingyu Wu +Reviewed-by: Conor Dooley +Fixes: edab7204afe5 ("clk: starfive: Add StarFive JH7110 system clock driver") +Signed-off-by: Stephen Boyd +Link: https://lore.kernel.org/r/20230413205528.4044216-1-sboyd@kernel.org +--- + drivers/clk/starfive/clk-starfive-jh7110-sys.c | 15 ++++++++++++--- + drivers/reset/starfive/reset-starfive-jh7110.c | 9 ++++++--- + include/soc/starfive/reset-starfive-jh71x0.h | 17 +++++++++++++++++ + 3 files changed, 35 insertions(+), 6 deletions(-) + create mode 100644 include/soc/starfive/reset-starfive-jh71x0.h + +--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +@@ -11,6 +11,9 @@ + #include + #include + #include ++#include ++ ++#include + + #include + +@@ -335,26 +338,32 @@ static void jh7110_reset_unregister_adev + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); ++ auxiliary_device_uninit(adev); + } + + static void jh7110_reset_adev_release(struct device *dev) + { + struct auxiliary_device *adev = to_auxiliary_dev(dev); ++ struct jh71x0_reset_adev *rdev = to_jh71x0_reset_adev(adev); + +- auxiliary_device_uninit(adev); ++ kfree(rdev); + } + + int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + const char *adev_name, + u32 adev_id) + { ++ struct jh71x0_reset_adev *rdev; + struct auxiliary_device *adev; + int ret; + +- adev = devm_kzalloc(priv->dev, sizeof(*adev), GFP_KERNEL); +- if (!adev) ++ rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); ++ if (!rdev) + return -ENOMEM; + ++ rdev->base = priv->base; ++ ++ adev = &rdev->adev; + adev->name = adev_name; + adev->dev.parent = priv->dev; + adev->dev.release = jh7110_reset_adev_release; +--- a/drivers/reset/starfive/reset-starfive-jh7110.c ++++ b/drivers/reset/starfive/reset-starfive-jh7110.c +@@ -7,6 +7,8 @@ + + #include + ++#include ++ + #include "reset-starfive-jh71x0.h" + + #include +@@ -33,14 +35,15 @@ static int jh7110_reset_probe(struct aux + const struct auxiliary_device_id *id) + { + struct jh7110_reset_info *info = (struct jh7110_reset_info *)(id->driver_data); +- void __iomem **base = (void __iomem **)dev_get_drvdata(adev->dev.parent); ++ struct jh71x0_reset_adev *rdev = to_jh71x0_reset_adev(adev); ++ void __iomem *base = rdev->base; + + if (!info || !base) + return -ENODEV; + + return reset_starfive_jh71x0_register(&adev->dev, adev->dev.parent->of_node, +- *base + info->assert_offset, +- *base + info->status_offset, ++ base + info->assert_offset, ++ base + info->status_offset, + NULL, + info->nr_resets, + NULL); +--- /dev/null ++++ b/include/soc/starfive/reset-starfive-jh71x0.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __SOC_STARFIVE_RESET_JH71X0_H ++#define __SOC_STARFIVE_RESET_JH71X0_H ++ ++#include ++#include ++#include ++ ++struct jh71x0_reset_adev { ++ void __iomem *base; ++ struct auxiliary_device adev; ++}; ++ ++#define to_jh71x0_reset_adev(_adev) \ ++ container_of((_adev), struct jh71x0_reset_adev, adev) ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0018-dt-bindings-timer-Add-StarFive-JH7110-clint.patch b/target/linux/starfive/patches-6.1/0018-dt-bindings-timer-Add-StarFive-JH7110-clint.patch new file mode 100644 index 0000000000..83de87edfc --- /dev/null +++ b/target/linux/starfive/patches-6.1/0018-dt-bindings-timer-Add-StarFive-JH7110-clint.patch @@ -0,0 +1,27 @@ +From f043ba93a8f22fda312574eb98217be15468b7ef Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:28 +0800 +Subject: [PATCH 018/122] dt-bindings: timer: Add StarFive JH7110 clint + +Add compatible string for the StarFive JH7110 clint. + +Reviewed-by: Conor Dooley +Acked-by: Krzysztof Kozlowski +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + Documentation/devicetree/bindings/timer/sifive,clint.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/timer/sifive,clint.yaml ++++ b/Documentation/devicetree/bindings/timer/sifive,clint.yaml +@@ -27,6 +27,7 @@ properties: + - enum: + - sifive,fu540-c000-clint + - starfive,jh7100-clint ++ - starfive,jh7110-clint + - canaan,k210-clint + - const: sifive,clint0 + - items: diff --git a/target/linux/starfive/patches-6.1/0019-dt-bindings-interrupt-controller-Add-StarFive-JH7110.patch b/target/linux/starfive/patches-6.1/0019-dt-bindings-interrupt-controller-Add-StarFive-JH7110.patch new file mode 100644 index 0000000000..bb604fee54 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0019-dt-bindings-interrupt-controller-Add-StarFive-JH7110.patch @@ -0,0 +1,28 @@ +From dba83b8b65b4ef47e8986739b6734894f3979c52 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:29 +0800 +Subject: [PATCH 019/122] dt-bindings: interrupt-controller: Add StarFive + JH7110 plic + +Add compatible string for StarFive JH7110 plic. + +Reviewed-by: Conor Dooley +Acked-by: Krzysztof Kozlowski +Reviewed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + .../bindings/interrupt-controller/sifive,plic-1.0.0.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +@@ -60,6 +60,7 @@ properties: + - enum: + - sifive,fu540-c000-plic + - starfive,jh7100-plic ++ - starfive,jh7110-plic + - canaan,k210-plic + - const: sifive,plic-1.0.0 + - items: diff --git a/target/linux/starfive/patches-6.1/0020-dt-bindings-riscv-Add-SiFive-S7-compatible.patch b/target/linux/starfive/patches-6.1/0020-dt-bindings-riscv-Add-SiFive-S7-compatible.patch new file mode 100644 index 0000000000..c8e282e04f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0020-dt-bindings-riscv-Add-SiFive-S7-compatible.patch @@ -0,0 +1,27 @@ +From fccbb0c52438762999ea16c85d4ebf4cc7e2deff Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Sat, 1 Apr 2023 19:19:30 +0800 +Subject: [PATCH 020/122] dt-bindings: riscv: Add SiFive S7 compatible + +Add a new compatible string in cpu.yaml for SiFive S7 CPU +core which is used on SiFive U74-MC core complex etc. + +Reviewed-by: Conor Dooley +Acked-by: Krzysztof Kozlowski +Reviewed-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Signed-off-by: Conor Dooley +--- + Documentation/devicetree/bindings/riscv/cpus.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/riscv/cpus.yaml ++++ b/Documentation/devicetree/bindings/riscv/cpus.yaml +@@ -33,6 +33,7 @@ properties: + - sifive,e5 + - sifive,e7 + - sifive,e71 ++ - sifive,s7 + - sifive,u74-mc + - sifive,u54 + - sifive,u74 diff --git a/target/linux/starfive/patches-6.1/0021-riscv-dts-starfive-Add-initial-StarFive-JH7110-devic.patch b/target/linux/starfive/patches-6.1/0021-riscv-dts-starfive-Add-initial-StarFive-JH7110-devic.patch new file mode 100644 index 0000000000..d1e1cfc8cd --- /dev/null +++ b/target/linux/starfive/patches-6.1/0021-riscv-dts-starfive-Add-initial-StarFive-JH7110-devic.patch @@ -0,0 +1,549 @@ +From ca57ce82224c21f93ad43754474fb8de1baf5caa Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:31 +0800 +Subject: [PATCH 021/122] riscv: dts: starfive: Add initial StarFive JH7110 + device tree + +Add initial device tree for the JH7110 RISC-V SoC by StarFive +Technology Ltd. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Signed-off-by: Emil Renner Berthing +Co-developed-by: Jianlong Huang +Signed-off-by: Jianlong Huang +Co-developed-by: Hal Feng +Signed-off-by: Hal Feng +[conor: squashed in the removal of the S7's non-existent mmu] +Reviewed-by: Emil Renner Berthing +Signed-off-by: Conor Dooley +--- + arch/riscv/Kconfig.socs | 5 + + arch/riscv/boot/dts/starfive/jh7110.dtsi | 500 +++++++++++++++++++++++ + 2 files changed, 505 insertions(+) + create mode 100644 arch/riscv/boot/dts/starfive/jh7110.dtsi + +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -7,6 +7,8 @@ config SOC_MICROCHIP_POLARFIRE + help + This enables support for Microchip PolarFire SoC platforms. + ++config ARCH_SIFIVE ++ def_bool SOC_SIFIVE + config SOC_SIFIVE + bool "SiFive SoCs" + select SERIAL_SIFIVE if TTY +@@ -18,6 +20,9 @@ config SOC_SIFIVE + help + This enables support for SiFive SoC platform hardware. + ++config ARCH_STARFIVE ++ def_bool SOC_STARFIVE ++ + config SOC_STARFIVE + bool "StarFive SoCs" + select PINCTRL +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi +@@ -0,0 +1,500 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Copyright (C) 2022 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include ++#include ++ ++/ { ++ compatible = "starfive,jh7110"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ S7_0: cpu@0 { ++ compatible = "sifive,s7", "riscv"; ++ reg = <0>; ++ device_type = "cpu"; ++ i-cache-block-size = <64>; ++ i-cache-sets = <64>; ++ i-cache-size = <16384>; ++ next-level-cache = <&ccache>; ++ riscv,isa = "rv64imac_zba_zbb"; ++ status = "disabled"; ++ ++ cpu0_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ U74_1: cpu@1 { ++ compatible = "sifive,u74-mc", "riscv"; ++ reg = <1>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <64>; ++ d-cache-size = <32768>; ++ d-tlb-sets = <1>; ++ d-tlb-size = <40>; ++ device_type = "cpu"; ++ i-cache-block-size = <64>; ++ i-cache-sets = <64>; ++ i-cache-size = <32768>; ++ i-tlb-sets = <1>; ++ i-tlb-size = <40>; ++ mmu-type = "riscv,sv39"; ++ next-level-cache = <&ccache>; ++ riscv,isa = "rv64imafdc_zba_zbb"; ++ tlb-split; ++ ++ cpu1_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ U74_2: cpu@2 { ++ compatible = "sifive,u74-mc", "riscv"; ++ reg = <2>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <64>; ++ d-cache-size = <32768>; ++ d-tlb-sets = <1>; ++ d-tlb-size = <40>; ++ device_type = "cpu"; ++ i-cache-block-size = <64>; ++ i-cache-sets = <64>; ++ i-cache-size = <32768>; ++ i-tlb-sets = <1>; ++ i-tlb-size = <40>; ++ mmu-type = "riscv,sv39"; ++ next-level-cache = <&ccache>; ++ riscv,isa = "rv64imafdc_zba_zbb"; ++ tlb-split; ++ ++ cpu2_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ U74_3: cpu@3 { ++ compatible = "sifive,u74-mc", "riscv"; ++ reg = <3>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <64>; ++ d-cache-size = <32768>; ++ d-tlb-sets = <1>; ++ d-tlb-size = <40>; ++ device_type = "cpu"; ++ i-cache-block-size = <64>; ++ i-cache-sets = <64>; ++ i-cache-size = <32768>; ++ i-tlb-sets = <1>; ++ i-tlb-size = <40>; ++ mmu-type = "riscv,sv39"; ++ next-level-cache = <&ccache>; ++ riscv,isa = "rv64imafdc_zba_zbb"; ++ tlb-split; ++ ++ cpu3_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ U74_4: cpu@4 { ++ compatible = "sifive,u74-mc", "riscv"; ++ reg = <4>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <64>; ++ d-cache-size = <32768>; ++ d-tlb-sets = <1>; ++ d-tlb-size = <40>; ++ device_type = "cpu"; ++ i-cache-block-size = <64>; ++ i-cache-sets = <64>; ++ i-cache-size = <32768>; ++ i-tlb-sets = <1>; ++ i-tlb-size = <40>; ++ mmu-type = "riscv,sv39"; ++ next-level-cache = <&ccache>; ++ riscv,isa = "rv64imafdc_zba_zbb"; ++ tlb-split; ++ ++ cpu4_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&S7_0>; ++ }; ++ ++ core1 { ++ cpu = <&U74_1>; ++ }; ++ ++ core2 { ++ cpu = <&U74_2>; ++ }; ++ ++ core3 { ++ cpu = <&U74_3>; ++ }; ++ ++ core4 { ++ cpu = <&U74_4>; ++ }; ++ }; ++ }; ++ }; ++ ++ gmac0_rgmii_rxin: gmac0-rgmii-rxin-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "gmac0_rgmii_rxin"; ++ #clock-cells = <0>; ++ }; ++ ++ gmac0_rmii_refin: gmac0-rmii-refin-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "gmac0_rmii_refin"; ++ #clock-cells = <0>; ++ }; ++ ++ gmac1_rgmii_rxin: gmac1-rgmii-rxin-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "gmac1_rgmii_rxin"; ++ #clock-cells = <0>; ++ }; ++ ++ gmac1_rmii_refin: gmac1-rmii-refin-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "gmac1_rmii_refin"; ++ #clock-cells = <0>; ++ }; ++ ++ i2srx_bclk_ext: i2srx-bclk-ext-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "i2srx_bclk_ext"; ++ #clock-cells = <0>; ++ }; ++ ++ i2srx_lrck_ext: i2srx-lrck-ext-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "i2srx_lrck_ext"; ++ #clock-cells = <0>; ++ }; ++ ++ i2stx_bclk_ext: i2stx-bclk-ext-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "i2stx_bclk_ext"; ++ #clock-cells = <0>; ++ }; ++ ++ i2stx_lrck_ext: i2stx-lrck-ext-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "i2stx_lrck_ext"; ++ #clock-cells = <0>; ++ }; ++ ++ mclk_ext: mclk-ext-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "mclk_ext"; ++ #clock-cells = <0>; ++ }; ++ ++ osc: oscillator { ++ compatible = "fixed-clock"; ++ clock-output-names = "osc"; ++ #clock-cells = <0>; ++ }; ++ ++ rtc_osc: rtc-oscillator { ++ compatible = "fixed-clock"; ++ clock-output-names = "rtc_osc"; ++ #clock-cells = <0>; ++ }; ++ ++ tdm_ext: tdm-ext-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "tdm_ext"; ++ #clock-cells = <0>; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ interrupt-parent = <&plic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clint: timer@2000000 { ++ compatible = "starfive,jh7110-clint", "sifive,clint0"; ++ reg = <0x0 0x2000000 0x0 0x10000>; ++ interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>, ++ <&cpu1_intc 3>, <&cpu1_intc 7>, ++ <&cpu2_intc 3>, <&cpu2_intc 7>, ++ <&cpu3_intc 3>, <&cpu3_intc 7>, ++ <&cpu4_intc 3>, <&cpu4_intc 7>; ++ }; ++ ++ ccache: cache-controller@2010000 { ++ compatible = "starfive,jh7110-ccache", "sifive,ccache0", "cache"; ++ reg = <0x0 0x2010000 0x0 0x4000>; ++ interrupts = <1>, <3>, <4>, <2>; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-sets = <2048>; ++ cache-size = <2097152>; ++ cache-unified; ++ }; ++ ++ plic: interrupt-controller@c000000 { ++ compatible = "starfive,jh7110-plic", "sifive,plic-1.0.0"; ++ reg = <0x0 0xc000000 0x0 0x4000000>; ++ interrupts-extended = <&cpu0_intc 11>, ++ <&cpu1_intc 11>, <&cpu1_intc 9>, ++ <&cpu2_intc 11>, <&cpu2_intc 9>, ++ <&cpu3_intc 11>, <&cpu3_intc 9>, ++ <&cpu4_intc 11>, <&cpu4_intc 9>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ #address-cells = <0>; ++ riscv,ndev = <136>; ++ }; ++ ++ uart0: serial@10000000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x0 0x10000000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_UART0_CORE>, ++ <&syscrg JH7110_SYSCLK_UART0_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&syscrg JH7110_SYSRST_UART0_APB>; ++ interrupts = <32>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@10010000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x0 0x10010000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_UART1_CORE>, ++ <&syscrg JH7110_SYSCLK_UART1_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&syscrg JH7110_SYSRST_UART1_APB>; ++ interrupts = <33>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@10020000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x0 0x10020000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_UART2_CORE>, ++ <&syscrg JH7110_SYSCLK_UART2_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&syscrg JH7110_SYSRST_UART2_APB>; ++ interrupts = <34>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@10030000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x10030000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C0_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C0_APB>; ++ interrupts = <35>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@10040000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x10040000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C1_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C1_APB>; ++ interrupts = <36>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@10050000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x10050000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C2_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C2_APB>; ++ interrupts = <37>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@12000000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x0 0x12000000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_UART3_CORE>, ++ <&syscrg JH7110_SYSCLK_UART3_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&syscrg JH7110_SYSRST_UART3_APB>; ++ interrupts = <45>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@12010000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x0 0x12010000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_UART4_CORE>, ++ <&syscrg JH7110_SYSCLK_UART4_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&syscrg JH7110_SYSRST_UART4_APB>; ++ interrupts = <46>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@12020000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x0 0x12020000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_UART5_CORE>, ++ <&syscrg JH7110_SYSCLK_UART5_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&syscrg JH7110_SYSRST_UART5_APB>; ++ interrupts = <47>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@12030000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x12030000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C3_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C3_APB>; ++ interrupts = <48>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@12040000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x12040000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C4_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C4_APB>; ++ interrupts = <49>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@12050000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x12050000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C5_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C5_APB>; ++ interrupts = <50>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@12060000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x12060000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_I2C6_APB>; ++ clock-names = "ref"; ++ resets = <&syscrg JH7110_SYSRST_I2C6_APB>; ++ interrupts = <51>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ syscrg: clock-controller@13020000 { ++ compatible = "starfive,jh7110-syscrg"; ++ reg = <0x0 0x13020000 0x0 0x10000>; ++ clocks = <&osc>, <&gmac1_rmii_refin>, ++ <&gmac1_rgmii_rxin>, ++ <&i2stx_bclk_ext>, <&i2stx_lrck_ext>, ++ <&i2srx_bclk_ext>, <&i2srx_lrck_ext>, ++ <&tdm_ext>, <&mclk_ext>; ++ clock-names = "osc", "gmac1_rmii_refin", ++ "gmac1_rgmii_rxin", ++ "i2stx_bclk_ext", "i2stx_lrck_ext", ++ "i2srx_bclk_ext", "i2srx_lrck_ext", ++ "tdm_ext", "mclk_ext"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ sysgpio: pinctrl@13040000 { ++ compatible = "starfive,jh7110-sys-pinctrl"; ++ reg = <0x0 0x13040000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_IOMUX_APB>; ++ resets = <&syscrg JH7110_SYSRST_IOMUX_APB>; ++ interrupts = <86>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ aoncrg: clock-controller@17000000 { ++ compatible = "starfive,jh7110-aoncrg"; ++ reg = <0x0 0x17000000 0x0 0x10000>; ++ clocks = <&osc>, <&gmac0_rmii_refin>, ++ <&gmac0_rgmii_rxin>, ++ <&syscrg JH7110_SYSCLK_STG_AXIAHB>, ++ <&syscrg JH7110_SYSCLK_APB_BUS>, ++ <&syscrg JH7110_SYSCLK_GMAC0_GTXCLK>, ++ <&rtc_osc>; ++ clock-names = "osc", "gmac0_rmii_refin", ++ "gmac0_rgmii_rxin", "stg_axiahb", ++ "apb_bus", "gmac0_gtxclk", ++ "rtc_osc"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ aongpio: pinctrl@17020000 { ++ compatible = "starfive,jh7110-aon-pinctrl"; ++ reg = <0x0 0x17020000 0x0 0x10000>; ++ resets = <&aoncrg JH7110_AONRST_IOMUX>; ++ interrupts = <85>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++}; diff --git a/target/linux/starfive/patches-6.1/0022-riscv-dts-starfive-Add-StarFive-JH7110-pin-function-.patch b/target/linux/starfive/patches-6.1/0022-riscv-dts-starfive-Add-StarFive-JH7110-pin-function-.patch new file mode 100644 index 0000000000..9c329d019f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0022-riscv-dts-starfive-Add-StarFive-JH7110-pin-function-.patch @@ -0,0 +1,331 @@ +From 878c16d22c0feb52c3af65139734b8bb45e349e1 Mon Sep 17 00:00:00 2001 +From: Jianlong Huang +Date: Sat, 1 Apr 2023 19:19:32 +0800 +Subject: [PATCH 022/122] riscv: dts: starfive: Add StarFive JH7110 pin + function definitions + +Add pin function definitions for StarFive JH7110 SoC. + +Tested-by: Tommaso Merciai +Co-developed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Jianlong Huang +Signed-off-by: Hal Feng +Reviewed-by: Emil Renner Berthing +Signed-off-by: Conor Dooley +--- + arch/riscv/boot/dts/starfive/jh7110-pinfunc.h | 308 ++++++++++++++++++ + 1 file changed, 308 insertions(+) + create mode 100644 arch/riscv/boot/dts/starfive/jh7110-pinfunc.h + +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7110-pinfunc.h +@@ -0,0 +1,308 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef __JH7110_PINFUNC_H__ ++#define __JH7110_PINFUNC_H__ ++ ++/* ++ * mux bits: ++ * | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 | ++ * | din | dout | doen | function | gpio nr | ++ * ++ * dout: output signal ++ * doen: output enable signal ++ * din: optional input signal, 0xff = none ++ * function: function selector ++ * gpio nr: gpio number, 0 - 63 ++ */ ++#define GPIOMUX(n, dout, doen, din) ( \ ++ (((din) & 0xff) << 24) | \ ++ (((dout) & 0xff) << 16) | \ ++ (((doen) & 0x3f) << 10) | \ ++ ((n) & 0x3f)) ++ ++#define PINMUX(n, func) ((1 << 10) | (((func) & 0x3) << 8) | ((n) & 0xff)) ++ ++/* sys_iomux dout */ ++#define GPOUT_LOW 0 ++#define GPOUT_HIGH 1 ++#define GPOUT_SYS_WAVE511_UART_TX 2 ++#define GPOUT_SYS_CAN0_STBY 3 ++#define GPOUT_SYS_CAN0_TST_NEXT_BIT 4 ++#define GPOUT_SYS_CAN0_TST_SAMPLE_POINT 5 ++#define GPOUT_SYS_CAN0_TXD 6 ++#define GPOUT_SYS_USB_DRIVE_VBUS 7 ++#define GPOUT_SYS_QSPI_CS1 8 ++#define GPOUT_SYS_SPDIF 9 ++#define GPOUT_SYS_HDMI_CEC_SDA 10 ++#define GPOUT_SYS_HDMI_DDC_SCL 11 ++#define GPOUT_SYS_HDMI_DDC_SDA 12 ++#define GPOUT_SYS_WATCHDOG 13 ++#define GPOUT_SYS_I2C0_CLK 14 ++#define GPOUT_SYS_I2C0_DATA 15 ++#define GPOUT_SYS_SDIO0_BACK_END_POWER 16 ++#define GPOUT_SYS_SDIO0_CARD_POWER_EN 17 ++#define GPOUT_SYS_SDIO0_CCMD_OD_PULLUP_EN 18 ++#define GPOUT_SYS_SDIO0_RST 19 ++#define GPOUT_SYS_UART0_TX 20 ++#define GPOUT_SYS_HIFI4_JTAG_TDO 21 ++#define GPOUT_SYS_JTAG_TDO 22 ++#define GPOUT_SYS_PDM_MCLK 23 ++#define GPOUT_SYS_PWM_CHANNEL0 24 ++#define GPOUT_SYS_PWM_CHANNEL1 25 ++#define GPOUT_SYS_PWM_CHANNEL2 26 ++#define GPOUT_SYS_PWM_CHANNEL3 27 ++#define GPOUT_SYS_PWMDAC_LEFT 28 ++#define GPOUT_SYS_PWMDAC_RIGHT 29 ++#define GPOUT_SYS_SPI0_CLK 30 ++#define GPOUT_SYS_SPI0_FSS 31 ++#define GPOUT_SYS_SPI0_TXD 32 ++#define GPOUT_SYS_GMAC_PHYCLK 33 ++#define GPOUT_SYS_I2SRX_BCLK 34 ++#define GPOUT_SYS_I2SRX_LRCK 35 ++#define GPOUT_SYS_I2STX0_BCLK 36 ++#define GPOUT_SYS_I2STX0_LRCK 37 ++#define GPOUT_SYS_MCLK 38 ++#define GPOUT_SYS_TDM_CLK 39 ++#define GPOUT_SYS_TDM_SYNC 40 ++#define GPOUT_SYS_TDM_TXD 41 ++#define GPOUT_SYS_TRACE_DATA0 42 ++#define GPOUT_SYS_TRACE_DATA1 43 ++#define GPOUT_SYS_TRACE_DATA2 44 ++#define GPOUT_SYS_TRACE_DATA3 45 ++#define GPOUT_SYS_TRACE_REF 46 ++#define GPOUT_SYS_CAN1_STBY 47 ++#define GPOUT_SYS_CAN1_TST_NEXT_BIT 48 ++#define GPOUT_SYS_CAN1_TST_SAMPLE_POINT 49 ++#define GPOUT_SYS_CAN1_TXD 50 ++#define GPOUT_SYS_I2C1_CLK 51 ++#define GPOUT_SYS_I2C1_DATA 52 ++#define GPOUT_SYS_SDIO1_BACK_END_POWER 53 ++#define GPOUT_SYS_SDIO1_CARD_POWER_EN 54 ++#define GPOUT_SYS_SDIO1_CLK 55 ++#define GPOUT_SYS_SDIO1_CMD_OD_PULLUP_EN 56 ++#define GPOUT_SYS_SDIO1_CMD 57 ++#define GPOUT_SYS_SDIO1_DATA0 58 ++#define GPOUT_SYS_SDIO1_DATA1 59 ++#define GPOUT_SYS_SDIO1_DATA2 60 ++#define GPOUT_SYS_SDIO1_DATA3 61 ++#define GPOUT_SYS_SDIO1_DATA4 63 ++#define GPOUT_SYS_SDIO1_DATA5 63 ++#define GPOUT_SYS_SDIO1_DATA6 64 ++#define GPOUT_SYS_SDIO1_DATA7 65 ++#define GPOUT_SYS_SDIO1_RST 66 ++#define GPOUT_SYS_UART1_RTS 67 ++#define GPOUT_SYS_UART1_TX 68 ++#define GPOUT_SYS_I2STX1_SDO0 69 ++#define GPOUT_SYS_I2STX1_SDO1 70 ++#define GPOUT_SYS_I2STX1_SDO2 71 ++#define GPOUT_SYS_I2STX1_SDO3 72 ++#define GPOUT_SYS_SPI1_CLK 73 ++#define GPOUT_SYS_SPI1_FSS 74 ++#define GPOUT_SYS_SPI1_TXD 75 ++#define GPOUT_SYS_I2C2_CLK 76 ++#define GPOUT_SYS_I2C2_DATA 77 ++#define GPOUT_SYS_UART2_RTS 78 ++#define GPOUT_SYS_UART2_TX 79 ++#define GPOUT_SYS_SPI2_CLK 80 ++#define GPOUT_SYS_SPI2_FSS 81 ++#define GPOUT_SYS_SPI2_TXD 82 ++#define GPOUT_SYS_I2C3_CLK 83 ++#define GPOUT_SYS_I2C3_DATA 84 ++#define GPOUT_SYS_UART3_TX 85 ++#define GPOUT_SYS_SPI3_CLK 86 ++#define GPOUT_SYS_SPI3_FSS 87 ++#define GPOUT_SYS_SPI3_TXD 88 ++#define GPOUT_SYS_I2C4_CLK 89 ++#define GPOUT_SYS_I2C4_DATA 90 ++#define GPOUT_SYS_UART4_RTS 91 ++#define GPOUT_SYS_UART4_TX 92 ++#define GPOUT_SYS_SPI4_CLK 93 ++#define GPOUT_SYS_SPI4_FSS 94 ++#define GPOUT_SYS_SPI4_TXD 95 ++#define GPOUT_SYS_I2C5_CLK 96 ++#define GPOUT_SYS_I2C5_DATA 97 ++#define GPOUT_SYS_UART5_RTS 98 ++#define GPOUT_SYS_UART5_TX 99 ++#define GPOUT_SYS_SPI5_CLK 100 ++#define GPOUT_SYS_SPI5_FSS 101 ++#define GPOUT_SYS_SPI5_TXD 102 ++#define GPOUT_SYS_I2C6_CLK 103 ++#define GPOUT_SYS_I2C6_DATA 104 ++#define GPOUT_SYS_SPI6_CLK 105 ++#define GPOUT_SYS_SPI6_FSS 106 ++#define GPOUT_SYS_SPI6_TXD 107 ++ ++/* aon_iomux dout */ ++#define GPOUT_AON_CLK_32K_OUT 2 ++#define GPOUT_AON_PTC0_PWM4 3 ++#define GPOUT_AON_PTC0_PWM5 4 ++#define GPOUT_AON_PTC0_PWM6 5 ++#define GPOUT_AON_PTC0_PWM7 6 ++#define GPOUT_AON_CLK_GCLK0 7 ++#define GPOUT_AON_CLK_GCLK1 8 ++#define GPOUT_AON_CLK_GCLK2 9 ++ ++/* sys_iomux doen */ ++#define GPOEN_ENABLE 0 ++#define GPOEN_DISABLE 1 ++#define GPOEN_SYS_HDMI_CEC_SDA 2 ++#define GPOEN_SYS_HDMI_DDC_SCL 3 ++#define GPOEN_SYS_HDMI_DDC_SDA 4 ++#define GPOEN_SYS_I2C0_CLK 5 ++#define GPOEN_SYS_I2C0_DATA 6 ++#define GPOEN_SYS_HIFI4_JTAG_TDO 7 ++#define GPOEN_SYS_JTAG_TDO 8 ++#define GPOEN_SYS_PWM0_CHANNEL0 9 ++#define GPOEN_SYS_PWM0_CHANNEL1 10 ++#define GPOEN_SYS_PWM0_CHANNEL2 11 ++#define GPOEN_SYS_PWM0_CHANNEL3 12 ++#define GPOEN_SYS_SPI0_NSSPCTL 13 ++#define GPOEN_SYS_SPI0_NSSP 14 ++#define GPOEN_SYS_TDM_SYNC 15 ++#define GPOEN_SYS_TDM_TXD 16 ++#define GPOEN_SYS_I2C1_CLK 17 ++#define GPOEN_SYS_I2C1_DATA 18 ++#define GPOEN_SYS_SDIO1_CMD 19 ++#define GPOEN_SYS_SDIO1_DATA0 20 ++#define GPOEN_SYS_SDIO1_DATA1 21 ++#define GPOEN_SYS_SDIO1_DATA2 22 ++#define GPOEN_SYS_SDIO1_DATA3 23 ++#define GPOEN_SYS_SDIO1_DATA4 24 ++#define GPOEN_SYS_SDIO1_DATA5 25 ++#define GPOEN_SYS_SDIO1_DATA6 26 ++#define GPOEN_SYS_SDIO1_DATA7 27 ++#define GPOEN_SYS_SPI1_NSSPCTL 28 ++#define GPOEN_SYS_SPI1_NSSP 29 ++#define GPOEN_SYS_I2C2_CLK 30 ++#define GPOEN_SYS_I2C2_DATA 31 ++#define GPOEN_SYS_SPI2_NSSPCTL 32 ++#define GPOEN_SYS_SPI2_NSSP 33 ++#define GPOEN_SYS_I2C3_CLK 34 ++#define GPOEN_SYS_I2C3_DATA 35 ++#define GPOEN_SYS_SPI3_NSSPCTL 36 ++#define GPOEN_SYS_SPI3_NSSP 37 ++#define GPOEN_SYS_I2C4_CLK 38 ++#define GPOEN_SYS_I2C4_DATA 39 ++#define GPOEN_SYS_SPI4_NSSPCTL 40 ++#define GPOEN_SYS_SPI4_NSSP 41 ++#define GPOEN_SYS_I2C5_CLK 42 ++#define GPOEN_SYS_I2C5_DATA 43 ++#define GPOEN_SYS_SPI5_NSSPCTL 44 ++#define GPOEN_SYS_SPI5_NSSP 45 ++#define GPOEN_SYS_I2C6_CLK 46 ++#define GPOEN_SYS_I2C6_DATA 47 ++#define GPOEN_SYS_SPI6_NSSPCTL 48 ++#define GPOEN_SYS_SPI6_NSSP 49 ++ ++/* aon_iomux doen */ ++#define GPOEN_AON_PTC0_OE_N_4 2 ++#define GPOEN_AON_PTC0_OE_N_5 3 ++#define GPOEN_AON_PTC0_OE_N_6 4 ++#define GPOEN_AON_PTC0_OE_N_7 5 ++ ++/* sys_iomux gin */ ++#define GPI_NONE 255 ++ ++#define GPI_SYS_WAVE511_UART_RX 0 ++#define GPI_SYS_CAN0_RXD 1 ++#define GPI_SYS_USB_OVERCURRENT 2 ++#define GPI_SYS_SPDIF 3 ++#define GPI_SYS_JTAG_RST 4 ++#define GPI_SYS_HDMI_CEC_SDA 5 ++#define GPI_SYS_HDMI_DDC_SCL 6 ++#define GPI_SYS_HDMI_DDC_SDA 7 ++#define GPI_SYS_HDMI_HPD 8 ++#define GPI_SYS_I2C0_CLK 9 ++#define GPI_SYS_I2C0_DATA 10 ++#define GPI_SYS_SDIO0_CD 11 ++#define GPI_SYS_SDIO0_INT 12 ++#define GPI_SYS_SDIO0_WP 13 ++#define GPI_SYS_UART0_RX 14 ++#define GPI_SYS_HIFI4_JTAG_TCK 15 ++#define GPI_SYS_HIFI4_JTAG_TDI 16 ++#define GPI_SYS_HIFI4_JTAG_TMS 17 ++#define GPI_SYS_HIFI4_JTAG_RST 18 ++#define GPI_SYS_JTAG_TDI 19 ++#define GPI_SYS_JTAG_TMS 20 ++#define GPI_SYS_PDM_DMIC0 21 ++#define GPI_SYS_PDM_DMIC1 22 ++#define GPI_SYS_I2SRX_SDIN0 23 ++#define GPI_SYS_I2SRX_SDIN1 24 ++#define GPI_SYS_I2SRX_SDIN2 25 ++#define GPI_SYS_SPI0_CLK 26 ++#define GPI_SYS_SPI0_FSS 27 ++#define GPI_SYS_SPI0_RXD 28 ++#define GPI_SYS_JTAG_TCK 29 ++#define GPI_SYS_MCLK_EXT 30 ++#define GPI_SYS_I2SRX_BCLK 31 ++#define GPI_SYS_I2SRX_LRCK 32 ++#define GPI_SYS_I2STX0_BCLK 33 ++#define GPI_SYS_I2STX0_LRCK 34 ++#define GPI_SYS_TDM_CLK 35 ++#define GPI_SYS_TDM_RXD 36 ++#define GPI_SYS_TDM_SYNC 37 ++#define GPI_SYS_CAN1_RXD 38 ++#define GPI_SYS_I2C1_CLK 39 ++#define GPI_SYS_I2C1_DATA 40 ++#define GPI_SYS_SDIO1_CD 41 ++#define GPI_SYS_SDIO1_INT 42 ++#define GPI_SYS_SDIO1_WP 43 ++#define GPI_SYS_SDIO1_CMD 44 ++#define GPI_SYS_SDIO1_DATA0 45 ++#define GPI_SYS_SDIO1_DATA1 46 ++#define GPI_SYS_SDIO1_DATA2 47 ++#define GPI_SYS_SDIO1_DATA3 48 ++#define GPI_SYS_SDIO1_DATA4 49 ++#define GPI_SYS_SDIO1_DATA5 50 ++#define GPI_SYS_SDIO1_DATA6 51 ++#define GPI_SYS_SDIO1_DATA7 52 ++#define GPI_SYS_SDIO1_STRB 53 ++#define GPI_SYS_UART1_CTS 54 ++#define GPI_SYS_UART1_RX 55 ++#define GPI_SYS_SPI1_CLK 56 ++#define GPI_SYS_SPI1_FSS 57 ++#define GPI_SYS_SPI1_RXD 58 ++#define GPI_SYS_I2C2_CLK 59 ++#define GPI_SYS_I2C2_DATA 60 ++#define GPI_SYS_UART2_CTS 61 ++#define GPI_SYS_UART2_RX 62 ++#define GPI_SYS_SPI2_CLK 63 ++#define GPI_SYS_SPI2_FSS 64 ++#define GPI_SYS_SPI2_RXD 65 ++#define GPI_SYS_I2C3_CLK 66 ++#define GPI_SYS_I2C3_DATA 67 ++#define GPI_SYS_UART3_RX 68 ++#define GPI_SYS_SPI3_CLK 69 ++#define GPI_SYS_SPI3_FSS 70 ++#define GPI_SYS_SPI3_RXD 71 ++#define GPI_SYS_I2C4_CLK 72 ++#define GPI_SYS_I2C4_DATA 73 ++#define GPI_SYS_UART4_CTS 74 ++#define GPI_SYS_UART4_RX 75 ++#define GPI_SYS_SPI4_CLK 76 ++#define GPI_SYS_SPI4_FSS 77 ++#define GPI_SYS_SPI4_RXD 78 ++#define GPI_SYS_I2C5_CLK 79 ++#define GPI_SYS_I2C5_DATA 80 ++#define GPI_SYS_UART5_CTS 81 ++#define GPI_SYS_UART5_RX 82 ++#define GPI_SYS_SPI5_CLK 83 ++#define GPI_SYS_SPI5_FSS 84 ++#define GPI_SYS_SPI5_RXD 85 ++#define GPI_SYS_I2C6_CLK 86 ++#define GPI_SYS_I2C6_DATA 87 ++#define GPI_SYS_SPI6_CLK 88 ++#define GPI_SYS_SPI6_FSS 89 ++#define GPI_SYS_SPI6_RXD 90 ++ ++/* aon_iomux gin */ ++#define GPI_AON_PMU_GPIO_WAKEUP_0 0 ++#define GPI_AON_PMU_GPIO_WAKEUP_1 1 ++#define GPI_AON_PMU_GPIO_WAKEUP_2 2 ++#define GPI_AON_PMU_GPIO_WAKEUP_3 3 ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0023-riscv-dts-starfive-Add-StarFive-JH7110-VisionFive-2-.patch b/target/linux/starfive/patches-6.1/0023-riscv-dts-starfive-Add-StarFive-JH7110-VisionFive-2-.patch new file mode 100644 index 0000000000..9e311bf527 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0023-riscv-dts-starfive-Add-StarFive-JH7110-VisionFive-2-.patch @@ -0,0 +1,290 @@ +From 76bc84c399f11c7d6a37fe68cbd5f182e4c18369 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 1 Apr 2023 19:19:33 +0800 +Subject: [PATCH 023/122] riscv: dts: starfive: Add StarFive JH7110 VisionFive + 2 board device tree + +Add a minimal device tree for StarFive JH7110 VisionFive 2 board +which has version A and version B. Support booting and basic +clock/reset/pinctrl/uart drivers. + +Tested-by: Tommaso Merciai +Reviewed-by: Conor Dooley +Acked-by: Conor Dooley +Signed-off-by: Emil Renner Berthing +Co-developed-by: Jianlong Huang +Signed-off-by: Jianlong Huang +Co-developed-by: Hal Feng +Signed-off-by: Hal Feng +Reviewed-by: Emil Renner Berthing +Signed-off-by: Conor Dooley +--- + arch/riscv/boot/dts/starfive/Makefile | 6 +- + .../jh7110-starfive-visionfive-2-v1.2a.dts | 13 ++ + .../jh7110-starfive-visionfive-2-v1.3b.dts | 13 ++ + .../jh7110-starfive-visionfive-2.dtsi | 215 ++++++++++++++++++ + 4 files changed, 246 insertions(+), 1 deletion(-) + create mode 100644 arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dts + create mode 100644 arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts + create mode 100644 arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi + +--- a/arch/riscv/boot/dts/starfive/Makefile ++++ b/arch/riscv/boot/dts/starfive/Makefile +@@ -1,2 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 +-dtb-$(CONFIG_SOC_STARFIVE) += jh7100-beaglev-starlight.dtb ++dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb ++dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb ++ ++dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb ++dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dts +@@ -0,0 +1,13 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Copyright (C) 2022 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include "jh7110-starfive-visionfive-2.dtsi" ++ ++/ { ++ model = "StarFive VisionFive 2 v1.2A"; ++ compatible = "starfive,visionfive-2-v1.2a", "starfive,jh7110"; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts +@@ -0,0 +1,13 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Copyright (C) 2022 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include "jh7110-starfive-visionfive-2.dtsi" ++ ++/ { ++ model = "StarFive VisionFive 2 v1.3B"; ++ compatible = "starfive,visionfive-2-v1.3b", "starfive,jh7110"; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -0,0 +1,215 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Copyright (C) 2022 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include "jh7110.dtsi" ++#include "jh7110-pinfunc.h" ++#include ++ ++/ { ++ aliases { ++ i2c0 = &i2c0; ++ i2c2 = &i2c2; ++ i2c5 = &i2c5; ++ i2c6 = &i2c6; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ cpus { ++ timebase-frequency = <4000000>; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000 0x1 0x0>; ++ }; ++ ++ gpio-restart { ++ compatible = "gpio-restart"; ++ gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>; ++ priority = <224>; ++ }; ++}; ++ ++&gmac0_rgmii_rxin { ++ clock-frequency = <125000000>; ++}; ++ ++&gmac0_rmii_refin { ++ clock-frequency = <50000000>; ++}; ++ ++&gmac1_rgmii_rxin { ++ clock-frequency = <125000000>; ++}; ++ ++&gmac1_rmii_refin { ++ clock-frequency = <50000000>; ++}; ++ ++&i2srx_bclk_ext { ++ clock-frequency = <12288000>; ++}; ++ ++&i2srx_lrck_ext { ++ clock-frequency = <192000>; ++}; ++ ++&i2stx_bclk_ext { ++ clock-frequency = <12288000>; ++}; ++ ++&i2stx_lrck_ext { ++ clock-frequency = <192000>; ++}; ++ ++&mclk_ext { ++ clock-frequency = <12288000>; ++}; ++ ++&osc { ++ clock-frequency = <24000000>; ++}; ++ ++&rtc_osc { ++ clock-frequency = <32768>; ++}; ++ ++&tdm_ext { ++ clock-frequency = <49152000>; ++}; ++ ++&i2c0 { ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++ status = "okay"; ++}; ++ ++&i2c5 { ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c5_pins>; ++ status = "okay"; ++}; ++ ++&i2c6 { ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c6_pins>; ++ status = "okay"; ++}; ++ ++&sysgpio { ++ i2c0_pins: i2c0-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-disable; /* external pull-up */ ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ i2c2_pins: i2c2-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-disable; /* external pull-up */ ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ i2c5_pins: i2c5-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-disable; /* external pull-up */ ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ i2c6_pins: i2c6-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-disable; /* external pull-up */ ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ uart0_pins: uart0-0 { ++ tx-pins { ++ pinmux = ; ++ bias-disable; ++ drive-strength = <12>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pinmux = ; ++ bias-disable; /* external pull-up */ ++ drive-strength = <2>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; ++ status = "okay"; ++}; diff --git a/target/linux/starfive/patches-6.1/0024-riscv-dts-starfive-Add-StarFive-VisionFive-V1-device.patch b/target/linux/starfive/patches-6.1/0024-riscv-dts-starfive-Add-StarFive-VisionFive-V1-device.patch new file mode 100644 index 0000000000..f823aff9a1 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0024-riscv-dts-starfive-Add-StarFive-VisionFive-V1-device.patch @@ -0,0 +1,43 @@ +From cbb348ddbc68fe4fc8ac80bed11c298149e7893f Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Oct 2022 00:05:42 +0300 +Subject: [PATCH 024/122] riscv: dts: starfive: Add StarFive VisionFive V1 + device tree + +Add initial device tree for the StarFive VisionFive V1 SBC, which +is similar with the already supported BeagleV Starlight Beta board, +both being based on the StarFive JH7100 SoC. + +Link: https://github.com/starfive-tech/VisionFive +Signed-off-by: Cristian Ciocaltea +Reviewed-by: Conor Dooley +Reviewed-by: Matthias Brugger +Signed-off-by: Conor Dooley +--- + .../jh7100-starfive-visionfive-v1.dts | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + create mode 100644 arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts + +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2021 StarFive Technology Co., Ltd. ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include "jh7100-common.dtsi" ++#include ++ ++/ { ++ model = "StarFive VisionFive V1"; ++ compatible = "starfive,visionfive-v1", "starfive,jh7100"; ++ ++ gpio-restart { ++ compatible = "gpio-restart"; ++ gpios = <&gpio 63 GPIO_ACTIVE_HIGH>; ++ priority = <224>; ++ }; ++}; diff --git a/target/linux/starfive/patches-6.1/0025-riscv-dts-starfive-Add-common-DT-for-JH7100-based-bo.patch b/target/linux/starfive/patches-6.1/0025-riscv-dts-starfive-Add-common-DT-for-JH7100-based-bo.patch new file mode 100644 index 0000000000..44b5836c34 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0025-riscv-dts-starfive-Add-common-DT-for-JH7100-based-bo.patch @@ -0,0 +1,349 @@ +From 2101233d71b74e33de33e4cc292c6a8cf5da9d42 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Oct 2022 00:05:41 +0300 +Subject: [PATCH 025/122] riscv: dts: starfive: Add common DT for JH7100 based + boards + +In preparation for adding initial device tree support for the StarFive +VisionFive board, which is similar with BeagleV Starlight, move most +of the content from jh7100-beaglev-starlight.dts to a new file, to be +shared between the two boards. + +Signed-off-by: Cristian Ciocaltea +Reviewed-by: Conor Dooley +Reviewed-by: Matthias Brugger +Signed-off-by: Conor Dooley +--- + .../dts/starfive/jh7100-beaglev-starlight.dts | 153 +---------------- + .../boot/dts/starfive/jh7100-common.dtsi | 161 ++++++++++++++++++ + 2 files changed, 162 insertions(+), 152 deletions(-) + create mode 100644 arch/riscv/boot/dts/starfive/jh7100-common.dtsi + +--- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts ++++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts +@@ -5,160 +5,9 @@ + */ + + /dts-v1/; +-#include "jh7100.dtsi" +-#include +-#include +-#include ++#include "jh7100-common.dtsi" + + / { + model = "BeagleV Starlight Beta"; + compatible = "beagle,beaglev-starlight-jh7100-r0", "starfive,jh7100"; +- +- aliases { +- serial0 = &uart3; +- }; +- +- chosen { +- stdout-path = "serial0:115200n8"; +- }; +- +- cpus { +- timebase-frequency = <6250000>; +- }; +- +- memory@80000000 { +- device_type = "memory"; +- reg = <0x0 0x80000000 0x2 0x0>; +- }; +- +- leds { +- compatible = "gpio-leds"; +- +- led-ack { +- gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; +- color = ; +- function = LED_FUNCTION_HEARTBEAT; +- linux,default-trigger = "heartbeat"; +- label = "ack"; +- }; +- }; +-}; +- +-&gpio { +- i2c0_pins: i2c0-0 { +- i2c-pins { +- pinmux = , +- ; +- bias-disable; /* external pull-up */ +- input-enable; +- input-schmitt-enable; +- }; +- }; +- +- i2c1_pins: i2c1-0 { +- i2c-pins { +- pinmux = , +- ; +- bias-pull-up; +- input-enable; +- input-schmitt-enable; +- }; +- }; +- +- i2c2_pins: i2c2-0 { +- i2c-pins { +- pinmux = , +- ; +- bias-disable; /* external pull-up */ +- input-enable; +- input-schmitt-enable; +- }; +- }; +- +- uart3_pins: uart3-0 { +- rx-pins { +- pinmux = ; +- bias-pull-up; +- drive-strength = <14>; +- input-enable; +- input-schmitt-enable; +- slew-rate = <0>; +- }; +- tx-pins { +- pinmux = ; +- bias-disable; +- drive-strength = <35>; +- input-disable; +- input-schmitt-disable; +- slew-rate = <0>; +- }; +- }; +-}; +- +-&i2c0 { +- clock-frequency = <100000>; +- i2c-sda-hold-time-ns = <300>; +- i2c-sda-falling-time-ns = <500>; +- i2c-scl-falling-time-ns = <500>; +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c0_pins>; +- status = "okay"; +- +- pmic@5e { +- compatible = "ti,tps65086"; +- reg = <0x5e>; +- gpio-controller; +- #gpio-cells = <2>; +- +- regulators { +- }; +- }; +-}; +- +-&i2c1 { +- clock-frequency = <400000>; +- i2c-sda-hold-time-ns = <300>; +- i2c-sda-falling-time-ns = <100>; +- i2c-scl-falling-time-ns = <100>; +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c1_pins>; +- status = "okay"; +-}; +- +-&i2c2 { +- clock-frequency = <100000>; +- i2c-sda-hold-time-ns = <300>; +- i2c-sda-falling-time-ns = <500>; +- i2c-scl-falling-time-ns = <500>; +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c2_pins>; +- status = "okay"; +-}; +- +-&osc_sys { +- clock-frequency = <25000000>; +-}; +- +-&osc_aud { +- clock-frequency = <27000000>; +-}; +- +-&uart3 { +- pinctrl-names = "default"; +- pinctrl-0 = <&uart3_pins>; +- status = "okay"; + }; +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi +@@ -0,0 +1,161 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2021 StarFive Technology Co., Ltd. ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include "jh7100.dtsi" ++#include ++#include ++#include ++ ++/ { ++ aliases { ++ serial0 = &uart3; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ cpus { ++ timebase-frequency = <6250000>; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x0 0x80000000 0x2 0x0>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led-ack { ++ gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; ++ color = ; ++ function = LED_FUNCTION_HEARTBEAT; ++ linux,default-trigger = "heartbeat"; ++ label = "ack"; ++ }; ++ }; ++}; ++ ++&gpio { ++ i2c0_pins: i2c0-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-disable; /* external pull-up */ ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ i2c1_pins: i2c1-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-pull-up; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ i2c2_pins: i2c2-0 { ++ i2c-pins { ++ pinmux = , ++ ; ++ bias-disable; /* external pull-up */ ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ uart3_pins: uart3-0 { ++ rx-pins { ++ pinmux = ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ tx-pins { ++ pinmux = ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++}; ++ ++&i2c0 { ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <500>; ++ i2c-scl-falling-time-ns = <500>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ status = "okay"; ++ ++ pmic@5e { ++ compatible = "ti,tps65086"; ++ reg = <0x5e>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ regulators { ++ }; ++ }; ++}; ++ ++&i2c1 { ++ clock-frequency = <400000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <100>; ++ i2c-scl-falling-time-ns = <100>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <500>; ++ i2c-scl-falling-time-ns = <500>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++ status = "okay"; ++}; ++ ++&osc_sys { ++ clock-frequency = <25000000>; ++}; ++ ++&osc_aud { ++ clock-frequency = <27000000>; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart3_pins>; ++ status = "okay"; ++}; diff --git a/target/linux/starfive/patches-6.1/0026-dt-bindings-pinctrl-Add-StarFive-JH7110-sys-pinctrl.patch b/target/linux/starfive/patches-6.1/0026-dt-bindings-pinctrl-Add-StarFive-JH7110-sys-pinctrl.patch new file mode 100644 index 0000000000..eab4e6ee9f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0026-dt-bindings-pinctrl-Add-StarFive-JH7110-sys-pinctrl.patch @@ -0,0 +1,303 @@ +From 28518a9637fee6b84464beff9d4308edc3efba72 Mon Sep 17 00:00:00 2001 +From: Jianlong Huang +Date: Thu, 9 Feb 2023 22:36:59 +0800 +Subject: [PATCH 026/122] dt-bindings: pinctrl: Add StarFive JH7110 sys pinctrl + +Add pinctrl bindings for StarFive JH7110 SoC sys pinctrl controller. + +Reviewed-by: Rob Herring +Signed-off-by: Jianlong Huang +Co-developed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +--- + .../pinctrl/starfive,jh7110-sys-pinctrl.yaml | 142 ++++++++++++++++++ + MAINTAINERS | 6 +- + .../pinctrl/starfive,jh7110-pinctrl.h | 115 ++++++++++++++ + 3 files changed, 261 insertions(+), 2 deletions(-) + create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh7110-sys-pinctrl.yaml + create mode 100644 include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-sys-pinctrl.yaml +@@ -0,0 +1,142 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pinctrl/starfive,jh7110-sys-pinctrl.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 SYS Pin Controller ++ ++description: | ++ Bindings for the JH7110 RISC-V SoC from StarFive Technology Ltd. ++ ++ Out of the SoC's many pins only the ones named PAD_GPIO0 to PAD_GPIO63 ++ can be multiplexed and have configurable bias, drive strength, ++ schmitt trigger etc. ++ Some peripherals have their I/O go through the 64 "GPIOs". This also ++ includes a number of other UARTs, I2Cs, SPIs, PWMs etc. ++ All these peripherals are connected to all 64 GPIOs such that ++ any GPIO can be set up to be controlled by any of the peripherals. ++ ++maintainers: ++ - Jianlong Huang ++ ++properties: ++ compatible: ++ const: starfive,jh7110-sys-pinctrl ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ interrupt-controller: true ++ ++ '#interrupt-cells': ++ const: 2 ++ ++ gpio-controller: true ++ ++ '#gpio-cells': ++ const: 2 ++ ++patternProperties: ++ '-[0-9]+$': ++ type: object ++ additionalProperties: false ++ patternProperties: ++ '-pins$': ++ type: object ++ description: | ++ A pinctrl node should contain at least one subnode representing the ++ pinctrl groups available on the machine. Each subnode will list the ++ pins it needs, and how they should be configured, with regard to ++ muxer configuration, bias, input enable/disable, input schmitt ++ trigger enable/disable, slew-rate and drive strength. ++ allOf: ++ - $ref: /schemas/pinctrl/pincfg-node.yaml ++ - $ref: /schemas/pinctrl/pinmux-node.yaml ++ additionalProperties: false ++ ++ properties: ++ pinmux: ++ description: | ++ The list of GPIOs and their mux settings that properties in the ++ node apply to. This should be set using the GPIOMUX or PINMUX ++ macros. ++ ++ bias-disable: true ++ ++ bias-pull-up: ++ type: boolean ++ ++ bias-pull-down: ++ type: boolean ++ ++ drive-strength: ++ enum: [ 2, 4, 8, 12 ] ++ ++ input-enable: true ++ ++ input-disable: true ++ ++ input-schmitt-enable: true ++ ++ input-schmitt-disable: true ++ ++ slew-rate: ++ maximum: 1 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - interrupts ++ - interrupt-controller ++ - '#interrupt-cells' ++ - gpio-controller ++ - '#gpio-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pinctrl@13040000 { ++ compatible = "starfive,jh7110-sys-pinctrl"; ++ reg = <0x13040000 0x10000>; ++ clocks = <&syscrg 112>; ++ resets = <&syscrg 2>; ++ interrupts = <86>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ uart0-0 { ++ tx-pins { ++ pinmux = <0xff140005>; ++ bias-disable; ++ drive-strength = <12>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pinmux = <0x0E000406>; ++ bias-pull-up; ++ drive-strength = <2>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ }; ++ ++... +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19658,13 +19658,15 @@ F: Documentation/devicetree/bindings/clo + F: drivers/clk/starfive/clk-starfive-jh71* + F: include/dt-bindings/clock/starfive?jh71*.h + +-STARFIVE JH7100 PINCTRL DRIVER ++STARFIVE JH71X0 PINCTRL DRIVERS + M: Emil Renner Berthing ++M: Jianlong Huang + L: linux-gpio@vger.kernel.org + S: Maintained +-F: Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml ++F: Documentation/devicetree/bindings/pinctrl/starfive,jh71*.yaml + F: drivers/pinctrl/starfive/ + F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h ++F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h + + STARFIVE JH71X0 RESET CONTROLLER DRIVERS + M: Emil Renner Berthing +--- /dev/null ++++ b/include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h +@@ -0,0 +1,115 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef __DT_BINDINGS_PINCTRL_STARFIVE_JH7110_H__ ++#define __DT_BINDINGS_PINCTRL_STARFIVE_JH7110_H__ ++ ++/* sys_iomux pins */ ++#define PAD_GPIO0 0 ++#define PAD_GPIO1 1 ++#define PAD_GPIO2 2 ++#define PAD_GPIO3 3 ++#define PAD_GPIO4 4 ++#define PAD_GPIO5 5 ++#define PAD_GPIO6 6 ++#define PAD_GPIO7 7 ++#define PAD_GPIO8 8 ++#define PAD_GPIO9 9 ++#define PAD_GPIO10 10 ++#define PAD_GPIO11 11 ++#define PAD_GPIO12 12 ++#define PAD_GPIO13 13 ++#define PAD_GPIO14 14 ++#define PAD_GPIO15 15 ++#define PAD_GPIO16 16 ++#define PAD_GPIO17 17 ++#define PAD_GPIO18 18 ++#define PAD_GPIO19 19 ++#define PAD_GPIO20 20 ++#define PAD_GPIO21 21 ++#define PAD_GPIO22 22 ++#define PAD_GPIO23 23 ++#define PAD_GPIO24 24 ++#define PAD_GPIO25 25 ++#define PAD_GPIO26 26 ++#define PAD_GPIO27 27 ++#define PAD_GPIO28 28 ++#define PAD_GPIO29 29 ++#define PAD_GPIO30 30 ++#define PAD_GPIO31 31 ++#define PAD_GPIO32 32 ++#define PAD_GPIO33 33 ++#define PAD_GPIO34 34 ++#define PAD_GPIO35 35 ++#define PAD_GPIO36 36 ++#define PAD_GPIO37 37 ++#define PAD_GPIO38 38 ++#define PAD_GPIO39 39 ++#define PAD_GPIO40 40 ++#define PAD_GPIO41 41 ++#define PAD_GPIO42 42 ++#define PAD_GPIO43 43 ++#define PAD_GPIO44 44 ++#define PAD_GPIO45 45 ++#define PAD_GPIO46 46 ++#define PAD_GPIO47 47 ++#define PAD_GPIO48 48 ++#define PAD_GPIO49 49 ++#define PAD_GPIO50 50 ++#define PAD_GPIO51 51 ++#define PAD_GPIO52 52 ++#define PAD_GPIO53 53 ++#define PAD_GPIO54 54 ++#define PAD_GPIO55 55 ++#define PAD_GPIO56 56 ++#define PAD_GPIO57 57 ++#define PAD_GPIO58 58 ++#define PAD_GPIO59 59 ++#define PAD_GPIO60 60 ++#define PAD_GPIO61 61 ++#define PAD_GPIO62 62 ++#define PAD_GPIO63 63 ++#define PAD_SD0_CLK 64 ++#define PAD_SD0_CMD 65 ++#define PAD_SD0_DATA0 66 ++#define PAD_SD0_DATA1 67 ++#define PAD_SD0_DATA2 68 ++#define PAD_SD0_DATA3 69 ++#define PAD_SD0_DATA4 70 ++#define PAD_SD0_DATA5 71 ++#define PAD_SD0_DATA6 72 ++#define PAD_SD0_DATA7 73 ++#define PAD_SD0_STRB 74 ++#define PAD_GMAC1_MDC 75 ++#define PAD_GMAC1_MDIO 76 ++#define PAD_GMAC1_RXD0 77 ++#define PAD_GMAC1_RXD1 78 ++#define PAD_GMAC1_RXD2 79 ++#define PAD_GMAC1_RXD3 80 ++#define PAD_GMAC1_RXDV 81 ++#define PAD_GMAC1_RXC 82 ++#define PAD_GMAC1_TXD0 83 ++#define PAD_GMAC1_TXD1 84 ++#define PAD_GMAC1_TXD2 85 ++#define PAD_GMAC1_TXD3 86 ++#define PAD_GMAC1_TXEN 87 ++#define PAD_GMAC1_TXC 88 ++#define PAD_QSPI_SCLK 89 ++#define PAD_QSPI_CS0 90 ++#define PAD_QSPI_DATA0 91 ++#define PAD_QSPI_DATA1 92 ++#define PAD_QSPI_DATA2 93 ++#define PAD_QSPI_DATA3 94 ++ ++#define GPOUT_LOW 0 ++#define GPOUT_HIGH 1 ++ ++#define GPOEN_ENABLE 0 ++#define GPOEN_DISABLE 1 ++ ++#define GPI_NONE 255 ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0027-dt-bindings-pinctrl-Add-StarFive-JH7110-aon-pinctrl.patch b/target/linux/starfive/patches-6.1/0027-dt-bindings-pinctrl-Add-StarFive-JH7110-aon-pinctrl.patch new file mode 100644 index 0000000000..8ef08efca1 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0027-dt-bindings-pinctrl-Add-StarFive-JH7110-aon-pinctrl.patch @@ -0,0 +1,176 @@ +From 514cae455122c799638226f4358e8e6f5e155248 Mon Sep 17 00:00:00 2001 +From: Jianlong Huang +Date: Thu, 9 Feb 2023 22:37:00 +0800 +Subject: [PATCH 027/122] dt-bindings: pinctrl: Add StarFive JH7110 aon pinctrl + +Add pinctrl bindings for StarFive JH7110 SoC aon pinctrl controller. + +Reviewed-by: Rob Herring +Signed-off-by: Jianlong Huang +Co-developed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +--- + .../pinctrl/starfive,jh7110-aon-pinctrl.yaml | 124 ++++++++++++++++++ + .../pinctrl/starfive,jh7110-pinctrl.h | 22 ++++ + 2 files changed, 146 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh7110-aon-pinctrl.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-aon-pinctrl.yaml +@@ -0,0 +1,124 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pinctrl/starfive,jh7110-aon-pinctrl.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 AON Pin Controller ++ ++description: | ++ Bindings for the JH7110 RISC-V SoC from StarFive Technology Ltd. ++ ++ Out of the SoC's many pins only the ones named PAD_RGPIO0 to PAD_RGPIO3 ++ can be multiplexed and have configurable bias, drive strength, ++ schmitt trigger etc. ++ Some peripherals such as PWM have their I/O go through the 4 "GPIOs". ++ ++maintainers: ++ - Jianlong Huang ++ ++properties: ++ compatible: ++ const: starfive,jh7110-aon-pinctrl ++ ++ reg: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ interrupt-controller: true ++ ++ '#interrupt-cells': ++ const: 2 ++ ++ gpio-controller: true ++ ++ '#gpio-cells': ++ const: 2 ++ ++patternProperties: ++ '-[0-9]+$': ++ type: object ++ additionalProperties: false ++ patternProperties: ++ '-pins$': ++ type: object ++ description: | ++ A pinctrl node should contain at least one subnode representing the ++ pinctrl groups available on the machine. Each subnode will list the ++ pins it needs, and how they should be configured, with regard to ++ muxer configuration, bias, input enable/disable, input schmitt ++ trigger enable/disable, slew-rate and drive strength. ++ allOf: ++ - $ref: /schemas/pinctrl/pincfg-node.yaml ++ - $ref: /schemas/pinctrl/pinmux-node.yaml ++ additionalProperties: false ++ ++ properties: ++ pinmux: ++ description: | ++ The list of GPIOs and their mux settings that properties in the ++ node apply to. This should be set using the GPIOMUX macro. ++ ++ bias-disable: true ++ ++ bias-pull-up: ++ type: boolean ++ ++ bias-pull-down: ++ type: boolean ++ ++ drive-strength: ++ enum: [ 2, 4, 8, 12 ] ++ ++ input-enable: true ++ ++ input-disable: true ++ ++ input-schmitt-enable: true ++ ++ input-schmitt-disable: true ++ ++ slew-rate: ++ maximum: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - interrupt-controller ++ - '#interrupt-cells' ++ - gpio-controller ++ - '#gpio-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pinctrl@17020000 { ++ compatible = "starfive,jh7110-aon-pinctrl"; ++ reg = <0x17020000 0x10000>; ++ resets = <&aoncrg 2>; ++ interrupts = <85>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ pwm-0 { ++ pwm-pins { ++ pinmux = <0xff030802>; ++ bias-disable; ++ drive-strength = <12>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ }; ++ ++... +--- a/include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h ++++ b/include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h +@@ -104,6 +104,28 @@ + #define PAD_QSPI_DATA2 93 + #define PAD_QSPI_DATA3 94 + ++/* aon_iomux pins */ ++#define PAD_TESTEN 0 ++#define PAD_RGPIO0 1 ++#define PAD_RGPIO1 2 ++#define PAD_RGPIO2 3 ++#define PAD_RGPIO3 4 ++#define PAD_RSTN 5 ++#define PAD_GMAC0_MDC 6 ++#define PAD_GMAC0_MDIO 7 ++#define PAD_GMAC0_RXD0 8 ++#define PAD_GMAC0_RXD1 9 ++#define PAD_GMAC0_RXD2 10 ++#define PAD_GMAC0_RXD3 11 ++#define PAD_GMAC0_RXDV 12 ++#define PAD_GMAC0_RXC 13 ++#define PAD_GMAC0_TXD0 14 ++#define PAD_GMAC0_TXD1 15 ++#define PAD_GMAC0_TXD2 16 ++#define PAD_GMAC0_TXD3 17 ++#define PAD_GMAC0_TXEN 18 ++#define PAD_GMAC0_TXC 19 ++ + #define GPOUT_LOW 0 + #define GPOUT_HIGH 1 + diff --git a/target/linux/starfive/patches-6.1/0028-pinctrl-starfive-Add-StarFive-JH7110-sys-controller-.patch b/target/linux/starfive/patches-6.1/0028-pinctrl-starfive-Add-StarFive-JH7110-sys-controller-.patch new file mode 100644 index 0000000000..a9310aadc3 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0028-pinctrl-starfive-Add-StarFive-JH7110-sys-controller-.patch @@ -0,0 +1,1581 @@ +From 4dba3156173e59131d234d702388ee7283bac8a9 Mon Sep 17 00:00:00 2001 +From: Jianlong Huang +Date: Thu, 9 Feb 2023 22:37:01 +0800 +Subject: [PATCH 028/122] pinctrl: starfive: Add StarFive JH7110 sys controller + driver + +Add pinctrl driver for StarFive JH7110 SoC sys pinctrl controller. + +Co-developed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Jianlong Huang +Signed-off-by: Hal Feng +--- + MAINTAINERS | 2 +- + drivers/pinctrl/starfive/Kconfig | 21 + + drivers/pinctrl/starfive/Makefile | 3 + + .../starfive/pinctrl-starfive-jh7110-sys.c | 449 ++++++++ + .../starfive/pinctrl-starfive-jh7110.c | 982 ++++++++++++++++++ + .../starfive/pinctrl-starfive-jh7110.h | 70 ++ + 6 files changed, 1526 insertions(+), 1 deletion(-) + create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c + create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c + create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19664,7 +19664,7 @@ M: Jianlong Huang ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#include "../core.h" ++#include "../pinctrl-utils.h" ++#include "../pinmux.h" ++#include "../pinconf.h" ++#include "pinctrl-starfive-jh7110.h" ++ ++#define JH7110_SYS_NGPIO 64 ++#define JH7110_SYS_GC_BASE 0 ++ ++/* registers */ ++#define JH7110_SYS_DOEN 0x000 ++#define JH7110_SYS_DOUT 0x040 ++#define JH7110_SYS_GPI 0x080 ++#define JH7110_SYS_GPIOIN 0x118 ++ ++#define JH7110_SYS_GPIOEN 0x0dc ++#define JH7110_SYS_GPIOIS0 0x0e0 ++#define JH7110_SYS_GPIOIS1 0x0e4 ++#define JH7110_SYS_GPIOIC0 0x0e8 ++#define JH7110_SYS_GPIOIC1 0x0ec ++#define JH7110_SYS_GPIOIBE0 0x0f0 ++#define JH7110_SYS_GPIOIBE1 0x0f4 ++#define JH7110_SYS_GPIOIEV0 0x0f8 ++#define JH7110_SYS_GPIOIEV1 0x0fc ++#define JH7110_SYS_GPIOIE0 0x100 ++#define JH7110_SYS_GPIOIE1 0x104 ++#define JH7110_SYS_GPIORIS0 0x108 ++#define JH7110_SYS_GPIORIS1 0x10c ++#define JH7110_SYS_GPIOMIS0 0x110 ++#define JH7110_SYS_GPIOMIS1 0x114 ++ ++#define JH7110_SYS_GPO_PDA_0_74_CFG 0x120 ++#define JH7110_SYS_GPO_PDA_89_94_CFG 0x284 ++ ++static const struct pinctrl_pin_desc jh7110_sys_pins[] = { ++ PINCTRL_PIN(PAD_GPIO0, "GPIO0"), ++ PINCTRL_PIN(PAD_GPIO1, "GPIO1"), ++ PINCTRL_PIN(PAD_GPIO2, "GPIO2"), ++ PINCTRL_PIN(PAD_GPIO3, "GPIO3"), ++ PINCTRL_PIN(PAD_GPIO4, "GPIO4"), ++ PINCTRL_PIN(PAD_GPIO5, "GPIO5"), ++ PINCTRL_PIN(PAD_GPIO6, "GPIO6"), ++ PINCTRL_PIN(PAD_GPIO7, "GPIO7"), ++ PINCTRL_PIN(PAD_GPIO8, "GPIO8"), ++ PINCTRL_PIN(PAD_GPIO9, "GPIO9"), ++ PINCTRL_PIN(PAD_GPIO10, "GPIO10"), ++ PINCTRL_PIN(PAD_GPIO11, "GPIO11"), ++ PINCTRL_PIN(PAD_GPIO12, "GPIO12"), ++ PINCTRL_PIN(PAD_GPIO13, "GPIO13"), ++ PINCTRL_PIN(PAD_GPIO14, "GPIO14"), ++ PINCTRL_PIN(PAD_GPIO15, "GPIO15"), ++ PINCTRL_PIN(PAD_GPIO16, "GPIO16"), ++ PINCTRL_PIN(PAD_GPIO17, "GPIO17"), ++ PINCTRL_PIN(PAD_GPIO18, "GPIO18"), ++ PINCTRL_PIN(PAD_GPIO19, "GPIO19"), ++ PINCTRL_PIN(PAD_GPIO20, "GPIO20"), ++ PINCTRL_PIN(PAD_GPIO21, "GPIO21"), ++ PINCTRL_PIN(PAD_GPIO22, "GPIO22"), ++ PINCTRL_PIN(PAD_GPIO23, "GPIO23"), ++ PINCTRL_PIN(PAD_GPIO24, "GPIO24"), ++ PINCTRL_PIN(PAD_GPIO25, "GPIO25"), ++ PINCTRL_PIN(PAD_GPIO26, "GPIO26"), ++ PINCTRL_PIN(PAD_GPIO27, "GPIO27"), ++ PINCTRL_PIN(PAD_GPIO28, "GPIO28"), ++ PINCTRL_PIN(PAD_GPIO29, "GPIO29"), ++ PINCTRL_PIN(PAD_GPIO30, "GPIO30"), ++ PINCTRL_PIN(PAD_GPIO31, "GPIO31"), ++ PINCTRL_PIN(PAD_GPIO32, "GPIO32"), ++ PINCTRL_PIN(PAD_GPIO33, "GPIO33"), ++ PINCTRL_PIN(PAD_GPIO34, "GPIO34"), ++ PINCTRL_PIN(PAD_GPIO35, "GPIO35"), ++ PINCTRL_PIN(PAD_GPIO36, "GPIO36"), ++ PINCTRL_PIN(PAD_GPIO37, "GPIO37"), ++ PINCTRL_PIN(PAD_GPIO38, "GPIO38"), ++ PINCTRL_PIN(PAD_GPIO39, "GPIO39"), ++ PINCTRL_PIN(PAD_GPIO40, "GPIO40"), ++ PINCTRL_PIN(PAD_GPIO41, "GPIO41"), ++ PINCTRL_PIN(PAD_GPIO42, "GPIO42"), ++ PINCTRL_PIN(PAD_GPIO43, "GPIO43"), ++ PINCTRL_PIN(PAD_GPIO44, "GPIO44"), ++ PINCTRL_PIN(PAD_GPIO45, "GPIO45"), ++ PINCTRL_PIN(PAD_GPIO46, "GPIO46"), ++ PINCTRL_PIN(PAD_GPIO47, "GPIO47"), ++ PINCTRL_PIN(PAD_GPIO48, "GPIO48"), ++ PINCTRL_PIN(PAD_GPIO49, "GPIO49"), ++ PINCTRL_PIN(PAD_GPIO50, "GPIO50"), ++ PINCTRL_PIN(PAD_GPIO51, "GPIO51"), ++ PINCTRL_PIN(PAD_GPIO52, "GPIO52"), ++ PINCTRL_PIN(PAD_GPIO53, "GPIO53"), ++ PINCTRL_PIN(PAD_GPIO54, "GPIO54"), ++ PINCTRL_PIN(PAD_GPIO55, "GPIO55"), ++ PINCTRL_PIN(PAD_GPIO56, "GPIO56"), ++ PINCTRL_PIN(PAD_GPIO57, "GPIO57"), ++ PINCTRL_PIN(PAD_GPIO58, "GPIO58"), ++ PINCTRL_PIN(PAD_GPIO59, "GPIO59"), ++ PINCTRL_PIN(PAD_GPIO60, "GPIO60"), ++ PINCTRL_PIN(PAD_GPIO61, "GPIO61"), ++ PINCTRL_PIN(PAD_GPIO62, "GPIO62"), ++ PINCTRL_PIN(PAD_GPIO63, "GPIO63"), ++ PINCTRL_PIN(PAD_SD0_CLK, "SD0_CLK"), ++ PINCTRL_PIN(PAD_SD0_CMD, "SD0_CMD"), ++ PINCTRL_PIN(PAD_SD0_DATA0, "SD0_DATA0"), ++ PINCTRL_PIN(PAD_SD0_DATA1, "SD0_DATA1"), ++ PINCTRL_PIN(PAD_SD0_DATA2, "SD0_DATA2"), ++ PINCTRL_PIN(PAD_SD0_DATA3, "SD0_DATA3"), ++ PINCTRL_PIN(PAD_SD0_DATA4, "SD0_DATA4"), ++ PINCTRL_PIN(PAD_SD0_DATA5, "SD0_DATA5"), ++ PINCTRL_PIN(PAD_SD0_DATA6, "SD0_DATA6"), ++ PINCTRL_PIN(PAD_SD0_DATA7, "SD0_DATA7"), ++ PINCTRL_PIN(PAD_SD0_STRB, "SD0_STRB"), ++ PINCTRL_PIN(PAD_GMAC1_MDC, "GMAC1_MDC"), ++ PINCTRL_PIN(PAD_GMAC1_MDIO, "GMAC1_MDIO"), ++ PINCTRL_PIN(PAD_GMAC1_RXD0, "GMAC1_RXD0"), ++ PINCTRL_PIN(PAD_GMAC1_RXD1, "GMAC1_RXD1"), ++ PINCTRL_PIN(PAD_GMAC1_RXD2, "GMAC1_RXD2"), ++ PINCTRL_PIN(PAD_GMAC1_RXD3, "GMAC1_RXD3"), ++ PINCTRL_PIN(PAD_GMAC1_RXDV, "GMAC1_RXDV"), ++ PINCTRL_PIN(PAD_GMAC1_RXC, "GMAC1_RXC"), ++ PINCTRL_PIN(PAD_GMAC1_TXD0, "GMAC1_TXD0"), ++ PINCTRL_PIN(PAD_GMAC1_TXD1, "GMAC1_TXD1"), ++ PINCTRL_PIN(PAD_GMAC1_TXD2, "GMAC1_TXD2"), ++ PINCTRL_PIN(PAD_GMAC1_TXD3, "GMAC1_TXD3"), ++ PINCTRL_PIN(PAD_GMAC1_TXEN, "GMAC1_TXEN"), ++ PINCTRL_PIN(PAD_GMAC1_TXC, "GMAC1_TXC"), ++ PINCTRL_PIN(PAD_QSPI_SCLK, "QSPI_SCLK"), ++ PINCTRL_PIN(PAD_QSPI_CS0, "QSPI_CS0"), ++ PINCTRL_PIN(PAD_QSPI_DATA0, "QSPI_DATA0"), ++ PINCTRL_PIN(PAD_QSPI_DATA1, "QSPI_DATA1"), ++ PINCTRL_PIN(PAD_QSPI_DATA2, "QSPI_DATA2"), ++ PINCTRL_PIN(PAD_QSPI_DATA3, "QSPI_DATA3"), ++}; ++ ++struct jh7110_func_sel { ++ u16 offset; ++ u8 shift; ++ u8 max; ++}; ++ ++static const struct jh7110_func_sel ++ jh7110_sys_func_sel[ARRAY_SIZE(jh7110_sys_pins)] = { ++ [PAD_GMAC1_RXC] = { 0x29c, 0, 1 }, ++ [PAD_GPIO10] = { 0x29c, 2, 3 }, ++ [PAD_GPIO11] = { 0x29c, 5, 3 }, ++ [PAD_GPIO12] = { 0x29c, 8, 3 }, ++ [PAD_GPIO13] = { 0x29c, 11, 3 }, ++ [PAD_GPIO14] = { 0x29c, 14, 3 }, ++ [PAD_GPIO15] = { 0x29c, 17, 3 }, ++ [PAD_GPIO16] = { 0x29c, 20, 3 }, ++ [PAD_GPIO17] = { 0x29c, 23, 3 }, ++ [PAD_GPIO18] = { 0x29c, 26, 3 }, ++ [PAD_GPIO19] = { 0x29c, 29, 3 }, ++ ++ [PAD_GPIO20] = { 0x2a0, 0, 3 }, ++ [PAD_GPIO21] = { 0x2a0, 3, 3 }, ++ [PAD_GPIO22] = { 0x2a0, 6, 3 }, ++ [PAD_GPIO23] = { 0x2a0, 9, 3 }, ++ [PAD_GPIO24] = { 0x2a0, 12, 3 }, ++ [PAD_GPIO25] = { 0x2a0, 15, 3 }, ++ [PAD_GPIO26] = { 0x2a0, 18, 3 }, ++ [PAD_GPIO27] = { 0x2a0, 21, 3 }, ++ [PAD_GPIO28] = { 0x2a0, 24, 3 }, ++ [PAD_GPIO29] = { 0x2a0, 27, 3 }, ++ ++ [PAD_GPIO30] = { 0x2a4, 0, 3 }, ++ [PAD_GPIO31] = { 0x2a4, 3, 3 }, ++ [PAD_GPIO32] = { 0x2a4, 6, 3 }, ++ [PAD_GPIO33] = { 0x2a4, 9, 3 }, ++ [PAD_GPIO34] = { 0x2a4, 12, 3 }, ++ [PAD_GPIO35] = { 0x2a4, 15, 3 }, ++ [PAD_GPIO36] = { 0x2a4, 17, 3 }, ++ [PAD_GPIO37] = { 0x2a4, 20, 3 }, ++ [PAD_GPIO38] = { 0x2a4, 23, 3 }, ++ [PAD_GPIO39] = { 0x2a4, 26, 3 }, ++ [PAD_GPIO40] = { 0x2a4, 29, 3 }, ++ ++ [PAD_GPIO41] = { 0x2a8, 0, 3 }, ++ [PAD_GPIO42] = { 0x2a8, 3, 3 }, ++ [PAD_GPIO43] = { 0x2a8, 6, 3 }, ++ [PAD_GPIO44] = { 0x2a8, 9, 3 }, ++ [PAD_GPIO45] = { 0x2a8, 12, 3 }, ++ [PAD_GPIO46] = { 0x2a8, 15, 3 }, ++ [PAD_GPIO47] = { 0x2a8, 18, 3 }, ++ [PAD_GPIO48] = { 0x2a8, 21, 3 }, ++ [PAD_GPIO49] = { 0x2a8, 24, 3 }, ++ [PAD_GPIO50] = { 0x2a8, 27, 3 }, ++ [PAD_GPIO51] = { 0x2a8, 30, 3 }, ++ ++ [PAD_GPIO52] = { 0x2ac, 0, 3 }, ++ [PAD_GPIO53] = { 0x2ac, 2, 3 }, ++ [PAD_GPIO54] = { 0x2ac, 4, 3 }, ++ [PAD_GPIO55] = { 0x2ac, 6, 3 }, ++ [PAD_GPIO56] = { 0x2ac, 9, 3 }, ++ [PAD_GPIO57] = { 0x2ac, 12, 3 }, ++ [PAD_GPIO58] = { 0x2ac, 15, 3 }, ++ [PAD_GPIO59] = { 0x2ac, 18, 3 }, ++ [PAD_GPIO60] = { 0x2ac, 21, 3 }, ++ [PAD_GPIO61] = { 0x2ac, 24, 3 }, ++ [PAD_GPIO62] = { 0x2ac, 27, 3 }, ++ [PAD_GPIO63] = { 0x2ac, 30, 3 }, ++ ++ [PAD_GPIO6] = { 0x2b0, 0, 3 }, ++ [PAD_GPIO7] = { 0x2b0, 2, 3 }, ++ [PAD_GPIO8] = { 0x2b0, 5, 3 }, ++ [PAD_GPIO9] = { 0x2b0, 8, 3 }, ++}; ++ ++struct jh7110_vin_group_sel { ++ u16 offset; ++ u8 shift; ++ u8 group; ++}; ++ ++static const struct jh7110_vin_group_sel ++ jh7110_sys_vin_group_sel[ARRAY_SIZE(jh7110_sys_pins)] = { ++ [PAD_GPIO6] = { 0x2b4, 21, 0 }, ++ [PAD_GPIO7] = { 0x2b4, 18, 0 }, ++ [PAD_GPIO8] = { 0x2b4, 15, 0 }, ++ [PAD_GPIO9] = { 0x2b0, 11, 0 }, ++ [PAD_GPIO10] = { 0x2b0, 20, 0 }, ++ [PAD_GPIO11] = { 0x2b0, 23, 0 }, ++ [PAD_GPIO12] = { 0x2b0, 26, 0 }, ++ [PAD_GPIO13] = { 0x2b0, 29, 0 }, ++ [PAD_GPIO14] = { 0x2b4, 0, 0 }, ++ [PAD_GPIO15] = { 0x2b4, 3, 0 }, ++ [PAD_GPIO16] = { 0x2b4, 6, 0 }, ++ [PAD_GPIO17] = { 0x2b4, 9, 0 }, ++ [PAD_GPIO18] = { 0x2b4, 12, 0 }, ++ [PAD_GPIO19] = { 0x2b0, 14, 0 }, ++ [PAD_GPIO20] = { 0x2b0, 17, 0 }, ++ ++ [PAD_GPIO21] = { 0x2b4, 21, 1 }, ++ [PAD_GPIO22] = { 0x2b4, 18, 1 }, ++ [PAD_GPIO23] = { 0x2b4, 15, 1 }, ++ [PAD_GPIO24] = { 0x2b0, 11, 1 }, ++ [PAD_GPIO25] = { 0x2b0, 20, 1 }, ++ [PAD_GPIO26] = { 0x2b0, 23, 1 }, ++ [PAD_GPIO27] = { 0x2b0, 26, 1 }, ++ [PAD_GPIO28] = { 0x2b0, 29, 1 }, ++ [PAD_GPIO29] = { 0x2b4, 0, 1 }, ++ [PAD_GPIO30] = { 0x2b4, 3, 1 }, ++ [PAD_GPIO31] = { 0x2b4, 6, 1 }, ++ [PAD_GPIO32] = { 0x2b4, 9, 1 }, ++ [PAD_GPIO33] = { 0x2b4, 12, 1 }, ++ [PAD_GPIO34] = { 0x2b0, 14, 1 }, ++ [PAD_GPIO35] = { 0x2b0, 17, 1 }, ++ ++ [PAD_GPIO36] = { 0x2b4, 21, 2 }, ++ [PAD_GPIO37] = { 0x2b4, 18, 2 }, ++ [PAD_GPIO38] = { 0x2b4, 15, 2 }, ++ [PAD_GPIO39] = { 0x2b0, 11, 2 }, ++ [PAD_GPIO40] = { 0x2b0, 20, 2 }, ++ [PAD_GPIO41] = { 0x2b0, 23, 2 }, ++ [PAD_GPIO42] = { 0x2b0, 26, 2 }, ++ [PAD_GPIO43] = { 0x2b0, 29, 2 }, ++ [PAD_GPIO44] = { 0x2b4, 0, 2 }, ++ [PAD_GPIO45] = { 0x2b4, 3, 2 }, ++ [PAD_GPIO46] = { 0x2b4, 6, 2 }, ++ [PAD_GPIO47] = { 0x2b4, 9, 2 }, ++ [PAD_GPIO48] = { 0x2b4, 12, 2 }, ++ [PAD_GPIO49] = { 0x2b0, 14, 2 }, ++ [PAD_GPIO50] = { 0x2b0, 17, 2 }, ++}; ++ ++static void jh7110_set_function(struct jh7110_pinctrl *sfp, ++ unsigned int pin, u32 func) ++{ ++ const struct jh7110_func_sel *fs = &jh7110_sys_func_sel[pin]; ++ unsigned long flags; ++ void __iomem *reg; ++ u32 mask; ++ ++ if (!fs->offset) ++ return; ++ ++ if (func > fs->max) ++ return; ++ ++ reg = sfp->base + fs->offset; ++ func = func << fs->shift; ++ mask = 0x3U << fs->shift; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ func |= readl_relaxed(reg) & ~mask; ++ writel_relaxed(func, reg); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static void jh7110_set_vin_group(struct jh7110_pinctrl *sfp, ++ unsigned int pin) ++{ ++ const struct jh7110_vin_group_sel *gs = &jh7110_sys_vin_group_sel[pin]; ++ unsigned long flags; ++ void __iomem *reg; ++ u32 mask; ++ u32 grp; ++ ++ if (!gs->offset) ++ return; ++ ++ reg = sfp->base + gs->offset; ++ grp = gs->group << gs->shift; ++ mask = 0x3U << gs->shift; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ grp |= readl_relaxed(reg) & ~mask; ++ writel_relaxed(grp, reg); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static int jh7110_sys_set_one_pin_mux(struct jh7110_pinctrl *sfp, ++ unsigned int pin, ++ unsigned int din, u32 dout, ++ u32 doen, u32 func) ++{ ++ if (pin < sfp->gc.ngpio && func == 0) ++ jh7110_set_gpiomux(sfp, pin, din, dout, doen); ++ ++ jh7110_set_function(sfp, pin, func); ++ ++ if (pin < sfp->gc.ngpio && func == 2) ++ jh7110_set_vin_group(sfp, pin); ++ ++ return 0; ++} ++ ++static int jh7110_sys_get_padcfg_base(struct jh7110_pinctrl *sfp, ++ unsigned int pin) ++{ ++ if (pin < PAD_GMAC1_MDC) ++ return JH7110_SYS_GPO_PDA_0_74_CFG; ++ else if (pin > PAD_GMAC1_TXC && pin <= PAD_QSPI_DATA3) ++ return JH7110_SYS_GPO_PDA_89_94_CFG; ++ else ++ return -1; ++} ++ ++static void jh7110_sys_irq_handler(struct irq_desc *desc) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_desc(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned long mis; ++ unsigned int pin; ++ ++ chained_irq_enter(chip, desc); ++ ++ mis = readl_relaxed(sfp->base + JH7110_SYS_GPIOMIS0); ++ for_each_set_bit(pin, &mis, 32) ++ generic_handle_domain_irq(sfp->gc.irq.domain, pin); ++ ++ mis = readl_relaxed(sfp->base + JH7110_SYS_GPIOMIS1); ++ for_each_set_bit(pin, &mis, 32) ++ generic_handle_domain_irq(sfp->gc.irq.domain, pin + 32); ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static int jh7110_sys_init_hw(struct gpio_chip *gc) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ ++ /* mask all GPIO interrupts */ ++ writel(0U, sfp->base + JH7110_SYS_GPIOIE0); ++ writel(0U, sfp->base + JH7110_SYS_GPIOIE1); ++ /* clear edge interrupt flags */ ++ writel(~0U, sfp->base + JH7110_SYS_GPIOIC0); ++ writel(~0U, sfp->base + JH7110_SYS_GPIOIC1); ++ /* enable GPIO interrupts */ ++ writel(1U, sfp->base + JH7110_SYS_GPIOEN); ++ return 0; ++} ++ ++static const struct jh7110_gpio_irq_reg jh7110_sys_irq_reg = { ++ .is_reg_base = JH7110_SYS_GPIOIS0, ++ .ic_reg_base = JH7110_SYS_GPIOIC0, ++ .ibe_reg_base = JH7110_SYS_GPIOIBE0, ++ .iev_reg_base = JH7110_SYS_GPIOIEV0, ++ .ie_reg_base = JH7110_SYS_GPIOIE0, ++ .ris_reg_base = JH7110_SYS_GPIORIS0, ++ .mis_reg_base = JH7110_SYS_GPIOMIS0, ++}; ++ ++static const struct jh7110_pinctrl_soc_info jh7110_sys_pinctrl_info = { ++ .pins = jh7110_sys_pins, ++ .npins = ARRAY_SIZE(jh7110_sys_pins), ++ .ngpios = JH7110_SYS_NGPIO, ++ .gc_base = JH7110_SYS_GC_BASE, ++ .dout_reg_base = JH7110_SYS_DOUT, ++ .dout_mask = GENMASK(6, 0), ++ .doen_reg_base = JH7110_SYS_DOEN, ++ .doen_mask = GENMASK(5, 0), ++ .gpi_reg_base = JH7110_SYS_GPI, ++ .gpi_mask = GENMASK(6, 0), ++ .gpioin_reg_base = JH7110_SYS_GPIOIN, ++ .irq_reg = &jh7110_sys_irq_reg, ++ .jh7110_set_one_pin_mux = jh7110_sys_set_one_pin_mux, ++ .jh7110_get_padcfg_base = jh7110_sys_get_padcfg_base, ++ .jh7110_gpio_irq_handler = jh7110_sys_irq_handler, ++ .jh7110_gpio_init_hw = jh7110_sys_init_hw, ++}; ++ ++static const struct of_device_id jh7110_sys_pinctrl_of_match[] = { ++ { ++ .compatible = "starfive,jh7110-sys-pinctrl", ++ .data = &jh7110_sys_pinctrl_info, ++ }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_sys_pinctrl_of_match); ++ ++static struct platform_driver jh7110_sys_pinctrl_driver = { ++ .probe = jh7110_pinctrl_probe, ++ .driver = { ++ .name = "starfive-jh7110-sys-pinctrl", ++ .of_match_table = jh7110_sys_pinctrl_of_match, ++ }, ++}; ++module_platform_driver(jh7110_sys_pinctrl_driver); ++ ++MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC sys controller"); ++MODULE_AUTHOR("Emil Renner Berthing "); ++MODULE_AUTHOR("Jianlong Huang "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c +@@ -0,0 +1,982 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Pinctrl / GPIO driver for StarFive JH7110 SoC ++ * ++ * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "../core.h" ++#include "../pinctrl-utils.h" ++#include "../pinmux.h" ++#include "../pinconf.h" ++#include "pinctrl-starfive-jh7110.h" ++ ++/* pad control bits */ ++#define JH7110_PADCFG_POS BIT(7) ++#define JH7110_PADCFG_SMT BIT(6) ++#define JH7110_PADCFG_SLEW BIT(5) ++#define JH7110_PADCFG_PD BIT(4) ++#define JH7110_PADCFG_PU BIT(3) ++#define JH7110_PADCFG_BIAS (JH7110_PADCFG_PD | JH7110_PADCFG_PU) ++#define JH7110_PADCFG_DS_MASK GENMASK(2, 1) ++#define JH7110_PADCFG_DS_2MA (0U << 1) ++#define JH7110_PADCFG_DS_4MA BIT(1) ++#define JH7110_PADCFG_DS_8MA (2U << 1) ++#define JH7110_PADCFG_DS_12MA (3U << 1) ++#define JH7110_PADCFG_IE BIT(0) ++ ++/* ++ * The packed pinmux values from the device tree look like this: ++ * ++ * | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 | ++ * | din | dout | doen | function | pin | ++ */ ++static unsigned int jh7110_pinmux_din(u32 v) ++{ ++ return (v & GENMASK(31, 24)) >> 24; ++} ++ ++static u32 jh7110_pinmux_dout(u32 v) ++{ ++ return (v & GENMASK(23, 16)) >> 16; ++} ++ ++static u32 jh7110_pinmux_doen(u32 v) ++{ ++ return (v & GENMASK(15, 10)) >> 10; ++} ++ ++static u32 jh7110_pinmux_function(u32 v) ++{ ++ return (v & GENMASK(9, 8)) >> 8; ++} ++ ++static unsigned int jh7110_pinmux_pin(u32 v) ++{ ++ return v & GENMASK(7, 0); ++} ++ ++static struct jh7110_pinctrl *jh7110_from_irq_data(struct irq_data *d) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ ++ return container_of(gc, struct jh7110_pinctrl, gc); ++} ++ ++struct jh7110_pinctrl *jh7110_from_irq_desc(struct irq_desc *desc) ++{ ++ struct gpio_chip *gc = irq_desc_get_handler_data(desc); ++ ++ return container_of(gc, struct jh7110_pinctrl, gc); ++} ++EXPORT_SYMBOL_GPL(jh7110_from_irq_desc); ++ ++#ifdef CONFIG_DEBUG_FS ++static void jh7110_pin_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, unsigned int pin) ++{ ++ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ ++ seq_printf(s, "%s", dev_name(pctldev->dev)); ++ ++ if (pin < sfp->gc.ngpio) { ++ unsigned int offset = 4 * (pin / 4); ++ unsigned int shift = 8 * (pin % 4); ++ u32 dout = readl_relaxed(sfp->base + info->dout_reg_base + offset); ++ u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset); ++ u32 gpi = readl_relaxed(sfp->base + info->gpi_reg_base + offset); ++ ++ dout = (dout >> shift) & info->dout_mask; ++ doen = (doen >> shift) & info->doen_mask; ++ gpi = ((gpi >> shift) - 2) & info->gpi_mask; ++ ++ seq_printf(s, " dout=%u doen=%u din=%u", dout, doen, gpi); ++ } ++} ++#else ++#define jh7110_pin_dbg_show NULL ++#endif ++ ++static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, ++ struct device_node *np, ++ struct pinctrl_map **maps, ++ unsigned int *num_maps) ++{ ++ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); ++ struct device *dev = sfp->gc.parent; ++ struct device_node *child; ++ struct pinctrl_map *map; ++ const char **pgnames; ++ const char *grpname; ++ int ngroups; ++ int nmaps; ++ int ret; ++ ++ ngroups = 0; ++ for_each_child_of_node(np, child) ++ ngroups += 1; ++ nmaps = 2 * ngroups; ++ ++ pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL); ++ if (!pgnames) ++ return -ENOMEM; ++ ++ map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL); ++ if (!map) ++ return -ENOMEM; ++ ++ nmaps = 0; ++ ngroups = 0; ++ mutex_lock(&sfp->mutex); ++ for_each_child_of_node(np, child) { ++ int npins = of_property_count_u32_elems(child, "pinmux"); ++ int *pins; ++ u32 *pinmux; ++ int i; ++ ++ if (npins < 1) { ++ dev_err(dev, ++ "invalid pinctrl group %pOFn.%pOFn: pinmux not set\n", ++ np, child); ++ ret = -EINVAL; ++ goto put_child; ++ } ++ ++ grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child); ++ if (!grpname) { ++ ret = -ENOMEM; ++ goto put_child; ++ } ++ ++ pgnames[ngroups++] = grpname; ++ ++ pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); ++ if (!pins) { ++ ret = -ENOMEM; ++ goto put_child; ++ } ++ ++ pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL); ++ if (!pinmux) { ++ ret = -ENOMEM; ++ goto put_child; ++ } ++ ++ ret = of_property_read_u32_array(child, "pinmux", pinmux, npins); ++ if (ret) ++ goto put_child; ++ ++ for (i = 0; i < npins; i++) ++ pins[i] = jh7110_pinmux_pin(pinmux[i]); ++ ++ map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; ++ map[nmaps].data.mux.function = np->name; ++ map[nmaps].data.mux.group = grpname; ++ nmaps += 1; ++ ++ ret = pinctrl_generic_add_group(pctldev, grpname, ++ pins, npins, pinmux); ++ if (ret < 0) { ++ dev_err(dev, "error adding group %s: %d\n", grpname, ret); ++ goto put_child; ++ } ++ ++ ret = pinconf_generic_parse_dt_config(child, pctldev, ++ &map[nmaps].data.configs.configs, ++ &map[nmaps].data.configs.num_configs); ++ if (ret) { ++ dev_err(dev, "error parsing pin config of group %s: %d\n", ++ grpname, ret); ++ goto put_child; ++ } ++ ++ /* don't create a map if there are no pinconf settings */ ++ if (map[nmaps].data.configs.num_configs == 0) ++ continue; ++ ++ map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; ++ map[nmaps].data.configs.group_or_pin = grpname; ++ nmaps += 1; ++ } ++ ++ ret = pinmux_generic_add_function(pctldev, np->name, ++ pgnames, ngroups, NULL); ++ if (ret < 0) { ++ dev_err(dev, "error adding function %s: %d\n", np->name, ret); ++ goto free_map; ++ } ++ mutex_unlock(&sfp->mutex); ++ ++ *maps = map; ++ *num_maps = nmaps; ++ return 0; ++ ++put_child: ++ of_node_put(child); ++free_map: ++ pinctrl_utils_free_map(pctldev, map, nmaps); ++ mutex_unlock(&sfp->mutex); ++ return ret; ++} ++ ++static const struct pinctrl_ops jh7110_pinctrl_ops = { ++ .get_groups_count = pinctrl_generic_get_group_count, ++ .get_group_name = pinctrl_generic_get_group_name, ++ .get_group_pins = pinctrl_generic_get_group_pins, ++ .pin_dbg_show = jh7110_pin_dbg_show, ++ .dt_node_to_map = jh7110_dt_node_to_map, ++ .dt_free_map = pinctrl_utils_free_map, ++}; ++ ++void jh7110_set_gpiomux(struct jh7110_pinctrl *sfp, unsigned int pin, ++ unsigned int din, u32 dout, u32 doen) ++{ ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ ++ unsigned int offset = 4 * (pin / 4); ++ unsigned int shift = 8 * (pin % 4); ++ u32 dout_mask = info->dout_mask << shift; ++ u32 done_mask = info->doen_mask << shift; ++ u32 ival, imask; ++ void __iomem *reg_dout; ++ void __iomem *reg_doen; ++ void __iomem *reg_din; ++ unsigned long flags; ++ ++ reg_dout = sfp->base + info->dout_reg_base + offset; ++ reg_doen = sfp->base + info->doen_reg_base + offset; ++ dout <<= shift; ++ doen <<= shift; ++ if (din != GPI_NONE) { ++ unsigned int ioffset = 4 * (din / 4); ++ unsigned int ishift = 8 * (din % 4); ++ ++ reg_din = sfp->base + info->gpi_reg_base + ioffset; ++ ival = (pin + 2) << ishift; ++ imask = info->gpi_mask << ishift; ++ } else { ++ reg_din = NULL; ++ } ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ dout |= readl_relaxed(reg_dout) & ~dout_mask; ++ writel_relaxed(dout, reg_dout); ++ doen |= readl_relaxed(reg_doen) & ~done_mask; ++ writel_relaxed(doen, reg_doen); ++ if (reg_din) { ++ ival |= readl_relaxed(reg_din) & ~imask; ++ writel_relaxed(ival, reg_din); ++ } ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++EXPORT_SYMBOL_GPL(jh7110_set_gpiomux); ++ ++static int jh7110_set_mux(struct pinctrl_dev *pctldev, ++ unsigned int fsel, unsigned int gsel) ++{ ++ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ const struct group_desc *group; ++ const u32 *pinmux; ++ unsigned int i; ++ ++ group = pinctrl_generic_get_group(pctldev, gsel); ++ if (!group) ++ return -EINVAL; ++ ++ pinmux = group->data; ++ for (i = 0; i < group->num_pins; i++) { ++ u32 v = pinmux[i]; ++ ++ if (info->jh7110_set_one_pin_mux) ++ info->jh7110_set_one_pin_mux(sfp, ++ jh7110_pinmux_pin(v), ++ jh7110_pinmux_din(v), ++ jh7110_pinmux_dout(v), ++ jh7110_pinmux_doen(v), ++ jh7110_pinmux_function(v)); ++ } ++ ++ return 0; ++} ++ ++static const struct pinmux_ops jh7110_pinmux_ops = { ++ .get_functions_count = pinmux_generic_get_function_count, ++ .get_function_name = pinmux_generic_get_function_name, ++ .get_function_groups = pinmux_generic_get_function_groups, ++ .set_mux = jh7110_set_mux, ++ .strict = true, ++}; ++ ++static const u8 jh7110_drive_strength_mA[4] = { 2, 4, 8, 12 }; ++ ++static u32 jh7110_padcfg_ds_to_mA(u32 padcfg) ++{ ++ return jh7110_drive_strength_mA[(padcfg >> 1) & 3U]; ++} ++ ++static u32 jh7110_padcfg_ds_from_mA(u32 v) ++{ ++ int i; ++ ++ for (i = 0; i < 3; i++) { ++ if (v <= jh7110_drive_strength_mA[i]) ++ break; ++ } ++ return i << 1; ++} ++ ++static void jh7110_padcfg_rmw(struct jh7110_pinctrl *sfp, ++ unsigned int pin, u32 mask, u32 value) ++{ ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ void __iomem *reg; ++ unsigned long flags; ++ int padcfg_base; ++ ++ if (!info->jh7110_get_padcfg_base) ++ return; ++ ++ padcfg_base = info->jh7110_get_padcfg_base(sfp, pin); ++ if (padcfg_base < 0) ++ return; ++ ++ reg = sfp->base + padcfg_base + 4 * pin; ++ value &= mask; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ value |= readl_relaxed(reg) & ~mask; ++ writel_relaxed(value, reg); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static int jh7110_pinconf_get(struct pinctrl_dev *pctldev, ++ unsigned int pin, unsigned long *config) ++{ ++ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ int param = pinconf_to_config_param(*config); ++ u32 padcfg, arg; ++ bool enabled; ++ int padcfg_base; ++ ++ if (!info->jh7110_get_padcfg_base) ++ return 0; ++ ++ padcfg_base = info->jh7110_get_padcfg_base(sfp, pin); ++ if (padcfg_base < 0) ++ return 0; ++ ++ padcfg = readl_relaxed(sfp->base + padcfg_base + 4 * pin); ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ enabled = !(padcfg & JH7110_PADCFG_BIAS); ++ arg = 0; ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ enabled = padcfg & JH7110_PADCFG_PD; ++ arg = 1; ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ enabled = padcfg & JH7110_PADCFG_PU; ++ arg = 1; ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ enabled = true; ++ arg = jh7110_padcfg_ds_to_mA(padcfg); ++ break; ++ case PIN_CONFIG_INPUT_ENABLE: ++ enabled = padcfg & JH7110_PADCFG_IE; ++ arg = enabled; ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ enabled = padcfg & JH7110_PADCFG_SMT; ++ arg = enabled; ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ enabled = true; ++ arg = !!(padcfg & JH7110_PADCFG_SLEW); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ return enabled ? 0 : -EINVAL; ++} ++ ++static int jh7110_pinconf_group_get(struct pinctrl_dev *pctldev, ++ unsigned int gsel, ++ unsigned long *config) ++{ ++ const struct group_desc *group; ++ ++ group = pinctrl_generic_get_group(pctldev, gsel); ++ if (!group) ++ return -EINVAL; ++ ++ return jh7110_pinconf_get(pctldev, group->pins[0], config); ++} ++ ++static int jh7110_pinconf_group_set(struct pinctrl_dev *pctldev, ++ unsigned int gsel, ++ unsigned long *configs, ++ unsigned int num_configs) ++{ ++ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); ++ const struct group_desc *group; ++ u16 mask, value; ++ int i; ++ ++ group = pinctrl_generic_get_group(pctldev, gsel); ++ if (!group) ++ return -EINVAL; ++ ++ mask = 0; ++ value = 0; ++ for (i = 0; i < num_configs; i++) { ++ int param = pinconf_to_config_param(configs[i]); ++ u32 arg = pinconf_to_config_argument(configs[i]); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ mask |= JH7110_PADCFG_BIAS; ++ value &= ~JH7110_PADCFG_BIAS; ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ if (arg == 0) ++ return -ENOTSUPP; ++ mask |= JH7110_PADCFG_BIAS; ++ value = (value & ~JH7110_PADCFG_BIAS) | JH7110_PADCFG_PD; ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ if (arg == 0) ++ return -ENOTSUPP; ++ mask |= JH7110_PADCFG_BIAS; ++ value = (value & ~JH7110_PADCFG_BIAS) | JH7110_PADCFG_PU; ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ mask |= JH7110_PADCFG_DS_MASK; ++ value = (value & ~JH7110_PADCFG_DS_MASK) | ++ jh7110_padcfg_ds_from_mA(arg); ++ break; ++ case PIN_CONFIG_INPUT_ENABLE: ++ mask |= JH7110_PADCFG_IE; ++ if (arg) ++ value |= JH7110_PADCFG_IE; ++ else ++ value &= ~JH7110_PADCFG_IE; ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ mask |= JH7110_PADCFG_SMT; ++ if (arg) ++ value |= JH7110_PADCFG_SMT; ++ else ++ value &= ~JH7110_PADCFG_SMT; ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ mask |= JH7110_PADCFG_SLEW; ++ if (arg) ++ value |= JH7110_PADCFG_SLEW; ++ else ++ value &= ~JH7110_PADCFG_SLEW; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ } ++ ++ for (i = 0; i < group->num_pins; i++) ++ jh7110_padcfg_rmw(sfp, group->pins[i], mask, value); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static void jh7110_pinconf_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, unsigned int pin) ++{ ++ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ u32 value; ++ int padcfg_base; ++ ++ if (!info->jh7110_get_padcfg_base) ++ return; ++ ++ padcfg_base = info->jh7110_get_padcfg_base(sfp, pin); ++ if (padcfg_base < 0) ++ return; ++ ++ value = readl_relaxed(sfp->base + padcfg_base + 4 * pin); ++ seq_printf(s, " (0x%02x)", value); ++} ++#else ++#define jh7110_pinconf_dbg_show NULL ++#endif ++ ++static const struct pinconf_ops jh7110_pinconf_ops = { ++ .pin_config_get = jh7110_pinconf_get, ++ .pin_config_group_get = jh7110_pinconf_group_get, ++ .pin_config_group_set = jh7110_pinconf_group_set, ++ .pin_config_dbg_show = jh7110_pinconf_dbg_show, ++ .is_generic = true, ++}; ++ ++static int jh7110_gpio_request(struct gpio_chip *gc, unsigned int gpio) ++{ ++ return pinctrl_gpio_request(gc->base + gpio); ++} ++ ++static void jh7110_gpio_free(struct gpio_chip *gc, unsigned int gpio) ++{ ++ pinctrl_gpio_free(gc->base + gpio); ++} ++ ++static int jh7110_gpio_get_direction(struct gpio_chip *gc, ++ unsigned int gpio) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ unsigned int offset = 4 * (gpio / 4); ++ unsigned int shift = 8 * (gpio % 4); ++ u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset); ++ ++ doen = (doen >> shift) & info->doen_mask; ++ ++ return doen == GPOEN_ENABLE ? ++ GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; ++} ++ ++static int jh7110_gpio_direction_input(struct gpio_chip *gc, ++ unsigned int gpio) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ ++ /* enable input and schmitt trigger */ ++ jh7110_padcfg_rmw(sfp, gpio, ++ JH7110_PADCFG_IE | JH7110_PADCFG_SMT, ++ JH7110_PADCFG_IE | JH7110_PADCFG_SMT); ++ ++ if (info->jh7110_set_one_pin_mux) ++ info->jh7110_set_one_pin_mux(sfp, gpio, ++ GPI_NONE, GPOUT_LOW, GPOEN_DISABLE, 0); ++ ++ return 0; ++} ++ ++static int jh7110_gpio_direction_output(struct gpio_chip *gc, ++ unsigned int gpio, int value) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ ++ if (info->jh7110_set_one_pin_mux) ++ info->jh7110_set_one_pin_mux(sfp, gpio, ++ GPI_NONE, value ? GPOUT_HIGH : GPOUT_LOW, ++ GPOEN_ENABLE, 0); ++ ++ /* disable input, schmitt trigger and bias */ ++ jh7110_padcfg_rmw(sfp, gpio, ++ JH7110_PADCFG_IE | JH7110_PADCFG_SMT | ++ JH7110_PADCFG_BIAS, 0); ++ return 0; ++} ++ ++static int jh7110_gpio_get(struct gpio_chip *gc, unsigned int gpio) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ void __iomem *reg = sfp->base + info->gpioin_reg_base ++ + 4 * (gpio / 32); ++ ++ return !!(readl_relaxed(reg) & BIT(gpio % 32)); ++} ++ ++static void jh7110_gpio_set(struct gpio_chip *gc, ++ unsigned int gpio, int value) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ const struct jh7110_pinctrl_soc_info *info = sfp->info; ++ unsigned int offset = 4 * (gpio / 4); ++ unsigned int shift = 8 * (gpio % 4); ++ void __iomem *reg_dout = sfp->base + info->dout_reg_base + offset; ++ u32 dout = (value ? GPOUT_HIGH : GPOUT_LOW) << shift; ++ u32 mask = info->dout_mask << shift; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ dout |= readl_relaxed(reg_dout) & ~mask; ++ writel_relaxed(dout, reg_dout); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static int jh7110_gpio_set_config(struct gpio_chip *gc, ++ unsigned int gpio, unsigned long config) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ u32 arg = pinconf_to_config_argument(config); ++ u32 value; ++ u32 mask; ++ ++ switch (pinconf_to_config_param(config)) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ mask = JH7110_PADCFG_BIAS; ++ value = 0; ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ if (arg == 0) ++ return -ENOTSUPP; ++ mask = JH7110_PADCFG_BIAS; ++ value = JH7110_PADCFG_PD; ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ if (arg == 0) ++ return -ENOTSUPP; ++ mask = JH7110_PADCFG_BIAS; ++ value = JH7110_PADCFG_PU; ++ break; ++ case PIN_CONFIG_DRIVE_PUSH_PULL: ++ return 0; ++ case PIN_CONFIG_INPUT_ENABLE: ++ mask = JH7110_PADCFG_IE; ++ value = arg ? JH7110_PADCFG_IE : 0; ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ mask = JH7110_PADCFG_SMT; ++ value = arg ? JH7110_PADCFG_SMT : 0; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ jh7110_padcfg_rmw(sfp, gpio, mask, value); ++ return 0; ++} ++ ++static int jh7110_gpio_add_pin_ranges(struct gpio_chip *gc) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ ++ sfp->gpios.name = sfp->gc.label; ++ sfp->gpios.base = sfp->gc.base; ++ sfp->gpios.pin_base = 0; ++ sfp->gpios.npins = sfp->gc.ngpio; ++ sfp->gpios.gc = &sfp->gc; ++ pinctrl_add_gpio_range(sfp->pctl, &sfp->gpios); ++ return 0; ++} ++ ++static void jh7110_irq_ack(struct irq_data *d) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d); ++ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg; ++ irq_hw_number_t gpio = irqd_to_hwirq(d); ++ void __iomem *ic = sfp->base + irq_reg->ic_reg_base ++ + 4 * (gpio / 32); ++ u32 mask = BIT(gpio % 32); ++ unsigned long flags; ++ u32 value; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ value = readl_relaxed(ic) & ~mask; ++ writel_relaxed(value, ic); ++ writel_relaxed(value | mask, ic); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static void jh7110_irq_mask(struct irq_data *d) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d); ++ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg; ++ irq_hw_number_t gpio = irqd_to_hwirq(d); ++ void __iomem *ie = sfp->base + irq_reg->ie_reg_base ++ + 4 * (gpio / 32); ++ u32 mask = BIT(gpio % 32); ++ unsigned long flags; ++ u32 value; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ value = readl_relaxed(ie) & ~mask; ++ writel_relaxed(value, ie); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++ ++ gpiochip_disable_irq(&sfp->gc, d->hwirq); ++} ++ ++static void jh7110_irq_mask_ack(struct irq_data *d) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d); ++ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg; ++ irq_hw_number_t gpio = irqd_to_hwirq(d); ++ void __iomem *ie = sfp->base + irq_reg->ie_reg_base ++ + 4 * (gpio / 32); ++ void __iomem *ic = sfp->base + irq_reg->ic_reg_base ++ + 4 * (gpio / 32); ++ u32 mask = BIT(gpio % 32); ++ unsigned long flags; ++ u32 value; ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ value = readl_relaxed(ie) & ~mask; ++ writel_relaxed(value, ie); ++ ++ value = readl_relaxed(ic) & ~mask; ++ writel_relaxed(value, ic); ++ writel_relaxed(value | mask, ic); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static void jh7110_irq_unmask(struct irq_data *d) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d); ++ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg; ++ irq_hw_number_t gpio = irqd_to_hwirq(d); ++ void __iomem *ie = sfp->base + irq_reg->ie_reg_base ++ + 4 * (gpio / 32); ++ u32 mask = BIT(gpio % 32); ++ unsigned long flags; ++ u32 value; ++ ++ gpiochip_enable_irq(&sfp->gc, d->hwirq); ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ value = readl_relaxed(ie) | mask; ++ writel_relaxed(value, ie); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++} ++ ++static int jh7110_irq_set_type(struct irq_data *d, unsigned int trigger) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d); ++ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg; ++ irq_hw_number_t gpio = irqd_to_hwirq(d); ++ void __iomem *base = sfp->base + 4 * (gpio / 32); ++ u32 mask = BIT(gpio % 32); ++ u32 irq_type, edge_both, polarity; ++ unsigned long flags; ++ ++ switch (trigger) { ++ case IRQ_TYPE_EDGE_RISING: ++ irq_type = mask; /* 1: edge triggered */ ++ edge_both = 0; /* 0: single edge */ ++ polarity = mask; /* 1: rising edge */ ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ irq_type = mask; /* 1: edge triggered */ ++ edge_both = 0; /* 0: single edge */ ++ polarity = 0; /* 0: falling edge */ ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ irq_type = mask; /* 1: edge triggered */ ++ edge_both = mask; /* 1: both edges */ ++ polarity = 0; /* 0: ignored */ ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ irq_type = 0; /* 0: level triggered */ ++ edge_both = 0; /* 0: ignored */ ++ polarity = mask; /* 1: high level */ ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ irq_type = 0; /* 0: level triggered */ ++ edge_both = 0; /* 0: ignored */ ++ polarity = 0; /* 0: low level */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (trigger & IRQ_TYPE_EDGE_BOTH) ++ irq_set_handler_locked(d, handle_edge_irq); ++ else ++ irq_set_handler_locked(d, handle_level_irq); ++ ++ raw_spin_lock_irqsave(&sfp->lock, flags); ++ irq_type |= readl_relaxed(base + irq_reg->is_reg_base) & ~mask; ++ writel_relaxed(irq_type, base + irq_reg->is_reg_base); ++ ++ edge_both |= readl_relaxed(base + irq_reg->ibe_reg_base) & ~mask; ++ writel_relaxed(edge_both, base + irq_reg->ibe_reg_base); ++ ++ polarity |= readl_relaxed(base + irq_reg->iev_reg_base) & ~mask; ++ writel_relaxed(polarity, base + irq_reg->iev_reg_base); ++ raw_spin_unlock_irqrestore(&sfp->lock, flags); ++ return 0; ++} ++ ++static struct irq_chip jh7110_irq_chip = { ++ .irq_ack = jh7110_irq_ack, ++ .irq_mask = jh7110_irq_mask, ++ .irq_mask_ack = jh7110_irq_mask_ack, ++ .irq_unmask = jh7110_irq_unmask, ++ .irq_set_type = jh7110_irq_set_type, ++ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED, ++ GPIOCHIP_IRQ_RESOURCE_HELPERS, ++}; ++ ++static void jh7110_disable_clock(void *data) ++{ ++ clk_disable_unprepare(data); ++} ++ ++int jh7110_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct jh7110_pinctrl_soc_info *info; ++ struct jh7110_pinctrl *sfp; ++ struct pinctrl_desc *jh7110_pinctrl_desc; ++ struct reset_control *rst; ++ struct clk *clk; ++ int ret; ++ ++ info = of_device_get_match_data(&pdev->dev); ++ if (!info) ++ return -ENODEV; ++ ++ if (!info->pins || !info->npins) { ++ dev_err(dev, "wrong pinctrl info\n"); ++ return -EINVAL; ++ } ++ ++ sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL); ++ if (!sfp) ++ return -ENOMEM; ++ ++ sfp->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(sfp->base)) ++ return PTR_ERR(sfp->base); ++ ++ clk = devm_clk_get_optional(dev, NULL); ++ if (IS_ERR(clk)) ++ return dev_err_probe(dev, PTR_ERR(clk), "could not get clock\n"); ++ ++ rst = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(rst)) ++ return dev_err_probe(dev, PTR_ERR(rst), "could not get reset\n"); ++ ++ /* ++ * we don't want to assert reset and risk undoing pin muxing for the ++ * early boot serial console, but let's make sure the reset line is ++ * deasserted in case someone runs a really minimal bootloader. ++ */ ++ ret = reset_control_deassert(rst); ++ if (ret) ++ return dev_err_probe(dev, ret, "could not deassert reset\n"); ++ ++ if (clk) { ++ ret = clk_prepare_enable(clk); ++ if (ret) ++ return dev_err_probe(dev, ret, "could not enable clock\n"); ++ ++ ret = devm_add_action_or_reset(dev, jh7110_disable_clock, clk); ++ if (ret) ++ return ret; ++ } ++ ++ jh7110_pinctrl_desc = devm_kzalloc(&pdev->dev, ++ sizeof(*jh7110_pinctrl_desc), ++ GFP_KERNEL); ++ if (!jh7110_pinctrl_desc) ++ return -ENOMEM; ++ ++ jh7110_pinctrl_desc->name = dev_name(dev); ++ jh7110_pinctrl_desc->pins = info->pins; ++ jh7110_pinctrl_desc->npins = info->npins; ++ jh7110_pinctrl_desc->pctlops = &jh7110_pinctrl_ops; ++ jh7110_pinctrl_desc->pmxops = &jh7110_pinmux_ops; ++ jh7110_pinctrl_desc->confops = &jh7110_pinconf_ops; ++ jh7110_pinctrl_desc->owner = THIS_MODULE; ++ ++ sfp->info = info; ++ sfp->dev = dev; ++ platform_set_drvdata(pdev, sfp); ++ sfp->gc.parent = dev; ++ raw_spin_lock_init(&sfp->lock); ++ mutex_init(&sfp->mutex); ++ ++ ret = devm_pinctrl_register_and_init(dev, ++ jh7110_pinctrl_desc, ++ sfp, &sfp->pctl); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "could not register pinctrl driver\n"); ++ ++ sfp->gc.label = dev_name(dev); ++ sfp->gc.owner = THIS_MODULE; ++ sfp->gc.request = jh7110_gpio_request; ++ sfp->gc.free = jh7110_gpio_free; ++ sfp->gc.get_direction = jh7110_gpio_get_direction; ++ sfp->gc.direction_input = jh7110_gpio_direction_input; ++ sfp->gc.direction_output = jh7110_gpio_direction_output; ++ sfp->gc.get = jh7110_gpio_get; ++ sfp->gc.set = jh7110_gpio_set; ++ sfp->gc.set_config = jh7110_gpio_set_config; ++ sfp->gc.add_pin_ranges = jh7110_gpio_add_pin_ranges; ++ sfp->gc.base = info->gc_base; ++ sfp->gc.ngpio = info->ngpios; ++ ++ jh7110_irq_chip.name = sfp->gc.label; ++ gpio_irq_chip_set_chip(&sfp->gc.irq, &jh7110_irq_chip); ++ sfp->gc.irq.parent_handler = info->jh7110_gpio_irq_handler; ++ sfp->gc.irq.num_parents = 1; ++ sfp->gc.irq.parents = devm_kcalloc(dev, sfp->gc.irq.num_parents, ++ sizeof(*sfp->gc.irq.parents), ++ GFP_KERNEL); ++ if (!sfp->gc.irq.parents) ++ return -ENOMEM; ++ sfp->gc.irq.default_type = IRQ_TYPE_NONE; ++ sfp->gc.irq.handler = handle_bad_irq; ++ sfp->gc.irq.init_hw = info->jh7110_gpio_init_hw; ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret < 0) ++ return ret; ++ sfp->gc.irq.parents[0] = ret; ++ ++ ret = devm_gpiochip_add_data(dev, &sfp->gc, sfp); ++ if (ret) ++ return dev_err_probe(dev, ret, "could not register gpiochip\n"); ++ ++ irq_domain_set_pm_device(sfp->gc.irq.domain, dev); ++ ++ dev_info(dev, "StarFive GPIO chip registered %d GPIOs\n", sfp->gc.ngpio); ++ ++ return pinctrl_enable(sfp->pctl); ++} ++EXPORT_SYMBOL_GPL(jh7110_pinctrl_probe); ++ ++MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC"); ++MODULE_AUTHOR("Emil Renner Berthing "); ++MODULE_AUTHOR("Jianlong Huang "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h +@@ -0,0 +1,70 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Pinctrl / GPIO driver for StarFive JH7110 SoC ++ * ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef __PINCTRL_STARFIVE_JH7110_H__ ++#define __PINCTRL_STARFIVE_JH7110_H__ ++ ++#include ++#include ++ ++struct jh7110_pinctrl { ++ struct device *dev; ++ struct gpio_chip gc; ++ struct pinctrl_gpio_range gpios; ++ raw_spinlock_t lock; ++ void __iomem *base; ++ struct pinctrl_dev *pctl; ++ /* register read/write mutex */ ++ struct mutex mutex; ++ const struct jh7110_pinctrl_soc_info *info; ++}; ++ ++struct jh7110_gpio_irq_reg { ++ unsigned int is_reg_base; ++ unsigned int ic_reg_base; ++ unsigned int ibe_reg_base; ++ unsigned int iev_reg_base; ++ unsigned int ie_reg_base; ++ unsigned int ris_reg_base; ++ unsigned int mis_reg_base; ++}; ++ ++struct jh7110_pinctrl_soc_info { ++ const struct pinctrl_pin_desc *pins; ++ unsigned int npins; ++ unsigned int ngpios; ++ unsigned int gc_base; ++ ++ /* gpio dout/doen/din/gpioinput register */ ++ unsigned int dout_reg_base; ++ unsigned int dout_mask; ++ unsigned int doen_reg_base; ++ unsigned int doen_mask; ++ unsigned int gpi_reg_base; ++ unsigned int gpi_mask; ++ unsigned int gpioin_reg_base; ++ ++ const struct jh7110_gpio_irq_reg *irq_reg; ++ ++ /* generic pinmux */ ++ int (*jh7110_set_one_pin_mux)(struct jh7110_pinctrl *sfp, ++ unsigned int pin, ++ unsigned int din, u32 dout, ++ u32 doen, u32 func); ++ /* gpio chip */ ++ int (*jh7110_get_padcfg_base)(struct jh7110_pinctrl *sfp, ++ unsigned int pin); ++ void (*jh7110_gpio_irq_handler)(struct irq_desc *desc); ++ int (*jh7110_gpio_init_hw)(struct gpio_chip *gc); ++}; ++ ++void jh7110_set_gpiomux(struct jh7110_pinctrl *sfp, unsigned int pin, ++ unsigned int din, u32 dout, u32 doen); ++int jh7110_pinctrl_probe(struct platform_device *pdev); ++struct jh7110_pinctrl *jh7110_from_irq_desc(struct irq_desc *desc); ++ ++#endif /* __PINCTRL_STARFIVE_JH7110_H__ */ diff --git a/target/linux/starfive/patches-6.1/0029-pinctrl-starfive-Add-StarFive-JH7110-aon-controller-.patch b/target/linux/starfive/patches-6.1/0029-pinctrl-starfive-Add-StarFive-JH7110-aon-controller-.patch new file mode 100644 index 0000000000..54e2c7c53b --- /dev/null +++ b/target/linux/starfive/patches-6.1/0029-pinctrl-starfive-Add-StarFive-JH7110-aon-controller-.patch @@ -0,0 +1,224 @@ +From 9c1a9d6dfd6a9c28794536c8af002746a20d840f Mon Sep 17 00:00:00 2001 +From: Jianlong Huang +Date: Thu, 9 Feb 2023 22:37:02 +0800 +Subject: [PATCH 029/122] pinctrl: starfive: Add StarFive JH7110 aon controller + driver + +Add pinctrl driver for StarFive JH7110 SoC aon pinctrl controller. + +Co-developed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Jianlong Huang +Signed-off-by: Hal Feng +--- + drivers/pinctrl/starfive/Kconfig | 12 ++ + drivers/pinctrl/starfive/Makefile | 1 + + .../starfive/pinctrl-starfive-jh7110-aon.c | 177 ++++++++++++++++++ + 3 files changed, 190 insertions(+) + create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c + +--- a/drivers/pinctrl/starfive/Kconfig ++++ b/drivers/pinctrl/starfive/Kconfig +@@ -37,3 +37,15 @@ config PINCTRL_STARFIVE_JH7110_SYS + This also provides an interface to the GPIO pins not used by other + peripherals supporting inputs, outputs, configuring pull-up/pull-down + and interrupts on input changes. ++ ++config PINCTRL_STARFIVE_JH7110_AON ++ tristate "Always-on pinctrl and GPIO driver for the StarFive JH7110 SoC" ++ depends on SOC_STARFIVE || COMPILE_TEST ++ depends on OF ++ select PINCTRL_STARFIVE_JH7110 ++ default SOC_STARFIVE ++ help ++ Say yes here to support always-on pin control on the StarFive JH7110 SoC. ++ This also provides an interface to the GPIO pins not used by other ++ peripherals supporting inputs, outputs, configuring pull-up/pull-down ++ and interrupts on input changes. +--- a/drivers/pinctrl/starfive/Makefile ++++ b/drivers/pinctrl/starfive/Makefile +@@ -4,3 +4,4 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7100) += + + obj-$(CONFIG_PINCTRL_STARFIVE_JH7110) += pinctrl-starfive-jh7110.o + obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_SYS) += pinctrl-starfive-jh7110-sys.o ++obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON) += pinctrl-starfive-jh7110-aon.o +--- /dev/null ++++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c +@@ -0,0 +1,177 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Pinctrl / GPIO driver for StarFive JH7110 SoC aon controller ++ * ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "../core.h" ++#include "../pinconf.h" ++#include "../pinmux.h" ++#include "pinctrl-starfive-jh7110.h" ++ ++#define JH7110_AON_NGPIO 4 ++#define JH7110_AON_GC_BASE 64 ++ ++/* registers */ ++#define JH7110_AON_DOEN 0x0 ++#define JH7110_AON_DOUT 0x4 ++#define JH7110_AON_GPI 0x8 ++#define JH7110_AON_GPIOIN 0x2c ++ ++#define JH7110_AON_GPIOEN 0xc ++#define JH7110_AON_GPIOIS 0x10 ++#define JH7110_AON_GPIOIC 0x14 ++#define JH7110_AON_GPIOIBE 0x18 ++#define JH7110_AON_GPIOIEV 0x1c ++#define JH7110_AON_GPIOIE 0x20 ++#define JH7110_AON_GPIORIS 0x28 ++#define JH7110_AON_GPIOMIS 0x28 ++ ++#define JH7110_AON_GPO_PDA_0_5_CFG 0x30 ++ ++static const struct pinctrl_pin_desc jh7110_aon_pins[] = { ++ PINCTRL_PIN(PAD_TESTEN, "TESTEN"), ++ PINCTRL_PIN(PAD_RGPIO0, "RGPIO0"), ++ PINCTRL_PIN(PAD_RGPIO1, "RGPIO1"), ++ PINCTRL_PIN(PAD_RGPIO2, "RGPIO2"), ++ PINCTRL_PIN(PAD_RGPIO3, "RGPIO3"), ++ PINCTRL_PIN(PAD_RSTN, "RSTN"), ++ PINCTRL_PIN(PAD_GMAC0_MDC, "GMAC0_MDC"), ++ PINCTRL_PIN(PAD_GMAC0_MDIO, "GMAC0_MDIO"), ++ PINCTRL_PIN(PAD_GMAC0_RXD0, "GMAC0_RXD0"), ++ PINCTRL_PIN(PAD_GMAC0_RXD1, "GMAC0_RXD1"), ++ PINCTRL_PIN(PAD_GMAC0_RXD2, "GMAC0_RXD2"), ++ PINCTRL_PIN(PAD_GMAC0_RXD3, "GMAC0_RXD3"), ++ PINCTRL_PIN(PAD_GMAC0_RXDV, "GMAC0_RXDV"), ++ PINCTRL_PIN(PAD_GMAC0_RXC, "GMAC0_RXC"), ++ PINCTRL_PIN(PAD_GMAC0_TXD0, "GMAC0_TXD0"), ++ PINCTRL_PIN(PAD_GMAC0_TXD1, "GMAC0_TXD1"), ++ PINCTRL_PIN(PAD_GMAC0_TXD2, "GMAC0_TXD2"), ++ PINCTRL_PIN(PAD_GMAC0_TXD3, "GMAC0_TXD3"), ++ PINCTRL_PIN(PAD_GMAC0_TXEN, "GMAC0_TXEN"), ++ PINCTRL_PIN(PAD_GMAC0_TXC, "GMAC0_TXC"), ++}; ++ ++static int jh7110_aon_set_one_pin_mux(struct jh7110_pinctrl *sfp, ++ unsigned int pin, ++ unsigned int din, u32 dout, ++ u32 doen, u32 func) ++{ ++ if (pin < sfp->gc.ngpio && func == 0) ++ jh7110_set_gpiomux(sfp, pin, din, dout, doen); ++ ++ return 0; ++} ++ ++static int jh7110_aon_get_padcfg_base(struct jh7110_pinctrl *sfp, ++ unsigned int pin) ++{ ++ if (pin < PAD_GMAC0_MDC) ++ return JH7110_AON_GPO_PDA_0_5_CFG; ++ ++ return -1; ++} ++ ++static void jh7110_aon_irq_handler(struct irq_desc *desc) ++{ ++ struct jh7110_pinctrl *sfp = jh7110_from_irq_desc(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned long mis; ++ unsigned int pin; ++ ++ chained_irq_enter(chip, desc); ++ ++ mis = readl_relaxed(sfp->base + JH7110_AON_GPIOMIS); ++ for_each_set_bit(pin, &mis, JH7110_AON_NGPIO) ++ generic_handle_domain_irq(sfp->gc.irq.domain, pin); ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static int jh7110_aon_init_hw(struct gpio_chip *gc) ++{ ++ struct jh7110_pinctrl *sfp = container_of(gc, ++ struct jh7110_pinctrl, gc); ++ ++ /* mask all GPIO interrupts */ ++ writel_relaxed(0, sfp->base + JH7110_AON_GPIOIE); ++ /* clear edge interrupt flags */ ++ writel_relaxed(0, sfp->base + JH7110_AON_GPIOIC); ++ writel_relaxed(0x0f, sfp->base + JH7110_AON_GPIOIC); ++ /* enable GPIO interrupts */ ++ writel_relaxed(1, sfp->base + JH7110_AON_GPIOEN); ++ return 0; ++} ++ ++static const struct jh7110_gpio_irq_reg jh7110_aon_irq_reg = { ++ .is_reg_base = JH7110_AON_GPIOIS, ++ .ic_reg_base = JH7110_AON_GPIOIC, ++ .ibe_reg_base = JH7110_AON_GPIOIBE, ++ .iev_reg_base = JH7110_AON_GPIOIEV, ++ .ie_reg_base = JH7110_AON_GPIOIE, ++ .ris_reg_base = JH7110_AON_GPIORIS, ++ .mis_reg_base = JH7110_AON_GPIOMIS, ++}; ++ ++static const struct jh7110_pinctrl_soc_info jh7110_aon_pinctrl_info = { ++ .pins = jh7110_aon_pins, ++ .npins = ARRAY_SIZE(jh7110_aon_pins), ++ .ngpios = JH7110_AON_NGPIO, ++ .gc_base = JH7110_AON_GC_BASE, ++ .dout_reg_base = JH7110_AON_DOUT, ++ .dout_mask = GENMASK(3, 0), ++ .doen_reg_base = JH7110_AON_DOEN, ++ .doen_mask = GENMASK(2, 0), ++ .gpi_reg_base = JH7110_AON_GPI, ++ .gpi_mask = GENMASK(3, 0), ++ .gpioin_reg_base = JH7110_AON_GPIOIN, ++ .irq_reg = &jh7110_aon_irq_reg, ++ .jh7110_set_one_pin_mux = jh7110_aon_set_one_pin_mux, ++ .jh7110_get_padcfg_base = jh7110_aon_get_padcfg_base, ++ .jh7110_gpio_irq_handler = jh7110_aon_irq_handler, ++ .jh7110_gpio_init_hw = jh7110_aon_init_hw, ++}; ++ ++static const struct of_device_id jh7110_aon_pinctrl_of_match[] = { ++ { ++ .compatible = "starfive,jh7110-aon-pinctrl", ++ .data = &jh7110_aon_pinctrl_info, ++ }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_aon_pinctrl_of_match); ++ ++static struct platform_driver jh7110_aon_pinctrl_driver = { ++ .probe = jh7110_pinctrl_probe, ++ .driver = { ++ .name = "starfive-jh7110-aon-pinctrl", ++ .of_match_table = jh7110_aon_pinctrl_of_match, ++ }, ++}; ++module_platform_driver(jh7110_aon_pinctrl_driver); ++ ++MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC aon controller"); ++MODULE_AUTHOR("Jianlong Huang "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0030-config-add-jh7110-defconfig-for-test-mini.patch b/target/linux/starfive/patches-6.1/0030-config-add-jh7110-defconfig-for-test-mini.patch new file mode 100644 index 0000000000..6c6afb853d --- /dev/null +++ b/target/linux/starfive/patches-6.1/0030-config-add-jh7110-defconfig-for-test-mini.patch @@ -0,0 +1,228 @@ +From 537ee9e5bb7b4ebee4ad5a607098c8200af6c261 Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Thu, 18 May 2023 19:27:28 -0700 +Subject: [PATCH 030/122] config: add jh7110 defconfig for test mini + +add jh7110 defconfig for test mini + +Signed-off-by: shanlong.li +--- + arch/riscv/configs/jh7110_defconfig | 212 ++++++++++++++++++++++++++++ + 1 file changed, 212 insertions(+) + create mode 100755 arch/riscv/configs/jh7110_defconfig + +--- /dev/null ++++ b/arch/riscv/configs/jh7110_defconfig +@@ -0,0 +1,212 @@ ++CONFIG_WERROR=y ++CONFIG_SYSVIPC=y ++# CONFIG_CROSS_MEMORY_ATTACH is not set ++CONFIG_NO_HZ_IDLE=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_PSI=y ++# CONFIG_CPU_ISOLATION is not set ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_CGROUPS=y ++CONFIG_CGROUP_SCHED=y ++CONFIG_CGROUP_PIDS=y ++CONFIG_CGROUP_CPUACCT=y ++CONFIG_NAMESPACES=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_RD_GZIP=y ++# CONFIG_RD_BZIP2 is not set ++# CONFIG_RD_LZMA is not set ++# CONFIG_RD_XZ is not set ++# CONFIG_RD_LZO is not set ++# CONFIG_RD_LZ4 is not set ++CONFIG_EXPERT=y ++# CONFIG_SYSFS_SYSCALL is not set ++CONFIG_KCMP=y ++CONFIG_PERF_EVENTS=y ++CONFIG_ARCH_STARFIVE=y ++CONFIG_SOC_STARFIVE=y ++CONFIG_ERRATA_SIFIVE=y ++CONFIG_SMP=y ++# CONFIG_RISCV_ISA_SVPBMT is not set ++# CONFIG_COMPAT is not set ++CONFIG_CPU_IDLE=y ++CONFIG_RISCV_SBI_CPUIDLE=y ++CONFIG_JUMP_LABEL=y ++# CONFIG_STACKPROTECTOR is not set ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODULE_COMPRESS_ZSTD=y ++# CONFIG_BLOCK_LEGACY_AUTOLOAD is not set ++CONFIG_BLK_WBT=y ++# CONFIG_BLK_DEBUG_FS is not set ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_MQ_IOSCHED_DEADLINE is not set ++# CONFIG_MQ_IOSCHED_KYBER is not set ++CONFIG_IOSCHED_BFQ=y ++CONFIG_KSM=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_INET_DIAG=m ++# CONFIG_IPV6_SIT is not set ++CONFIG_IPV6_MULTIPLE_TABLES=y ++# CONFIG_WIRELESS is not set ++# CONFIG_ETHTOOL_NETLINK is not set ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++# CONFIG_PREVENT_FIRMWARE_BUILD is not set ++# CONFIG_FW_LOADER is not set ++CONFIG_EFI_DISABLE_RUNTIME=y ++CONFIG_ZRAM=y ++CONFIG_ZRAM_MEMORY_TRACKING=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_LOOP_MIN_COUNT=1 ++CONFIG_NETDEVICES=y ++CONFIG_STMMAC_ETH=y ++CONFIG_DWMAC_DWC_QOS_ETH=y ++# CONFIG_DWMAC_GENERIC is not set ++CONFIG_DWMAC_STARFIVE=y ++CONFIG_MICROCHIP_PHY=y ++CONFIG_MOTORCOMM_PHY=y ++# CONFIG_WLAN is not set ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_SERIO is not set ++# CONFIG_VT is not set ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_LDISC_AUTOLOAD is not set ++CONFIG_SERIAL_8250=y ++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set ++# CONFIG_SERIAL_8250_16550A_VARIANTS is not set ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_DW=y ++CONFIG_SERIAL_OF_PLATFORM=y ++# CONFIG_DEVMEM is not set ++# CONFIG_RANDOM_TRUST_BOOTLOADER is not set ++CONFIG_I2C=y ++# CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_HELPER_AUTO is not set ++CONFIG_I2C_DESIGNWARE_PLATFORM=y ++# CONFIG_PTP_1588_CLOCK is not set ++CONFIG_PINCTRL_STARFIVE_JH7110=y ++CONFIG_GPIOLIB_FASTPATH_LIMIT=128 ++CONFIG_GPIO_SYSFS=y ++CONFIG_POWER_RESET=y ++CONFIG_POWER_RESET_GPIO_RESTART=y ++CONFIG_SENSORS_SFCTEMP=y ++# CONFIG_HID is not set ++CONFIG_MMC=y ++# CONFIG_PWRSEQ_EMMC is not set ++# CONFIG_PWRSEQ_SIMPLE is not set ++CONFIG_MMC_DW=y ++# CONFIG_VIRTIO_MENU is not set ++CONFIG_CLK_STARFIVE_JH7110_AON=y ++# CONFIG_VHOST_MENU is not set ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_BTRFS_FS=y ++CONFIG_BTRFS_FS_POSIX_ACL=y ++# CONFIG_DNOTIFY is not set ++CONFIG_FANOTIFY=y ++CONFIG_AUTOFS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-15" ++CONFIG_FAT_DEFAULT_UTF8=y ++CONFIG_PROC_KCORE=y ++CONFIG_PROC_CHILDREN=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_EFIVAR_FS=y ++# CONFIG_MISC_FILESYSTEMS is not set ++# CONFIG_NETWORK_FILESYSTEMS is not set ++CONFIG_NLS_DEFAULT="iso8859-15" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_15=y ++CONFIG_LSM="" ++CONFIG_CRYPTO_ZSTD=y ++# CONFIG_RAID6_PQ_BENCHMARK is not set ++# CONFIG_DEBUG_MISC is not set ++CONFIG_STRIP_ASM_SYMS=y ++CONFIG_DEBUG_SECTION_MISMATCH=y ++# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set ++CONFIG_DEBUG_FS=y ++# CONFIG_SLUB_DEBUG is not set ++CONFIG_PAGE_TABLE_CHECK=y ++CONFIG_DEBUG_RODATA_TEST=y ++CONFIG_DEBUG_WX=y ++CONFIG_SOFTLOCKUP_DETECTOR=y ++CONFIG_WQ_WATCHDOG=y ++# CONFIG_SCHED_DEBUG is not set ++CONFIG_STACKTRACE=y ++CONFIG_RCU_CPU_STALL_TIMEOUT=60 ++# CONFIG_RCU_TRACE is not set ++# CONFIG_FTRACE is not set ++# CONFIG_RUNTIME_TESTING_MENU is not set ++CONFIG_EXT4_FS=y ++CONFIG_CPUFREQ_DT_PLATDEV=y ++CONFIG_CPUFREQ_DT=y ++CONFIG_CPU_FREQ=y ++CONFIG_HIBERNATION=y ++CONFIG_ARCH_HIBERNATION_POSSIBLE=y ++CONFIG_SWAP=y ++CONFIG_PCIE_STARFIVE=y ++CONFIG_PCI_MSI=y ++CONFIG_PCI=y ++CONFIG_USB_CDNS3_STARFIVE=y ++CONFIG_PHY_STARFIVE_JH7110_PCIE=y ++CONFIG_PHY_STARFIVE_JH7110_USB=y ++CONFIG_USB_CDNS_SUPPORT=y ++CONFIG_USB_CDNS3=y ++CONFIG_USB=y ++CONFIG_USB_SUPPORT=y ++CONFIG_VIDEO_STARFIVE_CAMSS=y ++CONFIG_VIDEO_CADENCE_CSI2RX=y ++CONFIG_VIDEO_DEV=y ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_MEDIA_PLATFORM_DRIVERS=y ++CONFIG_MEDIA_PLATFORM_SUPPORT=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_PHY_STARFIVE_DPHY_RX=y ++CONFIG_CRYPTO_DEV_JH7110=y ++CONFIG_CRYPTO_HW=y ++CONFIG_CRYPTO=y ++CONFIG_SND_SOC_JH7110_TDM=y ++CONFIG_SND_SOC_STARFIVE=y ++CONFIG_SND_SOC=y ++CONFIG_SND=y ++CONFIG_SOUND=y ++CONFIG_DW_AXI_DMAC=y ++CONFIG_DMADEVICES=y ++CONFIG_HAS_IOMEM=y ++CONFIG_PWM_STARFIVE_PTC=y ++CONFIG_PWM=y ++CONFIG_STARFIVE_TIMER=y ++CONFIG_SECTION_MISMATCH_WARN_ONLY=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_STARFIVE_WATCHDOG=y ++CONFIG_WATCHDOG=y ++CONFIG_HW_RANDOM_JH7110=y ++CONFIG_HW_RANDOM=y ++CONFIG_STMMAC_PLATFORM=y ++CONFIG_SPI_CADENCE_QUADSPI=y ++CONFIG_SPI_MASTER=y ++CONFIG_SPI=y ++CONFIG_MMC_DW_STARFIVE=y ++CONFIG_CLK_STARFIVE_JH7110_PLL=y ++CONFIG_CLK_STARFIVE_JH7110_VOUT=y ++CONFIG_CLK_STARFIVE_JH7110_ISP=y ++CONFIG_CLK_STARFIVE_JH7110_STG=y ++CONFIG_JH71XX_PMU=y ++CONFIG_PM=y ++CONFIG_PINCTRL_STARFIVE_JH7110_AON=y ++CONFIG_PINCTRL_STARFIVE_JH7110_SYS=y ++CONFIG_CLK_STARFIVE_JH7110_AON=y ++CONFIG_CLK_STARFIVE_JH7110_SYS=y ++CONFIG_SIFIVE_CCACHE=y ++CONFIG_CLINT_TIMER=y ++CONFIG_SIFIVE_PLIC=y diff --git a/target/linux/starfive/patches-6.1/0031-dt-bindings-clock-Add-StarFive-JH7110-PLL-clock-gene.patch b/target/linux/starfive/patches-6.1/0031-dt-bindings-clock-Add-StarFive-JH7110-PLL-clock-gene.patch new file mode 100644 index 0000000000..74eb4b2f18 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0031-dt-bindings-clock-Add-StarFive-JH7110-PLL-clock-gene.patch @@ -0,0 +1,80 @@ +From 07f62b08668c0295b1c6342f9708b7e36093ff59 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Tue, 21 Feb 2023 17:13:48 +0800 +Subject: [PATCH 031/122] dt-bindings: clock: Add StarFive JH7110 PLL clock + generator + +Add bindings for the PLL clock generator on the JH7110 RISC-V SoC. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Xingyu Wu +--- + .../bindings/clock/starfive,jh7110-pll.yaml | 46 +++++++++++++++++++ + .../dt-bindings/clock/starfive,jh7110-crg.h | 6 +++ + 2 files changed, 52 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml +@@ -0,0 +1,46 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/starfive,jh7110-pll.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 PLL Clock Generator ++ ++description: ++ This PLL are high speed, low jitter frequency synthesizers in JH7110. ++ Each PLL clocks work in integer mode or fraction mode by some dividers, ++ and the configuration registers and dividers are set in several syscon ++ registers. So pll node should be a child of SYS-SYSCON node. ++ The formula for calculating frequency is that, ++ Fvco = Fref * (NI + NF) / M / Q1 ++ ++maintainers: ++ - Xingyu Wu ++ ++properties: ++ compatible: ++ const: starfive,jh7110-pll ++ ++ clocks: ++ maxItems: 1 ++ description: Main Oscillator (24 MHz) ++ ++ '#clock-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++required: ++ - compatible ++ - clocks ++ - '#clock-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pll-clock-controller { ++ compatible = "starfive,jh7110-pll"; ++ clocks = <&osc>; ++ #clock-cells = <1>; ++ }; +--- a/include/dt-bindings/clock/starfive,jh7110-crg.h ++++ b/include/dt-bindings/clock/starfive,jh7110-crg.h +@@ -6,6 +6,12 @@ + #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ + #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ + ++/* PLL clocks */ ++#define JH7110_CLK_PLL0_OUT 0 ++#define JH7110_CLK_PLL1_OUT 1 ++#define JH7110_CLK_PLL2_OUT 2 ++#define JH7110_PLLCLK_END 3 ++ + /* SYSCRG clocks */ + #define JH7110_SYSCLK_CPU_ROOT 0 + #define JH7110_SYSCLK_CPU_CORE 1 diff --git a/target/linux/starfive/patches-6.1/0032-clk-starfive-Add-StarFive-JH7110-PLL-clock-driver.patch b/target/linux/starfive/patches-6.1/0032-clk-starfive-Add-StarFive-JH7110-PLL-clock-driver.patch new file mode 100644 index 0000000000..711e0775cc --- /dev/null +++ b/target/linux/starfive/patches-6.1/0032-clk-starfive-Add-StarFive-JH7110-PLL-clock-driver.patch @@ -0,0 +1,786 @@ +From 0bc7aa28dcdee75a52b1874a02dfbf0107c2d448 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Fri, 17 Feb 2023 17:30:09 +0800 +Subject: [PATCH 032/122] clk: starfive: Add StarFive JH7110 PLL clock driver + +Add driver for the StarFive JH7110 PLL clock controller +and they work by reading and setting syscon registers. + +Signed-off-by: Xingyu Wu +--- + MAINTAINERS | 6 + + drivers/clk/starfive/Kconfig | 8 + + drivers/clk/starfive/Makefile | 1 + + .../clk/starfive/clk-starfive-jh7110-pll.c | 427 ++++++++++++++++++ + .../clk/starfive/clk-starfive-jh7110-pll.h | 293 ++++++++++++ + 5 files changed, 735 insertions(+) + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19650,6 +19650,12 @@ M: Emil Renner Berthing ++S: Supported ++F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml ++F: drivers/clk/starfive/clk-starfive-jh7110-pll.* ++ + STARFIVE JH71X0 CLOCK DRIVERS + M: Emil Renner Berthing + M: Hal Feng +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO + Say Y or M here to support the audio clocks on the StarFive JH7100 + SoC. + ++config CLK_STARFIVE_JH7110_PLL ++ bool "StarFive JH7110 PLL clock support" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ default ARCH_STARFIVE ++ help ++ Say yes here to support the PLL clock controller on the ++ StarFive JH7110 SoC. ++ + config CLK_STARFIVE_JH7110_SYS + bool "StarFive JH7110 system clock support" + depends on ARCH_STARFIVE || COMPILE_TEST +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk + obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o + obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o + ++obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7110 PLL Clock Generator Driver ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * ++ * This driver is about to register JH7110 PLL clock generator and support ops. ++ * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2. ++ * Each PLL clocks work in integer mode or fraction mode by some dividers, ++ * and the configuration registers and dividers are set in several syscon registers. ++ * The formula for calculating frequency is: ++ * Fvco = Fref * (NI + NF) / M / Q1 ++ * Fref: OSC source clock rate ++ * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0]. ++ * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999. ++ * M: frequency dividing ratio of pre-divider, set by prediv[5:0]. ++ * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-starfive-jh7110-pll.h" ++ ++static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw) ++{ ++ return container_of(hw, struct jh7110_clk_pll_data, hw); ++} ++ ++static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data) ++{ ++ return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]); ++} ++ ++/* Read register value from syscon and calculate PLL(x) frequency */ ++static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data, ++ unsigned long parent_rate) ++{ ++ struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data); ++ struct jh7110_pll_syscon_offset *offset = &data->offset; ++ struct jh7110_pll_syscon_mask *mask = &data->mask; ++ struct jh7110_pll_syscon_shift *shift = &data->shift; ++ unsigned long freq = 0; ++ unsigned long frac_cal; ++ u32 dacpd; ++ u32 dsmpd; ++ u32 fbdiv; ++ u32 prediv; ++ u32 postdiv1; ++ u32 frac; ++ u32 reg_val; ++ ++ if (regmap_read(priv->syscon_regmap, offset->dacpd, ®_val)) ++ goto read_error; ++ dacpd = (reg_val & mask->dacpd) >> shift->dacpd; ++ ++ if (regmap_read(priv->syscon_regmap, offset->dsmpd, ®_val)) ++ goto read_error; ++ dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd; ++ ++ if (regmap_read(priv->syscon_regmap, offset->fbdiv, ®_val)) ++ goto read_error; ++ fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv; ++ /* fbdiv value should be 8 to 4095 */ ++ if (fbdiv < 8) ++ goto read_error; ++ ++ if (regmap_read(priv->syscon_regmap, offset->prediv, ®_val)) ++ goto read_error; ++ prediv = (reg_val & mask->prediv) >> shift->prediv; ++ ++ if (regmap_read(priv->syscon_regmap, offset->postdiv1, ®_val)) ++ goto read_error; ++ /* postdiv1 = 2 ^ reg_val */ ++ postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1); ++ ++ if (regmap_read(priv->syscon_regmap, offset->frac, ®_val)) ++ goto read_error; ++ frac = (reg_val & mask->frac) >> shift->frac; ++ ++ /* ++ * Integer Mode (Both 1) or Fraction Mode (Both 0). ++ * And the decimal places are counted by expanding them by ++ * a factor of STARFIVE_PLL_FRAC_PATR_SIZE. ++ */ ++ if (dacpd == 1 && dsmpd == 1) ++ frac_cal = 0; ++ else if (dacpd == 0 && dsmpd == 0) ++ frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24); ++ else ++ goto read_error; ++ ++ /* Fvco = Fref * (NI + NF) / M / Q1 */ ++ freq = parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE * ++ (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1; ++ ++read_error: ++ return freq; ++} ++ ++static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2) ++{ ++ return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1); ++} ++ ++/* Select the appropriate frequency from the already configured registers value */ ++static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data, ++ unsigned long rate) ++{ ++ const struct starfive_pll_syscon_value *syscon_val; ++ unsigned int id; ++ unsigned int pll_arry_size; ++ unsigned long rate_diff; ++ ++ if (data->idx == JH7110_CLK_PLL0_OUT) ++ pll_arry_size = ARRAY_SIZE(jh7110_pll0_syscon_freq); ++ else if (data->idx == JH7110_CLK_PLL1_OUT) ++ pll_arry_size = ARRAY_SIZE(jh7110_pll1_syscon_freq); ++ else ++ pll_arry_size = ARRAY_SIZE(jh7110_pll2_syscon_freq); ++ ++ /* compare the frequency one by one from small to large in order */ ++ for (id = 0; id < pll_arry_size; id++) { ++ if (data->idx == JH7110_CLK_PLL0_OUT) ++ syscon_val = &jh7110_pll0_syscon_freq[id]; ++ else if (data->idx == JH7110_CLK_PLL1_OUT) ++ syscon_val = &jh7110_pll1_syscon_freq[id]; ++ else ++ syscon_val = &jh7110_pll2_syscon_freq[id]; ++ ++ if (rate == syscon_val->freq) ++ goto match_end; ++ ++ /* select near frequency */ ++ if (rate < syscon_val->freq) { ++ /* The last frequency is closer to the target rate than this time. */ ++ if (id > 0) ++ if (rate_diff < jh7110_pll_rate_sub_fabs(rate, syscon_val->freq)) ++ id--; ++ ++ goto match_end; ++ } else { ++ rate_diff = jh7110_pll_rate_sub_fabs(rate, syscon_val->freq); ++ } ++ } ++ ++match_end: ++ data->freq_select_idx = id; ++} ++ ++static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data) ++{ ++ struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data); ++ struct jh7110_pll_syscon_offset *offset = &data->offset; ++ struct jh7110_pll_syscon_mask *mask = &data->mask; ++ struct jh7110_pll_syscon_shift *shift = &data->shift; ++ unsigned int freq_idx = data->freq_select_idx; ++ const struct starfive_pll_syscon_value *syscon_val; ++ int ret; ++ ++ if (data->idx == JH7110_CLK_PLL0_OUT) ++ syscon_val = &jh7110_pll0_syscon_freq[freq_idx]; ++ else if (data->idx == JH7110_CLK_PLL1_OUT) ++ syscon_val = &jh7110_pll1_syscon_freq[freq_idx]; ++ else ++ syscon_val = &jh7110_pll2_syscon_freq[freq_idx]; ++ ++ ret = regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd, ++ (syscon_val->dacpd << shift->dacpd)); ++ if (ret) ++ goto set_failed; ++ ++ ret = regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd, ++ (syscon_val->dsmpd << shift->dsmpd)); ++ if (ret) ++ goto set_failed; ++ ++ ret = regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv, ++ (syscon_val->prediv << shift->prediv)); ++ if (ret) ++ goto set_failed; ++ ++ ret = regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv, ++ (syscon_val->fbdiv << shift->fbdiv)); ++ if (ret) ++ goto set_failed; ++ ++ ret = regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1, ++ ((syscon_val->postdiv1 >> 1) << shift->postdiv1)); ++ if (ret) ++ goto set_failed; ++ ++ /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */ ++ if (syscon_val->dacpd == 0 && syscon_val->dsmpd == 0) ++ ret = regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac, ++ (syscon_val->frac << shift->frac)); ++ else if (syscon_val->dacpd != syscon_val->dsmpd) ++ ret = -EINVAL; ++ ++set_failed: ++ return ret; ++} ++ ++static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw); ++ ++ return jh7110_pll_get_freq(data, parent_rate); ++} ++ ++static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) ++{ ++ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw); ++ ++ jh7110_pll_select_near_freq_id(data, req->rate); ++ ++ if (data->idx == JH7110_CLK_PLL0_OUT) ++ req->rate = jh7110_pll0_syscon_freq[data->freq_select_idx].freq; ++ else if (data->idx == JH7110_CLK_PLL1_OUT) ++ req->rate = jh7110_pll1_syscon_freq[data->freq_select_idx].freq; ++ else ++ req->rate = jh7110_pll2_syscon_freq[data->freq_select_idx].freq; ++ ++ return 0; ++} ++ ++static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw); ++ ++ return jh7110_pll_set_freq_syscon(data); ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ static const struct debugfs_reg32 jh7110_clk_pll_reg = { ++ .name = "CTRL", ++ .offset = 0, ++ }; ++ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw); ++ struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data); ++ struct debugfs_regset32 *regset; ++ ++ regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); ++ if (!regset) ++ return; ++ ++ regset->regs = &jh7110_clk_pll_reg; ++ regset->nregs = 1; ++ ++ debugfs_create_regset32("registers", 0400, dentry, regset); ++} ++#else ++#define jh7110_pll_debug_init NULL ++#endif ++ ++static const struct clk_ops jh7110_pll_ops = { ++ .recalc_rate = jh7110_pll_recalc_rate, ++ .determine_rate = jh7110_pll_determine_rate, ++ .set_rate = jh7110_pll_set_rate, ++ .debug_init = jh7110_pll_debug_init, ++}; ++ ++/* get offset, mask and shift of PLL(x) syscon */ ++static int jh7110_pll_data_get(struct jh7110_clk_pll_data *data, int index) ++{ ++ struct jh7110_pll_syscon_offset *offset = &data->offset; ++ struct jh7110_pll_syscon_mask *mask = &data->mask; ++ struct jh7110_pll_syscon_shift *shift = &data->shift; ++ ++ if (index == JH7110_CLK_PLL0_OUT) { ++ offset->dacpd = STARFIVE_JH7110_PLL0_DACPD_OFFSET; ++ offset->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_OFFSET; ++ offset->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_OFFSET; ++ offset->frac = STARFIVE_JH7110_PLL0_FRAC_OFFSET; ++ offset->prediv = STARFIVE_JH7110_PLL0_PREDIV_OFFSET; ++ offset->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET; ++ ++ mask->dacpd = STARFIVE_JH7110_PLL0_DACPD_MASK; ++ mask->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_MASK; ++ mask->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_MASK; ++ mask->frac = STARFIVE_JH7110_PLL0_FRAC_MASK; ++ mask->prediv = STARFIVE_JH7110_PLL0_PREDIV_MASK; ++ mask->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_MASK; ++ ++ shift->dacpd = STARFIVE_JH7110_PLL0_DACPD_SHIFT; ++ shift->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_SHIFT; ++ shift->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_SHIFT; ++ shift->frac = STARFIVE_JH7110_PLL0_FRAC_SHIFT; ++ shift->prediv = STARFIVE_JH7110_PLL0_PREDIV_SHIFT; ++ shift->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT; ++ ++ } else if (index == JH7110_CLK_PLL1_OUT) { ++ offset->dacpd = STARFIVE_JH7110_PLL1_DACPD_OFFSET; ++ offset->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_OFFSET; ++ offset->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_OFFSET; ++ offset->frac = STARFIVE_JH7110_PLL1_FRAC_OFFSET; ++ offset->prediv = STARFIVE_JH7110_PLL1_PREDIV_OFFSET; ++ offset->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET; ++ ++ mask->dacpd = STARFIVE_JH7110_PLL1_DACPD_MASK; ++ mask->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_MASK; ++ mask->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_MASK; ++ mask->frac = STARFIVE_JH7110_PLL1_FRAC_MASK; ++ mask->prediv = STARFIVE_JH7110_PLL1_PREDIV_MASK; ++ mask->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_MASK; ++ ++ shift->dacpd = STARFIVE_JH7110_PLL1_DACPD_SHIFT; ++ shift->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_SHIFT; ++ shift->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_SHIFT; ++ shift->frac = STARFIVE_JH7110_PLL1_FRAC_SHIFT; ++ shift->prediv = STARFIVE_JH7110_PLL1_PREDIV_SHIFT; ++ shift->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT; ++ ++ } else if (index == JH7110_CLK_PLL2_OUT) { ++ offset->dacpd = STARFIVE_JH7110_PLL2_DACPD_OFFSET; ++ offset->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_OFFSET; ++ offset->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_OFFSET; ++ offset->frac = STARFIVE_JH7110_PLL2_FRAC_OFFSET; ++ offset->prediv = STARFIVE_JH7110_PLL2_PREDIV_OFFSET; ++ offset->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET; ++ ++ mask->dacpd = STARFIVE_JH7110_PLL2_DACPD_MASK; ++ mask->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_MASK; ++ mask->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_MASK; ++ mask->frac = STARFIVE_JH7110_PLL2_FRAC_MASK; ++ mask->prediv = STARFIVE_JH7110_PLL2_PREDIV_MASK; ++ mask->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_MASK; ++ ++ shift->dacpd = STARFIVE_JH7110_PLL2_DACPD_SHIFT; ++ shift->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_SHIFT; ++ shift->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_SHIFT; ++ shift->frac = STARFIVE_JH7110_PLL2_FRAC_SHIFT; ++ shift->prediv = STARFIVE_JH7110_PLL2_PREDIV_SHIFT; ++ shift->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT; ++ ++ } else { ++ return -ENOENT; ++ } ++ ++ return 0; ++} ++ ++static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data) ++{ ++ struct jh7110_clk_pll_priv *priv = data; ++ unsigned int idx = clkspec->args[0]; ++ ++ if (idx < JH7110_PLLCLK_END) ++ return &priv->data[idx].hw; ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++static int jh7110_pll_probe(struct platform_device *pdev) ++{ ++ const char *pll_name[JH7110_PLLCLK_END] = { ++ "pll0_out", ++ "pll1_out", ++ "pll2_out" ++ }; ++ struct jh7110_clk_pll_priv *priv; ++ struct jh7110_clk_pll_data *data; ++ int ret; ++ unsigned int idx; ++ ++ priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, JH7110_PLLCLK_END), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = &pdev->dev; ++ priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent); ++ if (IS_ERR(priv->syscon_regmap)) ++ return PTR_ERR(priv->syscon_regmap); ++ ++ for (idx = 0; idx < JH7110_PLLCLK_END; idx++) { ++ struct clk_parent_data parents = { ++ .index = 0, ++ }; ++ struct clk_init_data init = { ++ .name = pll_name[idx], ++ .ops = &jh7110_pll_ops, ++ .parent_data = &parents, ++ .num_parents = 1, ++ .flags = 0, ++ }; ++ ++ data = &priv->data[idx]; ++ ++ ret = jh7110_pll_data_get(data, idx); ++ if (ret) ++ return ret; ++ ++ data->hw.init = &init; ++ data->idx = idx; ++ ++ ret = devm_clk_hw_register(&pdev->dev, &data->hw); ++ if (ret) ++ return ret; ++ } ++ ++ return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv); ++} ++ ++static const struct of_device_id jh7110_pll_match[] = { ++ { .compatible = "starfive,jh7110-pll" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_pll_match); ++ ++static struct platform_driver jh7110_pll_driver = { ++ .driver = { ++ .name = "clk-starfive-jh7110-pll", ++ .of_match_table = jh7110_pll_match, ++ }, ++}; ++builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe); +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h +@@ -0,0 +1,293 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * StarFive JH7110 PLL Clock Generator Driver ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef _CLK_STARFIVE_JH7110_PLL_H_ ++#define _CLK_STARFIVE_JH7110_PLL_H_ ++ ++#include ++ ++/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */ ++#define STARFIVE_PLL_FRAC_PATR_SIZE 1000 ++ ++#define STARFIVE_JH7110_PLL0_DACPD_OFFSET 0x18 ++#define STARFIVE_JH7110_PLL0_DACPD_SHIFT 24 ++#define STARFIVE_JH7110_PLL0_DACPD_MASK BIT(24) ++#define STARFIVE_JH7110_PLL0_DSMPD_OFFSET 0x18 ++#define STARFIVE_JH7110_PLL0_DSMPD_SHIFT 25 ++#define STARFIVE_JH7110_PLL0_DSMPD_MASK BIT(25) ++#define STARFIVE_JH7110_PLL0_FBDIV_OFFSET 0x1c ++#define STARFIVE_JH7110_PLL0_FBDIV_SHIFT 0 ++#define STARFIVE_JH7110_PLL0_FBDIV_MASK GENMASK(11, 0) ++#define STARFIVE_JH7110_PLL0_FRAC_OFFSET 0x20 ++#define STARFIVE_JH7110_PLL0_FRAC_SHIFT 0 ++#define STARFIVE_JH7110_PLL0_FRAC_MASK GENMASK(23, 0) ++#define STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET 0x20 ++#define STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT 28 ++#define STARFIVE_JH7110_PLL0_POSTDIV1_MASK GENMASK(29, 28) ++#define STARFIVE_JH7110_PLL0_PREDIV_OFFSET 0x24 ++#define STARFIVE_JH7110_PLL0_PREDIV_SHIFT 0 ++#define STARFIVE_JH7110_PLL0_PREDIV_MASK GENMASK(5, 0) ++ ++#define STARFIVE_JH7110_PLL1_DACPD_OFFSET 0x24 ++#define STARFIVE_JH7110_PLL1_DACPD_SHIFT 15 ++#define STARFIVE_JH7110_PLL1_DACPD_MASK BIT(15) ++#define STARFIVE_JH7110_PLL1_DSMPD_OFFSET 0x24 ++#define STARFIVE_JH7110_PLL1_DSMPD_SHIFT 16 ++#define STARFIVE_JH7110_PLL1_DSMPD_MASK BIT(16) ++#define STARFIVE_JH7110_PLL1_FBDIV_OFFSET 0x24 ++#define STARFIVE_JH7110_PLL1_FBDIV_SHIFT 17 ++#define STARFIVE_JH7110_PLL1_FBDIV_MASK GENMASK(28, 17) ++#define STARFIVE_JH7110_PLL1_FRAC_OFFSET 0x28 ++#define STARFIVE_JH7110_PLL1_FRAC_SHIFT 0 ++#define STARFIVE_JH7110_PLL1_FRAC_MASK GENMASK(23, 0) ++#define STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET 0x28 ++#define STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT 28 ++#define STARFIVE_JH7110_PLL1_POSTDIV1_MASK GENMASK(29, 28) ++#define STARFIVE_JH7110_PLL1_PREDIV_OFFSET 0x2c ++#define STARFIVE_JH7110_PLL1_PREDIV_SHIFT 0 ++#define STARFIVE_JH7110_PLL1_PREDIV_MASK GENMASK(5, 0) ++ ++#define STARFIVE_JH7110_PLL2_DACPD_OFFSET 0x2c ++#define STARFIVE_JH7110_PLL2_DACPD_SHIFT 15 ++#define STARFIVE_JH7110_PLL2_DACPD_MASK BIT(15) ++#define STARFIVE_JH7110_PLL2_DSMPD_OFFSET 0x2c ++#define STARFIVE_JH7110_PLL2_DSMPD_SHIFT 16 ++#define STARFIVE_JH7110_PLL2_DSMPD_MASK BIT(16) ++#define STARFIVE_JH7110_PLL2_FBDIV_OFFSET 0x2c ++#define STARFIVE_JH7110_PLL2_FBDIV_SHIFT 17 ++#define STARFIVE_JH7110_PLL2_FBDIV_MASK GENMASK(28, 17) ++#define STARFIVE_JH7110_PLL2_FRAC_OFFSET 0x30 ++#define STARFIVE_JH7110_PLL2_FRAC_SHIFT 0 ++#define STARFIVE_JH7110_PLL2_FRAC_MASK GENMASK(23, 0) ++#define STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET 0x30 ++#define STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT 28 ++#define STARFIVE_JH7110_PLL2_POSTDIV1_MASK GENMASK(29, 28) ++#define STARFIVE_JH7110_PLL2_PREDIV_OFFSET 0x34 ++#define STARFIVE_JH7110_PLL2_PREDIV_SHIFT 0 ++#define STARFIVE_JH7110_PLL2_PREDIV_MASK GENMASK(5, 0) ++ ++struct jh7110_pll_syscon_offset { ++ unsigned int dacpd; ++ unsigned int dsmpd; ++ unsigned int fbdiv; ++ unsigned int frac; ++ unsigned int prediv; ++ unsigned int postdiv1; ++}; ++ ++struct jh7110_pll_syscon_mask { ++ u32 dacpd; ++ u32 dsmpd; ++ u32 fbdiv; ++ u32 frac; ++ u32 prediv; ++ u32 postdiv1; ++}; ++ ++struct jh7110_pll_syscon_shift { ++ char dacpd; ++ char dsmpd; ++ char fbdiv; ++ char frac; ++ char prediv; ++ char postdiv1; ++}; ++ ++struct jh7110_clk_pll_data { ++ struct clk_hw hw; ++ unsigned int idx; ++ unsigned int freq_select_idx; ++ ++ struct jh7110_pll_syscon_offset offset; ++ struct jh7110_pll_syscon_mask mask; ++ struct jh7110_pll_syscon_shift shift; ++}; ++ ++struct jh7110_clk_pll_priv { ++ struct device *dev; ++ struct regmap *syscon_regmap; ++ struct jh7110_clk_pll_data data[]; ++}; ++ ++struct starfive_pll_syscon_value { ++ unsigned long freq; ++ u32 prediv; ++ u32 fbdiv; ++ u32 postdiv1; ++/* Both daxpd and dsmpd set 1 while integer mode */ ++/* Both daxpd and dsmpd set 0 while fraction mode */ ++ u32 dacpd; ++ u32 dsmpd; ++/* frac value should be decimals multiplied by 2^24 */ ++ u32 frac; ++}; ++ ++enum starfive_pll0_freq_index { ++ PLL0_FREQ_375 = 0, ++ PLL0_FREQ_500, ++ PLL0_FREQ_625, ++ PLL0_FREQ_750, ++ PLL0_FREQ_875, ++ PLL0_FREQ_1000, ++ PLL0_FREQ_1250, ++ PLL0_FREQ_1375, ++ PLL0_FREQ_1500, ++ PLL0_FREQ_MAX ++}; ++ ++enum starfive_pll1_freq_index { ++ PLL1_FREQ_1066 = 0, ++ PLL1_FREQ_1200, ++ PLL1_FREQ_1400, ++ PLL1_FREQ_1600, ++ PLL1_FREQ_MAX ++}; ++ ++enum starfive_pll2_freq_index { ++ PLL2_FREQ_1188 = 0, ++ PLL2_FREQ_12288, ++ PLL2_FREQ_MAX ++}; ++ ++/* ++ * Because the pll frequency is relatively fixed, ++ * it cannot be set arbitrarily, so it needs a specific configuration. ++ * PLL0 frequency should be multiple of 125MHz (USB frequency). ++ */ ++static const struct starfive_pll_syscon_value ++ jh7110_pll0_syscon_freq[PLL0_FREQ_MAX] = { ++ [PLL0_FREQ_375] = { ++ .freq = 375000000, ++ .prediv = 8, ++ .fbdiv = 125, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_500] = { ++ .freq = 500000000, ++ .prediv = 6, ++ .fbdiv = 125, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_625] = { ++ .freq = 625000000, ++ .prediv = 24, ++ .fbdiv = 625, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_750] = { ++ .freq = 750000000, ++ .prediv = 4, ++ .fbdiv = 125, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_875] = { ++ .freq = 875000000, ++ .prediv = 24, ++ .fbdiv = 875, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_1000] = { ++ .freq = 1000000000, ++ .prediv = 3, ++ .fbdiv = 125, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_1250] = { ++ .freq = 1250000000, ++ .prediv = 12, ++ .fbdiv = 625, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_1375] = { ++ .freq = 1375000000, ++ .prediv = 24, ++ .fbdiv = 1375, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL0_FREQ_1500] = { ++ .freq = 1500000000, ++ .prediv = 2, ++ .fbdiv = 125, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++}; ++ ++static const struct starfive_pll_syscon_value ++ jh7110_pll1_syscon_freq[PLL1_FREQ_MAX] = { ++ [PLL1_FREQ_1066] = { ++ .freq = 1066000000, ++ .prediv = 12, ++ .fbdiv = 533, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL1_FREQ_1200] = { ++ .freq = 1200000000, ++ .prediv = 1, ++ .fbdiv = 50, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL1_FREQ_1400] = { ++ .freq = 1400000000, ++ .prediv = 6, ++ .fbdiv = 350, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL1_FREQ_1600] = { ++ .freq = 1600000000, ++ .prediv = 3, ++ .fbdiv = 200, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++}; ++ ++static const struct starfive_pll_syscon_value ++ jh7110_pll2_syscon_freq[PLL2_FREQ_MAX] = { ++ [PLL2_FREQ_1188] = { ++ .freq = 1188000000, ++ .prediv = 2, ++ .fbdiv = 99, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++ [PLL2_FREQ_12288] = { ++ .freq = 1228800000, ++ .prediv = 5, ++ .fbdiv = 256, ++ .postdiv1 = 1, ++ .dacpd = 1, ++ .dsmpd = 1, ++ }, ++}; ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0033-dt-bindings-clock-jh7110-syscrg-Add-PLL-clock-inputs.patch b/target/linux/starfive/patches-6.1/0033-dt-bindings-clock-jh7110-syscrg-Add-PLL-clock-inputs.patch new file mode 100644 index 0000000000..4fd78cd5bb --- /dev/null +++ b/target/linux/starfive/patches-6.1/0033-dt-bindings-clock-jh7110-syscrg-Add-PLL-clock-inputs.patch @@ -0,0 +1,75 @@ +From 1f788a0a5092b1e1cfd02aa7f31ceb551befa7e6 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Tue, 14 Mar 2023 16:43:50 +0800 +Subject: [PATCH 033/122] dt-bindings: clock: jh7110-syscrg: Add PLL clock + inputs + +Add PLL clock inputs from PLL clock generator. + +Acked-by: Krzysztof Kozlowski +Signed-off-by: Xingyu Wu +--- + .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml +@@ -27,6 +27,9 @@ properties: + - description: External I2S RX left/right channel clock + - description: External TDM clock + - description: External audio master clock ++ - description: PLL0 ++ - description: PLL1 ++ - description: PLL2 + + - items: + - description: Main Oscillator (24 MHz) +@@ -38,6 +41,9 @@ properties: + - description: External I2S RX left/right channel clock + - description: External TDM clock + - description: External audio master clock ++ - description: PLL0 ++ - description: PLL1 ++ - description: PLL2 + + clock-names: + oneOf: +@@ -52,6 +58,9 @@ properties: + - const: i2srx_lrck_ext + - const: tdm_ext + - const: mclk_ext ++ - const: pll0_out ++ - const: pll1_out ++ - const: pll2_out + + - items: + - const: osc +@@ -63,6 +72,9 @@ properties: + - const: i2srx_lrck_ext + - const: tdm_ext + - const: mclk_ext ++ - const: pll0_out ++ - const: pll1_out ++ - const: pll2_out + + '#clock-cells': + const: 1 +@@ -93,12 +105,16 @@ examples: + <&gmac1_rgmii_rxin>, + <&i2stx_bclk_ext>, <&i2stx_lrck_ext>, + <&i2srx_bclk_ext>, <&i2srx_lrck_ext>, +- <&tdm_ext>, <&mclk_ext>; ++ <&tdm_ext>, <&mclk_ext>, ++ <&pllclk JH7110_CLK_PLL0_OUT>, ++ <&pllclk JH7110_CLK_PLL1_OUT>, ++ <&pllclk JH7110_CLK_PLL2_OUT>; + clock-names = "osc", "gmac1_rmii_refin", + "gmac1_rgmii_rxin", + "i2stx_bclk_ext", "i2stx_lrck_ext", + "i2srx_bclk_ext", "i2srx_lrck_ext", +- "tdm_ext", "mclk_ext"; ++ "tdm_ext", "mclk_ext", ++ "pll0_out", "pll1_out", "pll2_out"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/target/linux/starfive/patches-6.1/0034-clk-starfive-jh7110-sys-Modify-PLL-clocks-source.patch b/target/linux/starfive/patches-6.1/0034-clk-starfive-jh7110-sys-Modify-PLL-clocks-source.patch new file mode 100644 index 0000000000..3e6237681f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0034-clk-starfive-jh7110-sys-Modify-PLL-clocks-source.patch @@ -0,0 +1,71 @@ +From ffd7ee4fbd69d477a2156d9cba6ae80434a4c894 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Tue, 14 Mar 2023 17:16:07 +0800 +Subject: [PATCH 034/122] clk: starfive: jh7110-sys: Modify PLL clocks source + +Modify PLL clocks source to be got from dts instead of +the fixed factor clocks. + +Signed-off-by: Xingyu Wu +--- + drivers/clk/starfive/Kconfig | 1 + + .../clk/starfive/clk-starfive-jh7110-sys.c | 31 ++++--------------- + 2 files changed, 7 insertions(+), 25 deletions(-) + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -35,6 +35,7 @@ config CLK_STARFIVE_JH7110_SYS + select AUXILIARY_BUS + select CLK_STARFIVE_JH71X0 + select RESET_STARFIVE_JH7110 ++ select CLK_STARFIVE_JH7110_PLL + default ARCH_STARFIVE + help + Say yes here to support the system clock controller on the +--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +@@ -404,29 +404,6 @@ static int __init jh7110_syscrg_probe(st + + dev_set_drvdata(priv->dev, (void *)(&priv->base)); + +- /* +- * These PLL clocks are not actually fixed factor clocks and can be +- * controlled by the syscon registers of JH7110. They will be dropped +- * and registered in the PLL clock driver instead. +- */ +- /* 24MHz -> 1000.0MHz */ +- priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out", +- "osc", 0, 125, 3); +- if (IS_ERR(priv->pll[0])) +- return PTR_ERR(priv->pll[0]); +- +- /* 24MHz -> 1066.0MHz */ +- priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out", +- "osc", 0, 533, 12); +- if (IS_ERR(priv->pll[1])) +- return PTR_ERR(priv->pll[1]); +- +- /* 24MHz -> 1188.0MHz */ +- priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out", +- "osc", 0, 99, 2); +- if (IS_ERR(priv->pll[2])) +- return PTR_ERR(priv->pll[2]); +- + for (idx = 0; idx < JH7110_SYSCLK_END; idx++) { + u32 max = jh7110_sysclk_data[idx].max; + struct clk_parent_data parents[4] = {}; +@@ -464,8 +441,12 @@ static int __init jh7110_syscrg_probe(st + parents[i].fw_name = "tdm_ext"; + else if (pidx == JH7110_SYSCLK_MCLK_EXT) + parents[i].fw_name = "mclk_ext"; +- else +- parents[i].hw = priv->pll[pidx - JH7110_SYSCLK_PLL0_OUT]; ++ else if (pidx == JH7110_SYSCLK_PLL0_OUT) ++ parents[i].fw_name = "pll0_out"; ++ else if (pidx == JH7110_SYSCLK_PLL1_OUT) ++ parents[i].fw_name = "pll1_out"; ++ else if (pidx == JH7110_SYSCLK_PLL2_OUT) ++ parents[i].fw_name = "pll2_out"; + } + + clk->hw.init = &init; diff --git a/target/linux/starfive/patches-6.1/0035-dt-bindings-power-Add-starfive-jh7110-pmu.patch b/target/linux/starfive/patches-6.1/0035-dt-bindings-power-Add-starfive-jh7110-pmu.patch new file mode 100644 index 0000000000..cf5fc7cbba --- /dev/null +++ b/target/linux/starfive/patches-6.1/0035-dt-bindings-power-Add-starfive-jh7110-pmu.patch @@ -0,0 +1,86 @@ +From 35bc6491a7b24872155a616f7770d3a5d6e40344 Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Thu, 19 Jan 2023 17:44:46 +0800 +Subject: [PATCH 035/122] dt-bindings: power: Add starfive,jh7110-pmu + +Add bindings for the Power Management Unit on the StarFive JH7110 SoC. + +Signed-off-by: Walker Chen +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Conor Dooley +Reviewed-by: Heiko Stuebner +--- + .../bindings/power/starfive,jh7110-pmu.yaml | 45 +++++++++++++++++++ + .../dt-bindings/power/starfive,jh7110-pmu.h | 17 +++++++ + 2 files changed, 62 insertions(+) + create mode 100644 Documentation/devicetree/bindings/power/starfive,jh7110-pmu.yaml + create mode 100644 include/dt-bindings/power/starfive,jh7110-pmu.h + +--- /dev/null ++++ b/Documentation/devicetree/bindings/power/starfive,jh7110-pmu.yaml +@@ -0,0 +1,45 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/power/starfive,jh7110-pmu.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 Power Management Unit ++ ++maintainers: ++ - Walker Chen ++ ++description: | ++ StarFive JH7110 SoC includes support for multiple power domains which can be ++ powered on/off by software based on different application scenes to save power. ++ ++properties: ++ compatible: ++ enum: ++ - starfive,jh7110-pmu ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ "#power-domain-cells": ++ const: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - "#power-domain-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pwrc: power-controller@17030000 { ++ compatible = "starfive,jh7110-pmu"; ++ reg = <0x17030000 0x10000>; ++ interrupts = <111>; ++ #power-domain-cells = <1>; ++ }; +--- /dev/null ++++ b/include/dt-bindings/power/starfive,jh7110-pmu.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ ++/* ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Author: Walker Chen ++ */ ++#ifndef __DT_BINDINGS_POWER_JH7110_POWER_H__ ++#define __DT_BINDINGS_POWER_JH7110_POWER_H__ ++ ++#define JH7110_PD_SYSTOP 0 ++#define JH7110_PD_CPU 1 ++#define JH7110_PD_GPUA 2 ++#define JH7110_PD_VDEC 3 ++#define JH7110_PD_VOUT 4 ++#define JH7110_PD_ISP 5 ++#define JH7110_PD_VENC 6 ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0036-soc-starfive-Add-StarFive-JH71XX-pmu-driver.patch b/target/linux/starfive/patches-6.1/0036-soc-starfive-Add-StarFive-JH71XX-pmu-driver.patch new file mode 100644 index 0000000000..a5a33876fa --- /dev/null +++ b/target/linux/starfive/patches-6.1/0036-soc-starfive-Add-StarFive-JH71XX-pmu-driver.patch @@ -0,0 +1,478 @@ +From 3e3b85a1064b07a5107504af1e8f0a42ff9d1fc1 Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Thu, 19 Jan 2023 17:44:47 +0800 +Subject: [PATCH 036/122] soc: starfive: Add StarFive JH71XX pmu driver + +Add pmu driver for the StarFive JH71XX SoC. + +As the power domains provider, the Power Management Unit (PMU) is +designed for including multiple PM domains that can be used for power +gating of selected IP blocks for power saving by reduced leakage +current. It accepts software encourage command to switch the power mode +of SoC. + +Signed-off-by: Walker Chen +Reviewed-by: Conor Dooley +Reviewed-by: Heiko Stuebner +--- + MAINTAINERS | 14 ++ + drivers/soc/Kconfig | 1 + + drivers/soc/Makefile | 1 + + drivers/soc/starfive/Kconfig | 12 + + drivers/soc/starfive/Makefile | 3 + + drivers/soc/starfive/jh71xx_pmu.c | 383 ++++++++++++++++++++++++++++++ + 6 files changed, 414 insertions(+) + create mode 100644 drivers/soc/starfive/Kconfig + create mode 100644 drivers/soc/starfive/Makefile + create mode 100644 drivers/soc/starfive/jh71xx_pmu.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19682,6 +19682,20 @@ F: Documentation/devicetree/bindings/res + F: drivers/reset/starfive/reset-starfive-jh71* + F: include/dt-bindings/reset/starfive?jh71*.h + ++STARFIVE SOC DRIVER ++M: Conor Dooley ++S: Maintained ++T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ ++F: drivers/soc/starfive/ ++F: include/soc/starfive/ ++ ++STARFIVE JH71XX PMU CONTROLLER DRIVER ++M: Walker Chen ++S: Supported ++F: Documentation/devicetree/bindings/power/starfive* ++F: drivers/soc/starfive/jh71xx_pmu.c ++F: include/dt-bindings/power/starfive,jh7110-pmu.h ++ + STATIC BRANCH/CALL + M: Peter Zijlstra + M: Josh Poimboeuf +--- a/drivers/soc/Kconfig ++++ b/drivers/soc/Kconfig +@@ -21,6 +21,7 @@ source "drivers/soc/renesas/Kconfig" + source "drivers/soc/rockchip/Kconfig" + source "drivers/soc/samsung/Kconfig" + source "drivers/soc/sifive/Kconfig" ++source "drivers/soc/starfive/Kconfig" + source "drivers/soc/sunxi/Kconfig" + source "drivers/soc/tegra/Kconfig" + source "drivers/soc/ti/Kconfig" +--- a/drivers/soc/Makefile ++++ b/drivers/soc/Makefile +@@ -27,6 +27,7 @@ obj-y += renesas/ + obj-y += rockchip/ + obj-$(CONFIG_SOC_SAMSUNG) += samsung/ + obj-$(CONFIG_SOC_SIFIVE) += sifive/ ++obj-$(CONFIG_SOC_STARFIVE) += starfive/ + obj-y += sunxi/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ + obj-y += ti/ +--- /dev/null ++++ b/drivers/soc/starfive/Kconfig +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++config JH71XX_PMU ++ bool "Support PMU for StarFive JH71XX Soc" ++ depends on PM ++ depends on SOC_STARFIVE || COMPILE_TEST ++ default SOC_STARFIVE ++ select PM_GENERIC_DOMAINS ++ help ++ Say 'y' here to enable support power domain support. ++ In order to meet low power requirements, a Power Management Unit (PMU) ++ is designed for controlling power resources in StarFive JH71XX SoCs. +--- /dev/null ++++ b/drivers/soc/starfive/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-$(CONFIG_JH71XX_PMU) += jh71xx_pmu.o +--- /dev/null ++++ b/drivers/soc/starfive/jh71xx_pmu.c +@@ -0,0 +1,383 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * StarFive JH71XX PMU (Power Management Unit) Controller Driver ++ * ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* register offset */ ++#define JH71XX_PMU_SW_TURN_ON_POWER 0x0C ++#define JH71XX_PMU_SW_TURN_OFF_POWER 0x10 ++#define JH71XX_PMU_SW_ENCOURAGE 0x44 ++#define JH71XX_PMU_TIMER_INT_MASK 0x48 ++#define JH71XX_PMU_CURR_POWER_MODE 0x80 ++#define JH71XX_PMU_EVENT_STATUS 0x88 ++#define JH71XX_PMU_INT_STATUS 0x8C ++ ++/* sw encourage cfg */ ++#define JH71XX_PMU_SW_ENCOURAGE_EN_LO 0x05 ++#define JH71XX_PMU_SW_ENCOURAGE_EN_HI 0x50 ++#define JH71XX_PMU_SW_ENCOURAGE_DIS_LO 0x0A ++#define JH71XX_PMU_SW_ENCOURAGE_DIS_HI 0xA0 ++#define JH71XX_PMU_SW_ENCOURAGE_ON 0xFF ++ ++/* pmu int status */ ++#define JH71XX_PMU_INT_SEQ_DONE BIT(0) ++#define JH71XX_PMU_INT_HW_REQ BIT(1) ++#define JH71XX_PMU_INT_SW_FAIL GENMASK(3, 2) ++#define JH71XX_PMU_INT_HW_FAIL GENMASK(5, 4) ++#define JH71XX_PMU_INT_PCH_FAIL GENMASK(8, 6) ++#define JH71XX_PMU_INT_ALL_MASK GENMASK(8, 0) ++ ++/* ++ * The time required for switching power status is based on the time ++ * to turn on the largest domain's power, which is at microsecond level ++ */ ++#define JH71XX_PMU_TIMEOUT_US 100 ++ ++struct jh71xx_domain_info { ++ const char * const name; ++ unsigned int flags; ++ u8 bit; ++}; ++ ++struct jh71xx_pmu_match_data { ++ const struct jh71xx_domain_info *domain_info; ++ int num_domains; ++}; ++ ++struct jh71xx_pmu { ++ struct device *dev; ++ const struct jh71xx_pmu_match_data *match_data; ++ void __iomem *base; ++ struct generic_pm_domain **genpd; ++ struct genpd_onecell_data genpd_data; ++ int irq; ++ spinlock_t lock; /* protects pmu reg */ ++}; ++ ++struct jh71xx_pmu_dev { ++ const struct jh71xx_domain_info *domain_info; ++ struct jh71xx_pmu *pmu; ++ struct generic_pm_domain genpd; ++}; ++ ++static int jh71xx_pmu_get_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool *is_on) ++{ ++ struct jh71xx_pmu *pmu = pmd->pmu; ++ ++ if (!mask) ++ return -EINVAL; ++ ++ *is_on = readl(pmu->base + JH71XX_PMU_CURR_POWER_MODE) & mask; ++ ++ return 0; ++} ++ ++static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on) ++{ ++ struct jh71xx_pmu *pmu = pmd->pmu; ++ unsigned long flags; ++ u32 val; ++ u32 mode; ++ u32 encourage_lo; ++ u32 encourage_hi; ++ bool is_on; ++ int ret; ++ ++ ret = jh71xx_pmu_get_state(pmd, mask, &is_on); ++ if (ret) { ++ dev_dbg(pmu->dev, "unable to get current state for %s\n", ++ pmd->genpd.name); ++ return ret; ++ } ++ ++ if (is_on == on) { ++ dev_dbg(pmu->dev, "pm domain [%s] is already %sable status.\n", ++ pmd->genpd.name, on ? "en" : "dis"); ++ return 0; ++ } ++ ++ spin_lock_irqsave(&pmu->lock, flags); ++ ++ /* ++ * The PMU accepts software encourage to switch power mode in the following 2 steps: ++ * ++ * 1.Configure the register SW_TURN_ON_POWER (offset 0x0c) by writing 1 to ++ * the bit corresponding to the power domain that will be turned on ++ * and writing 0 to the others. ++ * Likewise, configure the register SW_TURN_OFF_POWER (offset 0x10) by ++ * writing 1 to the bit corresponding to the power domain that will be ++ * turned off and writing 0 to the others. ++ */ ++ if (on) { ++ mode = JH71XX_PMU_SW_TURN_ON_POWER; ++ encourage_lo = JH71XX_PMU_SW_ENCOURAGE_EN_LO; ++ encourage_hi = JH71XX_PMU_SW_ENCOURAGE_EN_HI; ++ } else { ++ mode = JH71XX_PMU_SW_TURN_OFF_POWER; ++ encourage_lo = JH71XX_PMU_SW_ENCOURAGE_DIS_LO; ++ encourage_hi = JH71XX_PMU_SW_ENCOURAGE_DIS_HI; ++ } ++ ++ writel(mask, pmu->base + mode); ++ ++ /* ++ * 2.Write SW encourage command sequence to the Software Encourage Reg (offset 0x44) ++ * First write SW_MODE_ENCOURAGE_ON to JH71XX_PMU_SW_ENCOURAGE. This will reset ++ * the state machine which parses the command sequence. This register must be ++ * written every time software wants to power on/off a domain. ++ * Then write the lower bits of the command sequence, followed by the upper ++ * bits. The sequence differs between powering on & off a domain. ++ */ ++ writel(JH71XX_PMU_SW_ENCOURAGE_ON, pmu->base + JH71XX_PMU_SW_ENCOURAGE); ++ writel(encourage_lo, pmu->base + JH71XX_PMU_SW_ENCOURAGE); ++ writel(encourage_hi, pmu->base + JH71XX_PMU_SW_ENCOURAGE); ++ ++ spin_unlock_irqrestore(&pmu->lock, flags); ++ ++ /* Wait for the power domain bit to be enabled / disabled */ ++ if (on) { ++ ret = readl_poll_timeout_atomic(pmu->base + JH71XX_PMU_CURR_POWER_MODE, ++ val, val & mask, ++ 1, JH71XX_PMU_TIMEOUT_US); ++ } else { ++ ret = readl_poll_timeout_atomic(pmu->base + JH71XX_PMU_CURR_POWER_MODE, ++ val, !(val & mask), ++ 1, JH71XX_PMU_TIMEOUT_US); ++ } ++ ++ if (ret) { ++ dev_err(pmu->dev, "%s: failed to power %s\n", ++ pmd->genpd.name, on ? "on" : "off"); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int jh71xx_pmu_on(struct generic_pm_domain *genpd) ++{ ++ struct jh71xx_pmu_dev *pmd = container_of(genpd, ++ struct jh71xx_pmu_dev, genpd); ++ u32 pwr_mask = BIT(pmd->domain_info->bit); ++ ++ return jh71xx_pmu_set_state(pmd, pwr_mask, true); ++} ++ ++static int jh71xx_pmu_off(struct generic_pm_domain *genpd) ++{ ++ struct jh71xx_pmu_dev *pmd = container_of(genpd, ++ struct jh71xx_pmu_dev, genpd); ++ u32 pwr_mask = BIT(pmd->domain_info->bit); ++ ++ return jh71xx_pmu_set_state(pmd, pwr_mask, false); ++} ++ ++static void jh71xx_pmu_int_enable(struct jh71xx_pmu *pmu, u32 mask, bool enable) ++{ ++ u32 val; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pmu->lock, flags); ++ val = readl(pmu->base + JH71XX_PMU_TIMER_INT_MASK); ++ ++ if (enable) ++ val &= ~mask; ++ else ++ val |= mask; ++ ++ writel(val, pmu->base + JH71XX_PMU_TIMER_INT_MASK); ++ spin_unlock_irqrestore(&pmu->lock, flags); ++} ++ ++static irqreturn_t jh71xx_pmu_interrupt(int irq, void *data) ++{ ++ struct jh71xx_pmu *pmu = data; ++ u32 val; ++ ++ val = readl(pmu->base + JH71XX_PMU_INT_STATUS); ++ ++ if (val & JH71XX_PMU_INT_SEQ_DONE) ++ dev_dbg(pmu->dev, "sequence done.\n"); ++ if (val & JH71XX_PMU_INT_HW_REQ) ++ dev_dbg(pmu->dev, "hardware encourage requestion.\n"); ++ if (val & JH71XX_PMU_INT_SW_FAIL) ++ dev_err(pmu->dev, "software encourage fail.\n"); ++ if (val & JH71XX_PMU_INT_HW_FAIL) ++ dev_err(pmu->dev, "hardware encourage fail.\n"); ++ if (val & JH71XX_PMU_INT_PCH_FAIL) ++ dev_err(pmu->dev, "p-channel fail event.\n"); ++ ++ /* clear interrupts */ ++ writel(val, pmu->base + JH71XX_PMU_INT_STATUS); ++ writel(val, pmu->base + JH71XX_PMU_EVENT_STATUS); ++ ++ return IRQ_HANDLED; ++} ++ ++static int jh71xx_pmu_init_domain(struct jh71xx_pmu *pmu, int index) ++{ ++ struct jh71xx_pmu_dev *pmd; ++ u32 pwr_mask; ++ int ret; ++ bool is_on = false; ++ ++ pmd = devm_kzalloc(pmu->dev, sizeof(*pmd), GFP_KERNEL); ++ if (!pmd) ++ return -ENOMEM; ++ ++ pmd->domain_info = &pmu->match_data->domain_info[index]; ++ pmd->pmu = pmu; ++ pwr_mask = BIT(pmd->domain_info->bit); ++ ++ pmd->genpd.name = pmd->domain_info->name; ++ pmd->genpd.flags = pmd->domain_info->flags; ++ ++ ret = jh71xx_pmu_get_state(pmd, pwr_mask, &is_on); ++ if (ret) ++ dev_warn(pmu->dev, "unable to get current state for %s\n", ++ pmd->genpd.name); ++ ++ pmd->genpd.power_on = jh71xx_pmu_on; ++ pmd->genpd.power_off = jh71xx_pmu_off; ++ pm_genpd_init(&pmd->genpd, NULL, !is_on); ++ ++ pmu->genpd_data.domains[index] = &pmd->genpd; ++ ++ return 0; ++} ++ ++static int jh71xx_pmu_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ const struct jh71xx_pmu_match_data *match_data; ++ struct jh71xx_pmu *pmu; ++ unsigned int i; ++ int ret; ++ ++ pmu = devm_kzalloc(dev, sizeof(*pmu), GFP_KERNEL); ++ if (!pmu) ++ return -ENOMEM; ++ ++ pmu->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pmu->base)) ++ return PTR_ERR(pmu->base); ++ ++ pmu->irq = platform_get_irq(pdev, 0); ++ if (pmu->irq < 0) ++ return pmu->irq; ++ ++ ret = devm_request_irq(dev, pmu->irq, jh71xx_pmu_interrupt, ++ 0, pdev->name, pmu); ++ if (ret) ++ dev_err(dev, "failed to request irq\n"); ++ ++ match_data = of_device_get_match_data(dev); ++ if (!match_data) ++ return -EINVAL; ++ ++ pmu->genpd = devm_kcalloc(dev, match_data->num_domains, ++ sizeof(struct generic_pm_domain *), ++ GFP_KERNEL); ++ if (!pmu->genpd) ++ return -ENOMEM; ++ ++ pmu->dev = dev; ++ pmu->match_data = match_data; ++ pmu->genpd_data.domains = pmu->genpd; ++ pmu->genpd_data.num_domains = match_data->num_domains; ++ ++ for (i = 0; i < match_data->num_domains; i++) { ++ ret = jh71xx_pmu_init_domain(pmu, i); ++ if (ret) { ++ dev_err(dev, "failed to initialize power domain\n"); ++ return ret; ++ } ++ } ++ ++ spin_lock_init(&pmu->lock); ++ jh71xx_pmu_int_enable(pmu, JH71XX_PMU_INT_ALL_MASK & ~JH71XX_PMU_INT_PCH_FAIL, true); ++ ++ ret = of_genpd_add_provider_onecell(np, &pmu->genpd_data); ++ if (ret) { ++ dev_err(dev, "failed to register genpd driver: %d\n", ret); ++ return ret; ++ } ++ ++ dev_dbg(dev, "registered %u power domains\n", i); ++ ++ return 0; ++} ++ ++static const struct jh71xx_domain_info jh7110_power_domains[] = { ++ [JH7110_PD_SYSTOP] = { ++ .name = "SYSTOP", ++ .bit = 0, ++ .flags = GENPD_FLAG_ALWAYS_ON, ++ }, ++ [JH7110_PD_CPU] = { ++ .name = "CPU", ++ .bit = 1, ++ .flags = GENPD_FLAG_ALWAYS_ON, ++ }, ++ [JH7110_PD_GPUA] = { ++ .name = "GPUA", ++ .bit = 2, ++ }, ++ [JH7110_PD_VDEC] = { ++ .name = "VDEC", ++ .bit = 3, ++ }, ++ [JH7110_PD_VOUT] = { ++ .name = "VOUT", ++ .bit = 4, ++ }, ++ [JH7110_PD_ISP] = { ++ .name = "ISP", ++ .bit = 5, ++ }, ++ [JH7110_PD_VENC] = { ++ .name = "VENC", ++ .bit = 6, ++ }, ++}; ++ ++static const struct jh71xx_pmu_match_data jh7110_pmu = { ++ .num_domains = ARRAY_SIZE(jh7110_power_domains), ++ .domain_info = jh7110_power_domains, ++}; ++ ++static const struct of_device_id jh71xx_pmu_of_match[] = { ++ { ++ .compatible = "starfive,jh7110-pmu", ++ .data = (void *)&jh7110_pmu, ++ }, { ++ /* sentinel */ ++ } ++}; ++ ++static struct platform_driver jh71xx_pmu_driver = { ++ .probe = jh71xx_pmu_probe, ++ .driver = { ++ .name = "jh71xx-pmu", ++ .of_match_table = jh71xx_pmu_of_match, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver(jh71xx_pmu_driver); ++ ++MODULE_AUTHOR("Walker Chen "); ++MODULE_DESCRIPTION("StarFive JH71XX PMU Driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0037-dt-bindings-soc-starfive-Add-StarFive-syscon-module.patch b/target/linux/starfive/patches-6.1/0037-dt-bindings-soc-starfive-Add-StarFive-syscon-module.patch new file mode 100644 index 0000000000..c4bf9bc56f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0037-dt-bindings-soc-starfive-Add-StarFive-syscon-module.patch @@ -0,0 +1,98 @@ +From 27d38dda7527414eb84ef471425e96c9d2566b38 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Thu, 6 Apr 2023 15:46:13 +0800 +Subject: [PATCH 037/122] dt-bindings: soc: starfive: Add StarFive syscon + module + +Add documentation to describe StarFive System Controller Registers. + +Signed-off-by: William Qiu +--- + .../soc/starfive/starfive,jh7110-syscon.yaml | 58 +++++++++++++++++++ + MAINTAINERS | 6 ++ + 2 files changed, 64 insertions(+) + create mode 100644 Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml +@@ -0,0 +1,58 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/soc/starfive/starfive,jh7110-syscon.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 SoC system controller ++ ++maintainers: ++ - William Qiu ++ ++description: | ++ The StarFive JH7110 SoC system controller provides register information such ++ as offset, mask and shift to configure related modules such as MMC and PCIe. ++ ++properties: ++ compatible: ++ oneOf: ++ - items: ++ - enum: ++ - starfive,jh7110-aon-syscon ++ - starfive,jh7110-sys-syscon ++ - const: syscon ++ - const: simple-mfd ++ - items: ++ - const: starfive,jh7110-stg-syscon ++ - const: syscon ++ ++ reg: ++ maxItems: 1 ++ ++ clock-controller: ++ $ref: /schemas/clock/starfive,jh7110-pll.yaml# ++ type: object ++ ++ power-controller: ++ $ref: /schemas/power/starfive,jh7110-pmu.yaml# ++ type: object ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ syscon@10240000 { ++ compatible = "starfive,jh7110-stg-syscon", "syscon"; ++ reg = <0x10240000 0x1000>; ++ }; ++ ++ syscon@13030000 { ++ compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd"; ++ reg = <0x13030000 0x1000>; ++ }; ++ ++... +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19656,6 +19656,11 @@ S: Supported + F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml + F: drivers/clk/starfive/clk-starfive-jh7110-pll.* + ++STARFIVE JH7110 SYSCON ++M: William Qiu ++S: Supported ++F: Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml ++ + STARFIVE JH71X0 CLOCK DRIVERS + M: Emil Renner Berthing + M: Hal Feng +@@ -19686,6 +19691,7 @@ STARFIVE SOC DRIVER + M: Conor Dooley + S: Maintained + T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ ++F: Documentation/devicetree/bindings/soc/starfive/ + F: drivers/soc/starfive/ + F: include/soc/starfive/ + diff --git a/target/linux/starfive/patches-6.1/0038-riscv-dts-starfive-jh7110-Add-syscon-nodes.patch b/target/linux/starfive/patches-6.1/0038-riscv-dts-starfive-jh7110-Add-syscon-nodes.patch new file mode 100644 index 0000000000..ad748151c7 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0038-riscv-dts-starfive-jh7110-Add-syscon-nodes.patch @@ -0,0 +1,52 @@ +From 40098f3d986dc90f6a7be0e5a35ddaccd1ded0b5 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Thu, 6 Apr 2023 15:46:34 +0800 +Subject: [PATCH 038/122] riscv: dts: starfive: jh7110: Add syscon nodes + +Add stg_syscon/sys_syscon/aon_syscon nodes for JH7110 Soc. + +Signed-off-by: William Qiu +Reviewed-by: Conor Dooley +Reviewed-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/jh7110.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi +@@ -353,6 +353,11 @@ + status = "disabled"; + }; + ++ stg_syscon: syscon@10240000 { ++ compatible = "starfive,jh7110-stg-syscon", "syscon"; ++ reg = <0x0 0x10240000 0x0 0x1000>; ++ }; ++ + uart3: serial@12000000 { + compatible = "snps,dw-apb-uart"; + reg = <0x0 0x12000000 0x0 0x10000>; +@@ -457,6 +462,11 @@ + #reset-cells = <1>; + }; + ++ sys_syscon: syscon@13030000 { ++ compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd"; ++ reg = <0x0 0x13030000 0x0 0x1000>; ++ }; ++ + sysgpio: pinctrl@13040000 { + compatible = "starfive,jh7110-sys-pinctrl"; + reg = <0x0 0x13040000 0x0 0x10000>; +@@ -486,6 +496,11 @@ + #reset-cells = <1>; + }; + ++ aon_syscon: syscon@17010000 { ++ compatible = "starfive,jh7110-aon-syscon", "syscon", "simple-mfd"; ++ reg = <0x0 0x17010000 0x0 0x1000>; ++ }; ++ + aongpio: pinctrl@17020000 { + compatible = "starfive,jh7110-aon-pinctrl"; + reg = <0x0 0x17020000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.1/0039-riscv-dts-starfive-jh7110-Add-PLL-clock-node-and-mod.patch b/target/linux/starfive/patches-6.1/0039-riscv-dts-starfive-jh7110-Add-PLL-clock-node-and-mod.patch new file mode 100644 index 0000000000..c771512bd3 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0039-riscv-dts-starfive-jh7110-Add-PLL-clock-node-and-mod.patch @@ -0,0 +1,48 @@ +From f0548ab9212ef35abe79f46e5f509f4fc9d78699 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Mon, 20 Feb 2023 14:33:33 +0800 +Subject: [PATCH 039/122] riscv: dts: starfive: jh7110: Add PLL clock node and + modify syscrg node + +Add the PLL clock node for the Starfive JH7110 SoC and +modify the SYSCRG node to add PLL clocks input. + +Signed-off-by: Xingyu Wu +--- + arch/riscv/boot/dts/starfive/jh7110.dtsi | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi +@@ -452,12 +452,16 @@ + <&gmac1_rgmii_rxin>, + <&i2stx_bclk_ext>, <&i2stx_lrck_ext>, + <&i2srx_bclk_ext>, <&i2srx_lrck_ext>, +- <&tdm_ext>, <&mclk_ext>; ++ <&tdm_ext>, <&mclk_ext>, ++ <&pllclk JH7110_CLK_PLL0_OUT>, ++ <&pllclk JH7110_CLK_PLL1_OUT>, ++ <&pllclk JH7110_CLK_PLL2_OUT>; + clock-names = "osc", "gmac1_rmii_refin", + "gmac1_rgmii_rxin", + "i2stx_bclk_ext", "i2stx_lrck_ext", + "i2srx_bclk_ext", "i2srx_lrck_ext", +- "tdm_ext", "mclk_ext"; ++ "tdm_ext", "mclk_ext", ++ "pll0_out", "pll1_out", "pll2_out"; + #clock-cells = <1>; + #reset-cells = <1>; + }; +@@ -465,6 +469,12 @@ + sys_syscon: syscon@13030000 { + compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd"; + reg = <0x0 0x13030000 0x0 0x1000>; ++ ++ pllclk: clock-controller { ++ compatible = "starfive,jh7110-pll"; ++ clocks = <&osc>; ++ #clock-cells = <1>; ++ }; + }; + + sysgpio: pinctrl@13040000 { diff --git a/target/linux/starfive/patches-6.1/0040-dt-bindings-net-snps-dwmac-Add-dwmac-5.20-version.patch b/target/linux/starfive/patches-6.1/0040-dt-bindings-net-snps-dwmac-Add-dwmac-5.20-version.patch new file mode 100644 index 0000000000..139cd8445b --- /dev/null +++ b/target/linux/starfive/patches-6.1/0040-dt-bindings-net-snps-dwmac-Add-dwmac-5.20-version.patch @@ -0,0 +1,49 @@ +From 5866a8486a261decacd19769556d1b79b5d1269d Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Mon, 8 Aug 2022 17:13:34 +0200 +Subject: [PATCH 040/122] dt-bindings: net: snps,dwmac: Add dwmac-5.20 version + +Add dwmac-5.20 IP version to snps.dwmac.yaml + +Acked-by: Krzysztof Kozlowski +Signed-off-by: Emil Renner Berthing +Signed-off-by: Samin Guo +Signed-off-by: Paolo Abeni +--- + Documentation/devicetree/bindings/net/snps,dwmac.yaml | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml ++++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +@@ -30,6 +30,7 @@ select: + - snps,dwmac-4.10a + - snps,dwmac-4.20a + - snps,dwmac-5.10a ++ - snps,dwmac-5.20 + - snps,dwxgmac + - snps,dwxgmac-2.10 + +@@ -87,6 +88,7 @@ properties: + - snps,dwmac-4.10a + - snps,dwmac-4.20a + - snps,dwmac-5.10a ++ - snps,dwmac-5.20 + - snps,dwxgmac + - snps,dwxgmac-2.10 + +@@ -393,6 +395,7 @@ allOf: + - snps,dwmac-3.50a + - snps,dwmac-4.10a + - snps,dwmac-4.20a ++ - snps,dwmac-5.20 + - snps,dwxgmac + - snps,dwxgmac-2.10 + - st,spear600-gmac +@@ -447,6 +450,7 @@ allOf: + - snps,dwmac-4.10a + - snps,dwmac-4.20a + - snps,dwmac-5.10a ++ - snps,dwmac-5.20 + - snps,dwxgmac + - snps,dwxgmac-2.10 + - st,spear600-gmac diff --git a/target/linux/starfive/patches-6.1/0041-net-stmmac-platform-Add-snps-dwmac-5.20-IP-compatibl.patch b/target/linux/starfive/patches-6.1/0041-net-stmmac-platform-Add-snps-dwmac-5.20-IP-compatibl.patch new file mode 100644 index 0000000000..077f161dcd --- /dev/null +++ b/target/linux/starfive/patches-6.1/0041-net-stmmac-platform-Add-snps-dwmac-5.20-IP-compatibl.patch @@ -0,0 +1,29 @@ +From cb00f835fc9f3ece473e7081f17c8613bf08a8ef Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sun, 7 Aug 2022 22:26:00 +0200 +Subject: [PATCH 041/122] net: stmmac: platform: Add snps,dwmac-5.20 IP + compatible string + +Add "snps,dwmac-5.20" compatible string for 5.20 version that can avoid +to define some platform data in the glue layer. + +Tested-by: Tommaso Merciai +Signed-off-by: Emil Renner Berthing +Signed-off-by: Paolo Abeni +Signed-off-by: Samin Guo +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -519,7 +519,8 @@ stmmac_probe_config_dt(struct platform_d + if (of_device_is_compatible(np, "snps,dwmac-4.00") || + of_device_is_compatible(np, "snps,dwmac-4.10a") || + of_device_is_compatible(np, "snps,dwmac-4.20a") || +- of_device_is_compatible(np, "snps,dwmac-5.10a")) { ++ of_device_is_compatible(np, "snps,dwmac-5.10a") || ++ of_device_is_compatible(np, "snps,dwmac-5.20")) { + plat->has_gmac4 = 1; + plat->has_gmac = 0; + plat->pmt = 1; diff --git a/target/linux/starfive/patches-6.1/0042-dt-bindings-net-snps-dwmac-Add-ahb-reset-reset-name.patch b/target/linux/starfive/patches-6.1/0042-dt-bindings-net-snps-dwmac-Add-ahb-reset-reset-name.patch new file mode 100644 index 0000000000..5b73752fd6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0042-dt-bindings-net-snps-dwmac-Add-ahb-reset-reset-name.patch @@ -0,0 +1,46 @@ +From 3b0609e57e031a3b680131b3fc25bc1165e3360f Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Mon, 27 Feb 2023 18:26:04 +0800 +Subject: [PATCH 042/122] dt-bindings: net: snps,dwmac: Add 'ahb' + reset/reset-name + +According to: +stmmac_platform.c: stmmac_probe_config_dt +stmmac_main.c: stmmac_dvr_probe + +dwmac controller may require one (stmmaceth) or two (stmmaceth+ahb) +reset signals, and the maxItems of resets/reset-names is going to be 2. + +The gmac of Starfive Jh7110 SOC must have two resets. +it uses snps,dwmac-5.20 IP. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Samin Guo +Signed-off-by: Paolo Abeni +--- + .../devicetree/bindings/net/snps,dwmac.yaml | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml ++++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +@@ -133,12 +133,16 @@ properties: + - ptp_ref + + resets: +- maxItems: 1 +- description: +- MAC Reset signal. ++ minItems: 1 ++ items: ++ - description: GMAC stmmaceth reset ++ - description: AHB reset + + reset-names: +- const: stmmaceth ++ minItems: 1 ++ items: ++ - const: stmmaceth ++ - const: ahb + + power-domains: + maxItems: 1 diff --git a/target/linux/starfive/patches-6.1/0043-dt-bindings-net-Add-support-StarFive-dwmac.patch b/target/linux/starfive/patches-6.1/0043-dt-bindings-net-Add-support-StarFive-dwmac.patch new file mode 100644 index 0000000000..4487c6995f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0043-dt-bindings-net-Add-support-StarFive-dwmac.patch @@ -0,0 +1,190 @@ +From 6bef17fa124f20723724e2a9a1d890fd1a9d5eaa Mon Sep 17 00:00:00 2001 +From: Yanhong Wang +Date: Mon, 31 Oct 2022 18:08:15 +0800 +Subject: [PATCH 043/122] dt-bindings: net: Add support StarFive dwmac + +Add documentation to describe StarFive dwmac driver(GMAC). + +Signed-off-by: Yanhong Wang +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Paolo Abeni +Signed-off-by: Samin Guo +--- + .../devicetree/bindings/net/snps,dwmac.yaml | 1 + + .../bindings/net/starfive,jh7110-dwmac.yaml | 144 ++++++++++++++++++ + MAINTAINERS | 6 + + 3 files changed, 151 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml + +--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml ++++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +@@ -91,6 +91,7 @@ properties: + - snps,dwmac-5.20 + - snps,dwxgmac + - snps,dwxgmac-2.10 ++ - starfive,jh7110-dwmac + + reg: + minItems: 1 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml +@@ -0,0 +1,144 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++# Copyright (C) 2022 StarFive Technology Co., Ltd. ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/starfive,jh7110-dwmac.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 DWMAC glue layer ++ ++maintainers: ++ - Emil Renner Berthing ++ - Samin Guo ++ ++select: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - starfive,jh7110-dwmac ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - starfive,jh7110-dwmac ++ - const: snps,dwmac-5.20 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: GMAC main clock ++ - description: GMAC AHB clock ++ - description: PTP clock ++ - description: TX clock ++ - description: GTX clock ++ ++ clock-names: ++ items: ++ - const: stmmaceth ++ - const: pclk ++ - const: ptp_ref ++ - const: tx ++ - const: gtx ++ ++ interrupts: ++ minItems: 3 ++ maxItems: 3 ++ ++ interrupt-names: ++ minItems: 3 ++ maxItems: 3 ++ ++ resets: ++ items: ++ - description: MAC Reset signal. ++ - description: AHB Reset signal. ++ ++ reset-names: ++ items: ++ - const: stmmaceth ++ - const: ahb ++ ++ starfive,tx-use-rgmii-clk: ++ description: ++ Tx clock is provided by external rgmii clock. ++ type: boolean ++ ++ starfive,syscon: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ items: ++ - items: ++ - description: phandle to syscon that configures phy mode ++ - description: Offset of phy mode selection ++ - description: Shift of phy mode selection ++ description: ++ A phandle to syscon with two arguments that configure phy mode. ++ The argument one is the offset of phy mode selection, the ++ argument two is the shift of phy mode selection. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - interrupts ++ - interrupt-names ++ - resets ++ - reset-names ++ ++allOf: ++ - $ref: snps,dwmac.yaml# ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ ethernet@16030000 { ++ compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20"; ++ reg = <0x16030000 0x10000>; ++ clocks = <&clk 3>, <&clk 2>, <&clk 109>, ++ <&clk 6>, <&clk 111>; ++ clock-names = "stmmaceth", "pclk", "ptp_ref", ++ "tx", "gtx"; ++ resets = <&rst 1>, <&rst 2>; ++ reset-names = "stmmaceth", "ahb"; ++ interrupts = <7>, <6>, <5>; ++ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; ++ phy-mode = "rgmii-id"; ++ snps,multicast-filter-bins = <64>; ++ snps,perfect-filter-entries = <8>; ++ rx-fifo-depth = <2048>; ++ tx-fifo-depth = <2048>; ++ snps,fixed-burst; ++ snps,no-pbl-x8; ++ snps,tso; ++ snps,force_thresh_dma_mode; ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,en-tx-lpi-clockgating; ++ snps,txpbl = <16>; ++ snps,rxpbl = <16>; ++ starfive,syscon = <&aon_syscon 0xc 0x12>; ++ phy-handle = <&phy0>; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ }; ++ ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,lpi_en; ++ snps,wr_osr_lmt = <4>; ++ snps,rd_osr_lmt = <4>; ++ snps,blen = <256 128 64 32 0 0 0>; ++ }; ++ }; +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19650,6 +19650,12 @@ M: Emil Renner Berthing ++M: Samin Guo ++S: Maintained ++F: Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml ++ + STARFIVE JH7110 PLL CLOCK DRIVER + M: Xingyu Wu + S: Supported diff --git a/target/linux/starfive/patches-6.1/0044-net-stmmac-Add-glue-layer-for-StarFive-JH7110-SoC.patch b/target/linux/starfive/patches-6.1/0044-net-stmmac-Add-glue-layer-for-StarFive-JH7110-SoC.patch new file mode 100644 index 0000000000..37ad5a192a --- /dev/null +++ b/target/linux/starfive/patches-6.1/0044-net-stmmac-Add-glue-layer-for-StarFive-JH7110-SoC.patch @@ -0,0 +1,187 @@ +From 7c82049adb0460985dd6a1e5c9b6954d901247d2 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Fri, 3 Mar 2023 16:50:58 +0800 +Subject: [PATCH 044/122] net: stmmac: Add glue layer for StarFive JH7110 SoC + +This adds StarFive dwmac driver support on the StarFive JH7110 SoC. + +Tested-by: Tommaso Merciai +Co-developed-by: Emil Renner Berthing +Signed-off-by: Emil Renner Berthing +Signed-off-by: Paolo Abeni +Signed-off-by: Samin Guo +--- + MAINTAINERS | 1 + + drivers/net/ethernet/stmicro/stmmac/Kconfig | 12 ++ + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + + .../ethernet/stmicro/stmmac/dwmac-starfive.c | 123 ++++++++++++++++++ + 4 files changed, 137 insertions(+) + create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19655,6 +19655,7 @@ M: Emil Renner Berthing + S: Maintained + F: Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml ++F: drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c + + STARFIVE JH7110 PLL CLOCK DRIVER + M: Xingyu Wu +--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig ++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig +@@ -165,6 +165,18 @@ config DWMAC_SOCFPGA + for the stmmac device driver. This driver is used for + arria5 and cyclone5 FPGA SoCs. + ++config DWMAC_STARFIVE ++ tristate "StarFive dwmac support" ++ depends on OF && (ARCH_STARFIVE || COMPILE_TEST) ++ select MFD_SYSCON ++ default m if ARCH_STARFIVE ++ help ++ Support for ethernet controllers on StarFive RISC-V SoCs ++ ++ This selects the StarFive platform specific glue layer support for ++ the stmmac device driver. This driver is used for StarFive JH7110 ++ ethernet controller. ++ + config DWMAC_STI + tristate "STi GMAC support" + default ARCH_STI +--- a/drivers/net/ethernet/stmicro/stmmac/Makefile ++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas + obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o + obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o + obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o ++obj-$(CONFIG_DWMAC_STARFIVE) += dwmac-starfive.o + obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o + obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o + obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +@@ -0,0 +1,123 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * StarFive DWMAC platform driver ++ * ++ * Copyright (C) 2021 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "stmmac_platform.h" ++ ++struct starfive_dwmac { ++ struct device *dev; ++ struct clk *clk_tx; ++}; ++ ++static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed) ++{ ++ struct starfive_dwmac *dwmac = priv; ++ unsigned long rate; ++ int err; ++ ++ rate = clk_get_rate(dwmac->clk_tx); ++ ++ switch (speed) { ++ case SPEED_1000: ++ rate = 125000000; ++ break; ++ case SPEED_100: ++ rate = 25000000; ++ break; ++ case SPEED_10: ++ rate = 2500000; ++ break; ++ default: ++ dev_err(dwmac->dev, "invalid speed %u\n", speed); ++ break; ++ } ++ ++ err = clk_set_rate(dwmac->clk_tx, rate); ++ if (err) ++ dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate); ++} ++ ++static int starfive_dwmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ struct starfive_dwmac *dwmac; ++ struct clk *clk_gtx; ++ int err; ++ ++ err = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (err) ++ return dev_err_probe(&pdev->dev, err, ++ "failed to get resources\n"); ++ ++ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(plat_dat), ++ "dt configuration failed\n"); ++ ++ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); ++ if (!dwmac) ++ return -ENOMEM; ++ ++ dwmac->clk_tx = devm_clk_get_enabled(&pdev->dev, "tx"); ++ if (IS_ERR(dwmac->clk_tx)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->clk_tx), ++ "error getting tx clock\n"); ++ ++ clk_gtx = devm_clk_get_enabled(&pdev->dev, "gtx"); ++ if (IS_ERR(clk_gtx)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(clk_gtx), ++ "error getting gtx clock\n"); ++ ++ /* Generally, the rgmii_tx clock is provided by the internal clock, ++ * which needs to match the corresponding clock frequency according ++ * to different speeds. If the rgmii_tx clock is provided by the ++ * external rgmii_rxin, there is no need to configure the clock ++ * internally, because rgmii_rxin will be adaptively adjusted. ++ */ ++ if (!device_property_read_bool(&pdev->dev, "starfive,tx-use-rgmii-clk")) ++ plat_dat->fix_mac_speed = starfive_dwmac_fix_mac_speed; ++ ++ dwmac->dev = &pdev->dev; ++ plat_dat->bsp_priv = dwmac; ++ plat_dat->dma_cfg->dche = true; ++ ++ err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++ if (err) { ++ stmmac_remove_config_dt(pdev, plat_dat); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id starfive_dwmac_match[] = { ++ { .compatible = "starfive,jh7110-dwmac" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, starfive_dwmac_match); ++ ++static struct platform_driver starfive_dwmac_driver = { ++ .probe = starfive_dwmac_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = "starfive-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = starfive_dwmac_match, ++ }, ++}; ++module_platform_driver(starfive_dwmac_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("StarFive DWMAC platform driver"); ++MODULE_AUTHOR("Emil Renner Berthing "); ++MODULE_AUTHOR("Samin Guo "); diff --git a/target/linux/starfive/patches-6.1/0045-net-stmmac-dwmac-starfive-Add-phy-interface-settings.patch b/target/linux/starfive/patches-6.1/0045-net-stmmac-dwmac-starfive-Add-phy-interface-settings.patch new file mode 100644 index 0000000000..a532c0e4dd --- /dev/null +++ b/target/linux/starfive/patches-6.1/0045-net-stmmac-dwmac-starfive-Add-phy-interface-settings.patch @@ -0,0 +1,93 @@ +From 20886cd583e8d569d78ea0e723f98384a61ab54b Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Thu, 2 Mar 2023 19:52:37 +0800 +Subject: [PATCH 045/122] net: stmmac: dwmac-starfive: Add phy interface + settings + +dwmac supports multiple modess. When working under rmii and rgmii, +you need to set different phy interfaces. + +According to the dwmac document, when working in rmii, it needs to be +set to 0x4, and rgmii needs to be set to 0x1. + +The phy interface needs to be set in syscon, the format is as follows: +starfive,syscon: <&syscon, offset, shift> + +Tested-by: Tommaso Merciai +Signed-off-by: Paolo Abeni +Signed-off-by: Samin Guo +--- + .../ethernet/stmicro/stmmac/dwmac-starfive.c | 48 +++++++++++++++++++ + 1 file changed, 48 insertions(+) + +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +@@ -13,6 +13,10 @@ + + #include "stmmac_platform.h" + ++#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 ++#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 ++#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U ++ + struct starfive_dwmac { + struct device *dev; + struct clk *clk_tx; +@@ -46,6 +50,46 @@ static void starfive_dwmac_fix_mac_speed + dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate); + } + ++static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) ++{ ++ struct starfive_dwmac *dwmac = plat_dat->bsp_priv; ++ struct regmap *regmap; ++ unsigned int args[2]; ++ unsigned int mode; ++ int err; ++ ++ switch (plat_dat->interface) { ++ case PHY_INTERFACE_MODE_RMII: ++ mode = STARFIVE_DWMAC_PHY_INFT_RMII; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ mode = STARFIVE_DWMAC_PHY_INFT_RGMII; ++ break; ++ ++ default: ++ dev_err(dwmac->dev, "unsupported interface %d\n", ++ plat_dat->interface); ++ return -EINVAL; ++ } ++ ++ regmap = syscon_regmap_lookup_by_phandle_args(dwmac->dev->of_node, ++ "starfive,syscon", ++ 2, args); ++ if (IS_ERR(regmap)) ++ return dev_err_probe(dwmac->dev, PTR_ERR(regmap), "getting the regmap failed\n"); ++ ++ /* args[0]:offset args[1]: shift */ ++ err = regmap_update_bits(regmap, args[0], ++ STARFIVE_DWMAC_PHY_INFT_FIELD << args[1], ++ mode << args[1]); ++ if (err) ++ return dev_err_probe(dwmac->dev, err, "error setting phy mode\n"); ++ ++ return 0; ++} ++ + static int starfive_dwmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -91,6 +135,10 @@ static int starfive_dwmac_probe(struct p + plat_dat->bsp_priv = dwmac; + plat_dat->dma_cfg->dche = true; + ++ err = starfive_dwmac_set_mode(plat_dat); ++ if (err) ++ return err; ++ + err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (err) { + stmmac_remove_config_dt(pdev, plat_dat); diff --git a/target/linux/starfive/patches-6.1/0046-riscv-dts-starfive-jh7110-Add-ethernet-device-nodes.patch b/target/linux/starfive/patches-6.1/0046-riscv-dts-starfive-jh7110-Add-ethernet-device-nodes.patch new file mode 100644 index 0000000000..50ad56f568 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0046-riscv-dts-starfive-jh7110-Add-ethernet-device-nodes.patch @@ -0,0 +1,101 @@ +From cad740398f4cb6604abf1ddcc70121b2634ac233 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Fri, 3 Mar 2023 16:49:31 +0800 +Subject: [PATCH 046/122] riscv: dts: starfive: jh7110: Add ethernet device + nodes + +Add JH7110 ethernet device node to support gmac driver for the JH7110 +RISC-V SoC. + +Tested-by: Tommaso Merciai +Signed-off-by: Yanhong Wang +Signed-off-by: Samin Guo +--- + arch/riscv/boot/dts/starfive/jh7110.dtsi | 69 ++++++++++++++++++++++++ + 1 file changed, 69 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi +@@ -230,6 +230,13 @@ + #clock-cells = <0>; + }; + ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,lpi_en; ++ snps,wr_osr_lmt = <4>; ++ snps,rd_osr_lmt = <4>; ++ snps,blen = <256 128 64 32 0 0 0>; ++ }; ++ + tdm_ext: tdm-ext-clock { + compatible = "fixed-clock"; + clock-output-names = "tdm_ext"; +@@ -489,6 +496,68 @@ + #gpio-cells = <2>; + }; + ++ gmac0: ethernet@16030000 { ++ compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20"; ++ reg = <0x0 0x16030000 0x0 0x10000>; ++ clocks = <&aoncrg JH7110_AONCLK_GMAC0_AXI>, ++ <&aoncrg JH7110_AONCLK_GMAC0_AHB>, ++ <&syscrg JH7110_SYSCLK_GMAC0_PTP>, ++ <&aoncrg JH7110_AONCLK_GMAC0_TX_INV>, ++ <&syscrg JH7110_SYSCLK_GMAC0_GTXC>; ++ clock-names = "stmmaceth", "pclk", "ptp_ref", ++ "tx", "gtx"; ++ resets = <&aoncrg JH7110_AONRST_GMAC0_AXI>, ++ <&aoncrg JH7110_AONRST_GMAC0_AHB>; ++ reset-names = "stmmaceth", "ahb"; ++ interrupts = <7>, <6>, <5>; ++ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; ++ rx-fifo-depth = <2048>; ++ tx-fifo-depth = <2048>; ++ snps,multicast-filter-bins = <64>; ++ snps,perfect-filter-entries = <8>; ++ snps,fixed-burst; ++ snps,no-pbl-x8; ++ snps,force_thresh_dma_mode; ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,tso; ++ snps,en-tx-lpi-clockgating; ++ snps,txpbl = <16>; ++ snps,rxpbl = <16>; ++ starfive,syscon = <&aon_syscon 0xc 0x12>; ++ status = "disabled"; ++ }; ++ ++ gmac1: ethernet@16040000 { ++ compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20"; ++ reg = <0x0 0x16040000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_GMAC1_AXI>, ++ <&syscrg JH7110_SYSCLK_GMAC1_AHB>, ++ <&syscrg JH7110_SYSCLK_GMAC1_PTP>, ++ <&syscrg JH7110_SYSCLK_GMAC1_TX_INV>, ++ <&syscrg JH7110_SYSCLK_GMAC1_GTXC>; ++ clock-names = "stmmaceth", "pclk", "ptp_ref", ++ "tx", "gtx"; ++ resets = <&syscrg JH7110_SYSRST_GMAC1_AXI>, ++ <&syscrg JH7110_SYSRST_GMAC1_AHB>; ++ reset-names = "stmmaceth", "ahb"; ++ interrupts = <78>, <77>, <76>; ++ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; ++ rx-fifo-depth = <2048>; ++ tx-fifo-depth = <2048>; ++ snps,multicast-filter-bins = <64>; ++ snps,perfect-filter-entries = <8>; ++ snps,fixed-burst; ++ snps,no-pbl-x8; ++ snps,force_thresh_dma_mode; ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,tso; ++ snps,en-tx-lpi-clockgating; ++ snps,txpbl = <16>; ++ snps,rxpbl = <16>; ++ starfive,syscon = <&sys_syscon 0x90 0x2>; ++ status = "disabled"; ++ }; ++ + aoncrg: clock-controller@17000000 { + compatible = "starfive,jh7110-aoncrg"; + reg = <0x0 0x17000000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.1/0047-riscv-dts-starfive-visionfive-2-Add-configuration-of.patch b/target/linux/starfive/patches-6.1/0047-riscv-dts-starfive-visionfive-2-Add-configuration-of.patch new file mode 100644 index 0000000000..9fbdebf5f4 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0047-riscv-dts-starfive-visionfive-2-Add-configuration-of.patch @@ -0,0 +1,128 @@ +From 6fd84cb9cceaa711671500a92dcee5b1072ab95a Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Tue, 1 Nov 2022 18:11:02 +0800 +Subject: [PATCH 047/122] riscv: dts: starfive: visionfive 2: Add configuration + of gmac and phy + +v1.3B: + v1.3B uses motorcomm YT8531(rgmii-id phy) x2, need delay and + inverse configurations. + The tx_clk of v1.3B uses an external clock and needs to be + switched to an external clock source. + +v1.2A: + v1.2A gmac0 uses motorcomm YT8531(rgmii-id) PHY, and needs delay + configurations. + v1.2A gmac1 uses motorcomm YT8512(rmii) PHY, and needs to + switch rx and rx to external clock sources. + +Tested-by: Tommaso Merciai +Signed-off-by: Samin Guo +--- + .../jh7110-starfive-visionfive-2-v1.2a.dts | 13 +++++++ + .../jh7110-starfive-visionfive-2-v1.3b.dts | 27 +++++++++++++++ + .../jh7110-starfive-visionfive-2.dtsi | 34 +++++++++++++++++++ + 3 files changed, 74 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dts ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dts +@@ -11,3 +11,16 @@ + model = "StarFive VisionFive 2 v1.2A"; + compatible = "starfive,visionfive-2-v1.2a", "starfive,jh7110"; + }; ++ ++&gmac1 { ++ phy-mode = "rmii"; ++ assigned-clocks = <&syscrg JH7110_SYSCLK_GMAC1_TX>, ++ <&syscrg JH7110_SYSCLK_GMAC1_RX>; ++ assigned-clock-parents = <&syscrg JH7110_SYSCLK_GMAC1_RMII_RTX>, ++ <&syscrg JH7110_SYSCLK_GMAC1_RMII_RTX>; ++}; ++ ++&phy0 { ++ rx-internal-delay-ps = <1900>; ++ tx-internal-delay-ps = <1350>; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts +@@ -11,3 +11,30 @@ + model = "StarFive VisionFive 2 v1.3B"; + compatible = "starfive,visionfive-2-v1.3b", "starfive,jh7110"; + }; ++ ++&gmac0 { ++ starfive,tx-use-rgmii-clk; ++ assigned-clocks = <&aoncrg JH7110_AONCLK_GMAC0_TX>; ++ assigned-clock-parents = <&aoncrg JH7110_AONCLK_GMAC0_RMII_RTX>; ++}; ++ ++&gmac1 { ++ starfive,tx-use-rgmii-clk; ++ assigned-clocks = <&syscrg JH7110_SYSCLK_GMAC1_TX>; ++ assigned-clock-parents = <&syscrg JH7110_SYSCLK_GMAC1_RMII_RTX>; ++}; ++ ++&phy0 { ++ motorcomm,tx-clk-adj-enabled; ++ motorcomm,tx-clk-100-inverted; ++ motorcomm,tx-clk-1000-inverted; ++ rx-internal-delay-ps = <1500>; ++ tx-internal-delay-ps = <1500>; ++}; ++ ++&phy1 { ++ motorcomm,tx-clk-adj-enabled; ++ motorcomm,tx-clk-100-inverted; ++ rx-internal-delay-ps = <300>; ++ tx-internal-delay-ps = <0>; ++}; +--- 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,8 @@ + + / { + aliases { ++ ethernet0 = &gmac0; ++ ethernet1 = &gmac1; + i2c0 = &i2c0; + i2c2 = &i2c2; + i2c5 = &i2c5; +@@ -86,6 +88,38 @@ + clock-frequency = <49152000>; + }; + ++&gmac0 { ++ phy-handle = <&phy0>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ }; ++}; ++ ++&gmac1 { ++ phy-handle = <&phy1>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <0>; ++ }; ++ }; ++}; ++ + &i2c0 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; diff --git a/target/linux/starfive/patches-6.1/0048-dt-bindings-net-Add-Motorcomm-yt8xxx-ethernet-phy.patch b/target/linux/starfive/patches-6.1/0048-dt-bindings-net-Add-Motorcomm-yt8xxx-ethernet-phy.patch new file mode 100644 index 0000000000..376481ee0f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0048-dt-bindings-net-Add-Motorcomm-yt8xxx-ethernet-phy.patch @@ -0,0 +1,147 @@ +From 96edc2f71ea7ac6683011609f6d1f51ae9ea0b7a Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Thu, 2 Feb 2023 11:00:33 +0800 +Subject: [PATCH 048/122] dt-bindings: net: Add Motorcomm yt8xxx ethernet phy + +Add a YAML binding document for the Motorcomm yt8xxx Ethernet phy. + +Signed-off-by: Frank Sae +Reviewed-by: Rob Herring +Signed-off-by: David S. Miller +--- + .../bindings/net/motorcomm,yt8xxx.yaml | 117 ++++++++++++++++++ + .../devicetree/bindings/vendor-prefixes.yaml | 2 + + 2 files changed, 119 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml +@@ -0,0 +1,117 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/motorcomm,yt8xxx.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: MotorComm yt8xxx Ethernet PHY ++ ++maintainers: ++ - Frank Sae ++ ++allOf: ++ - $ref: ethernet-phy.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - ethernet-phy-id4f51.e91a ++ - ethernet-phy-id4f51.e91b ++ ++ rx-internal-delay-ps: ++ description: | ++ RGMII RX Clock Delay used only when PHY operates in RGMII mode with ++ internal delay (phy-mode is 'rgmii-id' or 'rgmii-rxid') in pico-seconds. ++ enum: [ 0, 150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, ++ 1800, 1900, 1950, 2050, 2100, 2200, 2250, 2350, 2500, 2650, 2800, ++ 2950, 3100, 3250, 3400, 3550, 3700, 3850, 4000, 4150 ] ++ default: 1950 ++ ++ tx-internal-delay-ps: ++ description: | ++ RGMII TX Clock Delay used only when PHY operates in RGMII mode with ++ internal delay (phy-mode is 'rgmii-id' or 'rgmii-txid') in pico-seconds. ++ enum: [ 0, 150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, 1650, 1800, ++ 1950, 2100, 2250 ] ++ default: 1950 ++ ++ motorcomm,clk-out-frequency-hz: ++ description: clock output on clock output pin. ++ enum: [0, 25000000, 125000000] ++ default: 0 ++ ++ motorcomm,keep-pll-enabled: ++ description: | ++ If set, keep the PLL enabled even if there is no link. Useful if you ++ want to use the clock output without an ethernet link. ++ type: boolean ++ ++ motorcomm,auto-sleep-disabled: ++ description: | ++ If set, PHY will not enter sleep mode and close AFE after unplug cable ++ for a timer. ++ type: boolean ++ ++ motorcomm,tx-clk-adj-enabled: ++ description: | ++ This configuration is mainly to adapt to VF2 with JH7110 SoC. ++ Useful if you want to use tx-clk-xxxx-inverted to adj the delay of tx clk. ++ type: boolean ++ ++ motorcomm,tx-clk-10-inverted: ++ description: | ++ Use original or inverted RGMII Transmit PHY Clock to drive the RGMII ++ Transmit PHY Clock delay train configuration when speed is 10Mbps. ++ type: boolean ++ ++ motorcomm,tx-clk-100-inverted: ++ description: | ++ Use original or inverted RGMII Transmit PHY Clock to drive the RGMII ++ Transmit PHY Clock delay train configuration when speed is 100Mbps. ++ type: boolean ++ ++ motorcomm,tx-clk-1000-inverted: ++ description: | ++ Use original or inverted RGMII Transmit PHY Clock to drive the RGMII ++ Transmit PHY Clock delay train configuration when speed is 1000Mbps. ++ type: boolean ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy-mode = "rgmii-id"; ++ ethernet-phy@4 { ++ /* Only needed to make DT lint tools work. Do not copy/paste ++ * into real DTS files. ++ */ ++ compatible = "ethernet-phy-id4f51.e91a"; ++ ++ reg = <4>; ++ rx-internal-delay-ps = <2100>; ++ tx-internal-delay-ps = <150>; ++ motorcomm,clk-out-frequency-hz = <0>; ++ motorcomm,keep-pll-enabled; ++ motorcomm,auto-sleep-disabled; ++ }; ++ }; ++ - | ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy-mode = "rgmii"; ++ ethernet-phy@5 { ++ /* Only needed to make DT lint tools work. Do not copy/paste ++ * into real DTS files. ++ */ ++ compatible = "ethernet-phy-id4f51.e91a"; ++ ++ reg = <5>; ++ motorcomm,clk-out-frequency-hz = <125000000>; ++ motorcomm,keep-pll-enabled; ++ motorcomm,auto-sleep-disabled; ++ }; ++ }; +--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml ++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml +@@ -831,6 +831,8 @@ patternProperties: + description: Moortec Semiconductor Ltd. + "^mosaixtech,.*": + description: Mosaix Technologies, Inc. ++ "^motorcomm,.*": ++ description: MotorComm, Inc. + "^motorola,.*": + description: Motorola, Inc. + "^moxa,.*": diff --git a/target/linux/starfive/patches-6.1/0049-dt-bindings-net-motorcomm-Add-pad-driver-strength-cf.patch b/target/linux/starfive/patches-6.1/0049-dt-bindings-net-motorcomm-Add-pad-driver-strength-cf.patch new file mode 100644 index 0000000000..b9e9c65251 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0049-dt-bindings-net-motorcomm-Add-pad-driver-strength-cf.patch @@ -0,0 +1,34 @@ +From 2d146c6e550a4fb7f24ca44739cf14594cc2f892 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Tue, 25 Apr 2023 18:51:15 +0800 +Subject: [PATCH 049/122] dt-bindings: net: motorcomm: Add pad driver strength + cfg + +The motorcomm phy (YT8531) supports the ability to adjust the drive +strength of the rx_clk/rx_data, the value range of pad driver +strength is 0 to 7. + +Signed-off-by: Samin Guo +--- + .../devicetree/bindings/net/motorcomm,yt8xxx.yaml | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml ++++ b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml +@@ -18,6 +18,16 @@ properties: + - ethernet-phy-id4f51.e91a + - ethernet-phy-id4f51.e91b + ++ rx-clk-driver-strength: ++ description: drive strength of rx_clk pad. ++ enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ] ++ default: 3 ++ ++ rx-data-driver-strength: ++ description: drive strength of rxd/rx_ctl rgmii pad. ++ enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ] ++ default: 3 ++ + rx-internal-delay-ps: + description: | + RGMII RX Clock Delay used only when PHY operates in RGMII mode with diff --git a/target/linux/starfive/patches-6.1/0050-riscv-dts-starfive-visionfive-2-v1.3B-Set-the-driver.patch b/target/linux/starfive/patches-6.1/0050-riscv-dts-starfive-visionfive-2-v1.3B-Set-the-driver.patch new file mode 100644 index 0000000000..8dca72ad16 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0050-riscv-dts-starfive-visionfive-2-v1.3B-Set-the-driver.patch @@ -0,0 +1,34 @@ +From c156cb9ec64669600c96dbb01bf38dd2370b1850 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Wed, 26 Apr 2023 14:41:12 +0800 +Subject: [PATCH 050/122] riscv: dts: starfive: visionfive-2-v1.3B: Set the + driver strength of RXC/RXD + +VisionFive 2 v1.3B needs to increase the driver strength of rxd/rxc +to increase the stability of gmac's transmission. + +Signed-off-by: Samin Guo +--- + .../boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts +@@ -28,6 +28,8 @@ + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-100-inverted; + motorcomm,tx-clk-1000-inverted; ++ rx-clk-driver-strength = <0x6>; ++ rx-data-driver-strength = <0x3>; + rx-internal-delay-ps = <1500>; + tx-internal-delay-ps = <1500>; + }; +@@ -35,6 +37,8 @@ + &phy1 { + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-100-inverted; ++ rx-clk-driver-strength = <0x6>; ++ rx-data-driver-strength = <0x3>; + rx-internal-delay-ps = <300>; + tx-internal-delay-ps = <0>; + }; diff --git a/target/linux/starfive/patches-6.1/0051-dt-bindings-clock-Add-StarFive-JH7110-System-Top-Gro.patch b/target/linux/starfive/patches-6.1/0051-dt-bindings-clock-Add-StarFive-JH7110-System-Top-Gro.patch new file mode 100644 index 0000000000..6617e79965 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0051-dt-bindings-clock-Add-StarFive-JH7110-System-Top-Gro.patch @@ -0,0 +1,193 @@ +From 84575863e4cf1a5dd877a11d31115c19004ac36a Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 18 May 2023 18:12:24 +0800 +Subject: [PATCH 051/122] dt-bindings: clock: Add StarFive JH7110 + System-Top-Group clock and reset generator + +Add bindings for the System-Top-Group clock and reset generator (STGCRG) +on the JH7110 RISC-V SoC by StarFive Ltd. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Xingyu Wu +--- + .../clock/starfive,jh7110-stgcrg.yaml | 82 +++++++++++++++++++ + .../dt-bindings/clock/starfive,jh7110-crg.h | 34 ++++++++ + .../dt-bindings/reset/starfive,jh7110-crg.h | 28 +++++++ + 3 files changed, 144 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-stgcrg.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-stgcrg.yaml +@@ -0,0 +1,82 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/starfive,jh7110-stgcrg.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 System-Top-Group Clock and Reset Generator ++ ++maintainers: ++ - Xingyu Wu ++ ++properties: ++ compatible: ++ const: starfive,jh7110-stgcrg ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: Main Oscillator (24 MHz) ++ - description: HIFI4 core ++ - description: STG AXI/AHB ++ - description: USB (125 MHz) ++ - description: CPU Bus ++ - description: HIFI4 Axi ++ - description: NOC STG Bus ++ - description: APB Bus ++ ++ clock-names: ++ items: ++ - const: osc ++ - const: hifi4_core ++ - const: stg_axiahb ++ - const: usb_125m ++ - const: cpu_bus ++ - const: hifi4_axi ++ - const: nocstg_bus ++ - const: apb_bus ++ ++ '#clock-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ '#reset-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - '#clock-cells' ++ - '#reset-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ stgcrg: clock-controller@10230000 { ++ compatible = "starfive,jh7110-stgcrg"; ++ reg = <0x10230000 0x10000>; ++ clocks = <&osc>, ++ <&syscrg JH7110_SYSCLK_HIFI4_CORE>, ++ <&syscrg JH7110_SYSCLK_STG_AXIAHB>, ++ <&syscrg JH7110_SYSCLK_USB_125M>, ++ <&syscrg JH7110_SYSCLK_CPU_BUS>, ++ <&syscrg JH7110_SYSCLK_HIFI4_AXI>, ++ <&syscrg JH7110_SYSCLK_NOCSTG_BUS>, ++ <&syscrg JH7110_SYSCLK_APB_BUS>; ++ clock-names = "osc", "hifi4_core", ++ "stg_axiahb", "usb_125m", ++ "cpu_bus", "hifi4_axi", ++ "nocstg_bus", "apb_bus"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; +--- a/include/dt-bindings/clock/starfive,jh7110-crg.h ++++ b/include/dt-bindings/clock/starfive,jh7110-crg.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 OR MIT */ + /* + * Copyright 2022 Emil Renner Berthing ++ * Copyright 2022 StarFive Technology Co., Ltd. + */ + + #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ +@@ -224,4 +225,37 @@ + + #define JH7110_AONCLK_END 14 + ++/* STGCRG clocks */ ++#define JH7110_STGCLK_HIFI4_CLK_CORE 0 ++#define JH7110_STGCLK_USB0_APB 1 ++#define JH7110_STGCLK_USB0_UTMI_APB 2 ++#define JH7110_STGCLK_USB0_AXI 3 ++#define JH7110_STGCLK_USB0_LPM 4 ++#define JH7110_STGCLK_USB0_STB 5 ++#define JH7110_STGCLK_USB0_APP_125 6 ++#define JH7110_STGCLK_USB0_REFCLK 7 ++#define JH7110_STGCLK_PCIE0_AXI_MST0 8 ++#define JH7110_STGCLK_PCIE0_APB 9 ++#define JH7110_STGCLK_PCIE0_TL 10 ++#define JH7110_STGCLK_PCIE1_AXI_MST0 11 ++#define JH7110_STGCLK_PCIE1_APB 12 ++#define JH7110_STGCLK_PCIE1_TL 13 ++#define JH7110_STGCLK_PCIE_SLV_MAIN 14 ++#define JH7110_STGCLK_SEC_AHB 15 ++#define JH7110_STGCLK_SEC_MISC_AHB 16 ++#define JH7110_STGCLK_GRP0_MAIN 17 ++#define JH7110_STGCLK_GRP0_BUS 18 ++#define JH7110_STGCLK_GRP0_STG 19 ++#define JH7110_STGCLK_GRP1_MAIN 20 ++#define JH7110_STGCLK_GRP1_BUS 21 ++#define JH7110_STGCLK_GRP1_STG 22 ++#define JH7110_STGCLK_GRP1_HIFI 23 ++#define JH7110_STGCLK_E2_RTC 24 ++#define JH7110_STGCLK_E2_CORE 25 ++#define JH7110_STGCLK_E2_DBG 26 ++#define JH7110_STGCLK_DMA1P_AXI 27 ++#define JH7110_STGCLK_DMA1P_AHB 28 ++ ++#define JH7110_STGCLK_END 29 ++ + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ */ +--- a/include/dt-bindings/reset/starfive,jh7110-crg.h ++++ b/include/dt-bindings/reset/starfive,jh7110-crg.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 OR MIT */ + /* + * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + + #ifndef __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ +@@ -151,4 +152,31 @@ + + #define JH7110_AONRST_END 8 + ++/* STGCRG resets */ ++#define JH7110_STGRST_SYSCON 0 ++#define JH7110_STGRST_HIFI4_CORE 1 ++#define JH7110_STGRST_HIFI4_AXI 2 ++#define JH7110_STGRST_SEC_AHB 3 ++#define JH7110_STGRST_E24_CORE 4 ++#define JH7110_STGRST_DMA1P_AXI 5 ++#define JH7110_STGRST_DMA1P_AHB 6 ++#define JH7110_STGRST_USB0_AXI 7 ++#define JH7110_STGRST_USB0_APB 8 ++#define JH7110_STGRST_USB0_UTMI_APB 9 ++#define JH7110_STGRST_USB0_PWRUP 10 ++#define JH7110_STGRST_PCIE0_AXI_MST0 11 ++#define JH7110_STGRST_PCIE0_AXI_SLV0 12 ++#define JH7110_STGRST_PCIE0_AXI_SLV 13 ++#define JH7110_STGRST_PCIE0_BRG 14 ++#define JH7110_STGRST_PCIE0_CORE 15 ++#define JH7110_STGRST_PCIE0_APB 16 ++#define JH7110_STGRST_PCIE1_AXI_MST0 17 ++#define JH7110_STGRST_PCIE1_AXI_SLV0 18 ++#define JH7110_STGRST_PCIE1_AXI_SLV 19 ++#define JH7110_STGRST_PCIE1_BRG 20 ++#define JH7110_STGRST_PCIE1_CORE 21 ++#define JH7110_STGRST_PCIE1_APB 22 ++ ++#define JH7110_STGRST_END 23 ++ + #endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ */ diff --git a/target/linux/starfive/patches-6.1/0052-clk-starfive-Add-StarFive-JH7110-System-Top-Group-cl.patch b/target/linux/starfive/patches-6.1/0052-clk-starfive-Add-StarFive-JH7110-System-Top-Group-cl.patch new file mode 100644 index 0000000000..88b24a9c6d --- /dev/null +++ b/target/linux/starfive/patches-6.1/0052-clk-starfive-Add-StarFive-JH7110-System-Top-Group-cl.patch @@ -0,0 +1,218 @@ +From 9a02d66b0515d987037d0229b99367412b9eb38c Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 May 2023 18:12:25 +0800 +Subject: [PATCH 052/122] clk: starfive: Add StarFive JH7110 System-Top-Group + clock driver + +Add driver for the StarFive JH7110 System-Top-Group clock controller. + +Co-developed-by: Xingyu Wu +Signed-off-by: Xingyu Wu +Signed-off-by: Emil Renner Berthing +--- + drivers/clk/starfive/Kconfig | 11 ++ + drivers/clk/starfive/Makefile | 1 + + .../clk/starfive/clk-starfive-jh7110-stg.c | 173 ++++++++++++++++++ + 3 files changed, 185 insertions(+) + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-stg.c + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -51,3 +51,14 @@ config CLK_STARFIVE_JH7110_AON + help + Say yes here to support the always-on clock controller on the + StarFive JH7110 SoC. ++ ++config CLK_STARFIVE_JH7110_STG ++ tristate "StarFive JH7110 System-Top-Group clock support" ++ depends on CLK_STARFIVE_JH7110_SYS ++ select AUXILIARY_BUS ++ select CLK_STARFIVE_JH71X0 ++ select RESET_STARFIVE_JH7110 ++ default m if ARCH_STARFIVE ++ help ++ Say yes here to support the System-Top-Group clock controller ++ on the StarFive JH7110 SoC. +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) + obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o ++obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-stg.c +@@ -0,0 +1,173 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7110 System-Top-Group Clock Driver ++ * ++ * Copyright (C) 2022 Emil Renner Berthing ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-starfive-jh7110.h" ++ ++/* external clocks */ ++#define JH7110_STGCLK_OSC (JH7110_STGCLK_END + 0) ++#define JH7110_STGCLK_HIFI4_CORE (JH7110_STGCLK_END + 1) ++#define JH7110_STGCLK_STG_AXIAHB (JH7110_STGCLK_END + 2) ++#define JH7110_STGCLK_USB_125M (JH7110_STGCLK_END + 3) ++#define JH7110_STGCLK_CPU_BUS (JH7110_STGCLK_END + 4) ++#define JH7110_STGCLK_HIFI4_AXI (JH7110_STGCLK_END + 5) ++#define JH7110_STGCLK_NOCSTG_BUS (JH7110_STGCLK_END + 6) ++#define JH7110_STGCLK_APB_BUS (JH7110_STGCLK_END + 7) ++#define JH7110_STGCLK_EXT_END (JH7110_STGCLK_END + 8) ++ ++static const struct jh71x0_clk_data jh7110_stgclk_data[] = { ++ /* hifi4 */ ++ JH71X0_GATE(JH7110_STGCLK_HIFI4_CLK_CORE, "hifi4_clk_core", 0, ++ JH7110_STGCLK_HIFI4_CORE), ++ /* usb */ ++ JH71X0_GATE(JH7110_STGCLK_USB0_APB, "usb0_apb", 0, JH7110_STGCLK_APB_BUS), ++ JH71X0_GATE(JH7110_STGCLK_USB0_UTMI_APB, "usb0_utmi_apb", 0, JH7110_STGCLK_APB_BUS), ++ JH71X0_GATE(JH7110_STGCLK_USB0_AXI, "usb0_axi", 0, JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GDIV(JH7110_STGCLK_USB0_LPM, "usb0_lpm", 0, 2, JH7110_STGCLK_OSC), ++ JH71X0_GDIV(JH7110_STGCLK_USB0_STB, "usb0_stb", 0, 4, JH7110_STGCLK_OSC), ++ JH71X0_GATE(JH7110_STGCLK_USB0_APP_125, "usb0_app_125", 0, JH7110_STGCLK_USB_125M), ++ JH71X0__DIV(JH7110_STGCLK_USB0_REFCLK, "usb0_refclk", 2, JH7110_STGCLK_OSC), ++ /* pci-e */ ++ JH71X0_GATE(JH7110_STGCLK_PCIE0_AXI_MST0, "pcie0_axi_mst0", 0, ++ JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_PCIE0_APB, "pcie0_apb", 0, JH7110_STGCLK_APB_BUS), ++ JH71X0_GATE(JH7110_STGCLK_PCIE0_TL, "pcie0_tl", 0, JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_PCIE1_AXI_MST0, "pcie1_axi_mst0", 0, ++ JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_PCIE1_APB, "pcie1_apb", 0, JH7110_STGCLK_APB_BUS), ++ JH71X0_GATE(JH7110_STGCLK_PCIE1_TL, "pcie1_tl", 0, JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_PCIE_SLV_MAIN, "pcie_slv_main", CLK_IS_CRITICAL, ++ JH7110_STGCLK_STG_AXIAHB), ++ /* security */ ++ JH71X0_GATE(JH7110_STGCLK_SEC_AHB, "sec_ahb", 0, JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_SEC_MISC_AHB, "sec_misc_ahb", 0, JH7110_STGCLK_STG_AXIAHB), ++ /* stg mtrx */ ++ JH71X0_GATE(JH7110_STGCLK_GRP0_MAIN, "mtrx_grp0_main", CLK_IS_CRITICAL, ++ JH7110_STGCLK_CPU_BUS), ++ JH71X0_GATE(JH7110_STGCLK_GRP0_BUS, "mtrx_grp0_bus", CLK_IS_CRITICAL, ++ JH7110_STGCLK_NOCSTG_BUS), ++ JH71X0_GATE(JH7110_STGCLK_GRP0_STG, "mtrx_grp0_stg", CLK_IS_CRITICAL, ++ JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_GRP1_MAIN, "mtrx_grp1_main", CLK_IS_CRITICAL, ++ JH7110_STGCLK_CPU_BUS), ++ JH71X0_GATE(JH7110_STGCLK_GRP1_BUS, "mtrx_grp1_bus", CLK_IS_CRITICAL, ++ JH7110_STGCLK_NOCSTG_BUS), ++ JH71X0_GATE(JH7110_STGCLK_GRP1_STG, "mtrx_grp1_stg", CLK_IS_CRITICAL, ++ JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_GRP1_HIFI, "mtrx_grp1_hifi", CLK_IS_CRITICAL, ++ JH7110_STGCLK_HIFI4_AXI), ++ /* e24_rvpi */ ++ JH71X0_GDIV(JH7110_STGCLK_E2_RTC, "e2_rtc", 0, 24, JH7110_STGCLK_OSC), ++ JH71X0_GATE(JH7110_STGCLK_E2_CORE, "e2_core", 0, JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_E2_DBG, "e2_dbg", 0, JH7110_STGCLK_STG_AXIAHB), ++ /* dw_sgdma1p */ ++ JH71X0_GATE(JH7110_STGCLK_DMA1P_AXI, "dma1p_axi", 0, JH7110_STGCLK_STG_AXIAHB), ++ JH71X0_GATE(JH7110_STGCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7110_STGCLK_STG_AXIAHB), ++}; ++ ++static struct clk_hw *jh7110_stgclk_get(struct of_phandle_args *clkspec, void *data) ++{ ++ struct jh71x0_clk_priv *priv = data; ++ unsigned int idx = clkspec->args[0]; ++ ++ if (idx < JH7110_STGCLK_END) ++ return &priv->reg[idx].hw; ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++static int jh7110_stgcrg_probe(struct platform_device *pdev) ++{ ++ struct jh71x0_clk_priv *priv; ++ unsigned int idx; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7110_STGCLK_END), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->rmw_lock); ++ priv->dev = &pdev->dev; ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ for (idx = 0; idx < JH7110_STGCLK_END; idx++) { ++ u32 max = jh7110_stgclk_data[idx].max; ++ struct clk_parent_data parents[4] = {}; ++ struct clk_init_data init = { ++ .name = jh7110_stgclk_data[idx].name, ++ .ops = starfive_jh71x0_clk_ops(max), ++ .parent_data = parents, ++ .num_parents = ++ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, ++ .flags = jh7110_stgclk_data[idx].flags, ++ }; ++ struct jh71x0_clk *clk = &priv->reg[idx]; ++ const char *fw_name[JH7110_STGCLK_EXT_END - JH7110_STGCLK_END] = { ++ "osc", ++ "hifi4_core", ++ "stg_axiahb", ++ "usb_125m", ++ "cpu_bus", ++ "hifi4_axi", ++ "nocstg_bus", ++ "apb_bus" ++ }; ++ unsigned int i; ++ ++ for (i = 0; i < init.num_parents; i++) { ++ unsigned int pidx = jh7110_stgclk_data[idx].parents[i]; ++ ++ if (pidx < JH7110_STGCLK_END) ++ parents[i].hw = &priv->reg[pidx].hw; ++ else if (pidx < JH7110_STGCLK_EXT_END) ++ parents[i].fw_name = fw_name[pidx - JH7110_STGCLK_END]; ++ } ++ ++ clk->hw.init = &init; ++ clk->idx = idx; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clk->hw); ++ if (ret) ++ return ret; ++ } ++ ++ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_stgclk_get, priv); ++ if (ret) ++ return ret; ++ ++ return jh7110_reset_controller_register(priv, "rst-stg", 2); ++} ++ ++static const struct of_device_id jh7110_stgcrg_match[] = { ++ { .compatible = "starfive,jh7110-stgcrg" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_stgcrg_match); ++ ++static struct platform_driver jh7110_stgcrg_driver = { ++ .probe = jh7110_stgcrg_probe, ++ .driver = { ++ .name = "clk-starfive-jh7110-stg", ++ .of_match_table = jh7110_stgcrg_match, ++ }, ++}; ++module_platform_driver(jh7110_stgcrg_driver); ++ ++MODULE_AUTHOR("Xingyu Wu "); ++MODULE_AUTHOR("Emil Renner Berthing "); ++MODULE_DESCRIPTION("StarFive JH7110 System-Top-Group clock driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0053-dt-bindings-clock-Add-StarFive-JH7110-Image-Signal-P.patch b/target/linux/starfive/patches-6.1/0053-dt-bindings-clock-Add-StarFive-JH7110-Image-Signal-P.patch new file mode 100644 index 0000000000..eda4a0280a --- /dev/null +++ b/target/linux/starfive/patches-6.1/0053-dt-bindings-clock-Add-StarFive-JH7110-Image-Signal-P.patch @@ -0,0 +1,156 @@ +From 70df2590923e262ce8bf2b4f497f3481511d4fd6 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 18 May 2023 18:12:26 +0800 +Subject: [PATCH 053/122] dt-bindings: clock: Add StarFive JH7110 + Image-Signal-Process clock and reset generator + +Add bindings for the Image-Signal-Process clock and reset +generator (ISPCRG) on the JH7110 RISC-V SoC by StarFive Ltd. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Xingyu Wu +--- + .../clock/starfive,jh7110-ispcrg.yaml | 87 +++++++++++++++++++ + .../dt-bindings/clock/starfive,jh7110-crg.h | 18 ++++ + .../dt-bindings/reset/starfive,jh7110-crg.h | 16 ++++ + 3 files changed, 121 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-ispcrg.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-ispcrg.yaml +@@ -0,0 +1,87 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/starfive,jh7110-ispcrg.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 Image-Signal-Process Clock and Reset Generator ++ ++maintainers: ++ - Xingyu Wu ++ ++properties: ++ compatible: ++ const: starfive,jh7110-ispcrg ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: ISP Top core ++ - description: ISP Top Axi ++ - description: NOC ISP Bus ++ - description: external DVP ++ ++ clock-names: ++ items: ++ - const: isp_top_core ++ - const: isp_top_axi ++ - const: noc_bus_isp_axi ++ - const: dvp_clk ++ ++ resets: ++ items: ++ - description: ISP Top core ++ - description: ISP Top Axi ++ - description: NOC ISP Bus ++ ++ '#clock-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ '#reset-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ power-domains: ++ maxItems: 1 ++ description: ++ ISP domain power ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - '#clock-cells' ++ - '#reset-cells' ++ - power-domains ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ #include ++ ++ ispcrg: clock-controller@19810000 { ++ compatible = "starfive,jh7110-ispcrg"; ++ reg = <0x19810000 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_ISP_TOP_CORE>, ++ <&syscrg JH7110_SYSCLK_ISP_TOP_AXI>, ++ <&syscrg JH7110_SYSCLK_NOC_BUS_ISP_AXI>, ++ <&dvp_clk>; ++ clock-names = "isp_top_core", "isp_top_axi", ++ "noc_bus_isp_axi", "dvp_clk"; ++ resets = <&syscrg JH7110_SYSRST_ISP_TOP>, ++ <&syscrg JH7110_SYSRST_ISP_TOP_AXI>, ++ <&syscrg JH7110_SYSRST_NOC_BUS_ISP_AXI>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ power-domains = <&pwrc JH7110_PD_ISP>; ++ }; +--- a/include/dt-bindings/clock/starfive,jh7110-crg.h ++++ b/include/dt-bindings/clock/starfive,jh7110-crg.h +@@ -258,4 +258,22 @@ + + #define JH7110_STGCLK_END 29 + ++/* ISPCRG clocks */ ++#define JH7110_ISPCLK_DOM4_APB_FUNC 0 ++#define JH7110_ISPCLK_MIPI_RX0_PXL 1 ++#define JH7110_ISPCLK_DVP_INV 2 ++#define JH7110_ISPCLK_M31DPHY_CFG_IN 3 ++#define JH7110_ISPCLK_M31DPHY_REF_IN 4 ++#define JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0 5 ++#define JH7110_ISPCLK_VIN_APB 6 ++#define JH7110_ISPCLK_VIN_SYS 7 ++#define JH7110_ISPCLK_VIN_PIXEL_IF0 8 ++#define JH7110_ISPCLK_VIN_PIXEL_IF1 9 ++#define JH7110_ISPCLK_VIN_PIXEL_IF2 10 ++#define JH7110_ISPCLK_VIN_PIXEL_IF3 11 ++#define JH7110_ISPCLK_VIN_P_AXI_WR 12 ++#define JH7110_ISPCLK_ISPV2_TOP_WRAPPER_C 13 ++ ++#define JH7110_ISPCLK_END 14 ++ + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ */ +--- a/include/dt-bindings/reset/starfive,jh7110-crg.h ++++ b/include/dt-bindings/reset/starfive,jh7110-crg.h +@@ -179,4 +179,20 @@ + + #define JH7110_STGRST_END 23 + ++/* ISPCRG resets */ ++#define JH7110_ISPRST_ISPV2_TOP_WRAPPER_P 0 ++#define JH7110_ISPRST_ISPV2_TOP_WRAPPER_C 1 ++#define JH7110_ISPRST_M31DPHY_HW 2 ++#define JH7110_ISPRST_M31DPHY_B09_AON 3 ++#define JH7110_ISPRST_VIN_APB 4 ++#define JH7110_ISPRST_VIN_PIXEL_IF0 5 ++#define JH7110_ISPRST_VIN_PIXEL_IF1 6 ++#define JH7110_ISPRST_VIN_PIXEL_IF2 7 ++#define JH7110_ISPRST_VIN_PIXEL_IF3 8 ++#define JH7110_ISPRST_VIN_SYS 9 ++#define JH7110_ISPRST_VIN_P_AXI_RD 10 ++#define JH7110_ISPRST_VIN_P_AXI_WR 11 ++ ++#define JH7110_ISPRST_END 12 ++ + #endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ */ diff --git a/target/linux/starfive/patches-6.1/0054-clk-starfive-Add-StarFive-JH7110-Image-Signal-Proces.patch b/target/linux/starfive/patches-6.1/0054-clk-starfive-Add-StarFive-JH7110-Image-Signal-Proces.patch new file mode 100644 index 0000000000..2e049e77dd --- /dev/null +++ b/target/linux/starfive/patches-6.1/0054-clk-starfive-Add-StarFive-JH7110-Image-Signal-Proces.patch @@ -0,0 +1,293 @@ +From 003c13d81b525a184c5ca551e536e6786e2d2f5c Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 18 May 2023 18:12:27 +0800 +Subject: [PATCH 054/122] clk: starfive: Add StarFive JH7110 + Image-Signal-Process clock driver + +Add driver for the StarFive JH7110 Image-Signal-Process clock controller. +And these clock controllers should power on and enable the clocks from +SYSCRG first before registering. + +Signed-off-by: Xingyu Wu +--- + drivers/clk/starfive/Kconfig | 11 + + drivers/clk/starfive/Makefile | 1 + + .../clk/starfive/clk-starfive-jh7110-isp.c | 232 ++++++++++++++++++ + drivers/clk/starfive/clk-starfive-jh7110.h | 6 + + 4 files changed, 250 insertions(+) + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -62,3 +62,14 @@ config CLK_STARFIVE_JH7110_STG + help + Say yes here to support the System-Top-Group clock controller + on the StarFive JH7110 SoC. ++ ++config CLK_STARFIVE_JH7110_ISP ++ tristate "StarFive JH7110 Image-Signal-Process clock support" ++ depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU ++ select AUXILIARY_BUS ++ select CLK_STARFIVE_JH71X0 ++ select RESET_STARFIVE_JH7110 ++ default m if ARCH_STARFIVE ++ help ++ Say yes here to support the Image-Signal-Process clock controller ++ on the StarFive JH7110 SoC. +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += + obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o ++obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c +@@ -0,0 +1,232 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7110 Image-Signal-Process Clock Driver ++ * ++ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-starfive-jh7110.h" ++ ++/* external clocks */ ++#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0) ++#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1) ++#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2) ++#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3) ++#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4) ++ ++static struct clk_bulk_data jh7110_isp_top_clks[] = { ++ { .id = "isp_top_core" }, ++ { .id = "isp_top_axi" } ++}; ++ ++static const struct jh71x0_clk_data jh7110_ispclk_data[] = { ++ /* syscon */ ++ JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15, ++ JH7110_ISPCLK_ISP_TOP_AXI), ++ JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8, ++ JH7110_ISPCLK_ISP_TOP_CORE), ++ JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK), ++ /* vin */ ++ JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFG_IN, "m31dphy_cfg_in", 16, ++ JH7110_ISPCLK_ISP_TOP_CORE), ++ JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REF_IN, "m31dphy_ref_in", 16, ++ JH7110_ISPCLK_ISP_TOP_CORE), ++ JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0, "m31dphy_tx_esc_lan0", 60, ++ JH7110_ISPCLK_ISP_TOP_CORE), ++ JH71X0_GATE(JH7110_ISPCLK_VIN_APB, "vin_apb", 0, ++ JH7110_ISPCLK_DOM4_APB_FUNC), ++ JH71X0__DIV(JH7110_ISPCLK_VIN_SYS, "vin_sys", 8, JH7110_ISPCLK_ISP_TOP_CORE), ++ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF0, "vin_pixel_if0", 0, ++ JH7110_ISPCLK_MIPI_RX0_PXL), ++ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF1, "vin_pixel_if1", 0, ++ JH7110_ISPCLK_MIPI_RX0_PXL), ++ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF2, "vin_pixel_if2", 0, ++ JH7110_ISPCLK_MIPI_RX0_PXL), ++ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF3, "vin_pixel_if3", 0, ++ JH7110_ISPCLK_MIPI_RX0_PXL), ++ JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 2, ++ JH7110_ISPCLK_MIPI_RX0_PXL, ++ JH7110_ISPCLK_DVP_INV), ++ /* ispv2_top_wrapper */ ++ JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_C, "ispv2_top_wrapper_c", 0, 2, ++ JH7110_ISPCLK_MIPI_RX0_PXL, ++ JH7110_ISPCLK_DVP_INV), ++}; ++ ++static inline int jh7110_isp_top_rst_init(struct jh71x0_clk_priv *priv) ++{ ++ struct reset_control *top_rsts; ++ ++ /* The resets should be shared and other ISP modules will use its. */ ++ top_rsts = devm_reset_control_array_get_shared(priv->dev); ++ if (IS_ERR(top_rsts)) ++ return dev_err_probe(priv->dev, PTR_ERR(top_rsts), ++ "failed to get top resets\n"); ++ ++ return reset_control_deassert(top_rsts); ++} ++ ++static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data) ++{ ++ struct jh71x0_clk_priv *priv = data; ++ unsigned int idx = clkspec->args[0]; ++ ++ if (idx < JH7110_ISPCLK_END) ++ return &priv->reg[idx].hw; ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++#ifdef CONFIG_PM ++static int jh7110_ispcrg_suspend(struct device *dev) ++{ ++ struct top_sysclk *top = dev_get_drvdata(dev); ++ ++ clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks); ++ ++ return 0; ++} ++ ++static int jh7110_ispcrg_resume(struct device *dev) ++{ ++ struct top_sysclk *top = dev_get_drvdata(dev); ++ ++ return clk_bulk_prepare_enable(top->top_clks_num, top->top_clks); ++} ++#endif ++ ++static const struct dev_pm_ops jh7110_ispcrg_pm_ops = { ++ SET_RUNTIME_PM_OPS(jh7110_ispcrg_suspend, jh7110_ispcrg_resume, NULL) ++}; ++ ++static int jh7110_ispcrg_probe(struct platform_device *pdev) ++{ ++ struct jh71x0_clk_priv *priv; ++ struct top_sysclk *top; ++ unsigned int idx; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, ++ struct_size(priv, reg, JH7110_ISPCLK_END), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL); ++ if (!top) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->rmw_lock); ++ priv->dev = &pdev->dev; ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ top->top_clks = jh7110_isp_top_clks; ++ top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks); ++ ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks); ++ if (ret) ++ return dev_err_probe(priv->dev, ret, "failed to get main clocks\n"); ++ dev_set_drvdata(priv->dev, top); ++ ++ /* enable power domain and clocks */ ++ pm_runtime_enable(priv->dev); ++ ret = pm_runtime_get_sync(priv->dev); ++ if (ret < 0) ++ return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); ++ ++ ret = jh7110_isp_top_rst_init(priv); ++ if (ret) ++ goto err_exit; ++ ++ for (idx = 0; idx < JH7110_ISPCLK_END; idx++) { ++ u32 max = jh7110_ispclk_data[idx].max; ++ struct clk_parent_data parents[4] = {}; ++ struct clk_init_data init = { ++ .name = jh7110_ispclk_data[idx].name, ++ .ops = starfive_jh71x0_clk_ops(max), ++ .parent_data = parents, ++ .num_parents = ++ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, ++ .flags = jh7110_ispclk_data[idx].flags, ++ }; ++ struct jh71x0_clk *clk = &priv->reg[idx]; ++ unsigned int i; ++ const char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = { ++ "isp_top_core", ++ "isp_top_axi", ++ "noc_bus_isp_axi", ++ "dvp_clk" ++ }; ++ ++ for (i = 0; i < init.num_parents; i++) { ++ unsigned int pidx = jh7110_ispclk_data[idx].parents[i]; ++ ++ if (pidx < JH7110_ISPCLK_END) ++ parents[i].hw = &priv->reg[pidx].hw; ++ else ++ parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END]; ++ } ++ ++ clk->hw.init = &init; ++ clk->idx = idx; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clk->hw); ++ if (ret) ++ goto err_exit; ++ } ++ ++ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_ispclk_get, priv); ++ if (ret) ++ goto err_exit; ++ ++ ret = jh7110_reset_controller_register(priv, "rst-isp", 3); ++ if (ret) ++ goto err_exit; ++ ++ return 0; ++ ++err_exit: ++ pm_runtime_put_sync(priv->dev); ++ pm_runtime_disable(priv->dev); ++ return ret; ++} ++ ++static int jh7110_ispcrg_remove(struct platform_device *pdev) ++{ ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id jh7110_ispcrg_match[] = { ++ { .compatible = "starfive,jh7110-ispcrg" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match); ++ ++static struct platform_driver jh7110_ispcrg_driver = { ++ .probe = jh7110_ispcrg_probe, ++ .remove = jh7110_ispcrg_remove, ++ .driver = { ++ .name = "clk-starfive-jh7110-isp", ++ .of_match_table = jh7110_ispcrg_match, ++ .pm = &jh7110_ispcrg_pm_ops, ++ }, ++}; ++module_platform_driver(jh7110_ispcrg_driver); ++ ++MODULE_AUTHOR("Xingyu Wu "); ++MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver"); ++MODULE_LICENSE("GPL"); +--- a/drivers/clk/starfive/clk-starfive-jh7110.h ++++ b/drivers/clk/starfive/clk-starfive-jh7110.h +@@ -4,6 +4,12 @@ + + #include "clk-starfive-jh71x0.h" + ++/* top clocks of ISP/VOUT domain from SYSCRG */ ++struct top_sysclk { ++ struct clk_bulk_data *top_clks; ++ int top_clks_num; ++}; ++ + int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + const char *adev_name, + u32 adev_id); diff --git a/target/linux/starfive/patches-6.1/0055-dt-bindings-clock-Add-StarFive-JH7110-Video-Output-c.patch b/target/linux/starfive/patches-6.1/0055-dt-bindings-clock-Add-StarFive-JH7110-Video-Output-c.patch new file mode 100644 index 0000000000..fabc6aac17 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0055-dt-bindings-clock-Add-StarFive-JH7110-Video-Output-c.patch @@ -0,0 +1,163 @@ +From 06fa910083f37ecbc9234c7230dcbbd4d83e2f02 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 18 May 2023 18:12:28 +0800 +Subject: [PATCH 055/122] dt-bindings: clock: Add StarFive JH7110 Video-Output + clock and reset generator + +Add bindings for the Video-Output clock and reset generator (VOUTCRG) +on the JH7110 RISC-V SoC by StarFive Ltd. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Xingyu Wu +--- + .../clock/starfive,jh7110-voutcrg.yaml | 90 +++++++++++++++++++ + .../dt-bindings/clock/starfive,jh7110-crg.h | 22 +++++ + .../dt-bindings/reset/starfive,jh7110-crg.h | 16 ++++ + 3 files changed, 128 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml +@@ -0,0 +1,90 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/starfive,jh7110-voutcrg.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 Video-Output Clock and Reset Generator ++ ++maintainers: ++ - Xingyu Wu ++ ++properties: ++ compatible: ++ const: starfive,jh7110-voutcrg ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: Vout Top core ++ - description: Vout Top Ahb ++ - description: Vout Top Axi ++ - description: Vout Top HDMI MCLK ++ - description: I2STX0 BCLK ++ - description: external HDMI pixel ++ ++ clock-names: ++ items: ++ - const: vout_src ++ - const: vout_top_ahb ++ - const: vout_top_axi ++ - const: vout_top_hdmitx0_mclk ++ - const: i2stx0_bclk ++ - const: hdmitx0_pixelclk ++ ++ resets: ++ maxItems: 1 ++ description: Vout Top core ++ ++ '#clock-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ '#reset-cells': ++ const: 1 ++ description: ++ See for valid indices. ++ ++ power-domains: ++ maxItems: 1 ++ description: ++ Vout domain power ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - '#clock-cells' ++ - '#reset-cells' ++ - power-domains ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ #include ++ ++ voutcrg: clock-controller@295C0000 { ++ compatible = "starfive,jh7110-voutcrg"; ++ reg = <0x295C0000 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_VOUT_SRC>, ++ <&syscrg JH7110_SYSCLK_VOUT_TOP_AHB>, ++ <&syscrg JH7110_SYSCLK_VOUT_TOP_AXI>, ++ <&syscrg JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK>, ++ <&syscrg JH7110_SYSCLK_I2STX0_BCLK>, ++ <&hdmitx0_pixelclk>; ++ clock-names = "vout_src", "vout_top_ahb", ++ "vout_top_axi", "vout_top_hdmitx0_mclk", ++ "i2stx0_bclk", "hdmitx0_pixelclk"; ++ resets = <&syscrg JH7110_SYSRST_VOUT_TOP_SRC>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ power-domains = <&pwrc JH7110_PD_VOUT>; ++ }; +--- a/include/dt-bindings/clock/starfive,jh7110-crg.h ++++ b/include/dt-bindings/clock/starfive,jh7110-crg.h +@@ -276,4 +276,26 @@ + + #define JH7110_ISPCLK_END 14 + ++/* VOUTCRG clocks */ ++#define JH7110_VOUTCLK_APB 0 ++#define JH7110_VOUTCLK_DC8200_PIX 1 ++#define JH7110_VOUTCLK_DSI_SYS 2 ++#define JH7110_VOUTCLK_TX_ESC 3 ++#define JH7110_VOUTCLK_DC8200_AXI 4 ++#define JH7110_VOUTCLK_DC8200_CORE 5 ++#define JH7110_VOUTCLK_DC8200_AHB 6 ++#define JH7110_VOUTCLK_DC8200_PIX0 7 ++#define JH7110_VOUTCLK_DC8200_PIX1 8 ++#define JH7110_VOUTCLK_DOM_VOUT_TOP_LCD 9 ++#define JH7110_VOUTCLK_DSITX_APB 10 ++#define JH7110_VOUTCLK_DSITX_SYS 11 ++#define JH7110_VOUTCLK_DSITX_DPI 12 ++#define JH7110_VOUTCLK_DSITX_TXESC 13 ++#define JH7110_VOUTCLK_MIPITX_DPHY_TXESC 14 ++#define JH7110_VOUTCLK_HDMI_TX_MCLK 15 ++#define JH7110_VOUTCLK_HDMI_TX_BCLK 16 ++#define JH7110_VOUTCLK_HDMI_TX_SYS 17 ++ ++#define JH7110_VOUTCLK_END 18 ++ + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ */ +--- a/include/dt-bindings/reset/starfive,jh7110-crg.h ++++ b/include/dt-bindings/reset/starfive,jh7110-crg.h +@@ -195,4 +195,20 @@ + + #define JH7110_ISPRST_END 12 + ++/* VOUTCRG resets */ ++#define JH7110_VOUTRST_DC8200_AXI 0 ++#define JH7110_VOUTRST_DC8200_AHB 1 ++#define JH7110_VOUTRST_DC8200_CORE 2 ++#define JH7110_VOUTRST_DSITX_DPI 3 ++#define JH7110_VOUTRST_DSITX_APB 4 ++#define JH7110_VOUTRST_DSITX_RXESC 5 ++#define JH7110_VOUTRST_DSITX_SYS 6 ++#define JH7110_VOUTRST_DSITX_TXBYTEHS 7 ++#define JH7110_VOUTRST_DSITX_TXESC 8 ++#define JH7110_VOUTRST_HDMI_TX_HDMI 9 ++#define JH7110_VOUTRST_MIPITX_DPHY_SYS 10 ++#define JH7110_VOUTRST_MIPITX_DPHY_TXBYTEHS 11 ++ ++#define JH7110_VOUTRST_END 12 ++ + #endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ */ diff --git a/target/linux/starfive/patches-6.1/0056-clk-starfive-Add-StarFive-JH7110-Video-Output-clock-.patch b/target/linux/starfive/patches-6.1/0056-clk-starfive-Add-StarFive-JH7110-Video-Output-clock-.patch new file mode 100644 index 0000000000..8c31af5089 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0056-clk-starfive-Add-StarFive-JH7110-Video-Output-clock-.patch @@ -0,0 +1,284 @@ +From 2e632d5c5f8b4577ac823f6a9dcf3eacdb14a0ba Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 18 May 2023 18:12:29 +0800 +Subject: [PATCH 056/122] clk: starfive: Add StarFive JH7110 Video-Output clock + driver + +Add driver for the StarFive JH7110 Video-Output clock controller. +And these clock controllers should power on and enable the clocks from +SYSCRG first before registering. + +Signed-off-by: Xingyu Wu +--- + drivers/clk/starfive/Kconfig | 11 + + drivers/clk/starfive/Makefile | 1 + + .../clk/starfive/clk-starfive-jh7110-vout.c | 239 ++++++++++++++++++ + 3 files changed, 251 insertions(+) + create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c + +--- a/drivers/clk/starfive/Kconfig ++++ b/drivers/clk/starfive/Kconfig +@@ -73,3 +73,14 @@ config CLK_STARFIVE_JH7110_ISP + help + Say yes here to support the Image-Signal-Process clock controller + on the StarFive JH7110 SoC. ++ ++config CLK_STARFIVE_JH7110_VOUT ++ tristate "StarFive JH7110 Video-Output clock support" ++ depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU ++ select AUXILIARY_BUS ++ select CLK_STARFIVE_JH71X0 ++ select RESET_STARFIVE_JH7110 ++ default m if ARCH_STARFIVE ++ help ++ Say yes here to support the Video-Output clock controller ++ on the StarFive JH7110 SoC. +--- a/drivers/clk/starfive/Makefile ++++ b/drivers/clk/starfive/Makefile +@@ -9,3 +9,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += + obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o + obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o ++obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o +--- /dev/null ++++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c +@@ -0,0 +1,239 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive JH7110 Video-Output Clock Driver ++ * ++ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk-starfive-jh7110.h" ++ ++/* external clocks */ ++#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0) ++#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1) ++#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2) ++#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3) ++#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4) ++#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5) ++#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6) ++ ++static struct clk_bulk_data jh7110_vout_top_clks[] = { ++ { .id = "vout_src" }, ++ { .id = "vout_top_ahb" } ++}; ++ ++static const struct jh71x0_clk_data jh7110_voutclk_data[] = { ++ /* divider */ ++ JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB), ++ JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC), ++ JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC), ++ JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB), ++ /* dc8200 */ ++ JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI), ++ JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI), ++ JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB), ++ JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2, ++ JH7110_VOUTCLK_DC8200_PIX, ++ JH7110_VOUTCLK_HDMITX0_PIXELCLK), ++ JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2, ++ JH7110_VOUTCLK_DC8200_PIX, ++ JH7110_VOUTCLK_HDMITX0_PIXELCLK), ++ /* LCD */ ++ JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2, ++ JH7110_VOUTCLK_DC8200_PIX0, ++ JH7110_VOUTCLK_DC8200_PIX1), ++ /* dsiTx */ ++ JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS), ++ JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS), ++ JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2, ++ JH7110_VOUTCLK_DC8200_PIX, ++ JH7110_VOUTCLK_HDMITX0_PIXELCLK), ++ JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC), ++ /* mipitx DPHY */ ++ JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0, ++ JH7110_VOUTCLK_TX_ESC), ++ /* hdmi */ ++ JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0, ++ JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK), ++ JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0, ++ JH7110_VOUTCLK_I2STX0_BCLK), ++ JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB), ++}; ++ ++static int jh7110_vout_top_rst_init(struct jh71x0_clk_priv *priv) ++{ ++ struct reset_control *top_rst; ++ ++ /* The reset should be shared and other Vout modules will use its. */ ++ top_rst = devm_reset_control_get_shared(priv->dev, NULL); ++ if (IS_ERR(top_rst)) ++ return dev_err_probe(priv->dev, PTR_ERR(top_rst), "failed to get top reset\n"); ++ ++ return reset_control_deassert(top_rst); ++} ++ ++static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data) ++{ ++ struct jh71x0_clk_priv *priv = data; ++ unsigned int idx = clkspec->args[0]; ++ ++ if (idx < JH7110_VOUTCLK_END) ++ return &priv->reg[idx].hw; ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++#ifdef CONFIG_PM ++static int jh7110_voutcrg_suspend(struct device *dev) ++{ ++ struct top_sysclk *top = dev_get_drvdata(dev); ++ ++ clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks); ++ ++ return 0; ++} ++ ++static int jh7110_voutcrg_resume(struct device *dev) ++{ ++ struct top_sysclk *top = dev_get_drvdata(dev); ++ ++ return clk_bulk_prepare_enable(top->top_clks_num, top->top_clks); ++} ++#endif ++ ++static const struct dev_pm_ops jh7110_voutcrg_pm_ops = { ++ SET_RUNTIME_PM_OPS(jh7110_voutcrg_suspend, jh7110_voutcrg_resume, NULL) ++}; ++ ++static int jh7110_voutcrg_probe(struct platform_device *pdev) ++{ ++ struct jh71x0_clk_priv *priv; ++ struct top_sysclk *top; ++ unsigned int idx; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, ++ struct_size(priv, reg, JH7110_VOUTCLK_END), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL); ++ if (!top) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->rmw_lock); ++ priv->dev = &pdev->dev; ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ top->top_clks = jh7110_vout_top_clks; ++ top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks); ++ ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks); ++ if (ret) ++ return dev_err_probe(priv->dev, ret, "failed to get top clocks\n"); ++ dev_set_drvdata(priv->dev, top); ++ ++ /* enable power domain and clocks */ ++ pm_runtime_enable(priv->dev); ++ ret = pm_runtime_get_sync(priv->dev); ++ if (ret < 0) ++ return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); ++ ++ ret = jh7110_vout_top_rst_init(priv); ++ if (ret) ++ goto err_exit; ++ ++ for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) { ++ u32 max = jh7110_voutclk_data[idx].max; ++ struct clk_parent_data parents[4] = {}; ++ struct clk_init_data init = { ++ .name = jh7110_voutclk_data[idx].name, ++ .ops = starfive_jh71x0_clk_ops(max), ++ .parent_data = parents, ++ .num_parents = ++ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, ++ .flags = jh7110_voutclk_data[idx].flags, ++ }; ++ struct jh71x0_clk *clk = &priv->reg[idx]; ++ unsigned int i; ++ const char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = { ++ "vout_src", ++ "vout_top_ahb", ++ "vout_top_axi", ++ "vout_top_hdmitx0_mclk", ++ "i2stx0_bclk", ++ "hdmitx0_pixelclk" ++ }; ++ ++ for (i = 0; i < init.num_parents; i++) { ++ unsigned int pidx = jh7110_voutclk_data[idx].parents[i]; ++ ++ if (pidx < JH7110_VOUTCLK_END) ++ parents[i].hw = &priv->reg[pidx].hw; ++ else if (pidx < JH7110_VOUTCLK_EXT_END) ++ parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END]; ++ } ++ ++ clk->hw.init = &init; ++ clk->idx = idx; ++ clk->max_div = max & JH71X0_CLK_DIV_MASK; ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clk->hw); ++ if (ret) ++ goto err_exit; ++ } ++ ++ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv); ++ if (ret) ++ goto err_exit; ++ ++ ret = jh7110_reset_controller_register(priv, "rst-vo", 4); ++ if (ret) ++ goto err_exit; ++ ++ return 0; ++ ++err_exit: ++ pm_runtime_put_sync(priv->dev); ++ pm_runtime_disable(priv->dev); ++ return ret; ++} ++ ++static int jh7110_voutcrg_remove(struct platform_device *pdev) ++{ ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id jh7110_voutcrg_match[] = { ++ { .compatible = "starfive,jh7110-voutcrg" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match); ++ ++static struct platform_driver jh7110_voutcrg_driver = { ++ .probe = jh7110_voutcrg_probe, ++ .remove = jh7110_voutcrg_remove, ++ .driver = { ++ .name = "clk-starfive-jh7110-vout", ++ .of_match_table = jh7110_voutcrg_match, ++ .pm = &jh7110_voutcrg_pm_ops, ++ }, ++}; ++module_platform_driver(jh7110_voutcrg_driver); ++ ++MODULE_AUTHOR("Xingyu Wu "); ++MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0057-reset-starfive-jh7110-Add-StarFive-STG-ISP-VOUT-rese.patch b/target/linux/starfive/patches-6.1/0057-reset-starfive-jh7110-Add-StarFive-STG-ISP-VOUT-rese.patch new file mode 100644 index 0000000000..197337bb70 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0057-reset-starfive-jh7110-Add-StarFive-STG-ISP-VOUT-rese.patch @@ -0,0 +1,61 @@ +From a04a6eb3b4d112f3600bbd783249f24a43797e7a Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 18 May 2023 18:12:31 +0800 +Subject: [PATCH 057/122] reset: starfive: jh7110: Add StarFive STG/ISP/VOUT + resets support + +Add new struct members and auxiliary_device_id of resets to support +System-Top-Group, Image-Signal-Process and Video-Output on the StarFive +JH7110 SoC. + +Signed-off-by: Xingyu Wu +--- + .../reset/starfive/reset-starfive-jh7110.c | 30 +++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/reset/starfive/reset-starfive-jh7110.c ++++ b/drivers/reset/starfive/reset-starfive-jh7110.c +@@ -31,6 +31,24 @@ static const struct jh7110_reset_info jh + .status_offset = 0x3C, + }; + ++static const struct jh7110_reset_info jh7110_stg_info = { ++ .nr_resets = JH7110_STGRST_END, ++ .assert_offset = 0x74, ++ .status_offset = 0x78, ++}; ++ ++static const struct jh7110_reset_info jh7110_isp_info = { ++ .nr_resets = JH7110_ISPRST_END, ++ .assert_offset = 0x38, ++ .status_offset = 0x3C, ++}; ++ ++static const struct jh7110_reset_info jh7110_vout_info = { ++ .nr_resets = JH7110_VOUTRST_END, ++ .assert_offset = 0x48, ++ .status_offset = 0x4C, ++}; ++ + static int jh7110_reset_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) + { +@@ -58,6 +76,18 @@ static const struct auxiliary_device_id + .name = "clk_starfive_jh7110_sys.rst-aon", + .driver_data = (kernel_ulong_t)&jh7110_aon_info, + }, ++ { ++ .name = "clk_starfive_jh7110_sys.rst-stg", ++ .driver_data = (kernel_ulong_t)&jh7110_stg_info, ++ }, ++ { ++ .name = "clk_starfive_jh7110_sys.rst-isp", ++ .driver_data = (kernel_ulong_t)&jh7110_isp_info, ++ }, ++ { ++ .name = "clk_starfive_jh7110_sys.rst-vo", ++ .driver_data = (kernel_ulong_t)&jh7110_vout_info, ++ }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(auxiliary, jh7110_reset_ids); diff --git a/target/linux/starfive/patches-6.1/0058-clk-starfive-update-jh7110-PLL-clock-driver.patch b/target/linux/starfive/patches-6.1/0058-clk-starfive-update-jh7110-PLL-clock-driver.patch new file mode 100644 index 0000000000..fc3da897a5 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0058-clk-starfive-update-jh7110-PLL-clock-driver.patch @@ -0,0 +1,819 @@ +From 758c8c4c30f495465f34735aef2458c0cc255a75 Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Wed, 31 May 2023 01:03:02 -0700 +Subject: [PATCH 058/122] clk: starfive: update jh7110 PLL clock driver + +Update the StarFive JH7110 PLL clock controller +and they work by reading and setting syscon registers. + +Signed-off-by: shanlong.li +--- + .../clk/starfive/clk-starfive-jh7110-pll.c | 269 +++++------------- + .../clk/starfive/clk-starfive-jh7110-pll.h | 264 +++++++++-------- + 2 files changed, 227 insertions(+), 306 deletions(-) + +--- a/drivers/clk/starfive/clk-starfive-jh7110-pll.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c +@@ -24,11 +24,29 @@ + #include + #include + #include ++#include + + #include + + #include "clk-starfive-jh7110-pll.h" + ++struct jh7110_pll_conf_variant { ++ unsigned int pll_nums; ++ struct jh7110_pll_syscon_conf conf[]; ++}; ++ ++static const struct jh7110_pll_conf_variant jh7110_pll_variant = { ++ .pll_nums = JH7110_PLLCLK_END, ++ .conf = { ++ JH7110_PLL(JH7110_CLK_PLL0_OUT, "pll0_out", ++ JH7110_PLL0_FREQ_MAX, jh7110_pll0_syscon_val_preset), ++ JH7110_PLL(JH7110_CLK_PLL1_OUT, "pll1_out", ++ JH7110_PLL1_FREQ_MAX, jh7110_pll1_syscon_val_preset), ++ JH7110_PLL(JH7110_CLK_PLL2_OUT, "pll2_out", ++ JH7110_PLL2_FREQ_MAX, jh7110_pll2_syscon_val_preset), ++ }, ++}; ++ + static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw) + { + return container_of(hw, struct jh7110_clk_pll_data, hw); +@@ -44,10 +62,9 @@ static unsigned long jh7110_pll_get_freq + unsigned long parent_rate) + { + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data); +- struct jh7110_pll_syscon_offset *offset = &data->offset; +- struct jh7110_pll_syscon_mask *mask = &data->mask; +- struct jh7110_pll_syscon_shift *shift = &data->shift; +- unsigned long freq = 0; ++ struct jh7110_pll_syscon_offset *offset = &data->conf.offsets; ++ struct jh7110_pll_syscon_mask *mask = &data->conf.masks; ++ struct jh7110_pll_syscon_shift *shift = &data->conf.shifts; + unsigned long frac_cal; + u32 dacpd; + u32 dsmpd; +@@ -57,32 +74,23 @@ static unsigned long jh7110_pll_get_freq + u32 frac; + u32 reg_val; + +- if (regmap_read(priv->syscon_regmap, offset->dacpd, ®_val)) +- goto read_error; ++ regmap_read(priv->syscon_regmap, offset->dacpd, ®_val); + dacpd = (reg_val & mask->dacpd) >> shift->dacpd; + +- if (regmap_read(priv->syscon_regmap, offset->dsmpd, ®_val)) +- goto read_error; ++ regmap_read(priv->syscon_regmap, offset->dsmpd, ®_val); + dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd; + +- if (regmap_read(priv->syscon_regmap, offset->fbdiv, ®_val)) +- goto read_error; ++ regmap_read(priv->syscon_regmap, offset->fbdiv, ®_val); + fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv; +- /* fbdiv value should be 8 to 4095 */ +- if (fbdiv < 8) +- goto read_error; + +- if (regmap_read(priv->syscon_regmap, offset->prediv, ®_val)) +- goto read_error; ++ regmap_read(priv->syscon_regmap, offset->prediv, ®_val); + prediv = (reg_val & mask->prediv) >> shift->prediv; + +- if (regmap_read(priv->syscon_regmap, offset->postdiv1, ®_val)) +- goto read_error; ++ regmap_read(priv->syscon_regmap, offset->postdiv1, ®_val); + /* postdiv1 = 2 ^ reg_val */ + postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1); + +- if (regmap_read(priv->syscon_regmap, offset->frac, ®_val)) +- goto read_error; ++ regmap_read(priv->syscon_regmap, offset->frac, ®_val); + frac = (reg_val & mask->frac) >> shift->frac; + + /* +@@ -95,14 +103,11 @@ static unsigned long jh7110_pll_get_freq + else if (dacpd == 0 && dsmpd == 0) + frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24); + else +- goto read_error; ++ return 0; + + /* Fvco = Fref * (NI + NF) / M / Q1 */ +- freq = parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE * +- (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1; +- +-read_error: +- return freq; ++ return (parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE * ++ (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1); + } + + static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2) +@@ -114,40 +119,27 @@ static unsigned long jh7110_pll_rate_sub + static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data, + unsigned long rate) + { +- const struct starfive_pll_syscon_value *syscon_val; ++ const struct jh7110_pll_syscon_val *val; + unsigned int id; +- unsigned int pll_arry_size; + unsigned long rate_diff; + +- if (data->idx == JH7110_CLK_PLL0_OUT) +- pll_arry_size = ARRAY_SIZE(jh7110_pll0_syscon_freq); +- else if (data->idx == JH7110_CLK_PLL1_OUT) +- pll_arry_size = ARRAY_SIZE(jh7110_pll1_syscon_freq); +- else +- pll_arry_size = ARRAY_SIZE(jh7110_pll2_syscon_freq); +- + /* compare the frequency one by one from small to large in order */ +- for (id = 0; id < pll_arry_size; id++) { +- if (data->idx == JH7110_CLK_PLL0_OUT) +- syscon_val = &jh7110_pll0_syscon_freq[id]; +- else if (data->idx == JH7110_CLK_PLL1_OUT) +- syscon_val = &jh7110_pll1_syscon_freq[id]; +- else +- syscon_val = &jh7110_pll2_syscon_freq[id]; ++ for (id = 0; id < data->conf.preset_val_nums; id++) { ++ val = &data->conf.preset_val[id]; + +- if (rate == syscon_val->freq) ++ if (rate == val->freq) + goto match_end; + + /* select near frequency */ +- if (rate < syscon_val->freq) { ++ if (rate < val->freq) { + /* The last frequency is closer to the target rate than this time. */ + if (id > 0) +- if (rate_diff < jh7110_pll_rate_sub_fabs(rate, syscon_val->freq)) ++ if (rate_diff < jh7110_pll_rate_sub_fabs(rate, val->freq)) + id--; + + goto match_end; + } else { +- rate_diff = jh7110_pll_rate_sub_fabs(rate, syscon_val->freq); ++ rate_diff = jh7110_pll_rate_sub_fabs(rate, val->freq); + } + } + +@@ -158,54 +150,34 @@ match_end: + static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data) + { + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data); +- struct jh7110_pll_syscon_offset *offset = &data->offset; +- struct jh7110_pll_syscon_mask *mask = &data->mask; +- struct jh7110_pll_syscon_shift *shift = &data->shift; +- unsigned int freq_idx = data->freq_select_idx; +- const struct starfive_pll_syscon_value *syscon_val; +- int ret; ++ struct jh7110_pll_syscon_offset *offset = &data->conf.offsets; ++ struct jh7110_pll_syscon_mask *mask = &data->conf.masks; ++ struct jh7110_pll_syscon_shift *shift = &data->conf.shifts; ++ const struct jh7110_pll_syscon_val *val = &data->conf.preset_val[data->freq_select_idx]; + +- if (data->idx == JH7110_CLK_PLL0_OUT) +- syscon_val = &jh7110_pll0_syscon_freq[freq_idx]; +- else if (data->idx == JH7110_CLK_PLL1_OUT) +- syscon_val = &jh7110_pll1_syscon_freq[freq_idx]; +- else +- syscon_val = &jh7110_pll2_syscon_freq[freq_idx]; ++ /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */ ++ if (val->dacpd == 0 && val->dsmpd == 0) ++ regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac, ++ (val->frac << shift->frac)); ++ else if (val->dacpd != val->dsmpd) ++ return -EINVAL; + +- ret = regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd, +- (syscon_val->dacpd << shift->dacpd)); +- if (ret) +- goto set_failed; +- +- ret = regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd, +- (syscon_val->dsmpd << shift->dsmpd)); +- if (ret) +- goto set_failed; +- +- ret = regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv, +- (syscon_val->prediv << shift->prediv)); +- if (ret) +- goto set_failed; +- +- ret = regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv, +- (syscon_val->fbdiv << shift->fbdiv)); +- if (ret) +- goto set_failed; +- +- ret = regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1, +- ((syscon_val->postdiv1 >> 1) << shift->postdiv1)); +- if (ret) +- goto set_failed; ++ /* fbdiv value should be 8 to 4095 */ ++ if (val->fbdiv < 8) ++ return -EINVAL; + +- /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */ +- if (syscon_val->dacpd == 0 && syscon_val->dsmpd == 0) +- ret = regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac, +- (syscon_val->frac << shift->frac)); +- else if (syscon_val->dacpd != syscon_val->dsmpd) +- ret = -EINVAL; ++ regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd, ++ (val->dacpd << shift->dacpd)); ++ regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd, ++ (val->dsmpd << shift->dsmpd)); ++ regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv, ++ (val->prediv << shift->prediv)); ++ regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv, ++ (val->fbdiv << shift->fbdiv)); ++ regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1, ++ ((val->postdiv1 >> 1) << shift->postdiv1)); + +-set_failed: +- return ret; ++ return 0; + } + + static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +@@ -220,13 +192,7 @@ static int jh7110_pll_determine_rate(str + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw); + + jh7110_pll_select_near_freq_id(data, req->rate); +- +- if (data->idx == JH7110_CLK_PLL0_OUT) +- req->rate = jh7110_pll0_syscon_freq[data->freq_select_idx].freq; +- else if (data->idx == JH7110_CLK_PLL1_OUT) +- req->rate = jh7110_pll1_syscon_freq[data->freq_select_idx].freq; +- else +- req->rate = jh7110_pll2_syscon_freq[data->freq_select_idx].freq; ++ req->rate = data->conf.preset_val[data->freq_select_idx].freq; + + return 0; + } +@@ -270,92 +236,12 @@ static const struct clk_ops jh7110_pll_o + .debug_init = jh7110_pll_debug_init, + }; + +-/* get offset, mask and shift of PLL(x) syscon */ +-static int jh7110_pll_data_get(struct jh7110_clk_pll_data *data, int index) +-{ +- struct jh7110_pll_syscon_offset *offset = &data->offset; +- struct jh7110_pll_syscon_mask *mask = &data->mask; +- struct jh7110_pll_syscon_shift *shift = &data->shift; +- +- if (index == JH7110_CLK_PLL0_OUT) { +- offset->dacpd = STARFIVE_JH7110_PLL0_DACPD_OFFSET; +- offset->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_OFFSET; +- offset->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_OFFSET; +- offset->frac = STARFIVE_JH7110_PLL0_FRAC_OFFSET; +- offset->prediv = STARFIVE_JH7110_PLL0_PREDIV_OFFSET; +- offset->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET; +- +- mask->dacpd = STARFIVE_JH7110_PLL0_DACPD_MASK; +- mask->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_MASK; +- mask->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_MASK; +- mask->frac = STARFIVE_JH7110_PLL0_FRAC_MASK; +- mask->prediv = STARFIVE_JH7110_PLL0_PREDIV_MASK; +- mask->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_MASK; +- +- shift->dacpd = STARFIVE_JH7110_PLL0_DACPD_SHIFT; +- shift->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_SHIFT; +- shift->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_SHIFT; +- shift->frac = STARFIVE_JH7110_PLL0_FRAC_SHIFT; +- shift->prediv = STARFIVE_JH7110_PLL0_PREDIV_SHIFT; +- shift->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT; +- +- } else if (index == JH7110_CLK_PLL1_OUT) { +- offset->dacpd = STARFIVE_JH7110_PLL1_DACPD_OFFSET; +- offset->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_OFFSET; +- offset->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_OFFSET; +- offset->frac = STARFIVE_JH7110_PLL1_FRAC_OFFSET; +- offset->prediv = STARFIVE_JH7110_PLL1_PREDIV_OFFSET; +- offset->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET; +- +- mask->dacpd = STARFIVE_JH7110_PLL1_DACPD_MASK; +- mask->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_MASK; +- mask->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_MASK; +- mask->frac = STARFIVE_JH7110_PLL1_FRAC_MASK; +- mask->prediv = STARFIVE_JH7110_PLL1_PREDIV_MASK; +- mask->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_MASK; +- +- shift->dacpd = STARFIVE_JH7110_PLL1_DACPD_SHIFT; +- shift->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_SHIFT; +- shift->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_SHIFT; +- shift->frac = STARFIVE_JH7110_PLL1_FRAC_SHIFT; +- shift->prediv = STARFIVE_JH7110_PLL1_PREDIV_SHIFT; +- shift->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT; +- +- } else if (index == JH7110_CLK_PLL2_OUT) { +- offset->dacpd = STARFIVE_JH7110_PLL2_DACPD_OFFSET; +- offset->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_OFFSET; +- offset->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_OFFSET; +- offset->frac = STARFIVE_JH7110_PLL2_FRAC_OFFSET; +- offset->prediv = STARFIVE_JH7110_PLL2_PREDIV_OFFSET; +- offset->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET; +- +- mask->dacpd = STARFIVE_JH7110_PLL2_DACPD_MASK; +- mask->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_MASK; +- mask->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_MASK; +- mask->frac = STARFIVE_JH7110_PLL2_FRAC_MASK; +- mask->prediv = STARFIVE_JH7110_PLL2_PREDIV_MASK; +- mask->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_MASK; +- +- shift->dacpd = STARFIVE_JH7110_PLL2_DACPD_SHIFT; +- shift->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_SHIFT; +- shift->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_SHIFT; +- shift->frac = STARFIVE_JH7110_PLL2_FRAC_SHIFT; +- shift->prediv = STARFIVE_JH7110_PLL2_PREDIV_SHIFT; +- shift->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT; +- +- } else { +- return -ENOENT; +- } +- +- return 0; +-} +- + static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data) + { + struct jh7110_clk_pll_priv *priv = data; + unsigned int idx = clkspec->args[0]; + +- if (idx < JH7110_PLLCLK_END) ++ if (idx < priv->pll_nums) + return &priv->data[idx].hw; + + return ERR_PTR(-EINVAL); +@@ -363,17 +249,17 @@ static struct clk_hw *jh7110_pll_get(str + + static int jh7110_pll_probe(struct platform_device *pdev) + { +- const char *pll_name[JH7110_PLLCLK_END] = { +- "pll0_out", +- "pll1_out", +- "pll2_out" +- }; ++ const struct jh7110_pll_conf_variant *variant; + struct jh7110_clk_pll_priv *priv; + struct jh7110_clk_pll_data *data; + int ret; + unsigned int idx; + +- priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, JH7110_PLLCLK_END), ++ variant = of_device_get_match_data(&pdev->dev); ++ if (!variant) ++ return -ENOMEM; ++ ++ priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, variant->pll_nums), + GFP_KERNEL); + if (!priv) + return -ENOMEM; +@@ -383,12 +269,13 @@ static int jh7110_pll_probe(struct platf + if (IS_ERR(priv->syscon_regmap)) + return PTR_ERR(priv->syscon_regmap); + +- for (idx = 0; idx < JH7110_PLLCLK_END; idx++) { ++ priv->pll_nums = variant->pll_nums; ++ for (idx = 0; idx < priv->pll_nums; idx++) { + struct clk_parent_data parents = { + .index = 0, + }; + struct clk_init_data init = { +- .name = pll_name[idx], ++ .name = variant->conf[idx].name, + .ops = &jh7110_pll_ops, + .parent_data = &parents, + .num_parents = 1, +@@ -396,11 +283,7 @@ static int jh7110_pll_probe(struct platf + }; + + data = &priv->data[idx]; +- +- ret = jh7110_pll_data_get(data, idx); +- if (ret) +- return ret; +- ++ data->conf = variant->conf[idx]; + data->hw.init = &init; + data->idx = idx; + +@@ -413,7 +296,7 @@ static int jh7110_pll_probe(struct platf + } + + static const struct of_device_id jh7110_pll_match[] = { +- { .compatible = "starfive,jh7110-pll" }, ++ { .compatible = "starfive,jh7110-pll", .data = &jh7110_pll_variant }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, jh7110_pll_match); +--- a/drivers/clk/starfive/clk-starfive-jh7110-pll.h ++++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h +@@ -13,62 +13,93 @@ + /* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */ + #define STARFIVE_PLL_FRAC_PATR_SIZE 1000 + +-#define STARFIVE_JH7110_PLL0_DACPD_OFFSET 0x18 +-#define STARFIVE_JH7110_PLL0_DACPD_SHIFT 24 +-#define STARFIVE_JH7110_PLL0_DACPD_MASK BIT(24) +-#define STARFIVE_JH7110_PLL0_DSMPD_OFFSET 0x18 +-#define STARFIVE_JH7110_PLL0_DSMPD_SHIFT 25 +-#define STARFIVE_JH7110_PLL0_DSMPD_MASK BIT(25) +-#define STARFIVE_JH7110_PLL0_FBDIV_OFFSET 0x1c +-#define STARFIVE_JH7110_PLL0_FBDIV_SHIFT 0 +-#define STARFIVE_JH7110_PLL0_FBDIV_MASK GENMASK(11, 0) +-#define STARFIVE_JH7110_PLL0_FRAC_OFFSET 0x20 +-#define STARFIVE_JH7110_PLL0_FRAC_SHIFT 0 +-#define STARFIVE_JH7110_PLL0_FRAC_MASK GENMASK(23, 0) +-#define STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET 0x20 +-#define STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT 28 +-#define STARFIVE_JH7110_PLL0_POSTDIV1_MASK GENMASK(29, 28) +-#define STARFIVE_JH7110_PLL0_PREDIV_OFFSET 0x24 +-#define STARFIVE_JH7110_PLL0_PREDIV_SHIFT 0 +-#define STARFIVE_JH7110_PLL0_PREDIV_MASK GENMASK(5, 0) +- +-#define STARFIVE_JH7110_PLL1_DACPD_OFFSET 0x24 +-#define STARFIVE_JH7110_PLL1_DACPD_SHIFT 15 +-#define STARFIVE_JH7110_PLL1_DACPD_MASK BIT(15) +-#define STARFIVE_JH7110_PLL1_DSMPD_OFFSET 0x24 +-#define STARFIVE_JH7110_PLL1_DSMPD_SHIFT 16 +-#define STARFIVE_JH7110_PLL1_DSMPD_MASK BIT(16) +-#define STARFIVE_JH7110_PLL1_FBDIV_OFFSET 0x24 +-#define STARFIVE_JH7110_PLL1_FBDIV_SHIFT 17 +-#define STARFIVE_JH7110_PLL1_FBDIV_MASK GENMASK(28, 17) +-#define STARFIVE_JH7110_PLL1_FRAC_OFFSET 0x28 +-#define STARFIVE_JH7110_PLL1_FRAC_SHIFT 0 +-#define STARFIVE_JH7110_PLL1_FRAC_MASK GENMASK(23, 0) +-#define STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET 0x28 +-#define STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT 28 +-#define STARFIVE_JH7110_PLL1_POSTDIV1_MASK GENMASK(29, 28) +-#define STARFIVE_JH7110_PLL1_PREDIV_OFFSET 0x2c +-#define STARFIVE_JH7110_PLL1_PREDIV_SHIFT 0 +-#define STARFIVE_JH7110_PLL1_PREDIV_MASK GENMASK(5, 0) +- +-#define STARFIVE_JH7110_PLL2_DACPD_OFFSET 0x2c +-#define STARFIVE_JH7110_PLL2_DACPD_SHIFT 15 +-#define STARFIVE_JH7110_PLL2_DACPD_MASK BIT(15) +-#define STARFIVE_JH7110_PLL2_DSMPD_OFFSET 0x2c +-#define STARFIVE_JH7110_PLL2_DSMPD_SHIFT 16 +-#define STARFIVE_JH7110_PLL2_DSMPD_MASK BIT(16) +-#define STARFIVE_JH7110_PLL2_FBDIV_OFFSET 0x2c +-#define STARFIVE_JH7110_PLL2_FBDIV_SHIFT 17 +-#define STARFIVE_JH7110_PLL2_FBDIV_MASK GENMASK(28, 17) +-#define STARFIVE_JH7110_PLL2_FRAC_OFFSET 0x30 +-#define STARFIVE_JH7110_PLL2_FRAC_SHIFT 0 +-#define STARFIVE_JH7110_PLL2_FRAC_MASK GENMASK(23, 0) +-#define STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET 0x30 +-#define STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT 28 +-#define STARFIVE_JH7110_PLL2_POSTDIV1_MASK GENMASK(29, 28) +-#define STARFIVE_JH7110_PLL2_PREDIV_OFFSET 0x34 +-#define STARFIVE_JH7110_PLL2_PREDIV_SHIFT 0 +-#define STARFIVE_JH7110_PLL2_PREDIV_MASK GENMASK(5, 0) ++#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_OFFSET 0x18 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_SHIFT 24 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_MASK BIT(24) ++#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_OFFSET 0x18 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_SHIFT 25 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_MASK BIT(25) ++#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_OFFSET 0x1c ++#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_MASK GENMASK(11, 0) ++#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_OFFSET 0x20 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_MASK GENMASK(23, 0) ++#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_OFFSET 0x20 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_SHIFT 28 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_MASK GENMASK(29, 28) ++#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_OFFSET 0x24 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_MASK GENMASK(5, 0) ++ ++#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_OFFSET 0x24 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_SHIFT 15 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_MASK BIT(15) ++#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_OFFSET 0x24 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_SHIFT 16 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_MASK BIT(16) ++#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_OFFSET 0x24 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_SHIFT 17 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_MASK GENMASK(28, 17) ++#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_OFFSET 0x28 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_MASK GENMASK(23, 0) ++#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_OFFSET 0x28 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_SHIFT 28 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_MASK GENMASK(29, 28) ++#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_OFFSET 0x2c ++#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_MASK GENMASK(5, 0) ++ ++#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_OFFSET 0x2c ++#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_SHIFT 15 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_MASK BIT(15) ++#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_OFFSET 0x2c ++#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_SHIFT 16 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_MASK BIT(16) ++#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_OFFSET 0x2c ++#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_SHIFT 17 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_MASK GENMASK(28, 17) ++#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_OFFSET 0x30 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_MASK GENMASK(23, 0) ++#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_OFFSET 0x30 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_SHIFT 28 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_MASK GENMASK(29, 28) ++#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_OFFSET 0x34 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_SHIFT 0 ++#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_MASK GENMASK(5, 0) ++ ++#define JH7110_PLL(_idx, _name, _nums, _val) \ ++[_idx] = { \ ++ .name = _name, \ ++ .offsets = { \ ++ .dacpd = STARFIVE_##_idx##_DACPD_OFFSET, \ ++ .dsmpd = STARFIVE_##_idx##_DSMPD_OFFSET, \ ++ .fbdiv = STARFIVE_##_idx##_FBDIV_OFFSET, \ ++ .frac = STARFIVE_##_idx##_FRAC_OFFSET, \ ++ .prediv = STARFIVE_##_idx##_PREDIV_OFFSET, \ ++ .postdiv1 = STARFIVE_##_idx##_POSTDIV1_OFFSET, \ ++ }, \ ++ .masks = { \ ++ .dacpd = STARFIVE_##_idx##_DACPD_MASK, \ ++ .dsmpd = STARFIVE_##_idx##_DSMPD_MASK, \ ++ .fbdiv = STARFIVE_##_idx##_FBDIV_MASK, \ ++ .frac = STARFIVE_##_idx##_FRAC_MASK, \ ++ .prediv = STARFIVE_##_idx##_PREDIV_MASK, \ ++ .postdiv1 = STARFIVE_##_idx##_POSTDIV1_MASK, \ ++ }, \ ++ .shifts = { \ ++ .dacpd = STARFIVE_##_idx##_DACPD_SHIFT, \ ++ .dsmpd = STARFIVE_##_idx##_DSMPD_SHIFT, \ ++ .fbdiv = STARFIVE_##_idx##_FBDIV_SHIFT, \ ++ .frac = STARFIVE_##_idx##_FRAC_SHIFT, \ ++ .prediv = STARFIVE_##_idx##_PREDIV_SHIFT, \ ++ .postdiv1 = STARFIVE_##_idx##_POSTDIV1_SHIFT, \ ++ }, \ ++ .preset_val_nums = _nums, \ ++ .preset_val = _val, \ ++} + + struct jh7110_pll_syscon_offset { + unsigned int dacpd; +@@ -97,23 +128,7 @@ struct jh7110_pll_syscon_shift { + char postdiv1; + }; + +-struct jh7110_clk_pll_data { +- struct clk_hw hw; +- unsigned int idx; +- unsigned int freq_select_idx; +- +- struct jh7110_pll_syscon_offset offset; +- struct jh7110_pll_syscon_mask mask; +- struct jh7110_pll_syscon_shift shift; +-}; +- +-struct jh7110_clk_pll_priv { +- struct device *dev; +- struct regmap *syscon_regmap; +- struct jh7110_clk_pll_data data[]; +-}; +- +-struct starfive_pll_syscon_value { ++struct jh7110_pll_syscon_val { + unsigned long freq; + u32 prediv; + u32 fbdiv; +@@ -126,31 +141,54 @@ struct starfive_pll_syscon_value { + u32 frac; + }; + +-enum starfive_pll0_freq_index { +- PLL0_FREQ_375 = 0, +- PLL0_FREQ_500, +- PLL0_FREQ_625, +- PLL0_FREQ_750, +- PLL0_FREQ_875, +- PLL0_FREQ_1000, +- PLL0_FREQ_1250, +- PLL0_FREQ_1375, +- PLL0_FREQ_1500, +- PLL0_FREQ_MAX +-}; +- +-enum starfive_pll1_freq_index { +- PLL1_FREQ_1066 = 0, +- PLL1_FREQ_1200, +- PLL1_FREQ_1400, +- PLL1_FREQ_1600, +- PLL1_FREQ_MAX +-}; +- +-enum starfive_pll2_freq_index { +- PLL2_FREQ_1188 = 0, +- PLL2_FREQ_12288, +- PLL2_FREQ_MAX ++struct jh7110_pll_syscon_conf { ++ char *name; ++ struct jh7110_pll_syscon_offset offsets; ++ struct jh7110_pll_syscon_mask masks; ++ struct jh7110_pll_syscon_shift shifts; ++ unsigned int preset_val_nums; ++ const struct jh7110_pll_syscon_val *preset_val; ++}; ++ ++struct jh7110_clk_pll_data { ++ struct clk_hw hw; ++ unsigned int idx; ++ unsigned int freq_select_idx; ++ struct jh7110_pll_syscon_conf conf; ++}; ++ ++struct jh7110_clk_pll_priv { ++ unsigned int pll_nums; ++ struct device *dev; ++ struct regmap *syscon_regmap; ++ struct jh7110_clk_pll_data data[]; ++}; ++ ++enum jh7110_pll0_freq_index { ++ JH7110_PLL0_FREQ_375 = 0, ++ JH7110_PLL0_FREQ_500, ++ JH7110_PLL0_FREQ_625, ++ JH7110_PLL0_FREQ_750, ++ JH7110_PLL0_FREQ_875, ++ JH7110_PLL0_FREQ_1000, ++ JH7110_PLL0_FREQ_1250, ++ JH7110_PLL0_FREQ_1375, ++ JH7110_PLL0_FREQ_1500, ++ JH7110_PLL0_FREQ_MAX ++}; ++ ++enum jh7110_pll1_freq_index { ++ JH7110_PLL1_FREQ_1066 = 0, ++ JH7110_PLL1_FREQ_1200, ++ JH7110_PLL1_FREQ_1400, ++ JH7110_PLL1_FREQ_1600, ++ JH7110_PLL1_FREQ_MAX ++}; ++ ++enum jh7110_pll2_freq_index { ++ JH7110_PLL2_FREQ_1188 = 0, ++ JH7110_PLL2_FREQ_12288, ++ JH7110_PLL2_FREQ_MAX + }; + + /* +@@ -158,9 +196,9 @@ enum starfive_pll2_freq_index { + * it cannot be set arbitrarily, so it needs a specific configuration. + * PLL0 frequency should be multiple of 125MHz (USB frequency). + */ +-static const struct starfive_pll_syscon_value +- jh7110_pll0_syscon_freq[PLL0_FREQ_MAX] = { +- [PLL0_FREQ_375] = { ++static const struct jh7110_pll_syscon_val ++ jh7110_pll0_syscon_val_preset[] = { ++ [JH7110_PLL0_FREQ_375] = { + .freq = 375000000, + .prediv = 8, + .fbdiv = 125, +@@ -168,7 +206,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_500] = { ++ [JH7110_PLL0_FREQ_500] = { + .freq = 500000000, + .prediv = 6, + .fbdiv = 125, +@@ -176,7 +214,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_625] = { ++ [JH7110_PLL0_FREQ_625] = { + .freq = 625000000, + .prediv = 24, + .fbdiv = 625, +@@ -184,7 +222,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_750] = { ++ [JH7110_PLL0_FREQ_750] = { + .freq = 750000000, + .prediv = 4, + .fbdiv = 125, +@@ -192,7 +230,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_875] = { ++ [JH7110_PLL0_FREQ_875] = { + .freq = 875000000, + .prediv = 24, + .fbdiv = 875, +@@ -200,7 +238,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_1000] = { ++ [JH7110_PLL0_FREQ_1000] = { + .freq = 1000000000, + .prediv = 3, + .fbdiv = 125, +@@ -208,7 +246,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_1250] = { ++ [JH7110_PLL0_FREQ_1250] = { + .freq = 1250000000, + .prediv = 12, + .fbdiv = 625, +@@ -216,7 +254,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_1375] = { ++ [JH7110_PLL0_FREQ_1375] = { + .freq = 1375000000, + .prediv = 24, + .fbdiv = 1375, +@@ -224,7 +262,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL0_FREQ_1500] = { ++ [JH7110_PLL0_FREQ_1500] = { + .freq = 1500000000, + .prediv = 2, + .fbdiv = 125, +@@ -234,9 +272,9 @@ static const struct starfive_pll_syscon_ + }, + }; + +-static const struct starfive_pll_syscon_value +- jh7110_pll1_syscon_freq[PLL1_FREQ_MAX] = { +- [PLL1_FREQ_1066] = { ++static const struct jh7110_pll_syscon_val ++ jh7110_pll1_syscon_val_preset[] = { ++ [JH7110_PLL1_FREQ_1066] = { + .freq = 1066000000, + .prediv = 12, + .fbdiv = 533, +@@ -244,7 +282,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL1_FREQ_1200] = { ++ [JH7110_PLL1_FREQ_1200] = { + .freq = 1200000000, + .prediv = 1, + .fbdiv = 50, +@@ -252,7 +290,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL1_FREQ_1400] = { ++ [JH7110_PLL1_FREQ_1400] = { + .freq = 1400000000, + .prediv = 6, + .fbdiv = 350, +@@ -260,7 +298,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL1_FREQ_1600] = { ++ [JH7110_PLL1_FREQ_1600] = { + .freq = 1600000000, + .prediv = 3, + .fbdiv = 200, +@@ -270,9 +308,9 @@ static const struct starfive_pll_syscon_ + }, + }; + +-static const struct starfive_pll_syscon_value +- jh7110_pll2_syscon_freq[PLL2_FREQ_MAX] = { +- [PLL2_FREQ_1188] = { ++static const struct jh7110_pll_syscon_val ++ jh7110_pll2_syscon_val_preset[] = { ++ [JH7110_PLL2_FREQ_1188] = { + .freq = 1188000000, + .prediv = 2, + .fbdiv = 99, +@@ -280,7 +318,7 @@ static const struct starfive_pll_syscon_ + .dacpd = 1, + .dsmpd = 1, + }, +- [PLL2_FREQ_12288] = { ++ [JH7110_PLL2_FREQ_12288] = { + .freq = 1228800000, + .prediv = 5, + .fbdiv = 256, diff --git a/target/linux/starfive/patches-6.1/0059-dt-bindings-timer-Add-timer-for-StarFive-JH7110-SoC.patch b/target/linux/starfive/patches-6.1/0059-dt-bindings-timer-Add-timer-for-StarFive-JH7110-SoC.patch new file mode 100644 index 0000000000..f0b5b98610 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0059-dt-bindings-timer-Add-timer-for-StarFive-JH7110-SoC.patch @@ -0,0 +1,113 @@ +From 944b96d734199642e2ede978c48d754109ca334c Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Mon, 20 Mar 2023 21:54:31 +0800 +Subject: [PATCH 059/122] dt-bindings: timer: Add timer for StarFive JH7110 SoC + +Add bindings for the timer on the JH7110 RISC-V SoC +by StarFive Technology Ltd. + +Signed-off-by: Xingyu Wu +Reviewed-by: Krzysztof Kozlowski +--- + .../bindings/timer/starfive,jh7110-timer.yaml | 95 +++++++++++++++++++ + 1 file changed, 95 insertions(+) + create mode 100644 Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml +@@ -0,0 +1,95 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/timer/starfive,jh7110-timer.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 Timer ++maintainers: ++ - Xingyu Wu ++ - Samin Guo ++ ++description: ++ This timer has four free-running 32 bit counters in StarFive JH7110 SoC. ++ And each channel(counter) triggers an interrupt when timeout. They support ++ one-shot mode and continuous-run mode. ++ ++properties: ++ compatible: ++ const: starfive,jh7110-timer ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ items: ++ - description: channel 0 ++ - description: channel 1 ++ - description: channel 2 ++ - description: channel 3 ++ ++ clocks: ++ items: ++ - description: timer APB ++ - description: channel 0 ++ - description: channel 1 ++ - description: channel 2 ++ - description: channel 3 ++ ++ clock-names: ++ items: ++ - const: apb ++ - const: ch0 ++ - const: ch1 ++ - const: ch2 ++ - const: ch3 ++ ++ resets: ++ items: ++ - description: timer APB ++ - description: channel 0 ++ - description: channel 1 ++ - description: channel 2 ++ - description: channel 3 ++ ++ reset-names: ++ items: ++ - const: apb ++ - const: ch0 ++ - const: ch1 ++ - const: ch2 ++ - const: ch3 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - clock-names ++ - resets ++ - reset-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ timer@13050000 { ++ compatible = "starfive,jh7110-timer"; ++ reg = <0x13050000 0x10000>; ++ interrupts = <69>, <70>, <71> ,<72>; ++ clocks = <&clk 124>, ++ <&clk 125>, ++ <&clk 126>, ++ <&clk 127>, ++ <&clk 128>; ++ clock-names = "apb", "ch0", "ch1", ++ "ch2", "ch3"; ++ resets = <&rst 117>, ++ <&rst 118>, ++ <&rst 119>, ++ <&rst 120>, ++ <&rst 121>; ++ reset-names = "apb", "ch0", "ch1", ++ "ch2", "ch3"; ++ }; ++ diff --git a/target/linux/starfive/patches-6.1/0060-clocksource-Add-StarFive-timer-driver.patch b/target/linux/starfive/patches-6.1/0060-clocksource-Add-StarFive-timer-driver.patch new file mode 100644 index 0000000000..dc6f1e0bf8 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0060-clocksource-Add-StarFive-timer-driver.patch @@ -0,0 +1,540 @@ +From 3fbdabd59bac0978536fb11b1b9deb81559f1c54 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Mon, 20 Mar 2023 21:54:32 +0800 +Subject: [PATCH 060/122] clocksource: Add StarFive timer driver + +Add timer driver for the StarFive JH7110 SoC. + +Signed-off-by: Xingyu Wu +--- + drivers/clocksource/Kconfig | 12 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/timer-starfive.c | 390 +++++++++++++++++++++++++++ + drivers/clocksource/timer-starfive.h | 96 +++++++ + 4 files changed, 499 insertions(+) + create mode 100644 drivers/clocksource/timer-starfive.c + create mode 100644 drivers/clocksource/timer-starfive.h + +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -630,6 +630,18 @@ config RISCV_TIMER + is accessed via both the SBI and the rdcycle instruction. This is + required for all RISC-V systems. + ++config STARFIVE_TIMER ++ bool "Timer for the STARFIVE SoCs" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ select TIMER_OF ++ select CLKSRC_MMIO ++ default ARCH_STARFIVE ++ help ++ This enables the timer for StarFive SoCs. On RISC-V platform, ++ the system has started RISCV_TIMER. But you can also use this timer ++ to do a lot more on StarFive SoCs. This timer can provide high ++ precision and four channels to use in 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 +@@ -80,6 +80,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_TIMER) += timer-starfive.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-starfive.c +@@ -0,0 +1,390 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Starfive Timer driver ++ * ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * ++ * Author: ++ * Xingyu Wu ++ * Samin Guo ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "timer-starfive.h" ++ ++static const struct starfive_timer_chan_base starfive_timer_jh7110_base = { ++ .ctrl = STARFIVE_TIMER_JH7110_CTL, ++ .load = STARFIVE_TIMER_JH7110_LOAD, ++ .enable = STARFIVE_TIMER_JH7110_ENABLE, ++ .reload = STARFIVE_TIMER_JH7110_RELOAD, ++ .value = STARFIVE_TIMER_JH7110_VALUE, ++ .intclr = STARFIVE_TIMER_JH7110_INT_CLR, ++ .intmask = STARFIVE_TIMER_JH7110_INT_MASK, ++ .channel_num = STARFIVE_TIMER_CH_4, ++ .channel_base = {STARFIVE_TIMER_CH_BASE(0), STARFIVE_TIMER_CH_BASE(1), ++ STARFIVE_TIMER_CH_BASE(2), STARFIVE_TIMER_CH_BASE(3)}, ++}; ++ ++static inline struct starfive_clkevt *to_starfive_clkevt(struct clock_event_device *evt) ++{ ++ return container_of(evt, struct starfive_clkevt, evt); ++} ++ ++/* 0:continuous-run mode, 1:single-run mode */ ++static inline void starfive_timer_set_mod(struct starfive_clkevt *clkevt, int mod) ++{ ++ writel(mod, clkevt->ctrl); ++} ++ ++/* Interrupt Mask Register, 0:Unmask, 1:Mask */ ++static inline void starfive_timer_int_enable(struct starfive_clkevt *clkevt) ++{ ++ writel(STARFIVE_TIMER_INTMASK_DIS, clkevt->intmask); ++} ++ ++static inline void starfive_timer_int_disable(struct starfive_clkevt *clkevt) ++{ ++ writel(STARFIVE_TIMER_INTMASK_ENA, clkevt->intmask); ++} ++ ++/* ++ * BIT(0): Read value represent channel intr 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 starfive_timer_int_clear(struct starfive_clkevt *clkevt) ++{ ++ u32 value; ++ int ret; ++ ++ /* waiting interrupt can be to clearing */ ++ ret = readl_poll_timeout_atomic(clkevt->intclr, value, ++ !(value & STARFIVE_TIMER_JH7110_INT_CLR_AVA_MASK), ++ STARFIVE_DELAY_US, STARFIVE_TIMEOUT_US); ++ if (!ret) ++ writel(0x1, clkevt->intclr); ++ ++ return ret; ++} ++ ++/* ++ * The initial value to be loaded into the ++ * counter and is also used as the reload value. ++ * val = clock rate --> 1s ++ */ ++static inline void starfive_timer_set_load(struct starfive_clkevt *clkevt, u32 val) ++{ ++ writel(val, clkevt->load); ++} ++ ++static inline u32 starfive_timer_get_val(struct starfive_clkevt *clkevt) ++{ ++ return readl(clkevt->value); ++} ++ ++/* ++ * Write RELOAD register to reload preset value to counter. ++ * (Write 0 and write 1 are both ok) ++ */ ++static inline void starfive_timer_set_reload(struct starfive_clkevt *clkevt) ++{ ++ writel(0, clkevt->reload); ++} ++ ++static inline void starfive_timer_enable(struct starfive_clkevt *clkevt) ++{ ++ writel(STARFIVE_TIMER_ENA, clkevt->enable); ++} ++ ++static inline void starfive_timer_disable(struct starfive_clkevt *clkevt) ++{ ++ writel(STARFIVE_TIMER_DIS, clkevt->enable); ++} ++ ++static int starfive_timer_int_init_enable(struct starfive_clkevt *clkevt) ++{ ++ int ret; ++ ++ starfive_timer_int_disable(clkevt); ++ ret = starfive_timer_int_clear(clkevt); ++ if (ret) ++ return ret; ++ ++ starfive_timer_int_enable(clkevt); ++ starfive_timer_enable(clkevt); ++ ++ return 0; ++} ++ ++static int starfive_timer_shutdown(struct clock_event_device *evt) ++{ ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ starfive_timer_disable(clkevt); ++ return starfive_timer_int_clear(clkevt); ++} ++ ++static void starfive_timer_suspend(struct clock_event_device *evt) ++{ ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ clkevt->reload_val = starfive_timer_get_val(clkevt); ++ starfive_timer_shutdown(evt); ++} ++ ++static void starfive_timer_resume(struct clock_event_device *evt) ++{ ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ starfive_timer_set_load(clkevt, clkevt->reload_val); ++ starfive_timer_set_reload(clkevt); ++ starfive_timer_int_enable(clkevt); ++ starfive_timer_enable(clkevt); ++} ++ ++static int starfive_timer_tick_resume(struct clock_event_device *evt) ++{ ++ starfive_timer_resume(evt); ++ ++ return 0; ++} ++ ++static int starfive_clocksource_init(struct starfive_clkevt *clkevt) ++{ ++ int ret; ++ ++ starfive_timer_set_mod(clkevt, STARFIVE_TIMER_MOD_CONTIN); ++ starfive_timer_set_load(clkevt, STARFIVE_TIMER_MAX_TICKS); ++ ret = starfive_timer_int_init_enable(clkevt); ++ if (ret) ++ return ret; ++ ++ return clocksource_mmio_init(clkevt->value, clkevt->name, clkevt->rate, ++ STARFIVE_CLOCK_SOURCE_RATING, STARFIVE_VALID_BITS, ++ clocksource_mmio_readl_down); ++} ++ ++/* IRQ handler for the timer */ ++static irqreturn_t starfive_timer_interrupt(int irq, void *priv) ++{ ++ struct clock_event_device *evt = (struct clock_event_device *)priv; ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ if (starfive_timer_int_clear(clkevt)) ++ return IRQ_NONE; ++ ++ if (evt->event_handler) ++ evt->event_handler(evt); ++ ++ return IRQ_HANDLED; ++} ++ ++static int starfive_timer_set_periodic(struct clock_event_device *evt) ++{ ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ starfive_timer_disable(clkevt); ++ starfive_timer_set_mod(clkevt, STARFIVE_TIMER_MOD_CONTIN); ++ starfive_timer_set_load(clkevt, clkevt->periodic); ++ ++ return starfive_timer_int_init_enable(clkevt); ++} ++ ++static int starfive_timer_set_oneshot(struct clock_event_device *evt) ++{ ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ starfive_timer_disable(clkevt); ++ starfive_timer_set_mod(clkevt, STARFIVE_TIMER_MOD_SINGLE); ++ starfive_timer_set_load(clkevt, STARFIVE_TIMER_MAX_TICKS); ++ ++ return starfive_timer_int_init_enable(clkevt); ++} ++ ++static int starfive_timer_set_next_event(unsigned long next, ++ struct clock_event_device *evt) ++{ ++ struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); ++ ++ starfive_timer_disable(clkevt); ++ starfive_timer_set_mod(clkevt, STARFIVE_TIMER_MOD_SINGLE); ++ starfive_timer_set_load(clkevt, next); ++ starfive_timer_enable(clkevt); ++ ++ return 0; ++} ++ ++static void starfive_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 = starfive_timer_shutdown; ++ evt->set_state_periodic = starfive_timer_set_periodic; ++ evt->set_state_oneshot = starfive_timer_set_oneshot; ++ evt->set_state_oneshot_stopped = starfive_timer_shutdown; ++ evt->tick_resume = starfive_timer_tick_resume; ++ evt->set_next_event = starfive_timer_set_next_event; ++ evt->suspend = starfive_timer_suspend; ++ evt->resume = starfive_timer_resume; ++ evt->rating = STARFIVE_CLOCKEVENT_RATING; ++} ++ ++static void starfive_clockevents_register(struct starfive_clkevt *clkevt) ++{ ++ clkevt->rate = clk_get_rate(clkevt->clk); ++ clkevt->periodic = DIV_ROUND_CLOSEST(clkevt->rate, HZ); ++ ++ starfive_set_clockevent(&clkevt->evt); ++ clkevt->evt.name = clkevt->name; ++ clkevt->evt.irq = clkevt->irq; ++ clkevt->evt.cpumask = cpu_possible_mask; ++ ++ clockevents_config_and_register(&clkevt->evt, clkevt->rate, ++ STARFIVE_TIMER_MIN_TICKS, STARFIVE_TIMER_MAX_TICKS); ++} ++ ++static void __init starfive_clkevt_base_init(const struct starfive_timer_chan_base *timer, ++ struct starfive_clkevt *clkevt, ++ void __iomem *base, int ch) ++{ ++ void __iomem *channel_base; ++ ++ channel_base = base + timer->channel_base[ch]; ++ clkevt->base = channel_base; ++ clkevt->ctrl = channel_base + timer->ctrl; ++ clkevt->load = channel_base + timer->load; ++ clkevt->enable = channel_base + timer->enable; ++ clkevt->reload = channel_base + timer->reload; ++ clkevt->value = channel_base + timer->value; ++ clkevt->intclr = channel_base + timer->intclr; ++ clkevt->intmask = channel_base + timer->intmask; ++} ++ ++static int __init starfive_timer_probe(struct platform_device *pdev) ++{ ++ const struct starfive_timer_chan_base *timer_base = of_device_get_match_data(&pdev->dev); ++ char name[10]; ++ struct starfive_timer_priv *priv; ++ struct starfive_clkevt *clkevt; ++ struct clk *pclk; ++ struct reset_control *rst; ++ int ch; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, struct_size(priv, clkevt, timer_base->channel_num), ++ GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(priv->base), ++ "failed to map registers\n"); ++ ++ rst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); ++ if (IS_ERR(rst)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rst), "failed to get apb reset\n"); ++ ++ pclk = devm_clk_get_enabled(&pdev->dev, "apb"); ++ if (IS_ERR(pclk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pclk), ++ "failed to get & enable apb clock\n"); ++ ++ ret = reset_control_deassert(rst); ++ if (ret) ++ goto err; ++ ++ priv->dev = &pdev->dev; ++ platform_set_drvdata(pdev, priv); ++ ++ for (ch = 0; ch < timer_base->channel_num; ch++) { ++ clkevt = &priv->clkevt[ch]; ++ snprintf(name, sizeof(name), "ch%d", ch); ++ ++ starfive_clkevt_base_init(timer_base, clkevt, priv->base, ch); ++ /* Ensure timers are disabled */ ++ starfive_timer_disable(clkevt); ++ ++ rst = devm_reset_control_get_exclusive(&pdev->dev, name); ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ goto err; ++ } ++ ++ clkevt->clk = devm_clk_get_enabled(&pdev->dev, name); ++ if (IS_ERR(clkevt->clk)) { ++ ret = PTR_ERR(clkevt->clk); ++ goto err; ++ } ++ ++ ret = reset_control_deassert(rst); ++ if (ret) ++ goto ch_err; ++ ++ clkevt->irq = platform_get_irq(pdev, ch); ++ if (clkevt->irq < 0) { ++ ret = clkevt->irq; ++ goto ch_err; ++ } ++ ++ snprintf(clkevt->name, sizeof(clkevt->name), "%s.ch%d", pdev->name, ch); ++ starfive_clockevents_register(clkevt); ++ ++ ret = devm_request_irq(&pdev->dev, clkevt->irq, starfive_timer_interrupt, ++ IRQF_TIMER | IRQF_IRQPOLL, ++ clkevt->name, &clkevt->evt); ++ if (ret) ++ goto ch_err; ++ ++ ret = starfive_clocksource_init(clkevt); ++ if (ret) ++ goto ch_err; ++ } ++ ++ return 0; ++ ++ch_err: ++ /* Only unregister the failed channel and the rest timer channels continue to work. */ ++ clk_disable_unprepare(clkevt->clk); ++err: ++ /* If no other channel successfully registers, pclk should be disabled. */ ++ if (!ch) ++ clk_disable_unprepare(pclk); ++ ++ return ret; ++} ++ ++static const struct of_device_id starfive_timer_match[] = { ++ { .compatible = "starfive,jh7110-timer", .data = &starfive_timer_jh7110_base }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, starfive_timer_match); ++ ++static struct platform_driver starfive_timer_driver = { ++ .probe = starfive_timer_probe, ++ .driver = { ++ .name = "starfive-timer", ++ .of_match_table = starfive_timer_match, ++ }, ++}; ++module_platform_driver(starfive_timer_driver); ++ ++MODULE_AUTHOR("Xingyu Wu "); ++MODULE_DESCRIPTION("StarFive timer driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/clocksource/timer-starfive.h +@@ -0,0 +1,96 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef __STARFIVE_TIMER_H__ ++#define __STARFIVE_TIMER_H__ ++ ++/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ ++#define STARFIVE_TIMER_CH_LEN 0x40 ++#define STARFIVE_TIMER_CH_BASE(x) ((STARFIVE_TIMER_CH_##x) * STARFIVE_TIMER_CH_LEN) ++ ++#define STARFIVE_CLOCK_SOURCE_RATING 200 ++#define STARFIVE_VALID_BITS 32 ++#define STARFIVE_DELAY_US 0 ++#define STARFIVE_TIMEOUT_US 10000 ++#define STARFIVE_CLOCKEVENT_RATING 300 ++#define STARFIVE_TIMER_MAX_TICKS 0xffffffff ++#define STARFIVE_TIMER_MIN_TICKS 0xf ++ ++#define STARFIVE_TIMER_JH7110_INT_STATUS 0x00 /* RO[0:4]: Interrupt Status for channel0~4 */ ++#define STARFIVE_TIMER_JH7110_CTL 0x04 /* RW[0]: 0-continuous run, 1-single run */ ++#define STARFIVE_TIMER_JH7110_LOAD 0x08 /* RW: load value to counter */ ++#define STARFIVE_TIMER_JH7110_ENABLE 0x10 /* RW[0]: timer enable register */ ++#define STARFIVE_TIMER_JH7110_RELOAD 0x14 /* RW: write 1 or 0 both reload counter */ ++#define STARFIVE_TIMER_JH7110_VALUE 0x18 /* RO: timer value register */ ++#define STARFIVE_TIMER_JH7110_INT_CLR 0x20 /* RW: timer interrupt clear register */ ++#define STARFIVE_TIMER_JH7110_INT_MASK 0x24 /* RW[0]: timer interrupt mask register */ ++#define STARFIVE_TIMER_JH7110_INT_CLR_AVA_MASK BIT(1) ++ ++enum STARFIVE_TIMER_CH { ++ STARFIVE_TIMER_CH_0 = 0, ++ STARFIVE_TIMER_CH_1, ++ STARFIVE_TIMER_CH_2, ++ STARFIVE_TIMER_CH_3, ++ STARFIVE_TIMER_CH_4, ++ STARFIVE_TIMER_CH_5, ++ STARFIVE_TIMER_CH_6, ++ STARFIVE_TIMER_CH_7, ++ STARFIVE_TIMER_CH_MAX ++}; ++ ++enum STARFIVE_TIMER_INTMASK { ++ STARFIVE_TIMER_INTMASK_DIS = 0, ++ STARFIVE_TIMER_INTMASK_ENA = 1 ++}; ++ ++enum STARFIVE_TIMER_MOD { ++ STARFIVE_TIMER_MOD_CONTIN = 0, ++ STARFIVE_TIMER_MOD_SINGLE = 1 ++}; ++ ++enum STARFIVE_TIMER_CTL_EN { ++ STARFIVE_TIMER_DIS = 0, ++ STARFIVE_TIMER_ENA = 1 ++}; ++ ++struct starfive_timer_chan_base { ++ /* Resgister */ ++ unsigned int ctrl; ++ unsigned int load; ++ unsigned int enable; ++ unsigned int reload; ++ unsigned int value; ++ unsigned int intclr; ++ unsigned int intmask; ++ ++ unsigned int channel_num; /* timer channel numbers */ ++ unsigned int channel_base[]; ++}; ++ ++struct starfive_clkevt { ++ struct clock_event_device evt; ++ struct clk *clk; ++ char name[20]; ++ int irq; ++ u32 periodic; ++ u32 rate; ++ u32 reload_val; ++ void __iomem *base; ++ void __iomem *ctrl; ++ void __iomem *load; ++ void __iomem *enable; ++ void __iomem *reload; ++ void __iomem *value; ++ void __iomem *intclr; ++ void __iomem *intmask; ++}; ++ ++struct starfive_timer_priv { ++ struct device *dev; ++ void __iomem *base; ++ struct starfive_clkevt clkevt[]; ++}; ++ ++#endif /* __STARFIVE_TIMER_H__ */ diff --git a/target/linux/starfive/patches-6.1/0061-dt-bindings-net-motorcomm-Add-pad-driver-strength-cf.patch b/target/linux/starfive/patches-6.1/0061-dt-bindings-net-motorcomm-Add-pad-driver-strength-cf.patch new file mode 100644 index 0000000000..58f29cda8f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0061-dt-bindings-net-motorcomm-Add-pad-driver-strength-cf.patch @@ -0,0 +1,36 @@ +From 16214121afaadb8ae9aaf73351e874405eb47c15 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Tue, 25 Apr 2023 18:51:15 +0800 +Subject: [PATCH 061/122] dt-bindings: net: motorcomm: Add pad driver strength + cfg + +The motorcomm phy (YT8531) supports the ability to adjust the drive +strength of the rx_clk/rx_data, the value range of pad driver +strength is 0 to 7. + +Signed-off-by: Samin Guo +--- + .../devicetree/bindings/net/motorcomm,yt8xxx.yaml | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml ++++ b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml +@@ -62,6 +62,18 @@ properties: + for a timer. + type: boolean + ++ motorcomm,rx-clk-driver-strength: ++ description: drive strength of rx_clk pad. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ] ++ default: 3 ++ ++ motorcomm,rx-data-driver-strength: ++ description: drive strength of rx_data/rx_ctl rgmii pad. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ] ++ default: 3 ++ + motorcomm,tx-clk-adj-enabled: + description: | + This configuration is mainly to adapt to VF2 with JH7110 SoC. diff --git a/target/linux/starfive/patches-6.1/0062-dt-bindings-PWM-Add-StarFive-PWM-module.patch b/target/linux/starfive/patches-6.1/0062-dt-bindings-PWM-Add-StarFive-PWM-module.patch new file mode 100644 index 0000000000..20546650a3 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0062-dt-bindings-PWM-Add-StarFive-PWM-module.patch @@ -0,0 +1,71 @@ +From 99f0bf43994dada29e33fd8718fd25484634da3a Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Tue, 21 Mar 2023 13:52:27 +0800 +Subject: [PATCH 062/122] dt-bindings: PWM: Add StarFive PWM module + +Add documentation to describe StarFive Pulse Width Modulation +controller driver. + +Signed-off-by: William Qiu +Reviewed-by: Krzysztof Kozlowski +--- + .../bindings/pwm/starfive,jh7110-pwm.yaml | 53 +++++++++++++++++++ + 1 file changed, 53 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pwm/starfive,jh7110-pwm.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/starfive,jh7110-pwm.yaml +@@ -0,0 +1,53 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pwm/starfive,jh7110-pwm.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive PWM controller ++ ++maintainers: ++ - William Qiu ++ ++description: ++ StarFive SoCs contain PWM and when operating in PWM mode, the PTC core generates ++ binary signal with user-programmable low and high periods. Clock source for the ++ PWM can be either system clockor external clock. Each PWM timer block provides 8 ++ PWM channels. ++ ++allOf: ++ - $ref: pwm.yaml# ++ ++properties: ++ compatible: ++ const: starfive,jh7110-pwm ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ ++ "#pwm-cells": ++ const: 3 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - resets ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pwm@120d0000 { ++ compatible = "starfive,jh7110-pwm"; ++ reg = <0x120d0000 0x10000>; ++ clocks = <&syscrg 121>; ++ resets = <&syscrg 108>; ++ #pwm-cells = <3>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0063-pwm-starfive-Add-PWM-driver-support.patch b/target/linux/starfive/patches-6.1/0063-pwm-starfive-Add-PWM-driver-support.patch new file mode 100644 index 0000000000..0433160a20 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0063-pwm-starfive-Add-PWM-driver-support.patch @@ -0,0 +1,294 @@ +From fddea961e7ce1f26dd549e3d92ede624246690c0 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Tue, 21 Mar 2023 13:52:28 +0800 +Subject: [PATCH 063/122] pwm: starfive: Add PWM driver support + +Add Pulse Width Modulation driver support for StarFive +JH7110 soc. + +Signed-off-by: Hal Feng +Signed-off-by: William Qiu +--- + drivers/pwm/Kconfig | 10 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-starfive-ptc.c | 245 +++++++++++++++++++++++++++++++++ + 3 files changed, 256 insertions(+) + create mode 100644 drivers/pwm/pwm-starfive-ptc.c + +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -536,6 +536,16 @@ config PWM_SPRD + To compile this driver as a module, choose M here: the module + will be called pwm-sprd. + ++config PWM_STARFIVE_PTC ++ tristate "StarFive PWM PTC support" ++ depends on OF ++ depends on COMMON_CLK ++ help ++ Generic PWM framework driver for StarFive SoCs. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-starfive-ptc. ++ + config PWM_STI + tristate "STiH4xx PWM support" + depends on ARCH_STI || COMPILE_TEST +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -49,6 +49,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o + obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o + obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o + obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o ++obj-$(CONFIG_PWM_STARFIVE_PTC) += pwm-starfive-ptc.o + obj-$(CONFIG_PWM_STI) += pwm-sti.o + obj-$(CONFIG_PWM_STM32) += pwm-stm32.o + obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o +--- /dev/null ++++ b/drivers/pwm/pwm-starfive-ptc.c +@@ -0,0 +1,245 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * PWM driver for the StarFive JH7110 SoC ++ * ++ * Copyright (C) 2018 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* how many parameters can be transferred to ptc */ ++#define OF_PWM_N_CELLS 3 ++ ++/* PTC Register offsets */ ++#define REG_RPTC_CNTR 0x0 ++#define REG_RPTC_HRC 0x4 ++#define REG_RPTC_LRC 0x8 ++#define REG_RPTC_CTRL 0xC ++ ++/* Bit for PWM clock */ ++#define BIT_PWM_CLOCK_EN 31 ++ ++/* Bit for clock gen soft reset */ ++#define BIT_CLK_GEN_SOFT_RESET 13 ++ ++#define NS_PER_SECOND 1000000000 ++ ++/* ++ * Access PTC register (cntr hrc lrc and ctrl), ++ * need to replace PWM_BASE_ADDR ++ */ ++#define REG_PTC_BASE_ADDR_SUB(base, N) \ ++((base) + (((N) > 3) ? (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) ++#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) ++#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) ++#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) ++#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) ++ ++/* PTC_RPTC_CTRL */ ++#define PTC_EN BIT(0) ++#define PTC_ECLK BIT(1) ++#define PTC_NEC BIT(2) ++#define PTC_OE BIT(3) ++#define PTC_SIGNLE BIT(4) ++#define PTC_INTE BIT(5) ++#define PTC_INT BIT(6) ++#define PTC_CNTRRST BIT(7) ++#define PTC_CAPTE BIT(8) ++ ++struct starfive_pwm_ptc_device { ++ struct pwm_chip chip; ++ struct clk *clk; ++ struct reset_control *rst; ++ void __iomem *regs; ++ int irq; ++ unsigned int approx_freq;/*pwm apb clock frequency*/ ++}; ++ ++static inline ++struct starfive_pwm_ptc_device *chip_to_starfive_ptc(struct pwm_chip *c) ++{ ++ return container_of(c, struct starfive_pwm_ptc_device, chip); ++} ++ ++static int starfive_pwm_ptc_get_state(struct pwm_chip *chip, ++ struct pwm_device *dev, ++ struct pwm_state *state) ++{ ++ struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); ++ u32 data_lrc, data_hrc; ++ u32 pwm_clk_ns = 0; ++ ++ data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); ++ data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); ++ ++ pwm_clk_ns = NS_PER_SECOND / pwm->approx_freq; ++ ++ state->period = data_lrc * pwm_clk_ns; ++ state->duty_cycle = data_hrc * pwm_clk_ns; ++ state->polarity = PWM_POLARITY_NORMAL; ++ state->enabled = 1; ++ ++ return 0; ++} ++ ++static int starfive_pwm_ptc_apply(struct pwm_chip *chip, ++ struct pwm_device *dev, ++ struct pwm_state *state) ++{ ++ struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); ++ u32 data_hrc = 0; ++ u32 data_lrc = 0; ++ u32 period_data = 0; ++ u32 duty_data = 0; ++ s64 multi = pwm->approx_freq; ++ s64 div = NS_PER_SECOND; ++ void __iomem *reg_addr; ++ ++ if (state->duty_cycle > state->period) ++ state->duty_cycle = state->period; ++ ++ while (multi % 10 == 0 && div % 10 == 0 && multi > 0 && div > 0) { ++ multi /= 10; ++ div /= 10; ++ } ++ ++ period_data = (u32)(state->period * multi / div); ++ if (abs(period_data * div / multi - state->period) ++ > abs((period_data + 1) * div / multi - state->period) || ++ (state->period > 0 && period_data == 0)) ++ period_data += 1; ++ ++ if (state->enabled) { ++ duty_data = (u32)(state->duty_cycle * multi / div); ++ if (abs(duty_data * div / multi - state->duty_cycle) ++ > abs((duty_data + 1) * div / multi - state->duty_cycle) || ++ (state->duty_cycle > 0 && duty_data == 0)) ++ duty_data += 1; ++ } else { ++ duty_data = 0; ++ } ++ ++ if (state->polarity == PWM_POLARITY_NORMAL) ++ data_hrc = period_data - duty_data; ++ else ++ data_hrc = duty_data; ++ ++ data_lrc = period_data; ++ ++ reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm); ++ iowrite32(data_hrc, reg_addr); ++ ++ reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm); ++ iowrite32(data_lrc, reg_addr); ++ ++ reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm); ++ iowrite32(0, reg_addr); ++ ++ reg_addr = REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm); ++ iowrite32(PTC_EN | PTC_OE, reg_addr); ++ ++ return 0; ++} ++ ++static const struct pwm_ops starfive_pwm_ptc_ops = { ++ .get_state = starfive_pwm_ptc_get_state, ++ .apply = (void *)starfive_pwm_ptc_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static int starfive_pwm_ptc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct starfive_pwm_ptc_device *pwm; ++ struct pwm_chip *chip; ++ int ret; ++ ++ pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); ++ if (!pwm) ++ return -ENOMEM; ++ ++ chip = &pwm->chip; ++ chip->dev = dev; ++ chip->ops = &starfive_pwm_ptc_ops; ++ chip->npwm = 8; ++ ++ chip->of_pwm_n_cells = OF_PWM_N_CELLS; ++ chip->base = -1; ++ ++ pwm->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pwm->regs)) ++ return dev_err_probe(dev, PTR_ERR(pwm->regs), ++ "Unable to map IO resources\n"); ++ ++ pwm->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pwm->clk)) ++ return dev_err_probe(dev, PTR_ERR(pwm->clk), ++ "Unable to get pwm clock\n"); ++ ++ pwm->rst = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(pwm->rst)) ++ return dev_err_probe(dev, PTR_ERR(pwm->rst), ++ "Unable to get pwm reset\n"); ++ ++ ret = clk_prepare_enable(pwm->clk); ++ if (ret) { ++ dev_err(dev, ++ "Failed to enable pwm clock, %d\n", ret); ++ return ret; ++ } ++ ++ reset_control_deassert(pwm->rst); ++ ++ pwm->approx_freq = (unsigned int)clk_get_rate(pwm->clk); ++ if (!pwm->approx_freq) ++ dev_err(dev, "get pwm apb clock rate failed.\n"); ++ ++ ret = devm_pwmchip_add(dev, chip); ++ if (ret < 0) { ++ dev_err(dev, "cannot register PTC: %d\n", ret); ++ clk_disable_unprepare(pwm->clk); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, pwm); ++ ++ return 0; ++} ++ ++static int starfive_pwm_ptc_remove(struct platform_device *dev) ++{ ++ struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev); ++ struct pwm_chip *chip = &pwm->chip; ++ ++ pwmchip_remove(chip); ++ ++ return 0; ++} ++ ++static const struct of_device_id starfive_pwm_ptc_of_match[] = { ++ { .compatible = "starfive,jh7110-pwm" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match); ++ ++static struct platform_driver starfive_pwm_ptc_driver = { ++ .probe = starfive_pwm_ptc_probe, ++ .remove = starfive_pwm_ptc_remove, ++ .driver = { ++ .name = "pwm-starfive-ptc", ++ .of_match_table = starfive_pwm_ptc_of_match, ++ }, ++}; ++module_platform_driver(starfive_pwm_ptc_driver); ++ ++MODULE_AUTHOR("Jenny Zhang "); ++MODULE_AUTHOR("Hal Feng "); ++MODULE_DESCRIPTION("StarFive PWM PTC driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0064-dt-bindings-crypto-Add-StarFive-crypto-module.patch b/target/linux/starfive/patches-6.1/0064-dt-bindings-crypto-Add-StarFive-crypto-module.patch new file mode 100644 index 0000000000..09b2dccef9 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0064-dt-bindings-crypto-Add-StarFive-crypto-module.patch @@ -0,0 +1,90 @@ +From 207dde3ed123613cd84c8f706a24d75cefece67c Mon Sep 17 00:00:00 2001 +From: Jia Jie Ho +Date: Mon, 15 May 2023 20:53:52 +0800 +Subject: [PATCH 064/122] dt-bindings: crypto: Add StarFive crypto module + +Add documentation to describe StarFive cryptographic engine. + +Co-developed-by: Huan Feng +Signed-off-by: Huan Feng +Signed-off-by: Jia Jie Ho +Reviewed-by: Rob Herring +Signed-off-by: Herbert Xu +--- + .../crypto/starfive,jh7110-crypto.yaml | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + create mode 100644 Documentation/devicetree/bindings/crypto/starfive,jh7110-crypto.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/crypto/starfive,jh7110-crypto.yaml +@@ -0,0 +1,70 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/crypto/starfive,jh7110-crypto.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive Cryptographic Module ++ ++maintainers: ++ - Jia Jie Ho ++ - William Qiu ++ ++properties: ++ compatible: ++ const: starfive,jh7110-crypto ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: Hardware reference clock ++ - description: AHB reference clock ++ ++ clock-names: ++ items: ++ - const: hclk ++ - const: ahb ++ ++ interrupts: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ ++ dmas: ++ items: ++ - description: TX DMA channel ++ - description: RX DMA channel ++ ++ dma-names: ++ items: ++ - const: tx ++ - const: rx ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - dmas ++ - dma-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ crypto: crypto@16000000 { ++ compatible = "starfive,jh7110-crypto"; ++ reg = <0x16000000 0x4000>; ++ clocks = <&clk 15>, <&clk 16>; ++ clock-names = "hclk", "ahb"; ++ interrupts = <28>; ++ resets = <&reset 3>; ++ dmas = <&dma 1 2>, ++ <&dma 0 2>; ++ dma-names = "tx", "rx"; ++ }; ++... diff --git a/target/linux/starfive/patches-6.1/0065-crypto-starfive-Add-crypto-engine-support.patch b/target/linux/starfive/patches-6.1/0065-crypto-starfive-Add-crypto-engine-support.patch new file mode 100644 index 0000000000..5aa3bc10f6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0065-crypto-starfive-Add-crypto-engine-support.patch @@ -0,0 +1,337 @@ +From 8b1069fcc1dbb524556d851f3dedf0629a71f17b Mon Sep 17 00:00:00 2001 +From: Jia Jie Ho +Date: Mon, 15 May 2023 20:53:53 +0800 +Subject: [PATCH 065/122] crypto: starfive - Add crypto engine support + +Adding device probe and DMA init for StarFive cryptographic module. + +Co-developed-by: Huan Feng +Signed-off-by: Huan Feng +Signed-off-by: Jia Jie Ho +Signed-off-by: Herbert Xu +--- + drivers/crypto/Kconfig | 1 + + drivers/crypto/Makefile | 1 + + drivers/crypto/starfive/Kconfig | 17 +++ + drivers/crypto/starfive/Makefile | 4 + + drivers/crypto/starfive/jh7110-cryp.c | 201 ++++++++++++++++++++++++++ + drivers/crypto/starfive/jh7110-cryp.h | 63 ++++++++ + 6 files changed, 287 insertions(+) + create mode 100644 drivers/crypto/starfive/Kconfig + create mode 100644 drivers/crypto/starfive/Makefile + create mode 100644 drivers/crypto/starfive/jh7110-cryp.c + create mode 100644 drivers/crypto/starfive/jh7110-cryp.h + +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -823,5 +823,6 @@ config CRYPTO_DEV_SA2UL + + source "drivers/crypto/keembay/Kconfig" + source "drivers/crypto/aspeed/Kconfig" ++source "drivers/crypto/starfive/Kconfig" + + endif # CRYPTO_HW +--- a/drivers/crypto/Makefile ++++ b/drivers/crypto/Makefile +@@ -53,3 +53,4 @@ obj-y += xilinx/ + obj-y += hisilicon/ + obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ + obj-y += keembay/ ++obj-y += starfive/ +--- /dev/null ++++ b/drivers/crypto/starfive/Kconfig +@@ -0,0 +1,17 @@ ++# ++# StarFive crypto drivers configuration ++# ++ ++config CRYPTO_DEV_JH7110 ++ tristate "StarFive JH7110 cryptographic engine driver" ++ depends on SOC_STARFIVE || COMPILE_TEST ++ select CRYPTO_ENGINE ++ select ARM_AMBA ++ select DMADEVICES ++ select AMBA_PL08X ++ help ++ Support for StarFive JH7110 crypto hardware acceleration engine. ++ This module provides acceleration for public key algo, ++ skciphers, AEAD and hash functions. ++ ++ If you choose 'M' here, this module will be called jh7110-crypto. +--- /dev/null ++++ b/drivers/crypto/starfive/Makefile +@@ -0,0 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-$(CONFIG_CRYPTO_DEV_JH7110) += jh7110-crypto.o ++jh7110-crypto-objs := jh7110-cryp.o +--- /dev/null ++++ b/drivers/crypto/starfive/jh7110-cryp.c +@@ -0,0 +1,201 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Cryptographic API. ++ * ++ * Support for StarFive hardware cryptographic engine. ++ * Copyright (c) 2022 StarFive Technology ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jh7110-cryp.h" ++ ++#define DRIVER_NAME "jh7110-crypto" ++ ++struct starfive_dev_list { ++ struct list_head dev_list; ++ spinlock_t lock; /* protect dev_list */ ++}; ++ ++static struct starfive_dev_list dev_list = { ++ .dev_list = LIST_HEAD_INIT(dev_list.dev_list), ++ .lock = __SPIN_LOCK_UNLOCKED(dev_list.lock), ++}; ++ ++struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx) ++{ ++ struct starfive_cryp_dev *cryp = NULL, *tmp; ++ ++ spin_lock_bh(&dev_list.lock); ++ if (!ctx->cryp) { ++ list_for_each_entry(tmp, &dev_list.dev_list, list) { ++ cryp = tmp; ++ break; ++ } ++ ctx->cryp = cryp; ++ } else { ++ cryp = ctx->cryp; ++ } ++ ++ spin_unlock_bh(&dev_list.lock); ++ ++ return cryp; ++} ++ ++static int starfive_dma_init(struct starfive_cryp_dev *cryp) ++{ ++ dma_cap_mask_t mask; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ ++ cryp->tx = dma_request_chan(cryp->dev, "tx"); ++ if (IS_ERR(cryp->tx)) ++ return dev_err_probe(cryp->dev, PTR_ERR(cryp->tx), ++ "Error requesting tx dma channel.\n"); ++ ++ cryp->rx = dma_request_chan(cryp->dev, "rx"); ++ if (IS_ERR(cryp->rx)) { ++ dma_release_channel(cryp->tx); ++ return dev_err_probe(cryp->dev, PTR_ERR(cryp->rx), ++ "Error requesting rx dma channel.\n"); ++ } ++ ++ return 0; ++} ++ ++static void starfive_dma_cleanup(struct starfive_cryp_dev *cryp) ++{ ++ dma_release_channel(cryp->tx); ++ dma_release_channel(cryp->rx); ++} ++ ++static int starfive_cryp_probe(struct platform_device *pdev) ++{ ++ struct starfive_cryp_dev *cryp; ++ struct resource *res; ++ int ret; ++ ++ cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL); ++ if (!cryp) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, cryp); ++ cryp->dev = &pdev->dev; ++ ++ cryp->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); ++ if (IS_ERR(cryp->base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cryp->base), ++ "Error remapping memory for platform device\n"); ++ ++ cryp->phys_base = res->start; ++ cryp->dma_maxburst = 32; ++ ++ cryp->hclk = devm_clk_get(&pdev->dev, "hclk"); ++ if (IS_ERR(cryp->hclk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cryp->hclk), ++ "Error getting hardware reference clock\n"); ++ ++ cryp->ahb = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(cryp->ahb)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cryp->ahb), ++ "Error getting ahb reference clock\n"); ++ ++ cryp->rst = devm_reset_control_get_shared(cryp->dev, NULL); ++ if (IS_ERR(cryp->rst)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst), ++ "Error getting hardware reset line\n"); ++ ++ clk_prepare_enable(cryp->hclk); ++ clk_prepare_enable(cryp->ahb); ++ reset_control_deassert(cryp->rst); ++ ++ spin_lock(&dev_list.lock); ++ list_add(&cryp->list, &dev_list.dev_list); ++ spin_unlock(&dev_list.lock); ++ ++ ret = starfive_dma_init(cryp); ++ if (ret) { ++ if (ret == -EPROBE_DEFER) ++ goto err_probe_defer; ++ else ++ goto err_dma_init; ++ } ++ ++ /* Initialize crypto engine */ ++ cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1); ++ if (!cryp->engine) { ++ ret = -ENOMEM; ++ goto err_engine; ++ } ++ ++ ret = crypto_engine_start(cryp->engine); ++ if (ret) ++ goto err_engine_start; ++ ++ return 0; ++ ++err_engine_start: ++ crypto_engine_exit(cryp->engine); ++err_engine: ++ starfive_dma_cleanup(cryp); ++err_dma_init: ++ spin_lock(&dev_list.lock); ++ list_del(&cryp->list); ++ spin_unlock(&dev_list.lock); ++ ++ clk_disable_unprepare(cryp->hclk); ++ clk_disable_unprepare(cryp->ahb); ++ reset_control_assert(cryp->rst); ++err_probe_defer: ++ return ret; ++} ++ ++static int starfive_cryp_remove(struct platform_device *pdev) ++{ ++ struct starfive_cryp_dev *cryp = platform_get_drvdata(pdev); ++ ++ crypto_engine_stop(cryp->engine); ++ crypto_engine_exit(cryp->engine); ++ ++ starfive_dma_cleanup(cryp); ++ ++ spin_lock(&dev_list.lock); ++ list_del(&cryp->list); ++ spin_unlock(&dev_list.lock); ++ ++ clk_disable_unprepare(cryp->hclk); ++ clk_disable_unprepare(cryp->ahb); ++ reset_control_assert(cryp->rst); ++ ++ return 0; ++} ++ ++static const struct of_device_id starfive_dt_ids[] __maybe_unused = { ++ { .compatible = "starfive,jh7110-crypto", .data = NULL}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, starfive_dt_ids); ++ ++static struct platform_driver starfive_cryp_driver = { ++ .probe = starfive_cryp_probe, ++ .remove = starfive_cryp_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .of_match_table = starfive_dt_ids, ++ }, ++}; ++ ++module_platform_driver(starfive_cryp_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("StarFive JH7110 Cryptographic Module"); +--- /dev/null ++++ b/drivers/crypto/starfive/jh7110-cryp.h +@@ -0,0 +1,63 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __STARFIVE_STR_H__ ++#define __STARFIVE_STR_H__ ++ ++#include ++#include ++#include ++ ++#include ++ ++#define STARFIVE_ALG_CR_OFFSET 0x0 ++#define STARFIVE_ALG_FIFO_OFFSET 0x4 ++#define STARFIVE_IE_MASK_OFFSET 0x8 ++#define STARFIVE_IE_FLAG_OFFSET 0xc ++#define STARFIVE_DMA_IN_LEN_OFFSET 0x10 ++#define STARFIVE_DMA_OUT_LEN_OFFSET 0x14 ++ ++#define STARFIVE_MSG_BUFFER_SIZE SZ_16K ++ ++union starfive_alg_cr { ++ u32 v; ++ struct { ++ u32 start :1; ++ u32 aes_dma_en :1; ++ u32 rsvd_0 :1; ++ u32 hash_dma_en :1; ++ u32 alg_done :1; ++ u32 rsvd_1 :3; ++ u32 clear :1; ++ u32 rsvd_2 :23; ++ }; ++}; ++ ++struct starfive_cryp_ctx { ++ struct crypto_engine_ctx enginectx; ++ struct starfive_cryp_dev *cryp; ++}; ++ ++struct starfive_cryp_dev { ++ struct list_head list; ++ struct device *dev; ++ ++ struct clk *hclk; ++ struct clk *ahb; ++ struct reset_control *rst; ++ ++ void __iomem *base; ++ phys_addr_t phys_base; ++ ++ u32 dma_maxburst; ++ struct dma_chan *tx; ++ struct dma_chan *rx; ++ struct dma_slave_config cfg_in; ++ struct dma_slave_config cfg_out; ++ ++ struct crypto_engine *engine; ++ ++ union starfive_alg_cr alg_cr; ++}; ++ ++struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx); ++ ++#endif diff --git a/target/linux/starfive/patches-6.1/0066-crypto-starfive-Fix-driver-dependencies.patch b/target/linux/starfive/patches-6.1/0066-crypto-starfive-Fix-driver-dependencies.patch new file mode 100644 index 0000000000..fc8e86bad5 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0066-crypto-starfive-Fix-driver-dependencies.patch @@ -0,0 +1,29 @@ +From 0d3ee821ed469a787e8007de2d87e98a2370e087 Mon Sep 17 00:00:00 2001 +From: Jia Jie Ho +Date: Fri, 19 May 2023 21:42:33 +0800 +Subject: [PATCH 066/122] crypto: starfive - Fix driver dependencies + +Kconfig updated to depend on DMADEVICES instead of selecting it. + +Reported-by: kernel test robot +Link: https://lore.kernel.org/oe-kbuild-all/202305191929.Eq4OVZ6D-lkp@intel.com/ +Signed-off-by: Jia Jie Ho +Signed-off-by: Herbert Xu +--- + drivers/crypto/starfive/Kconfig | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/crypto/starfive/Kconfig ++++ b/drivers/crypto/starfive/Kconfig +@@ -4,10 +4,9 @@ + + config CRYPTO_DEV_JH7110 + tristate "StarFive JH7110 cryptographic engine driver" +- depends on SOC_STARFIVE || COMPILE_TEST ++ depends on (SOC_STARFIVE || COMPILE_TEST) && DMADEVICES + select CRYPTO_ENGINE + select ARM_AMBA +- select DMADEVICES + select AMBA_PL08X + help + Support for StarFive JH7110 crypto hardware acceleration engine. diff --git a/target/linux/starfive/patches-6.1/0067-riscv-Kconfig-Add-select-ARM_AMBA-to-SOC_STARFIVE.patch b/target/linux/starfive/patches-6.1/0067-riscv-Kconfig-Add-select-ARM_AMBA-to-SOC_STARFIVE.patch new file mode 100644 index 0000000000..2deca609e1 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0067-riscv-Kconfig-Add-select-ARM_AMBA-to-SOC_STARFIVE.patch @@ -0,0 +1,23 @@ +From e8d070e2eb856856055566d3515072a8346446f3 Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Wed, 31 May 2023 01:37:41 -0700 +Subject: [PATCH 067/122] riscv: Kconfig: Add select ARM_AMBA to SOC_STARFIVE + +Selects ARM_AMBA platform support for StarFive SoCs required by spi and +crypto dma engine. + +Signed-off-by: shanlong.li +--- + arch/riscv/Kconfig.socs | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -4,6 +4,7 @@ config SOC_MICROCHIP_POLARFIRE + bool "Microchip PolarFire SoCs" + select MCHP_CLK_MPFS + select SIFIVE_PLIC ++ select ARM_AMBA + help + This enables support for Microchip PolarFire SoC platforms. + diff --git a/target/linux/starfive/patches-6.1/0068-ASoC-dt-bindings-Add-TDM-controller-bindings-for-Sta.patch b/target/linux/starfive/patches-6.1/0068-ASoC-dt-bindings-Add-TDM-controller-bindings-for-Sta.patch new file mode 100644 index 0000000000..41d0a8fe11 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0068-ASoC-dt-bindings-Add-TDM-controller-bindings-for-Sta.patch @@ -0,0 +1,117 @@ +From 3b90e0fb53c31c50e64d2039e30ec25c1d8a8d5c Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Fri, 26 May 2023 22:54:00 +0800 +Subject: [PATCH 068/122] ASoC: dt-bindings: Add TDM controller bindings for + StarFive JH7110 + +Add bindings for TDM driver which supports multi-channel audio playback +and capture on JH7110 platform. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Walker Chen +--- + .../bindings/sound/starfive,jh7110-tdm.yaml | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + create mode 100644 Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml +@@ -0,0 +1,98 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/sound/starfive,jh7110-tdm.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 TDM Controller ++ ++description: | ++ The TDM Controller is a Time Division Multiplexed audio interface ++ integrated in StarFive JH7110 SoC, allowing up to 8 channels of ++ audio over a serial interface. The TDM controller can operate both ++ in master and slave mode. ++ ++maintainers: ++ - Walker Chen ++ ++allOf: ++ - $ref: dai-common.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - starfive,jh7110-tdm ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: TDM AHB Clock ++ - description: TDM APB Clock ++ - description: TDM Internal Clock ++ - description: TDM Clock ++ - description: Inner MCLK ++ - description: TDM External Clock ++ ++ clock-names: ++ items: ++ - const: tdm_ahb ++ - const: tdm_apb ++ - const: tdm_internal ++ - const: tdm ++ - const: mclk_inner ++ - const: tdm_ext ++ ++ resets: ++ items: ++ - description: tdm ahb reset line ++ - description: tdm apb reset line ++ - description: tdm core reset line ++ ++ dmas: ++ items: ++ - description: RX DMA Channel ++ - description: TX DMA Channel ++ ++ dma-names: ++ items: ++ - const: rx ++ - const: tx ++ ++ "#sound-dai-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - dmas ++ - dma-names ++ - "#sound-dai-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ tdm@10090000 { ++ compatible = "starfive,jh7110-tdm"; ++ reg = <0x10090000 0x1000>; ++ clocks = <&syscrg 184>, ++ <&syscrg 185>, ++ <&syscrg 186>, ++ <&syscrg 187>, ++ <&syscrg 17>, ++ <&tdm_ext>; ++ clock-names = "tdm_ahb", "tdm_apb", ++ "tdm_internal", "tdm", ++ "mclk_inner", "tdm_ext"; ++ resets = <&syscrg 105>, ++ <&syscrg 107>, ++ <&syscrg 106>; ++ dmas = <&dma 20>, <&dma 21>; ++ dma-names = "rx","tx"; ++ #sound-dai-cells = <0>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0069-ASoC-starfive-Add-JH7110-TDM-driver.patch b/target/linux/starfive/patches-6.1/0069-ASoC-starfive-Add-JH7110-TDM-driver.patch new file mode 100644 index 0000000000..57ea99d685 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0069-ASoC-starfive-Add-JH7110-TDM-driver.patch @@ -0,0 +1,744 @@ +From 9d90936b0f69d891001a11d3f6c0c3728d8b6d85 Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Fri, 26 May 2023 22:54:01 +0800 +Subject: [PATCH 069/122] ASoC: starfive: Add JH7110 TDM driver + +Add tdm driver support for the StarFive JH7110 SoC. + +Signed-off-by: Walker Chen +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + sound/soc/starfive/Kconfig | 15 + + sound/soc/starfive/Makefile | 2 + + sound/soc/starfive/jh7110_tdm.c | 679 ++++++++++++++++++++++++++++++++ + 5 files changed, 698 insertions(+) + create mode 100644 sound/soc/starfive/Kconfig + create mode 100644 sound/soc/starfive/Makefile + create mode 100644 sound/soc/starfive/jh7110_tdm.c + +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -91,6 +91,7 @@ source "sound/soc/sh/Kconfig" + source "sound/soc/sof/Kconfig" + source "sound/soc/spear/Kconfig" + source "sound/soc/sprd/Kconfig" ++source "sound/soc/starfive/Kconfig" + source "sound/soc/sti/Kconfig" + source "sound/soc/stm/Kconfig" + source "sound/soc/sunxi/Kconfig" +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -59,6 +59,7 @@ obj-$(CONFIG_SND_SOC) += sh/ + obj-$(CONFIG_SND_SOC) += sof/ + obj-$(CONFIG_SND_SOC) += spear/ + obj-$(CONFIG_SND_SOC) += sprd/ ++obj-$(CONFIG_SND_SOC) += starfive/ + obj-$(CONFIG_SND_SOC) += sti/ + obj-$(CONFIG_SND_SOC) += stm/ + obj-$(CONFIG_SND_SOC) += sunxi/ +--- /dev/null ++++ b/sound/soc/starfive/Kconfig +@@ -0,0 +1,15 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config SND_SOC_STARFIVE ++ tristate "Audio support for StarFive SoC" ++ depends on COMPILE_TEST || ARCH_STARFIVE ++ help ++ Say Y or M if you want to add support for codecs attached to ++ the Starfive SoCs' Audio interfaces. You will also need to ++ select the audio interfaces to support below. ++ ++config SND_SOC_JH7110_TDM ++ tristate "JH7110 TDM device driver" ++ depends on HAVE_CLK && SND_SOC_STARFIVE ++ select SND_SOC_GENERIC_DMAENGINE_PCM ++ help ++ Say Y or M if you want to add support for StarFive TDM driver. +--- /dev/null ++++ b/sound/soc/starfive/Makefile +@@ -0,0 +1,2 @@ ++# StarFive Platform Support ++obj-$(CONFIG_SND_SOC_JH7110_TDM) += jh7110_tdm.o +--- /dev/null ++++ b/sound/soc/starfive/jh7110_tdm.c +@@ -0,0 +1,679 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * jh7110_tdm.c -- StarFive JH7110 TDM driver ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * ++ * Author: Walker Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TDM_PCMGBCR 0x00 ++ #define PCMGBCR_MASK 0x1e ++ #define PCMGBCR_ENABLE BIT(0) ++ #define PCMGBCR_TRITXEN BIT(4) ++ #define CLKPOL_BIT 5 ++ #define TRITXEN_BIT 4 ++ #define ELM_BIT 3 ++ #define SYNCM_BIT 2 ++ #define MS_BIT 1 ++#define TDM_PCMTXCR 0x04 ++ #define PCMTXCR_TXEN BIT(0) ++ #define IFL_BIT 11 ++ #define WL_BIT 8 ++ #define SSCALE_BIT 4 ++ #define SL_BIT 2 ++ #define LRJ_BIT 1 ++#define TDM_PCMRXCR 0x08 ++ #define PCMRXCR_RXEN BIT(0) ++ #define PCMRXCR_RXSL_MASK 0xc ++ #define PCMRXCR_RXSL_16BIT 0x4 ++ #define PCMRXCR_RXSL_32BIT 0x8 ++ #define PCMRXCR_SCALE_MASK 0xf0 ++ #define PCMRXCR_SCALE_1CH 0x10 ++#define TDM_PCMDIV 0x0c ++ ++#define JH7110_TDM_FIFO 0x170c0000 ++#define JH7110_TDM_FIFO_DEPTH 32 ++ ++enum TDM_MASTER_SLAVE_MODE { ++ TDM_AS_MASTER = 0, ++ TDM_AS_SLAVE, ++}; ++ ++enum TDM_CLKPOL { ++ /* tx raising and rx falling */ ++ TDM_TX_RASING_RX_FALLING = 0, ++ /* tx falling and rx raising */ ++ TDM_TX_FALLING_RX_RASING, ++}; ++ ++enum TDM_ELM { ++ /* only work while SYNCM=0 */ ++ TDM_ELM_LATE = 0, ++ TDM_ELM_EARLY, ++}; ++ ++enum TDM_SYNCM { ++ /* short frame sync */ ++ TDM_SYNCM_SHORT = 0, ++ /* long frame sync */ ++ TDM_SYNCM_LONG, ++}; ++ ++enum TDM_IFL { ++ /* FIFO to send or received : half-1/2, Quarter-1/4 */ ++ TDM_FIFO_HALF = 0, ++ TDM_FIFO_QUARTER, ++}; ++ ++enum TDM_WL { ++ /* send or received word length */ ++ TDM_8BIT_WORD_LEN = 0, ++ TDM_16BIT_WORD_LEN, ++ TDM_20BIT_WORD_LEN, ++ TDM_24BIT_WORD_LEN, ++ TDM_32BIT_WORD_LEN, ++}; ++ ++enum TDM_SL { ++ /* send or received slot length */ ++ TDM_8BIT_SLOT_LEN = 0, ++ TDM_16BIT_SLOT_LEN, ++ TDM_32BIT_SLOT_LEN, ++}; ++ ++enum TDM_LRJ { ++ /* left-justify or right-justify */ ++ TDM_RIGHT_JUSTIFY = 0, ++ TDM_LEFT_JUSTIFT, ++}; ++ ++struct tdm_chan_cfg { ++ enum TDM_IFL ifl; ++ enum TDM_WL wl; ++ unsigned char sscale; ++ enum TDM_SL sl; ++ enum TDM_LRJ lrj; ++ unsigned char enable; ++}; ++ ++struct jh7110_tdm_dev { ++ void __iomem *tdm_base; ++ struct device *dev; ++ struct clk_bulk_data clks[6]; ++ struct reset_control *resets; ++ ++ enum TDM_CLKPOL clkpolity; ++ enum TDM_ELM elm; ++ enum TDM_SYNCM syncm; ++ enum TDM_MASTER_SLAVE_MODE ms_mode; ++ ++ struct tdm_chan_cfg tx; ++ struct tdm_chan_cfg rx; ++ ++ u16 syncdiv; ++ u32 samplerate; ++ u32 pcmclk; ++ ++ /* data related to DMA transfers b/w tdm and DMAC */ ++ struct snd_dmaengine_dai_dma_data play_dma_data; ++ struct snd_dmaengine_dai_dma_data capture_dma_data; ++ u32 saved_pcmgbcr; ++ u32 saved_pcmtxcr; ++ u32 saved_pcmrxcr; ++ u32 saved_pcmdiv; ++}; ++ ++static inline u32 jh7110_tdm_readl(struct jh7110_tdm_dev *tdm, u16 reg) ++{ ++ return readl_relaxed(tdm->tdm_base + reg); ++} ++ ++static inline void jh7110_tdm_writel(struct jh7110_tdm_dev *tdm, u16 reg, u32 val) ++{ ++ writel_relaxed(val, tdm->tdm_base + reg); ++} ++ ++static void jh7110_tdm_save_context(struct jh7110_tdm_dev *tdm, ++ struct snd_pcm_substream *substream) ++{ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ tdm->saved_pcmtxcr = jh7110_tdm_readl(tdm, TDM_PCMTXCR); ++ else ++ tdm->saved_pcmrxcr = jh7110_tdm_readl(tdm, TDM_PCMRXCR); ++} ++ ++static void jh7110_tdm_start(struct jh7110_tdm_dev *tdm, ++ struct snd_pcm_substream *substream) ++{ ++ u32 data; ++ ++ data = jh7110_tdm_readl(tdm, TDM_PCMGBCR); ++ jh7110_tdm_writel(tdm, TDM_PCMGBCR, data | PCMGBCR_ENABLE); ++ ++ /* restore context */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ jh7110_tdm_writel(tdm, TDM_PCMTXCR, tdm->saved_pcmtxcr | PCMTXCR_TXEN); ++ else ++ jh7110_tdm_writel(tdm, TDM_PCMRXCR, tdm->saved_pcmrxcr | PCMRXCR_RXEN); ++} ++ ++static void jh7110_tdm_stop(struct jh7110_tdm_dev *tdm, ++ struct snd_pcm_substream *substream) ++{ ++ unsigned int val; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ val = jh7110_tdm_readl(tdm, TDM_PCMTXCR); ++ val &= ~PCMTXCR_TXEN; ++ jh7110_tdm_writel(tdm, TDM_PCMTXCR, val); ++ } else { ++ val = jh7110_tdm_readl(tdm, TDM_PCMRXCR); ++ val &= ~PCMRXCR_RXEN; ++ jh7110_tdm_writel(tdm, TDM_PCMRXCR, val); ++ } ++} ++ ++static int jh7110_tdm_syncdiv(struct jh7110_tdm_dev *tdm) ++{ ++ u32 sl, sscale, syncdiv; ++ ++ if (tdm->rx.sl >= tdm->tx.sl) ++ sl = tdm->rx.sl; ++ else ++ sl = tdm->tx.sl; ++ ++ if (tdm->rx.sscale >= tdm->tx.sscale) ++ sscale = tdm->rx.sscale; ++ else ++ sscale = tdm->tx.sscale; ++ ++ syncdiv = tdm->pcmclk / tdm->samplerate - 1; ++ ++ if ((syncdiv + 1) < (sl * sscale)) { ++ dev_err(tdm->dev, "Failed to set syncdiv!\n"); ++ return -EINVAL; ++ } ++ ++ if (tdm->syncm == TDM_SYNCM_LONG && ++ (tdm->rx.sscale <= 1 || tdm->tx.sscale <= 1) && ++ ((syncdiv + 1) <= sl)) { ++ dev_err(tdm->dev, "Wrong syncdiv! It must be (syncdiv+1) > max[tx.sl, rx.sl]\n"); ++ return -EINVAL; ++ } ++ ++ jh7110_tdm_writel(tdm, TDM_PCMDIV, syncdiv); ++ return 0; ++} ++ ++static int jh7110_tdm_config(struct jh7110_tdm_dev *tdm, ++ struct snd_pcm_substream *substream) ++{ ++ u32 datarx, datatx; ++ int ret; ++ ++ ret = jh7110_tdm_syncdiv(tdm); ++ if (ret) ++ return ret; ++ ++ datarx = (tdm->rx.ifl << IFL_BIT) | ++ (tdm->rx.wl << WL_BIT) | ++ (tdm->rx.sscale << SSCALE_BIT) | ++ (tdm->rx.sl << SL_BIT) | ++ (tdm->rx.lrj << LRJ_BIT); ++ ++ datatx = (tdm->tx.ifl << IFL_BIT) | ++ (tdm->tx.wl << WL_BIT) | ++ (tdm->tx.sscale << SSCALE_BIT) | ++ (tdm->tx.sl << SL_BIT) | ++ (tdm->tx.lrj << LRJ_BIT); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ jh7110_tdm_writel(tdm, TDM_PCMTXCR, datatx); ++ else ++ jh7110_tdm_writel(tdm, TDM_PCMRXCR, datarx); ++ ++ return 0; ++} ++ ++static void jh7110_tdm_clk_disable(struct jh7110_tdm_dev *tdm) ++{ ++ clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks); ++} ++ ++static int jh7110_tdm_clk_enable(struct jh7110_tdm_dev *tdm) ++{ ++ int ret; ++ ++ ret = clk_bulk_prepare_enable(ARRAY_SIZE(tdm->clks), tdm->clks); ++ if (ret) { ++ dev_err(tdm->dev, "Failed to enable tdm clocks\n"); ++ return ret; ++ } ++ ++ ret = reset_control_deassert(tdm->resets); ++ if (ret) { ++ dev_err(tdm->dev, "Failed to deassert tdm resets\n"); ++ goto dis_tdm_clk; ++ } ++ ++ /* select tdm_ext clock as the clock source for tdm */ ++ ret = clk_set_parent(tdm->clks[5].clk, tdm->clks[4].clk); ++ if (ret) { ++ dev_err(tdm->dev, "Can't set extern clock source for clk_tdm\n"); ++ goto dis_tdm_clk; ++ } ++ ++ return 0; ++ ++dis_tdm_clk: ++ clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks); ++ ++ return ret; ++} ++ ++static int jh7110_tdm_runtime_suspend(struct device *dev) ++{ ++ struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); ++ ++ jh7110_tdm_clk_disable(tdm); ++ return 0; ++} ++ ++static int jh7110_tdm_runtime_resume(struct device *dev) ++{ ++ struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); ++ ++ return jh7110_tdm_clk_enable(tdm); ++} ++ ++static int jh7110_tdm_system_suspend(struct device *dev) ++{ ++ struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); ++ ++ /* save context */ ++ tdm->saved_pcmgbcr = jh7110_tdm_readl(tdm, TDM_PCMGBCR); ++ tdm->saved_pcmdiv = jh7110_tdm_readl(tdm, TDM_PCMDIV); ++ ++ return pm_runtime_force_suspend(dev); ++} ++ ++static int jh7110_tdm_system_resume(struct device *dev) ++{ ++ struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); ++ ++ /* restore context */ ++ jh7110_tdm_writel(tdm, TDM_PCMGBCR, tdm->saved_pcmgbcr); ++ jh7110_tdm_writel(tdm, TDM_PCMDIV, tdm->saved_pcmdiv); ++ ++ return pm_runtime_force_resume(dev); ++} ++ ++static const struct snd_soc_component_driver jh7110_tdm_component = { ++ .name = "jh7110-tdm", ++}; ++ ++static int jh7110_tdm_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *cpu_dai) ++{ ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct snd_soc_dai_link *dai_link = rtd->dai_link; ++ ++ dai_link->stop_dma_first = 1; ++ ++ return 0; ++} ++ ++static int jh7110_tdm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); ++ int chan_wl, chan_sl, chan_nr; ++ unsigned int data_width; ++ unsigned int dma_bus_width; ++ struct snd_dmaengine_dai_dma_data *dma_data = NULL; ++ int ret; ++ ++ data_width = params_width(params); ++ ++ tdm->samplerate = params_rate(params); ++ tdm->pcmclk = params_channels(params) * tdm->samplerate * data_width; ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ chan_wl = TDM_16BIT_WORD_LEN; ++ chan_sl = TDM_16BIT_SLOT_LEN; ++ dma_bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ break; ++ ++ case SNDRV_PCM_FORMAT_S32_LE: ++ chan_wl = TDM_32BIT_WORD_LEN; ++ chan_sl = TDM_32BIT_SLOT_LEN; ++ dma_bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ break; ++ ++ default: ++ dev_err(tdm->dev, "tdm: unsupported PCM fmt"); ++ return -EINVAL; ++ } ++ ++ chan_nr = params_channels(params); ++ switch (chan_nr) { ++ case 1: ++ case 2: ++ case 4: ++ case 6: ++ case 8: ++ break; ++ default: ++ dev_err(tdm->dev, "channel not supported\n"); ++ return -EINVAL; ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ tdm->tx.wl = chan_wl; ++ tdm->tx.sl = chan_sl; ++ tdm->tx.sscale = chan_nr; ++ tdm->play_dma_data.addr_width = dma_bus_width; ++ dma_data = &tdm->play_dma_data; ++ } else { ++ tdm->rx.wl = chan_wl; ++ tdm->rx.sl = chan_sl; ++ tdm->rx.sscale = chan_nr; ++ tdm->capture_dma_data.addr_width = dma_bus_width; ++ dma_data = &tdm->capture_dma_data; ++ } ++ ++ snd_soc_dai_set_dma_data(dai, substream, dma_data); ++ ++ ret = jh7110_tdm_config(tdm, substream); ++ if (ret) ++ return ret; ++ ++ jh7110_tdm_save_context(tdm, substream); ++ return 0; ++} ++ ++static int jh7110_tdm_trigger(struct snd_pcm_substream *substream, ++ int cmd, struct snd_soc_dai *dai) ++{ ++ struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); ++ int ret = 0; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ jh7110_tdm_start(tdm, substream); ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ jh7110_tdm_stop(tdm, substream); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, ++ unsigned int fmt) ++{ ++ struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(cpu_dai); ++ unsigned int gbcr; ++ ++ /* set master/slave audio interface */ ++ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { ++ case SND_SOC_DAIFMT_BP_FP: ++ /* cpu is master */ ++ tdm->ms_mode = TDM_AS_MASTER; ++ break; ++ case SND_SOC_DAIFMT_BC_FC: ++ /* codec is master */ ++ tdm->ms_mode = TDM_AS_SLAVE; ++ break; ++ case SND_SOC_DAIFMT_BC_FP: ++ case SND_SOC_DAIFMT_BP_FC: ++ return -EINVAL; ++ default: ++ dev_dbg(tdm->dev, "dwc : Invalid clock provider format\n"); ++ return -EINVAL; ++ } ++ ++ gbcr = (tdm->clkpolity << CLKPOL_BIT) | ++ (tdm->elm << ELM_BIT) | ++ (tdm->syncm << SYNCM_BIT) | ++ (tdm->ms_mode << MS_BIT); ++ jh7110_tdm_writel(tdm, TDM_PCMGBCR, gbcr); ++ ++ return 0; ++} ++ ++static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { ++ .startup = jh7110_tdm_startup, ++ .hw_params = jh7110_tdm_hw_params, ++ .trigger = jh7110_tdm_trigger, ++ .set_fmt = jh7110_tdm_set_dai_fmt, ++}; ++ ++static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); ++ ++ snd_soc_dai_init_dma_data(dai, &tdm->play_dma_data, &tdm->capture_dma_data); ++ snd_soc_dai_set_drvdata(dai, tdm); ++ return 0; ++} ++ ++#define JH7110_TDM_RATES SNDRV_PCM_RATE_8000_48000 ++ ++#define JH7110_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++static struct snd_soc_dai_driver jh7110_tdm_dai = { ++ .name = "sf_tdm", ++ .id = 0, ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = JH7110_TDM_RATES, ++ .formats = JH7110_TDM_FORMATS, ++ }, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = JH7110_TDM_RATES, ++ .formats = JH7110_TDM_FORMATS, ++ }, ++ .ops = &jh7110_tdm_dai_ops, ++ .probe = jh7110_tdm_dai_probe, ++ .symmetric_rate = 1, ++}; ++ ++static const struct snd_pcm_hardware jh7110_pcm_hardware = { ++ .info = (SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_PAUSE | ++ SNDRV_PCM_INFO_RESUME | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER), ++ .buffer_bytes_max = 192512, ++ .period_bytes_min = 4096, ++ .period_bytes_max = 32768, ++ .periods_min = 1, ++ .periods_max = 48, ++ .fifo_size = 16, ++}; ++ ++static const struct snd_dmaengine_pcm_config jh7110_dmaengine_pcm_config = { ++ .pcm_hardware = &jh7110_pcm_hardware, ++ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, ++ .prealloc_buffer_size = 192512, ++}; ++ ++static void jh7110_tdm_init_params(struct jh7110_tdm_dev *tdm) ++{ ++ tdm->clkpolity = TDM_TX_RASING_RX_FALLING; ++ tdm->elm = TDM_ELM_LATE; ++ tdm->syncm = TDM_SYNCM_SHORT; ++ ++ tdm->rx.ifl = TDM_FIFO_HALF; ++ tdm->tx.ifl = TDM_FIFO_HALF; ++ tdm->rx.wl = TDM_16BIT_WORD_LEN; ++ tdm->tx.wl = TDM_16BIT_WORD_LEN; ++ tdm->rx.sscale = 2; ++ tdm->tx.sscale = 2; ++ tdm->rx.lrj = TDM_LEFT_JUSTIFT; ++ tdm->tx.lrj = TDM_LEFT_JUSTIFT; ++ ++ tdm->play_dma_data.addr = JH7110_TDM_FIFO; ++ tdm->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ tdm->play_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2; ++ tdm->play_dma_data.maxburst = 16; ++ ++ tdm->capture_dma_data.addr = JH7110_TDM_FIFO; ++ tdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ tdm->capture_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2; ++ tdm->capture_dma_data.maxburst = 8; ++} ++ ++static int jh7110_tdm_clk_reset_get(struct platform_device *pdev, ++ struct jh7110_tdm_dev *tdm) ++{ ++ int ret; ++ ++ tdm->clks[0].id = "mclk_inner"; ++ tdm->clks[1].id = "tdm_ahb"; ++ tdm->clks[2].id = "tdm_apb"; ++ tdm->clks[3].id = "tdm_internal"; ++ tdm->clks[4].id = "tdm_ext"; ++ tdm->clks[5].id = "tdm"; ++ ++ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to get tdm clocks\n"); ++ return ret; ++ } ++ ++ tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev); ++ if (IS_ERR_OR_NULL(tdm->resets)) { ++ ret = PTR_ERR(tdm->resets); ++ dev_err(&pdev->dev, "Failed to get tdm resets"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int jh7110_tdm_probe(struct platform_device *pdev) ++{ ++ struct jh7110_tdm_dev *tdm; ++ int ret; ++ ++ tdm = devm_kzalloc(&pdev->dev, sizeof(*tdm), GFP_KERNEL); ++ if (!tdm) ++ return -ENOMEM; ++ ++ tdm->tdm_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(tdm->tdm_base)) ++ return PTR_ERR(tdm->tdm_base); ++ ++ tdm->dev = &pdev->dev; ++ ++ ret = jh7110_tdm_clk_reset_get(pdev, tdm); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n"); ++ return ret; ++ } ++ ++ jh7110_tdm_init_params(tdm); ++ ++ dev_set_drvdata(&pdev->dev, tdm); ++ ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component, ++ &jh7110_tdm_dai, 1); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register dai\n"); ++ return ret; ++ } ++ ++ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, ++ &jh7110_dmaengine_pcm_config, ++ SND_DMAENGINE_PCM_FLAG_COMPAT); ++ if (ret) { ++ dev_err(&pdev->dev, "Could not register pcm: %d\n", ret); ++ return ret; ++ } ++ ++ pm_runtime_enable(&pdev->dev); ++ if (!pm_runtime_enabled(&pdev->dev)) { ++ ret = jh7110_tdm_runtime_resume(&pdev->dev); ++ if (ret) ++ goto err_pm_disable; ++ } ++ ++ return 0; ++ ++err_pm_disable: ++ pm_runtime_disable(&pdev->dev); ++ ++ return ret; ++} ++ ++static int jh7110_tdm_dev_remove(struct platform_device *pdev) ++{ ++ pm_runtime_disable(&pdev->dev); ++ return 0; ++} ++ ++static const struct of_device_id jh7110_tdm_of_match[] = { ++ { .compatible = "starfive,jh7110-tdm", }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(of, jh7110_tdm_of_match); ++ ++static const struct dev_pm_ops jh7110_tdm_pm_ops = { ++ RUNTIME_PM_OPS(jh7110_tdm_runtime_suspend, ++ jh7110_tdm_runtime_resume, NULL) ++ SYSTEM_SLEEP_PM_OPS(jh7110_tdm_system_suspend, ++ jh7110_tdm_system_resume) ++}; ++ ++static struct platform_driver jh7110_tdm_driver = { ++ .driver = { ++ .name = "jh7110-tdm", ++ .of_match_table = jh7110_tdm_of_match, ++ .pm = pm_ptr(&jh7110_tdm_pm_ops), ++ }, ++ .probe = jh7110_tdm_probe, ++ .remove = jh7110_tdm_dev_remove, ++}; ++module_platform_driver(jh7110_tdm_driver); ++ ++MODULE_DESCRIPTION("StarFive JH7110 TDM ASoC Driver"); ++MODULE_AUTHOR("Walker Chen "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0070-dt-bindings-power-Add-power-domain-header-for-JH7110.patch b/target/linux/starfive/patches-6.1/0070-dt-bindings-power-Add-power-domain-header-for-JH7110.patch new file mode 100644 index 0000000000..d8ba979f55 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0070-dt-bindings-power-Add-power-domain-header-for-JH7110.patch @@ -0,0 +1,32 @@ +From 598083825494088f927fa42c5a7bb2872029a7bc Mon Sep 17 00:00:00 2001 +From: Changhuang Liang +Date: Thu, 18 May 2023 23:01:59 -0700 +Subject: [PATCH 070/122] dt-bindings: power: Add power-domain header for + JH7110 + +Add power-domain header for JH7110 SoC, it can use to operate dphy +power. + +Signed-off-by: Changhuang Liang +--- + include/dt-bindings/power/starfive,jh7110-pmu.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/include/dt-bindings/power/starfive,jh7110-pmu.h ++++ b/include/dt-bindings/power/starfive,jh7110-pmu.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + /* +- * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. + * Author: Walker Chen + */ + #ifndef __DT_BINDINGS_POWER_JH7110_POWER_H__ +@@ -14,4 +14,7 @@ + #define JH7110_PD_ISP 5 + #define JH7110_PD_VENC 6 + ++#define JH7110_PD_DPHY_TX 0 ++#define JH7110_PD_DPHY_RX 1 ++ + #endif diff --git a/target/linux/starfive/patches-6.1/0071-soc-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFIVE.patch b/target/linux/starfive/patches-6.1/0071-soc-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFIVE.patch new file mode 100644 index 0000000000..fa0201b6ca --- /dev/null +++ b/target/linux/starfive/patches-6.1/0071-soc-starfive-Replace-SOC_STARFIVE-with-ARCH_STARFIVE.patch @@ -0,0 +1,28 @@ +From d83b51f60997365b80637f71924ab3dec91d5b77 Mon Sep 17 00:00:00 2001 +From: Changhuang Liang +Date: Thu, 18 May 2023 23:02:00 -0700 +Subject: [PATCH 071/122] soc: starfive: Replace SOC_STARFIVE with + ARCH_STARFIVE + +Using ARCH_FOO symbol is preferred than SOC_FOO. + +Reviewed-by: Conor Dooley +Reviewed-by: Walker Chen +Signed-off-by: Changhuang Liang +--- + drivers/soc/starfive/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/soc/starfive/Kconfig ++++ b/drivers/soc/starfive/Kconfig +@@ -3,8 +3,8 @@ + config JH71XX_PMU + bool "Support PMU for StarFive JH71XX Soc" + depends on PM +- depends on SOC_STARFIVE || COMPILE_TEST +- default SOC_STARFIVE ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ default ARCH_STARFIVE + select PM_GENERIC_DOMAINS + help + Say 'y' here to enable support power domain support. diff --git a/target/linux/starfive/patches-6.1/0072-soc-starfive-Extract-JH7110-pmu-private-operations.patch b/target/linux/starfive/patches-6.1/0072-soc-starfive-Extract-JH7110-pmu-private-operations.patch new file mode 100644 index 0000000000..5f2cb2810f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0072-soc-starfive-Extract-JH7110-pmu-private-operations.patch @@ -0,0 +1,175 @@ +From 52e2ade50f3ec212468e284b1236aaa521ba5913 Mon Sep 17 00:00:00 2001 +From: Changhuang Liang +Date: Thu, 18 May 2023 23:02:01 -0700 +Subject: [PATCH 072/122] soc: starfive: Extract JH7110 pmu private operations + +Move JH7110 private operation into private data of compatible. Convenient +to add AON PMU which would not have interrupts property. + +Signed-off-by: Changhuang Liang +Reviewed-by: Walker Chen +--- + drivers/soc/starfive/jh71xx_pmu.c | 89 +++++++++++++++++++++---------- + 1 file changed, 62 insertions(+), 27 deletions(-) + +--- a/drivers/soc/starfive/jh71xx_pmu.c ++++ b/drivers/soc/starfive/jh71xx_pmu.c +@@ -51,9 +51,17 @@ struct jh71xx_domain_info { + u8 bit; + }; + ++struct jh71xx_pmu; ++struct jh71xx_pmu_dev; ++ + struct jh71xx_pmu_match_data { + const struct jh71xx_domain_info *domain_info; + int num_domains; ++ unsigned int pmu_status; ++ int (*pmu_parse_irq)(struct platform_device *pdev, ++ struct jh71xx_pmu *pmu); ++ int (*pmu_set_state)(struct jh71xx_pmu_dev *pmd, ++ u32 mask, bool on); + }; + + struct jh71xx_pmu { +@@ -79,12 +87,12 @@ static int jh71xx_pmu_get_state(struct j + if (!mask) + return -EINVAL; + +- *is_on = readl(pmu->base + JH71XX_PMU_CURR_POWER_MODE) & mask; ++ *is_on = readl(pmu->base + pmu->match_data->pmu_status) & mask; + + return 0; + } + +-static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on) ++static int jh7110_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on) + { + struct jh71xx_pmu *pmu = pmd->pmu; + unsigned long flags; +@@ -92,22 +100,8 @@ static int jh71xx_pmu_set_state(struct j + u32 mode; + u32 encourage_lo; + u32 encourage_hi; +- bool is_on; + int ret; + +- ret = jh71xx_pmu_get_state(pmd, mask, &is_on); +- if (ret) { +- dev_dbg(pmu->dev, "unable to get current state for %s\n", +- pmd->genpd.name); +- return ret; +- } +- +- if (is_on == on) { +- dev_dbg(pmu->dev, "pm domain [%s] is already %sable status.\n", +- pmd->genpd.name, on ? "en" : "dis"); +- return 0; +- } +- + spin_lock_irqsave(&pmu->lock, flags); + + /* +@@ -166,6 +160,29 @@ static int jh71xx_pmu_set_state(struct j + return 0; + } + ++static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on) ++{ ++ struct jh71xx_pmu *pmu = pmd->pmu; ++ const struct jh71xx_pmu_match_data *match_data = pmu->match_data; ++ bool is_on; ++ int ret; ++ ++ ret = jh71xx_pmu_get_state(pmd, mask, &is_on); ++ if (ret) { ++ dev_dbg(pmu->dev, "unable to get current state for %s\n", ++ pmd->genpd.name); ++ return ret; ++ } ++ ++ if (is_on == on) { ++ dev_dbg(pmu->dev, "pm domain [%s] is already %sable status.\n", ++ pmd->genpd.name, on ? "en" : "dis"); ++ return 0; ++ } ++ ++ return match_data->pmu_set_state(pmd, mask, on); ++} ++ + static int jh71xx_pmu_on(struct generic_pm_domain *genpd) + { + struct jh71xx_pmu_dev *pmd = container_of(genpd, +@@ -226,6 +243,25 @@ static irqreturn_t jh71xx_pmu_interrupt( + return IRQ_HANDLED; + } + ++static int jh7110_pmu_parse_irq(struct platform_device *pdev, struct jh71xx_pmu *pmu) ++{ ++ struct device *dev = &pdev->dev; ++ int ret; ++ ++ pmu->irq = platform_get_irq(pdev, 0); ++ if (pmu->irq < 0) ++ return pmu->irq; ++ ++ ret = devm_request_irq(dev, pmu->irq, jh71xx_pmu_interrupt, ++ 0, pdev->name, pmu); ++ if (ret) ++ dev_err(dev, "failed to request irq\n"); ++ ++ jh71xx_pmu_int_enable(pmu, JH71XX_PMU_INT_ALL_MASK & ~JH71XX_PMU_INT_PCH_FAIL, true); ++ ++ return 0; ++} ++ + static int jh71xx_pmu_init_domain(struct jh71xx_pmu *pmu, int index) + { + struct jh71xx_pmu_dev *pmd; +@@ -275,19 +311,18 @@ static int jh71xx_pmu_probe(struct platf + if (IS_ERR(pmu->base)) + return PTR_ERR(pmu->base); + +- pmu->irq = platform_get_irq(pdev, 0); +- if (pmu->irq < 0) +- return pmu->irq; +- +- ret = devm_request_irq(dev, pmu->irq, jh71xx_pmu_interrupt, +- 0, pdev->name, pmu); +- if (ret) +- dev_err(dev, "failed to request irq\n"); ++ spin_lock_init(&pmu->lock); + + match_data = of_device_get_match_data(dev); + if (!match_data) + return -EINVAL; + ++ ret = match_data->pmu_parse_irq(pdev, pmu); ++ if (ret) { ++ dev_err(dev, "failed to parse irq\n"); ++ return ret; ++ } ++ + pmu->genpd = devm_kcalloc(dev, match_data->num_domains, + sizeof(struct generic_pm_domain *), + GFP_KERNEL); +@@ -307,9 +342,6 @@ static int jh71xx_pmu_probe(struct platf + } + } + +- spin_lock_init(&pmu->lock); +- jh71xx_pmu_int_enable(pmu, JH71XX_PMU_INT_ALL_MASK & ~JH71XX_PMU_INT_PCH_FAIL, true); +- + ret = of_genpd_add_provider_onecell(np, &pmu->genpd_data); + if (ret) { + dev_err(dev, "failed to register genpd driver: %d\n", ret); +@@ -357,6 +389,9 @@ static const struct jh71xx_domain_info j + static const struct jh71xx_pmu_match_data jh7110_pmu = { + .num_domains = ARRAY_SIZE(jh7110_power_domains), + .domain_info = jh7110_power_domains, ++ .pmu_status = JH71XX_PMU_CURR_POWER_MODE, ++ .pmu_parse_irq = jh7110_pmu_parse_irq, ++ .pmu_set_state = jh7110_pmu_set_state, + }; + + static const struct of_device_id jh71xx_pmu_of_match[] = { diff --git a/target/linux/starfive/patches-6.1/0073-soc-starfive-Add-JH7110-AON-PMU-support.patch b/target/linux/starfive/patches-6.1/0073-soc-starfive-Add-JH7110-AON-PMU-support.patch new file mode 100644 index 0000000000..ec7a476b8f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0073-soc-starfive-Add-JH7110-AON-PMU-support.patch @@ -0,0 +1,119 @@ +From 3124d653318c50e20eadbb3998eafa5928ac9b63 Mon Sep 17 00:00:00 2001 +From: Changhuang Liang +Date: Thu, 18 May 2023 23:02:02 -0700 +Subject: [PATCH 073/122] soc: starfive: Add JH7110 AON PMU support + +Add AON PMU for StarFive JH7110 SoC. It can be used to turn on/off the +dphy rx/tx power switch. + +Reviewed-by: Walker Chen +Signed-off-by: Changhuang Liang +--- + drivers/soc/starfive/jh71xx_pmu.c | 57 ++++++++++++++++++++++++++++--- + 1 file changed, 52 insertions(+), 5 deletions(-) + +--- a/drivers/soc/starfive/jh71xx_pmu.c ++++ b/drivers/soc/starfive/jh71xx_pmu.c +@@ -2,7 +2,7 @@ + /* + * StarFive JH71XX PMU (Power Management Unit) Controller Driver + * +- * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. + */ + + #include +@@ -24,6 +24,9 @@ + #define JH71XX_PMU_EVENT_STATUS 0x88 + #define JH71XX_PMU_INT_STATUS 0x8C + ++/* aon pmu register offset */ ++#define JH71XX_AON_PMU_SWITCH 0x00 ++ + /* sw encourage cfg */ + #define JH71XX_PMU_SW_ENCOURAGE_EN_LO 0x05 + #define JH71XX_PMU_SW_ENCOURAGE_EN_HI 0x50 +@@ -160,6 +163,26 @@ static int jh7110_pmu_set_state(struct j + return 0; + } + ++static int jh7110_aon_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on) ++{ ++ struct jh71xx_pmu *pmu = pmd->pmu; ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&pmu->lock, flags); ++ val = readl(pmu->base + JH71XX_AON_PMU_SWITCH); ++ ++ if (on) ++ val |= mask; ++ else ++ val &= ~mask; ++ ++ writel(val, pmu->base + JH71XX_AON_PMU_SWITCH); ++ spin_unlock_irqrestore(&pmu->lock, flags); ++ ++ return 0; ++} ++ + static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on) + { + struct jh71xx_pmu *pmu = pmd->pmu; +@@ -317,10 +340,12 @@ static int jh71xx_pmu_probe(struct platf + if (!match_data) + return -EINVAL; + +- ret = match_data->pmu_parse_irq(pdev, pmu); +- if (ret) { +- dev_err(dev, "failed to parse irq\n"); +- return ret; ++ if (match_data->pmu_parse_irq) { ++ ret = match_data->pmu_parse_irq(pdev, pmu); ++ if (ret) { ++ dev_err(dev, "failed to parse irq\n"); ++ return ret; ++ } + } + + pmu->genpd = devm_kcalloc(dev, match_data->num_domains, +@@ -394,11 +419,32 @@ static const struct jh71xx_pmu_match_dat + .pmu_set_state = jh7110_pmu_set_state, + }; + ++static const struct jh71xx_domain_info jh7110_aon_power_domains[] = { ++ [JH7110_PD_DPHY_TX] = { ++ .name = "DPHY-TX", ++ .bit = 30, ++ }, ++ [JH7110_PD_DPHY_RX] = { ++ .name = "DPHY-RX", ++ .bit = 31, ++ }, ++}; ++ ++static const struct jh71xx_pmu_match_data jh7110_aon_pmu = { ++ .num_domains = ARRAY_SIZE(jh7110_aon_power_domains), ++ .domain_info = jh7110_aon_power_domains, ++ .pmu_status = JH71XX_AON_PMU_SWITCH, ++ .pmu_set_state = jh7110_aon_pmu_set_state, ++}; ++ + static const struct of_device_id jh71xx_pmu_of_match[] = { + { + .compatible = "starfive,jh7110-pmu", + .data = (void *)&jh7110_pmu, + }, { ++ .compatible = "starfive,jh7110-aon-syscon", ++ .data = (void *)&jh7110_aon_pmu, ++ }, { + /* sentinel */ + } + }; +@@ -414,5 +460,6 @@ static struct platform_driver jh71xx_pmu + builtin_platform_driver(jh71xx_pmu_driver); + + MODULE_AUTHOR("Walker Chen "); ++MODULE_AUTHOR("Changhuang Liang "); + MODULE_DESCRIPTION("StarFive JH71XX PMU Driver"); + MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0074-dt-bindings-phy-Add-starfive-jh7110-dphy-rx.patch b/target/linux/starfive/patches-6.1/0074-dt-bindings-phy-Add-starfive-jh7110-dphy-rx.patch new file mode 100644 index 0000000000..6368e53d84 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0074-dt-bindings-phy-Add-starfive-jh7110-dphy-rx.patch @@ -0,0 +1,88 @@ +From 7492ebbdd926da258f9abea5c41a9f8c4ec48631 Mon Sep 17 00:00:00 2001 +From: Changhuang Liang +Date: Mon, 29 May 2023 05:15:01 -0700 +Subject: [PATCH 074/122] dt-bindings: phy: Add starfive,jh7110-dphy-rx + +StarFive SoCs like the jh7110 use a MIPI D-PHY RX controller based on +a M31 IP. Add a binding for it. + +Signed-off-by: Changhuang Liang +--- + .../bindings/phy/starfive,jh7110-dphy-rx.yaml | 71 +++++++++++++++++++ + 1 file changed, 71 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml +@@ -0,0 +1,71 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/phy/starfive,jh7110-dphy-rx.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive SoC MIPI D-PHY Rx Controller ++ ++maintainers: ++ - Jack Zhu ++ - Changhuang Liang ++ ++description: ++ The StarFive SoC uses the MIPI CSI D-PHY based on M31 IP to transfer ++ CSI camera data. ++ ++properties: ++ compatible: ++ const: starfive,jh7110-dphy-rx ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: config clock ++ - description: reference clock ++ - description: escape mode transmit clock ++ ++ clock-names: ++ items: ++ - const: cfg ++ - const: ref ++ - const: tx ++ ++ resets: ++ items: ++ - description: DPHY_HW reset ++ - description: DPHY_B09_ALWAYS_ON reset ++ ++ power-domains: ++ maxItems: 1 ++ ++ "#phy-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - power-domains ++ - "#phy-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ phy@19820000 { ++ compatible = "starfive,jh7110-dphy-rx"; ++ reg = <0x19820000 0x10000>; ++ clocks = <&ispcrg 3>, ++ <&ispcrg 4>, ++ <&ispcrg 5>; ++ clock-names = "cfg", "ref", "tx"; ++ resets = <&ispcrg 2>, ++ <&ispcrg 3>; ++ power-domains = <&dphy_pwrc 1>; ++ #phy-cells = <0>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0075-phy-starfive-Add-mipi-dphy-rx-support.patch b/target/linux/starfive/patches-6.1/0075-phy-starfive-Add-mipi-dphy-rx-support.patch new file mode 100644 index 0000000000..d5db36a1e6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0075-phy-starfive-Add-mipi-dphy-rx-support.patch @@ -0,0 +1,365 @@ +From f6fbb431f9e3ac5c9144edf05340db9a96dffa59 Mon Sep 17 00:00:00 2001 +From: Changhuang Liang +Date: Mon, 29 May 2023 05:15:02 -0700 +Subject: [PATCH 075/122] phy: starfive: Add mipi dphy rx support + +Add mipi dphy rx support for the StarFive JH7110 SoC. It is used to +transfer CSI camera data. + +Signed-off-by: Changhuang Liang +--- + drivers/phy/Kconfig | 1 + + drivers/phy/Makefile | 1 + + drivers/phy/starfive/Kconfig | 13 + + drivers/phy/starfive/Makefile | 2 + + drivers/phy/starfive/phy-starfive-dphy-rx.c | 301 ++++++++++++++++++++ + 5 files changed, 318 insertions(+) + create mode 100644 drivers/phy/starfive/Kconfig + create mode 100644 drivers/phy/starfive/Makefile + create mode 100644 drivers/phy/starfive/phy-starfive-dphy-rx.c + +--- a/drivers/phy/Kconfig ++++ b/drivers/phy/Kconfig +@@ -91,6 +91,7 @@ source "drivers/phy/rockchip/Kconfig" + source "drivers/phy/samsung/Kconfig" + source "drivers/phy/socionext/Kconfig" + source "drivers/phy/st/Kconfig" ++source "drivers/phy/starfive/Kconfig" + source "drivers/phy/sunplus/Kconfig" + source "drivers/phy/tegra/Kconfig" + source "drivers/phy/ti/Kconfig" +--- a/drivers/phy/Makefile ++++ b/drivers/phy/Makefile +@@ -31,6 +31,7 @@ obj-y += allwinner/ \ + samsung/ \ + socionext/ \ + st/ \ ++ starfive/ \ + sunplus/ \ + tegra/ \ + ti/ \ +--- /dev/null ++++ b/drivers/phy/starfive/Kconfig +@@ -0,0 +1,13 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Phy drivers for StarFive platforms ++# ++ ++config PHY_STARFIVE_DPHY_RX ++ tristate "StarFive D-PHY RX Support" ++ select GENERIC_PHY ++ select GENERIC_PHY_MIPI_DPHY ++ help ++ Choose this option if you have a StarFive D-PHY in your ++ system. If M is selected, the module will be called ++ phy-starfive-dphy-rx. +--- /dev/null ++++ b/drivers/phy/starfive/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_PHY_STARFIVE_DPHY_RX) += phy-starfive-dphy-rx.o +--- /dev/null ++++ b/drivers/phy/starfive/phy-starfive-dphy-rx.c +@@ -0,0 +1,301 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DPHY driver for the StarFive JH7110 SoC ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define STF_DPHY_APBCFGSAIF_SYSCFG(x) (x) ++ ++#define STF_DPHY_DA_CDPHY_R100_CTRL0_2D1C_EFUSE_EN BIT(6) ++#define STF_DPHY_DA_CDPHY_R100_CTRL0_2D1C_EFUSE_IN GENMASK(12, 7) ++#define STF_DPHY_DA_CDPHY_R100_CTRL1_2D1C_EFUSE_EN BIT(19) ++#define STF_DPHY_DA_CDPHY_R100_CTRL1_2D1C_EFUSE_IN GENMASK(25, 20) ++ ++#define STF_DPHY_DATA_BUS16_8 BIT(8) ++#define STF_DPHY_DEBUG_MODE_SEL GENMASK(15, 9) ++ ++#define STF_DPHY_ENABLE_CLK BIT(6) ++#define STF_DPHY_ENABLE_CLK1 BIT(7) ++#define STF_DPHY_ENABLE_LAN0 BIT(8) ++#define STF_DPHY_ENABLE_LAN1 BIT(9) ++#define STF_DPHY_ENABLE_LAN2 BIT(10) ++#define STF_DPHY_ENABLE_LAN3 BIT(11) ++#define STF_DPHY_GPI_EN GENMASK(17, 12) ++#define STF_DPHY_HS_FREQ_CHANGE_CLK BIT(18) ++#define STF_DPHY_HS_FREQ_CHANGE_CLK1 BIT(19) ++#define STF_DPHY_LANE_SWAP_CLK GENMASK(22, 20) ++#define STF_DPHY_LANE_SWAP_CLK1 GENMASK(25, 23) ++#define STF_DPHY_LANE_SWAP_LAN0 GENMASK(28, 26) ++#define STF_DPHY_LANE_SWAP_LAN1 GENMASK(31, 29) ++ ++#define STF_DPHY_LANE_SWAP_LAN2 GENMASK(2, 0) ++#define STF_DPHY_LANE_SWAP_LAN3 GENMASK(5, 3) ++#define STF_DPHY_MP_TEST_EN BIT(6) ++#define STF_DPHY_MP_TEST_MODE_SEL GENMASK(11, 7) ++#define STF_DPHY_PLL_CLK_SEL GENMASK(21, 12) ++#define STF_DPHY_PRECOUNTER_IN_CLK GENMASK(29, 22) ++ ++#define STF_DPHY_PRECOUNTER_IN_CLK1 GENMASK(7, 0) ++#define STF_DPHY_PRECOUNTER_IN_LAN0 GENMASK(15, 8) ++#define STF_DPHY_PRECOUNTER_IN_LAN1 GENMASK(23, 16) ++#define STF_DPHY_PRECOUNTER_IN_LAN2 GENMASK(31, 24) ++ ++#define STF_DPHY_PRECOUNTER_IN_LAN3 GENMASK(7, 0) ++#define STF_DPHY_RX_1C2C_SEL BIT(8) ++ ++#define STF_MAP_LANES_NUM 6 ++ ++struct regval { ++ u32 addr; ++ u32 val; ++}; ++ ++struct stf_dphy_info { ++ /** ++ * @maps: ++ * ++ * Physical lanes and logic lanes mapping table. ++ * ++ * The default order is: ++ * [clk lane0, data lane 0, data lane 1, data lane 2, date lane 3, clk lane 1] ++ */ ++ u8 maps[STF_MAP_LANES_NUM]; ++}; ++ ++struct stf_dphy { ++ struct device *dev; ++ void __iomem *regs; ++ struct clk *cfg_clk; ++ struct clk *ref_clk; ++ struct clk *tx_clk; ++ struct reset_control *rstc; ++ struct regulator *mipi_0p9; ++ struct phy *phy; ++ const struct stf_dphy_info *info; ++}; ++ ++static const struct regval stf_dphy_init_list[] = { ++ { STF_DPHY_APBCFGSAIF_SYSCFG(4), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(8), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(12), 0x0000fff0 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(16), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(20), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(24), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(28), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(32), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(36), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(40), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(40), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(48), 0x24000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(52), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(56), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(60), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(64), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(68), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(72), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(76), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(80), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(84), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(88), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(92), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(96), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(100), 0x02000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(104), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(108), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(112), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(116), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(120), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(124), 0x0000000c }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(128), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(132), 0xcc500000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(136), 0x000000cc }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(140), 0x00000000 }, ++ { STF_DPHY_APBCFGSAIF_SYSCFG(144), 0x00000000 }, ++}; ++ ++static int stf_dphy_configure(struct phy *phy, union phy_configure_opts *opts) ++{ ++ struct stf_dphy *dphy = phy_get_drvdata(phy); ++ const struct stf_dphy_info *info = dphy->info; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(stf_dphy_init_list); i++) ++ writel(stf_dphy_init_list[i].val, ++ dphy->regs + stf_dphy_init_list[i].addr); ++ ++ writel(FIELD_PREP(STF_DPHY_DA_CDPHY_R100_CTRL0_2D1C_EFUSE_EN, 1) | ++ FIELD_PREP(STF_DPHY_DA_CDPHY_R100_CTRL0_2D1C_EFUSE_IN, 0x1b) | ++ FIELD_PREP(STF_DPHY_DA_CDPHY_R100_CTRL1_2D1C_EFUSE_EN, 1) | ++ FIELD_PREP(STF_DPHY_DA_CDPHY_R100_CTRL1_2D1C_EFUSE_IN, 0x1b), ++ dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(0)); ++ ++ writel(FIELD_PREP(STF_DPHY_DATA_BUS16_8, 0) | ++ FIELD_PREP(STF_DPHY_DEBUG_MODE_SEL, 0x5a), ++ dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(184)); ++ ++ writel(FIELD_PREP(STF_DPHY_ENABLE_CLK, 1) | ++ FIELD_PREP(STF_DPHY_ENABLE_CLK1, 1) | ++ FIELD_PREP(STF_DPHY_ENABLE_LAN0, 1) | ++ FIELD_PREP(STF_DPHY_ENABLE_LAN1, 1) | ++ FIELD_PREP(STF_DPHY_ENABLE_LAN2, 1) | ++ FIELD_PREP(STF_DPHY_ENABLE_LAN3, 1) | ++ FIELD_PREP(STF_DPHY_GPI_EN, 0) | ++ FIELD_PREP(STF_DPHY_HS_FREQ_CHANGE_CLK, 0) | ++ FIELD_PREP(STF_DPHY_HS_FREQ_CHANGE_CLK1, 0) | ++ FIELD_PREP(STF_DPHY_LANE_SWAP_CLK, info->maps[0]) | ++ FIELD_PREP(STF_DPHY_LANE_SWAP_CLK1, info->maps[5]) | ++ FIELD_PREP(STF_DPHY_LANE_SWAP_LAN0, info->maps[1]) | ++ FIELD_PREP(STF_DPHY_LANE_SWAP_LAN1, info->maps[2]), ++ dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(188)); ++ ++ writel(FIELD_PREP(STF_DPHY_LANE_SWAP_LAN2, info->maps[3]) | ++ FIELD_PREP(STF_DPHY_LANE_SWAP_LAN3, info->maps[4]) | ++ FIELD_PREP(STF_DPHY_MP_TEST_EN, 0) | ++ FIELD_PREP(STF_DPHY_MP_TEST_MODE_SEL, 0) | ++ FIELD_PREP(STF_DPHY_PLL_CLK_SEL, 0x37c) | ++ FIELD_PREP(STF_DPHY_PRECOUNTER_IN_CLK, 8), ++ dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(192)); ++ ++ writel(FIELD_PREP(STF_DPHY_PRECOUNTER_IN_CLK1, 8) | ++ FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN0, 7) | ++ FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN1, 7) | ++ FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN2, 7), ++ dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(196)); ++ ++ writel(FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN3, 7) | ++ FIELD_PREP(STF_DPHY_RX_1C2C_SEL, 0), ++ dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(200)); ++ ++ return 0; ++} ++ ++static int stf_dphy_power_on(struct phy *phy) ++{ ++ struct stf_dphy *dphy = phy_get_drvdata(phy); ++ int ret; ++ ++ pm_runtime_get_sync(dphy->dev); ++ ++ ret = regulator_enable(dphy->mipi_0p9); ++ if (ret) ++ return ret; ++ ++ clk_set_rate(dphy->cfg_clk, 99000000); ++ clk_set_rate(dphy->ref_clk, 49500000); ++ clk_set_rate(dphy->tx_clk, 19800000); ++ reset_control_deassert(dphy->rstc); ++ ++ return 0; ++} ++ ++static int stf_dphy_power_off(struct phy *phy) ++{ ++ struct stf_dphy *dphy = phy_get_drvdata(phy); ++ ++ reset_control_assert(dphy->rstc); ++ ++ regulator_disable(dphy->mipi_0p9); ++ ++ pm_runtime_put_sync(dphy->dev); ++ ++ return 0; ++} ++ ++static const struct phy_ops stf_dphy_ops = { ++ .configure = stf_dphy_configure, ++ .power_on = stf_dphy_power_on, ++ .power_off = stf_dphy_power_off, ++}; ++ ++static int stf_dphy_probe(struct platform_device *pdev) ++{ ++ struct phy_provider *phy_provider; ++ struct stf_dphy *dphy; ++ ++ dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); ++ if (!dphy) ++ return -ENOMEM; ++ ++ dphy->info = of_device_get_match_data(&pdev->dev); ++ ++ dev_set_drvdata(&pdev->dev, dphy); ++ dphy->dev = &pdev->dev; ++ ++ dphy->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(dphy->regs)) ++ return PTR_ERR(dphy->regs); ++ ++ dphy->cfg_clk = devm_clk_get(&pdev->dev, "cfg"); ++ if (IS_ERR(dphy->cfg_clk)) ++ return PTR_ERR(dphy->cfg_clk); ++ ++ dphy->ref_clk = devm_clk_get(&pdev->dev, "ref"); ++ if (IS_ERR(dphy->ref_clk)) ++ return PTR_ERR(dphy->ref_clk); ++ ++ dphy->tx_clk = devm_clk_get(&pdev->dev, "tx"); ++ if (IS_ERR(dphy->tx_clk)) ++ return PTR_ERR(dphy->tx_clk); ++ ++ dphy->rstc = devm_reset_control_array_get_exclusive(&pdev->dev); ++ if (IS_ERR(dphy->rstc)) ++ return PTR_ERR(dphy->rstc); ++ ++ dphy->mipi_0p9 = devm_regulator_get(&pdev->dev, "mipi_0p9"); ++ if (IS_ERR(dphy->mipi_0p9)) ++ return PTR_ERR(dphy->mipi_0p9); ++ ++ dphy->phy = devm_phy_create(&pdev->dev, NULL, &stf_dphy_ops); ++ if (IS_ERR(dphy->phy)) { ++ dev_err(&pdev->dev, "Failed to create PHY\n"); ++ return PTR_ERR(dphy->phy); ++ } ++ ++ pm_runtime_enable(&pdev->dev); ++ ++ phy_set_drvdata(dphy->phy, dphy); ++ phy_provider = devm_of_phy_provider_register(&pdev->dev, ++ of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct stf_dphy_info starfive_dphy_info = { ++ .maps = {4, 0, 1, 2, 3, 5}, ++}; ++ ++static const struct of_device_id stf_dphy_dt_ids[] = { ++ { ++ .compatible = "starfive,jh7110-dphy-rx", ++ .data = &starfive_dphy_info, ++ }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, stf_dphy_dt_ids); ++ ++static struct platform_driver stf_dphy_driver = { ++ .probe = stf_dphy_probe, ++ .driver = { ++ .name = "starfive-dphy-rx", ++ .of_match_table = stf_dphy_dt_ids, ++ }, ++}; ++module_platform_driver(stf_dphy_driver); ++ ++MODULE_AUTHOR("Jack Zhu "); ++MODULE_AUTHOR("Changhuang Liang "); ++MODULE_DESCRIPTION("StarFive DPHY RX driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0076-media-dt-bindings-cadence-csi2rx-Convert-to-DT-schem.patch b/target/linux/starfive/patches-6.1/0076-media-dt-bindings-cadence-csi2rx-Convert-to-DT-schem.patch new file mode 100644 index 0000000000..4cabffbe53 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0076-media-dt-bindings-cadence-csi2rx-Convert-to-DT-schem.patch @@ -0,0 +1,306 @@ +From 243b040c3517093309a41877e3c1c6e8a7540071 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Tue, 23 May 2023 16:56:22 +0800 +Subject: [PATCH 076/122] media: dt-bindings: cadence-csi2rx: Convert to DT + schema + +Convert DT bindings document for Cadence MIPI-CSI2 RX controller to +DT schema format. + +For compatible, new compatibles should not be messed with conversion, +but the original binding did not specify any SoC-specific compatible +string, so add the StarFive compatible string. + +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Laurent Pinchart +Signed-off-by: Jack Zhu +--- + .../devicetree/bindings/media/cdns,csi2rx.txt | 100 ---------- + .../bindings/media/cdns,csi2rx.yaml | 177 ++++++++++++++++++ + 2 files changed, 177 insertions(+), 100 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/media/cdns,csi2rx.txt + create mode 100644 Documentation/devicetree/bindings/media/cdns,csi2rx.yaml + +--- a/Documentation/devicetree/bindings/media/cdns,csi2rx.txt ++++ /dev/null +@@ -1,100 +0,0 @@ +-Cadence MIPI-CSI2 RX controller +-=============================== +- +-The Cadence MIPI-CSI2 RX controller is a CSI-2 bridge supporting up to 4 CSI +-lanes in input, and 4 different pixel streams in output. +- +-Required properties: +- - compatible: must be set to "cdns,csi2rx" and an SoC-specific compatible +- - reg: base address and size of the memory mapped region +- - clocks: phandles to the clocks driving the controller +- - clock-names: must contain: +- * sys_clk: main clock +- * p_clk: register bank clock +- * pixel_if[0-3]_clk: pixel stream output clock, one for each stream +- implemented in hardware, between 0 and 3 +- +-Optional properties: +- - phys: phandle to the external D-PHY, phy-names must be provided +- - phy-names: must contain "dphy", if the implementation uses an +- external D-PHY +- +-Required subnodes: +- - ports: A ports node with one port child node per device input and output +- port, in accordance with the video interface bindings defined in +- Documentation/devicetree/bindings/media/video-interfaces.txt. The +- port nodes are numbered as follows: +- +- Port Description +- ----------------------------- +- 0 CSI-2 input +- 1 Stream 0 output +- 2 Stream 1 output +- 3 Stream 2 output +- 4 Stream 3 output +- +- The stream output port nodes are optional if they are not +- connected to anything at the hardware level or implemented +- in the design.Since there is only one endpoint per port, +- the endpoints are not numbered. +- +- +-Example: +- +-csi2rx: csi-bridge@0d060000 { +- compatible = "cdns,csi2rx"; +- reg = <0x0d060000 0x1000>; +- clocks = <&byteclock>, <&byteclock> +- <&coreclock>, <&coreclock>, +- <&coreclock>, <&coreclock>; +- clock-names = "sys_clk", "p_clk", +- "pixel_if0_clk", "pixel_if1_clk", +- "pixel_if2_clk", "pixel_if3_clk"; +- +- ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- port@0 { +- reg = <0>; +- +- csi2rx_in_sensor: endpoint { +- remote-endpoint = <&sensor_out_csi2rx>; +- clock-lanes = <0>; +- data-lanes = <1 2>; +- }; +- }; +- +- port@1 { +- reg = <1>; +- +- csi2rx_out_grabber0: endpoint { +- remote-endpoint = <&grabber0_in_csi2rx>; +- }; +- }; +- +- port@2 { +- reg = <2>; +- +- csi2rx_out_grabber1: endpoint { +- remote-endpoint = <&grabber1_in_csi2rx>; +- }; +- }; +- +- port@3 { +- reg = <3>; +- +- csi2rx_out_grabber2: endpoint { +- remote-endpoint = <&grabber2_in_csi2rx>; +- }; +- }; +- +- port@4 { +- reg = <4>; +- +- csi2rx_out_grabber3: endpoint { +- remote-endpoint = <&grabber3_in_csi2rx>; +- }; +- }; +- }; +-}; +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml +@@ -0,0 +1,177 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/cdns,csi2rx.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Cadence MIPI-CSI2 RX controller ++ ++maintainers: ++ - Maxime Ripard ++ ++description: ++ The Cadence MIPI-CSI2 RX controller is a CSI-2 bridge supporting up to 4 CSI ++ lanes in input, and 4 different pixel streams in output. ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - starfive,jh7110-csi2rx ++ - const: cdns,csi2rx ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: CSI2Rx system clock ++ - description: Gated Register bank clock for APB interface ++ - description: pixel Clock for Stream interface 0 ++ - description: pixel Clock for Stream interface 1 ++ - description: pixel Clock for Stream interface 2 ++ - description: pixel Clock for Stream interface 3 ++ ++ clock-names: ++ items: ++ - const: sys_clk ++ - const: p_clk ++ - const: pixel_if0_clk ++ - const: pixel_if1_clk ++ - const: pixel_if2_clk ++ - const: pixel_if3_clk ++ ++ phys: ++ maxItems: 1 ++ description: MIPI D-PHY ++ ++ phy-names: ++ items: ++ - const: dphy ++ ++ ports: ++ $ref: /schemas/graph.yaml#/properties/ports ++ ++ properties: ++ port@0: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ unevaluatedProperties: false ++ description: ++ Input port node, single endpoint describing the CSI-2 transmitter. ++ ++ properties: ++ endpoint: ++ $ref: video-interfaces.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ bus-type: ++ const: 4 ++ ++ clock-lanes: ++ const: 0 ++ ++ data-lanes: ++ minItems: 1 ++ maxItems: 4 ++ items: ++ maximum: 4 ++ ++ required: ++ - data-lanes ++ ++ port@1: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: ++ Stream 0 Output port node ++ ++ port@2: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: ++ Stream 1 Output port node ++ ++ port@3: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: ++ Stream 2 Output port node ++ ++ port@4: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: ++ Stream 3 Output port node ++ ++ required: ++ - port@0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - ports ++ ++additionalProperties: false ++ ++examples: ++ - | ++ csi@d060000 { ++ compatible = "starfive,jh7110-csi2rx", "cdns,csi2rx"; ++ reg = <0x0d060000 0x1000>; ++ clocks = <&byteclock 7>, <&byteclock 6>, ++ <&coreclock 8>, <&coreclock 9>, ++ <&coreclock 10>, <&coreclock 11>; ++ clock-names = "sys_clk", "p_clk", ++ "pixel_if0_clk", "pixel_if1_clk", ++ "pixel_if2_clk", "pixel_if3_clk"; ++ phys = <&csi_phy>; ++ phy-names = "dphy"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ ++ csi2rx_in_sensor: endpoint { ++ remote-endpoint = <&sensor_out_csi2rx>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ ++ csi2rx_out_grabber0: endpoint { ++ remote-endpoint = <&grabber0_in_csi2rx>; ++ }; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ ++ csi2rx_out_grabber1: endpoint { ++ remote-endpoint = <&grabber1_in_csi2rx>; ++ }; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ ++ csi2rx_out_grabber2: endpoint { ++ remote-endpoint = <&grabber2_in_csi2rx>; ++ }; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ ++ csi2rx_out_grabber3: endpoint { ++ remote-endpoint = <&grabber3_in_csi2rx>; ++ }; ++ }; ++ }; ++ }; ++ ++... diff --git a/target/linux/starfive/patches-6.1/0077-media-dt-bindings-cadence-csi2rx-Add-resets-property.patch b/target/linux/starfive/patches-6.1/0077-media-dt-bindings-cadence-csi2rx-Add-resets-property.patch new file mode 100644 index 0000000000..55b3fade7d --- /dev/null +++ b/target/linux/starfive/patches-6.1/0077-media-dt-bindings-cadence-csi2rx-Add-resets-property.patch @@ -0,0 +1,55 @@ +From 60817a4e755c6e98092fdceec35fcda94d35e4b1 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Tue, 23 May 2023 16:56:23 +0800 +Subject: [PATCH 077/122] media: dt-bindings: cadence-csi2rx: Add resets + property + +Add resets property for Cadence MIPI-CSI2 RX controller + +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Laurent Pinchart +Signed-off-by: Jack Zhu +--- + .../bindings/media/cdns,csi2rx.yaml | 24 +++++++++++++++++++ + 1 file changed, 24 insertions(+) + +--- a/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml ++++ b/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml +@@ -41,6 +41,24 @@ properties: + - const: pixel_if2_clk + - const: pixel_if3_clk + ++ resets: ++ items: ++ - description: CSI2Rx system reset ++ - description: Gated Register bank reset for APB interface ++ - description: pixel reset for Stream interface 0 ++ - description: pixel reset for Stream interface 1 ++ - description: pixel reset for Stream interface 2 ++ - description: pixel reset for Stream interface 3 ++ ++ reset-names: ++ items: ++ - const: sys ++ - const: reg_bank ++ - const: pixel_if0 ++ - const: pixel_if1 ++ - const: pixel_if2 ++ - const: pixel_if3 ++ + phys: + maxItems: 1 + description: MIPI D-PHY +@@ -123,6 +141,12 @@ examples: + clock-names = "sys_clk", "p_clk", + "pixel_if0_clk", "pixel_if1_clk", + "pixel_if2_clk", "pixel_if3_clk"; ++ resets = <&bytereset 9>, <&bytereset 4>, ++ <&corereset 5>, <&corereset 6>, ++ <&corereset 7>, <&corereset 8>; ++ reset-names = "sys", "reg_bank", ++ "pixel_if0", "pixel_if1", ++ "pixel_if2", "pixel_if3"; + phys = <&csi_phy>; + phy-names = "dphy"; + diff --git a/target/linux/starfive/patches-6.1/0078-media-cadence-Add-operation-on-reset.patch b/target/linux/starfive/patches-6.1/0078-media-cadence-Add-operation-on-reset.patch new file mode 100644 index 0000000000..2cc7b69089 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0078-media-cadence-Add-operation-on-reset.patch @@ -0,0 +1,129 @@ +From 2fbf4d367b25de4fa2f2d9cec57c88766c37d9de Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Tue, 23 May 2023 16:56:24 +0800 +Subject: [PATCH 078/122] media: cadence: Add operation on reset + +Add operation on reset for Cadence MIPI-CSI2 RX Controller. + +Reviewed-by: Laurent Pinchart +Signed-off-by: Jack Zhu +--- + drivers/media/platform/cadence/cdns-csi2rx.c | 40 +++++++++++++++++--- + 1 file changed, 35 insertions(+), 5 deletions(-) + +--- a/drivers/media/platform/cadence/cdns-csi2rx.c ++++ b/drivers/media/platform/cadence/cdns-csi2rx.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -68,6 +69,9 @@ struct csi2rx_priv { + struct clk *sys_clk; + struct clk *p_clk; + struct clk *pixel_clk[CSI2RX_STREAMS_MAX]; ++ struct reset_control *sys_rst; ++ struct reset_control *p_rst; ++ struct reset_control *pixel_rst[CSI2RX_STREAMS_MAX]; + struct phy *dphy; + + u8 lanes[CSI2RX_LANES_MAX]; +@@ -112,6 +116,7 @@ static int csi2rx_start(struct csi2rx_pr + if (ret) + return ret; + ++ reset_control_deassert(csi2rx->p_rst); + csi2rx_reset(csi2rx); + + reg = csi2rx->num_lanes << 8; +@@ -154,6 +159,8 @@ static int csi2rx_start(struct csi2rx_pr + if (ret) + goto err_disable_pixclk; + ++ reset_control_deassert(csi2rx->pixel_rst[i]); ++ + writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, + csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); + +@@ -169,13 +176,16 @@ static int csi2rx_start(struct csi2rx_pr + if (ret) + goto err_disable_pixclk; + ++ reset_control_deassert(csi2rx->sys_rst); + clk_disable_unprepare(csi2rx->p_clk); + + return 0; + + err_disable_pixclk: +- for (; i > 0; i--) ++ for (; i > 0; i--) { ++ reset_control_assert(csi2rx->pixel_rst[i - 1]); + clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); ++ } + + err_disable_pclk: + clk_disable_unprepare(csi2rx->p_clk); +@@ -188,14 +198,17 @@ static void csi2rx_stop(struct csi2rx_pr + unsigned int i; + + clk_prepare_enable(csi2rx->p_clk); ++ reset_control_assert(csi2rx->sys_rst); + clk_disable_unprepare(csi2rx->sys_clk); + + for (i = 0; i < csi2rx->max_streams; i++) { + writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + ++ reset_control_assert(csi2rx->pixel_rst[i]); + clk_disable_unprepare(csi2rx->pixel_clk[i]); + } + ++ reset_control_assert(csi2rx->p_rst); + clk_disable_unprepare(csi2rx->p_clk); + + if (v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, false)) +@@ -299,6 +312,16 @@ static int csi2rx_get_resources(struct c + return PTR_ERR(csi2rx->p_clk); + } + ++ csi2rx->sys_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, ++ "sys"); ++ if (IS_ERR(csi2rx->sys_rst)) ++ return PTR_ERR(csi2rx->sys_rst); ++ ++ csi2rx->p_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, ++ "reg_bank"); ++ if (IS_ERR(csi2rx->p_rst)) ++ return PTR_ERR(csi2rx->p_rst); ++ + csi2rx->dphy = devm_phy_optional_get(&pdev->dev, "dphy"); + if (IS_ERR(csi2rx->dphy)) { + dev_err(&pdev->dev, "Couldn't get external D-PHY\n"); +@@ -349,14 +372,21 @@ static int csi2rx_get_resources(struct c + } + + for (i = 0; i < csi2rx->max_streams; i++) { +- char clk_name[16]; ++ char name[16]; + +- snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); +- csi2rx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name); ++ snprintf(name, sizeof(name), "pixel_if%u_clk", i); ++ csi2rx->pixel_clk[i] = devm_clk_get(&pdev->dev, name); + if (IS_ERR(csi2rx->pixel_clk[i])) { +- dev_err(&pdev->dev, "Couldn't get clock %s\n", clk_name); ++ dev_err(&pdev->dev, "Couldn't get clock %s\n", name); + return PTR_ERR(csi2rx->pixel_clk[i]); + } ++ ++ snprintf(name, sizeof(name), "pixel_if%u", i); ++ csi2rx->pixel_rst[i] = ++ devm_reset_control_get_optional_exclusive(&pdev->dev, ++ name); ++ if (IS_ERR(csi2rx->pixel_rst[i])) ++ return PTR_ERR(csi2rx->pixel_rst[i]); + } + + return 0; diff --git a/target/linux/starfive/patches-6.1/0079-media-cadence-Add-support-for-external-dphy.patch b/target/linux/starfive/patches-6.1/0079-media-cadence-Add-support-for-external-dphy.patch new file mode 100644 index 0000000000..77e506eb47 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0079-media-cadence-Add-support-for-external-dphy.patch @@ -0,0 +1,141 @@ +From e97eb58b321b5b25b7d5c40880e6eb133d381581 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Tue, 23 May 2023 16:56:25 +0800 +Subject: [PATCH 079/122] media: cadence: Add support for external dphy + +Add support for external MIPI D-PHY. + +Reviewed-by: Laurent Pinchart +Signed-off-by: Jack Zhu +--- + drivers/media/platform/cadence/cdns-csi2rx.c | 66 +++++++++++++++++--- + 1 file changed, 56 insertions(+), 10 deletions(-) + +--- a/drivers/media/platform/cadence/cdns-csi2rx.c ++++ b/drivers/media/platform/cadence/cdns-csi2rx.c +@@ -31,6 +31,12 @@ + #define CSI2RX_STATIC_CFG_DLANE_MAP(llane, plane) ((plane) << (16 + (llane) * 4)) + #define CSI2RX_STATIC_CFG_LANES_MASK GENMASK(11, 8) + ++#define CSI2RX_DPHY_LANE_CTRL_REG 0x40 ++#define CSI2RX_DPHY_CL_RST BIT(16) ++#define CSI2RX_DPHY_DL_RST(i) BIT((i) + 12) ++#define CSI2RX_DPHY_CL_EN BIT(4) ++#define CSI2RX_DPHY_DL_EN(i) BIT(i) ++ + #define CSI2RX_STREAM_BASE(n) (((n) + 1) * 0x100) + + #define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000) +@@ -105,6 +111,24 @@ static void csi2rx_reset(struct csi2rx_p + writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG); + } + ++static int csi2rx_configure_ext_dphy(struct csi2rx_priv *csi2rx) ++{ ++ union phy_configure_opts opts = { }; ++ int ret; ++ ++ ret = phy_power_on(csi2rx->dphy); ++ if (ret) ++ return ret; ++ ++ ret = phy_configure(csi2rx->dphy, &opts); ++ if (ret) { ++ phy_power_off(csi2rx->dphy); ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int csi2rx_start(struct csi2rx_priv *csi2rx) + { + unsigned int i; +@@ -144,6 +168,17 @@ static int csi2rx_start(struct csi2rx_pr + if (ret) + goto err_disable_pclk; + ++ /* Enable DPHY clk and data lanes. */ ++ if (csi2rx->dphy) { ++ reg = CSI2RX_DPHY_CL_EN | CSI2RX_DPHY_CL_RST; ++ for (i = 0; i < csi2rx->num_lanes; i++) { ++ reg |= CSI2RX_DPHY_DL_EN(csi2rx->lanes[i] - 1); ++ reg |= CSI2RX_DPHY_DL_RST(csi2rx->lanes[i] - 1); ++ } ++ ++ writel(reg, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); ++ } ++ + /* + * Create a static mapping between the CSI virtual channels + * and the output stream. +@@ -177,10 +212,22 @@ static int csi2rx_start(struct csi2rx_pr + goto err_disable_pixclk; + + reset_control_deassert(csi2rx->sys_rst); ++ ++ if (csi2rx->dphy) { ++ ret = csi2rx_configure_ext_dphy(csi2rx); ++ if (ret) { ++ dev_err(csi2rx->dev, ++ "Failed to configure external DPHY: %d\n", ret); ++ goto err_disable_sysclk; ++ } ++ } ++ + clk_disable_unprepare(csi2rx->p_clk); + + return 0; + ++err_disable_sysclk: ++ clk_disable_unprepare(csi2rx->sys_clk); + err_disable_pixclk: + for (; i > 0; i--) { + reset_control_assert(csi2rx->pixel_rst[i - 1]); +@@ -213,6 +260,13 @@ static void csi2rx_stop(struct csi2rx_pr + + if (v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, false)) + dev_warn(csi2rx->dev, "Couldn't disable our subdev\n"); ++ ++ if (csi2rx->dphy) { ++ writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); ++ ++ if (phy_power_off(csi2rx->dphy)) ++ dev_warn(csi2rx->dev, "Couldn't power off DPHY\n"); ++ } + } + + static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) +@@ -328,15 +382,6 @@ static int csi2rx_get_resources(struct c + return PTR_ERR(csi2rx->dphy); + } + +- /* +- * FIXME: Once we'll have external D-PHY support, the check +- * will need to be removed. +- */ +- if (csi2rx->dphy) { +- dev_err(&pdev->dev, "External D-PHY not supported yet\n"); +- return -EINVAL; +- } +- + ret = clk_prepare_enable(csi2rx->p_clk); + if (ret) { + dev_err(&pdev->dev, "Couldn't prepare and enable P clock\n"); +@@ -366,7 +411,7 @@ static int csi2rx_get_resources(struct c + * FIXME: Once we'll have internal D-PHY support, the check + * will need to be removed. + */ +- if (csi2rx->has_internal_dphy) { ++ if (!csi2rx->dphy && csi2rx->has_internal_dphy) { + dev_err(&pdev->dev, "Internal D-PHY not supported yet\n"); + return -EINVAL; + } +@@ -494,6 +539,7 @@ static int csi2rx_probe(struct platform_ + dev_info(&pdev->dev, + "Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n", + csi2rx->num_lanes, csi2rx->max_lanes, csi2rx->max_streams, ++ csi2rx->dphy ? "external" : + csi2rx->has_internal_dphy ? "internal" : "no"); + + return 0; diff --git a/target/linux/starfive/patches-6.1/0080-media-cadence-Add-support-for-JH7110-SoC.patch b/target/linux/starfive/patches-6.1/0080-media-cadence-Add-support-for-JH7110-SoC.patch new file mode 100644 index 0000000000..f3527840b6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0080-media-cadence-Add-support-for-JH7110-SoC.patch @@ -0,0 +1,23 @@ +From d541f0ab42983dbc856f2229ee471677e80945a3 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Tue, 23 May 2023 16:56:26 +0800 +Subject: [PATCH 080/122] media: cadence: Add support for JH7110 SoC + +Add support for Starfive JH7110 SoC which has the cadence csi2 receiver. + +Reviewed-by: Laurent Pinchart +Signed-off-by: Jack Zhu +--- + drivers/media/platform/cadence/cdns-csi2rx.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/platform/cadence/cdns-csi2rx.c ++++ b/drivers/media/platform/cadence/cdns-csi2rx.c +@@ -565,6 +565,7 @@ static int csi2rx_remove(struct platform + } + + static const struct of_device_id csi2rx_of_table[] = { ++ { .compatible = "starfive,jh7110-csi2rx" }, + { .compatible = "cdns,csi2rx" }, + { }, + }; diff --git a/target/linux/starfive/patches-6.1/0081-media-dt-bindings-Add-JH7110-Camera-Subsystem.patch b/target/linux/starfive/patches-6.1/0081-media-dt-bindings-Add-JH7110-Camera-Subsystem.patch new file mode 100644 index 0000000000..0b3bf80b46 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0081-media-dt-bindings-Add-JH7110-Camera-Subsystem.patch @@ -0,0 +1,197 @@ +From f3195b45a3845fd3892ca932a9cc8e352942dbcd Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Fri, 12 May 2023 18:28:39 +0800 +Subject: [PATCH 081/122] media: dt-bindings: Add JH7110 Camera Subsystem + +Add the bindings documentation for Starfive JH7110 Camera Subsystem +which is used for handing image sensor data. + +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Jack Zhu +--- + .../bindings/media/starfive,jh7110-camss.yaml | 179 ++++++++++++++++++ + 1 file changed, 179 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml +@@ -0,0 +1,179 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/starfive,jh7110-camss.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Starfive SoC CAMSS ISP ++ ++maintainers: ++ - Jack Zhu ++ - Changhuang Liang ++ ++description: ++ The Starfive CAMSS ISP is a Camera interface for Starfive JH7110 SoC. It ++ consists of a VIN controller (Video In Controller, a top-level control until) ++ and an ISP. ++ ++properties: ++ compatible: ++ const: starfive,jh7110-camss ++ ++ reg: ++ maxItems: 2 ++ ++ reg-names: ++ items: ++ - const: syscon ++ - const: isp ++ ++ clocks: ++ maxItems: 7 ++ ++ clock-names: ++ items: ++ - const: apb_func ++ - const: wrapper_clk_c ++ - const: dvp_inv ++ - const: axiwr ++ - const: mipi_rx0_pxl ++ - const: ispcore_2x ++ - const: isp_axi ++ ++ resets: ++ maxItems: 6 ++ ++ reset-names: ++ items: ++ - const: wrapper_p ++ - const: wrapper_c ++ - const: axird ++ - const: axiwr ++ - const: isp_top_n ++ - const: isp_top_axi ++ ++ power-domains: ++ items: ++ - description: JH7110 ISP Power Domain Switch Controller. ++ ++ interrupts: ++ maxItems: 4 ++ ++ ports: ++ $ref: /schemas/graph.yaml#/properties/ports ++ ++ properties: ++ port@0: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ unevaluatedProperties: false ++ description: Input port for receiving DVP data. ++ ++ properties: ++ endpoint: ++ $ref: video-interfaces.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ bus-type: ++ enum: [5, 6] ++ ++ bus-width: ++ enum: [8, 10, 12] ++ ++ data-shift: ++ enum: [0, 2] ++ default: 0 ++ ++ hsync-active: ++ enum: [0, 1] ++ default: 1 ++ ++ vsync-active: ++ enum: [0, 1] ++ default: 1 ++ ++ required: ++ - bus-type ++ - bus-width ++ ++ port@1: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: Input port for receiving CSI data. ++ ++ required: ++ - port@0 ++ - port@1 ++ ++required: ++ - compatible ++ - reg ++ - reg-names ++ - clocks ++ - clock-names ++ - resets ++ - reset-names ++ - power-domains ++ - interrupts ++ - ports ++ ++additionalProperties: false ++ ++examples: ++ - | ++ isp@19840000 { ++ compatible = "starfive,jh7110-camss"; ++ reg = <0x19840000 0x10000>, ++ <0x19870000 0x30000>; ++ reg-names = "syscon", "isp"; ++ clocks = <&ispcrg 0>, ++ <&ispcrg 13>, ++ <&ispcrg 2>, ++ <&ispcrg 12>, ++ <&ispcrg 1>, ++ <&syscrg 51>, ++ <&syscrg 52>; ++ clock-names = "apb_func", ++ "wrapper_clk_c", ++ "dvp_inv", ++ "axiwr", ++ "mipi_rx0_pxl", ++ "ispcore_2x", ++ "isp_axi"; ++ resets = <&ispcrg 0>, ++ <&ispcrg 1>, ++ <&ispcrg 10>, ++ <&ispcrg 11>, ++ <&syscrg 41>, ++ <&syscrg 42>; ++ reset-names = "wrapper_p", ++ "wrapper_c", ++ "axird", ++ "axiwr", ++ "isp_top_n", ++ "isp_top_axi"; ++ power-domains = <&pwrc 5>; ++ interrupts = <92>, <87>, <88>, <90>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ vin_from_sc2235: endpoint { ++ remote-endpoint = <&sc2235_to_vin>; ++ bus-width = <8>; ++ data-shift = <2>; ++ hsync-active = <1>; ++ vsync-active = <0>; ++ pclk-sample = <1>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ vin_from_csi2rx: endpoint { ++ remote-endpoint = <&csi2rx_to_vin>; ++ }; ++ }; ++ }; ++ }; diff --git a/target/linux/starfive/patches-6.1/0082-media-admin-guide-Add-starfive_camss.rst-for-Starfiv.patch b/target/linux/starfive/patches-6.1/0082-media-admin-guide-Add-starfive_camss.rst-for-Starfiv.patch new file mode 100644 index 0000000000..7d59112e8e --- /dev/null +++ b/target/linux/starfive/patches-6.1/0082-media-admin-guide-Add-starfive_camss.rst-for-Starfiv.patch @@ -0,0 +1,106 @@ +From 949807343300a75b6e7c3e47463f817a7b6bc790 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Fri, 12 May 2023 18:28:40 +0800 +Subject: [PATCH 082/122] media: admin-guide: Add starfive_camss.rst for + Starfive Camera Subsystem + +Add starfive_camss.rst file that documents the Starfive Camera +Subsystem driver which is used for handing image sensor data. + +Signed-off-by: Jack Zhu +--- + .../admin-guide/media/starfive_camss.rst | 57 +++++++++++++++++++ + .../media/starfive_camss_graph.dot | 16 ++++++ + .../admin-guide/media/v4l-drivers.rst | 1 + + 3 files changed, 74 insertions(+) + create mode 100644 Documentation/admin-guide/media/starfive_camss.rst + create mode 100644 Documentation/admin-guide/media/starfive_camss_graph.dot + +--- /dev/null ++++ b/Documentation/admin-guide/media/starfive_camss.rst +@@ -0,0 +1,57 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++.. include:: ++ ++================================ ++Starfive Camera Subsystem driver ++================================ ++ ++Introduction ++------------ ++ ++This file documents the driver for the Starfive Camera Subsystem found on ++Starfive JH7110 SoC. The driver is located under drivers/media/platform/ ++starfive. ++ ++The driver implements V4L2, Media controller and v4l2_subdev interfaces. ++Camera sensor using V4L2 subdev interface in the kernel is supported. ++ ++The driver has been successfully used on the Gstreamer 1.18.5 with ++v4l2src plugin. ++ ++ ++Starfive Camera Subsystem hardware ++---------------------------------- ++ ++The Starfive Camera Subsystem hardware consists of: ++ ++- MIPI DPHY Receiver: receives mipi data from a MIPI camera sensor. ++- MIPI CSIRx Controller: is responsible for handling and decoding CSI2 protocol ++ based camera sensor data stream. ++- ISP: handles the image data streams from the MIPI CSIRx Controller. ++- VIN(Video In): a top-level module, is responsible for controlling power ++ and clocks to other modules, dumps the input data to memory or transfers the ++ input data to ISP. ++ ++ ++Topology ++-------- ++ ++The media controller pipeline graph is as follows: ++ ++.. _starfive_camss_graph: ++ ++.. kernel-figure:: starfive_camss_graph.dot ++ :alt: starfive_camss_graph.dot ++ :align: center ++ ++The driver has 2 video devices: ++ ++- stf_vin0_wr_video0: capture device for images directly from the VIN module. ++- stf_vin0_isp0_video1: capture device for images without scaling. ++ ++The driver has 3 subdevices: ++ ++- stf_isp0: is responsible for all the isp operations. ++- stf_vin0_wr: used to dump RAW images to memory. ++- stf_vin0_isp0: used to capture images for the stf_vin0_isp0_video1 device. +--- /dev/null ++++ b/Documentation/admin-guide/media/starfive_camss_graph.dot +@@ -0,0 +1,16 @@ ++digraph board { ++ rankdir=TB ++ n00000001 [label="{{ 0} | stf_isp0\n/dev/v4l-subdev0 | { 1}}", shape=Mrecord, style=filled, fillcolor=green] ++ n00000001:port1 -> n0000000d:port0 ++ n00000004 [label="{{ 0} | stf_vin0_wr\n/dev/v4l-subdev1 | { 1}}", shape=Mrecord, style=filled, fillcolor=green] ++ n00000004:port1 -> n00000007 [style=bold] ++ n00000007 [label="stf_vin0_wr_video0\n/dev/video0", shape=box, style=filled, fillcolor=yellow] ++ n0000000d [label="{{ 0} | stf_vin0_isp0\n/dev/v4l-subdev2 | { 1}}", shape=Mrecord, style=filled, fillcolor=green] ++ n0000000d:port1 -> n00000010 [style=bold] ++ n00000010 [label="stf_vin0_isp0_video1\n/dev/video1", shape=box, style=filled, fillcolor=yellow] ++ n00000018 [label="{{ 0} | cdns_csi2rx.19800000.csi-bridge\n | { 1 | 2 | 3 | 4}}", shape=Mrecord, style=filled, fillcolor=green] ++ n00000018:port1 -> n00000004:port0 [style=dashed] ++ n00000018:port1 -> n00000001:port0 ++ n00000028 [label="{{} | imx219 6-0010\n | { 0}}", shape=Mrecord, style=filled, fillcolor=green] ++ n00000028:port0 -> n00000018:port0 [style=bold] ++} +--- a/Documentation/admin-guide/media/v4l-drivers.rst ++++ b/Documentation/admin-guide/media/v4l-drivers.rst +@@ -30,5 +30,6 @@ Video4Linux (V4L) driver-specific docume + si470x + si4713 + si476x ++ starfive_camss + vimc + vivid diff --git a/target/linux/starfive/patches-6.1/0083-media-starfive-Add-basic-driver.patch b/target/linux/starfive/patches-6.1/0083-media-starfive-Add-basic-driver.patch new file mode 100644 index 0000000000..bc5141cfbc --- /dev/null +++ b/target/linux/starfive/patches-6.1/0083-media-starfive-Add-basic-driver.patch @@ -0,0 +1,630 @@ +From 0dc93c9321ba947ac429baeb58202496e4b0f219 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Fri, 12 May 2023 18:28:41 +0800 +Subject: [PATCH 083/122] media: starfive: Add basic driver + +Add basic platform driver for StarFive Camera Subsystem. + +Signed-off-by: Jack Zhu +Reviewed-by: Bryan O'Donoghue +--- + drivers/media/platform/Kconfig | 1 + + drivers/media/platform/Makefile | 1 + + drivers/media/platform/starfive/Kconfig | 19 + + drivers/media/platform/starfive/Makefile | 9 + + drivers/media/platform/starfive/stf_camss.c | 372 +++++++++++++++++++ + drivers/media/platform/starfive/stf_camss.h | 153 ++++++++ + drivers/media/platform/starfive/stf_common.h | 18 + + 7 files changed, 573 insertions(+) + create mode 100644 drivers/media/platform/starfive/Kconfig + create mode 100644 drivers/media/platform/starfive/Makefile + create mode 100644 drivers/media/platform/starfive/stf_camss.c + create mode 100644 drivers/media/platform/starfive/stf_camss.h + create mode 100644 drivers/media/platform/starfive/stf_common.h + +--- a/drivers/media/platform/Kconfig ++++ b/drivers/media/platform/Kconfig +@@ -79,6 +79,7 @@ source "drivers/media/platform/renesas/K + source "drivers/media/platform/rockchip/Kconfig" + source "drivers/media/platform/samsung/Kconfig" + source "drivers/media/platform/st/Kconfig" ++source "drivers/media/platform/starfive/Kconfig" + source "drivers/media/platform/sunxi/Kconfig" + source "drivers/media/platform/ti/Kconfig" + source "drivers/media/platform/verisilicon/Kconfig" +--- a/drivers/media/platform/Makefile ++++ b/drivers/media/platform/Makefile +@@ -22,6 +22,7 @@ obj-y += renesas/ + obj-y += rockchip/ + obj-y += samsung/ + obj-y += st/ ++obj-y += starfive/ + obj-y += sunxi/ + obj-y += ti/ + obj-y += verisilicon/ +--- /dev/null ++++ b/drivers/media/platform/starfive/Kconfig +@@ -0,0 +1,19 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++comment "Starfive media platform drivers" ++ ++config VIDEO_STARFIVE_CAMSS ++ tristate "Starfive Camera Subsystem driver" ++ depends on V4L_PLATFORM_DRIVERS ++ depends on VIDEO_DEV && OF ++ depends on DMA_CMA ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_FWNODE ++ help ++ Enable this to support for the Starfive Camera subsystem ++ found on Starfive JH7110 SoC. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called stf-camss. +--- /dev/null ++++ b/drivers/media/platform/starfive/Makefile +@@ -0,0 +1,9 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for StarFive camera subsystem driver. ++# ++ ++starfive-camss-objs += \ ++ stf_camss.o ++ ++obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \ +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_camss.c +@@ -0,0 +1,372 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * stf_camss.c ++ * ++ * Starfive Camera Subsystem driver ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "stf_camss.h" ++ ++static const char * const stfcamss_clocks[] = { ++ "clk_apb_func", ++ "clk_wrapper_clk_c", ++ "clk_dvp_inv", ++ "clk_axiwr", ++ "clk_mipi_rx0_pxl", ++ "clk_ispcore_2x", ++ "clk_isp_axi", ++}; ++ ++static const char * const stfcamss_resets[] = { ++ "rst_wrapper_p", ++ "rst_wrapper_c", ++ "rst_axird", ++ "rst_axiwr", ++ "rst_isp_top_n", ++ "rst_isp_top_axi", ++}; ++ ++static int stfcamss_get_mem_res(struct platform_device *pdev, ++ struct stfcamss *stfcamss) ++{ ++ stfcamss->syscon_base = ++ devm_platform_ioremap_resource_byname(pdev, "syscon"); ++ if (IS_ERR(stfcamss->syscon_base)) ++ return PTR_ERR(stfcamss->syscon_base); ++ ++ stfcamss->isp_base = ++ devm_platform_ioremap_resource_byname(pdev, "isp"); ++ if (IS_ERR(stfcamss->isp_base)) ++ return PTR_ERR(stfcamss->isp_base); ++ ++ return 0; ++} ++ ++/* ++ * stfcamss_of_parse_endpoint_node - Parse port endpoint node ++ * @dev: Device ++ * @node: Device node to be parsed ++ * @csd: Parsed data from port endpoint node ++ * ++ * Return 0 on success or a negative error code on failure ++ */ ++static int stfcamss_of_parse_endpoint_node(struct device *dev, ++ struct device_node *node, ++ struct stfcamss_async_subdev *csd) ++{ ++ struct v4l2_fwnode_endpoint vep = { { 0 } }; ++ ++ v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); ++ dev_dbg(dev, "vep.base.port = 0x%x, id = 0x%x\n", ++ vep.base.port, vep.base.id); ++ ++ csd->port = vep.base.port; ++ ++ return 0; ++} ++ ++/* ++ * stfcamss_of_parse_ports - Parse ports node ++ * @stfcamss: STFCAMSS device ++ * ++ * Return number of "port" nodes found in "ports" node ++ */ ++static int stfcamss_of_parse_ports(struct stfcamss *stfcamss) ++{ ++ struct device *dev = stfcamss->dev; ++ struct device_node *node = NULL; ++ struct device_node *remote = NULL; ++ int ret, num_subdevs = 0; ++ ++ for_each_endpoint_of_node(dev->of_node, node) { ++ struct stfcamss_async_subdev *csd; ++ ++ if (!of_device_is_available(node)) ++ continue; ++ ++ remote = of_graph_get_remote_port_parent(node); ++ if (!remote) { ++ dev_err(dev, "Cannot get remote parent\n"); ++ ret = -EINVAL; ++ goto err_cleanup; ++ } ++ ++ csd = v4l2_async_nf_add_fwnode(&stfcamss->notifier, ++ of_fwnode_handle(remote), ++ struct stfcamss_async_subdev); ++ of_node_put(remote); ++ if (IS_ERR(csd)) { ++ ret = PTR_ERR(csd); ++ goto err_cleanup; ++ } ++ ++ ret = stfcamss_of_parse_endpoint_node(dev, node, csd); ++ if (ret < 0) ++ goto err_cleanup; ++ ++ num_subdevs++; ++ } ++ ++ return num_subdevs; ++ ++err_cleanup: ++ of_node_put(node); ++ return ret; ++} ++ ++static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct stfcamss *stfcamss = ++ container_of(async, struct stfcamss, notifier); ++ struct host_data *host_data = &stfcamss->host_data; ++ struct media_entity *source; ++ int i, j; ++ ++ source = &subdev->entity; ++ ++ for (i = 0; i < source->num_pads; i++) { ++ if (source->pads[i].flags & MEDIA_PAD_FL_SOURCE) ++ break; ++ } ++ ++ if (i == source->num_pads) { ++ dev_err(stfcamss->dev, "No source pad in external entity\n"); ++ return -EINVAL; ++ } ++ ++ for (j = 0; host_data->host_entity[j] && (j < HOST_ENTITY_MAX); j++) { ++ struct media_entity *input; ++ int ret; ++ ++ input = host_data->host_entity[j]; ++ ++ ret = media_create_pad_link( ++ source, ++ i, ++ input, ++ STF_PAD_SINK, ++ source->function == MEDIA_ENT_F_CAM_SENSOR ? ++ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED : ++ 0); ++ if (ret < 0) { ++ dev_err(stfcamss->dev, ++ "Failed to link %s->%s entities: %d\n", ++ source->name, input->name, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf) ++{ ++ struct stfcamss *stfcamss = ++ container_of(ntf, struct stfcamss, notifier); ++ ++ return v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev); ++} ++ ++static const struct v4l2_async_notifier_operations ++stfcamss_subdev_notifier_ops = { ++ .bound = stfcamss_subdev_notifier_bound, ++ .complete = stfcamss_subdev_notifier_complete, ++}; ++ ++static const struct media_device_ops stfcamss_media_ops = { ++ .link_notify = v4l2_pipeline_link_notify, ++}; ++ ++static void stfcamss_mc_init(struct platform_device *pdev, ++ struct stfcamss *stfcamss) ++{ ++ stfcamss->media_dev.dev = stfcamss->dev; ++ strscpy(stfcamss->media_dev.model, "Starfive Camera Subsystem", ++ sizeof(stfcamss->media_dev.model)); ++ snprintf(stfcamss->media_dev.bus_info, ++ sizeof(stfcamss->media_dev.bus_info), ++ "%s:%s", dev_bus_name(&pdev->dev), pdev->name); ++ stfcamss->media_dev.hw_revision = 0x01; ++ stfcamss->media_dev.ops = &stfcamss_media_ops; ++ media_device_init(&stfcamss->media_dev); ++ ++ stfcamss->v4l2_dev.mdev = &stfcamss->media_dev; ++} ++ ++/* ++ * stfcamss_probe - Probe STFCAMSS platform device ++ * @pdev: Pointer to STFCAMSS platform device ++ * ++ * Return 0 on success or a negative error code on failure ++ */ ++static int stfcamss_probe(struct platform_device *pdev) ++{ ++ struct stfcamss *stfcamss; ++ struct device *dev = &pdev->dev; ++ int ret = 0, i, num_subdevs; ++ ++ stfcamss = devm_kzalloc(dev, sizeof(*stfcamss), GFP_KERNEL); ++ if (!stfcamss) ++ return -ENOMEM; ++ ++ for (i = 0; i < ARRAY_SIZE(stfcamss->irq); ++i) { ++ stfcamss->irq[i] = platform_get_irq(pdev, i); ++ if (stfcamss->irq[i] < 0) ++ return dev_err_probe(&pdev->dev, stfcamss->irq[i], ++ "Failed to get clock%d", i); ++ } ++ ++ stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk); ++ for (i = 0; i < ARRAY_SIZE(stfcamss->sys_clk); ++i) ++ stfcamss->sys_clk[i].id = stfcamss_clocks[i]; ++ ret = devm_clk_bulk_get(dev, stfcamss->nclks, stfcamss->sys_clk); ++ if (ret) { ++ dev_err(dev, "Failed to get clk controls\n"); ++ return ret; ++ } ++ ++ stfcamss->nrsts = ARRAY_SIZE(stfcamss->sys_rst); ++ for (i = 0; i < ARRAY_SIZE(stfcamss->sys_rst); ++i) ++ stfcamss->sys_rst[i].id = stfcamss_resets[i]; ++ ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts, ++ stfcamss->sys_rst); ++ if (ret) { ++ dev_err(dev, "Failed to get reset controls\n"); ++ return ret; ++ } ++ ++ ret = stfcamss_get_mem_res(pdev, stfcamss); ++ if (ret) { ++ dev_err(dev, "Could not map registers\n"); ++ return ret; ++ } ++ ++ stfcamss->dev = dev; ++ platform_set_drvdata(pdev, stfcamss); ++ ++ v4l2_async_nf_init(&stfcamss->notifier); ++ ++ num_subdevs = stfcamss_of_parse_ports(stfcamss); ++ if (num_subdevs < 0) { ++ dev_err(dev, "Failed to find subdevices\n"); ++ return -ENODEV; ++ } ++ ++ stfcamss_mc_init(pdev, stfcamss); ++ ++ ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev); ++ if (ret < 0) { ++ dev_err(dev, "Failed to register V4L2 device: %d\n", ret); ++ goto err_cleanup_notifier; ++ } ++ ++ ret = media_device_register(&stfcamss->media_dev); ++ if (ret) { ++ dev_err(dev, "Failed to register media device: %d\n", ret); ++ goto err_unregister_device; ++ } ++ ++ stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops; ++ ret = v4l2_async_nf_register(&stfcamss->v4l2_dev, &stfcamss->notifier); ++ if (ret) { ++ dev_err(dev, "Failed to register async subdev nodes: %d\n", ++ ret); ++ goto err_unregister_media_dev; ++ } ++ ++ pm_runtime_enable(dev); ++ ++ return 0; ++ ++err_unregister_media_dev: ++ media_device_unregister(&stfcamss->media_dev); ++err_unregister_device: ++ v4l2_device_unregister(&stfcamss->v4l2_dev); ++err_cleanup_notifier: ++ v4l2_async_nf_cleanup(&stfcamss->notifier); ++ return ret; ++} ++ ++/* ++ * stfcamss_remove - Remove STFCAMSS platform device ++ * @pdev: Pointer to STFCAMSS platform device ++ * ++ * Always returns 0. ++ */ ++static int stfcamss_remove(struct platform_device *pdev) ++{ ++ struct stfcamss *stfcamss = platform_get_drvdata(pdev); ++ ++ v4l2_device_unregister(&stfcamss->v4l2_dev); ++ media_device_cleanup(&stfcamss->media_dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id stfcamss_of_match[] = { ++ { .compatible = "starfive,jh7110-camss" }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, stfcamss_of_match); ++ ++static int __maybe_unused stfcamss_runtime_suspend(struct device *dev) ++{ ++ struct stfcamss *stfcamss = dev_get_drvdata(dev); ++ ++ reset_control_assert(stfcamss->sys_rst[STF_RST_ISP_TOP_AXI].rstc); ++ reset_control_assert(stfcamss->sys_rst[STF_RST_ISP_TOP_N].rstc); ++ clk_disable_unprepare(stfcamss->sys_clk[STF_CLK_ISP_AXI].clk); ++ clk_disable_unprepare(stfcamss->sys_clk[STF_CLK_ISPCORE_2X].clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused stfcamss_runtime_resume(struct device *dev) ++{ ++ struct stfcamss *stfcamss = dev_get_drvdata(dev); ++ ++ clk_prepare_enable(stfcamss->sys_clk[STF_CLK_ISPCORE_2X].clk); ++ clk_prepare_enable(stfcamss->sys_clk[STF_CLK_ISP_AXI].clk); ++ reset_control_deassert(stfcamss->sys_rst[STF_RST_ISP_TOP_N].rstc); ++ reset_control_deassert(stfcamss->sys_rst[STF_RST_ISP_TOP_AXI].rstc); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops stfcamss_pm_ops = { ++ SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend, ++ stfcamss_runtime_resume, ++ NULL) ++}; ++ ++static struct platform_driver stfcamss_driver = { ++ .probe = stfcamss_probe, ++ .remove = stfcamss_remove, ++ .driver = { ++ .name = DRV_NAME, ++ .pm = &stfcamss_pm_ops, ++ .of_match_table = of_match_ptr(stfcamss_of_match), ++ }, ++}; ++ ++module_platform_driver(stfcamss_driver); ++ ++MODULE_AUTHOR("StarFive Corporation"); ++MODULE_DESCRIPTION("StarFive Camera Subsystem driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_camss.h +@@ -0,0 +1,153 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * stf_camss.h ++ * ++ * Starfive Camera Subsystem driver ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef STF_CAMSS_H ++#define STF_CAMSS_H ++ ++#include ++#include ++#include ++#include ++ ++#include "stf_common.h" ++ ++#define DRV_NAME "starfive-camss" ++#define STF_DVP_NAME "stf_dvp" ++#define STF_CSI_NAME "cdns_csi2rx" ++#define STF_ISP_NAME "stf_isp" ++#define STF_VIN_NAME "stf_vin" ++ ++#define STF_PAD_SINK 0 ++#define STF_PAD_SRC 1 ++#define STF_PADS_NUM 2 ++ ++enum port_num { ++ PORT_NUMBER_DVP_SENSOR = 0, ++ PORT_NUMBER_CSI2RX ++}; ++ ++enum stf_clk { ++ STF_CLK_APB_FUNC = 0, ++ STF_CLK_WRAPPER_CLK_C, ++ STF_CLK_DVP_INV, ++ STF_CLK_AXIWR, ++ STF_CLK_MIPI_RX0_PXL, ++ STF_CLK_ISPCORE_2X, ++ STF_CLK_ISP_AXI, ++ STF_CLK_NUM ++}; ++ ++enum stf_rst { ++ STF_RST_WRAPPER_P = 0, ++ STF_RST_WRAPPER_C, ++ STF_RST_AXIRD, ++ STF_RST_AXIWR, ++ STF_RST_ISP_TOP_N, ++ STF_RST_ISP_TOP_AXI, ++ STF_RST_NUM ++}; ++ ++enum stf_irq { ++ STF_IRQ_VINWR = 0, ++ STF_IRQ_ISP, ++ STF_IRQ_ISPCSIL, ++ STF_IRQ_NUM ++}; ++ ++#define HOST_ENTITY_MAX 2 ++ ++struct host_data { ++ struct media_entity *host_entity[HOST_ENTITY_MAX]; ++}; ++ ++struct stfcamss { ++ struct v4l2_device v4l2_dev; ++ struct media_device media_dev; ++ struct media_pipeline pipe; ++ struct device *dev; ++ struct v4l2_async_notifier notifier; ++ struct host_data host_data; ++ void __iomem *syscon_base; ++ void __iomem *isp_base; ++ int irq[STF_IRQ_NUM]; ++ struct clk_bulk_data sys_clk[STF_CLK_NUM]; ++ int nclks; ++ struct reset_control_bulk_data sys_rst[STF_RST_NUM]; ++ int nrsts; ++}; ++ ++struct stfcamss_async_subdev { ++ struct v4l2_async_subdev asd; /* must be first */ ++ enum port_num port; ++}; ++ ++static inline u32 stf_isp_reg_read(struct stfcamss *stfcamss, u32 reg) ++{ ++ return ioread32(stfcamss->isp_base + reg); ++} ++ ++static inline void stf_isp_reg_write(struct stfcamss *stfcamss, ++ u32 reg, u32 val) ++{ ++ iowrite32(val, stfcamss->isp_base + reg); ++} ++ ++static inline void stf_isp_reg_write_delay(struct stfcamss *stfcamss, ++ u32 reg, u32 val, u32 delay) ++{ ++ iowrite32(val, stfcamss->isp_base + reg); ++ usleep_range(1000 * delay, 1000 * delay + 100); ++} ++ ++static inline void stf_isp_reg_set_bit(struct stfcamss *stfcamss, ++ u32 reg, u32 mask, u32 val) ++{ ++ u32 value; ++ ++ value = ioread32(stfcamss->isp_base + reg) & ~mask; ++ val &= mask; ++ val |= value; ++ iowrite32(val, stfcamss->isp_base + reg); ++} ++ ++static inline void stf_isp_reg_set(struct stfcamss *stfcamss, u32 reg, u32 mask) ++{ ++ iowrite32(ioread32(stfcamss->isp_base + reg) | mask, ++ stfcamss->isp_base + reg); ++} ++ ++static inline u32 stf_syscon_reg_read(struct stfcamss *stfcamss, u32 reg) ++{ ++ return ioread32(stfcamss->syscon_base + reg); ++} ++ ++static inline void stf_syscon_reg_write(struct stfcamss *stfcamss, ++ u32 reg, u32 val) ++{ ++ iowrite32(val, stfcamss->syscon_base + reg); ++} ++ ++static inline void stf_syscon_reg_set_bit(struct stfcamss *stfcamss, ++ u32 reg, u32 bit_mask) ++{ ++ u32 value; ++ ++ value = ioread32(stfcamss->syscon_base + reg); ++ iowrite32(value | bit_mask, stfcamss->syscon_base + reg); ++} ++ ++static inline void stf_syscon_reg_clear_bit(struct stfcamss *stfcamss, ++ u32 reg, u32 bit_mask) ++{ ++ u32 value; ++ ++ value = ioread32(stfcamss->syscon_base + reg); ++ iowrite32(value & ~bit_mask, stfcamss->syscon_base + reg); ++} ++#endif /* STF_CAMSS_H */ +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_common.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * stf_common.h ++ * ++ * StarFive Camera Subsystem - Common definitions ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef STF_COMMON_H ++#define STF_COMMON_H ++ ++enum stf_subdev_type { ++ STF_SUBDEV_TYPE_VIN, ++ STF_SUBDEV_TYPE_ISP, ++}; ++ ++#endif /* STF_COMMON_H */ diff --git a/target/linux/starfive/patches-6.1/0084-media-starfive-Add-video-driver.patch b/target/linux/starfive/patches-6.1/0084-media-starfive-Add-video-driver.patch new file mode 100644 index 0000000000..f9317485a2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0084-media-starfive-Add-video-driver.patch @@ -0,0 +1,992 @@ +From 70a588f7daefe34697ccd04fa6ac3a6d4b63be88 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Fri, 12 May 2023 18:28:42 +0800 +Subject: [PATCH 084/122] media: starfive: Add video driver + +Add video driver for StarFive Camera Subsystem. + +Signed-off-by: Jack Zhu +--- + drivers/media/platform/starfive/Makefile | 3 +- + drivers/media/platform/starfive/stf_video.c | 864 ++++++++++++++++++++ + drivers/media/platform/starfive/stf_video.h | 95 +++ + 3 files changed, 961 insertions(+), 1 deletion(-) + create mode 100644 drivers/media/platform/starfive/stf_video.c + create mode 100644 drivers/media/platform/starfive/stf_video.h + +--- a/drivers/media/platform/starfive/Makefile ++++ b/drivers/media/platform/starfive/Makefile +@@ -4,6 +4,7 @@ + # + + starfive-camss-objs += \ +- stf_camss.o ++ stf_camss.o \ ++ stf_video.o + + obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \ +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_video.c +@@ -0,0 +1,864 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * stf_video.c ++ * ++ * StarFive Camera Subsystem - V4L2 device node ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "stf_camss.h" ++#include "stf_video.h" ++ ++static const struct stfcamss_format_info formats_pix_wr[] = { ++ { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1, ++ { { 1, 1 } }, { { 1, 1 } }, { 10 } }, ++ { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1, ++ { { 1, 1 } }, { { 1, 1 } }, { 10 } }, ++ { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1, ++ { { 1, 1 } }, { { 1, 1 } }, { 10 } }, ++ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1, ++ { { 1, 1 } }, { { 1, 1 } }, { 10 } }, ++}; ++ ++static const struct stfcamss_format_info formats_pix_isp[] = { ++ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1, ++ { { 1, 1 } }, { { 2, 3 } }, { 8 } }, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * Helper functions ++ */ ++ ++static int video_find_format(u32 code, u32 pixelformat, ++ const struct stfcamss_format_info *formats, ++ unsigned int nformats) ++{ ++ int i; ++ ++ for (i = 0; i < nformats; i++) { ++ if (formats[i].code == code && ++ formats[i].pixelformat == pixelformat) ++ return i; ++ } ++ ++ for (i = 0; i < nformats; i++) ++ if (formats[i].code == code) ++ return i; ++ ++ for (i = 0; i < nformats; i++) ++ if (formats[i].pixelformat == pixelformat) ++ return i; ++ ++ return -EINVAL; ++} ++ ++static int __video_try_fmt(struct stfcamss_video *video, struct v4l2_format *f) ++{ ++ struct v4l2_pix_format *pix; ++ const struct stfcamss_format_info *fi; ++ u32 width, height; ++ u32 bpl; ++ int i; ++ ++ pix = &f->fmt.pix; ++ ++ for (i = 0; i < video->nformats; i++) ++ if (pix->pixelformat == video->formats[i].pixelformat) ++ break; ++ ++ if (i == video->nformats) ++ i = 0; /* default format */ ++ ++ fi = &video->formats[i]; ++ width = pix->width; ++ height = pix->height; ++ ++ memset(pix, 0, sizeof(*pix)); ++ ++ pix->pixelformat = fi->pixelformat; ++ pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH, ++ STFCAMSS_FRAME_MAX_WIDTH); ++ pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT, ++ STFCAMSS_FRAME_MAX_HEIGHT); ++ bpl = pix->width / fi->hsub[0].numerator * ++ fi->hsub[0].denominator * fi->bpp[0] / 8; ++ bpl = ALIGN(bpl, video->bpl_alignment); ++ pix->bytesperline = bpl; ++ pix->sizeimage = pix->height / fi->vsub[0].numerator * ++ fi->vsub[0].denominator * bpl; ++ ++ pix->field = V4L2_FIELD_NONE; ++ pix->colorspace = V4L2_COLORSPACE_SRGB; ++ pix->flags = 0; ++ pix->ycbcr_enc = ++ V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); ++ pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, ++ pix->colorspace, ++ pix->ycbcr_enc); ++ pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); ++ ++ return 0; ++} ++ ++static int stf_video_init_format(struct stfcamss_video *video) ++{ ++ int ret; ++ struct v4l2_format format = { ++ .type = video->type, ++ .fmt.pix = { ++ .width = 1920, ++ .height = 1080, ++ .pixelformat = V4L2_PIX_FMT_RGB565, ++ }, ++ }; ++ ++ ret = __video_try_fmt(video, &format); ++ ++ if (ret < 0) ++ return ret; ++ ++ video->active_fmt = format; ++ ++ return 0; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * Video queue operations ++ */ ++ ++static int video_queue_setup(struct vb2_queue *q, ++ unsigned int *num_buffers, ++ unsigned int *num_planes, ++ unsigned int sizes[], ++ struct device *alloc_devs[]) ++{ ++ struct stfcamss_video *video = vb2_get_drv_priv(q); ++ const struct v4l2_pix_format *format = &video->active_fmt.fmt.pix; ++ ++ if (*num_planes) { ++ if (*num_planes != 1) ++ return -EINVAL; ++ ++ if (sizes[0] < format->sizeimage) ++ return -EINVAL; ++ } ++ ++ *num_planes = 1; ++ sizes[0] = format->sizeimage; ++ if (!sizes[0]) ++ dev_err(video->stfcamss->dev, ++ "%s: error size is zero!!!\n", __func__); ++ ++ dev_dbg(video->stfcamss->dev, "planes = %d, size = %d\n", ++ *num_planes, sizes[0]); ++ ++ return 0; ++} ++ ++static int video_buf_init(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue); ++ struct stfcamss_buffer *buffer = ++ container_of(vbuf, struct stfcamss_buffer, vb); ++ const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix; ++ dma_addr_t *paddr; ++ ++ buffer->sizeimage = 0; ++ ++ paddr = vb2_plane_cookie(vb, 0); ++ buffer->sizeimage = vb2_plane_size(vb, 0); ++ buffer->addr[0] = *paddr; ++ if (fmt->pixelformat == V4L2_PIX_FMT_NV12 || ++ fmt->pixelformat == V4L2_PIX_FMT_NV21 || ++ fmt->pixelformat == V4L2_PIX_FMT_NV16 || ++ fmt->pixelformat == V4L2_PIX_FMT_NV61) ++ buffer->addr[1] = ++ buffer->addr[0] + fmt->bytesperline * fmt->height; ++ ++ return 0; ++} ++ ++static int video_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue); ++ const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix; ++ ++ if (fmt->sizeimage > vb2_plane_size(vb, 0)) { ++ dev_err(video->stfcamss->dev, ++ "sizeimage = %d, plane size = %d\n", ++ fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0)); ++ return -EINVAL; ++ } ++ vb2_set_plane_payload(vb, 0, fmt->sizeimage); ++ ++ vbuf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static void video_buf_queue(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue); ++ struct stfcamss_buffer *buffer = ++ container_of(vbuf, struct stfcamss_buffer, vb); ++ ++ video->ops->queue_buffer(video, buffer); ++} ++ ++/* ++ * video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format ++ * @mbus: v4l2_mbus_framefmt format (input) ++ * @pix: v4l2_pix_format_mplane format (output) ++ * @f: a pointer to formats array element to be used for the conversion ++ * @alignment: bytesperline alignment value ++ * ++ * Fill the output pix structure with information from the input mbus format. ++ * ++ * Return 0 on success or a negative error code otherwise ++ */ ++static int video_mbus_to_pix(const struct v4l2_mbus_framefmt *mbus, ++ struct v4l2_pix_format *pix, ++ const struct stfcamss_format_info *f, ++ unsigned int alignment) ++{ ++ u32 bytesperline; ++ ++ memset(pix, 0, sizeof(*pix)); ++ v4l2_fill_pix_format(pix, mbus); ++ pix->pixelformat = f->pixelformat; ++ bytesperline = pix->width / f->hsub[0].numerator * ++ f->hsub[0].denominator * f->bpp[0] / 8; ++ bytesperline = ALIGN(bytesperline, alignment); ++ pix->bytesperline = bytesperline; ++ pix->sizeimage = pix->height / f->vsub[0].numerator * ++ f->vsub[0].denominator * bytesperline; ++ return 0; ++} ++ ++static struct v4l2_subdev *video_remote_subdev(struct stfcamss_video *video, ++ u32 *pad) ++{ ++ struct media_pad *remote; ++ ++ remote = media_pad_remote_pad_first(&video->pad); ++ ++ if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) ++ return NULL; ++ ++ if (pad) ++ *pad = remote->index; ++ ++ return media_entity_to_v4l2_subdev(remote->entity); ++} ++ ++static int video_get_subdev_format(struct stfcamss_video *video, ++ struct v4l2_format *format) ++{ ++ struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix; ++ struct v4l2_subdev_format fmt; ++ struct v4l2_subdev *subdev; ++ u32 pixelformat; ++ u32 pad; ++ int ret; ++ ++ subdev = video_remote_subdev(video, &pad); ++ if (!subdev) ++ return -EPIPE; ++ ++ fmt.pad = pad; ++ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ++ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); ++ if (ret) ++ return ret; ++ ++ pixelformat = pix->pixelformat; ++ ret = video_find_format(fmt.format.code, pixelformat, ++ video->formats, video->nformats); ++ if (ret < 0) ++ return ret; ++ ++ format->type = video->type; ++ ++ return video_mbus_to_pix(&fmt.format, &format->fmt.pix, ++ &video->formats[ret], video->bpl_alignment); ++} ++ ++static int video_check_format(struct stfcamss_video *video) ++{ ++ struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix; ++ struct v4l2_format format; ++ struct v4l2_pix_format *sd_pix = &format.fmt.pix; ++ int ret; ++ ++ sd_pix->pixelformat = pix->pixelformat; ++ ret = video_get_subdev_format(video, &format); ++ if (ret < 0) ++ return ret; ++ ++ if (pix->pixelformat != sd_pix->pixelformat || ++ pix->height > sd_pix->height || ++ pix->width > sd_pix->width || ++ pix->field != format.fmt.pix.field) { ++ dev_err(video->stfcamss->dev, ++ "%s, not match:\n" ++ "0x%x 0x%x\n0x%x 0x%x\n0x%x 0x%x\n", ++ __func__, ++ pix->pixelformat, sd_pix->pixelformat, ++ pix->height, sd_pix->height, ++ pix->field, format.fmt.pix.field); ++ return -EPIPE; ++ } ++ ++ return 0; ++} ++ ++static int video_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct stfcamss_video *video = vb2_get_drv_priv(q); ++ struct video_device *vdev = &video->vdev; ++ struct media_entity *entity; ++ struct media_pad *pad; ++ struct v4l2_subdev *subdev; ++ int ret; ++ ++ ret = video_device_pipeline_start(vdev, &video->stfcamss->pipe); ++ if (ret < 0) { ++ dev_err(video->stfcamss->dev, ++ "Failed to media_pipeline_start: %d\n", ret); ++ return ret; ++ } ++ ++ ret = video_check_format(video); ++ if (ret < 0) ++ goto error; ++ entity = &vdev->entity; ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ ret = v4l2_subdev_call(subdev, video, s_stream, 1); ++ if (ret < 0 && ret != -ENOIOCTLCMD) ++ goto error; ++ } ++ return 0; ++ ++error: ++ video_device_pipeline_stop(vdev); ++ video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); ++ return ret; ++} ++ ++static void video_stop_streaming(struct vb2_queue *q) ++{ ++ struct stfcamss_video *video = vb2_get_drv_priv(q); ++ struct video_device *vdev = &video->vdev; ++ struct media_entity *entity; ++ struct media_pad *pad; ++ struct v4l2_subdev *subdev; ++ ++ entity = &vdev->entity; ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ v4l2_subdev_call(subdev, video, s_stream, 0); ++ } ++ ++ video_device_pipeline_stop(vdev); ++ video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); ++} ++ ++static const struct vb2_ops stf_video_vb2_q_ops = { ++ .queue_setup = video_queue_setup, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .buf_init = video_buf_init, ++ .buf_prepare = video_buf_prepare, ++ .buf_queue = video_buf_queue, ++ .start_streaming = video_start_streaming, ++ .stop_streaming = video_stop_streaming, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 ioctls ++ */ ++ ++static int video_querycap(struct file *file, void *fh, ++ struct v4l2_capability *cap) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ ++ strscpy(cap->driver, "stf camss", sizeof(cap->driver)); ++ strscpy(cap->card, "Starfive Camera Subsystem", sizeof(cap->card)); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ dev_name(video->stfcamss->dev)); ++ return 0; ++} ++ ++static int video_get_pfmt_by_index(struct stfcamss_video *video, int ndx) ++{ ++ int i, j, k; ++ ++ /* find index "i" of "k"th unique pixelformat in formats array */ ++ k = -1; ++ for (i = 0; i < video->nformats; i++) { ++ for (j = 0; j < i; j++) { ++ if (video->formats[i].pixelformat == ++ video->formats[j].pixelformat) ++ break; ++ } ++ ++ if (j == i) ++ k++; ++ ++ if (k == ndx) ++ return i; ++ } ++ ++ return -EINVAL; ++} ++ ++static int video_get_pfmt_by_mcode(struct stfcamss_video *video, u32 mcode) ++{ ++ int i; ++ ++ for (i = 0; i < video->nformats; i++) { ++ if (video->formats[i].code == mcode) ++ return i; ++ } ++ ++ return -EINVAL; ++} ++ ++static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ int i; ++ ++ if (f->type != video->type) ++ return -EINVAL; ++ if (f->index >= video->nformats) ++ return -EINVAL; ++ ++ if (f->mbus_code) { ++ /* Each entry in formats[] table has unique mbus_code */ ++ if (f->index > 0) ++ return -EINVAL; ++ ++ i = video_get_pfmt_by_mcode(video, f->mbus_code); ++ } else { ++ i = video_get_pfmt_by_index(video, f->index); ++ } ++ ++ if (i < 0) ++ return -EINVAL; ++ ++ f->pixelformat = video->formats[i].pixelformat; ++ ++ return 0; ++} ++ ++static int video_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ int i; ++ ++ if (fsize->index) ++ return -EINVAL; ++ ++ for (i = 0; i < video->nformats; i++) { ++ if (video->formats[i].pixelformat == fsize->pixel_format) ++ break; ++ } ++ ++ if (i == video->nformats) ++ return -EINVAL; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; ++ fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH; ++ fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH; ++ fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT; ++ fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT; ++ fsize->stepwise.step_width = 1; ++ fsize->stepwise.step_height = 1; ++ ++ return 0; ++} ++ ++static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ ++ *f = video->active_fmt; ++ ++ return 0; ++} ++ ++static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ int ret; ++ ++ if (vb2_is_busy(&video->vb2_q)) ++ return -EBUSY; ++ ++ ret = __video_try_fmt(video, f); ++ if (ret < 0) ++ return ret; ++ ++ video->active_fmt = *f; ++ ++ return 0; ++} ++ ++static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ ++ return __video_try_fmt(video, f); ++} ++ ++static int video_enum_input(struct file *file, void *fh, ++ struct v4l2_input *input) ++{ ++ if (input->index > 0) ++ return -EINVAL; ++ ++ strscpy(input->name, "camera", sizeof(input->name)); ++ input->type = V4L2_INPUT_TYPE_CAMERA; ++ ++ return 0; ++} ++ ++static int video_g_input(struct file *file, void *fh, unsigned int *input) ++{ ++ *input = 0; ++ ++ return 0; ++} ++ ++static int video_s_input(struct file *file, void *fh, unsigned int input) ++{ ++ return input == 0 ? 0 : -EINVAL; ++} ++ ++static int video_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *p) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ struct video_device *vdev = &video->vdev; ++ struct media_entity *entity; ++ struct v4l2_subdev *subdev; ++ struct media_pad *pad; ++ int ret, is_support = 0; ++ ++ entity = &vdev->entity; ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ ret = v4l2_g_parm_cap(vdev, subdev, p); ++ if (ret < 0 && ret != -ENOIOCTLCMD) ++ break; ++ if (!ret) ++ is_support = 1; ++ } ++ ++ return is_support ? 0 : ret; ++} ++ ++static int video_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *p) ++{ ++ struct stfcamss_video *video = video_drvdata(file); ++ struct video_device *vdev = &video->vdev; ++ struct media_entity *entity; ++ struct v4l2_subdev *subdev; ++ struct media_pad *pad; ++ struct v4l2_streamparm tmp_p; ++ int ret, is_support = 0; ++ ++ entity = &vdev->entity; ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ tmp_p = *p; ++ ret = v4l2_s_parm_cap(vdev, subdev, &tmp_p); ++ if (ret < 0 && ret != -ENOIOCTLCMD) ++ break; ++ if (!ret) { ++ is_support = 1; ++ *p = tmp_p; ++ } ++ } ++ ++ return is_support ? 0 : ret; ++} ++ ++static const struct v4l2_ioctl_ops stf_vid_vin_ioctl_ops = { ++ .vidioc_querycap = video_querycap, ++ .vidioc_enum_fmt_vid_cap = video_enum_fmt, ++ .vidioc_enum_fmt_vid_out = video_enum_fmt, ++ .vidioc_enum_framesizes = video_enum_framesizes, ++ .vidioc_g_fmt_vid_cap = video_g_fmt, ++ .vidioc_s_fmt_vid_cap = video_s_fmt, ++ .vidioc_try_fmt_vid_cap = video_try_fmt, ++ .vidioc_g_fmt_vid_out = video_g_fmt, ++ .vidioc_s_fmt_vid_out = video_s_fmt, ++ .vidioc_try_fmt_vid_out = video_try_fmt, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = video_enum_input, ++ .vidioc_g_input = video_g_input, ++ .vidioc_s_input = video_s_input, ++ .vidioc_g_parm = video_g_parm, ++ .vidioc_s_parm = video_s_parm, ++}; ++ ++static const struct v4l2_ioctl_ops stf_vid_isp_ioctl_ops = { ++ .vidioc_querycap = video_querycap, ++ .vidioc_enum_fmt_vid_cap = video_enum_fmt, ++ .vidioc_enum_fmt_vid_out = video_enum_fmt, ++ .vidioc_enum_framesizes = video_enum_framesizes, ++ .vidioc_g_fmt_vid_cap = video_g_fmt, ++ .vidioc_s_fmt_vid_cap = video_s_fmt, ++ .vidioc_try_fmt_vid_cap = video_try_fmt, ++ .vidioc_g_fmt_vid_out = video_g_fmt, ++ .vidioc_s_fmt_vid_out = video_s_fmt, ++ .vidioc_try_fmt_vid_out = video_try_fmt, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = video_enum_input, ++ .vidioc_g_input = video_g_input, ++ .vidioc_s_input = video_s_input, ++ .vidioc_g_parm = video_g_parm, ++ .vidioc_s_parm = video_s_parm, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 file operations ++ */ ++ ++static int video_open(struct file *file) ++{ ++ struct video_device *vdev = video_devdata(file); ++ struct stfcamss_video *video = video_drvdata(file); ++ struct v4l2_fh *vfh; ++ int ret; ++ ++ mutex_lock(&video->lock); ++ ++ vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); ++ if (!vfh) { ++ ret = -ENOMEM; ++ goto error_alloc; ++ } ++ ++ v4l2_fh_init(vfh, vdev); ++ v4l2_fh_add(vfh); ++ ++ file->private_data = vfh; ++ ++ ret = v4l2_pipeline_pm_get(&vdev->entity); ++ if (ret < 0) { ++ dev_err(video->stfcamss->dev, ++ "Failed to power up pipeline: %d\n", ret); ++ goto error_pm_use; ++ } ++ mutex_unlock(&video->lock); ++ ++ return 0; ++ ++error_pm_use: ++ v4l2_fh_release(file); ++error_alloc: ++ mutex_unlock(&video->lock); ++ return ret; ++} ++ ++static int video_release(struct file *file) ++{ ++ struct video_device *vdev = video_devdata(file); ++ ++ vb2_fop_release(file); ++ v4l2_pipeline_pm_put(&vdev->entity); ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static const struct v4l2_file_operations stf_vid_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .open = video_open, ++ .release = video_release, ++ .poll = vb2_fop_poll, ++ .mmap = vb2_fop_mmap, ++ .read = vb2_fop_read, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * STFCAMSS video core ++ */ ++ ++static void stf_video_release(struct video_device *vdev) ++{ ++ struct stfcamss_video *video = video_get_drvdata(vdev); ++ ++ media_entity_cleanup(&vdev->entity); ++ ++ mutex_destroy(&video->q_lock); ++ mutex_destroy(&video->lock); ++} ++ ++int stf_video_register(struct stfcamss_video *video, ++ struct v4l2_device *v4l2_dev, const char *name) ++{ ++ struct video_device *vdev; ++ struct vb2_queue *q; ++ struct media_pad *pad = &video->pad; ++ int ret; ++ ++ vdev = &video->vdev; ++ ++ mutex_init(&video->q_lock); ++ ++ q = &video->vb2_q; ++ q->drv_priv = video; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->ops = &stf_video_vb2_q_ops; ++ q->type = video->type; ++ q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ; ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->buf_struct_size = sizeof(struct stfcamss_buffer); ++ q->dev = video->stfcamss->dev; ++ q->lock = &video->q_lock; ++ q->min_buffers_needed = STFCAMSS_MIN_BUFFERS; ++ ret = vb2_queue_init(q); ++ if (ret < 0) { ++ dev_err(video->stfcamss->dev, ++ "Failed to init vb2 queue: %d\n", ret); ++ goto err_vb2_init; ++ } ++ ++ pad->flags = MEDIA_PAD_FL_SINK; ++ ret = media_entity_pads_init(&vdev->entity, 1, pad); ++ if (ret < 0) { ++ dev_err(video->stfcamss->dev, ++ "Failed to init video entity: %d\n", ret); ++ goto err_vb2_init; ++ } ++ ++ mutex_init(&video->lock); ++ ++ if (video->id == STF_V_LINE_WR) { ++ video->formats = formats_pix_wr; ++ video->nformats = ARRAY_SIZE(formats_pix_wr); ++ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8; ++ vdev->ioctl_ops = &stf_vid_vin_ioctl_ops; ++ } else { ++ video->formats = formats_pix_isp; ++ video->nformats = ARRAY_SIZE(formats_pix_isp); ++ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8; ++ vdev->ioctl_ops = &stf_vid_isp_ioctl_ops; ++ } ++ ++ ret = stf_video_init_format(video); ++ if (ret < 0) { ++ dev_err(video->stfcamss->dev, ++ "Failed to init format: %d\n", ret); ++ goto err_vid_init_format; ++ } ++ ++ vdev->fops = &stf_vid_fops; ++ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE; ++ vdev->vfl_dir = VFL_DIR_RX; ++ vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; ++ vdev->release = stf_video_release; ++ vdev->v4l2_dev = v4l2_dev; ++ vdev->queue = &video->vb2_q; ++ vdev->lock = &video->lock; ++ strscpy(vdev->name, name, sizeof(vdev->name)); ++ ++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, video->id); ++ if (ret < 0) { ++ dev_err(video->stfcamss->dev, ++ "Failed to register video device: %d\n", ret); ++ goto err_vid_reg; ++ } ++ ++ video_set_drvdata(vdev, video); ++ return 0; ++ ++err_vid_reg: ++err_vid_init_format: ++ media_entity_cleanup(&vdev->entity); ++ mutex_destroy(&video->lock); ++err_vb2_init: ++ mutex_destroy(&video->q_lock); ++ return ret; ++} ++ ++void stf_video_unregister(struct stfcamss_video *video) ++{ ++ vb2_video_unregister_device(&video->vdev); ++} +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_video.h +@@ -0,0 +1,95 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * stf_video.h ++ * ++ * StarFive Camera Subsystem - V4L2 device node ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef STF_VIDEO_H ++#define STF_VIDEO_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define STFCAMSS_FRAME_MIN_WIDTH 64 ++#define STFCAMSS_FRAME_MAX_WIDTH 1920 ++#define STFCAMSS_FRAME_MIN_HEIGHT 64 ++#define STFCAMSS_FRAME_MAX_HEIGHT 1080 ++#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8 ++#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128 ++#define STFCAMSS_MIN_BUFFERS 2 ++ ++#define STFCAMSS_MAX_ENTITY_NAME_LEN 27 ++ ++enum stf_v_line_id { ++ STF_V_LINE_WR = 0, ++ STF_V_LINE_ISP, ++ STF_V_LINE_MAX, ++}; ++ ++struct stfcamss_buffer { ++ struct vb2_v4l2_buffer vb; ++ dma_addr_t addr[3]; ++ struct list_head queue; ++ int sizeimage; ++}; ++ ++struct fract { ++ u8 numerator; ++ u8 denominator; ++}; ++ ++/* ++ * struct stfcamss_format_info - ISP media bus format information ++ * @code: V4L2 media bus format code ++ * @pixelformat: V4L2 pixel format FCC identifier ++ * @planes: Number of planes ++ * @hsub: Horizontal subsampling (for each plane) ++ * @vsub: Vertical subsampling (for each plane) ++ * @bpp: Bits per pixel when stored in memory (for each plane) ++ */ ++struct stfcamss_format_info { ++ u32 code; ++ u32 pixelformat; ++ u8 planes; ++ struct fract hsub[3]; ++ struct fract vsub[3]; ++ u8 bpp[3]; ++}; ++ ++struct stfcamss_video { ++ struct stfcamss *stfcamss; ++ u8 id; ++ struct vb2_queue vb2_q; ++ struct video_device vdev; ++ struct media_pad pad; ++ struct media_pipeline pipe; ++ struct v4l2_format active_fmt; ++ enum v4l2_buf_type type; ++ const struct stfcamss_video_ops *ops; ++ struct mutex lock; /* serialize device access */ ++ struct mutex q_lock; /* protects the queue */ ++ unsigned int bpl_alignment; ++ const struct stfcamss_format_info *formats; ++ unsigned int nformats; ++}; ++ ++struct stfcamss_video_ops { ++ int (*queue_buffer)(struct stfcamss_video *vid, ++ struct stfcamss_buffer *buf); ++ int (*flush_buffers)(struct stfcamss_video *vid, ++ enum vb2_buffer_state state); ++}; ++ ++int stf_video_register(struct stfcamss_video *video, ++ struct v4l2_device *v4l2_dev, const char *name); ++ ++void stf_video_unregister(struct stfcamss_video *video); ++ ++#endif /* STF_VIDEO_H */ diff --git a/target/linux/starfive/patches-6.1/0085-media-starfive-Add-ISP-driver.patch b/target/linux/starfive/patches-6.1/0085-media-starfive-Add-ISP-driver.patch new file mode 100644 index 0000000000..3a871b5a7f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0085-media-starfive-Add-ISP-driver.patch @@ -0,0 +1,1667 @@ +From 3b814965133cd53b1f30a34e4425294726cb0087 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Fri, 12 May 2023 18:28:43 +0800 +Subject: [PATCH 085/122] media: starfive: Add ISP driver + +Add ISP driver for StarFive Camera Subsystem. + +Signed-off-by: Jack Zhu +--- + drivers/media/platform/starfive/Makefile | 2 + + drivers/media/platform/starfive/stf_camss.c | 71 ++- + drivers/media/platform/starfive/stf_camss.h | 2 + + drivers/media/platform/starfive/stf_isp.c | 550 ++++++++++++++++++ + drivers/media/platform/starfive/stf_isp.h | 476 +++++++++++++++ + .../media/platform/starfive/stf_isp_hw_ops.c | 452 ++++++++++++++ + 6 files changed, 1551 insertions(+), 2 deletions(-) + create mode 100644 drivers/media/platform/starfive/stf_isp.c + create mode 100644 drivers/media/platform/starfive/stf_isp.h + create mode 100644 drivers/media/platform/starfive/stf_isp_hw_ops.c + +--- a/drivers/media/platform/starfive/Makefile ++++ b/drivers/media/platform/starfive/Makefile +@@ -5,6 +5,8 @@ + + starfive-camss-objs += \ + stf_camss.o \ ++ stf_isp.o \ ++ stf_isp_hw_ops.o \ + stf_video.o + + obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \ +--- a/drivers/media/platform/starfive/stf_camss.c ++++ b/drivers/media/platform/starfive/stf_camss.c +@@ -126,16 +126,66 @@ err_cleanup: + return ret; + } + ++/* ++ * stfcamss_init_subdevices - Initialize subdev structures and resources ++ * @stfcamss: STFCAMSS device ++ * ++ * Return 0 on success or a negative error code on failure ++ */ ++static int stfcamss_init_subdevices(struct stfcamss *stfcamss) ++{ ++ int ret; ++ ++ ret = stf_isp_subdev_init(stfcamss); ++ if (ret < 0) { ++ dev_err(stfcamss->dev, "Failed to init isp subdev: %d\n", ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int stfcamss_register_subdevices(struct stfcamss *stfcamss) ++{ ++ int ret; ++ struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; ++ ++ ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev); ++ if (ret < 0) { ++ dev_err(stfcamss->dev, ++ "Failed to register stf isp%d entity: %d\n", 0, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static void stfcamss_unregister_subdevices(struct stfcamss *stfcamss) ++{ ++ stf_isp_unregister(&stfcamss->isp_dev); ++} ++ + static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) + { + struct stfcamss *stfcamss = + container_of(async, struct stfcamss, notifier); ++ struct stfcamss_async_subdev *csd = ++ container_of(asd, struct stfcamss_async_subdev, asd); ++ enum port_num port = csd->port; ++ struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; + struct host_data *host_data = &stfcamss->host_data; + struct media_entity *source; + int i, j; + ++ if (port == PORT_NUMBER_CSI2RX) { ++ host_data->host_entity[1] = &isp_dev->subdev.entity; ++ } else if (port == PORT_NUMBER_DVP_SENSOR) { ++ dev_err(stfcamss->dev, "Not support DVP sensor\n"); ++ return -EPERM; ++ } ++ + source = &subdev->entity; + + for (i = 0; i < source->num_pads; i++) { +@@ -266,12 +316,18 @@ static int stfcamss_probe(struct platfor + return -ENODEV; + } + ++ ret = stfcamss_init_subdevices(stfcamss); ++ if (ret < 0) { ++ dev_err(dev, "Failed to init subdevice: %d\n", ret); ++ goto err_cleanup_notifier; ++ } ++ + stfcamss_mc_init(pdev, stfcamss); + + ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev); + if (ret < 0) { + dev_err(dev, "Failed to register V4L2 device: %d\n", ret); +- goto err_cleanup_notifier; ++ goto err_cleanup_media_device; + } + + ret = media_device_register(&stfcamss->media_dev); +@@ -280,22 +336,32 @@ static int stfcamss_probe(struct platfor + goto err_unregister_device; + } + ++ ret = stfcamss_register_subdevices(stfcamss); ++ if (ret < 0) { ++ dev_err(dev, "Failed to register subdevice: %d\n", ret); ++ goto err_unregister_media_dev; ++ } ++ + stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops; + ret = v4l2_async_nf_register(&stfcamss->v4l2_dev, &stfcamss->notifier); + if (ret) { + dev_err(dev, "Failed to register async subdev nodes: %d\n", + ret); +- goto err_unregister_media_dev; ++ goto err_unregister_subdevs; + } + + pm_runtime_enable(dev); + + return 0; + ++err_unregister_subdevs: ++ stfcamss_unregister_subdevices(stfcamss); + err_unregister_media_dev: + media_device_unregister(&stfcamss->media_dev); + err_unregister_device: + v4l2_device_unregister(&stfcamss->v4l2_dev); ++err_cleanup_media_device: ++ media_device_cleanup(&stfcamss->media_dev); + err_cleanup_notifier: + v4l2_async_nf_cleanup(&stfcamss->notifier); + return ret; +@@ -311,6 +377,7 @@ static int stfcamss_remove(struct platfo + { + struct stfcamss *stfcamss = platform_get_drvdata(pdev); + ++ stfcamss_unregister_subdevices(stfcamss); + v4l2_device_unregister(&stfcamss->v4l2_dev); + media_device_cleanup(&stfcamss->media_dev); + pm_runtime_disable(&pdev->dev); +--- a/drivers/media/platform/starfive/stf_camss.h ++++ b/drivers/media/platform/starfive/stf_camss.h +@@ -16,6 +16,7 @@ + #include + + #include "stf_common.h" ++#include "stf_isp.h" + + #define DRV_NAME "starfive-camss" + #define STF_DVP_NAME "stf_dvp" +@@ -71,6 +72,7 @@ struct stfcamss { + struct media_device media_dev; + struct media_pipeline pipe; + struct device *dev; ++ struct stf_isp_dev isp_dev; + struct v4l2_async_notifier notifier; + struct host_data host_data; + void __iomem *syscon_base; +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_isp.c +@@ -0,0 +1,550 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * stf_isp.c ++ * ++ * StarFive Camera Subsystem - ISP Module ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++#include ++#include ++ ++#include "stf_camss.h" ++ ++#define SINK_FORMATS_INDEX 0 ++#define UO_FORMATS_INDEX 1 ++ ++static int isp_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_selection *sel); ++ ++static const struct isp_format isp_formats_sink[] = { ++ { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, ++ { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, ++ { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, ++ { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, ++}; ++ ++static const struct isp_format isp_formats_uo[] = { ++ { MEDIA_BUS_FMT_Y12_1X12, 8 }, ++}; ++ ++static const struct isp_format_table isp_formats_st7110[] = { ++ { isp_formats_sink, ARRAY_SIZE(isp_formats_sink) }, ++ { isp_formats_uo, ARRAY_SIZE(isp_formats_uo) }, ++}; ++ ++int stf_isp_subdev_init(struct stfcamss *stfcamss) ++{ ++ struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; ++ ++ isp_dev->sdev_type = STF_SUBDEV_TYPE_ISP; ++ isp_dev->stfcamss = stfcamss; ++ isp_dev->formats = isp_formats_st7110; ++ isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110); ++ ++ mutex_init(&isp_dev->stream_lock); ++ mutex_init(&isp_dev->power_lock); ++ return 0; ++} ++ ++static int isp_set_power(struct v4l2_subdev *sd, int on) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ ++ mutex_lock(&isp_dev->power_lock); ++ if (on) { ++ if (isp_dev->power_count == 0) ++ dev_dbg(isp_dev->stfcamss->dev, "turn on isp\n"); ++ isp_dev->power_count++; ++ } else { ++ if (isp_dev->power_count == 0) ++ goto exit; ++ isp_dev->power_count--; ++ } ++exit: ++ mutex_unlock(&isp_dev->power_lock); ++ ++ return 0; ++} ++ ++static struct v4l2_mbus_framefmt * ++__isp_get_format(struct stf_isp_dev *isp_dev, ++ struct v4l2_subdev_state *state, ++ unsigned int pad, ++ enum v4l2_subdev_format_whence which) ++{ ++ if (which == V4L2_SUBDEV_FORMAT_TRY) ++ return v4l2_subdev_get_try_format(&isp_dev->subdev, state, pad); ++ ++ return &isp_dev->fmt[pad]; ++} ++ ++static int isp_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ struct v4l2_mbus_framefmt *fmt; ++ struct v4l2_event src_ch = { 0 }; ++ ++ fmt = __isp_get_format(isp_dev, NULL, STF_ISP_PAD_SINK, ++ V4L2_SUBDEV_FORMAT_ACTIVE); ++ mutex_lock(&isp_dev->stream_lock); ++ if (enable) { ++ if (isp_dev->stream_count == 0) { ++ stf_isp_clk_enable(isp_dev); ++ stf_isp_reset(isp_dev); ++ stf_isp_init_cfg(isp_dev); ++ stf_isp_settings(isp_dev, isp_dev->rect, fmt->code); ++ stf_isp_stream_set(isp_dev); ++ } ++ isp_dev->stream_count++; ++ } else { ++ if (isp_dev->stream_count == 0) ++ goto exit; ++ ++ if (isp_dev->stream_count == 1) ++ stf_isp_clk_disable(isp_dev); ++ ++ isp_dev->stream_count--; ++ } ++ src_ch.type = V4L2_EVENT_SOURCE_CHANGE, ++ src_ch.u.src_change.changes = isp_dev->stream_count, ++ ++ v4l2_subdev_notify_event(sd, &src_ch); ++exit: ++ mutex_unlock(&isp_dev->stream_lock); ++ ++ return ret; ++} ++ ++static void isp_try_format(struct stf_isp_dev *isp_dev, ++ struct v4l2_subdev_state *state, ++ unsigned int pad, ++ struct v4l2_mbus_framefmt *fmt, ++ enum v4l2_subdev_format_whence which) ++{ ++ const struct isp_format_table *formats; ++ struct stf_isp_crop *rect; ++ int i; ++ ++ switch (pad) { ++ case STF_ISP_PAD_SINK: ++ /* Set format on sink pad */ ++ formats = &isp_dev->formats[SINK_FORMATS_INDEX]; ++ rect = &isp_dev->rect[SINK_FORMATS_INDEX]; ++ fmt->width = clamp_t(u32, ++ fmt->width, STFCAMSS_FRAME_MIN_WIDTH, ++ STFCAMSS_FRAME_MAX_WIDTH); ++ fmt->height = clamp_t(u32, ++ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT, ++ STFCAMSS_FRAME_MAX_HEIGHT); ++ fmt->height &= ~0x1; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_SRGB; ++ fmt->flags = 0; ++ break; ++ ++ case STF_ISP_PAD_SRC: ++ formats = &isp_dev->formats[UO_FORMATS_INDEX]; ++ rect = &isp_dev->rect[UO_FORMATS_INDEX]; ++ *fmt = *__isp_get_format(isp_dev, state, ++ STF_ISP_PAD_SINK, which); ++ break; ++ } ++ ++ for (i = 0; i < formats->nfmts; i++) { ++ if (fmt->code == formats->fmts[i].code) ++ break; ++ } ++ ++ if (i >= formats->nfmts) { ++ fmt->code = formats->fmts[0].code; ++ rect->bpp = formats->fmts[0].bpp; ++ } else { ++ rect->bpp = formats->fmts[i].bpp; ++ } ++} ++ ++static int isp_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ const struct isp_format_table *formats; ++ ++ if (code->index >= isp_dev->nformats) ++ return -EINVAL; ++ if (code->pad == STF_ISP_PAD_SINK) { ++ formats = &isp_dev->formats[SINK_FORMATS_INDEX]; ++ code->code = formats->fmts[code->index].code; ++ } else { ++ struct v4l2_mbus_framefmt *sink_fmt; ++ ++ sink_fmt = __isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, ++ code->which); ++ ++ code->code = sink_fmt->code; ++ if (!code->code) ++ return -EINVAL; ++ } ++ code->flags = 0; ++ ++ return 0; ++} ++ ++static int isp_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt format; ++ ++ if (fse->index != 0) ++ return -EINVAL; ++ ++ format.code = fse->code; ++ format.width = 1; ++ format.height = 1; ++ isp_try_format(isp_dev, state, fse->pad, &format, fse->which); ++ fse->min_width = format.width; ++ fse->min_height = format.height; ++ ++ if (format.code != fse->code) ++ return -EINVAL; ++ ++ format.code = fse->code; ++ format.width = -1; ++ format.height = -1; ++ isp_try_format(isp_dev, state, fse->pad, &format, fse->which); ++ fse->max_width = format.width; ++ fse->max_height = format.height; ++ ++ return 0; ++} ++ ++static int isp_get_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt *format; ++ ++ format = __isp_get_format(isp_dev, state, fmt->pad, fmt->which); ++ if (!format) ++ return -EINVAL; ++ ++ fmt->format = *format; ++ ++ return 0; ++} ++ ++static int isp_set_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt *format; ++ ++ format = __isp_get_format(isp_dev, state, fmt->pad, fmt->which); ++ if (!format) ++ return -EINVAL; ++ ++ mutex_lock(&isp_dev->stream_lock); ++ ++ isp_try_format(isp_dev, state, fmt->pad, &fmt->format, fmt->which); ++ *format = fmt->format; ++ ++ mutex_unlock(&isp_dev->stream_lock); ++ ++ /* Propagate to in crop */ ++ if (fmt->pad == STF_ISP_PAD_SINK) { ++ struct v4l2_subdev_selection sel = { 0 }; ++ int ret; ++ ++ /* Reset sink pad compose selection */ ++ sel.which = fmt->which; ++ sel.pad = STF_ISP_PAD_SINK; ++ sel.target = V4L2_SEL_TGT_CROP; ++ sel.r.width = fmt->format.width; ++ sel.r.height = fmt->format.height; ++ ret = isp_set_selection(sd, state, &sel); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static struct v4l2_rect * ++__isp_get_crop(struct stf_isp_dev *isp_dev, ++ struct v4l2_subdev_state *state, ++ unsigned int pad, ++ enum v4l2_subdev_format_whence which) ++{ ++ if (which == V4L2_SUBDEV_FORMAT_TRY) ++ return v4l2_subdev_get_try_crop(&isp_dev->subdev, state, ++ STF_ISP_PAD_SINK); ++ ++ return &isp_dev->rect[pad].rect; ++} ++ ++static void isp_try_crop(struct stf_isp_dev *isp_dev, ++ struct v4l2_subdev_state *state, ++ struct v4l2_rect *rect, ++ enum v4l2_subdev_format_whence which) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ ++ fmt = __isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, which); ++ ++ if (rect->width > fmt->width) ++ rect->width = fmt->width; ++ ++ if (rect->width + rect->left > fmt->width) ++ rect->left = fmt->width - rect->width; ++ ++ if (rect->height > fmt->height) ++ rect->height = fmt->height; ++ ++ if (rect->height + rect->top > fmt->height) ++ rect->top = fmt->height - rect->height; ++ ++ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) { ++ rect->left = 0; ++ rect->width = STFCAMSS_FRAME_MAX_WIDTH; ++ } ++ ++ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) { ++ rect->top = 0; ++ rect->height = STFCAMSS_FRAME_MAX_HEIGHT; ++ } ++ rect->height &= ~0x1; ++} ++ ++static int isp_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ struct v4l2_subdev_format fmt = { 0 }; ++ struct v4l2_rect *rect; ++ int ret; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ if (sel->pad == STF_ISP_PAD_SINK) { ++ fmt.pad = sel->pad; ++ fmt.which = sel->which; ++ ret = isp_get_format(sd, state, &fmt); ++ if (ret < 0) ++ return ret; ++ ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = fmt.format.width; ++ sel->r.height = fmt.format.height; ++ } else if (sel->pad == STF_ISP_PAD_SRC) { ++ rect = __isp_get_crop(isp_dev, state, ++ sel->pad, sel->which); ++ sel->r = *rect; ++ } ++ break; ++ ++ case V4L2_SEL_TGT_CROP: ++ rect = __isp_get_crop(isp_dev, state, sel->pad, sel->which); ++ if (!rect) ++ return -EINVAL; ++ ++ sel->r = *rect; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int isp_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); ++ struct v4l2_rect *rect; ++ int ret = 0; ++ ++ if (sel->target == V4L2_SEL_TGT_CROP && ++ sel->pad == STF_ISP_PAD_SINK) { ++ struct v4l2_subdev_selection crop = { 0 }; ++ ++ rect = __isp_get_crop(isp_dev, state, sel->pad, sel->which); ++ if (!rect) ++ return -EINVAL; ++ ++ mutex_lock(&isp_dev->stream_lock); ++ isp_try_crop(isp_dev, state, &sel->r, sel->which); ++ *rect = sel->r; ++ mutex_unlock(&isp_dev->stream_lock); ++ ++ /* Reset source crop selection */ ++ crop.which = sel->which; ++ crop.pad = STF_ISP_PAD_SRC; ++ crop.target = V4L2_SEL_TGT_CROP; ++ crop.r = *rect; ++ ret = isp_set_selection(sd, state, &crop); ++ } else if (sel->target == V4L2_SEL_TGT_CROP && ++ sel->pad == STF_ISP_PAD_SRC) { ++ struct v4l2_subdev_format fmt = { 0 }; ++ ++ rect = __isp_get_crop(isp_dev, state, sel->pad, sel->which); ++ if (!rect) ++ return -EINVAL; ++ ++ mutex_lock(&isp_dev->stream_lock); ++ isp_try_crop(isp_dev, state, &sel->r, sel->which); ++ *rect = sel->r; ++ mutex_unlock(&isp_dev->stream_lock); ++ ++ /* Reset source pad format width and height */ ++ fmt.which = sel->which; ++ fmt.pad = STF_ISP_PAD_SRC; ++ fmt.format.width = rect->width; ++ fmt.format.height = rect->height; ++ ret = isp_set_format(sd, state, &fmt); ++ if (ret < 0) ++ return ret; ++ } ++ ++ dev_dbg(isp_dev->stfcamss->dev, "pad: %d sel(%d,%d)/%dx%d\n", ++ sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); ++ ++ return 0; ++} ++ ++static int isp_init_formats(struct v4l2_subdev *sd, ++ struct v4l2_subdev_fh *fh) ++{ ++ struct v4l2_subdev_format format = { ++ .pad = STF_ISP_PAD_SINK, ++ .which = ++ fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, ++ .format = { ++ .code = MEDIA_BUS_FMT_RGB565_2X8_LE, ++ .width = 1920, ++ .height = 1080 ++ } ++ }; ++ ++ return isp_set_format(sd, fh ? fh->state : NULL, &format); ++} ++ ++static int isp_link_setup(struct media_entity *entity, ++ const struct media_pad *local, ++ const struct media_pad *remote, u32 flags) ++{ ++ if (flags & MEDIA_LNK_FL_ENABLED) ++ if (media_pad_remote_pad_first(local)) ++ return -EBUSY; ++ return 0; ++} ++ ++static int stf_isp_subscribe_event(struct v4l2_subdev *sd, ++ struct v4l2_fh *fh, ++ struct v4l2_event_subscription *sub) ++{ ++ switch (sub->type) { ++ case V4L2_EVENT_SOURCE_CHANGE: ++ return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static const struct v4l2_subdev_core_ops isp_core_ops = { ++ .s_power = isp_set_power, ++ .subscribe_event = stf_isp_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops isp_video_ops = { ++ .s_stream = isp_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops isp_pad_ops = { ++ .enum_mbus_code = isp_enum_mbus_code, ++ .enum_frame_size = isp_enum_frame_size, ++ .get_fmt = isp_get_format, ++ .set_fmt = isp_set_format, ++ .get_selection = isp_get_selection, ++ .set_selection = isp_set_selection, ++}; ++ ++static const struct v4l2_subdev_ops isp_v4l2_ops = { ++ .core = &isp_core_ops, ++ .video = &isp_video_ops, ++ .pad = &isp_pad_ops, ++}; ++ ++static const struct v4l2_subdev_internal_ops isp_v4l2_internal_ops = { ++ .open = isp_init_formats, ++}; ++ ++static const struct media_entity_operations isp_media_ops = { ++ .link_setup = isp_link_setup, ++ .link_validate = v4l2_subdev_link_validate, ++}; ++ ++int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev) ++{ ++ struct v4l2_subdev *sd = &isp_dev->subdev; ++ struct media_pad *pads = isp_dev->pads; ++ int ret; ++ ++ v4l2_subdev_init(sd, &isp_v4l2_ops); ++ sd->internal_ops = &isp_v4l2_internal_ops; ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; ++ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d", STF_ISP_NAME, 0); ++ v4l2_set_subdevdata(sd, isp_dev); ++ ++ ret = isp_init_formats(sd, NULL); ++ if (ret < 0) { ++ dev_err(isp_dev->stfcamss->dev, "Failed to init format: %d\n", ++ ret); ++ return ret; ++ } ++ ++ pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; ++ pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; ++ ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; ++ sd->entity.ops = &isp_media_ops; ++ ret = media_entity_pads_init(&sd->entity, STF_ISP_PAD_MAX, pads); ++ if (ret < 0) { ++ dev_err(isp_dev->stfcamss->dev, ++ "Failed to init media entity: %d\n", ret); ++ return ret; ++ } ++ ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if (ret < 0) { ++ dev_err(isp_dev->stfcamss->dev, ++ "Failed to register subdev: %d\n", ret); ++ goto err_sreg; ++ } ++ ++ return 0; ++ ++err_sreg: ++ media_entity_cleanup(&sd->entity); ++ return ret; ++} ++ ++int stf_isp_unregister(struct stf_isp_dev *isp_dev) ++{ ++ v4l2_device_unregister_subdev(&isp_dev->subdev); ++ media_entity_cleanup(&isp_dev->subdev.entity); ++ mutex_destroy(&isp_dev->stream_lock); ++ mutex_destroy(&isp_dev->power_lock); ++ return 0; ++} +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_isp.h +@@ -0,0 +1,476 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * stf_isp.h ++ * ++ * StarFive Camera Subsystem - ISP Module ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef STF_ISP_H ++#define STF_ISP_H ++ ++#include ++#include ++ ++#include "stf_video.h" ++ ++#define ISP_RAW_DATA_BITS 12 ++#define SCALER_RATIO_MAX 1 ++#define STF_ISP_REG_OFFSET_MAX 0x0fff ++#define STF_ISP_REG_DELAY_MAX 100 ++ ++/* isp registers */ ++#define ISP_REG_CSI_INPUT_EN_AND_STATUS 0x000 ++#define CSI_SCD_ERR BIT(6) ++#define CSI_ITU656_ERR BIT(4) ++#define CSI_ITU656_F BIT(3) ++#define CSI_SCD_DONE BIT(2) ++#define CSI_BUSY_S BIT(1) ++#define CSI_EN_S BIT(0) ++ ++#define ISP_REG_CSIINTS 0x008 ++#define CSI_INTS(n) ((n) << 16) ++#define CSI_SHA_M(n) ((n) << 0) ++#define CSI_INTS_MASK GENMASK(17, 16) ++ ++#define ISP_REG_CSI_MODULE_CFG 0x010 ++#define CSI_DUMP_EN BIT(19) ++#define CSI_VS_EN BIT(18) ++#define CSI_SC_EN BIT(17) ++#define CSI_OBA_EN BIT(16) ++#define CSI_AWB_EN BIT(7) ++#define CSI_LCCF_EN BIT(6) ++#define CSI_OECFHM_EN BIT(5) ++#define CSI_OECF_EN BIT(4) ++#define CSI_LCBQ_EN BIT(3) ++#define CSI_OBC_EN BIT(2) ++#define CSI_DEC_EN BIT(1) ++#define CSI_DC_EN BIT(0) ++ ++#define ISP_REG_SENSOR 0x014 ++#define DVP_SYNC_POL(n) ((n) << 2) ++#define ITU656_EN(n) ((n) << 1) ++#define IMAGER_SEL(n) ((n) << 0) ++ ++#define ISP_REG_RAW_FORMAT_CFG 0x018 ++#define SMY13(n) ((n) << 14) ++#define SMY12(n) ((n) << 12) ++#define SMY11(n) ((n) << 10) ++#define SMY10(n) ((n) << 8) ++#define SMY3(n) ((n) << 6) ++#define SMY2(n) ((n) << 4) ++#define SMY1(n) ((n) << 2) ++#define SMY0(n) ((n) << 0) ++ ++#define ISP_REG_PIC_CAPTURE_START_CFG 0x01c ++#define VSTART_CAP(n) ((n) << 16) ++#define HSTART_CAP(n) ((n) << 0) ++ ++#define ISP_REG_PIC_CAPTURE_END_CFG 0x020 ++#define VEND_CAP(n) ((n) << 16) ++#define HEND_CAP(n) ((n) << 0) ++ ++#define ISP_REG_DUMP_CFG_0 0x024 ++#define ISP_REG_DUMP_CFG_1 0x028 ++#define DUMP_ID(n) ((n) << 24) ++#define DUMP_SHT(n) ((n) << 20) ++#define DUMP_BURST_LEN(n) ((n) << 16) ++#define DUMP_SD(n) ((n) << 0) ++#define DUMP_BURST_LEN_MASK GENMASK(17, 16) ++#define DUMP_SD_MASK GENMASK(15, 0) ++ ++#define ISP_REG_DEC_CFG 0x030 ++#define DEC_V_KEEP(n) ((n) << 24) ++#define DEC_V_PERIOD(n) ((n) << 16) ++#define DEC_H_KEEP(n) ((n) << 8) ++#define DEC_H_PERIOD(n) ((n) << 0) ++ ++#define ISP_REG_OBC_CFG 0x034 ++#define OBC_W_H(y) ((y) << 4) ++#define OBC_W_W(x) ((x) << 0) ++ ++#define ISP_REG_DC_CFG_1 0x044 ++#define DC_AXI_ID(n) ((n) << 0) ++ ++#define ISP_REG_LCCF_CFG_0 0x050 ++#define Y_DISTANCE(y) ((y) << 16) ++#define X_DISTANCE(x) ((x) << 16) ++ ++#define ISP_REG_LCCF_CFG_1 0x058 ++#define LCCF_MAX_DIS(n) ((n) << 0) ++ ++#define ISP_REG_LCBQ_CFG_0 0x074 ++#define H_LCBQ(y) ((y) << 12) ++#define W_LCBQ(x) ((x) << 8) ++ ++#define ISP_REG_LCBQ_CFG_1 0x07c ++#define Y_COOR(y) ((y) << 16) ++#define X_COOR(x) ((x) << 0) ++ ++#define ISP_REG_OECF_X0_CFG0 0x100 ++#define ISP_REG_OECF_X0_CFG1 0x104 ++#define ISP_REG_OECF_X0_CFG2 0x108 ++#define ISP_REG_OECF_X0_CFG3 0x10c ++#define ISP_REG_OECF_X0_CFG4 0x110 ++#define ISP_REG_OECF_X0_CFG5 0x114 ++#define ISP_REG_OECF_X0_CFG6 0x118 ++#define ISP_REG_OECF_X0_CFG7 0x11c ++ ++#define ISP_REG_OECF_Y3_CFG0 0x1e0 ++#define ISP_REG_OECF_Y3_CFG1 0x1e4 ++#define ISP_REG_OECF_Y3_CFG2 0x1e8 ++#define ISP_REG_OECF_Y3_CFG3 0x1ec ++#define ISP_REG_OECF_Y3_CFG4 0x1f0 ++#define ISP_REG_OECF_Y3_CFG5 0x1f4 ++#define ISP_REG_OECF_Y3_CFG6 0x1f8 ++#define ISP_REG_OECF_Y3_CFG7 0x1fc ++ ++#define ISP_REG_OECF_S0_CFG0 0x200 ++#define ISP_REG_OECF_S3_CFG7 0x27c ++#define OCEF_PAR_H(n) ((n) << 16) ++#define OCEF_PAR_L(n) ((n) << 0) ++ ++#define ISP_REG_AWB_X0_CFG_0 0x280 ++#define ISP_REG_AWB_X0_CFG_1 0x284 ++#define ISP_REG_AWB_X1_CFG_0 0x288 ++#define ISP_REG_AWB_X1_CFG_1 0x28c ++#define ISP_REG_AWB_X2_CFG_0 0x290 ++#define ISP_REG_AWB_X2_CFG_1 0x294 ++#define ISP_REG_AWB_X3_CFG_0 0x298 ++#define ISP_REG_AWB_X3_CFG_1 0x29c ++#define AWB_X_SYMBOL_H(n) ((n) << 16) ++#define AWB_X_SYMBOL_L(n) ((n) << 0) ++ ++#define ISP_REG_AWB_Y0_CFG_0 0x2a0 ++#define ISP_REG_AWB_Y0_CFG_1 0x2a4 ++#define ISP_REG_AWB_Y1_CFG_0 0x2a8 ++#define ISP_REG_AWB_Y1_CFG_1 0x2ac ++#define ISP_REG_AWB_Y2_CFG_0 0x2b0 ++#define ISP_REG_AWB_Y2_CFG_1 0x2b4 ++#define ISP_REG_AWB_Y3_CFG_0 0x2b8 ++#define ISP_REG_AWB_Y3_CFG_1 0x2bc ++#define AWB_Y_SYMBOL_H(n) ((n) << 16) ++#define AWB_Y_SYMBOL_L(n) ((n) << 0) ++ ++#define ISP_REG_AWB_S0_CFG_0 0x2c0 ++#define ISP_REG_AWB_S0_CFG_1 0x2c4 ++#define ISP_REG_AWB_S1_CFG_0 0x2c8 ++#define ISP_REG_AWB_S1_CFG_1 0x2cc ++#define ISP_REG_AWB_S2_CFG_0 0x2d0 ++#define ISP_REG_AWB_S2_CFG_1 0x2d4 ++#define ISP_REG_AWB_S3_CFG_0 0x2d8 ++#define ISP_REG_AWB_S3_CFG_1 0x2dc ++#define AWB_S_SYMBOL_H(n) ((n) << 16) ++#define AWB_S_SYMBOL_L(n) ((n) << 0) ++ ++#define ISP_REG_OBCG_CFG_0 0x2e0 ++#define ISP_REG_OBCG_CFG_1 0x2e4 ++#define ISP_REG_OBCG_CFG_2 0x2e8 ++#define ISP_REG_OBCG_CFG_3 0x2ec ++#define ISP_REG_OBCO_CFG_0 0x2f0 ++#define ISP_REG_OBCO_CFG_1 0x2f4 ++#define ISP_REG_OBCO_CFG_2 0x2f8 ++#define ISP_REG_OBCO_CFG_3 0x2fc ++#define GAIN_D_POINT(x) ((x) << 24) ++#define GAIN_C_POINT(x) ((x) << 16) ++#define GAIN_B_POINT(x) ((x) << 8) ++#define GAIN_A_POINT(x) ((x) << 0) ++#define OFFSET_D_POINT(x) ((x) << 24) ++#define OFFSET_C_POINT(x) ((x) << 16) ++#define OFFSET_B_POINT(x) ((x) << 8) ++#define OFFSET_A_POINT(x) ((x) << 0) ++ ++#define ISP_REG_ISP_CTRL_0 0xa00 ++#define ISPC_SCFEINT BIT(27) ++#define ISPC_VSFWINT BIT(26) ++#define ISPC_VSINT BIT(25) ++#define ISPC_INTS BIT(24) ++#define ISPC_ENUO BIT(20) ++#define ISPC_ENLS BIT(17) ++#define ISPC_ENSS1 BIT(12) ++#define ISPC_ENSS0 BIT(11) ++#define ISPC_RST BIT(1) ++#define ISPC_EN BIT(0) ++#define ISPC_RST_MASK BIT(1) ++ ++#define ISP_REG_ISP_CTRL_1 0xa08 ++#define CTRL_SAT(n) ((n) << 28) ++#define CTRL_DBC BIT(22) ++#define CTRL_CTC BIT(21) ++#define CTRL_YHIST BIT(20) ++#define CTRL_YCURVE BIT(19) ++#define CTRL_CTM BIT(18) ++#define CTRL_BIYUV BIT(17) ++#define CTRL_SCE BIT(8) ++#define CTRL_EE BIT(7) ++#define CTRL_CCE BIT(5) ++#define CTRL_RGE BIT(4) ++#define CTRL_CME BIT(3) ++#define CTRL_AE BIT(2) ++#define CTRL_CE BIT(1) ++#define CTRL_SAT_MASK GENMASK(31, 28) ++ ++#define ISP_REG_PIPELINE_XY_SIZE 0xa0c ++#define H_ACT_CAP(n) ((n) << 16) ++#define W_ACT_CAP(n) ((n) << 0) ++ ++#define ISP_REG_ICTC 0xa10 ++#define GF_MODE(n) ((n) << 30) ++#define MAXGT(n) ((n) << 16) ++#define MINGT(n) ((n) << 0) ++ ++#define ISP_REG_IDBC 0xa14 ++#define BADGT(n) ((n) << 16) ++#define BADXT(n) ((n) << 0) ++ ++#define ISP_REG_ICFAM 0xa1c ++#define CROSS_COV(n) ((n) << 4) ++#define HV_W(n) ((n) << 0) ++ ++#define ISP_REG_CS_GAIN 0xa30 ++#define CMAD(n) ((n) << 16) ++#define CMAB(n) ((n) << 0) ++ ++#define ISP_REG_CS_THRESHOLD 0xa34 ++#define CMD(n) ((n) << 16) ++#define CMB(n) ((n) << 0) ++ ++#define ISP_REG_CS_OFFSET 0xa38 ++#define VOFF(n) ((n) << 16) ++#define UOFF(n) ((n) << 0) ++ ++#define ISP_REG_CS_HUE_F 0xa3c ++#define SIN(n) ((n) << 16) ++#define COS(n) ((n) << 0) ++ ++#define ISP_REG_CS_SCALE 0xa40 ++#define CMSF(n) ((n) << 0) ++ ++#define ISP_REG_IESHD 0xa50 ++#define SHAD_UP_M BIT(1) ++#define SHAD_UP_EN BIT(0) ++ ++#define ISP_REG_YADJ0 0xa54 ++#define YOIR(n) ((n) << 16) ++#define YIMIN(n) ((n) << 0) ++ ++#define ISP_REG_YADJ1 0xa58 ++#define YOMAX(n) ((n) << 16) ++#define YOMIN(n) ((n) << 0) ++ ++#define ISP_REG_Y_PLANE_START_ADDR 0xa80 ++#define ISP_REG_UV_PLANE_START_ADDR 0xa84 ++ ++#define ISP_REG_STRIDE 0xa88 ++#define IMG_STR(n) ((n) << 0) ++ ++#define ISP_REG_ITIIWSR 0xb20 ++#define ITI_HSIZE(n) ((n) << 16) ++#define ITI_WSIZE(n) ((n) << 0) ++ ++#define ISP_REG_ITIDWLSR 0xb24 ++#define ITI_WSTRIDE(n) ((n) << 0) ++ ++#define ISP_REG_ITIPDFR 0xb38 ++#define ITI_PACKAGE_FMT(n) ((n) << 0) ++ ++#define ISP_REG_ITIDRLSR 0xb3C ++#define ITI_STRIDE_L(n) ((n) << 0) ++ ++#define ISP_REG_DNYUV_YSWR0 0xc00 ++#define ISP_REG_DNYUV_YSWR1 0xc04 ++#define ISP_REG_DNYUV_CSWR0 0xc08 ++#define ISP_REG_DNYUV_CSWR1 0xc0c ++#define YUVSW5(n) ((n) << 20) ++#define YUVSW4(n) ((n) << 16) ++#define YUVSW3(n) ((n) << 12) ++#define YUVSW2(n) ((n) << 8) ++#define YUVSW1(n) ((n) << 4) ++#define YUVSW0(n) ((n) << 0) ++ ++#define ISP_REG_DNYUV_YDR0 0xc10 ++#define ISP_REG_DNYUV_YDR1 0xc14 ++#define ISP_REG_DNYUV_YDR2 0xc18 ++#define ISP_REG_DNYUV_CDR0 0xc1c ++#define ISP_REG_DNYUV_CDR1 0xc20 ++#define ISP_REG_DNYUV_CDR2 0xc24 ++#define CURVE_D_H(n) ((n) << 16) ++#define CURVE_D_L(n) ((n) << 0) ++ ++#define ISP_REG_ICAMD_0 0xc40 ++#define DNRM_F(n) ((n) << 16) ++#define ISP_REG_ICAMD_12 0xc70 ++#define ISP_REG_ICAMD_20 0xc90 ++#define ISP_REG_ICAMD_24 0xca0 ++#define ISP_REG_ICAMD_25 0xca4 ++#define CCM_M_DAT(n) ((n) << 0) ++ ++#define ISP_REG_GAMMA_VAL0 0xe00 ++#define ISP_REG_GAMMA_VAL1 0xe04 ++#define ISP_REG_GAMMA_VAL2 0xe08 ++#define ISP_REG_GAMMA_VAL3 0xe0c ++#define ISP_REG_GAMMA_VAL4 0xe10 ++#define ISP_REG_GAMMA_VAL5 0xe14 ++#define ISP_REG_GAMMA_VAL6 0xe18 ++#define ISP_REG_GAMMA_VAL7 0xe1c ++#define ISP_REG_GAMMA_VAL8 0xe20 ++#define ISP_REG_GAMMA_VAL9 0xe24 ++#define ISP_REG_GAMMA_VAL10 0xe28 ++#define ISP_REG_GAMMA_VAL11 0xe2c ++#define ISP_REG_GAMMA_VAL12 0xe30 ++#define ISP_REG_GAMMA_VAL13 0xe34 ++#define ISP_REG_GAMMA_VAL14 0xe38 ++#define GAMMA_S_VAL(n) ((n) << 16) ++#define GAMMA_VAL(n) ((n) << 0) ++ ++#define ISP_REG_R2Y_0 0xe40 ++#define ISP_REG_R2Y_1 0xe44 ++#define ISP_REG_R2Y_2 0xe48 ++#define ISP_REG_R2Y_3 0xe4c ++#define ISP_REG_R2Y_4 0xe50 ++#define ISP_REG_R2Y_5 0xe54 ++#define ISP_REG_R2Y_6 0xe58 ++#define ISP_REG_R2Y_7 0xe5c ++#define ISP_REG_R2Y_8 0xe60 ++#define CSC_M(n) ((n) << 0) ++ ++#define ISP_REG_SHARPEN0 0xe80 ++#define ISP_REG_SHARPEN1 0xe84 ++#define ISP_REG_SHARPEN2 0xe88 ++#define ISP_REG_SHARPEN3 0xe8c ++#define ISP_REG_SHARPEN4 0xe90 ++#define ISP_REG_SHARPEN5 0xe94 ++#define ISP_REG_SHARPEN6 0xe98 ++#define ISP_REG_SHARPEN7 0xe9c ++#define ISP_REG_SHARPEN8 0xea0 ++#define ISP_REG_SHARPEN9 0xea4 ++#define ISP_REG_SHARPEN10 0xea8 ++#define ISP_REG_SHARPEN11 0xeac ++#define ISP_REG_SHARPEN12 0xeb0 ++#define ISP_REG_SHARPEN13 0xeb4 ++#define ISP_REG_SHARPEN14 0xeb8 ++#define S_DELTA(n) ((n) << 16) ++#define S_WEIGHT(n) ((n) << 8) ++ ++#define ISP_REG_SHARPEN_FS0 0xebc ++#define ISP_REG_SHARPEN_FS1 0xec0 ++#define ISP_REG_SHARPEN_FS2 0xec4 ++#define ISP_REG_SHARPEN_FS3 0xec8 ++#define ISP_REG_SHARPEN_FS4 0xecc ++#define ISP_REG_SHARPEN_FS5 0xed0 ++#define S_FACTOR(n) ((n) << 24) ++#define S_SLOPE(n) ((n) << 0) ++ ++#define ISP_REG_SHARPEN_WN 0xed4 ++#define PDIRF(n) ((n) << 28) ++#define NDIRF(n) ((n) << 24) ++#define WSUM(n) ((n) << 0) ++ ++#define ISP_REG_IUVS1 0xed8 ++#define UVDIFF2(n) ((n) << 16) ++#define UVDIFF1(n) ((n) << 0) ++ ++#define ISP_REG_IUVS2 0xedc ++#define UVF(n) ((n) << 24) ++#define UVSLOPE(n) ((n) << 0) ++ ++#define ISP_REG_IUVCKS1 0xee0 ++#define UVCKDIFF2(n) ((n) << 16) ++#define UVCKDIFF1(n) ((n) << 0) ++ ++#define ISP_REG_IUVCKS2 0xee4 ++#define UVCKSLOPE(n) ((n) << 0) ++ ++#define ISP_REG_ISHRPET 0xee8 ++#define TH(n) ((n) << 8) ++#define EN(n) ((n) << 0) ++ ++#define ISP_REG_YCURVE_0 0xf00 ++#define ISP_REG_YCURVE_63 0xffc ++#define L_PARAM(n) ((n) << 0) ++ ++#define IMAGE_MAX_WIDTH 1920 ++#define IMAGE_MAX_HEIGH 1080 ++ ++/* The output line of ISP */ ++enum isp_line_id { ++ STF_ISP_LINE_INVALID = -1, ++ STF_ISP_LINE_SRC = 1, ++ STF_ISP_LINE_MAX = STF_ISP_LINE_SRC ++}; ++ ++/* pad id for media framework */ ++enum isp_pad_id { ++ STF_ISP_PAD_SINK = 0, ++ STF_ISP_PAD_SRC, ++ STF_ISP_PAD_MAX ++}; ++ ++enum { ++ EN_INT_NONE = 0, ++ EN_INT_ISP_DONE = (0x1 << 24), ++ EN_INT_CSI_DONE = (0x1 << 25), ++ EN_INT_SC_DONE = (0x1 << 26), ++ EN_INT_LINE_INT = (0x1 << 27), ++ EN_INT_ALL = (0xF << 24), ++}; ++ ++enum { ++ INTERFACE_DVP = 0, ++ INTERFACE_CSI, ++}; ++ ++struct isp_format { ++ u32 code; ++ u8 bpp; ++}; ++ ++struct isp_format_table { ++ const struct isp_format *fmts; ++ int nfmts; ++}; ++ ++struct regval_t { ++ u32 addr; ++ u32 val; ++ u32 delay_ms; ++}; ++ ++struct reg_table { ++ const struct regval_t *regval; ++ int regval_num; ++}; ++ ++struct stf_isp_crop { ++ struct v4l2_rect rect; ++ u32 bpp; ++}; ++ ++struct stf_isp_dev { ++ enum stf_subdev_type sdev_type; /* This member must be first */ ++ struct stfcamss *stfcamss; ++ struct v4l2_subdev subdev; ++ struct media_pad pads[STF_ISP_PAD_MAX]; ++ struct v4l2_mbus_framefmt fmt[STF_ISP_PAD_MAX]; ++ struct stf_isp_crop rect[STF_ISP_PAD_MAX]; ++ const struct isp_format_table *formats; ++ unsigned int nformats; ++ struct mutex power_lock; /* serialize power control*/ ++ int power_count; ++ struct mutex stream_lock; /* serialize stream control */ ++ int stream_count; ++}; ++ ++int stf_isp_clk_enable(struct stf_isp_dev *isp_dev); ++int stf_isp_clk_disable(struct stf_isp_dev *isp_dev); ++int stf_isp_reset(struct stf_isp_dev *isp_dev); ++void stf_isp_init_cfg(struct stf_isp_dev *isp_dev); ++void stf_isp_settings(struct stf_isp_dev *isp_dev, ++ struct stf_isp_crop *crop_array, u32 mcode); ++void stf_isp_stream_set(struct stf_isp_dev *isp_dev); ++int stf_isp_subdev_init(struct stfcamss *stfcamss); ++int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev); ++int stf_isp_unregister(struct stf_isp_dev *isp_dev); ++ ++#endif /* STF_ISP_H */ +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_isp_hw_ops.c +@@ -0,0 +1,452 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * stf_isp_hw_ops.c ++ * ++ * Register interface file for StarFive ISP driver ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ * ++ */ ++ ++#include "stf_camss.h" ++ ++static void stf_isp_config_obc(struct stfcamss *stfcamss) ++{ ++ u32 reg_val, reg_add; ++ ++ stf_isp_reg_write(stfcamss, ISP_REG_OBC_CFG, OBC_W_H(11) | OBC_W_W(11)); ++ ++ reg_val = GAIN_D_POINT(0x40) | GAIN_C_POINT(0x40) | ++ GAIN_B_POINT(0x40) | GAIN_A_POINT(0x40); ++ for (reg_add = ISP_REG_OBCG_CFG_0; reg_add <= ISP_REG_OBCG_CFG_3;) { ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ } ++ ++ reg_val = OFFSET_D_POINT(0) | OFFSET_C_POINT(0) | ++ OFFSET_B_POINT(0) | OFFSET_A_POINT(0); ++ for (reg_add = ISP_REG_OBCO_CFG_0; reg_add <= ISP_REG_OBCO_CFG_3;) { ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ } ++} ++ ++static void stf_isp_config_oecf(struct stfcamss *stfcamss) ++{ ++ u32 reg_add, par_val; ++ u16 par_h, par_l; ++ ++ par_h = 0x10; par_l = 0; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG0; reg_add <= ISP_REG_OECF_Y3_CFG0;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x40; par_l = 0x20; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG1; reg_add <= ISP_REG_OECF_Y3_CFG1;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x80; par_l = 0x60; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG2; reg_add <= ISP_REG_OECF_Y3_CFG2;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0xc0; par_l = 0xa0; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG3; reg_add <= ISP_REG_OECF_Y3_CFG3;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x100; par_l = 0xe0; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG4; reg_add <= ISP_REG_OECF_Y3_CFG4;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x200; par_l = 0x180; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG5; reg_add <= ISP_REG_OECF_Y3_CFG5;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x300; par_l = 0x280; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG6; reg_add <= ISP_REG_OECF_Y3_CFG6;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x3fe; par_l = 0x380; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_X0_CFG7; reg_add <= ISP_REG_OECF_Y3_CFG7;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 0x20; ++ } ++ ++ par_h = 0x80; par_l = 0x80; ++ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l); ++ for (reg_add = ISP_REG_OECF_S0_CFG0; reg_add <= ISP_REG_OECF_S3_CFG7;) { ++ stf_isp_reg_write(stfcamss, reg_add, par_val); ++ reg_add += 4; ++ } ++} ++ ++static void stf_isp_config_awb(struct stfcamss *stfcamss) ++{ ++ u32 reg_val, reg_add; ++ u16 symbol_h, symbol_l; ++ ++ symbol_h = 0x0; symbol_l = 0x0; ++ reg_val = AWB_X_SYMBOL_H(symbol_h) | AWB_X_SYMBOL_L(symbol_l); ++ ++ for (reg_add = ISP_REG_AWB_X0_CFG_0; reg_add <= ISP_REG_AWB_X3_CFG_1;) { ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ } ++ ++ symbol_h = 0x0, symbol_l = 0x0; ++ reg_val = AWB_Y_SYMBOL_H(symbol_h) | AWB_Y_SYMBOL_L(symbol_l); ++ ++ for (reg_add = ISP_REG_AWB_Y0_CFG_0; reg_add <= ISP_REG_AWB_Y3_CFG_1;) { ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ } ++ ++ symbol_h = 0x80, symbol_l = 0x80; ++ reg_val = AWB_S_SYMBOL_H(symbol_h) | AWB_S_SYMBOL_L(symbol_l); ++ ++ for (reg_add = ISP_REG_AWB_S0_CFG_0; reg_add <= ISP_REG_AWB_S3_CFG_1;) { ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ } ++} ++ ++static void stf_isp_config_grgb(struct stfcamss *stfcamss) ++{ ++ stf_isp_reg_write(stfcamss, ISP_REG_ICTC, ++ GF_MODE(1) | MAXGT(0x140) | MINGT(0x40)); ++ stf_isp_reg_write(stfcamss, ISP_REG_IDBC, BADGT(0x200) | BADXT(0x200)); ++} ++ ++static void stf_isp_config_cfa(struct stfcamss *stfcamss) ++{ ++ stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG, ++ SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | SMY3(2) | ++ SMY2(3) | SMY1(2) | SMY0(3)); ++ stf_isp_reg_write(stfcamss, ISP_REG_ICFAM, CROSS_COV(3) | HV_W(2)); ++} ++ ++static void stf_isp_config_ccm(struct stfcamss *stfcamss) ++{ ++ u32 reg_add; ++ ++ stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_0, DNRM_F(6) | CCM_M_DAT(0)); ++ ++ for (reg_add = ISP_REG_ICAMD_12; reg_add <= ISP_REG_ICAMD_20;) { ++ stf_isp_reg_write(stfcamss, reg_add, CCM_M_DAT(0x80)); ++ reg_add += 0x10; ++ } ++ ++ stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_24, CCM_M_DAT(0x700)); ++ stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_25, CCM_M_DAT(0x200)); ++} ++ ++static void stf_isp_config_gamma(struct stfcamss *stfcamss) ++{ ++ u32 reg_val, reg_add; ++ u16 gamma_slope_v, gamma_v; ++ ++ gamma_slope_v = 0x2400; gamma_v = 0x0; ++ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); ++ stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL0, reg_val); ++ ++ gamma_slope_v = 0x800; gamma_v = 0x20; ++ for (reg_add = ISP_REG_GAMMA_VAL1; reg_add <= ISP_REG_GAMMA_VAL7;) { ++ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ gamma_v += 0x20; ++ } ++ ++ gamma_v = 0x100; ++ for (reg_add = ISP_REG_GAMMA_VAL8; reg_add <= ISP_REG_GAMMA_VAL13;) { ++ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); ++ stf_isp_reg_write(stfcamss, reg_add, reg_val); ++ reg_add += 4; ++ gamma_v += 0x80; ++ } ++ ++ gamma_v = 0x3fe; ++ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v); ++ stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL14, reg_val); ++} ++ ++static void stf_isp_config_r2y(struct stfcamss *stfcamss) ++{ ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_0, CSC_M(0x4C)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_1, CSC_M(0x97)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_2, CSC_M(0x1d)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_3, CSC_M(0x1d5)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_4, CSC_M(0x1ac)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_5, CSC_M(0x80)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_6, CSC_M(0x80)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_7, CSC_M(0x194)); ++ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_8, CSC_M(0x1ec)); ++} ++ ++static void stf_isp_config_y_curve(struct stfcamss *stfcamss) ++{ ++ u32 reg_add; ++ u16 y_curve; ++ ++ y_curve = 0x0; ++ for (reg_add = ISP_REG_YCURVE_0; reg_add <= ISP_REG_YCURVE_63;) { ++ stf_isp_reg_write(stfcamss, reg_add, y_curve); ++ reg_add += 4; ++ y_curve += 0x10; ++ } ++} ++ ++static void stf_isp_config_sharpen(struct stfcamss *sc) ++{ ++ u32 reg_add; ++ ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN0, S_DELTA(0x7) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN1, S_DELTA(0x18) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN2, S_DELTA(0x80) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN3, S_DELTA(0x100) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN4, S_DELTA(0x10) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN5, S_DELTA(0x60) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN6, S_DELTA(0x100) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN7, S_DELTA(0x190) | S_WEIGHT(0xf)); ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN8, S_DELTA(0x0) | S_WEIGHT(0xf)); ++ ++ for (reg_add = ISP_REG_SHARPEN9; reg_add <= ISP_REG_SHARPEN14;) { ++ stf_isp_reg_write(sc, reg_add, S_WEIGHT(0xf)); ++ reg_add += 4; ++ } ++ ++ for (reg_add = ISP_REG_SHARPEN_FS0; reg_add <= ISP_REG_SHARPEN_FS5;) { ++ stf_isp_reg_write(sc, reg_add, S_FACTOR(0x10) | S_SLOPE(0x0)); ++ reg_add += 4; ++ } ++ ++ stf_isp_reg_write(sc, ISP_REG_SHARPEN_WN, ++ PDIRF(0x8) | NDIRF(0x8) | WSUM(0xd7c)); ++ stf_isp_reg_write(sc, ISP_REG_IUVS1, UVDIFF2(0xC0) | UVDIFF1(0x40)); ++ stf_isp_reg_write(sc, ISP_REG_IUVS2, UVF(0xff) | UVSLOPE(0x0)); ++ stf_isp_reg_write(sc, ISP_REG_IUVCKS1, ++ UVCKDIFF2(0xa0) | UVCKDIFF1(0x40)); ++} ++ ++static void stf_isp_config_dnyuv(struct stfcamss *stfcamss) ++{ ++ u32 reg_val; ++ ++ reg_val = YUVSW5(7) | YUVSW4(7) | YUVSW3(7) | YUVSW2(7) | ++ YUVSW1(7) | YUVSW0(7); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR0, reg_val); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR0, reg_val); ++ ++ reg_val = YUVSW3(7) | YUVSW2(7) | YUVSW1(7) | YUVSW0(7); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR1, reg_val); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR1, reg_val); ++ ++ reg_val = CURVE_D_H(0x60) | CURVE_D_L(0x40); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR0, reg_val); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR0, reg_val); ++ ++ reg_val = CURVE_D_H(0xd8) | CURVE_D_L(0x90); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR1, reg_val); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR1, reg_val); ++ ++ reg_val = CURVE_D_H(0x1e6) | CURVE_D_L(0x144); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR2, reg_val); ++ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR2, reg_val); ++} ++ ++static void stf_isp_config_sat(struct stfcamss *stfcamss) ++{ ++ stf_isp_reg_write(stfcamss, ISP_REG_CS_GAIN, CMAD(0x0) | CMAB(0x100)); ++ stf_isp_reg_write(stfcamss, ISP_REG_CS_THRESHOLD, CMD(0x1f) | CMB(0x1)); ++ stf_isp_reg_write(stfcamss, ISP_REG_CS_OFFSET, VOFF(0x0) | UOFF(0x0)); ++ stf_isp_reg_write(stfcamss, ISP_REG_CS_HUE_F, SIN(0x0) | COS(0x100)); ++ stf_isp_reg_write(stfcamss, ISP_REG_CS_SCALE, CMSF(0x8)); ++ stf_isp_reg_write(stfcamss, ISP_REG_YADJ0, YOIR(0x401) | YIMIN(0x1)); ++ stf_isp_reg_write(stfcamss, ISP_REG_YADJ1, YOMAX(0x3ff) | YOMIN(0x1)); ++} ++ ++int stf_isp_clk_enable(struct stf_isp_dev *isp_dev) ++{ ++ struct stfcamss *stfcamss = isp_dev->stfcamss; ++ ++ clk_prepare_enable(stfcamss->sys_clk[STF_CLK_WRAPPER_CLK_C].clk); ++ reset_control_deassert(stfcamss->sys_rst[STF_RST_WRAPPER_C].rstc); ++ reset_control_deassert(stfcamss->sys_rst[STF_RST_WRAPPER_P].rstc); ++ ++ return 0; ++} ++ ++int stf_isp_clk_disable(struct stf_isp_dev *isp_dev) ++{ ++ struct stfcamss *stfcamss = isp_dev->stfcamss; ++ ++ reset_control_assert(stfcamss->sys_rst[STF_RST_WRAPPER_C].rstc); ++ reset_control_assert(stfcamss->sys_rst[STF_RST_WRAPPER_P].rstc); ++ clk_disable_unprepare(stfcamss->sys_clk[STF_CLK_WRAPPER_CLK_C].clk); ++ ++ return 0; ++} ++ ++int stf_isp_reset(struct stf_isp_dev *isp_dev) ++{ ++ stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0, ++ ISPC_RST_MASK, ISPC_RST); ++ stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0, ++ ISPC_RST_MASK, 0); ++ ++ return 0; ++} ++ ++void stf_isp_init_cfg(struct stf_isp_dev *isp_dev) ++{ ++ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DC_CFG_1, DC_AXI_ID(0x0)); ++ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DEC_CFG, ++ DEC_V_KEEP(0x0) | ++ DEC_V_PERIOD(0x0) | ++ DEC_H_KEEP(0x0) | ++ DEC_H_PERIOD(0x0)); ++ ++ stf_isp_config_obc(isp_dev->stfcamss); ++ stf_isp_config_oecf(isp_dev->stfcamss); ++ stf_isp_config_awb(isp_dev->stfcamss); ++ stf_isp_config_grgb(isp_dev->stfcamss); ++ stf_isp_config_cfa(isp_dev->stfcamss); ++ stf_isp_config_ccm(isp_dev->stfcamss); ++ stf_isp_config_gamma(isp_dev->stfcamss); ++ stf_isp_config_r2y(isp_dev->stfcamss); ++ stf_isp_config_y_curve(isp_dev->stfcamss); ++ stf_isp_config_sharpen(isp_dev->stfcamss); ++ stf_isp_config_dnyuv(isp_dev->stfcamss); ++ stf_isp_config_sat(isp_dev->stfcamss); ++ ++ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_CSI_MODULE_CFG, ++ CSI_DUMP_EN | CSI_SC_EN | CSI_AWB_EN | ++ CSI_LCCF_EN | CSI_OECF_EN | CSI_OBC_EN | CSI_DEC_EN); ++ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_ISP_CTRL_1, ++ CTRL_SAT(1) | CTRL_DBC | CTRL_CTC | CTRL_YHIST | ++ CTRL_YCURVE | CTRL_BIYUV | CTRL_SCE | CTRL_EE | ++ CTRL_CCE | CTRL_RGE | CTRL_CME | CTRL_AE | CTRL_CE); ++} ++ ++static void stf_isp_config_crop(struct stfcamss *stfcamss, ++ struct stf_isp_crop *crop) ++{ ++ struct v4l2_rect *rect = &crop[STF_ISP_PAD_SRC].rect; ++ u32 bpp = crop[STF_ISP_PAD_SRC].bpp; ++ u32 val; ++ ++ val = VSTART_CAP(rect->top) | HSTART_CAP(rect->left); ++ stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_START_CFG, val); ++ ++ val = VEND_CAP(rect->height + rect->top - 1) | ++ HEND_CAP(rect->width + rect->left - 1); ++ stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_END_CFG, val); ++ ++ val = H_ACT_CAP(rect->height) | W_ACT_CAP(rect->width); ++ stf_isp_reg_write(stfcamss, ISP_REG_PIPELINE_XY_SIZE, val); ++ ++ val = ALIGN(rect->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8); ++ stf_isp_reg_write(stfcamss, ISP_REG_STRIDE, val); ++} ++ ++static void stf_isp_config_raw_fmt(struct stfcamss *stfcamss, u32 mcode) ++{ ++ u32 val, val1; ++ ++ switch (mcode) { ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ /* 3 2 3 2 1 0 1 0 B Gb B Gb Gr R Gr R */ ++ val = SMY13(3) | SMY12(2) | SMY11(3) | SMY10(2) | ++ SMY3(1) | SMY2(0) | SMY1(1) | SMY0(0); ++ val1 = CTRL_SAT(0x0); ++ break; ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ /* 2 3 2 3 0 1 0 1, Gb B Gb B R Gr R Gr */ ++ val = SMY13(2) | SMY12(3) | SMY11(2) | SMY10(3) | ++ SMY3(0) | SMY2(1) | SMY1(0) | SMY0(1); ++ val1 = CTRL_SAT(0x2); ++ break; ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ /* 1 0 1 0 3 2 3 2, Gr R Gr R B Gb B Gb */ ++ val = SMY13(1) | SMY12(0) | SMY11(1) | SMY10(0) | ++ SMY3(3) | SMY2(2) | SMY1(3) | SMY0(2); ++ val1 = CTRL_SAT(0x3); ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ /* 0 1 0 1 2 3 2 3 R Gr R Gr Gb B Gb B */ ++ val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | ++ SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3); ++ val1 = CTRL_SAT(0x1); ++ break; ++ default: ++ val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | ++ SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3); ++ val1 = CTRL_SAT(0x1); ++ break; ++ } ++ stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG, val); ++ stf_isp_reg_set_bit(stfcamss, ISP_REG_ISP_CTRL_1, CTRL_SAT_MASK, val1); ++} ++ ++void stf_isp_settings(struct stf_isp_dev *isp_dev, ++ struct stf_isp_crop *crop, u32 mcode) ++{ ++ struct stfcamss *stfcamss = isp_dev->stfcamss; ++ ++ stf_isp_config_crop(stfcamss, crop); ++ stf_isp_config_raw_fmt(stfcamss, mcode); ++ ++ stf_isp_reg_set_bit(stfcamss, ISP_REG_DUMP_CFG_1, ++ DUMP_BURST_LEN_MASK | DUMP_SD_MASK, ++ DUMP_BURST_LEN(3)); ++ ++ stf_isp_reg_write(stfcamss, ISP_REG_ITIIWSR, ++ ITI_HSIZE(IMAGE_MAX_HEIGH) | ++ ITI_WSIZE(IMAGE_MAX_WIDTH)); ++ stf_isp_reg_write(stfcamss, ISP_REG_ITIDWLSR, ITI_WSTRIDE(0x960)); ++ stf_isp_reg_write(stfcamss, ISP_REG_ITIDRLSR, ITI_STRIDE_L(0x960)); ++ stf_isp_reg_write(stfcamss, ISP_REG_SENSOR, 0x1); ++} ++ ++void stf_isp_stream_set(struct stf_isp_dev *isp_dev) ++{ ++ struct stfcamss *stfcamss = isp_dev->stfcamss; ++ ++ stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0, ++ ISPC_ENUO | ISPC_ENLS | ISPC_RST, 10); ++ stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0, ++ ISPC_ENUO | ISPC_ENLS, 10); ++ stf_isp_reg_write(stfcamss, ISP_REG_IESHD, SHAD_UP_M); ++ stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0, ++ ISPC_ENUO | ISPC_ENLS | ISPC_EN, 10); ++ stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS, ++ CSI_INTS(1) | CSI_SHA_M(4), 10); ++ stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS, ++ CSI_INTS(2) | CSI_SHA_M(4), 10); ++ stf_isp_reg_write_delay(stfcamss, ISP_REG_CSI_INPUT_EN_AND_STATUS, ++ CSI_EN_S, 10); ++} diff --git a/target/linux/starfive/patches-6.1/0086-media-starfive-Add-VIN-driver.patch b/target/linux/starfive/patches-6.1/0086-media-starfive-Add-VIN-driver.patch new file mode 100644 index 0000000000..2ab822ae96 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0086-media-starfive-Add-VIN-driver.patch @@ -0,0 +1,1694 @@ +From 030f0312433a85899fab4dccada5b2cbceb3bad5 Mon Sep 17 00:00:00 2001 +From: Jack Zhu +Date: Fri, 12 May 2023 18:28:44 +0800 +Subject: [PATCH 086/122] media: starfive: Add VIN driver + +Add Video In Controller driver for StarFive Camera Subsystem. + +Signed-off-by: Jack Zhu +--- + drivers/media/platform/starfive/Makefile | 4 +- + drivers/media/platform/starfive/stf_camss.c | 39 +- + drivers/media/platform/starfive/stf_camss.h | 2 + + drivers/media/platform/starfive/stf_vin.c | 1134 +++++++++++++++++ + drivers/media/platform/starfive/stf_vin.h | 180 +++ + .../media/platform/starfive/stf_vin_hw_ops.c | 241 ++++ + 6 files changed, 1598 insertions(+), 2 deletions(-) + create mode 100644 drivers/media/platform/starfive/stf_vin.c + create mode 100644 drivers/media/platform/starfive/stf_vin.h + create mode 100644 drivers/media/platform/starfive/stf_vin_hw_ops.c + +--- a/drivers/media/platform/starfive/Makefile ++++ b/drivers/media/platform/starfive/Makefile +@@ -7,6 +7,8 @@ starfive-camss-objs += \ + stf_camss.o \ + stf_isp.o \ + stf_isp_hw_ops.o \ +- stf_video.o ++ stf_video.o \ ++ stf_vin.o \ ++ stf_vin_hw_ops.o + + obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \ +--- a/drivers/media/platform/starfive/stf_camss.c ++++ b/drivers/media/platform/starfive/stf_camss.c +@@ -142,27 +142,61 @@ static int stfcamss_init_subdevices(stru + return ret; + } + ++ ret = stf_vin_subdev_init(stfcamss); ++ if (ret < 0) { ++ dev_err(stfcamss->dev, "Failed to init vin subdev: %d\n", ret); ++ return ret; ++ } + return ret; + } + + static int stfcamss_register_subdevices(struct stfcamss *stfcamss) + { + int ret; ++ struct stf_vin_dev *vin_dev = &stfcamss->vin_dev; + struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; + + ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev); + if (ret < 0) { + dev_err(stfcamss->dev, + "Failed to register stf isp%d entity: %d\n", 0, ret); +- return ret; ++ goto err_reg_isp; ++ } ++ ++ ret = stf_vin_register(vin_dev, &stfcamss->v4l2_dev); ++ if (ret < 0) { ++ dev_err(stfcamss->dev, ++ "Failed to register vin entity: %d\n", ret); ++ goto err_reg_vin; + } + ++ ret = media_create_pad_link(&isp_dev->subdev.entity, ++ STF_ISP_PAD_SRC, ++ &vin_dev->line[VIN_LINE_ISP].subdev.entity, ++ STF_VIN_PAD_SINK, ++ 0); ++ if (ret < 0) { ++ dev_err(stfcamss->dev, ++ "Failed to link %s->%s entities: %d\n", ++ isp_dev->subdev.entity.name, ++ vin_dev->line[VIN_LINE_ISP].subdev.entity.name, ret); ++ goto err_link; ++ } ++ ++ return ret; ++ ++err_link: ++ stf_vin_unregister(&stfcamss->vin_dev); ++err_reg_vin: ++ stf_isp_unregister(&stfcamss->isp_dev); ++err_reg_isp: + return ret; + } + + static void stfcamss_unregister_subdevices(struct stfcamss *stfcamss) + { + stf_isp_unregister(&stfcamss->isp_dev); ++ stf_vin_unregister(&stfcamss->vin_dev); + } + + static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async, +@@ -175,11 +209,14 @@ static int stfcamss_subdev_notifier_boun + container_of(asd, struct stfcamss_async_subdev, asd); + enum port_num port = csd->port; + struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; ++ struct stf_vin_dev *vin_dev = &stfcamss->vin_dev; + struct host_data *host_data = &stfcamss->host_data; + struct media_entity *source; + int i, j; + + if (port == PORT_NUMBER_CSI2RX) { ++ host_data->host_entity[0] = ++ &vin_dev->line[VIN_LINE_WR].subdev.entity; + host_data->host_entity[1] = &isp_dev->subdev.entity; + } else if (port == PORT_NUMBER_DVP_SENSOR) { + dev_err(stfcamss->dev, "Not support DVP sensor\n"); +--- a/drivers/media/platform/starfive/stf_camss.h ++++ b/drivers/media/platform/starfive/stf_camss.h +@@ -17,6 +17,7 @@ + + #include "stf_common.h" + #include "stf_isp.h" ++#include "stf_vin.h" + + #define DRV_NAME "starfive-camss" + #define STF_DVP_NAME "stf_dvp" +@@ -72,6 +73,7 @@ struct stfcamss { + struct media_device media_dev; + struct media_pipeline pipe; + struct device *dev; ++ struct stf_vin_dev vin_dev; + struct stf_isp_dev isp_dev; + struct v4l2_async_notifier notifier; + struct host_data host_data; +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_vin.c +@@ -0,0 +1,1134 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * stf_vin.c ++ * ++ * StarFive Camera Subsystem - VIN Module ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++#include ++ ++#include "stf_camss.h" ++ ++#define vin_line_array(ptr_line) \ ++ ((const struct vin_line (*)[]) &(ptr_line)[-((ptr_line)->id)]) ++ ++#define line_to_vin_dev(ptr_line) \ ++ container_of(vin_line_array(ptr_line), struct stf_vin_dev, line) ++ ++#define VIN_FRAME_DROP_MAX_VAL 90 ++#define VIN_FRAME_DROP_MIN_VAL 4 ++#define VIN_FRAME_PER_SEC_MAX_VAL 90 ++ ++/* ISP ctrl need 1 sec to let frames become stable. */ ++#define VIN_FRAME_DROP_SEC_FOR_ISP_CTRL 1 ++ ++static const struct vin_format vin_formats_wr[] = { ++ { MEDIA_BUS_FMT_SRGGB10_1X10, 10}, ++ { MEDIA_BUS_FMT_SGRBG10_1X10, 10}, ++ { MEDIA_BUS_FMT_SGBRG10_1X10, 10}, ++ { MEDIA_BUS_FMT_SBGGR10_1X10, 10}, ++}; ++ ++static const struct vin_format vin_formats_uo[] = { ++ { MEDIA_BUS_FMT_Y12_1X12, 8}, ++}; ++ ++static const struct vin_format_table vin_formats_table[] = { ++ /* VIN_LINE_WR */ ++ { vin_formats_wr, ARRAY_SIZE(vin_formats_wr) }, ++ /* VIN_LINE_ISP */ ++ { vin_formats_uo, ARRAY_SIZE(vin_formats_uo) }, ++}; ++ ++static void vin_buffer_done(struct vin_line *line); ++static void vin_change_buffer(struct vin_line *line); ++static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output); ++static void vin_output_init_addrs(struct vin_line *line); ++static void vin_init_outputs(struct vin_line *line); ++static struct v4l2_mbus_framefmt * ++__vin_get_format(struct vin_line *line, ++ struct v4l2_subdev_state *state, ++ unsigned int pad, ++ enum v4l2_subdev_format_whence which); ++ ++static char *vin_get_line_subdevname(int line_id) ++{ ++ char *name = NULL; ++ ++ switch (line_id) { ++ case VIN_LINE_WR: ++ name = "wr"; ++ break; ++ case VIN_LINE_ISP: ++ name = "isp0"; ++ break; ++ default: ++ name = "unknown"; ++ break; ++ } ++ return name; ++} ++ ++static enum isp_line_id vin_map_isp_line(enum vin_line_id line) ++{ ++ enum isp_line_id line_id; ++ ++ if (line > VIN_LINE_WR && line < VIN_LINE_MAX) ++ line_id = STF_ISP_LINE_SRC; ++ else ++ line_id = STF_ISP_LINE_INVALID; ++ ++ return line_id; ++} ++ ++enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line, enum isp_pad_id def) ++{ ++ enum isp_pad_id pad_id; ++ ++ if (line == VIN_LINE_WR) ++ pad_id = STF_ISP_PAD_SINK; ++ else if ((line > VIN_LINE_WR) && (line < VIN_LINE_MAX)) ++ pad_id = (enum isp_pad_id)vin_map_isp_line(line); ++ else ++ pad_id = def; ++ ++ return pad_id; ++} ++ ++int stf_vin_subdev_init(struct stfcamss *stfcamss) ++{ ++ struct device *dev = stfcamss->dev; ++ struct stf_vin_dev *vin_dev = &stfcamss->vin_dev; ++ int i, ret = 0; ++ ++ vin_dev->stfcamss = stfcamss; ++ ++ vin_dev->isr_ops = devm_kzalloc(dev, sizeof(*vin_dev->isr_ops), ++ GFP_KERNEL); ++ if (!vin_dev->isr_ops) ++ return -ENOMEM; ++ vin_dev->isr_ops->isr_buffer_done = vin_buffer_done; ++ vin_dev->isr_ops->isr_change_buffer = vin_change_buffer; ++ ++ atomic_set(&vin_dev->ref_count, 0); ++ ++ ret = devm_request_irq(dev, ++ stfcamss->irq[STF_IRQ_VINWR], ++ stf_vin_wr_irq_handler, ++ 0, "vin_axiwr_irq", vin_dev); ++ if (ret) { ++ dev_err(dev, "Failed to request irq\n"); ++ goto out; ++ } ++ ++ ret = devm_request_irq(dev, ++ stfcamss->irq[STF_IRQ_ISP], ++ stf_vin_isp_irq_handler, ++ 0, "vin_isp_irq", vin_dev); ++ if (ret) { ++ dev_err(dev, "Failed to request isp irq\n"); ++ goto out; ++ } ++ ++ ret = devm_request_irq(dev, ++ stfcamss->irq[STF_IRQ_ISPCSIL], ++ stf_vin_isp_irq_csiline_handler, ++ 0, "vin_isp_irq_csiline", vin_dev); ++ if (ret) { ++ dev_err(dev, "failed to request isp irq csiline\n"); ++ goto out; ++ } ++ ++ mutex_init(&vin_dev->power_lock); ++ vin_dev->power_count = 0; ++ ++ for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++) { ++ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[i]; ++ ++ mutex_init(&dummy_buffer->stream_lock); ++ dummy_buffer->nums = ++ i == 0 ? VIN_DUMMY_BUFFER_NUMS : ISP_DUMMY_BUFFER_NUMS; ++ dummy_buffer->stream_count = 0; ++ dummy_buffer->buffer = ++ devm_kzalloc(dev, ++ dummy_buffer->nums * sizeof(struct vin_dummy_buffer), ++ GFP_KERNEL); ++ atomic_set(&dummy_buffer->frame_skip, 0); ++ } ++ ++ for (i = VIN_LINE_WR; i < STF_ISP_LINE_MAX + 1; i++) { ++ struct vin_line *l = &vin_dev->line[i]; ++ ++ l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ l->video_out.stfcamss = stfcamss; ++ l->id = i; ++ l->sdev_type = STF_SUBDEV_TYPE_VIN; ++ l->formats = vin_formats_table[i].fmts; ++ l->nformats = vin_formats_table[i].nfmts; ++ spin_lock_init(&l->output_lock); ++ ++ mutex_init(&l->stream_lock); ++ l->stream_count = 0; ++ mutex_init(&l->power_lock); ++ l->power_count = 0; ++ } ++ ++ return 0; ++out: ++ return ret; ++} ++ ++static enum link vin_get_link(struct media_entity *entity) ++{ ++ struct v4l2_subdev *subdev; ++ struct media_pad *pad; ++ bool isp = false; ++ ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ return LINK_ERROR; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ return LINK_ERROR; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ if (!strncmp(subdev->name, STF_CSI_NAME, ++ strlen(STF_CSI_NAME))) { ++ if (isp) ++ return LINK_CSI_TO_ISP; ++ else ++ return LINK_CSI_TO_WR; ++ } else if (!strncmp(subdev->name, STF_DVP_NAME, ++ strlen(STF_DVP_NAME))) { ++ if (isp) ++ return LINK_DVP_TO_ISP; ++ else ++ return LINK_DVP_TO_WR; ++ } else if (!strncmp(subdev->name, STF_ISP_NAME, ++ strlen(STF_ISP_NAME))) { ++ isp = true; ++ } else { ++ return LINK_ERROR; ++ } ++ } ++} ++ ++static int vin_set_power(struct v4l2_subdev *sd, int on) ++{ ++ struct vin_line *line = v4l2_get_subdevdata(sd); ++ struct stf_vin_dev *vin_dev = line_to_vin_dev(line); ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ enum link link; ++ ++ mutex_lock(&line->power_lock); ++ if (on) { ++ if (line->power_count == 0) ++ vin_init_outputs(line); ++ line->power_count++; ++ } else { ++ if (line->power_count == 0) { ++ dev_err(stfcamss->dev, ++ "line power off on power_count = 0\n"); ++ goto exit_line; ++ } ++ line->power_count--; ++ } ++exit_line: ++ mutex_unlock(&line->power_lock); ++ ++ mutex_lock(&vin_dev->power_lock); ++ link = vin_get_link(&sd->entity); ++ if (link == LINK_ERROR) ++ goto exit; ++ ++ if (on) { ++ if (vin_dev->power_count == 0) { ++ pm_runtime_get_sync(stfcamss->dev); ++ stf_vin_clk_enable(vin_dev, link); ++ } ++ vin_dev->power_count++; ++ } else { ++ if (vin_dev->power_count == 0) { ++ dev_err(stfcamss->dev, ++ "vin_dev power off on power_count=0\n"); ++ goto exit; ++ } ++ if (vin_dev->power_count == 1) { ++ stf_vin_clk_disable(vin_dev, link); ++ pm_runtime_put_sync(stfcamss->dev); ++ } ++ vin_dev->power_count--; ++ } ++exit: ++ ++ mutex_unlock(&vin_dev->power_lock); ++ ++ return 0; ++} ++ ++static int vin_enable_output(struct vin_line *line) ++{ ++ struct vin_output *output = &line->output; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&line->output_lock, flags); ++ ++ output->state = VIN_OUTPUT_IDLE; ++ ++ output->buf[0] = vin_buf_get_pending(output); ++ ++ if (!output->buf[0] && output->buf[1]) { ++ output->buf[0] = output->buf[1]; ++ output->buf[1] = NULL; ++ } ++ ++ if (output->buf[0]) ++ output->state = VIN_OUTPUT_SINGLE; ++ ++ output->sequence = 0; ++ ++ vin_output_init_addrs(line); ++ spin_unlock_irqrestore(&line->output_lock, flags); ++ return 0; ++} ++ ++static int vin_disable_output(struct vin_line *line) ++{ ++ struct vin_output *output = &line->output; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&line->output_lock, flags); ++ ++ output->state = VIN_OUTPUT_OFF; ++ ++ spin_unlock_irqrestore(&line->output_lock, flags); ++ return 0; ++} ++ ++static u32 vin_line_to_dummy_module(struct vin_line *line) ++{ ++ u32 dummy_module = 0; ++ ++ switch (line->id) { ++ case VIN_LINE_WR: ++ dummy_module = STF_DUMMY_VIN; ++ break; ++ case VIN_LINE_ISP: ++ dummy_module = STF_DUMMY_ISP; ++ break; ++ default: ++ dummy_module = STF_DUMMY_VIN; ++ break; ++ } ++ ++ return dummy_module; ++} ++ ++static int vin_alloc_dummy_buffer(struct stf_vin_dev *vin_dev, ++ struct v4l2_mbus_framefmt *fmt, ++ int dummy_module) ++{ ++ struct device *dev = vin_dev->stfcamss->dev; ++ struct dummy_buffer *dummy_buffer = ++ &vin_dev->dummy_buffer[dummy_module]; ++ struct vin_dummy_buffer *buffer = NULL; ++ int ret = 0, i; ++ u32 aligns; ++ ++ for (i = 0; i < dummy_buffer->nums; i++) { ++ buffer = &vin_dev->dummy_buffer[dummy_module].buffer[i]; ++ buffer->width = fmt->width; ++ buffer->height = fmt->height; ++ buffer->mcode = fmt->code; ++ if (i == STF_VIN_PAD_SINK) { ++ aligns = ALIGN(fmt->width * 4, ++ STFCAMSS_FRAME_WIDTH_ALIGN_8); ++ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height); ++ } else if (i == STF_ISP_PAD_SRC) { ++ aligns = ALIGN(fmt->width, ++ STFCAMSS_FRAME_WIDTH_ALIGN_8); ++ buffer->buffer_size = ++ PAGE_ALIGN(aligns * fmt->height * 3 / 2); ++ } else { ++ continue; ++ } ++ ++ buffer->vaddr = dma_alloc_coherent(dev, ++ buffer->buffer_size, ++ &buffer->paddr[0], ++ GFP_DMA | GFP_KERNEL); ++ ++ if (buffer->vaddr) { ++ if (i == STF_ISP_PAD_SRC) ++ buffer->paddr[1] = ++ (dma_addr_t)(buffer->paddr[0] + aligns * fmt->height); ++ else ++ dev_dbg(dev, "signal plane\n"); ++ } ++ } ++ ++ return ret; ++} ++ ++static void vin_free_dummy_buffer(struct stf_vin_dev *vin_dev, int dummy_module) ++{ ++ struct device *dev = vin_dev->stfcamss->dev; ++ struct dummy_buffer *dummy_buffer = ++ &vin_dev->dummy_buffer[dummy_module]; ++ struct vin_dummy_buffer *buffer = NULL; ++ int i; ++ ++ for (i = 0; i < dummy_buffer->nums; i++) { ++ buffer = &dummy_buffer->buffer[i]; ++ if (buffer->vaddr) ++ dma_free_coherent(dev, buffer->buffer_size, ++ buffer->vaddr, buffer->paddr[0]); ++ memset(buffer, 0, sizeof(struct vin_dummy_buffer)); ++ } ++} ++ ++static void vin_set_dummy_buffer(struct vin_line *line, u32 pad) ++{ ++ struct stf_vin_dev *vin_dev = line_to_vin_dev(line); ++ int dummy_module = vin_line_to_dummy_module(line); ++ struct dummy_buffer *dummy_buffer = ++ &vin_dev->dummy_buffer[dummy_module]; ++ struct vin_dummy_buffer *buffer = NULL; ++ ++ switch (pad) { ++ case STF_VIN_PAD_SINK: ++ if (line->id == VIN_LINE_WR) { ++ buffer = &dummy_buffer->buffer[STF_VIN_PAD_SINK]; ++ stf_vin_wr_set_ping_addr(vin_dev, buffer->paddr[0]); ++ stf_vin_wr_set_pong_addr(vin_dev, buffer->paddr[0]); ++ } else { ++ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC]; ++ stf_vin_isp_set_yuv_addr(vin_dev, ++ buffer->paddr[0], ++ buffer->paddr[1]); ++ } ++ break; ++ case STF_ISP_PAD_SRC: ++ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC]; ++ stf_vin_isp_set_yuv_addr(vin_dev, ++ buffer->paddr[0], ++ buffer->paddr[1]); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int vin_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct vin_line *line = v4l2_get_subdevdata(sd); ++ struct stf_vin_dev *vin_dev = line_to_vin_dev(line); ++ int dummy_module = vin_line_to_dummy_module(line); ++ struct dummy_buffer *dummy_buffer = ++ &vin_dev->dummy_buffer[dummy_module]; ++ struct v4l2_mbus_framefmt *fmt; ++ enum link link; ++ ++ fmt = __vin_get_format(line, NULL, ++ STF_VIN_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE); ++ mutex_lock(&dummy_buffer->stream_lock); ++ if (enable) { ++ if (dummy_buffer->stream_count == 0) { ++ vin_alloc_dummy_buffer(vin_dev, fmt, dummy_module); ++ vin_set_dummy_buffer(line, STF_VIN_PAD_SINK); ++ atomic_set(&dummy_buffer->frame_skip, ++ VIN_FRAME_DROP_MIN_VAL + 30); ++ } ++ dummy_buffer->stream_count++; ++ } else { ++ if (dummy_buffer->stream_count == 1) { ++ vin_free_dummy_buffer(vin_dev, dummy_module); ++ /* set buffer addr to zero */ ++ vin_set_dummy_buffer(line, STF_VIN_PAD_SINK); ++ } else { ++ vin_set_dummy_buffer(line, ++ stf_vin_map_isp_pad(line->id, STF_ISP_PAD_SINK)); ++ } ++ ++ dummy_buffer->stream_count--; ++ } ++ mutex_unlock(&dummy_buffer->stream_lock); ++ ++ mutex_lock(&line->stream_lock); ++ link = vin_get_link(&sd->entity); ++ if (link == LINK_ERROR) ++ goto exit; ++ ++ if (enable) { ++ if (line->stream_count == 0) { ++ stf_vin_stream_set(vin_dev, link); ++ if (line->id == VIN_LINE_WR) { ++ stf_vin_wr_irq_enable(vin_dev, 1); ++ stf_vin_wr_stream_set(vin_dev); ++ } ++ } ++ line->stream_count++; ++ } else { ++ if (line->stream_count == 1 && line->id == VIN_LINE_WR) ++ stf_vin_wr_irq_enable(vin_dev, 0); ++ line->stream_count--; ++ } ++exit: ++ mutex_unlock(&line->stream_lock); ++ ++ if (enable) ++ vin_enable_output(line); ++ else ++ vin_disable_output(line); ++ ++ return 0; ++} ++ ++static struct v4l2_mbus_framefmt * ++__vin_get_format(struct vin_line *line, ++ struct v4l2_subdev_state *state, ++ unsigned int pad, ++ enum v4l2_subdev_format_whence which) ++{ ++ if (which == V4L2_SUBDEV_FORMAT_TRY) ++ return v4l2_subdev_get_try_format(&line->subdev, state, pad); ++ return &line->fmt[pad]; ++} ++ ++static void vin_try_format(struct vin_line *line, ++ struct v4l2_subdev_state *state, ++ unsigned int pad, ++ struct v4l2_mbus_framefmt *fmt, ++ enum v4l2_subdev_format_whence which) ++{ ++ unsigned int i; ++ ++ switch (pad) { ++ case STF_VIN_PAD_SINK: ++ /* Set format on sink pad */ ++ for (i = 0; i < line->nformats; i++) ++ if (fmt->code == line->formats[i].code) ++ break; ++ ++ /* If not found, use UYVY as default */ ++ if (i >= line->nformats) ++ fmt->code = line->formats[0].code; ++ ++ fmt->width = clamp_t(u32, fmt->width, ++ STFCAMSS_FRAME_MIN_WIDTH, ++ STFCAMSS_FRAME_MAX_WIDTH); ++ fmt->height = clamp_t(u32, fmt->height, ++ STFCAMSS_FRAME_MIN_HEIGHT, ++ STFCAMSS_FRAME_MAX_HEIGHT); ++ ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_SRGB; ++ fmt->flags = 0; ++ break; ++ ++ case STF_VIN_PAD_SRC: ++ /* Set and return a format same as sink pad */ ++ *fmt = *__vin_get_format(line, state, STF_VIN_PAD_SINK, which); ++ break; ++ } ++ ++ fmt->colorspace = V4L2_COLORSPACE_SRGB; ++} ++ ++static int vin_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct vin_line *line = v4l2_get_subdevdata(sd); ++ ++ if (code->index >= line->nformats) ++ return -EINVAL; ++ if (code->pad == STF_VIN_PAD_SINK) { ++ code->code = line->formats[code->index].code; ++ } else { ++ struct v4l2_mbus_framefmt *sink_fmt; ++ ++ sink_fmt = __vin_get_format(line, state, STF_VIN_PAD_SINK, ++ code->which); ++ ++ code->code = sink_fmt->code; ++ if (!code->code) ++ return -EINVAL; ++ } ++ code->flags = 0; ++ ++ return 0; ++} ++ ++static int vin_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct vin_line *line = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt format; ++ ++ if (fse->index != 0) ++ return -EINVAL; ++ ++ format.code = fse->code; ++ format.width = 1; ++ format.height = 1; ++ vin_try_format(line, state, fse->pad, &format, fse->which); ++ fse->min_width = format.width; ++ fse->min_height = format.height; ++ ++ if (format.code != fse->code) ++ return -EINVAL; ++ ++ format.code = fse->code; ++ format.width = -1; ++ format.height = -1; ++ vin_try_format(line, state, fse->pad, &format, fse->which); ++ fse->max_width = format.width; ++ fse->max_height = format.height; ++ ++ return 0; ++} ++ ++static int vin_get_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct vin_line *line = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt *format; ++ ++ format = __vin_get_format(line, state, fmt->pad, fmt->which); ++ if (!format) ++ return -EINVAL; ++ ++ fmt->format = *format; ++ ++ return 0; ++} ++ ++static int vin_set_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct vin_line *line = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt *format; ++ ++ format = __vin_get_format(line, state, fmt->pad, fmt->which); ++ if (!format) ++ return -EINVAL; ++ ++ mutex_lock(&line->stream_lock); ++ if (line->stream_count) { ++ fmt->format = *format; ++ mutex_unlock(&line->stream_lock); ++ goto out; ++ } else { ++ vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which); ++ *format = fmt->format; ++ } ++ mutex_unlock(&line->stream_lock); ++ ++ if (fmt->pad == STF_VIN_PAD_SINK) { ++ /* Propagate the format from sink to source */ ++ format = __vin_get_format(line, state, STF_VIN_PAD_SRC, ++ fmt->which); ++ ++ *format = fmt->format; ++ vin_try_format(line, state, STF_VIN_PAD_SRC, format, ++ fmt->which); ++ } ++ ++out: ++ return 0; ++} ++ ++static int vin_init_formats(struct v4l2_subdev *sd, ++ struct v4l2_subdev_fh *fh) ++{ ++ struct v4l2_subdev_format format = { ++ .pad = STF_VIN_PAD_SINK, ++ .which = fh ? ++ V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, ++ .format = { ++ .code = MEDIA_BUS_FMT_RGB565_2X8_LE, ++ .width = 1920, ++ .height = 1080 ++ } ++ }; ++ ++ return vin_set_format(sd, fh ? fh->state : NULL, &format); ++} ++ ++static void vin_output_init_addrs(struct vin_line *line) ++{ ++ struct vin_output *output = &line->output; ++ struct stf_vin_dev *vin_dev = line_to_vin_dev(line); ++ dma_addr_t ping_addr; ++ dma_addr_t y_addr, uv_addr; ++ ++ output->active_buf = 0; ++ ++ if (output->buf[0]) { ++ ping_addr = output->buf[0]->addr[0]; ++ y_addr = output->buf[0]->addr[0]; ++ uv_addr = output->buf[0]->addr[1]; ++ } else { ++ return; ++ } ++ ++ switch (vin_map_isp_line(line->id)) { ++ case STF_ISP_LINE_SRC: ++ stf_vin_isp_set_yuv_addr(vin_dev, y_addr, uv_addr); ++ break; ++ default: ++ if (line->id == VIN_LINE_WR) { ++ stf_vin_wr_set_ping_addr(vin_dev, ping_addr); ++ stf_vin_wr_set_pong_addr(vin_dev, ping_addr); ++ } ++ break; ++ } ++} ++ ++static void vin_init_outputs(struct vin_line *line) ++{ ++ struct vin_output *output = &line->output; ++ ++ output->state = VIN_OUTPUT_OFF; ++ output->buf[0] = NULL; ++ output->buf[1] = NULL; ++ output->active_buf = 0; ++ INIT_LIST_HEAD(&output->pending_bufs); ++ INIT_LIST_HEAD(&output->ready_bufs); ++} ++ ++static void vin_buf_add_ready(struct vin_output *output, ++ struct stfcamss_buffer *buffer) ++{ ++ INIT_LIST_HEAD(&buffer->queue); ++ list_add_tail(&buffer->queue, &output->ready_bufs); ++} ++ ++static struct stfcamss_buffer *vin_buf_get_ready(struct vin_output *output) ++{ ++ struct stfcamss_buffer *buffer = NULL; ++ ++ if (!list_empty(&output->ready_bufs)) { ++ buffer = list_first_entry(&output->ready_bufs, ++ struct stfcamss_buffer, ++ queue); ++ list_del(&buffer->queue); ++ } ++ ++ return buffer; ++} ++ ++static void vin_buf_add_pending(struct vin_output *output, ++ struct stfcamss_buffer *buffer) ++{ ++ INIT_LIST_HEAD(&buffer->queue); ++ list_add_tail(&buffer->queue, &output->pending_bufs); ++} ++ ++static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output) ++{ ++ struct stfcamss_buffer *buffer = NULL; ++ ++ if (!list_empty(&output->pending_bufs)) { ++ buffer = list_first_entry(&output->pending_bufs, ++ struct stfcamss_buffer, ++ queue); ++ list_del(&buffer->queue); ++ } ++ ++ return buffer; ++} ++ ++static void vin_buf_update_on_last(struct vin_line *line) ++{ ++ struct vin_output *output = &line->output; ++ ++ switch (output->state) { ++ case VIN_OUTPUT_CONTINUOUS: ++ output->state = VIN_OUTPUT_SINGLE; ++ output->active_buf = !output->active_buf; ++ break; ++ case VIN_OUTPUT_SINGLE: ++ output->state = VIN_OUTPUT_STOPPING; ++ break; ++ default: ++ break; ++ } ++} ++ ++static void vin_buf_update_on_next(struct vin_line *line) ++{ ++ struct vin_output *output = &line->output; ++ ++ switch (output->state) { ++ case VIN_OUTPUT_CONTINUOUS: ++ output->active_buf = !output->active_buf; ++ break; ++ case VIN_OUTPUT_SINGLE: ++ default: ++ break; ++ } ++} ++ ++static void vin_buf_update_on_new(struct vin_line *line, ++ struct vin_output *output, ++ struct stfcamss_buffer *new_buf) ++{ ++ switch (output->state) { ++ case VIN_OUTPUT_SINGLE: ++ vin_buf_add_pending(output, new_buf); ++ break; ++ case VIN_OUTPUT_IDLE: ++ if (!output->buf[0]) { ++ output->buf[0] = new_buf; ++ vin_output_init_addrs(line); ++ output->state = VIN_OUTPUT_SINGLE; ++ } else { ++ vin_buf_add_pending(output, new_buf); ++ } ++ break; ++ case VIN_OUTPUT_STOPPING: ++ if (output->last_buffer) { ++ output->buf[output->active_buf] = output->last_buffer; ++ output->last_buffer = NULL; ++ } ++ ++ output->state = VIN_OUTPUT_SINGLE; ++ vin_buf_add_pending(output, new_buf); ++ break; ++ case VIN_OUTPUT_CONTINUOUS: ++ default: ++ vin_buf_add_pending(output, new_buf); ++ break; ++ } ++} ++ ++static void vin_buf_flush(struct vin_output *output, ++ enum vb2_buffer_state state) ++{ ++ struct stfcamss_buffer *buf; ++ struct stfcamss_buffer *t; ++ ++ list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) { ++ vb2_buffer_done(&buf->vb.vb2_buf, state); ++ list_del(&buf->queue); ++ } ++ list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) { ++ vb2_buffer_done(&buf->vb.vb2_buf, state); ++ list_del(&buf->queue); ++ } ++} ++ ++static void vin_buffer_done(struct vin_line *line) ++{ ++ struct stfcamss_buffer *ready_buf; ++ struct vin_output *output = &line->output; ++ unsigned long flags; ++ u64 ts = ktime_get_ns(); ++ ++ if (output->state == VIN_OUTPUT_OFF || ++ output->state == VIN_OUTPUT_RESERVED) ++ return; ++ ++ spin_lock_irqsave(&line->output_lock, flags); ++ ++ while ((ready_buf = vin_buf_get_ready(output))) { ++ ready_buf->vb.vb2_buf.timestamp = ts; ++ ready_buf->vb.sequence = output->sequence++; ++ ++ vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); ++ } ++ ++ spin_unlock_irqrestore(&line->output_lock, flags); ++} ++ ++static void vin_change_buffer(struct vin_line *line) ++{ ++ struct stfcamss_buffer *ready_buf; ++ struct vin_output *output = &line->output; ++ struct stf_vin_dev *vin_dev = line_to_vin_dev(line); ++ dma_addr_t *new_addr; ++ unsigned long flags; ++ u32 active_index; ++ ++ if (output->state == VIN_OUTPUT_OFF || ++ output->state == VIN_OUTPUT_STOPPING || ++ output->state == VIN_OUTPUT_RESERVED || ++ output->state == VIN_OUTPUT_IDLE) ++ return; ++ ++ spin_lock_irqsave(&line->output_lock, flags); ++ ++ active_index = output->active_buf; ++ ++ ready_buf = output->buf[active_index]; ++ if (!ready_buf) { ++ dev_warn(vin_dev->stfcamss->dev, "Missing ready buf %d %d!\n", ++ active_index, output->state); ++ active_index = !active_index; ++ ready_buf = output->buf[active_index]; ++ if (!ready_buf) { ++ dev_err(vin_dev->stfcamss->dev, ++ "Missing ready buf2 %d %d!\n", ++ active_index, output->state); ++ goto out_unlock; ++ } ++ } ++ ++ /* Get next buffer */ ++ output->buf[active_index] = vin_buf_get_pending(output); ++ if (!output->buf[active_index]) { ++ /* No next buffer - set same address */ ++ new_addr = ready_buf->addr; ++ vin_buf_update_on_last(line); ++ } else { ++ new_addr = output->buf[active_index]->addr; ++ vin_buf_update_on_next(line); ++ } ++ ++ if (output->state == VIN_OUTPUT_STOPPING) { ++ output->last_buffer = ready_buf; ++ } else { ++ switch (vin_map_isp_line(line->id)) { ++ case STF_ISP_LINE_SRC: ++ stf_vin_isp_set_yuv_addr(vin_dev, ++ new_addr[0], ++ new_addr[1]); ++ break; ++ default: ++ if (line->id == VIN_LINE_WR) { ++ stf_vin_wr_set_ping_addr(vin_dev, new_addr[0]); ++ stf_vin_wr_set_pong_addr(vin_dev, new_addr[0]); ++ } ++ break; ++ } ++ ++ vin_buf_add_ready(output, ready_buf); ++ } ++ ++ spin_unlock_irqrestore(&line->output_lock, flags); ++ return; ++ ++out_unlock: ++ spin_unlock_irqrestore(&line->output_lock, flags); ++} ++ ++static int vin_queue_buffer(struct stfcamss_video *vid, ++ struct stfcamss_buffer *buf) ++{ ++ struct vin_line *line = container_of(vid, struct vin_line, video_out); ++ struct vin_output *output; ++ unsigned long flags; ++ ++ output = &line->output; ++ ++ spin_lock_irqsave(&line->output_lock, flags); ++ ++ vin_buf_update_on_new(line, output, buf); ++ ++ spin_unlock_irqrestore(&line->output_lock, flags); ++ ++ return 0; ++} ++ ++static int vin_flush_buffers(struct stfcamss_video *vid, ++ enum vb2_buffer_state state) ++{ ++ struct vin_line *line = container_of(vid, struct vin_line, video_out); ++ struct vin_output *output = &line->output; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&line->output_lock, flags); ++ ++ vin_buf_flush(output, state); ++ if (output->buf[0]) ++ vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state); ++ ++ if (output->buf[1]) ++ vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state); ++ ++ if (output->last_buffer) { ++ vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state); ++ output->last_buffer = NULL; ++ } ++ output->buf[0] = NULL; ++ output->buf[1] = NULL; ++ ++ spin_unlock_irqrestore(&line->output_lock, flags); ++ return 0; ++} ++ ++static int vin_link_setup(struct media_entity *entity, ++ const struct media_pad *local, ++ const struct media_pad *remote, u32 flags) ++{ ++ if (flags & MEDIA_LNK_FL_ENABLED) ++ if (media_pad_remote_pad_first(local)) ++ return -EBUSY; ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops vin_core_ops = { ++ .s_power = vin_set_power, ++}; ++ ++static const struct v4l2_subdev_video_ops vin_video_ops = { ++ .s_stream = vin_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops vin_pad_ops = { ++ .enum_mbus_code = vin_enum_mbus_code, ++ .enum_frame_size = vin_enum_frame_size, ++ .get_fmt = vin_get_format, ++ .set_fmt = vin_set_format, ++}; ++ ++static const struct v4l2_subdev_ops vin_v4l2_ops = { ++ .core = &vin_core_ops, ++ .video = &vin_video_ops, ++ .pad = &vin_pad_ops, ++}; ++ ++static const struct v4l2_subdev_internal_ops vin_v4l2_internal_ops = { ++ .open = vin_init_formats, ++}; ++ ++static const struct stfcamss_video_ops stfcamss_vin_video_ops = { ++ .queue_buffer = vin_queue_buffer, ++ .flush_buffers = vin_flush_buffers, ++}; ++ ++static const struct media_entity_operations vin_media_ops = { ++ .link_setup = vin_link_setup, ++ .link_validate = v4l2_subdev_link_validate, ++}; ++ ++int stf_vin_register(struct stf_vin_dev *vin_dev, struct v4l2_device *v4l2_dev) ++{ ++ struct v4l2_subdev *sd; ++ struct stfcamss_video *video_out; ++ struct media_pad *pads; ++ int ret; ++ int i; ++ ++ for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) { ++ char name[32]; ++ char *sub_name = vin_get_line_subdevname(i); ++ ++ sd = &vin_dev->line[i].subdev; ++ pads = vin_dev->line[i].pads; ++ video_out = &vin_dev->line[i].video_out; ++ video_out->id = i; ++ ++ v4l2_subdev_init(sd, &vin_v4l2_ops); ++ sd->internal_ops = &vin_v4l2_internal_ops; ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s", ++ STF_VIN_NAME, 0, sub_name); ++ v4l2_set_subdevdata(sd, &vin_dev->line[i]); ++ ++ ret = vin_init_formats(sd, NULL); ++ if (ret < 0) { ++ dev_err(vin_dev->stfcamss->dev, ++ "Failed to init format: %d\n", ret); ++ goto err_init; ++ } ++ ++ pads[STF_VIN_PAD_SINK].flags = MEDIA_PAD_FL_SINK; ++ pads[STF_VIN_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; ++ ++ sd->entity.function = ++ MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; ++ sd->entity.ops = &vin_media_ops; ++ ret = media_entity_pads_init(&sd->entity, ++ STF_VIN_PADS_NUM, pads); ++ if (ret < 0) { ++ dev_err(vin_dev->stfcamss->dev, ++ "Failed to init media entity: %d\n", ++ ret); ++ goto err_init; ++ } ++ ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if (ret < 0) { ++ dev_err(vin_dev->stfcamss->dev, ++ "Failed to register subdev: %d\n", ret); ++ goto err_reg_subdev; ++ } ++ ++ video_out->ops = &stfcamss_vin_video_ops; ++ video_out->bpl_alignment = 16 * 8; ++ ++ snprintf(name, ARRAY_SIZE(name), "%s_%s%d", ++ sd->name, "video", i); ++ ret = stf_video_register(video_out, v4l2_dev, name); ++ if (ret < 0) { ++ dev_err(vin_dev->stfcamss->dev, ++ "Failed to register video node: %d\n", ret); ++ goto err_vid_reg; ++ } ++ ++ ret = media_create_pad_link( ++ &sd->entity, STF_VIN_PAD_SRC, ++ &video_out->vdev.entity, 0, ++ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ if (ret < 0) { ++ dev_err(vin_dev->stfcamss->dev, ++ "Failed to link %s->%s entities: %d\n", ++ sd->entity.name, video_out->vdev.entity.name, ++ ret); ++ goto err_create_link; ++ } ++ } ++ ++ return 0; ++ ++err_create_link: ++ stf_video_unregister(video_out); ++err_vid_reg: ++ v4l2_device_unregister_subdev(sd); ++err_reg_subdev: ++ media_entity_cleanup(&sd->entity); ++err_init: ++ for (i--; i >= 0; i--) { ++ sd = &vin_dev->line[i].subdev; ++ video_out = &vin_dev->line[i].video_out; ++ ++ stf_video_unregister(video_out); ++ v4l2_device_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ } ++ return ret; ++} ++ ++int stf_vin_unregister(struct stf_vin_dev *vin_dev) ++{ ++ struct v4l2_subdev *sd; ++ struct stfcamss_video *video_out; ++ int i; ++ ++ mutex_destroy(&vin_dev->power_lock); ++ for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++) ++ mutex_destroy(&vin_dev->dummy_buffer[i].stream_lock); ++ ++ for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) { ++ sd = &vin_dev->line[i].subdev; ++ video_out = &vin_dev->line[i].video_out; ++ ++ stf_video_unregister(video_out); ++ v4l2_device_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ mutex_destroy(&vin_dev->line[i].stream_lock); ++ mutex_destroy(&vin_dev->line[i].power_lock); ++ } ++ return 0; ++} +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_vin.h +@@ -0,0 +1,180 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * stf_vin.h ++ * ++ * StarFive Camera Subsystem - VIN Module ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++ ++#ifndef STF_VIN_H ++#define STF_VIN_H ++ ++#include ++#include ++#include ++ ++#include "stf_video.h" ++ ++#define SYSCONSAIF_SYSCFG(x) (x) ++ ++/* syscon offset 0 */ ++#define U0_VIN_CNFG_AXI_DVP_EN BIT(2) ++ ++/* syscon offset 20 */ ++#define U0_VIN_CHANNEL_SEL_MASK GENMASK(3, 0) ++#define U0_VIN_AXIWR0_EN BIT(4) ++#define CHANNEL(x) ((x) << 0) ++ ++/* syscon offset 32 */ ++#define U0_VIN_INTR_CLEAN BIT(0) ++#define U0_VIN_INTR_M BIT(1) ++#define U0_VIN_PIX_CNT_END_MASK GENMASK(12, 2) ++#define U0_VIN_PIX_CT_MASK GENMASK(14, 13) ++#define U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS GENMASK(16, 15) ++ ++#define PIX_CNT_END(x) ((x) << 2) ++#define PIX_CT(x) ((x) << 13) ++#define PIXEL_HEIGH_BIT_SEL(x) ((x) << 15) ++ ++/* syscon offset 36 */ ++#define U0_VIN_CNFG_DVP_HS_POS BIT(1) ++#define U0_VIN_CNFG_DVP_SWAP_EN BIT(2) ++#define U0_VIN_CNFG_DVP_VS_POS BIT(3) ++#define U0_VIN_CNFG_GEN_EN_AXIRD BIT(4) ++#define U0_VIN_CNFG_ISP_DVP_EN0 BIT(5) ++#define U0_VIN_MIPI_BYTE_EN_ISP0(n) ((n) << 6) ++#define U0_VIN_MIPI_CHANNEL_SEL0(n) ((n) << 8) ++#define U0_VIN_P_I_MIPI_HAEDER_EN0(n) ((n) << 12) ++#define U0_VIN_PIX_NUM(n) ((n) << 13) ++#define U0_VIN_MIPI_BYTE_EN_ISP0_MASK GENMASK(7, 6) ++#define U0_VIN_MIPI_CHANNEL_SEL0_MASK GENMASK(11, 8) ++#define U0_VIN_P_I_MIPI_HAEDER_EN0_MASK BIT(12) ++#define U0_VIN_PIX_NUM_MASK GENMASK(16, 13) ++ ++#define STF_VIN_PAD_SINK 0 ++#define STF_VIN_PAD_SRC 1 ++#define STF_VIN_PADS_NUM 2 ++ ++#define ISP_DUMMY_BUFFER_NUMS STF_ISP_PAD_MAX ++#define VIN_DUMMY_BUFFER_NUMS 1 ++ ++enum { ++ STF_DUMMY_VIN, ++ STF_DUMMY_ISP, ++ STF_DUMMY_MODULE_NUMS, ++}; ++ ++enum link { ++ LINK_ERROR = -1, ++ LINK_DVP_TO_WR, ++ LINK_DVP_TO_ISP, ++ LINK_CSI_TO_WR, ++ LINK_CSI_TO_ISP, ++}; ++ ++struct vin_format { ++ u32 code; ++ u8 bpp; ++}; ++ ++struct vin_format_table { ++ const struct vin_format *fmts; ++ int nfmts; ++}; ++ ++enum vin_output_state { ++ VIN_OUTPUT_OFF, ++ VIN_OUTPUT_RESERVED, ++ VIN_OUTPUT_SINGLE, ++ VIN_OUTPUT_CONTINUOUS, ++ VIN_OUTPUT_IDLE, ++ VIN_OUTPUT_STOPPING ++}; ++ ++struct vin_output { ++ int active_buf; ++ struct stfcamss_buffer *buf[2]; ++ struct stfcamss_buffer *last_buffer; ++ struct list_head pending_bufs; ++ struct list_head ready_bufs; ++ enum vin_output_state state; ++ unsigned int sequence; ++ unsigned int frame_skip; ++}; ++ ++/* The vin output lines */ ++enum vin_line_id { ++ VIN_LINE_NONE = -1, ++ VIN_LINE_WR = 0, ++ VIN_LINE_ISP, ++ VIN_LINE_MAX, ++}; ++ ++struct vin_line { ++ enum stf_subdev_type sdev_type; /* must be frist */ ++ enum vin_line_id id; ++ struct v4l2_subdev subdev; ++ struct media_pad pads[STF_VIN_PADS_NUM]; ++ struct v4l2_mbus_framefmt fmt[STF_VIN_PADS_NUM]; ++ struct stfcamss_video video_out; ++ struct mutex stream_lock; /* serialize stream control */ ++ int stream_count; ++ struct mutex power_lock; /* serialize pipeline control in power process*/ ++ int power_count; ++ struct vin_output output; /* pipeline and stream states */ ++ spinlock_t output_lock; ++ const struct vin_format *formats; ++ unsigned int nformats; ++}; ++ ++struct vin_dummy_buffer { ++ dma_addr_t paddr[3]; ++ void *vaddr; ++ u32 buffer_size; ++ u32 width; ++ u32 height; ++ u32 mcode; ++}; ++ ++struct dummy_buffer { ++ struct vin_dummy_buffer *buffer; ++ u32 nums; ++ struct mutex stream_lock; /* protects buffer data */ ++ int stream_count; ++ atomic_t frame_skip; ++}; ++ ++struct vin_isr_ops { ++ void (*isr_buffer_done)(struct vin_line *line); ++ void (*isr_change_buffer)(struct vin_line *line); ++}; ++ ++struct stf_vin_dev { ++ struct stfcamss *stfcamss; ++ struct vin_line line[VIN_LINE_MAX]; ++ struct dummy_buffer dummy_buffer[STF_DUMMY_MODULE_NUMS]; ++ struct vin_isr_ops *isr_ops; ++ atomic_t ref_count; ++ struct mutex power_lock; /* serialize power control*/ ++ int power_count; ++}; ++ ++int stf_vin_clk_enable(struct stf_vin_dev *vin_dev, enum link link); ++int stf_vin_clk_disable(struct stf_vin_dev *vin_dev, enum link link); ++int stf_vin_wr_stream_set(struct stf_vin_dev *vin_dev); ++int stf_vin_stream_set(struct stf_vin_dev *vin_dev, enum link link); ++void stf_vin_wr_irq_enable(struct stf_vin_dev *vin_dev, int enable); ++void stf_vin_wr_set_ping_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr); ++void stf_vin_wr_set_pong_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr); ++void stf_vin_isp_set_yuv_addr(struct stf_vin_dev *vin_dev, ++ dma_addr_t y_addr, dma_addr_t uv_addr); ++irqreturn_t stf_vin_wr_irq_handler(int irq, void *priv); ++irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv); ++irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv); ++int stf_vin_subdev_init(struct stfcamss *stfcamss); ++int stf_vin_register(struct stf_vin_dev *vin_dev, struct v4l2_device *v4l2_dev); ++int stf_vin_unregister(struct stf_vin_dev *vin_dev); ++enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line, enum isp_pad_id def); ++ ++#endif /* STF_VIN_H */ +--- /dev/null ++++ b/drivers/media/platform/starfive/stf_vin_hw_ops.c +@@ -0,0 +1,241 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * stf_vin_hw_ops.c ++ * ++ * Register interface file for StarFive VIN module driver ++ * ++ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. ++ */ ++#include "stf_camss.h" ++ ++static void vin_intr_clear(struct stfcamss *stfcamss) ++{ ++ stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(28), ++ U0_VIN_INTR_CLEAN); ++ stf_syscon_reg_clear_bit(stfcamss, SYSCONSAIF_SYSCFG(28), ++ U0_VIN_INTR_CLEAN); ++} ++ ++irqreturn_t stf_vin_wr_irq_handler(int irq, void *priv) ++{ ++ struct stf_vin_dev *vin_dev = priv; ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ struct dummy_buffer *dummy_buffer = ++ &vin_dev->dummy_buffer[STF_DUMMY_VIN]; ++ ++ if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) { ++ vin_dev->isr_ops->isr_change_buffer(&vin_dev->line[VIN_LINE_WR]); ++ vin_dev->isr_ops->isr_buffer_done(&vin_dev->line[VIN_LINE_WR]); ++ } ++ ++ vin_intr_clear(stfcamss); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv) ++{ ++ struct stf_vin_dev *vin_dev = priv; ++ u32 int_status; ++ ++ int_status = stf_isp_reg_read(vin_dev->stfcamss, ISP_REG_ISP_CTRL_0); ++ ++ if (int_status & ISPC_INTS) { ++ if ((int_status & ISPC_ENUO)) ++ vin_dev->isr_ops->isr_buffer_done( ++ &vin_dev->line[VIN_LINE_ISP]); ++ ++ /* clear interrupt */ ++ stf_isp_reg_write(vin_dev->stfcamss, ++ ISP_REG_ISP_CTRL_0, ++ (int_status & ~EN_INT_ALL) | ++ EN_INT_ISP_DONE | ++ EN_INT_CSI_DONE | ++ EN_INT_SC_DONE); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv) ++{ ++ struct stf_vin_dev *vin_dev = priv; ++ struct stf_isp_dev *isp_dev; ++ u32 int_status; ++ ++ isp_dev = &vin_dev->stfcamss->isp_dev; ++ ++ int_status = stf_isp_reg_read(vin_dev->stfcamss, ISP_REG_ISP_CTRL_0); ++ if (int_status & ISPC_SCFEINT) { ++ struct dummy_buffer *dummy_buffer = ++ &vin_dev->dummy_buffer[STF_DUMMY_ISP]; ++ ++ if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) { ++ if ((int_status & ISPC_ENUO)) ++ vin_dev->isr_ops->isr_change_buffer( ++ &vin_dev->line[VIN_LINE_ISP]); ++ } ++ ++ stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_CSIINTS, ++ CSI_INTS_MASK, CSI_INTS(0x3)); ++ stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_IESHD, ++ SHAD_UP_M | SHAD_UP_EN, 0x3); ++ ++ /* clear interrupt */ ++ stf_isp_reg_write(vin_dev->stfcamss, ISP_REG_ISP_CTRL_0, ++ (int_status & ~EN_INT_ALL) | EN_INT_LINE_INT); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++int stf_vin_clk_enable(struct stf_vin_dev *vin_dev, enum link link) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ ++ clk_set_rate(stfcamss->sys_clk[STF_CLK_APB_FUNC].clk, 49500000); ++ ++ switch (link) { ++ case LINK_CSI_TO_WR: ++ clk_set_rate(stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk, ++ 198000000); ++ reset_control_deassert(stfcamss->sys_rst[STF_RST_AXIWR].rstc); ++ clk_set_parent(stfcamss->sys_clk[STF_CLK_AXIWR].clk, ++ stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk); ++ break; ++ case LINK_CSI_TO_ISP: ++ clk_set_rate(stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk, ++ 198000000); ++ clk_set_parent(stfcamss->sys_clk[STF_CLK_WRAPPER_CLK_C].clk, ++ stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk); ++ break; ++ case LINK_DVP_TO_WR: ++ case LINK_DVP_TO_ISP: ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int stf_vin_clk_disable(struct stf_vin_dev *vin_dev, enum link link) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ ++ switch (link) { ++ case LINK_CSI_TO_WR: ++ reset_control_assert(stfcamss->sys_rst[STF_RST_AXIWR].rstc); ++ break; ++ case LINK_CSI_TO_ISP: ++ break; ++ case LINK_DVP_TO_WR: ++ case LINK_DVP_TO_ISP: ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int stf_vin_wr_stream_set(struct stf_vin_dev *vin_dev) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ ++ /* make the axiwr alway on */ ++ stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(20), ++ U0_VIN_AXIWR0_EN); ++ ++ return 0; ++} ++ ++int stf_vin_stream_set(struct stf_vin_dev *vin_dev, enum link link) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ u32 val; ++ ++ switch (link) { ++ case LINK_CSI_TO_WR: ++ val = stf_syscon_reg_read(stfcamss, SYSCONSAIF_SYSCFG(20)); ++ val &= ~U0_VIN_CHANNEL_SEL_MASK; ++ val |= CHANNEL(0); ++ stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(20), val); ++ ++ val = stf_syscon_reg_read(stfcamss, SYSCONSAIF_SYSCFG(28)); ++ val &= ~U0_VIN_PIX_CT_MASK; ++ val |= PIX_CT(1); ++ ++ val &= ~U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS; ++ val |= PIXEL_HEIGH_BIT_SEL(0); ++ ++ val &= ~U0_VIN_PIX_CNT_END_MASK; ++ val |= PIX_CNT_END(IMAGE_MAX_WIDTH / 4 - 1); ++ ++ stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(28), val); ++ break; ++ case LINK_CSI_TO_ISP: ++ val = stf_syscon_reg_read(stfcamss, SYSCONSAIF_SYSCFG(36)); ++ val &= ~U0_VIN_MIPI_BYTE_EN_ISP0_MASK; ++ val |= U0_VIN_MIPI_BYTE_EN_ISP0(0); ++ ++ val &= ~U0_VIN_MIPI_CHANNEL_SEL0_MASK; ++ val |= U0_VIN_MIPI_CHANNEL_SEL0(0); ++ ++ val &= ~U0_VIN_PIX_NUM_MASK; ++ val |= U0_VIN_PIX_NUM(0); ++ ++ val &= ~U0_VIN_P_I_MIPI_HAEDER_EN0_MASK; ++ val |= U0_VIN_P_I_MIPI_HAEDER_EN0(1); ++ ++ stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(36), val); ++ break; ++ case LINK_DVP_TO_WR: ++ case LINK_DVP_TO_ISP: ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++void stf_vin_wr_irq_enable(struct stf_vin_dev *vin_dev, int enable) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ ++ if (enable) { ++ stf_syscon_reg_clear_bit(stfcamss, SYSCONSAIF_SYSCFG(28), ++ U0_VIN_INTR_M); ++ } else { ++ /* clear vin interrupt */ ++ stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(28), ++ U0_VIN_INTR_CLEAN); ++ stf_syscon_reg_clear_bit(stfcamss, SYSCONSAIF_SYSCFG(28), ++ U0_VIN_INTR_CLEAN); ++ stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(28), ++ U0_VIN_INTR_M); ++ } ++} ++ ++void stf_vin_wr_set_ping_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ ++ /* set the start address */ ++ stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(32), (long)addr); ++} ++ ++void stf_vin_wr_set_pong_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr) ++{ ++ struct stfcamss *stfcamss = vin_dev->stfcamss; ++ ++ /* set the start address */ ++ stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(24), (long)addr); ++} ++ ++void stf_vin_isp_set_yuv_addr(struct stf_vin_dev *vin_dev, ++ dma_addr_t y_addr, dma_addr_t uv_addr) ++{ ++ stf_isp_reg_write(vin_dev->stfcamss, ++ ISP_REG_Y_PLANE_START_ADDR, y_addr); ++ stf_isp_reg_write(vin_dev->stfcamss, ++ ISP_REG_UV_PLANE_START_ADDR, uv_addr); ++} diff --git a/target/linux/starfive/patches-6.1/0087-dt-bindings-phy-Add-StarFive-JH7110-USB-PHY.patch b/target/linux/starfive/patches-6.1/0087-dt-bindings-phy-Add-StarFive-JH7110-USB-PHY.patch new file mode 100644 index 0000000000..08eee9ca9e --- /dev/null +++ b/target/linux/starfive/patches-6.1/0087-dt-bindings-phy-Add-StarFive-JH7110-USB-PHY.patch @@ -0,0 +1,68 @@ +From 2ebd77fa8fb95f60b275cefb98ea7d6f4df06e55 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 May 2023 19:27:44 +0800 +Subject: [PATCH 087/122] dt-bindings: phy: Add StarFive JH7110 USB PHY + +Add StarFive JH7110 SoC USB 2.0 PHY dt-binding. + +Signed-off-by: Minda Chen +Reviewed-by: Hal Feng +Reviewed-by: Rob Herring +--- + .../bindings/phy/starfive,jh7110-usb-phy.yaml | 50 +++++++++++++++++++ + 1 file changed, 50 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml +@@ -0,0 +1,50 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/phy/starfive,jh7110-usb-phy.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 USB 2.0 PHY ++ ++maintainers: ++ - Minda Chen ++ ++properties: ++ compatible: ++ const: starfive,jh7110-usb-phy ++ ++ reg: ++ maxItems: 1 ++ ++ "#phy-cells": ++ const: 0 ++ ++ clocks: ++ items: ++ - description: PHY 125m ++ - description: app 125m ++ ++ clock-names: ++ items: ++ - const: 125m ++ - const: app_125m ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - "#phy-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ phy@10200000 { ++ compatible = "starfive,jh7110-usb-phy"; ++ reg = <0x10200000 0x10000>; ++ clocks = <&syscrg 95>, ++ <&stgcrg 6>; ++ clock-names = "125m", "app_125m"; ++ #phy-cells = <0>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0088-dt-bindings-phy-Add-StarFive-JH7110-PCIe-PHY.patch b/target/linux/starfive/patches-6.1/0088-dt-bindings-phy-Add-StarFive-JH7110-PCIe-PHY.patch new file mode 100644 index 0000000000..6911bba9d2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0088-dt-bindings-phy-Add-StarFive-JH7110-PCIe-PHY.patch @@ -0,0 +1,77 @@ +From d57245d420a2ced6a588cc6e03e2eaacbbf1bfb2 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 May 2023 19:27:45 +0800 +Subject: [PATCH 088/122] dt-bindings: phy: Add StarFive JH7110 PCIe PHY + +Add StarFive JH7110 SoC PCIe 2.0 PHY dt-binding. +PCIe PHY0 (phy@10210000) can be used as USB 3.0 PHY. + +Signed-off-by: Minda Chen +Reviewed-by: Hal Feng +Reviewed-by: Rob Herring +--- + .../phy/starfive,jh7110-pcie-phy.yaml | 58 +++++++++++++++++++ + 1 file changed, 58 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml +@@ -0,0 +1,58 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/phy/starfive,jh7110-pcie-phy.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 PCIe 2.0 PHY ++ ++maintainers: ++ - Minda Chen ++ ++properties: ++ compatible: ++ const: starfive,jh7110-pcie-phy ++ ++ reg: ++ maxItems: 1 ++ ++ "#phy-cells": ++ const: 0 ++ ++ starfive,sys-syscon: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ items: ++ - items: ++ - description: phandle to System Register Controller sys_syscon node. ++ - description: PHY connect offset of SYS_SYSCONSAIF__SYSCFG register for USB PHY. ++ description: ++ The phandle to System Register Controller syscon node and the PHY connect offset ++ of SYS_SYSCONSAIF__SYSCFG register. Connect PHY to USB3 controller. ++ ++ starfive,stg-syscon: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ items: ++ - items: ++ - description: phandle to System Register Controller stg_syscon node. ++ - description: PHY mode offset of STG_SYSCONSAIF__SYSCFG register. ++ - description: PHY enable for USB offset of STG_SYSCONSAIF__SYSCFG register. ++ description: ++ The phandle to System Register Controller syscon node and the offset ++ of STG_SYSCONSAIF__SYSCFG register for PCIe PHY. Total 2 regsisters offset. ++ ++required: ++ - compatible ++ - reg ++ - "#phy-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ phy@10210000 { ++ compatible = "starfive,jh7110-pcie-phy"; ++ reg = <0x10210000 0x10000>; ++ #phy-cells = <0>; ++ starfive,sys-syscon = <&sys_syscon 0x18>; ++ starfive,stg-syscon = <&stg_syscon 0x148 0x1f4>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0089-phy-starfive-Add-JH7110-USB-2.0-PHY-driver.patch b/target/linux/starfive/patches-6.1/0089-phy-starfive-Add-JH7110-USB-2.0-PHY-driver.patch new file mode 100644 index 0000000000..0b608868c1 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0089-phy-starfive-Add-JH7110-USB-2.0-PHY-driver.patch @@ -0,0 +1,192 @@ +From 3d74980ca3ba91dae6e84fbc23750e702e71d41a Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 May 2023 19:27:46 +0800 +Subject: [PATCH 089/122] phy: starfive: Add JH7110 USB 2.0 PHY driver + +Add Starfive JH7110 SoC USB 2.0 PHY driver support. +USB 2.0 PHY default connect to Cadence USB controller. + +Signed-off-by: Minda Chen +--- + drivers/phy/starfive/Kconfig | 11 ++ + drivers/phy/starfive/Makefile | 1 + + drivers/phy/starfive/phy-jh7110-usb.c | 150 ++++++++++++++++++++++++++ + 3 files changed, 162 insertions(+) + create mode 100644 drivers/phy/starfive/phy-jh7110-usb.c + +--- a/drivers/phy/starfive/Kconfig ++++ b/drivers/phy/starfive/Kconfig +@@ -11,3 +11,14 @@ config PHY_STARFIVE_DPHY_RX + Choose this option if you have a StarFive D-PHY in your + system. If M is selected, the module will be called + phy-starfive-dphy-rx. ++ ++config PHY_STARFIVE_JH7110_USB ++ tristate "Starfive JH7110 USB 2.0 PHY support" ++ depends on USB_SUPPORT ++ select GENERIC_PHY ++ select USB_PHY ++ help ++ Enable this to support the StarFive USB 2.0 PHY, ++ used with the Cadence USB controller. ++ If M is selected, the module will be called ++ phy-jh7110-usb.ko. +--- a/drivers/phy/starfive/Makefile ++++ b/drivers/phy/starfive/Makefile +@@ -1,2 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_PHY_STARFIVE_DPHY_RX) += phy-starfive-dphy-rx.o ++obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o +--- /dev/null ++++ b/drivers/phy/starfive/phy-jh7110-usb.c +@@ -0,0 +1,150 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * StarFive JH7110 USB 2.0 PHY driver ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * Author: Minda Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define USB_125M_CLK_RATE 125000000 ++#define USB_LS_KEEPALIVE_OFF 0x4 ++#define USB_LS_KEEPALIVE_ENABLE BIT(4) ++ ++struct jh7110_usb2_phy { ++ struct phy *phy; ++ void __iomem *regs; ++ struct clk *usb_125m_clk; ++ struct clk *app_125m; ++ enum phy_mode mode; ++}; ++ ++static void jh7110_usb2_mode_set(struct jh7110_usb2_phy *phy) ++{ ++ unsigned int val; ++ ++ if (phy->mode != PHY_MODE_USB_HOST) { ++ /* Enable the LS speed keep-alive signal */ ++ val = readl(phy->regs + USB_LS_KEEPALIVE_OFF); ++ val |= USB_LS_KEEPALIVE_ENABLE; ++ writel(val, phy->regs + USB_LS_KEEPALIVE_OFF); ++ } ++} ++ ++static int jh7110_usb2_phy_set_mode(struct phy *_phy, ++ enum phy_mode mode, int submode) ++{ ++ struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); ++ ++ switch (mode) { ++ case PHY_MODE_USB_HOST: ++ case PHY_MODE_USB_DEVICE: ++ case PHY_MODE_USB_OTG: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (mode != phy->mode) { ++ dev_dbg(&_phy->dev, "Changing phy to %d\n", mode); ++ phy->mode = mode; ++ jh7110_usb2_mode_set(phy); ++ } ++ ++ return 0; ++} ++ ++static int jh7110_usb2_phy_init(struct phy *_phy) ++{ ++ struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); ++ int ret; ++ ++ ret = clk_set_rate(phy->usb_125m_clk, USB_125M_CLK_RATE); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(phy->app_125m); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int jh7110_usb2_phy_exit(struct phy *_phy) ++{ ++ struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); ++ ++ clk_disable_unprepare(phy->app_125m); ++ ++ return 0; ++} ++ ++static const struct phy_ops jh7110_usb2_phy_ops = { ++ .init = jh7110_usb2_phy_init, ++ .exit = jh7110_usb2_phy_exit, ++ .set_mode = jh7110_usb2_phy_set_mode, ++ .owner = THIS_MODULE, ++}; ++ ++static int jh7110_usb_phy_probe(struct platform_device *pdev) ++{ ++ struct jh7110_usb2_phy *phy; ++ struct device *dev = &pdev->dev; ++ struct phy_provider *phy_provider; ++ ++ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); ++ if (!phy) ++ return -ENOMEM; ++ ++ phy->usb_125m_clk = devm_clk_get(dev, "125m"); ++ if (IS_ERR(phy->usb_125m_clk)) ++ return dev_err_probe(dev, PTR_ERR(phy->usb_125m_clk), ++ "Failed to get 125m clock\n"); ++ ++ phy->app_125m = devm_clk_get(dev, "app_125m"); ++ if (IS_ERR(phy->app_125m)) ++ return dev_err_probe(dev, PTR_ERR(phy->app_125m), ++ "Failed to get app 125m clock\n"); ++ ++ phy->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(phy->regs)) ++ return dev_err_probe(dev, PTR_ERR(phy->regs), ++ "Failed to map phy base\n"); ++ ++ phy->phy = devm_phy_create(dev, NULL, &jh7110_usb2_phy_ops); ++ if (IS_ERR(phy->phy)) ++ return dev_err_probe(dev, PTR_ERR(phy->phy), ++ "Failed to create phy\n"); ++ ++ phy_set_drvdata(phy->phy, phy); ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct of_device_id jh7110_usb_phy_of_match[] = { ++ { .compatible = "starfive,jh7110-usb-phy" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, jh7110_usb_phy_of_match); ++ ++static struct platform_driver jh7110_usb_phy_driver = { ++ .probe = jh7110_usb_phy_probe, ++ .driver = { ++ .of_match_table = jh7110_usb_phy_of_match, ++ .name = "jh7110-usb-phy", ++ } ++}; ++module_platform_driver(jh7110_usb_phy_driver); ++ ++MODULE_DESCRIPTION("StarFive JH7110 USB 2.0 PHY driver"); ++MODULE_AUTHOR("Minda Chen "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0090-phy-starfive-Add-JH7110-PCIE-2.0-PHY-driver.patch b/target/linux/starfive/patches-6.1/0090-phy-starfive-Add-JH7110-PCIE-2.0-PHY-driver.patch new file mode 100644 index 0000000000..452ffd25c6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0090-phy-starfive-Add-JH7110-PCIE-2.0-PHY-driver.patch @@ -0,0 +1,250 @@ +From d900724fdae7c41a663b31e1ed9b8ba10b998e6f Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 May 2023 19:27:47 +0800 +Subject: [PATCH 090/122] phy: starfive: Add JH7110 PCIE 2.0 PHY driver + +Add Starfive JH7110 SoC PCIe 2.0 PHY driver support. +PCIe 2.0 PHY default connect to PCIe controller. +PCIe PHY can connect to USB 3.0 controller. + +Signed-off-by: Minda Chen +--- + drivers/phy/starfive/Kconfig | 10 ++ + drivers/phy/starfive/Makefile | 1 + + drivers/phy/starfive/phy-jh7110-pcie.c | 204 +++++++++++++++++++++++++ + 3 files changed, 215 insertions(+) + create mode 100644 drivers/phy/starfive/phy-jh7110-pcie.c + +--- a/drivers/phy/starfive/Kconfig ++++ b/drivers/phy/starfive/Kconfig +@@ -12,6 +12,16 @@ config PHY_STARFIVE_DPHY_RX + system. If M is selected, the module will be called + phy-starfive-dphy-rx. + ++config PHY_STARFIVE_JH7110_PCIE ++ tristate "Starfive JH7110 PCIE 2.0/USB 3.0 PHY support" ++ select GENERIC_PHY ++ select USB_PHY ++ help ++ Enable this to support the StarFive PCIe 2.0 PHY, ++ or used as USB 3.0 PHY. ++ If M is selected, the module will be called ++ phy-jh7110-pcie.ko. ++ + config PHY_STARFIVE_JH7110_USB + tristate "Starfive JH7110 USB 2.0 PHY support" + depends on USB_SUPPORT +--- a/drivers/phy/starfive/Makefile ++++ b/drivers/phy/starfive/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_PHY_STARFIVE_DPHY_RX) += phy-starfive-dphy-rx.o ++obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o + obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o +--- /dev/null ++++ b/drivers/phy/starfive/phy-jh7110-pcie.c +@@ -0,0 +1,204 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * StarFive JH7110 PCIe 2.0 PHY driver ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * Author: Minda Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PCIE_KVCO_LEVEL_OFF 0x28 ++#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c ++#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80 ++#define PCIE_USB3_PHY_ENABLE BIT(4) ++#define PHY_KVCO_FINE_TUNE_LEVEL 0x91 ++#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc ++ ++#define USB_PDRSTN_SPLIT BIT(17) ++ ++#define PCIE_PHY_MODE BIT(20) ++#define PCIE_PHY_MODE_MASK GENMASK(21, 20) ++#define PCIE_USB3_BUS_WIDTH_MASK GENMASK(3, 2) ++#define PCIE_USB3_BUS_WIDTH BIT(3) ++#define PCIE_USB3_RATE_MASK GENMASK(6, 5) ++#define PCIE_USB3_RX_STANDBY_MASK BIT(7) ++#define PCIE_USB3_PHY_ENABLE BIT(4) ++ ++struct jh7110_pcie_phy { ++ struct phy *phy; ++ struct regmap *stg_syscon; ++ struct regmap *sys_syscon; ++ void __iomem *regs; ++ u32 sys_phy_connect; ++ u32 stg_pcie_mode; ++ u32 stg_pcie_usb; ++ enum phy_mode mode; ++}; ++ ++static int phy_usb3_mode_set(struct jh7110_pcie_phy *data) ++{ ++ if (!data->stg_syscon || !data->sys_syscon) { ++ dev_err(&data->phy->dev, "doesn't support usb3 mode\n"); ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(data->stg_syscon, data->stg_pcie_mode, ++ PCIE_PHY_MODE_MASK, PCIE_PHY_MODE); ++ regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, ++ PCIE_USB3_BUS_WIDTH_MASK, 0); ++ regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, ++ PCIE_USB3_PHY_ENABLE, PCIE_USB3_PHY_ENABLE); ++ ++ /* Connect usb 3.0 phy mode */ ++ regmap_update_bits(data->sys_syscon, data->sys_phy_connect, ++ USB_PDRSTN_SPLIT, 0); ++ ++ /* Configuare spread-spectrum mode: down-spread-spectrum */ ++ writel(PCIE_USB3_PHY_ENABLE, data->regs + PCIE_USB3_PHY_PLL_CTL_OFF); ++ ++ return 0; ++} ++ ++static void phy_pcie_mode_set(struct jh7110_pcie_phy *data) ++{ ++ u32 val; ++ ++ /* default is PCIe mode */ ++ if (!data->stg_syscon || !data->sys_syscon) ++ return; ++ ++ regmap_update_bits(data->stg_syscon, data->stg_pcie_mode, ++ PCIE_PHY_MODE_MASK, 0); ++ regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, ++ PCIE_USB3_BUS_WIDTH_MASK, ++ PCIE_USB3_BUS_WIDTH); ++ regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, ++ PCIE_USB3_PHY_ENABLE, 0); ++ ++ regmap_update_bits(data->sys_syscon, data->sys_phy_connect, ++ USB_PDRSTN_SPLIT, 0); ++ ++ val = readl(data->regs + PCIE_USB3_PHY_PLL_CTL_OFF); ++ val &= ~PCIE_USB3_PHY_ENABLE; ++ writel(val, data->regs + PCIE_USB3_PHY_PLL_CTL_OFF); ++} ++ ++static void phy_kvco_gain_set(struct jh7110_pcie_phy *phy) ++{ ++ /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */ ++ writel(PHY_KVCO_FINE_TUNE_LEVEL, phy->regs + PCIE_KVCO_LEVEL_OFF); ++ writel(PHY_KVCO_FINE_TUNE_SIGNALS, phy->regs + PCIE_KVCO_TUNE_SIGNAL_OFF); ++} ++ ++static int jh7110_pcie_phy_set_mode(struct phy *_phy, ++ enum phy_mode mode, int submode) ++{ ++ struct jh7110_pcie_phy *phy = phy_get_drvdata(_phy); ++ int ret; ++ ++ if (mode == phy->mode) ++ return 0; ++ ++ switch (mode) { ++ case PHY_MODE_USB_HOST: ++ case PHY_MODE_USB_DEVICE: ++ case PHY_MODE_USB_OTG: ++ ret = phy_usb3_mode_set(phy); ++ if (ret) ++ return ret; ++ break; ++ case PHY_MODE_PCIE: ++ phy_pcie_mode_set(phy); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ dev_dbg(&_phy->dev, "Changing phy mode to %d\n", mode); ++ phy->mode = mode; ++ ++ return 0; ++} ++ ++static const struct phy_ops jh7110_pcie_phy_ops = { ++ .set_mode = jh7110_pcie_phy_set_mode, ++ .owner = THIS_MODULE, ++}; ++ ++static int jh7110_pcie_phy_probe(struct platform_device *pdev) ++{ ++ struct jh7110_pcie_phy *phy; ++ struct device *dev = &pdev->dev; ++ struct phy_provider *phy_provider; ++ u32 args[2]; ++ ++ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); ++ if (!phy) ++ return -ENOMEM; ++ ++ phy->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(phy->regs)) ++ return PTR_ERR(phy->regs); ++ ++ phy->phy = devm_phy_create(dev, NULL, &jh7110_pcie_phy_ops); ++ if (IS_ERR(phy->phy)) ++ return dev_err_probe(dev, PTR_ERR(phy->regs), ++ "Failed to map phy base\n"); ++ ++ phy->sys_syscon = ++ syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, ++ "starfive,sys-syscon", ++ 1, args); ++ ++ if (!IS_ERR_OR_NULL(phy->sys_syscon)) ++ phy->sys_phy_connect = args[0]; ++ else ++ phy->sys_syscon = NULL; ++ ++ phy->stg_syscon = ++ syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, ++ "starfive,stg-syscon", ++ 2, args); ++ ++ if (!IS_ERR_OR_NULL(phy->stg_syscon)) { ++ phy->stg_pcie_mode = args[0]; ++ phy->stg_pcie_usb = args[1]; ++ } else { ++ phy->stg_syscon = NULL; ++ } ++ ++ phy_kvco_gain_set(phy); ++ ++ phy_set_drvdata(phy->phy, phy); ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct of_device_id jh7110_pcie_phy_of_match[] = { ++ { .compatible = "starfive,jh7110-pcie-phy" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, jh7110_pcie_phy_of_match); ++ ++static struct platform_driver jh7110_pcie_phy_driver = { ++ .probe = jh7110_pcie_phy_probe, ++ .driver = { ++ .of_match_table = jh7110_pcie_phy_of_match, ++ .name = "jh7110-pcie-phy", ++ } ++}; ++module_platform_driver(jh7110_pcie_phy_driver); ++ ++MODULE_DESCRIPTION("StarFive JH7110 PCIe 2.0 PHY driver"); ++MODULE_AUTHOR("Minda Chen "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0091-dt-bindings-usb-Add-StarFive-JH7110-USB-controller.patch b/target/linux/starfive/patches-6.1/0091-dt-bindings-usb-Add-StarFive-JH7110-USB-controller.patch new file mode 100644 index 0000000000..8a7575094c --- /dev/null +++ b/target/linux/starfive/patches-6.1/0091-dt-bindings-usb-Add-StarFive-JH7110-USB-controller.patch @@ -0,0 +1,135 @@ +From 6a2392c96041d0599d33799a9aedbcdbfb4030b6 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 May 2023 19:27:48 +0800 +Subject: [PATCH 091/122] dt-bindings: usb: Add StarFive JH7110 USB controller + +StarFive JH7110 platforms USB have a wrapper module around +the Cadence USBSS-DRD controller. Add binding information doc +for that. + +Signed-off-by: Minda Chen +Reviewed-by: Peter Chen +Reviewed-by: Hal Feng +--- + .../bindings/usb/starfive,jh7110-usb.yaml | 115 ++++++++++++++++++ + 1 file changed, 115 insertions(+) + create mode 100644 Documentation/devicetree/bindings/usb/starfive,jh7110-usb.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/usb/starfive,jh7110-usb.yaml +@@ -0,0 +1,115 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/usb/starfive,jh7110-usb.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 wrapper module for the Cadence USBSS-DRD controller ++ ++maintainers: ++ - Minda Chen ++ ++properties: ++ compatible: ++ const: starfive,jh7110-usb ++ ++ ranges: true ++ ++ starfive,stg-syscon: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ items: ++ - items: ++ - description: phandle to System Register Controller stg_syscon node. ++ - description: dr mode register offset of STG_SYSCONSAIF__SYSCFG register for USB. ++ description: ++ The phandle to System Register Controller syscon node and the offset ++ of STG_SYSCONSAIF__SYSCFG register for USB. ++ ++ dr_mode: ++ enum: [host, otg, peripheral] ++ ++ "#address-cells": ++ enum: [1, 2] ++ ++ "#size-cells": ++ enum: [1, 2] ++ ++ clocks: ++ items: ++ - description: link power management clock ++ - description: standby clock ++ - description: APB clock ++ - description: AXI clock ++ - description: UTMI APB clock ++ ++ clock-names: ++ items: ++ - const: lpm ++ - const: stb ++ - const: apb ++ - const: axi ++ - const: utmi_apb ++ ++ resets: ++ items: ++ - description: Power up reset ++ - description: APB clock reset ++ - description: AXI clock reset ++ - description: UTMI APB clock reset ++ ++ reset-names: ++ items: ++ - const: pwrup ++ - const: apb ++ - const: axi ++ - const: utmi_apb ++ ++patternProperties: ++ "^usb@[0-9a-f]+$": ++ $ref: cdns,usb3.yaml# ++ description: Required child node ++ ++required: ++ - compatible ++ - ranges ++ - starfive,stg-syscon ++ - '#address-cells' ++ - '#size-cells' ++ - dr_mode ++ - clocks ++ - resets ++ ++additionalProperties: false ++ ++examples: ++ - | ++ usb@10100000 { ++ compatible = "starfive,jh7110-usb"; ++ ranges = <0x0 0x10100000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ starfive,stg-syscon = <&stg_syscon 0x4>; ++ clocks = <&syscrg 4>, ++ <&stgcrg 5>, ++ <&stgcrg 1>, ++ <&stgcrg 3>, ++ <&stgcrg 2>; ++ clock-names = "lpm", "stb", "apb", "axi", "utmi_apb"; ++ resets = <&stgcrg 10>, ++ <&stgcrg 8>, ++ <&stgcrg 7>, ++ <&stgcrg 9>; ++ reset-names = "pwrup", "apb", "axi", "utmi_apb"; ++ dr_mode = "host"; ++ ++ usb@0 { ++ compatible = "cdns,usb3"; ++ reg = <0x0 0x10000>, ++ <0x10000 0x10000>, ++ <0x20000 0x10000>; ++ reg-names = "otg", "xhci", "dev"; ++ interrupts = <100>, <108>, <110>; ++ interrupt-names = "host", "peripheral", "otg"; ++ maximum-speed = "super-speed"; ++ }; ++ }; diff --git a/target/linux/starfive/patches-6.1/0092-dt-bindings-qspi-cdns-qspi-nor-constrain-minItems-ma.patch b/target/linux/starfive/patches-6.1/0092-dt-bindings-qspi-cdns-qspi-nor-constrain-minItems-ma.patch new file mode 100644 index 0000000000..650545cf3c --- /dev/null +++ b/target/linux/starfive/patches-6.1/0092-dt-bindings-qspi-cdns-qspi-nor-constrain-minItems-ma.patch @@ -0,0 +1,78 @@ +From 464fa29e8f3fb2c209647efbb365470b35daec38 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Thu, 2 Mar 2023 18:52:20 +0800 +Subject: [PATCH 092/122] dt-bindings: qspi: cdns,qspi-nor: constrain + minItems/maxItems of resets + +The QSPI controller needs three reset items to work properly on JH7110 SoC, +so there is need to change the maxItems's value to 3 and add minItems +whose value is equal to 2. Other platforms do not have this constraint. + +Signed-off-by: William Qiu +--- + .../bindings/spi/cdns,qspi-nor.yaml | 37 +++++++++++++++++-- + 1 file changed, 33 insertions(+), 4 deletions(-) + +--- a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml ++++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +@@ -19,6 +19,33 @@ allOf: + then: + required: + - power-domains ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: starfive,jh7110-qspi ++ then: ++ properties: ++ resets: ++ minItems: 2 ++ maxItems: 3 ++ ++ reset-names: ++ minItems: 2 ++ maxItems: 3 ++ items: ++ enum: [ qspi, qspi-ocp, rstc_ref ] ++ ++ else: ++ properties: ++ resets: ++ maxItems: 2 ++ ++ reset-names: ++ minItems: 1 ++ maxItems: 2 ++ items: ++ enum: [ qspi, qspi-ocp ] + + properties: + compatible: +@@ -30,6 +57,7 @@ properties: + - intel,lgm-qspi + - xlnx,versal-ospi-1.0 + - intel,socfpga-qspi ++ - starfive,jh7110-qspi + - const: cdns,qspi-nor + - const: cdns,qspi-nor + +@@ -79,13 +107,14 @@ properties: + maxItems: 1 + + resets: +- maxItems: 2 ++ minItems: 2 ++ maxItems: 3 + + reset-names: +- minItems: 1 +- maxItems: 2 ++ minItems: 2 ++ maxItems: 3 + items: +- enum: [ qspi, qspi-ocp ] ++ enum: [ qspi, qspi-ocp, rstc_ref ] + + required: + - compatible diff --git a/target/linux/starfive/patches-6.1/0093-usb-cdns3-Add-StarFive-JH7110-USB-driver.patch b/target/linux/starfive/patches-6.1/0093-usb-cdns3-Add-StarFive-JH7110-USB-driver.patch new file mode 100644 index 0000000000..2431dc45dd --- /dev/null +++ b/target/linux/starfive/patches-6.1/0093-usb-cdns3-Add-StarFive-JH7110-USB-driver.patch @@ -0,0 +1,298 @@ +From 27c75f360a76084ee6a249876483cfa8d0bedd65 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 May 2023 19:27:49 +0800 +Subject: [PATCH 093/122] usb: cdns3: Add StarFive JH7110 USB driver + +Adds Specific Glue layer to support USB peripherals on +StarFive JH7110 SoC. +There is a Cadence USB3 core for JH7110 SoCs, the cdns +core is the child of this USB wrapper module device. + +Signed-off-by: Minda Chen +Acked-by: Peter Chen +--- + drivers/usb/cdns3/Kconfig | 11 ++ + drivers/usb/cdns3/Makefile | 1 + + drivers/usb/cdns3/cdns3-starfive.c | 246 +++++++++++++++++++++++++++++ + 3 files changed, 258 insertions(+) + create mode 100644 drivers/usb/cdns3/cdns3-starfive.c + +--- a/drivers/usb/cdns3/Kconfig ++++ b/drivers/usb/cdns3/Kconfig +@@ -78,6 +78,17 @@ config USB_CDNS3_IMX + + For example, imx8qm and imx8qxp. + ++config USB_CDNS3_STARFIVE ++ tristate "Cadence USB3 support on StarFive SoC platforms" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ help ++ Say 'Y' or 'M' here if you are building for StarFive SoCs ++ platforms that contain Cadence USB3 controller core. ++ ++ e.g. JH7110. ++ ++ If you choose to build this driver as module it will ++ be dynamically linked and module will be called cdns3-starfive.ko + endif + + if USB_CDNS_SUPPORT +--- a/drivers/usb/cdns3/Makefile ++++ b/drivers/usb/cdns3/Makefile +@@ -24,6 +24,7 @@ endif + obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o + obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o + obj-$(CONFIG_USB_CDNS3_IMX) += cdns3-imx.o ++obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o + + cdnsp-udc-pci-y := cdnsp-pci.o + +--- /dev/null ++++ b/drivers/usb/cdns3/cdns3-starfive.c +@@ -0,0 +1,246 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * ++ * Author: Minda Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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) ++ ++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) ++{ ++ enum usb_dr_mode mode; ++ ++ regmap_update_bits(data->stg_syscon, data->stg_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); ++ ++ 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); ++ 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); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int cdns_clk_rst_init(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"); ++ ++ ret = reset_control_deassert(data->resets); ++ if (ret) { ++ dev_err(data->dev, "failed to reset clocks\n"); ++ goto err_clk_init; ++ } ++ ++ return ret; ++ ++err_clk_init: ++ clk_bulk_disable_unprepare(data->num_clks, data->clks); ++ return ret; ++} ++ ++static void cdns_clk_rst_deinit(struct cdns_starfive *data) ++{ ++ reset_control_assert(data->resets); ++ clk_bulk_disable_unprepare(data->num_clks, data->clks); ++} ++ ++static int cdns_starfive_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct cdns_starfive *data; ++ unsigned int args; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ 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, ++ "Failed to get clocks\n"); ++ ++ data->resets = devm_reset_control_array_get_exclusive(data->dev); ++ if (IS_ERR(data->resets)) ++ return dev_err_probe(data->dev, PTR_ERR(data->resets), ++ "Failed to get resets"); ++ ++ cdns_mode_init(pdev, data); ++ ret = cdns_clk_rst_init(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; ++ } ++ ++ device_set_wakeup_capable(dev, true); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ platform_set_drvdata(pdev, data); ++ ++ return 0; ++} ++ ++static int cdns_starfive_remove_core(struct device *dev, void *c) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ ++ platform_device_unregister(pdev); ++ ++ return 0; ++} ++ ++static int cdns_starfive_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct cdns_starfive *data = dev_get_drvdata(dev); ++ ++ pm_runtime_get_sync(dev); ++ device_for_each_child(dev, NULL, cdns_starfive_remove_core); ++ ++ pm_runtime_disable(dev); ++ pm_runtime_put_noidle(dev); ++ cdns_clk_rst_deinit(data); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int cdns_starfive_runtime_resume(struct device *dev) ++{ ++ struct cdns_starfive *data = dev_get_drvdata(dev); ++ ++ return clk_bulk_prepare_enable(data->num_clks, data->clks); ++} ++ ++static int cdns_starfive_runtime_suspend(struct device *dev) ++{ ++ struct cdns_starfive *data = dev_get_drvdata(dev); ++ ++ clk_bulk_disable_unprepare(data->num_clks, data->clks); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cdns_starfive_resume(struct device *dev) ++{ ++ struct cdns_starfive *data = dev_get_drvdata(dev); ++ ++ return cdns_clk_rst_init(data); ++} ++ ++static int cdns_starfive_suspend(struct device *dev) ++{ ++ struct cdns_starfive *data = dev_get_drvdata(dev); ++ ++ cdns_clk_rst_deinit(data); ++ ++ return 0; ++} ++#endif ++#endif ++ ++static const struct dev_pm_ops cdns_starfive_pm_ops = { ++ SET_RUNTIME_PM_OPS(cdns_starfive_runtime_suspend, ++ cdns_starfive_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(cdns_starfive_suspend, cdns_starfive_resume) ++}; ++ ++static const struct of_device_id cdns_starfive_of_match[] = { ++ { .compatible = "starfive,jh7110-usb", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, cdns_starfive_of_match); ++ ++static struct platform_driver cdns_starfive_driver = { ++ .probe = cdns_starfive_probe, ++ .remove = cdns_starfive_remove, ++ .driver = { ++ .name = "cdns3-starfive", ++ .of_match_table = cdns_starfive_of_match, ++ .pm = &cdns_starfive_pm_ops, ++ }, ++}; ++module_platform_driver(cdns_starfive_driver); ++ ++MODULE_ALIAS("platform:cdns3-starfive"); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Cadence USB3 StarFive Glue Layer"); diff --git a/target/linux/starfive/patches-6.1/0094-dt-binding-pci-add-JH7110-PCIe-dt-binding-documents.patch b/target/linux/starfive/patches-6.1/0094-dt-binding-pci-add-JH7110-PCIe-dt-binding-documents.patch new file mode 100644 index 0000000000..150fef8eb4 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0094-dt-binding-pci-add-JH7110-PCIe-dt-binding-documents.patch @@ -0,0 +1,181 @@ +From 3d555cfd72df1a02849565f281149d321e0f8425 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 6 Apr 2023 19:11:40 +0800 +Subject: [PATCH 094/122] dt-binding: pci: add JH7110 PCIe dt-binding + documents. + +Add PCIe controller driver dt-binding documents +for StarFive JH7110 SoC platform. + +Signed-off-by: Minda Chen +--- + .../bindings/pci/starfive,jh7110-pcie.yaml | 163 ++++++++++++++++++ + 1 file changed, 163 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml +@@ -0,0 +1,163 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pci/starfive,jh7110-pcie.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7110 PCIe 2.0 host controller ++ ++maintainers: ++ - Minda Chen ++ ++allOf: ++ - $ref: /schemas/pci/pci-bus.yaml# ++ - $ref: /schemas/interrupt-controller/msi-controller.yaml# ++ ++properties: ++ compatible: ++ const: starfive,jh7110-pcie ++ ++ reg: ++ maxItems: 2 ++ ++ reg-names: ++ items: ++ - const: reg ++ - const: config ++ ++ msi-parent: true ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 4 ++ ++ clock-names: ++ items: ++ - const: noc ++ - const: tl ++ - const: axi_mst0 ++ - const: apb ++ ++ resets: ++ items: ++ - description: AXI MST0 reset ++ - description: AXI SLAVE reset ++ - description: AXI SLAVE0 reset ++ - description: PCIE BRIDGE reset ++ - description: PCIE CORE reset ++ - description: PCIE APB reset ++ ++ reset-names: ++ items: ++ - const: mst0 ++ - const: slv0 ++ - const: slv ++ - const: brg ++ - const: core ++ - const: apb ++ ++ starfive,stg-syscon: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ items: ++ items: ++ - description: phandle to System Register Controller stg_syscon node. ++ - description: register0 offset of STG_SYSCONSAIF__SYSCFG register for PCIe. ++ - description: register1 offset of STG_SYSCONSAIF__SYSCFG register for PCIe. ++ - description: register2 offset of STG_SYSCONSAIF__SYSCFG register for PCIe. ++ - description: register3 offset of STG_SYSCONSAIF__SYSCFG register for PCIe. ++ description: ++ The phandle to System Register Controller syscon node and the offset ++ of STG_SYSCONSAIF__SYSCFG register for PCIe. Total 4 regsisters offset ++ for PCIe. ++ ++ pwren-gpios: ++ description: Should specify the GPIO for controlling the PCI bus device power on. ++ maxItems: 1 ++ ++ reset-gpios: ++ maxItems: 1 ++ ++ phys: ++ maxItems: 1 ++ ++ interrupt-controller: ++ type: object ++ properties: ++ '#address-cells': ++ const: 0 ++ ++ '#interrupt-cells': ++ const: 1 ++ ++ interrupt-controller: true ++ ++ required: ++ - '#address-cells' ++ - '#interrupt-cells' ++ - interrupt-controller ++ ++ additionalProperties: false ++ ++required: ++ - reg ++ - reg-names ++ - "#interrupt-cells" ++ - interrupts ++ - interrupt-map-mask ++ - interrupt-map ++ - clocks ++ - clock-names ++ - resets ++ - msi-controller ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ bus { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ pcie0: pcie@2B000000 { ++ compatible = "starfive,jh7110-pcie"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ reg = <0x0 0x2B000000 0x0 0x1000000>, ++ <0x9 0x40000000 0x0 0x10000000>; ++ reg-names = "reg", "config"; ++ device_type = "pci"; ++ starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130 0x1b8>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>, ++ <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>; ++ interrupt-parent = <&plic>; ++ interrupts = <56>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>, ++ <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>, ++ <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>, ++ <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>; ++ msi-parent = <&pcie0>; ++ msi-controller; ++ clocks = <&syscrg 86>, ++ <&stgcrg 10>, ++ <&stgcrg 8>, ++ <&stgcrg 9>; ++ clock-names = "noc", "tl", "axi_mst0", "apb"; ++ resets = <&stgcrg 11>, ++ <&stgcrg 12>, ++ <&stgcrg 13>, ++ <&stgcrg 14>, ++ <&stgcrg 15>, ++ <&stgcrg 16>; ++ ++ pcie_intc0: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; ++ }; diff --git a/target/linux/starfive/patches-6.1/0095-spi-cadence-quadspi-Add-support-for-StarFive-JH7110-.patch b/target/linux/starfive/patches-6.1/0095-spi-cadence-quadspi-Add-support-for-StarFive-JH7110-.patch new file mode 100644 index 0000000000..de701baaa9 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0095-spi-cadence-quadspi-Add-support-for-StarFive-JH7110-.patch @@ -0,0 +1,79 @@ +From a3749d68d81488ae07878393485278eab24a5818 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Thu, 2 Mar 2023 18:52:21 +0800 +Subject: [PATCH 095/122] spi: cadence-quadspi: Add support for StarFive JH7110 + QSPI + +Add QSPI reset operation in device probe and add RISCV support to +QUAD SPI Kconfig. + +Co-developed-by: Ziv Xu +Signed-off-by: Ziv Xu +Signed-off-by: William Qiu +--- + drivers/spi/Kconfig | 2 +- + drivers/spi/spi-cadence-quadspi.c | 21 ++++++++++++++++++++- + 2 files changed, 21 insertions(+), 2 deletions(-) + +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -230,7 +230,7 @@ config SPI_CADENCE + + config SPI_CADENCE_QUADSPI + tristate "Cadence Quad SPI controller" +- depends on OF && (ARM || ARM64 || X86 || COMPILE_TEST) ++ depends on OF && (ARM || ARM64 || X86 || RISCV || COMPILE_TEST) + help + Enable support for the Cadence Quad SPI Flash controller. + +--- a/drivers/spi/spi-cadence-quadspi.c ++++ b/drivers/spi/spi-cadence-quadspi.c +@@ -1575,7 +1575,7 @@ static int cqspi_setup_flash(struct cqsp + static int cqspi_probe(struct platform_device *pdev) + { + const struct cqspi_driver_platdata *ddata; +- struct reset_control *rstc, *rstc_ocp; ++ struct reset_control *rstc, *rstc_ocp, *rstc_ref; + struct device *dev = &pdev->dev; + struct spi_master *master; + struct resource *res_ahb; +@@ -1668,6 +1668,17 @@ static int cqspi_probe(struct platform_d + goto probe_reset_failed; + } + ++ if (of_device_is_compatible(pdev->dev.of_node, "starfive,jh7110-qspi")) { ++ rstc_ref = devm_reset_control_get_optional_exclusive(dev, "rstc_ref"); ++ if (IS_ERR(rstc_ref)) { ++ ret = PTR_ERR(rstc_ref); ++ dev_err(dev, "Cannot get QSPI REF reset.\n"); ++ goto probe_reset_failed; ++ } ++ reset_control_assert(rstc_ref); ++ reset_control_deassert(rstc_ref); ++ } ++ + reset_control_assert(rstc); + reset_control_deassert(rstc); + +@@ -1827,6 +1838,10 @@ static const struct cqspi_driver_platdat + .get_dma_status = cqspi_get_versal_dma_status, + }; + ++static const struct cqspi_driver_platdata jh7110_qspi = { ++ .quirks = CQSPI_DISABLE_DAC_MODE, ++}; ++ + static const struct of_device_id cqspi_dt_ids[] = { + { + .compatible = "cdns,qspi-nor", +@@ -1852,6 +1867,10 @@ static const struct of_device_id cqspi_d + .compatible = "intel,socfpga-qspi", + .data = &socfpga_qspi, + }, ++ { ++ .compatible = "starfive,jh7110-qspi", ++ .data = &jh7110_qspi, ++ }, + { /* end of table */ } + }; + diff --git a/target/linux/starfive/patches-6.1/0096-pcie-starfive-add-StarFive-JH7110-PCIe-driver.patch b/target/linux/starfive/patches-6.1/0096-pcie-starfive-add-StarFive-JH7110-PCIe-driver.patch new file mode 100644 index 0000000000..ffd413c088 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0096-pcie-starfive-add-StarFive-JH7110-PCIe-driver.patch @@ -0,0 +1,1004 @@ +From e0cd43bcbc9b74343e529fde66a3ec20b533ac61 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 6 Apr 2023 19:11:41 +0800 +Subject: [PATCH 096/122] pcie: starfive: add StarFive JH7110 PCIe driver. + +Add PCIe controller driver for StarFive JH7110 +SoC platform. The PCIe controller is PCIe 2.0, single lane. + +Signed-off-by: Minda Chen +--- + drivers/pci/controller/Kconfig | 8 + + drivers/pci/controller/Makefile | 1 + + drivers/pci/controller/pcie-starfive.c | 958 +++++++++++++++++++++++++ + 3 files changed, 967 insertions(+) + create mode 100644 drivers/pci/controller/pcie-starfive.c + +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -343,6 +343,14 @@ config PCIE_MT7621 + help + This selects a driver for the MediaTek MT7621 PCIe Controller. + ++config PCIE_STARFIVE ++ tristate "StarFive JH7110 PCIe controller" ++ depends on PCI_MSI && OF ++ select PCI_MSI_IRQ_DOMAIN ++ help ++ Say 'Y' here if you want kernel to support the StarFive JH7110 ++ PCIe Host driver. ++ + source "drivers/pci/controller/dwc/Kconfig" + source "drivers/pci/controller/mobiveil/Kconfig" + source "drivers/pci/controller/cadence/Kconfig" +--- a/drivers/pci/controller/Makefile ++++ b/drivers/pci/controller/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_PCI_LOONGSON) += pci-loongs + obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o + obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o + obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o ++obj-$(CONFIG_PCIE_STARFIVE) += pcie-starfive.o + + # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW + obj-y += dwc/ +--- /dev/null ++++ b/drivers/pci/controller/pcie-starfive.c +@@ -0,0 +1,958 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * PCIe host controller driver for Starfive JH7110 Soc. ++ * ++ * Based on pcie-altera.c, pcie-altera-msi.c. ++ * ++ * Copyright (C) StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../pci.h" ++ ++#define IMASK_LOCAL 0x180 ++#define ISTATUS_LOCAL 0x184 ++#define IMSI_ADDR 0x190 ++#define ISTATUS_MSI 0x194 ++#define GEN_SETTINGS 0x80 ++#define PCIE_PCI_IDS 0x9C ++#define PCIE_WINROM 0xFC ++#define PMSG_SUPPORT_RX 0x3F0 ++ ++#define PCI_MISC 0xB4 ++ ++#define RP_ENABLE 1 ++ ++#define IDS_CLASS_CODE_SHIFT 16 ++ ++#define DATA_LINK_ACTIVE BIT(5) ++#define PREF_MEM_WIN_64_SUPPORT BIT(3) ++#define PMSG_LTR_SUPPORT BIT(2) ++#define LINK_SPEED_GEN2 BIT(12) ++#define PHY_FUNCTION_DIS BIT(15) ++#define PCIE_FUNC_NUM 4 ++#define PHY_FUNC_SHIFT 9 ++ ++#define XR3PCI_ATR_AXI4_SLV0 0x800 ++#define XR3PCI_ATR_SRC_ADDR_LOW 0x0 ++#define XR3PCI_ATR_SRC_ADDR_HIGH 0x4 ++#define XR3PCI_ATR_TRSL_ADDR_LOW 0x8 ++#define XR3PCI_ATR_TRSL_ADDR_HIGH 0xc ++#define XR3PCI_ATR_TRSL_PARAM 0x10 ++#define XR3PCI_ATR_TABLE_OFFSET 0x20 ++#define XR3PCI_ATR_MAX_TABLE_NUM 8 ++ ++#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT 1 ++#define XR3PCI_ATR_SRC_ADDR_MASK GENMASK(31, 12) ++#define XR3PCI_ATR_TRSL_ADDR_MASK GENMASK(31, 12) ++#define XR3PCI_ECAM_SIZE BIT(28) ++#define XR3PCI_ATR_TRSL_DIR BIT(22) ++/* IDs used in the XR3PCI_ATR_TRSL_PARAM */ ++#define XR3PCI_ATR_TRSLID_PCIE_MEMORY 0x0 ++#define XR3PCI_ATR_TRSLID_PCIE_CONFIG 0x1 ++ ++#define INT_AXI_POST_ERROR BIT(16) ++#define INT_AXI_FETCH_ERROR BIT(17) ++#define INT_AXI_DISCARD_ERROR BIT(18) ++#define INT_PCIE_POST_ERROR BIT(20) ++#define INT_PCIE_FETCH_ERROR BIT(21) ++#define INT_PCIE_DISCARD_ERROR BIT(22) ++#define INT_ERRORS (INT_AXI_POST_ERROR | INT_AXI_FETCH_ERROR | \ ++ INT_AXI_DISCARD_ERROR | INT_PCIE_POST_ERROR | \ ++ INT_PCIE_FETCH_ERROR | INT_PCIE_DISCARD_ERROR) ++ ++#define INTA_OFFSET 24 ++#define INTA BIT(24) ++#define INTB BIT(25) ++#define INTC BIT(26) ++#define INTD BIT(27) ++#define INT_MSI BIT(28) ++#define INT_INTX_MASK (INTA | INTB | INTC | INTD) ++#define INT_MASK (INT_INTX_MASK | INT_MSI | INT_ERRORS) ++ ++#define INT_PCI_MSI_NR 32 ++ ++/* system control */ ++#define STG_SYSCON_K_RP_NEP BIT(8) ++#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK GENMASK(22, 8) ++#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 8 ++#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK GENMASK(14, 0) ++#define STG_SYSCON_CLKREQ BIT(22) ++#define STG_SYSCON_CKREF_SRC_SHIFT 18 ++#define STG_SYSCON_CKREF_SRC_MASK GENMASK(19, 18) ++ ++/* MSI information */ ++struct jh7110_pcie_msi { ++ DECLARE_BITMAP(used, INT_PCI_MSI_NR); ++ struct irq_domain *msi_domain; ++ struct irq_domain *inner_domain; ++ /* Protect bitmap variable */ ++ struct mutex lock; ++}; ++ ++struct starfive_jh7110_pcie { ++ struct platform_device *pdev; ++ void __iomem *reg_base; ++ void __iomem *config_base; ++ phys_addr_t config_phyaddr; ++ struct regmap *reg_syscon; ++ struct phy *phy; ++ u32 stg_arfun; ++ u32 stg_awfun; ++ u32 stg_rp_nep; ++ u32 stg_lnksta; ++ int irq; ++ struct irq_domain *legacy_irq_domain; ++ struct pci_host_bridge *bridge; ++ struct jh7110_pcie_msi msi; ++ struct reset_control *resets; ++ struct clk_bulk_data *clks; ++ int num_clks; ++ int atr_table_num; ++ struct gpio_desc *power_gpio; ++ struct gpio_desc *reset_gpio; ++}; ++ ++/* ++ * StarFive PCIe port uses BAR0-BAR1 of RC's configuration space as ++ * the translation from PCI bus to native BUS. Entire DDR region ++ * is mapped into PCIe space using these registers, so it can be ++ * reached by DMA from EP devices. The BAR0/1 of bridge should be ++ * hidden during enumeration to avoid the sizing and resource allocation ++ * by PCIe core. ++ */ ++static bool starfive_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int devfn, ++ int offset) ++{ ++ if (pci_is_root_bus(bus) && (devfn == 0) ++ && ((offset == PCI_BASE_ADDRESS_0) ++ || (offset == PCI_BASE_ADDRESS_1))) ++ return true; ++ ++ return false; ++} ++ ++void __iomem *starfive_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, ++ int where) ++{ ++ struct starfive_jh7110_pcie *pcie = bus->sysdata; ++ ++ return pcie->config_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); ++} ++ ++int starfive_pcie_config_write(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 value) ++{ ++ if (starfive_pcie_hide_rc_bar(bus, devfn, where)) ++ return PCIBIOS_BAD_REGISTER_NUMBER; ++ ++ return pci_generic_config_write(bus, devfn, where, size, value); ++} ++ ++static void starfive_pcie_handle_msi_irq(struct starfive_jh7110_pcie *pcie) ++{ ++ struct jh7110_pcie_msi *msi = &pcie->msi; ++ u32 bit; ++ u32 virq; ++ unsigned long status = readl(pcie->reg_base + ISTATUS_MSI); ++ ++ for_each_set_bit(bit, &status, INT_PCI_MSI_NR) { ++ /* Clear interrupts */ ++ writel(1 << bit, pcie->reg_base + ISTATUS_MSI); ++ virq = irq_find_mapping(msi->inner_domain, bit); ++ if (virq) { ++ if (test_bit(bit, msi->used)) ++ generic_handle_irq(virq); ++ else ++ dev_err(&pcie->pdev->dev, ++ "Unhandled MSI, MSI%d virq %d\n", bit, ++ virq); ++ } else ++ dev_err(&pcie->pdev->dev, "Unexpected MSI, MSI%d\n", ++ bit); ++ } ++ writel(INT_MSI, pcie->reg_base + ISTATUS_LOCAL); ++} ++ ++static void starfive_pcie_handle_intx_irq(struct starfive_jh7110_pcie *pcie, ++ unsigned long status) ++{ ++ u32 bit; ++ u32 virq; ++ ++ status >>= INTA_OFFSET; ++ ++ for_each_set_bit(bit, &status, PCI_NUM_INTX) { ++ /* Clear interrupts */ ++ writel(1 << (bit + INTA_OFFSET), pcie->reg_base + ISTATUS_LOCAL); ++ ++ virq = irq_find_mapping(pcie->legacy_irq_domain, bit); ++ if (virq) ++ generic_handle_irq(virq); ++ else ++ dev_err(&pcie->pdev->dev, ++ "unexpected IRQ, INT%d\n", bit); ++ } ++} ++ ++static void starfive_pcie_handle_errors_irq(struct starfive_jh7110_pcie *pcie, u32 status) ++{ ++ if (status & INT_AXI_POST_ERROR) ++ dev_err(&pcie->pdev->dev, "AXI post error\n"); ++ if (status & INT_AXI_FETCH_ERROR) ++ dev_err(&pcie->pdev->dev, "AXI fetch error\n"); ++ if (status & INT_AXI_DISCARD_ERROR) ++ dev_err(&pcie->pdev->dev, "AXI discard error\n"); ++ if (status & INT_PCIE_POST_ERROR) ++ dev_err(&pcie->pdev->dev, "PCIe post error\n"); ++ if (status & INT_PCIE_FETCH_ERROR) ++ dev_err(&pcie->pdev->dev, "PCIe fetch error\n"); ++ if (status & INT_PCIE_DISCARD_ERROR) ++ dev_err(&pcie->pdev->dev, "PCIe discard error\n"); ++ ++ writel(INT_ERRORS, pcie->reg_base + ISTATUS_LOCAL); ++} ++ ++static void starfive_pcie_isr(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct starfive_jh7110_pcie *pcie; ++ u32 status; ++ ++ chained_irq_enter(chip, desc); ++ pcie = irq_desc_get_handler_data(desc); ++ ++ status = readl(pcie->reg_base + ISTATUS_LOCAL); ++ while ((status = (readl(pcie->reg_base + ISTATUS_LOCAL) & INT_MASK))) { ++ if (status & INT_INTX_MASK) ++ starfive_pcie_handle_intx_irq(pcie, status); ++ ++ if (status & INT_MSI) ++ starfive_pcie_handle_msi_irq(pcie); ++ ++ if (status & INT_ERRORS) ++ starfive_pcie_handle_errors_irq(pcie, status); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++#ifdef CONFIG_PCI_MSI ++static struct irq_chip starfive_pcie_msi_irq_chip = { ++ .name = "StarFive PCIe MSI", ++ .irq_mask = pci_msi_mask_irq, ++ .irq_unmask = pci_msi_unmask_irq, ++}; ++ ++static struct msi_domain_info starfive_pcie_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ++ MSI_FLAG_PCI_MSIX), ++ .chip = &starfive_pcie_msi_irq_chip, ++}; ++#endif ++ ++static void starfive_pcie_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) ++{ ++ struct starfive_jh7110_pcie *pcie = irq_data_get_irq_chip_data(data); ++ phys_addr_t msi_addr = readl(pcie->reg_base + IMSI_ADDR); ++ ++ msg->address_lo = lower_32_bits(msi_addr); ++ msg->address_hi = upper_32_bits(msi_addr); ++ msg->data = data->hwirq; ++ ++ dev_info(&pcie->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n", ++ (int)data->hwirq, msg->address_hi, msg->address_lo); ++} ++ ++static int starfive_pcie_msi_set_affinity(struct irq_data *irq_data, ++ const struct cpumask *mask, bool force) ++{ ++ return -EINVAL; ++} ++ ++static struct irq_chip starfive_irq_chip = { ++ .name = "StarFive MSI", ++ .irq_compose_msi_msg = starfive_pcie_compose_msi_msg, ++ .irq_set_affinity = starfive_pcie_msi_set_affinity, ++}; ++ ++static int starfive_pcie_msi_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *args) ++{ ++ struct starfive_jh7110_pcie *pcie = domain->host_data; ++ struct jh7110_pcie_msi *msi = &pcie->msi; ++ int bit; ++ ++ WARN_ON(nr_irqs != 1); ++ mutex_lock(&msi->lock); ++ ++ bit = find_first_zero_bit(msi->used, INT_PCI_MSI_NR); ++ if (bit >= INT_PCI_MSI_NR) { ++ mutex_unlock(&msi->lock); ++ return -ENOSPC; ++ } ++ ++ set_bit(bit, msi->used); ++ ++ irq_domain_set_info(domain, virq, bit, &starfive_irq_chip, ++ domain->host_data, handle_simple_irq, ++ NULL, NULL); ++ mutex_unlock(&msi->lock); ++ ++ return 0; ++} ++ ++static void starfive_pcie_msi_free(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs) ++{ ++ struct irq_data *data = irq_domain_get_irq_data(domain, virq); ++ struct starfive_jh7110_pcie *pcie = irq_data_get_irq_chip_data(data); ++ struct jh7110_pcie_msi *msi = &pcie->msi; ++ ++ mutex_lock(&msi->lock); ++ ++ if (!test_bit(data->hwirq, msi->used)) ++ dev_err(&pcie->pdev->dev, "Trying to free unused MSI#%lu\n", ++ data->hwirq); ++ else ++ __clear_bit(data->hwirq, msi->used); ++ ++ writel(0xffffffff, pcie->reg_base + ISTATUS_MSI); ++ mutex_unlock(&msi->lock); ++} ++ ++static const struct irq_domain_ops dev_msi_domain_ops = { ++ .alloc = starfive_pcie_msi_alloc, ++ .free = starfive_pcie_msi_free, ++}; ++ ++static void starfive_pcie_msi_free_irq_domain(struct starfive_jh7110_pcie *pcie) ++{ ++#ifdef CONFIG_PCI_MSI ++ struct jh7110_pcie_msi *msi = &pcie->msi; ++ u32 irq; ++ int i; ++ ++ for (i = 0; i < INT_PCI_MSI_NR; i++) { ++ irq = irq_find_mapping(msi->inner_domain, i); ++ if (irq > 0) ++ irq_dispose_mapping(irq); ++ } ++ ++ if (msi->msi_domain) ++ irq_domain_remove(msi->msi_domain); ++ ++ if (msi->inner_domain) ++ irq_domain_remove(msi->inner_domain); ++#endif ++} ++ ++static void starfive_pcie_free_irq_domain(struct starfive_jh7110_pcie *pcie) ++{ ++ int i; ++ u32 irq; ++ ++ /* Disable all interrupts */ ++ writel(0, pcie->reg_base + IMASK_LOCAL); ++ ++ if (pcie->legacy_irq_domain) { ++ for (i = 0; i < PCI_NUM_INTX; i++) { ++ irq = irq_find_mapping(pcie->legacy_irq_domain, i); ++ if (irq > 0) ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(pcie->legacy_irq_domain); ++ } ++ ++ if (pci_msi_enabled()) ++ starfive_pcie_msi_free_irq_domain(pcie); ++ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); ++} ++ ++static int starfive_pcie_init_msi_irq_domain(struct starfive_jh7110_pcie *pcie) ++{ ++#ifdef CONFIG_PCI_MSI ++ struct fwnode_handle *fwn = of_node_to_fwnode(pcie->pdev->dev.of_node); ++ struct jh7110_pcie_msi *msi = &pcie->msi; ++ ++ msi->inner_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR, ++ &dev_msi_domain_ops, pcie); ++ if (!msi->inner_domain) { ++ dev_err(&pcie->pdev->dev, "Failed to create dev IRQ domain\n"); ++ return -ENOMEM; ++ } ++ msi->msi_domain = pci_msi_create_irq_domain(fwn, &starfive_pcie_msi_domain_info, ++ msi->inner_domain); ++ if (!msi->msi_domain) { ++ dev_err(&pcie->pdev->dev, "Failed to create msi IRQ domain\n"); ++ irq_domain_remove(msi->inner_domain); ++ return -ENOMEM; ++ } ++#endif ++ return 0; ++} ++ ++static int starfive_pcie_enable_msi(struct starfive_jh7110_pcie *pcie, struct pci_bus *bus) ++{ ++ struct jh7110_pcie_msi *msi = &pcie->msi; ++ u32 reg; ++ ++ mutex_init(&msi->lock); ++ ++ /* Enable MSI */ ++ reg = readl(pcie->reg_base + IMASK_LOCAL); ++ reg |= INT_MSI; ++ writel(reg, pcie->reg_base + IMASK_LOCAL); ++ return 0; ++} ++ ++static int starfive_pcie_intx_map(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); ++ irq_set_chip_data(irq, domain->host_data); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops intx_domain_ops = { ++ .map = starfive_pcie_intx_map, ++ .xlate = pci_irqd_intx_xlate, ++}; ++ ++static int starfive_pcie_init_irq_domain(struct starfive_jh7110_pcie *pcie) ++{ ++ struct device *dev = &pcie->pdev->dev; ++ struct device_node *node = dev->of_node; ++ int ret; ++ ++ if (pci_msi_enabled()) { ++ ret = starfive_pcie_init_msi_irq_domain(pcie); ++ if (ret != 0) ++ return -ENOMEM; ++ } ++ ++ /* Setup INTx */ ++ pcie->legacy_irq_domain = irq_domain_add_linear(node, PCI_NUM_INTX, ++ &intx_domain_ops, pcie); ++ ++ if (!pcie->legacy_irq_domain) { ++ dev_err(dev, "Failed to get a INTx IRQ domain\n"); ++ return -ENOMEM; ++ } ++ ++ irq_set_chained_handler_and_data(pcie->irq, starfive_pcie_isr, pcie); ++ ++ return 0; ++} ++ ++static int starfive_pcie_parse_dt(struct starfive_jh7110_pcie *pcie) ++{ ++ struct resource *cfg_res; ++ struct platform_device *pdev = pcie->pdev; ++ unsigned int args[4]; ++ ++ pcie->reg_base = ++ devm_platform_ioremap_resource_byname(pdev, "reg"); ++ ++ if (IS_ERR(pcie->reg_base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pcie->reg_base), ++ "Failed to map reg memory\n"); ++ ++ cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); ++ if (!cfg_res) ++ return dev_err_probe(&pdev->dev, -ENODEV, ++ "Failed to get config memory\n"); ++ ++ pcie->config_base = devm_ioremap_resource(&pdev->dev, cfg_res); ++ if (IS_ERR(pcie->config_base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pcie->config_base), ++ "Failed to map config memory\n"); ++ ++ pcie->config_phyaddr = cfg_res->start; ++ ++ pcie->phy = devm_phy_optional_get(&pdev->dev, NULL); ++ if (IS_ERR(pcie->phy)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pcie->phy), ++ "Failed to get pcie phy\n"); ++ ++ pcie->irq = platform_get_irq(pdev, 0); ++ if (pcie->irq < 0) ++ return dev_err_probe(&pdev->dev, -EINVAL, ++ "Failed to get IRQ: %d\n", pcie->irq); ++ ++ pcie->reg_syscon = syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, ++ "starfive,stg-syscon", 4, args); ++ ++ if (IS_ERR(pcie->reg_syscon)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pcie->reg_syscon), ++ "Failed to parse starfive,stg-syscon\n"); ++ ++ pcie->stg_arfun = args[0]; ++ pcie->stg_awfun = args[1]; ++ pcie->stg_rp_nep = args[2]; ++ pcie->stg_lnksta = args[3]; ++ ++ /* Clear all interrupts */ ++ writel(0xffffffff, pcie->reg_base + ISTATUS_LOCAL); ++ writel(INT_INTX_MASK | INT_ERRORS, pcie->reg_base + IMASK_LOCAL); ++ ++ return 0; ++} ++ ++static struct pci_ops starfive_pcie_ops = { ++ .map_bus = starfive_pcie_map_bus, ++ .read = pci_generic_config_read, ++ .write = starfive_pcie_config_write, ++}; ++ ++static void starfive_pcie_set_atr_entry(struct starfive_jh7110_pcie *pcie, ++ phys_addr_t src_addr, phys_addr_t trsl_addr, ++ size_t window_size, int trsl_param) ++{ ++ void __iomem *base = ++ pcie->reg_base + XR3PCI_ATR_AXI4_SLV0; ++ ++ /* Support AXI4 Slave 0 Address Translation Tables 0-7. */ ++ if (pcie->atr_table_num >= XR3PCI_ATR_MAX_TABLE_NUM) ++ pcie->atr_table_num = XR3PCI_ATR_MAX_TABLE_NUM - 1; ++ base += XR3PCI_ATR_TABLE_OFFSET * pcie->atr_table_num; ++ pcie->atr_table_num++; ++ ++ /* ++ * X3PCI_ATR_SRC_ADDR_LOW: ++ * - bit 0: enable entry, ++ * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1) ++ * - bits 7-11: reserved ++ * - bits 12-31: start of source address ++ */ ++ writel((lower_32_bits(src_addr) & XR3PCI_ATR_SRC_ADDR_MASK) | ++ (fls(window_size) - 1) << XR3PCI_ATR_SRC_WIN_SIZE_SHIFT | 1, ++ base + XR3PCI_ATR_SRC_ADDR_LOW); ++ writel(upper_32_bits(src_addr), base + XR3PCI_ATR_SRC_ADDR_HIGH); ++ writel((lower_32_bits(trsl_addr) & XR3PCI_ATR_TRSL_ADDR_MASK), ++ base + XR3PCI_ATR_TRSL_ADDR_LOW); ++ writel(upper_32_bits(trsl_addr), base + XR3PCI_ATR_TRSL_ADDR_HIGH); ++ writel(trsl_param, base + XR3PCI_ATR_TRSL_PARAM); ++ ++ dev_info(&pcie->pdev->dev, "ATR entry: 0x%010llx %s 0x%010llx [0x%010llx] (param: 0x%06x)\n", ++ src_addr, (trsl_param & XR3PCI_ATR_TRSL_DIR) ? "<-" : "->", ++ trsl_addr, (u64)window_size, trsl_param); ++} ++ ++static int starfive_pcie_setup_windows(struct starfive_jh7110_pcie *pcie) ++{ ++ struct pci_host_bridge *bridge = pcie->bridge; ++ struct resource_entry *entry; ++ u64 pci_addr; ++ ++ resource_list_for_each_entry(entry, &bridge->windows) { ++ if (resource_type(entry->res) == IORESOURCE_MEM) { ++ pci_addr = entry->res->start - entry->offset; ++ starfive_pcie_set_atr_entry(pcie, ++ entry->res->start, pci_addr, ++ resource_size(entry->res), ++ XR3PCI_ATR_TRSLID_PCIE_MEMORY); ++ } ++ } ++ ++ return 0; ++} ++ ++static int starfive_pcie_clk_rst_init(struct starfive_jh7110_pcie *pcie) ++{ ++ int ret; ++ struct device *dev = &pcie->pdev->dev; ++ ++ pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks); ++ if (pcie->num_clks < 0) ++ return dev_err_probe(dev, -ENODEV, ++ "Failed to get pcie clocks\n"); ++ ++ ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); ++ if (ret) ++ return dev_err_probe(&pcie->pdev->dev, ret, ++ "Failed to enable clocks\n"); ++ ++ pcie->resets = devm_reset_control_array_get_exclusive(dev); ++ if (IS_ERR(pcie->resets)) { ++ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); ++ return dev_err_probe(dev, PTR_ERR(pcie->resets), ++ "Failed to get pcie resets"); ++ } ++ ++ return reset_control_deassert(pcie->resets); ++} ++ ++static void starfive_pcie_clk_rst_deinit(struct starfive_jh7110_pcie *pcie) ++{ ++ reset_control_assert(pcie->resets); ++ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); ++} ++ ++int starfive_pcie_gpio_init(struct starfive_jh7110_pcie *pcie) ++{ ++ struct device *dev = &pcie->pdev->dev; ++ ++ pcie->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); ++ if (IS_ERR_OR_NULL(pcie->reset_gpio)) { ++ dev_warn(dev, "Failed to get reset-gpio.\n"); ++ return -EINVAL; ++ } ++ ++ pcie->power_gpio = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); ++ if (IS_ERR_OR_NULL(pcie->power_gpio)) ++ pcie->power_gpio = NULL; ++ ++ return 0; ++} ++ ++static void starfive_pcie_hw_init(struct starfive_jh7110_pcie *pcie) ++{ ++ unsigned int value; ++ int i; ++ ++ if (pcie->power_gpio) ++ gpiod_set_value_cansleep(pcie->power_gpio, 1); ++ ++ if (pcie->reset_gpio) ++ gpiod_set_value_cansleep(pcie->reset_gpio, 1); ++ ++ /* Disable physical functions except #0 */ ++ for (i = 1; i < PCIE_FUNC_NUM; i++) { ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_arfun, ++ STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, ++ (i << PHY_FUNC_SHIFT) << ++ STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT); ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_awfun, ++ STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, ++ i << PHY_FUNC_SHIFT); ++ ++ value = readl(pcie->reg_base + PCI_MISC); ++ value |= PHY_FUNCTION_DIS; ++ writel(value, pcie->reg_base + PCI_MISC); ++ } ++ ++ ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_arfun, ++ STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, ++ 0); ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_awfun, ++ STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, ++ 0); ++ ++ /* Enable root port */ ++ value = readl(pcie->reg_base + GEN_SETTINGS); ++ value |= RP_ENABLE; ++ writel(value, pcie->reg_base + GEN_SETTINGS); ++ ++ /* PCIe PCI Standard Configuration Identification Settings. */ ++ value = (PCI_CLASS_BRIDGE_PCI << IDS_CLASS_CODE_SHIFT); ++ writel(value, pcie->reg_base + PCIE_PCI_IDS); ++ ++ /* ++ * The LTR message forwarding of PCIe Message Reception was set by core ++ * as default, but the forward id & addr are also need to be reset. ++ * If we do not disable LTR message forwarding here, or set a legal ++ * forwarding address, the kernel will get stuck after this driver probe. ++ * To workaround, disable the LTR message forwarding support on ++ * PCIe Message Reception. ++ */ ++ value = readl(pcie->reg_base + PMSG_SUPPORT_RX); ++ value &= ~PMSG_LTR_SUPPORT; ++ writel(value, pcie->reg_base + PMSG_SUPPORT_RX); ++ ++ /* Prefetchable memory window 64-bit addressing support */ ++ value = readl(pcie->reg_base + PCIE_WINROM); ++ value |= PREF_MEM_WIN_64_SUPPORT; ++ writel(value, pcie->reg_base + PCIE_WINROM); ++ ++ /* ++ * As the two host bridges in JH7110 soc have the same default ++ * address translation table, this cause the second root port can't ++ * access it's host bridge config space correctly. ++ * To workaround, config the ATR of host bridge config space by SW. ++ */ ++ starfive_pcie_set_atr_entry(pcie, ++ pcie->config_phyaddr, 0, ++ XR3PCI_ECAM_SIZE, ++ XR3PCI_ATR_TRSLID_PCIE_CONFIG); ++ ++ starfive_pcie_setup_windows(pcie); ++ ++ /* Ensure that PERST has been asserted for at least 100 ms */ ++ msleep(300); ++ if (pcie->reset_gpio) ++ gpiod_set_value_cansleep(pcie->reset_gpio, 0); ++} ++ ++static bool starfive_pcie_is_link_up(struct starfive_jh7110_pcie *pcie) ++{ ++ struct device *dev = &pcie->pdev->dev; ++ int ret; ++ u32 stg_reg_val; ++ ++ /* 100ms timeout value should be enough for Gen1/2 training */ ++ ret = regmap_read_poll_timeout(pcie->reg_syscon, ++ pcie->stg_lnksta, ++ stg_reg_val, ++ stg_reg_val & DATA_LINK_ACTIVE, ++ 10 * 1000, 100 * 1000); ++ ++ /* If the link is down (no device in slot), then exit. */ ++ if (ret == -ETIMEDOUT) { ++ dev_info(dev, "Port link down, exit.\n"); ++ return false; ++ } else if (ret == 0) { ++ dev_info(dev, "Port link up.\n"); ++ return true; ++ } ++ ++ dev_warn(dev, "Read stg_linksta failed.\n"); ++ ++ return false; ++} ++ ++static int starfive_pcie_enable_phy(struct device *dev, ++ struct starfive_jh7110_pcie *pcie) ++{ ++ int ret; ++ ++ if (!pcie->phy) ++ return 0; ++ ++ ret = phy_init(pcie->phy); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "failed to initialize pcie phy\n"); ++ ++ ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE); ++ if (ret) { ++ ret = dev_err_probe(dev, ret, ++ "failed to set pcie mode\n"); ++ goto err_phy_on; ++ } ++ ++ ret = phy_power_on(pcie->phy); ++ if (ret) { ++ ret = dev_err_probe(dev, ret, "failed to power on pcie phy\n"); ++ goto err_phy_on; ++ } ++ ++ return 0; ++ ++err_phy_on: ++ phy_exit(pcie->phy); ++ return ret; ++} ++ ++static void starfive_pcie_disable_phy(struct starfive_jh7110_pcie *pcie) ++{ ++ phy_power_off(pcie->phy); ++ phy_exit(pcie->phy); ++} ++ ++static int starfive_pcie_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct starfive_jh7110_pcie *pcie; ++ struct pci_bus *bus; ++ struct pci_host_bridge *bridge; ++ int ret; ++ ++ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); ++ if (!pcie) ++ return -ENOMEM; ++ ++ pcie->pdev = pdev; ++ pcie->atr_table_num = 0; ++ ++ ret = starfive_pcie_parse_dt(pcie); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, pcie); ++ ++ ret = starfive_pcie_gpio_init(pcie); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_rp_nep, ++ STG_SYSCON_K_RP_NEP, ++ STG_SYSCON_K_RP_NEP); ++ ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_awfun, ++ STG_SYSCON_CKREF_SRC_MASK, ++ 2 << STG_SYSCON_CKREF_SRC_SHIFT); ++ ++ regmap_update_bits(pcie->reg_syscon, ++ pcie->stg_awfun, ++ STG_SYSCON_CLKREQ, ++ STG_SYSCON_CLKREQ); ++ ++ ret = starfive_pcie_clk_rst_init(pcie); ++ if (ret) ++ return ret; ++ ++ ret = starfive_pcie_init_irq_domain(pcie); ++ if (ret) ++ return ret; ++ ++ bridge = devm_pci_alloc_host_bridge(dev, 0); ++ if (!bridge) ++ return -ENOMEM; ++ ++ pm_runtime_enable(&pdev->dev); ++ pm_runtime_get_sync(&pdev->dev); ++ ++ /* Set default bus ops */ ++ bridge->ops = &starfive_pcie_ops; ++ bridge->sysdata = pcie; ++ pcie->bridge = bridge; ++ ++ starfive_pcie_hw_init(pcie); ++ ++ if (starfive_pcie_is_link_up(pcie) == false) ++ goto release; ++ ++ if (IS_ENABLED(CONFIG_PCI_MSI)) { ++ ret = starfive_pcie_enable_msi(pcie, bus); ++ if (ret < 0) { ++ dev_err(dev, "Failed to enable MSI support: %d\n", ret); ++ goto release; ++ } ++ } ++ ++ ret = starfive_pcie_enable_phy(dev, pcie); ++ if (ret) ++ goto release; ++ ++ ret = pci_host_probe(bridge); ++ if (ret < 0) { ++ dev_err_probe(dev, ret, "Failed to pci host probe: %d\n", ret); ++ goto err_phy_on; ++ } ++ ++ return ret; ++ ++err_phy_on: ++ starfive_pcie_disable_phy(pcie); ++release: ++ if (pcie->power_gpio) ++ gpiod_set_value_cansleep(pcie->power_gpio, 0); ++ ++ starfive_pcie_clk_rst_deinit(pcie); ++ ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ pci_free_host_bridge(pcie->bridge); ++ platform_set_drvdata(pdev, NULL); ++ ++ return ret; ++} ++ ++static int starfive_pcie_remove(struct platform_device *pdev) ++{ ++ struct starfive_jh7110_pcie *pcie = platform_get_drvdata(pdev); ++ ++ starfive_pcie_disable_phy(pcie); ++ if (pcie->power_gpio) ++ gpiod_set_value_cansleep(pcie->power_gpio, 0); ++ starfive_pcie_free_irq_domain(pcie); ++ starfive_pcie_clk_rst_deinit(pcie); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int __maybe_unused starfive_pcie_suspend_noirq(struct device *dev) ++{ ++ struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev); ++ ++ if (!pcie) ++ return 0; ++ ++ starfive_pcie_disable_phy(pcie); ++ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); ++ ++ return 0; ++} ++ ++static int __maybe_unused starfive_pcie_resume_noirq(struct device *dev) ++{ ++ struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev); ++ int ret; ++ ++ if (!pcie) ++ return 0; ++ ++ ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to enable clocks\n"); ++ ++ ret = starfive_pcie_enable_phy(dev, pcie); ++ if (ret) ++ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); ++ ++ return ret; ++} ++ ++static const struct dev_pm_ops starfive_pcie_pm_ops = { ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(starfive_pcie_suspend_noirq, ++ starfive_pcie_resume_noirq) ++}; ++#endif ++ ++static const struct of_device_id starfive_pcie_of_match[] = { ++ { .compatible = "starfive,jh7110-pcie"}, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, starfive_pcie_of_match); ++ ++static struct platform_driver starfive_pcie_driver = { ++ .driver = { ++ .name = "pcie-starfive", ++ .of_match_table = of_match_ptr(starfive_pcie_of_match), ++#ifdef CONFIG_PM_SLEEP ++ .pm = &starfive_pcie_pm_ops, ++#endif ++ }, ++ .probe = starfive_pcie_probe, ++ .remove = starfive_pcie_remove, ++}; ++module_platform_driver(starfive_pcie_driver); ++ ++MODULE_DESCRIPTION("StarFive JH7110 PCIe host driver"); ++MODULE_AUTHOR("Mason Huo "); ++MODULE_AUTHOR("Kevin Xie "); ++MODULE_AUTHOR("Minda Chen "); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/starfive/patches-6.1/0097-cpufreq-dt-platdev-Add-JH7110-SOC-to-the-allowlist.patch b/target/linux/starfive/patches-6.1/0097-cpufreq-dt-platdev-Add-JH7110-SOC-to-the-allowlist.patch new file mode 100644 index 0000000000..cc629f06d2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0097-cpufreq-dt-platdev-Add-JH7110-SOC-to-the-allowlist.patch @@ -0,0 +1,24 @@ +From 214c40d5393cdf08c8b0746224e76bfd2a8d9cf7 Mon Sep 17 00:00:00 2001 +From: Mason Huo +Date: Fri, 21 Apr 2023 11:14:30 +0800 +Subject: [PATCH 097/122] cpufreq: dt-platdev: Add JH7110 SOC to the allowlist + +Add the compatible strings for supporting the generic +cpufreq driver on the StarFive JH7110 SoC. + +Signed-off-by: Mason Huo +--- + drivers/cpufreq/cpufreq-dt-platdev.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -86,6 +86,8 @@ static const struct of_device_id allowli + { .compatible = "st-ericsson,u9500", }, + { .compatible = "st-ericsson,u9540", }, + ++ { .compatible = "starfive,jh7110", }, ++ + { .compatible = "ti,omap2", }, + { .compatible = "ti,omap4", }, + { .compatible = "ti,omap5", }, diff --git a/target/linux/starfive/patches-6.1/0098-riscv-dts-starfive-Add-full-support-for-JH7110-and-V.patch b/target/linux/starfive/patches-6.1/0098-riscv-dts-starfive-Add-full-support-for-JH7110-and-V.patch new file mode 100644 index 0000000000..168782a280 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0098-riscv-dts-starfive-Add-full-support-for-JH7110-and-V.patch @@ -0,0 +1,1034 @@ +From 16e358dcf5e072c82f643d11add5b7e55b36a6f8 Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Wed, 31 May 2023 01:53:31 -0700 +Subject: [PATCH 098/122] riscv: dts: starfive: Add full support for JH7110 and + VisionFive 2 board + +Merge all StarFive dts patches together. + +Signed-off-by: shanlong.li +--- + .../jh7110-starfive-visionfive-2-v1.3b.dts | 8 +- + .../jh7110-starfive-visionfive-2.dtsi | 338 ++++++++++++ + arch/riscv/boot/dts/starfive/jh7110.dtsi | 506 +++++++++++++++++- + 3 files changed, 847 insertions(+), 5 deletions(-) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dts +@@ -28,8 +28,8 @@ + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-100-inverted; + motorcomm,tx-clk-1000-inverted; +- rx-clk-driver-strength = <0x6>; +- rx-data-driver-strength = <0x3>; ++ motorcomm,rx-clk-driver-strength = <0x6>; ++ motorcomm,rx-data-driver-strength = <0x3>; + rx-internal-delay-ps = <1500>; + tx-internal-delay-ps = <1500>; + }; +@@ -37,8 +37,8 @@ + &phy1 { + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-100-inverted; +- rx-clk-driver-strength = <0x6>; +- rx-data-driver-strength = <0x3>; ++ motorcomm,rx-clk-driver-strength = <0x6>; ++ motorcomm,rx-data-driver-strength = <0x3>; + rx-internal-delay-ps = <300>; + tx-internal-delay-ps = <0>; + }; +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -33,11 +33,64 @@ + reg = <0x0 0x40000000 0x1 0x0>; + }; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ size = <0x0 0x20000000>; ++ alignment = <0x0 0x1000>; ++ alloc-ranges = <0x0 0x80000000 0x0 0x20000000>; ++ linux,cma-default; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu-thermal { ++ polling-delay-passive = <250>; ++ polling-delay = <15000>; ++ ++ thermal-sensors = <&sfctemp>; ++ ++ cooling-maps { ++ }; ++ ++ trips { ++ cpu_alert0: cpu_alert0 { ++ /* milliCelsius */ ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu_crit { ++ /* milliCelsius */ ++ temperature = <90000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++ + gpio-restart { + compatible = "gpio-restart"; + gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>; + priority = <224>; + }; ++ ++ clk_ext_camera: clk_ext_camera { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++}; ++ ++&dvp_clk { ++ clock-frequency = <74250000>; + }; + + &gmac0_rgmii_rxin { +@@ -56,6 +109,10 @@ + clock-frequency = <50000000>; + }; + ++&hdmitx0_pixelclk { ++ clock-frequency = <297000000>; ++}; ++ + &i2srx_bclk_ext { + clock-frequency = <12288000>; + }; +@@ -88,6 +145,39 @@ + clock-frequency = <49152000>; + }; + ++&csi2rx { ++ status = "okay"; ++ ++ assigned-clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>; ++ assigned-clock-rates = <297000000>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ ++ csi2rx_from_imx219: endpoint { ++ remote-endpoint = <&imx219_to_csi2rx>; ++ bus-type = <4>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ status = "okay"; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ ++ csi2rx_to_vin: endpoint { ++ remote-endpoint = <&vin_from_csi2rx>; ++ status = "okay"; ++ }; ++ }; ++ }; ++}; ++ + &gmac0 { + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; +@@ -148,6 +238,20 @@ + pinctrl-names = "default"; + pinctrl-0 = <&i2c5_pins>; + status = "okay"; ++ ++ axp15060: pmic@36 { ++ compatible = "x-powers,axp15060"; ++ reg = <0x36>; ++ ++ regulators { ++ vdd_cpu: dcdc2 { ++ regulator-always-on; ++ regulator-min-microvolt = <500000>; ++ regulator-max-microvolt = <1540000>; ++ regulator-name = "vdd-cpu"; ++ }; ++ }; ++ }; + }; + + &i2c6 { +@@ -158,6 +262,121 @@ + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_pins>; + status = "okay"; ++ ++ imx219: imx219@10 { ++ compatible = "sony,imx219"; ++ reg = <0x10>; ++ clocks = <&clk_ext_camera>; ++ reset-gpio = <&sysgpio 18 0>; ++ rotation = <0>; ++ orientation = <1>; ++ ++ port { ++ imx219_to_csi2rx: endpoint { ++ remote-endpoint = <&csi2rx_from_imx219>; ++ bus-type = <4>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ link-frequencies = /bits/ 64 <456000000>; ++ }; ++ }; ++ }; ++}; ++ ++&mmc0 { ++ max-frequency = <100000000>; ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ mmc-ddr-1_8v; ++ mmc-hs200-1_8v; ++ non-removable; ++ cap-mmc-hw-reset; ++ post-power-on-delay-ms = <200>; ++ status = "okay"; ++}; ++ ++&mmc1 { ++ max-frequency = <100000000>; ++ bus-width = <4>; ++ no-sdio; ++ no-mmc; ++ broken-cd; ++ cap-sd-highspeed; ++ post-power-on-delay-ms = <200>; ++ status = "okay"; ++}; ++ ++&pcie0 { ++ pinctrl-names = "default"; ++ reset-gpios = <&sysgpio 26 GPIO_ACTIVE_LOW>; ++ phys = <&pciephy0>; ++ status = "okay"; ++}; ++ ++&pcie1 { ++ pinctrl-names = "default"; ++ reset-gpios = <&sysgpio 28 GPIO_ACTIVE_LOW>; ++ phys = <&pciephy1>; ++ status = "okay"; ++}; ++ ++&ptc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ status = "okay"; ++}; ++ ++&qspi { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ nor_flash: flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg=<0>; ++ cdns,read-delay = <5>; ++ spi-max-frequency = <12000000>; ++ cdns,tshsl-ns = <1>; ++ cdns,tsd2d-ns = <1>; ++ cdns,tchsh-ns = <1>; ++ cdns,tslch-ns = <1>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ spl@0 { ++ reg = <0x0 0x20000>; ++ }; ++ uboot@100000 { ++ reg = <0x100000 0x300000>; ++ }; ++ data@f00000 { ++ reg = <0xf00000 0x100000>; ++ }; ++ }; ++ }; ++}; ++ ++&stfcamss { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vin_from_csi2rx: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&csi2rx_to_vin>; ++ status = "okay"; ++ }; ++ }; ++ }; + }; + + &sysgpio { +@@ -217,6 +436,98 @@ + }; + }; + ++ pcie0_wake_default: pcie0_wake_default { ++ wake-pins { ++ pinmux = ; ++ bias-disable; ++ drive-strength = <2>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ pcie0_clkreq_default: pcie0_clkreq_default { ++ clkreq-pins { ++ bias-disable; ++ pinmux = ; ++ drive-strength = <2>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ pcie1_wake_default: pcie1_wake_default { ++ wake-pins { ++ bias-disable; ++ pinmux = ; ++ drive-strength = <2>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ pcie1_clkreq_default: pcie1_clkreq_default { ++ clkreq-pins { ++ bias-disable; ++ pinmux = ; ++ drive-strength = <2>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ pwm_pins: pwm-0 { ++ pwm-pins { ++ pinmux = , ++ ; ++ bias-disable; ++ drive-strength = <12>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ tdm0_pins: tdm0-pins { ++ tdm0-pins-tx { ++ pinmux = ; ++ bias-pull-up; ++ drive-strength = <2>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ tdm0-pins-rx { ++ pinmux = ; ++ input-enable; ++ }; ++ ++ tdm0-pins-sync { ++ pinmux = ; ++ input-enable; ++ }; ++ ++ tdm0-pins-pcmclk { ++ pinmux = ; ++ input-enable; ++ }; ++ }; ++ + uart0_pins: uart0-0 { + tx-pins { + pinmux = ; ++ status = "okay"; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; + }; ++ ++&usb0 { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; ++ ++&U74_1 { ++ cpu-supply = <&vdd_cpu>; ++}; ++ ++&U74_2 { ++ cpu-supply = <&vdd_cpu>; ++}; ++ ++&U74_3 { ++ cpu-supply = <&vdd_cpu>; ++}; ++ ++&U74_4 { ++ cpu-supply = <&vdd_cpu>; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi +@@ -6,6 +6,7 @@ + + /dts-v1/; + #include ++#include + #include + + / { +@@ -53,6 +54,9 @@ + next-level-cache = <&ccache>; + riscv,isa = "rv64imafdc_zba_zbb"; + tlb-split; ++ operating-points-v2 = <&cpu_opp>; ++ clocks = <&syscrg JH7110_SYSCLK_CPU_CORE>; ++ clock-names = "cpu"; + + cpu1_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -79,6 +83,9 @@ + next-level-cache = <&ccache>; + riscv,isa = "rv64imafdc_zba_zbb"; + tlb-split; ++ operating-points-v2 = <&cpu_opp>; ++ clocks = <&syscrg JH7110_SYSCLK_CPU_CORE>; ++ clock-names = "cpu"; + + cpu2_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -105,6 +112,9 @@ + next-level-cache = <&ccache>; + riscv,isa = "rv64imafdc_zba_zbb"; + tlb-split; ++ operating-points-v2 = <&cpu_opp>; ++ clocks = <&syscrg JH7110_SYSCLK_CPU_CORE>; ++ clock-names = "cpu"; + + cpu3_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -131,6 +141,9 @@ + next-level-cache = <&ccache>; + riscv,isa = "rv64imafdc_zba_zbb"; + tlb-split; ++ operating-points-v2 = <&cpu_opp>; ++ clocks = <&syscrg JH7110_SYSCLK_CPU_CORE>; ++ clock-names = "cpu"; + + cpu4_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -164,6 +177,33 @@ + }; + }; + ++ cpu_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ opp-375000000 { ++ opp-hz = /bits/ 64 <375000000>; ++ opp-microvolt = <800000>; ++ }; ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <800000>; ++ }; ++ opp-750000000 { ++ opp-hz = /bits/ 64 <750000000>; ++ opp-microvolt = <800000>; ++ }; ++ opp-1500000000 { ++ opp-hz = /bits/ 64 <1500000000>; ++ opp-microvolt = <1040000>; ++ }; ++ }; ++ ++ dvp_clk: dvp-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "dvp_clk"; ++ #clock-cells = <0>; ++ }; ++ + gmac0_rgmii_rxin: gmac0-rgmii-rxin-clock { + compatible = "fixed-clock"; + clock-output-names = "gmac0_rgmii_rxin"; +@@ -188,6 +228,12 @@ + #clock-cells = <0>; + }; + ++ hdmitx0_pixelclk: hdmitx0-pixel-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "hdmitx0_pixelclk"; ++ #clock-cells = <0>; ++ }; ++ + i2srx_bclk_ext: i2srx-bclk-ext-clock { + compatible = "fixed-clock"; + clock-output-names = "i2srx_bclk_ext"; +@@ -360,6 +406,99 @@ + status = "disabled"; + }; + ++ tdm: tdm@10090000 { ++ compatible = "starfive,jh7110-tdm"; ++ reg = <0x0 0x10090000 0x0 0x1000>; ++ clocks = <&syscrg JH7110_SYSCLK_TDM_AHB>, ++ <&syscrg JH7110_SYSCLK_TDM_APB>, ++ <&syscrg JH7110_SYSCLK_TDM_INTERNAL>, ++ <&syscrg JH7110_SYSCLK_TDM_TDM>, ++ <&syscrg JH7110_SYSCLK_MCLK_INNER>, ++ <&tdm_ext>; ++ clock-names = "tdm_ahb", "tdm_apb", ++ "tdm_internal", "tdm", ++ "mclk_inner", "tdm_ext"; ++ resets = <&syscrg JH7110_SYSRST_TDM_AHB>, ++ <&syscrg JH7110_SYSRST_TDM_APB>, ++ <&syscrg JH7110_SYSRST_TDM_CORE>; ++ dmas = <&dma 20>, <&dma 21>; ++ dma-names = "rx","tx"; ++ #sound-dai-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ usb0: usb@10100000 { ++ compatible = "starfive,jh7110-usb"; ++ ranges = <0x0 0x0 0x10100000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ starfive,stg-syscon = <&stg_syscon 0x4>; ++ clocks = <&stgcrg JH7110_STGCLK_USB0_LPM>, ++ <&stgcrg JH7110_STGCLK_USB0_STB>, ++ <&stgcrg JH7110_STGCLK_USB0_APB>, ++ <&stgcrg JH7110_STGCLK_USB0_AXI>, ++ <&stgcrg JH7110_STGCLK_USB0_UTMI_APB>; ++ clock-names = "lpm", "stb", "apb", "axi", "utmi_apb"; ++ resets = <&stgcrg JH7110_STGRST_USB0_PWRUP>, ++ <&stgcrg JH7110_STGRST_USB0_APB>, ++ <&stgcrg JH7110_STGRST_USB0_AXI>, ++ <&stgcrg JH7110_STGRST_USB0_UTMI_APB>; ++ reset-names = "pwrup", "apb", "axi", "utmi_apb"; ++ status = "disabled"; ++ ++ usb_cdns3: usb@0 { ++ compatible = "cdns,usb3"; ++ reg = <0x0 0x10000>, ++ <0x10000 0x10000>, ++ <0x20000 0x10000>; ++ reg-names = "otg", "xhci", "dev"; ++ interrupts = <100>, <108>, <110>; ++ interrupt-names = "host", "peripheral", "otg"; ++ phys = <&usbphy0>; ++ phy-names = "cdns3,usb2-phy"; ++ }; ++ }; ++ ++ usbphy0: phy@10200000 { ++ compatible = "starfive,jh7110-usb-phy"; ++ reg = <0x0 0x10200000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_USB_125M>, ++ <&stgcrg JH7110_STGCLK_USB0_APP_125>; ++ clock-names = "125m", "app_125m"; ++ #phy-cells = <0>; ++ }; ++ ++ pciephy0: phy@10210000 { ++ compatible = "starfive,jh7110-pcie-phy"; ++ reg = <0x0 0x10210000 0x0 0x10000>; ++ #phy-cells = <0>; ++ }; ++ ++ pciephy1: phy@10220000 { ++ compatible = "starfive,jh7110-pcie-phy"; ++ reg = <0x0 0x10220000 0x0 0x10000>; ++ #phy-cells = <0>; ++ }; ++ ++ stgcrg: clock-controller@10230000 { ++ compatible = "starfive,jh7110-stgcrg"; ++ reg = <0x0 0x10230000 0x0 0x10000>; ++ clocks = <&osc>, ++ <&syscrg JH7110_SYSCLK_HIFI4_CORE>, ++ <&syscrg JH7110_SYSCLK_STG_AXIAHB>, ++ <&syscrg JH7110_SYSCLK_USB_125M>, ++ <&syscrg JH7110_SYSCLK_CPU_BUS>, ++ <&syscrg JH7110_SYSCLK_HIFI4_AXI>, ++ <&syscrg JH7110_SYSCLK_NOCSTG_BUS>, ++ <&syscrg JH7110_SYSCLK_APB_BUS>; ++ clock-names = "osc", "hifi4_core", ++ "stg_axiahb", "usb_125m", ++ "cpu_bus", "hifi4_axi", ++ "nocstg_bus", "apb_bus"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ + stg_syscon: syscon@10240000 { + compatible = "starfive,jh7110-stg-syscon", "syscon"; + reg = <0x0 0x10240000 0x0 0x1000>; +@@ -452,6 +591,45 @@ + status = "disabled"; + }; + ++ ptc: pwm@120d0000 { ++ compatible = "starfive,jh7110-pwm"; ++ reg = <0x0 0x120d0000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_PWM_APB>; ++ resets = <&syscrg JH7110_SYSRST_PWM_APB>; ++ #pwm-cells=<3>; ++ status = "disabled"; ++ }; ++ ++ sfctemp: temperature-sensor@120e0000 { ++ compatible = "starfive,jh7110-temp"; ++ reg = <0x0 0x120e0000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_TEMP_CORE>, ++ <&syscrg JH7110_SYSCLK_TEMP_APB>; ++ clock-names = "sense", "bus"; ++ resets = <&syscrg JH7110_SYSRST_TEMP_CORE>, ++ <&syscrg JH7110_SYSRST_TEMP_APB>; ++ reset-names = "sense", "bus"; ++ #thermal-sensor-cells = <0>; ++ }; ++ ++ qspi: spi@13010000 { ++ compatible = "starfive,jh7110-qspi", "cdns,qspi-nor"; ++ reg = <0x0 0x13010000 0x0 0x10000 ++ 0x0 0x21000000 0x0 0x400000>; ++ interrupts = <25>; ++ clocks = <&syscrg JH7110_SYSCLK_QSPI_REF>, ++ <&syscrg JH7110_SYSCLK_QSPI_AHB>, ++ <&syscrg JH7110_SYSCLK_QSPI_APB>; ++ clock-names = "qspi-ref", "qspi-ahb", "qspi-apb"; ++ resets = <&syscrg JH7110_SYSRST_QSPI_APB>, ++ <&syscrg JH7110_SYSRST_QSPI_AHB>, ++ <&syscrg JH7110_SYSRST_QSPI_REF>; ++ reset-names = "qspi", "qspi-ocp", "rstc_ref"; ++ cdns,fifo-depth = <256>; ++ cdns,fifo-width = <4>; ++ cdns,trigger-address = <0x0>; ++ }; ++ + syscrg: clock-controller@13020000 { + compatible = "starfive,jh7110-syscrg"; + reg = <0x0 0x13020000 0x0 0x10000>; +@@ -496,6 +674,107 @@ + #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>; ++ clocks = <&syscrg JH7110_SYSCLK_WDT_APB>, ++ <&syscrg JH7110_SYSCLK_WDT_CORE>; ++ clock-names = "apb", "core"; ++ resets = <&syscrg JH7110_SYSRST_WDT_APB>, ++ <&syscrg JH7110_SYSRST_WDT_CORE>; ++ }; ++ ++ crypto: crypto@16000000 { ++ compatible = "starfive,jh7110-crypto"; ++ reg = <0x0 0x16000000 0x0 0x4000>; ++ clocks = <&stgcrg JH7110_STGCLK_SEC_AHB>, ++ <&stgcrg JH7110_STGCLK_SEC_MISC_AHB>; ++ clock-names = "hclk", "ahb"; ++ interrupts = <28>; ++ resets = <&stgcrg JH7110_STGRST_SEC_AHB>; ++ dmas = <&sdma 1 2>, <&sdma 0 2>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ sdma: dma@16008000 { ++ compatible = "arm,pl080", "arm,primecell"; ++ arm,primecell-periphid = <0x00041080>; ++ reg = <0x0 0x16008000 0x0 0x4000>; ++ interrupts = <29>; ++ clocks = <&stgcrg JH7110_STGCLK_SEC_AHB>, ++ <&stgcrg JH7110_STGCLK_SEC_MISC_AHB>; ++ clock-names = "hclk", "apb_pclk"; ++ resets = <&stgcrg JH7110_STGRST_SEC_AHB>; ++ lli-bus-interface-ahb1; ++ mem-bus-interface-ahb1; ++ memcpy-burst-size = <256>; ++ memcpy-bus-width = <32>; ++ #dma-cells = <2>; ++ }; ++ ++ rng: rng@1600c000 { ++ compatible = "starfive,jh7110-trng"; ++ reg = <0x0 0x1600C000 0x0 0x4000>; ++ clocks = <&stgcrg JH7110_STGCLK_SEC_AHB>, ++ <&stgcrg JH7110_STGCLK_SEC_MISC_AHB>; ++ clock-names = "hclk", "ahb"; ++ resets = <&stgcrg JH7110_STGRST_SEC_AHB>; ++ interrupts = <30>; ++ }; ++ ++ mmc0: mmc@16010000 { ++ compatible = "starfive,jh7110-mmc"; ++ reg = <0x0 0x16010000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_SDIO0_AHB>, ++ <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>; ++ clock-names = "biu","ciu"; ++ resets = <&syscrg JH7110_SYSRST_SDIO0_AHB>; ++ reset-names = "reset"; ++ interrupts = <74>; ++ fifo-depth = <32>; ++ fifo-watermark-aligned; ++ data-addr = <0>; ++ starfive,sysreg = <&sys_syscon 0x14 0x1a 0x7c000000>; ++ status = "disabled"; ++ }; ++ ++ mmc1: mmc@16020000 { ++ compatible = "starfive,jh7110-mmc"; ++ reg = <0x0 0x16020000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_SDIO1_AHB>, ++ <&syscrg JH7110_SYSCLK_SDIO1_SDCARD>; ++ clock-names = "biu","ciu"; ++ resets = <&syscrg JH7110_SYSRST_SDIO1_AHB>; ++ reset-names = "reset"; ++ interrupts = <75>; ++ fifo-depth = <32>; ++ fifo-watermark-aligned; ++ data-addr = <0>; ++ starfive,sysreg = <&sys_syscon 0x9c 0x1 0x3e>; ++ status = "disabled"; ++ }; ++ + gmac0: ethernet@16030000 { + compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20"; + reg = <0x0 0x16030000 0x0 0x10000>; +@@ -558,6 +837,24 @@ + status = "disabled"; + }; + ++ dma: dma-controller@16050000 { ++ compatible = "starfive,jh7110-axi-dma"; ++ reg = <0x0 0x16050000 0x0 0x10000>; ++ clocks = <&stgcrg JH7110_STGCLK_DMA1P_AXI>, ++ <&stgcrg JH7110_STGCLK_DMA1P_AHB>; ++ clock-names = "core-clk", "cfgr-clk"; ++ resets = <&stgcrg JH7110_STGRST_DMA1P_AXI>, ++ <&stgcrg JH7110_STGRST_DMA1P_AHB>; ++ interrupts = <73>; ++ #dma-cells = <1>; ++ dma-channels = <4>; ++ snps,dma-masters = <1>; ++ snps,data-width = <3>; ++ snps,block-size = <65536 65536 65536 65536>; ++ snps,priority = <0 1 2 3>; ++ snps,axi-max-burst-len = <16>; ++ }; ++ + aoncrg: clock-controller@17000000 { + compatible = "starfive,jh7110-aoncrg"; + reg = <0x0 0x17000000 0x0 0x10000>; +@@ -576,8 +873,9 @@ + }; + + aon_syscon: syscon@17010000 { +- compatible = "starfive,jh7110-aon-syscon", "syscon", "simple-mfd"; ++ compatible = "starfive,jh7110-aon-syscon", "syscon"; + reg = <0x0 0x17010000 0x0 0x1000>; ++ #power-domain-cells = <1>; + }; + + aongpio: pinctrl@17020000 { +@@ -590,5 +888,211 @@ + gpio-controller; + #gpio-cells = <2>; + }; ++ ++ pwrc: power-controller@17030000 { ++ compatible = "starfive,jh7110-pmu"; ++ reg = <0x0 0x17030000 0x0 0x10000>; ++ interrupts = <111>; ++ #power-domain-cells = <1>; ++ }; ++ ++ csi2rx: csi-bridge@19800000 { ++ compatible = "starfive,jh7110-csi2rx"; ++ reg = <0x0 0x19800000 0x0 0x10000>; ++ clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>, ++ <&ispcrg JH7110_ISPCLK_VIN_APB>, ++ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF0>, ++ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF1>, ++ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF2>, ++ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF3>; ++ clock-names = "sys_clk", "p_clk", ++ "pixel_if0_clk", "pixel_if1_clk", ++ "pixel_if2_clk", "pixel_if3_clk"; ++ resets = <&ispcrg JH7110_ISPRST_VIN_SYS>, ++ <&ispcrg JH7110_ISPRST_VIN_APB>, ++ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF0>, ++ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF1>, ++ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF2>, ++ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF3>; ++ reset-names = "sys", "reg_bank", ++ "pixel_if0", "pixel_if1", ++ "pixel_if2", "pixel_if3"; ++ phys = <&csi_phy>; ++ phy-names = "dphy"; ++ status = "disabled"; ++ }; ++ ++ ispcrg: clock-controller@19810000 { ++ compatible = "starfive,jh7110-ispcrg"; ++ reg = <0x0 0x19810000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_ISP_TOP_CORE>, ++ <&syscrg JH7110_SYSCLK_ISP_TOP_AXI>, ++ <&syscrg JH7110_SYSCLK_NOC_BUS_ISP_AXI>, ++ <&dvp_clk>; ++ clock-names = "isp_top_core", "isp_top_axi", ++ "noc_bus_isp_axi", "dvp_clk"; ++ resets = <&syscrg JH7110_SYSRST_ISP_TOP>, ++ <&syscrg JH7110_SYSRST_ISP_TOP_AXI>, ++ <&syscrg JH7110_SYSRST_NOC_BUS_ISP_AXI>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ power-domains = <&pwrc JH7110_PD_ISP>; ++ }; ++ ++ csi_phy: phy@19820000 { ++ compatible = "starfive,jh7110-dphy-rx"; ++ reg = <0x0 0x19820000 0x0 0x10000>; ++ clocks = <&ispcrg JH7110_ISPCLK_M31DPHY_CFG_IN>, ++ <&ispcrg JH7110_ISPCLK_M31DPHY_REF_IN>, ++ <&ispcrg JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0>; ++ clock-names = "cfg", "ref", "tx"; ++ resets = <&ispcrg JH7110_ISPRST_M31DPHY_HW>, ++ <&ispcrg JH7110_ISPRST_M31DPHY_B09_AON>; ++ power-domains = <&aon_syscon JH7110_PD_DPHY_RX>; ++ #phy-cells = <0>; ++ }; ++ ++ stfcamss: camss@19840000 { ++ compatible = "starfive,jh7110-camss"; ++ reg = <0x0 0x19840000 0x0 0x10000>, ++ <0x0 0x19870000 0x0 0x30000>; ++ reg-names = "syscon", "isp"; ++ clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>, ++ <&ispcrg JH7110_ISPCLK_ISPV2_TOP_WRAPPER_C>, ++ <&ispcrg JH7110_ISPCLK_DVP_INV>, ++ <&ispcrg JH7110_ISPCLK_VIN_P_AXI_WR>, ++ <&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>, ++ <&syscrg JH7110_SYSCLK_ISP_TOP_CORE>, ++ <&syscrg JH7110_SYSCLK_ISP_TOP_AXI>; ++ clock-names = "clk_apb_func", ++ "clk_wrapper_clk_c", ++ "clk_dvp_inv", ++ "clk_axiwr", ++ "clk_mipi_rx0_pxl", ++ "clk_ispcore_2x", ++ "clk_isp_axi"; ++ resets = <&ispcrg JH7110_ISPRST_ISPV2_TOP_WRAPPER_P>, ++ <&ispcrg JH7110_ISPRST_ISPV2_TOP_WRAPPER_C>, ++ <&ispcrg JH7110_ISPRST_VIN_P_AXI_RD>, ++ <&ispcrg JH7110_ISPRST_VIN_P_AXI_WR>, ++ <&syscrg JH7110_SYSRST_ISP_TOP>, ++ <&syscrg JH7110_SYSRST_ISP_TOP_AXI>; ++ reset-names = "rst_wrapper_p", ++ "rst_wrapper_c", ++ "rst_axird", ++ "rst_axiwr", ++ "rst_isp_top_n", ++ "rst_isp_top_axi"; ++ power-domains = <&pwrc JH7110_PD_ISP>; ++ /* irq nr: vin, isp, isp_csi, isp_csiline */ ++ interrupts = <92>, <87>, <90>; ++ status = "disabled"; ++ }; ++ ++ voutcrg: clock-controller@295c0000 { ++ compatible = "starfive,jh7110-voutcrg"; ++ reg = <0x0 0x295c0000 0x0 0x10000>; ++ clocks = <&syscrg JH7110_SYSCLK_VOUT_SRC>, ++ <&syscrg JH7110_SYSCLK_VOUT_TOP_AHB>, ++ <&syscrg JH7110_SYSCLK_VOUT_TOP_AXI>, ++ <&syscrg JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK>, ++ <&syscrg JH7110_SYSCLK_I2STX0_BCLK>, ++ <&hdmitx0_pixelclk>; ++ clock-names = "vout_src", "vout_top_ahb", ++ "vout_top_axi", "vout_top_hdmitx0_mclk", ++ "i2stx0_bclk", "hdmitx0_pixelclk"; ++ resets = <&syscrg JH7110_SYSRST_VOUT_TOP_SRC>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ power-domains = <&pwrc JH7110_PD_VOUT>; ++ }; ++ ++ pcie0: pcie@2B000000 { ++ compatible = "starfive,jh7110-pcie"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ reg = <0x0 0x2B000000 0x0 0x1000000 ++ 0x9 0x40000000 0x0 0x10000000>; ++ reg-names = "reg", "config"; ++ device_type = "pci"; ++ starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130 0x1b8>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>, ++ <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>; ++ interrupts = <56>; ++ interrupt-parent = <&plic>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>, ++ <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>, ++ <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>, ++ <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>; ++ msi-parent = <&pcie0>; ++ msi-controller; ++ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>, ++ <&stgcrg JH7110_STGCLK_PCIE0_TL>, ++ <&stgcrg JH7110_STGCLK_PCIE0_AXI_MST0>, ++ <&stgcrg JH7110_STGCLK_PCIE0_APB>; ++ clock-names = "noc", "tl", "axi_mst0", "apb"; ++ resets = <&stgcrg JH7110_STGRST_PCIE0_AXI_MST0>, ++ <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV0>, ++ <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV>, ++ <&stgcrg JH7110_STGRST_PCIE0_BRG>, ++ <&stgcrg JH7110_STGRST_PCIE0_CORE>, ++ <&stgcrg JH7110_STGRST_PCIE0_APB>; ++ reset-names = "mst0", "slv0", "slv", "brg", ++ "core", "apb"; ++ status = "disabled"; ++ ++ pcie_intc0: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; ++ ++ pcie1: pcie@2C000000 { ++ compatible = "starfive,jh7110-pcie"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ reg = <0x0 0x2C000000 0x0 0x1000000 ++ 0x9 0xc0000000 0x0 0x10000000>; ++ reg-names = "reg", "config"; ++ device_type = "pci"; ++ starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0 0x368>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x82000000 0x0 0x38000000 0x0 0x38000000 0x0 0x08000000>, ++ <0xc3000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>; ++ interrupts = <57>; ++ interrupt-parent = <&plic>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc1 0x1>, ++ <0x0 0x0 0x0 0x2 &pcie_intc1 0x2>, ++ <0x0 0x0 0x0 0x3 &pcie_intc1 0x3>, ++ <0x0 0x0 0x0 0x4 &pcie_intc1 0x4>; ++ msi-parent = <&pcie1>; ++ msi-controller; ++ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>, ++ <&stgcrg JH7110_STGCLK_PCIE1_TL>, ++ <&stgcrg JH7110_STGCLK_PCIE1_AXI_MST0>, ++ <&stgcrg JH7110_STGCLK_PCIE1_APB>; ++ clock-names = "noc", "tl", "axi_mst0", "apb"; ++ resets = <&stgcrg JH7110_STGRST_PCIE1_AXI_MST0>, ++ <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV0>, ++ <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV>, ++ <&stgcrg JH7110_STGRST_PCIE1_BRG>, ++ <&stgcrg JH7110_STGRST_PCIE1_CORE>, ++ <&stgcrg JH7110_STGRST_PCIE1_APB>; ++ reset-names = "mst0", "slv0", "slv", "brg", ++ "core", "apb"; ++ status = "disabled"; ++ ++ pcie_intc1: interrupt-controller { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ }; ++ }; + }; + }; diff --git a/target/linux/starfive/patches-6.1/0099-update-jh7110_defconfig-for-test.patch b/target/linux/starfive/patches-6.1/0099-update-jh7110_defconfig-for-test.patch new file mode 100644 index 0000000000..d63efb93dd --- /dev/null +++ b/target/linux/starfive/patches-6.1/0099-update-jh7110_defconfig-for-test.patch @@ -0,0 +1,48 @@ +From d91e8a78ce8d6a1f60a3f5c16b4f7c013ba40257 Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Wed, 31 May 2023 01:56:22 -0700 +Subject: [PATCH 099/122] update jh7110_defconfig for test + +Signed-off-by: shanlong.li +--- + arch/riscv/configs/jh7110_defconfig | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/riscv/configs/jh7110_defconfig ++++ b/arch/riscv/configs/jh7110_defconfig +@@ -106,7 +106,6 @@ CONFIG_MMC=y + # CONFIG_PWRSEQ_SIMPLE is not set + CONFIG_MMC_DW=y + # CONFIG_VIRTIO_MENU is not set +-CONFIG_CLK_STARFIVE_JH7110_AON=y + # CONFIG_VHOST_MENU is not set + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_BTRFS_FS=y +@@ -160,6 +159,19 @@ CONFIG_PCI=y + CONFIG_USB_CDNS3_STARFIVE=y + CONFIG_PHY_STARFIVE_JH7110_PCIE=y + CONFIG_PHY_STARFIVE_JH7110_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_HCD_PLATFORM=y ++CONFIG_USB_OHCI_HCD=y ++CONFIG_USB_OHCI_HCD_PLATFORM=y ++CONFIG_SCSI=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_UAS=y ++CONFIG_USB_CDNS3_GADGET=y ++CONFIG_USB_CDNS3_HOST=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_CONFIGFS=y ++CONFIG_USB_CONFIGFS_F_FS=y + CONFIG_USB_CDNS_SUPPORT=y + CONFIG_USB_CDNS3=y + CONFIG_USB=y +@@ -177,6 +189,7 @@ CONFIG_CRYPTO_HW=y + CONFIG_CRYPTO=y + CONFIG_SND_SOC_JH7110_TDM=y + CONFIG_SND_SOC_STARFIVE=y ++CONFIG_SND_SIMPLE_CARD=y + CONFIG_SND_SOC=y + CONFIG_SND=y + CONFIG_SOUND=y diff --git a/target/linux/starfive/patches-6.1/0100-Add-readme.patch b/target/linux/starfive/patches-6.1/0100-Add-readme.patch new file mode 100644 index 0000000000..82db368796 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0100-Add-readme.patch @@ -0,0 +1,75 @@ +From 13c570f2350f59a7994c26a51f749a50fa9b4726 Mon Sep 17 00:00:00 2001 +From: Hal Feng <87058983+hal-feng@users.noreply.github.com> +Date: Tue, 20 Dec 2022 16:18:35 +0800 +Subject: [PATCH 100/122] Add readme + +--- + README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 62 insertions(+) + create mode 100644 README.md + +--- /dev/null ++++ b/README.md +@@ -0,0 +1,62 @@ ++## JH7110 Upstream Status ## ++ ++To get the latest status of each upstreaming patch series, please visit ++our RVspace. ++ ++https://rvspace.org/en/project/JH7110_Upstream_Plan ++ ++## Build Instructions ## ++ ++1. Configure Kconfig options ++ ++```shell ++# Use default selections ++make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig ++``` ++ ++or ++ ++```shell ++# Select options manually ++make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- nconfig ++``` ++ ++To boot up the VisionFive 2 board, please make sure **SOC_STARFIVE**, ++**CLK_STARFIVE_JH7110_SYS**, **PINCTRL_STARFIVE_JH7110_SYS**, ++**SERIAL_8250_DW** are selected. ++> If you need MMC and GMAC drivers, you should also select ++**MMC_DW_STARFIVE** and **DWMAC_STARFIVE**. ++ ++2. Build ++```shell ++make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- ++``` ++ ++## How to Run on VisionFive 2 Board via Network ## ++ ++1. Power on, enter u-boot and set enviroment parameters ++``` ++setenv fdt_high 0xffffffffffffffff; setenv initrd_high 0xffffffffffffffff; ++setenv scriptaddr 0x88100000; setenv script_offset_f 0x1fff000; setenv script_size_f 0x1000; ++setenv kernel_addr_r 0x84000000; setenv kernel_comp_addr_r 0x90000000; setenv kernel_comp_size 0x10000000; ++setenv fdt_addr_r 0x88000000; setenv ramdisk_addr_r 0x88300000; ++``` ++2. Set IP addresses for the board and your tftp server ++``` ++setenv serverip 192.168.w.x; setenv gatewayip 192.168.w.y; setenv ipaddr 192.168.w.z; setenv hostname starfive; setenv netdev eth0; ++``` ++3. Upload dtb, image and file system to DDR from your tftp server ++``` ++tftpboot ${fdt_addr_r} jh7110-starfive-visionfive-2-v1.3b.dtb; tftpboot ${kernel_addr_r} Image.gz; tftpboot ${ramdisk_addr_r} initramfs.cpio.gz; ++``` ++> If your VisionFive 2 is v1.2A, you should upload jh7110-starfive-visionfive-2-v1.2a.dtb instead. ++4. Load and boot the kernel ++``` ++booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r}; ++``` ++When you see the message "buildroot login:", the launch was successful. ++You can just input the following accout and password, then continue. ++``` ++buildroot login: root ++Password: starfive ++``` diff --git a/target/linux/starfive/patches-6.1/0101-dt-bindings-rng-Add-StarFive-TRNG-module.patch b/target/linux/starfive/patches-6.1/0101-dt-bindings-rng-Add-StarFive-TRNG-module.patch new file mode 100644 index 0000000000..60cb6cc433 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0101-dt-bindings-rng-Add-StarFive-TRNG-module.patch @@ -0,0 +1,76 @@ +From 0b99a4626c7e148df128c6a8cb686d500431189b Mon Sep 17 00:00:00 2001 +From: Jia Jie Ho +Date: Tue, 17 Jan 2023 09:54:43 +0800 +Subject: [PATCH 101/122] dt-bindings: rng: Add StarFive TRNG module + +Add documentation to describe Starfive true random number generator +module. + +Co-developed-by: Jenny Zhang +Signed-off-by: Jenny Zhang +Signed-off-by: Jia Jie Ho +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Conor Dooley +--- + .../bindings/rng/starfive,jh7110-trng.yaml | 55 +++++++++++++++++++ + 1 file changed, 55 insertions(+) + create mode 100644 Documentation/devicetree/bindings/rng/starfive,jh7110-trng.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/rng/starfive,jh7110-trng.yaml +@@ -0,0 +1,55 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/rng/starfive,jh7110-trng.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive SoC TRNG Module ++ ++maintainers: ++ - Jia Jie Ho ++ ++properties: ++ compatible: ++ const: starfive,jh7110-trng ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: Hardware reference clock ++ - description: AHB reference clock ++ ++ clock-names: ++ items: ++ - const: hclk ++ - const: ahb ++ ++ resets: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ rng: rng@1600C000 { ++ compatible = "starfive,jh7110-trng"; ++ reg = <0x1600C000 0x4000>; ++ clocks = <&clk 15>, <&clk 16>; ++ clock-names = "hclk", "ahb"; ++ resets = <&reset 3>; ++ interrupts = <30>; ++ }; ++... diff --git a/target/linux/starfive/patches-6.1/0102-hwrng-starfive-Add-TRNG-driver-for-StarFive-SoC.patch b/target/linux/starfive/patches-6.1/0102-hwrng-starfive-Add-TRNG-driver-for-StarFive-SoC.patch new file mode 100644 index 0000000000..e9f8387e7f --- /dev/null +++ b/target/linux/starfive/patches-6.1/0102-hwrng-starfive-Add-TRNG-driver-for-StarFive-SoC.patch @@ -0,0 +1,457 @@ +From 99a7ca1d1320288efc5b4532ce4ea637d622aa00 Mon Sep 17 00:00:00 2001 +From: Jia Jie Ho +Date: Tue, 17 Jan 2023 09:54:44 +0800 +Subject: [PATCH 102/122] hwrng: starfive - Add TRNG driver for StarFive SoC + +This adds driver support for the hardware random number generator in +Starfive SoCs and adds StarFive TRNG entry to MAINTAINERS. + +Co-developed-by: Jenny Zhang +Signed-off-by: Jenny Zhang +Signed-off-by: Jia Jie Ho +--- + MAINTAINERS | 6 + + drivers/char/hw_random/Kconfig | 11 + + drivers/char/hw_random/Makefile | 1 + + drivers/char/hw_random/jh7110-trng.c | 393 +++++++++++++++++++++++++++ + 4 files changed, 411 insertions(+) + create mode 100644 drivers/char/hw_random/jh7110-trng.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19709,6 +19709,12 @@ F: Documentation/devicetree/bindings/pow + F: drivers/soc/starfive/jh71xx_pmu.c + F: include/dt-bindings/power/starfive,jh7110-pmu.h + ++STARFIVE TRNG DRIVER ++M: Jia Jie Ho ++S: Supported ++F: Documentation/devicetree/bindings/rng/starfive* ++F: drivers/char/hw_random/starfive-trng.c ++ + STATIC BRANCH/CALL + M: Peter Zijlstra + M: Josh Poimboeuf +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -549,6 +549,17 @@ config HW_RANDOM_CN10K + To compile this driver as a module, choose M here. + The module will be called cn10k_rng. If unsure, say Y. + ++config HW_RANDOM_JH7110 ++ tristate "StarFive JH7110 Random Number Generator support" ++ depends on SOC_STARFIVE ++ depends on HW_RANDOM ++ help ++ This driver provides support for the True Random Number ++ Generator in StarFive JH7110 SoCs. ++ ++ To compile this driver as a module, choose M here. ++ The module will be called jh7110-trng. ++ + endif # HW_RANDOM + + config UML_RANDOM +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -47,3 +47,4 @@ obj-$(CONFIG_HW_RANDOM_XIPHERA) += xiphe + obj-$(CONFIG_HW_RANDOM_ARM_SMCCC_TRNG) += arm_smccc_trng.o + obj-$(CONFIG_HW_RANDOM_CN10K) += cn10k-rng.o + obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o ++obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o +--- /dev/null ++++ b/drivers/char/hw_random/jh7110-trng.c +@@ -0,0 +1,393 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * TRNG driver for the StarFive JH7110 SoC ++ * ++ * Copyright (C) 2022 StarFive Technology Co. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* trng register offset */ ++#define STARFIVE_CTRL 0x00 ++#define STARFIVE_STAT 0x04 ++#define STARFIVE_MODE 0x08 ++#define STARFIVE_SMODE 0x0C ++#define STARFIVE_IE 0x10 ++#define STARFIVE_ISTAT 0x14 ++#define STARFIVE_RAND0 0x20 ++#define STARFIVE_RAND1 0x24 ++#define STARFIVE_RAND2 0x28 ++#define STARFIVE_RAND3 0x2C ++#define STARFIVE_RAND4 0x30 ++#define STARFIVE_RAND5 0x34 ++#define STARFIVE_RAND6 0x38 ++#define STARFIVE_RAND7 0x3C ++#define STARFIVE_AUTO_RQSTS 0x60 ++#define STARFIVE_AUTO_AGE 0x64 ++ ++/* CTRL CMD */ ++#define STARFIVE_CTRL_EXEC_NOP 0x0 ++#define STARFIVE_CTRL_GENE_RANDNUM 0x1 ++#define STARFIVE_CTRL_EXEC_RANDRESEED 0x2 ++ ++/* STAT */ ++#define STARFIVE_STAT_NONCE_MODE BIT(2) ++#define STARFIVE_STAT_R256 BIT(3) ++#define STARFIVE_STAT_MISSION_MODE BIT(8) ++#define STARFIVE_STAT_SEEDED BIT(9) ++#define STARFIVE_STAT_LAST_RESEED(x) ((x) << 16) ++#define STARFIVE_STAT_SRVC_RQST BIT(27) ++#define STARFIVE_STAT_RAND_GENERATING BIT(30) ++#define STARFIVE_STAT_RAND_SEEDING BIT(31) ++ ++/* MODE */ ++#define STARFIVE_MODE_R256 BIT(3) ++ ++/* SMODE */ ++#define STARFIVE_SMODE_NONCE_MODE BIT(2) ++#define STARFIVE_SMODE_MISSION_MODE BIT(8) ++#define STARFIVE_SMODE_MAX_REJECTS(x) ((x) << 16) ++ ++/* IE */ ++#define STARFIVE_IE_RAND_RDY_EN BIT(0) ++#define STARFIVE_IE_SEED_DONE_EN BIT(1) ++#define STARFIVE_IE_LFSR_LOCKUP_EN BIT(4) ++#define STARFIVE_IE_GLBL_EN BIT(31) ++ ++#define STARFIVE_IE_ALL (STARFIVE_IE_GLBL_EN | \ ++ STARFIVE_IE_RAND_RDY_EN | \ ++ STARFIVE_IE_SEED_DONE_EN | \ ++ STARFIVE_IE_LFSR_LOCKUP_EN) ++ ++/* ISTAT */ ++#define STARFIVE_ISTAT_RAND_RDY BIT(0) ++#define STARFIVE_ISTAT_SEED_DONE BIT(1) ++#define STARFIVE_ISTAT_LFSR_LOCKUP BIT(4) ++ ++#define STARFIVE_RAND_LEN sizeof(u32) ++ ++#define to_trng(p) container_of(p, struct starfive_trng, rng) ++ ++enum reseed { ++ RANDOM_RESEED, ++ NONCE_RESEED, ++}; ++ ++enum mode { ++ PRNG_128BIT, ++ PRNG_256BIT, ++}; ++ ++struct starfive_trng { ++ struct device *dev; ++ void __iomem *base; ++ struct clk *hclk; ++ struct clk *ahb; ++ struct reset_control *rst; ++ struct hwrng rng; ++ struct completion random_done; ++ struct completion reseed_done; ++ u32 mode; ++ u32 mission; ++ u32 reseed; ++ /* protects against concurrent write to ctrl register */ ++ spinlock_t write_lock; ++}; ++ ++static u16 autoreq; ++module_param(autoreq, ushort, 0); ++MODULE_PARM_DESC(autoreq, "Auto-reseeding after random number requests by host reaches specified counter:\n" ++ " 0 - disable counter\n" ++ " other - reload value for internal counter"); ++ ++static u16 autoage; ++module_param(autoage, ushort, 0); ++MODULE_PARM_DESC(autoage, "Auto-reseeding after specified timer countdowns to 0:\n" ++ " 0 - disable timer\n" ++ " other - reload value for internal timer"); ++ ++static inline int starfive_trng_wait_idle(struct starfive_trng *trng) ++{ ++ u32 stat; ++ ++ return readl_relaxed_poll_timeout(trng->base + STARFIVE_STAT, stat, ++ !(stat & (STARFIVE_STAT_RAND_GENERATING | ++ STARFIVE_STAT_RAND_SEEDING)), ++ 10, 100000); ++} ++ ++static inline void starfive_trng_irq_mask_clear(struct starfive_trng *trng) ++{ ++ /* clear register: ISTAT */ ++ u32 data = readl(trng->base + STARFIVE_ISTAT); ++ ++ writel(data, trng->base + STARFIVE_ISTAT); ++} ++ ++static int starfive_trng_cmd(struct starfive_trng *trng, u32 cmd, bool wait) ++{ ++ int wait_time = 1000; ++ ++ /* allow up to 40 us for wait == 0 */ ++ if (!wait) ++ wait_time = 40; ++ ++ switch (cmd) { ++ case STARFIVE_CTRL_GENE_RANDNUM: ++ reinit_completion(&trng->random_done); ++ spin_lock_irq(&trng->write_lock); ++ writel(cmd, trng->base + STARFIVE_CTRL); ++ spin_unlock_irq(&trng->write_lock); ++ if (!wait_for_completion_timeout(&trng->random_done, usecs_to_jiffies(wait_time))) ++ return -ETIMEDOUT; ++ break; ++ case STARFIVE_CTRL_EXEC_RANDRESEED: ++ reinit_completion(&trng->reseed_done); ++ spin_lock_irq(&trng->write_lock); ++ writel(cmd, trng->base + STARFIVE_CTRL); ++ spin_unlock_irq(&trng->write_lock); ++ if (!wait_for_completion_timeout(&trng->reseed_done, usecs_to_jiffies(wait_time))) ++ return -ETIMEDOUT; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int starfive_trng_init(struct hwrng *rng) ++{ ++ struct starfive_trng *trng = to_trng(rng); ++ u32 mode, intr = 0; ++ ++ /* setup Auto Request/Age register */ ++ writel(autoage, trng->base + STARFIVE_AUTO_AGE); ++ writel(autoreq, trng->base + STARFIVE_AUTO_RQSTS); ++ ++ /* clear register: ISTAT */ ++ starfive_trng_irq_mask_clear(trng); ++ ++ intr |= STARFIVE_IE_ALL; ++ writel(intr, trng->base + STARFIVE_IE); ++ ++ mode = readl(trng->base + STARFIVE_MODE); ++ ++ switch (trng->mode) { ++ case PRNG_128BIT: ++ mode &= ~STARFIVE_MODE_R256; ++ break; ++ case PRNG_256BIT: ++ mode |= STARFIVE_MODE_R256; ++ break; ++ default: ++ mode |= STARFIVE_MODE_R256; ++ break; ++ } ++ ++ writel(mode, trng->base + STARFIVE_MODE); ++ ++ return starfive_trng_cmd(trng, STARFIVE_CTRL_EXEC_RANDRESEED, 1); ++} ++ ++static irqreturn_t starfive_trng_irq(int irq, void *priv) ++{ ++ u32 status; ++ struct starfive_trng *trng = (struct starfive_trng *)priv; ++ ++ status = readl(trng->base + STARFIVE_ISTAT); ++ if (status & STARFIVE_ISTAT_RAND_RDY) { ++ writel(STARFIVE_ISTAT_RAND_RDY, trng->base + STARFIVE_ISTAT); ++ complete(&trng->random_done); ++ } ++ ++ if (status & STARFIVE_ISTAT_SEED_DONE) { ++ writel(STARFIVE_ISTAT_SEED_DONE, trng->base + STARFIVE_ISTAT); ++ complete(&trng->reseed_done); ++ } ++ ++ if (status & STARFIVE_ISTAT_LFSR_LOCKUP) { ++ writel(STARFIVE_ISTAT_LFSR_LOCKUP, trng->base + STARFIVE_ISTAT); ++ /* SEU occurred, reseeding required*/ ++ spin_lock(&trng->write_lock); ++ writel(STARFIVE_CTRL_EXEC_RANDRESEED, trng->base + STARFIVE_CTRL); ++ spin_unlock(&trng->write_lock); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void starfive_trng_cleanup(struct hwrng *rng) ++{ ++ struct starfive_trng *trng = to_trng(rng); ++ ++ writel(0, trng->base + STARFIVE_CTRL); ++ ++ reset_control_assert(trng->rst); ++ clk_disable_unprepare(trng->hclk); ++ clk_disable_unprepare(trng->ahb); ++} ++ ++static int starfive_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) ++{ ++ struct starfive_trng *trng = to_trng(rng); ++ int ret; ++ ++ pm_runtime_get_sync(trng->dev); ++ ++ if (trng->mode == PRNG_256BIT) ++ max = min_t(size_t, max, (STARFIVE_RAND_LEN * 8)); ++ else ++ max = min_t(size_t, max, (STARFIVE_RAND_LEN * 4)); ++ ++ if (wait) { ++ ret = starfive_trng_wait_idle(trng); ++ if (ret) ++ return -ETIMEDOUT; ++ } ++ ++ ret = starfive_trng_cmd(trng, STARFIVE_CTRL_GENE_RANDNUM, wait); ++ if (ret) ++ return ret; ++ ++ memcpy_fromio(buf, trng->base + STARFIVE_RAND0, max); ++ ++ pm_runtime_put_sync_autosuspend(trng->dev); ++ ++ return max; ++} ++ ++static int starfive_trng_probe(struct platform_device *pdev) ++{ ++ int ret; ++ int irq; ++ struct starfive_trng *trng; ++ ++ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); ++ if (!trng) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, trng); ++ trng->dev = &pdev->dev; ++ ++ trng->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(trng->base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(trng->base), ++ "Error remapping memory for platform device.\n"); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ init_completion(&trng->random_done); ++ init_completion(&trng->reseed_done); ++ spin_lock_init(&trng->write_lock); ++ ++ ret = devm_request_irq(&pdev->dev, irq, starfive_trng_irq, 0, pdev->name, ++ (void *)trng); ++ if (ret) ++ return dev_err_probe(&pdev->dev, irq, ++ "Failed to register interrupt handler\n"); ++ ++ trng->hclk = devm_clk_get(&pdev->dev, "hclk"); ++ if (IS_ERR(trng->hclk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(trng->hclk), ++ "Error getting hardware reference clock\n"); ++ ++ trng->ahb = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(trng->ahb)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(trng->ahb), ++ "Error getting ahb reference clock\n"); ++ ++ trng->rst = devm_reset_control_get_shared(&pdev->dev, NULL); ++ if (IS_ERR(trng->rst)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(trng->rst), ++ "Error getting hardware reset line\n"); ++ ++ clk_prepare_enable(trng->hclk); ++ clk_prepare_enable(trng->ahb); ++ reset_control_deassert(trng->rst); ++ ++ trng->rng.name = dev_driver_string(&pdev->dev); ++ trng->rng.init = starfive_trng_init; ++ trng->rng.cleanup = starfive_trng_cleanup; ++ trng->rng.read = starfive_trng_read; ++ ++ trng->mode = PRNG_256BIT; ++ trng->mission = 1; ++ trng->reseed = RANDOM_RESEED; ++ ++ pm_runtime_use_autosuspend(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(&pdev->dev, 100); ++ pm_runtime_enable(&pdev->dev); ++ ++ ret = devm_hwrng_register(&pdev->dev, &trng->rng); ++ if (ret) { ++ pm_runtime_disable(&pdev->dev); ++ ++ reset_control_assert(trng->rst); ++ clk_disable_unprepare(trng->ahb); ++ clk_disable_unprepare(trng->hclk); ++ ++ return dev_err_probe(&pdev->dev, ret, "Failed to register hwrng\n"); ++ } ++ ++ return 0; ++} ++ ++static int __maybe_unused starfive_trng_suspend(struct device *dev) ++{ ++ struct starfive_trng *trng = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(trng->hclk); ++ clk_disable_unprepare(trng->ahb); ++ ++ return 0; ++} ++ ++static int __maybe_unused starfive_trng_resume(struct device *dev) ++{ ++ struct starfive_trng *trng = dev_get_drvdata(dev); ++ ++ clk_prepare_enable(trng->hclk); ++ clk_prepare_enable(trng->ahb); ++ ++ return 0; ++} ++ ++static DEFINE_SIMPLE_DEV_PM_OPS(starfive_trng_pm_ops, starfive_trng_suspend, ++ starfive_trng_resume); ++ ++static const struct of_device_id trng_dt_ids[] __maybe_unused = { ++ { .compatible = "starfive,jh7110-trng" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, trng_dt_ids); ++ ++static struct platform_driver starfive_trng_driver = { ++ .probe = starfive_trng_probe, ++ .driver = { ++ .name = "jh7110-trng", ++ .pm = &starfive_trng_pm_ops, ++ .of_match_table = of_match_ptr(trng_dt_ids), ++ }, ++}; ++ ++module_platform_driver(starfive_trng_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("StarFive True Random Number Generator"); diff --git a/target/linux/starfive/patches-6.1/0103-hwrng-starfive-Enable-compile-testing.patch b/target/linux/starfive/patches-6.1/0103-hwrng-starfive-Enable-compile-testing.patch new file mode 100644 index 0000000000..39b4bc6ad9 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0103-hwrng-starfive-Enable-compile-testing.patch @@ -0,0 +1,28 @@ +From 4b02d00911c2e6bd31d8160b0337174dd55dc644 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Fri, 27 Jan 2023 19:03:21 +0800 +Subject: [PATCH 103/122] hwrng: starfive - Enable compile testing + +Enable compile testing for jh7110. Also remove the dependency on +HW_RANDOM. + +Signed-off-by: Herbert Xu +Reviewed-by: Conor Dooley +Reviewed-by: Jia Jie Ho +Signed-off-by: Herbert Xu +--- + drivers/char/hw_random/Kconfig | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -551,8 +551,7 @@ config HW_RANDOM_CN10K + + config HW_RANDOM_JH7110 + tristate "StarFive JH7110 Random Number Generator support" +- depends on SOC_STARFIVE +- depends on HW_RANDOM ++ depends on SOC_STARFIVE || COMPILE_TEST + help + This driver provides support for the True Random Number + Generator in StarFive JH7110 SoCs. diff --git a/target/linux/starfive/patches-6.1/0104-dt-bindings-watchdog-Add-watchdog-for-StarFive-JH710.patch b/target/linux/starfive/patches-6.1/0104-dt-bindings-watchdog-Add-watchdog-for-StarFive-JH710.patch new file mode 100644 index 0000000000..f68232f035 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0104-dt-bindings-watchdog-Add-watchdog-for-StarFive-JH710.patch @@ -0,0 +1,91 @@ +From 8559b2db6aecbee62cf9e02c17349379d72edcfb Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Tue, 14 Mar 2023 21:24:35 +0800 +Subject: [PATCH 104/122] dt-bindings: watchdog: Add watchdog for StarFive + JH7100 and JH7110 + +Add bindings to describe the watchdog for the StarFive JH7100/JH7110 SoC. +And Use JH7100 as first StarFive SoC with watchdog. + +Signed-off-by: Xingyu Wu +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Guenter Roeck +--- + .../watchdog/starfive,jh7100-wdt.yaml | 71 +++++++++++++++++++ + 1 file changed, 71 insertions(+) + create mode 100644 Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml +@@ -0,0 +1,71 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/watchdog/starfive,jh7100-wdt.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive Watchdog for JH7100 and JH7110 SoC ++ ++maintainers: ++ - Xingyu Wu ++ - Samin Guo ++ ++description: ++ The JH7100 and JH7110 watchdog both are 32 bit counters. JH7100 watchdog ++ has only one timeout phase and reboots. And JH7110 watchdog has two ++ timeout phases. At the first phase, the signal of watchdog interrupt ++ output(WDOGINT) will rise when counter is 0. The counter will reload ++ the timeout value. And then, if counter decreases to 0 again and WDOGINT ++ isn't cleared, the watchdog will reset the system unless the watchdog ++ reset is disabled. ++ ++allOf: ++ - $ref: watchdog.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - starfive,jh7100-wdt ++ - starfive,jh7110-wdt ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: APB clock ++ - description: Core clock ++ ++ clock-names: ++ items: ++ - const: apb ++ - const: core ++ ++ resets: ++ items: ++ - description: APB reset ++ - description: Core reset ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ watchdog@12480000 { ++ compatible = "starfive,jh7100-wdt"; ++ reg = <0x12480000 0x10000>; ++ clocks = <&clk 171>, ++ <&clk 172>; ++ clock-names = "apb", "core"; ++ resets = <&rst 99>, ++ <&rst 100>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0105-drivers-watchdog-Add-StarFive-Watchdog-driver.patch b/target/linux/starfive/patches-6.1/0105-drivers-watchdog-Add-StarFive-Watchdog-driver.patch new file mode 100644 index 0000000000..ec330250e2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0105-drivers-watchdog-Add-StarFive-Watchdog-driver.patch @@ -0,0 +1,675 @@ +From e835861823130ae47665db5e8039a7097ede14e4 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Tue, 14 Mar 2023 21:24:36 +0800 +Subject: [PATCH 105/122] drivers: watchdog: Add StarFive Watchdog driver + +Add watchdog driver for the StarFive JH7100 and JH7110 SoC. + +Signed-off-by: Xingyu Wu +Reviewed-by: Emil Renner Berthing +Reviewed-by: Guenter Roeck +--- + MAINTAINERS | 7 + + drivers/watchdog/Kconfig | 11 + + drivers/watchdog/Makefile | 3 + + drivers/watchdog/starfive-wdt.c | 606 ++++++++++++++++++++++++++++++++ + 4 files changed, 627 insertions(+) + create mode 100644 drivers/watchdog/starfive-wdt.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19715,6 +19715,13 @@ S: Supported + F: Documentation/devicetree/bindings/rng/starfive* + F: drivers/char/hw_random/starfive-trng.c + ++STARFIVE WATCHDOG DRIVER ++M: Xingyu Wu ++M: Samin Guo ++S: Supported ++F: Documentation/devicetree/bindings/watchdog/starfive* ++F: drivers/watchdog/starfive-wdt.c ++ + STATIC BRANCH/CALL + M: Peter Zijlstra + M: Josh Poimboeuf +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1991,6 +1991,17 @@ config WATCHDOG_RTAS + To compile this driver as a module, choose M here. The module + will be called wdrtas. + ++# RISC-V Architecture ++ ++config STARFIVE_WATCHDOG ++ tristate "StarFive Watchdog support" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ select WATCHDOG_CORE ++ default ARCH_STARFIVE ++ help ++ Say Y here to support the watchdog of StarFive JH7100 and JH7110 ++ SoC. This driver can also be built as a module if choose M. ++ + # S390 Architecture + + config DIAG288_WATCHDOG +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -191,6 +191,9 @@ obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt. + obj-$(CONFIG_PSERIES_WDT) += pseries-wdt.o + obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o + ++# RISC-V Architecture ++obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o ++ + # S390 Architecture + obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o + +--- /dev/null ++++ b/drivers/watchdog/starfive-wdt.c +@@ -0,0 +1,606 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Starfive Watchdog driver ++ * ++ * Copyright (C) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* JH7100 Watchdog register define */ ++#define STARFIVE_WDT_JH7100_INTSTAUS 0x000 ++#define STARFIVE_WDT_JH7100_CONTROL 0x104 ++#define STARFIVE_WDT_JH7100_LOAD 0x108 ++#define STARFIVE_WDT_JH7100_EN 0x110 ++#define STARFIVE_WDT_JH7100_RELOAD 0x114 /* Write 0 or 1 to reload preset value */ ++#define STARFIVE_WDT_JH7100_VALUE 0x118 ++#define STARFIVE_WDT_JH7100_INTCLR 0x120 /* ++ * [0]: Write 1 to clear interrupt ++ * [1]: 1 mean clearing and 0 mean complete ++ * [31:2]: reserved. ++ */ ++#define STARFIVE_WDT_JH7100_LOCK 0x13c /* write 0x378f0765 to unlock */ ++ ++/* JH7110 Watchdog register define */ ++#define STARFIVE_WDT_JH7110_LOAD 0x000 ++#define STARFIVE_WDT_JH7110_VALUE 0x004 ++#define STARFIVE_WDT_JH7110_CONTROL 0x008 /* ++ * [0]: reset enable; ++ * [1]: interrupt enable && watchdog enable ++ * [31:2]: reserved. ++ */ ++#define STARFIVE_WDT_JH7110_INTCLR 0x00c /* clear intterupt and reload the counter */ ++#define STARFIVE_WDT_JH7110_IMS 0x014 ++#define STARFIVE_WDT_JH7110_LOCK 0xc00 /* write 0x1ACCE551 to unlock */ ++ ++/* WDOGCONTROL */ ++#define STARFIVE_WDT_ENABLE 0x1 ++#define STARFIVE_WDT_EN_SHIFT 0 ++#define STARFIVE_WDT_RESET_EN 0x1 ++#define STARFIVE_WDT_JH7100_RST_EN_SHIFT 0 ++#define STARFIVE_WDT_JH7110_RST_EN_SHIFT 1 ++ ++/* WDOGLOCK */ ++#define STARFIVE_WDT_JH7100_UNLOCK_KEY 0x378f0765 ++#define STARFIVE_WDT_JH7110_UNLOCK_KEY 0x1acce551 ++ ++/* WDOGINTCLR */ ++#define STARFIVE_WDT_INTCLR 0x1 ++#define STARFIVE_WDT_JH7100_INTCLR_AVA_SHIFT 1 /* Watchdog can clear interrupt when 0 */ ++ ++#define STARFIVE_WDT_MAXCNT 0xffffffff ++#define STARFIVE_WDT_DEFAULT_TIME (15) ++#define STARFIVE_WDT_DELAY_US 0 ++#define STARFIVE_WDT_TIMEOUT_US 10000 ++ ++/* module parameter */ ++#define STARFIVE_WDT_EARLY_ENA 0 ++ ++static bool nowayout = WATCHDOG_NOWAYOUT; ++static int heartbeat; ++static bool early_enable = STARFIVE_WDT_EARLY_ENA; ++ ++module_param(heartbeat, int, 0); ++module_param(early_enable, bool, 0); ++module_param(nowayout, bool, 0); ++ ++MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default=" ++ __MODULE_STRING(STARFIVE_WDT_DEFAULT_TIME) ")"); ++MODULE_PARM_DESC(early_enable, ++ "Watchdog is started at boot time if set to 1, default=" ++ __MODULE_STRING(STARFIVE_WDT_EARLY_ENA)); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" ++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++ ++struct starfive_wdt_variant { ++ unsigned int control; /* Watchdog Control Resgister for reset enable */ ++ unsigned int load; /* Watchdog Load register */ ++ unsigned int reload; /* Watchdog Reload Control register */ ++ unsigned int enable; /* Watchdog Enable Register */ ++ unsigned int value; /* Watchdog Counter Value Register */ ++ unsigned int int_clr; /* Watchdog Interrupt Clear Register */ ++ unsigned int unlock; /* Watchdog Lock Register */ ++ unsigned int int_status; /* Watchdog Interrupt Status Register */ ++ ++ u32 unlock_key; ++ char enrst_shift; ++ char en_shift; ++ bool intclr_check; /* whether need to check it before clearing interrupt */ ++ char intclr_ava_shift; ++ bool double_timeout; /* The watchdog need twice timeout to reboot */ ++}; ++ ++struct starfive_wdt { ++ struct watchdog_device wdd; ++ spinlock_t lock; /* spinlock for register handling */ ++ void __iomem *base; ++ struct clk *core_clk; ++ struct clk *apb_clk; ++ const struct starfive_wdt_variant *variant; ++ unsigned long freq; ++ u32 count; /* count of timeout */ ++ u32 reload; /* restore the count */ ++}; ++ ++/* Register layout and configuration for the JH7100 */ ++static const struct starfive_wdt_variant starfive_wdt_jh7100_variant = { ++ .control = STARFIVE_WDT_JH7100_CONTROL, ++ .load = STARFIVE_WDT_JH7100_LOAD, ++ .reload = STARFIVE_WDT_JH7100_RELOAD, ++ .enable = STARFIVE_WDT_JH7100_EN, ++ .value = STARFIVE_WDT_JH7100_VALUE, ++ .int_clr = STARFIVE_WDT_JH7100_INTCLR, ++ .unlock = STARFIVE_WDT_JH7100_LOCK, ++ .unlock_key = STARFIVE_WDT_JH7100_UNLOCK_KEY, ++ .int_status = STARFIVE_WDT_JH7100_INTSTAUS, ++ .enrst_shift = STARFIVE_WDT_JH7100_RST_EN_SHIFT, ++ .en_shift = STARFIVE_WDT_EN_SHIFT, ++ .intclr_check = true, ++ .intclr_ava_shift = STARFIVE_WDT_JH7100_INTCLR_AVA_SHIFT, ++ .double_timeout = false, ++}; ++ ++/* Register layout and configuration for the JH7110 */ ++static const struct starfive_wdt_variant starfive_wdt_jh7110_variant = { ++ .control = STARFIVE_WDT_JH7110_CONTROL, ++ .load = STARFIVE_WDT_JH7110_LOAD, ++ .enable = STARFIVE_WDT_JH7110_CONTROL, ++ .value = STARFIVE_WDT_JH7110_VALUE, ++ .int_clr = STARFIVE_WDT_JH7110_INTCLR, ++ .unlock = STARFIVE_WDT_JH7110_LOCK, ++ .unlock_key = STARFIVE_WDT_JH7110_UNLOCK_KEY, ++ .int_status = STARFIVE_WDT_JH7110_IMS, ++ .enrst_shift = STARFIVE_WDT_JH7110_RST_EN_SHIFT, ++ .en_shift = STARFIVE_WDT_EN_SHIFT, ++ .intclr_check = false, ++ .double_timeout = true, ++}; ++ ++static int starfive_wdt_enable_clock(struct starfive_wdt *wdt) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(wdt->apb_clk); ++ if (ret) ++ return dev_err_probe(wdt->wdd.parent, ret, "failed to enable apb clock\n"); ++ ++ ret = clk_prepare_enable(wdt->core_clk); ++ if (ret) ++ return dev_err_probe(wdt->wdd.parent, ret, "failed to enable core clock\n"); ++ ++ return 0; ++} ++ ++static void starfive_wdt_disable_clock(struct starfive_wdt *wdt) ++{ ++ clk_disable_unprepare(wdt->core_clk); ++ clk_disable_unprepare(wdt->apb_clk); ++} ++ ++static inline int starfive_wdt_get_clock(struct starfive_wdt *wdt) ++{ ++ struct device *dev = wdt->wdd.parent; ++ ++ wdt->apb_clk = devm_clk_get(dev, "apb"); ++ if (IS_ERR(wdt->apb_clk)) ++ return dev_err_probe(dev, PTR_ERR(wdt->apb_clk), "failed to get apb clock\n"); ++ ++ wdt->core_clk = devm_clk_get(dev, "core"); ++ if (IS_ERR(wdt->core_clk)) ++ return dev_err_probe(dev, PTR_ERR(wdt->core_clk), "failed to get core clock\n"); ++ ++ return 0; ++} ++ ++static inline int starfive_wdt_reset_init(struct device *dev) ++{ ++ struct reset_control *rsts; ++ int ret; ++ ++ rsts = devm_reset_control_array_get_exclusive(dev); ++ if (IS_ERR(rsts)) ++ return dev_err_probe(dev, PTR_ERR(rsts), "failed to get resets\n"); ++ ++ ret = reset_control_deassert(rsts); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to deassert resets\n"); ++ ++ return 0; ++} ++ ++static u32 starfive_wdt_ticks_to_sec(struct starfive_wdt *wdt, u32 ticks) ++{ ++ return DIV_ROUND_CLOSEST(ticks, wdt->freq); ++} ++ ++/* Write unlock-key to unlock. Write other value to lock. */ ++static void starfive_wdt_unlock(struct starfive_wdt *wdt) ++{ ++ spin_lock(&wdt->lock); ++ writel(wdt->variant->unlock_key, wdt->base + wdt->variant->unlock); ++} ++ ++static void starfive_wdt_lock(struct starfive_wdt *wdt) ++{ ++ writel(~wdt->variant->unlock_key, wdt->base + wdt->variant->unlock); ++ spin_unlock(&wdt->lock); ++} ++ ++/* enable watchdog interrupt to reset/reboot */ ++static void starfive_wdt_enable_reset(struct starfive_wdt *wdt) ++{ ++ u32 val; ++ ++ val = readl(wdt->base + wdt->variant->control); ++ val |= STARFIVE_WDT_RESET_EN << wdt->variant->enrst_shift; ++ writel(val, wdt->base + wdt->variant->control); ++} ++ ++/* interrupt status whether has been raised from the counter */ ++static bool starfive_wdt_raise_irq_status(struct starfive_wdt *wdt) ++{ ++ return !!readl(wdt->base + wdt->variant->int_status); ++} ++ ++/* waiting interrupt can be free to clear */ ++static int starfive_wdt_wait_int_free(struct starfive_wdt *wdt) ++{ ++ u32 value; ++ ++ return readl_poll_timeout_atomic(wdt->base + wdt->variant->int_clr, value, ++ !(value & BIT(wdt->variant->intclr_ava_shift)), ++ STARFIVE_WDT_DELAY_US, STARFIVE_WDT_TIMEOUT_US); ++} ++ ++/* clear interrupt signal before initialization or reload */ ++static int starfive_wdt_int_clr(struct starfive_wdt *wdt) ++{ ++ int ret; ++ ++ if (wdt->variant->intclr_check) { ++ ret = starfive_wdt_wait_int_free(wdt); ++ if (ret) ++ return dev_err_probe(wdt->wdd.parent, ret, ++ "watchdog is not ready to clear interrupt.\n"); ++ } ++ writel(STARFIVE_WDT_INTCLR, wdt->base + wdt->variant->int_clr); ++ ++ return 0; ++} ++ ++static inline void starfive_wdt_set_count(struct starfive_wdt *wdt, u32 val) ++{ ++ writel(val, wdt->base + wdt->variant->load); ++} ++ ++static inline u32 starfive_wdt_get_count(struct starfive_wdt *wdt) ++{ ++ return readl(wdt->base + wdt->variant->value); ++} ++ ++/* enable watchdog */ ++static inline void starfive_wdt_enable(struct starfive_wdt *wdt) ++{ ++ u32 val; ++ ++ val = readl(wdt->base + wdt->variant->enable); ++ val |= STARFIVE_WDT_ENABLE << wdt->variant->en_shift; ++ writel(val, wdt->base + wdt->variant->enable); ++} ++ ++/* disable watchdog */ ++static inline void starfive_wdt_disable(struct starfive_wdt *wdt) ++{ ++ u32 val; ++ ++ val = readl(wdt->base + wdt->variant->enable); ++ val &= ~(STARFIVE_WDT_ENABLE << wdt->variant->en_shift); ++ writel(val, wdt->base + wdt->variant->enable); ++} ++ ++static inline void starfive_wdt_set_reload_count(struct starfive_wdt *wdt, u32 count) ++{ ++ starfive_wdt_set_count(wdt, count); ++ ++ /* 7100 need set any value to reload register and could reload value to counter */ ++ if (wdt->variant->reload) ++ writel(0x1, wdt->base + wdt->variant->reload); ++} ++ ++static unsigned int starfive_wdt_max_timeout(struct starfive_wdt *wdt) ++{ ++ if (wdt->variant->double_timeout) ++ return DIV_ROUND_UP(STARFIVE_WDT_MAXCNT, (wdt->freq / 2)) - 1; ++ ++ return DIV_ROUND_UP(STARFIVE_WDT_MAXCNT, wdt->freq) - 1; ++} ++ ++static unsigned int starfive_wdt_get_timeleft(struct watchdog_device *wdd) ++{ ++ struct starfive_wdt *wdt = watchdog_get_drvdata(wdd); ++ u32 count; ++ ++ /* ++ * If the watchdog takes twice timeout and set half count value, ++ * timeleft value should add the count value before first timeout. ++ */ ++ count = starfive_wdt_get_count(wdt); ++ if (wdt->variant->double_timeout && !starfive_wdt_raise_irq_status(wdt)) ++ count += wdt->count; ++ ++ return starfive_wdt_ticks_to_sec(wdt, count); ++} ++ ++static int starfive_wdt_keepalive(struct watchdog_device *wdd) ++{ ++ struct starfive_wdt *wdt = watchdog_get_drvdata(wdd); ++ int ret; ++ ++ starfive_wdt_unlock(wdt); ++ ret = starfive_wdt_int_clr(wdt); ++ if (ret) ++ goto exit; ++ ++ starfive_wdt_set_reload_count(wdt, wdt->count); ++ ++exit: ++ /* exit with releasing spinlock and locking registers */ ++ starfive_wdt_lock(wdt); ++ return ret; ++} ++ ++static int starfive_wdt_start(struct starfive_wdt *wdt) ++{ ++ int ret; ++ ++ starfive_wdt_unlock(wdt); ++ /* disable watchdog, to be safe */ ++ starfive_wdt_disable(wdt); ++ ++ starfive_wdt_enable_reset(wdt); ++ ret = starfive_wdt_int_clr(wdt); ++ if (ret) ++ goto exit; ++ ++ starfive_wdt_set_count(wdt, wdt->count); ++ starfive_wdt_enable(wdt); ++ ++exit: ++ starfive_wdt_lock(wdt); ++ return ret; ++} ++ ++static void starfive_wdt_stop(struct starfive_wdt *wdt) ++{ ++ starfive_wdt_unlock(wdt); ++ starfive_wdt_disable(wdt); ++ starfive_wdt_lock(wdt); ++} ++ ++static int starfive_wdt_pm_start(struct watchdog_device *wdd) ++{ ++ struct starfive_wdt *wdt = watchdog_get_drvdata(wdd); ++ int ret = pm_runtime_get_sync(wdd->parent); ++ ++ if (ret < 0) ++ return ret; ++ ++ return starfive_wdt_start(wdt); ++} ++ ++static int starfive_wdt_pm_stop(struct watchdog_device *wdd) ++{ ++ struct starfive_wdt *wdt = watchdog_get_drvdata(wdd); ++ ++ starfive_wdt_stop(wdt); ++ return pm_runtime_put_sync(wdd->parent); ++} ++ ++static int starfive_wdt_set_timeout(struct watchdog_device *wdd, ++ unsigned int timeout) ++{ ++ struct starfive_wdt *wdt = watchdog_get_drvdata(wdd); ++ unsigned long count = timeout * wdt->freq; ++ ++ /* some watchdogs take two timeouts to reset */ ++ if (wdt->variant->double_timeout) ++ count /= 2; ++ ++ wdt->count = count; ++ wdd->timeout = timeout; ++ ++ starfive_wdt_unlock(wdt); ++ starfive_wdt_disable(wdt); ++ starfive_wdt_set_reload_count(wdt, wdt->count); ++ starfive_wdt_enable(wdt); ++ starfive_wdt_lock(wdt); ++ ++ return 0; ++} ++ ++#define STARFIVE_WDT_OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) ++ ++static const struct watchdog_info starfive_wdt_info = { ++ .options = STARFIVE_WDT_OPTIONS, ++ .identity = "StarFive Watchdog", ++}; ++ ++static const struct watchdog_ops starfive_wdt_ops = { ++ .owner = THIS_MODULE, ++ .start = starfive_wdt_pm_start, ++ .stop = starfive_wdt_pm_stop, ++ .ping = starfive_wdt_keepalive, ++ .set_timeout = starfive_wdt_set_timeout, ++ .get_timeleft = starfive_wdt_get_timeleft, ++}; ++ ++static int starfive_wdt_probe(struct platform_device *pdev) ++{ ++ struct starfive_wdt *wdt; ++ int ret; ++ ++ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); ++ if (!wdt) ++ return -ENOMEM; ++ ++ wdt->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(wdt->base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(wdt->base), "error mapping registers\n"); ++ ++ wdt->wdd.parent = &pdev->dev; ++ ret = starfive_wdt_get_clock(wdt); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, wdt); ++ pm_runtime_enable(&pdev->dev); ++ if (pm_runtime_enabled(&pdev->dev)) { ++ ret = pm_runtime_get_sync(&pdev->dev); ++ if (ret < 0) ++ return ret; ++ } else { ++ /* runtime PM is disabled but clocks need to be enabled */ ++ ret = starfive_wdt_enable_clock(wdt); ++ if (ret) ++ return ret; ++ } ++ ++ ret = starfive_wdt_reset_init(&pdev->dev); ++ if (ret) ++ goto err_exit; ++ ++ watchdog_set_drvdata(&wdt->wdd, wdt); ++ wdt->wdd.info = &starfive_wdt_info; ++ wdt->wdd.ops = &starfive_wdt_ops; ++ wdt->variant = of_device_get_match_data(&pdev->dev); ++ spin_lock_init(&wdt->lock); ++ ++ wdt->freq = clk_get_rate(wdt->core_clk); ++ if (!wdt->freq) { ++ dev_err(&pdev->dev, "get clock rate failed.\n"); ++ ret = -EINVAL; ++ goto err_exit; ++ } ++ ++ wdt->wdd.min_timeout = 1; ++ wdt->wdd.max_timeout = starfive_wdt_max_timeout(wdt); ++ wdt->wdd.timeout = STARFIVE_WDT_DEFAULT_TIME; ++ watchdog_init_timeout(&wdt->wdd, heartbeat, &pdev->dev); ++ starfive_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout); ++ ++ watchdog_set_nowayout(&wdt->wdd, nowayout); ++ watchdog_stop_on_reboot(&wdt->wdd); ++ watchdog_stop_on_unregister(&wdt->wdd); ++ ++ if (early_enable) { ++ ret = starfive_wdt_start(wdt); ++ if (ret) ++ goto err_exit; ++ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); ++ } else { ++ starfive_wdt_stop(wdt); ++ } ++ ++ ret = watchdog_register_device(&wdt->wdd); ++ if (ret) ++ goto err_exit; ++ ++ if (!early_enable) ++ return pm_runtime_put_sync(&pdev->dev); ++ ++ return 0; ++ ++err_exit: ++ starfive_wdt_disable_clock(wdt); ++ pm_runtime_disable(&pdev->dev); ++ ++ return ret; ++} ++ ++static int starfive_wdt_remove(struct platform_device *pdev) ++{ ++ struct starfive_wdt *wdt = platform_get_drvdata(pdev); ++ ++ starfive_wdt_stop(wdt); ++ watchdog_unregister_device(&wdt->wdd); ++ ++ if (pm_runtime_enabled(&pdev->dev)) ++ pm_runtime_disable(&pdev->dev); ++ else ++ /* disable clock without PM */ ++ starfive_wdt_disable_clock(wdt); ++ ++ return 0; ++} ++ ++static void starfive_wdt_shutdown(struct platform_device *pdev) ++{ ++ struct starfive_wdt *wdt = platform_get_drvdata(pdev); ++ ++ starfive_wdt_pm_stop(&wdt->wdd); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int starfive_wdt_suspend(struct device *dev) ++{ ++ struct starfive_wdt *wdt = dev_get_drvdata(dev); ++ ++ /* Save watchdog state, and turn it off. */ ++ wdt->reload = starfive_wdt_get_count(wdt); ++ ++ /* Note that WTCNT doesn't need to be saved. */ ++ starfive_wdt_stop(wdt); ++ ++ return pm_runtime_force_suspend(dev); ++} ++ ++static int starfive_wdt_resume(struct device *dev) ++{ ++ struct starfive_wdt *wdt = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pm_runtime_force_resume(dev); ++ if (ret) ++ return ret; ++ ++ starfive_wdt_unlock(wdt); ++ /* Restore watchdog state. */ ++ starfive_wdt_set_reload_count(wdt, wdt->reload); ++ starfive_wdt_lock(wdt); ++ ++ return starfive_wdt_start(wdt); ++} ++#endif /* CONFIG_PM_SLEEP */ ++ ++#ifdef CONFIG_PM ++static int starfive_wdt_runtime_suspend(struct device *dev) ++{ ++ struct starfive_wdt *wdt = dev_get_drvdata(dev); ++ ++ starfive_wdt_disable_clock(wdt); ++ ++ return 0; ++} ++ ++static int starfive_wdt_runtime_resume(struct device *dev) ++{ ++ struct starfive_wdt *wdt = dev_get_drvdata(dev); ++ ++ return starfive_wdt_enable_clock(wdt); ++} ++#endif /* CONFIG_PM */ ++ ++static const struct dev_pm_ops starfive_wdt_pm_ops = { ++ SET_RUNTIME_PM_OPS(starfive_wdt_runtime_suspend, starfive_wdt_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(starfive_wdt_suspend, starfive_wdt_resume) ++}; ++ ++static const struct of_device_id starfive_wdt_match[] = { ++ { .compatible = "starfive,jh7100-wdt", .data = &starfive_wdt_jh7100_variant }, ++ { .compatible = "starfive,jh7110-wdt", .data = &starfive_wdt_jh7110_variant }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, starfive_wdt_match); ++ ++static struct platform_driver starfive_wdt_driver = { ++ .probe = starfive_wdt_probe, ++ .remove = starfive_wdt_remove, ++ .shutdown = starfive_wdt_shutdown, ++ .driver = { ++ .name = "starfive-wdt", ++ .pm = &starfive_wdt_pm_ops, ++ .of_match_table = of_match_ptr(starfive_wdt_match), ++ }, ++}; ++module_platform_driver(starfive_wdt_driver); ++ ++MODULE_AUTHOR("Xingyu Wu "); ++MODULE_AUTHOR("Samin Guo "); ++MODULE_DESCRIPTION("StarFive Watchdog Device Driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0106-riscv-dts-starfive-jh7100-Add-watchdog-node.patch b/target/linux/starfive/patches-6.1/0106-riscv-dts-starfive-jh7100-Add-watchdog-node.patch new file mode 100644 index 0000000000..a7b7bd88db --- /dev/null +++ b/target/linux/starfive/patches-6.1/0106-riscv-dts-starfive-jh7100-Add-watchdog-node.patch @@ -0,0 +1,31 @@ +From b085b6233065b1e5145fbf93d75264b2042c0eb5 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Tue, 14 Mar 2023 21:24:37 +0800 +Subject: [PATCH 106/122] riscv: dts: starfive: jh7100: Add watchdog node + +Add watchdog node for the StarFive JH7100 RISC-V SoC. + +Signed-off-by: Xingyu Wu +Reviewed-by: Emil Renner Berthing +--- + 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 +@@ -238,5 +238,15 @@ + #size-cells = <0>; + status = "disabled"; + }; ++ ++ watchdog@12480000 { ++ compatible = "starfive,jh7100-wdt"; ++ reg = <0x0 0x12480000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_WDTIMER_APB>, ++ <&clkgen JH7100_CLK_WDT_CORE>; ++ clock-names = "apb", "core"; ++ resets = <&rstgen JH7100_RSTN_WDTIMER_APB>, ++ <&rstgen JH7100_RSTN_WDT>; ++ }; + }; + }; diff --git a/target/linux/starfive/patches-6.1/0107-dt-bindings-mmc-Add-StarFive-MMC-module.patch b/target/linux/starfive/patches-6.1/0107-dt-bindings-mmc-Add-StarFive-MMC-module.patch new file mode 100644 index 0000000000..39844b5b77 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0107-dt-bindings-mmc-Add-StarFive-MMC-module.patch @@ -0,0 +1,95 @@ +From fc157f3d411ac570e8261e4238c6e6aac74a6cc6 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Wed, 15 Feb 2023 19:32:46 +0800 +Subject: [PATCH 107/122] dt-bindings: mmc: Add StarFive MMC module + +Add documentation to describe StarFive designware mobile storage +host controller driver. + +Signed-off-by: William Qiu +Reviewed-by: Krzysztof Kozlowski +--- + .../bindings/mmc/starfive,jh7110-mmc.yaml | 77 +++++++++++++++++++ + 1 file changed, 77 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mmc/starfive,jh7110-mmc.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mmc/starfive,jh7110-mmc.yaml +@@ -0,0 +1,77 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mmc/starfive,jh7110-mmc.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive Designware Mobile Storage Host Controller ++ ++description: ++ StarFive uses the Synopsys designware mobile storage host controller ++ to interface a SoC with storage medium such as eMMC or SD/MMC cards. ++ ++allOf: ++ - $ref: synopsys-dw-mshc-common.yaml# ++ ++maintainers: ++ - William Qiu ++ ++properties: ++ compatible: ++ const: starfive,jh7110-mmc ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: biu clock ++ - description: ciu clock ++ ++ clock-names: ++ items: ++ - const: biu ++ - const: ciu ++ ++ interrupts: ++ maxItems: 1 ++ ++ starfive,sysreg: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ items: ++ - items: ++ - description: phandle to System Register Controller syscon node ++ - description: offset of SYS_SYSCONSAIF__SYSCFG register for MMC controller ++ - description: shift of SYS_SYSCONSAIF__SYSCFG register for MMC controller ++ - description: mask of SYS_SYSCONSAIF__SYSCFG register for MMC controller ++ description: ++ Should be four parameters, the phandle to System Register Controller ++ syscon node and the offset/shift/mask of SYS_SYSCONSAIF__SYSCFG register ++ for MMC controller. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - interrupts ++ - starfive,sysreg ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ mmc@16010000 { ++ compatible = "starfive,jh7110-mmc"; ++ reg = <0x16010000 0x10000>; ++ clocks = <&syscrg 91>, ++ <&syscrg 93>; ++ clock-names = "biu","ciu"; ++ resets = <&syscrg 64>; ++ reset-names = "reset"; ++ interrupts = <74>; ++ fifo-depth = <32>; ++ fifo-watermark-aligned; ++ data-addr = <0>; ++ starfive,sysreg = <&sys_syscon 0x14 0x1a 0x7c000000>; ++ }; diff --git a/target/linux/starfive/patches-6.1/0108-mmc-starfive-Add-sdio-emmc-driver-support.patch b/target/linux/starfive/patches-6.1/0108-mmc-starfive-Add-sdio-emmc-driver-support.patch new file mode 100644 index 0000000000..3aecc0a204 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0108-mmc-starfive-Add-sdio-emmc-driver-support.patch @@ -0,0 +1,250 @@ +From ee990c664fad993275b2615d0ff06af5d04922f0 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Wed, 15 Feb 2023 19:32:47 +0800 +Subject: [PATCH 108/122] mmc: starfive: Add sdio/emmc driver support + +Add sdio/emmc driver support for StarFive JH7110 soc. + +Tested-by: Conor Dooley +Signed-off-by: William Qiu +--- + MAINTAINERS | 6 + + drivers/mmc/host/Kconfig | 10 ++ + drivers/mmc/host/Makefile | 1 + + drivers/mmc/host/dw_mmc-starfive.c | 186 +++++++++++++++++++++++++++++ + 4 files changed, 203 insertions(+) + create mode 100644 drivers/mmc/host/dw_mmc-starfive.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19657,6 +19657,12 @@ S: Maintained + F: Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml + F: drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c + ++STARFIVE JH7110 MMC/SD/SDIO DRIVER ++M: William Qiu ++S: Supported ++F: Documentation/devicetree/bindings/mmc/starfive* ++F: drivers/mmc/host/dw_mmc-starfive.c ++ + STARFIVE JH7110 PLL CLOCK DRIVER + M: Xingyu Wu + S: Supported +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -872,6 +872,16 @@ config MMC_DW_ROCKCHIP + Synopsys DesignWare Memory Card Interface driver. Select this option + for platforms based on RK3066, RK3188 and RK3288 SoC's. + ++config MMC_DW_STARFIVE ++ tristate "StarFive specific extensions for Synopsys DW Memory Card Interface" ++ depends on SOC_STARFIVE ++ depends on MMC_DW ++ select MMC_DW_PLTFM ++ help ++ This selects support for StarFive JH7110 SoC specific extensions to the ++ Synopsys DesignWare Memory Card Interface driver. Select this option ++ for platforms based on StarFive JH7110 SoC. ++ + config MMC_SH_MMCIF + tristate "SuperH Internal MMCIF support" + depends on SUPERH || ARCH_RENESAS || COMPILE_TEST +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -56,6 +56,7 @@ obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_m + obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o + obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o + obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o ++obj-$(CONFIG_MMC_DW_STARFIVE) += dw_mmc-starfive.o + obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o + obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o + obj-$(CONFIG_MMC_VUB300) += vub300.o +--- /dev/null ++++ b/drivers/mmc/host/dw_mmc-starfive.c +@@ -0,0 +1,186 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive Designware Mobile Storage Host Controller Driver ++ * ++ * Copyright (c) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dw_mmc.h" ++#include "dw_mmc-pltfm.h" ++ ++#define ALL_INT_CLR 0x1ffff ++#define MAX_DELAY_CHAIN 32 ++ ++struct starfive_priv { ++ struct device *dev; ++ struct regmap *reg_syscon; ++ u32 syscon_offset; ++ u32 syscon_shift; ++ u32 syscon_mask; ++}; ++ ++static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios) ++{ ++ int ret; ++ unsigned int clock; ++ ++ if (ios->timing == MMC_TIMING_MMC_DDR52 || ios->timing == MMC_TIMING_UHS_DDR50) { ++ clock = (ios->clock > 50000000 && ios->clock <= 52000000) ? 100000000 : ios->clock; ++ ret = clk_set_rate(host->ciu_clk, clock); ++ if (ret) ++ dev_dbg(host->dev, "Use an external frequency divider %uHz\n", ios->clock); ++ host->bus_hz = clk_get_rate(host->ciu_clk); ++ } else { ++ dev_dbg(host->dev, "Using the internal divider\n"); ++ } ++} ++ ++static int dw_mci_starfive_execute_tuning(struct dw_mci_slot *slot, ++ u32 opcode) ++{ ++ static const int grade = MAX_DELAY_CHAIN; ++ struct dw_mci *host = slot->host; ++ struct starfive_priv *priv = host->priv; ++ int rise_point = -1, fall_point = -1; ++ int err, prev_err; ++ int i; ++ bool found = 0; ++ u32 regval; ++ ++ /* ++ * Use grade as the max delay chain, and use the rise_point and ++ * fall_point to ensure the best sampling point of a data input ++ * signals. ++ */ ++ for (i = 0; i < grade; i++) { ++ regval = i << priv->syscon_shift; ++ err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset, ++ priv->syscon_mask, regval); ++ if (err) ++ return err; ++ mci_writel(host, RINTSTS, ALL_INT_CLR); ++ ++ err = mmc_send_tuning(slot->mmc, opcode, NULL); ++ if (!err) ++ found = 1; ++ ++ if (i > 0) { ++ if (err && !prev_err) ++ fall_point = i - 1; ++ if (!err && prev_err) ++ rise_point = i; ++ } ++ ++ if (rise_point != -1 && fall_point != -1) ++ goto tuning_out; ++ ++ prev_err = err; ++ err = 0; ++ } ++ ++tuning_out: ++ if (found) { ++ if (rise_point == -1) ++ rise_point = 0; ++ if (fall_point == -1) ++ fall_point = grade - 1; ++ if (fall_point < rise_point) { ++ if ((rise_point + fall_point) > ++ (grade - 1)) ++ i = fall_point / 2; ++ else ++ i = (rise_point + grade - 1) / 2; ++ } else { ++ i = (rise_point + fall_point) / 2; ++ } ++ ++ regval = i << priv->syscon_shift; ++ err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset, ++ priv->syscon_mask, regval); ++ if (err) ++ return err; ++ mci_writel(host, RINTSTS, ALL_INT_CLR); ++ ++ dev_info(host->dev, "Found valid delay chain! use it [delay=%d]\n", i); ++ } else { ++ dev_err(host->dev, "No valid delay chain! use default\n"); ++ err = -EINVAL; ++ } ++ ++ mci_writel(host, RINTSTS, ALL_INT_CLR); ++ return err; ++} ++ ++static int dw_mci_starfive_parse_dt(struct dw_mci *host) ++{ ++ struct of_phandle_args args; ++ struct starfive_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ ret = of_parse_phandle_with_fixed_args(host->dev->of_node, ++ "starfive,sysreg", 3, 0, &args); ++ if (ret) { ++ dev_err(host->dev, "Failed to parse starfive,sysreg\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); ++ ++ priv->syscon_offset = args.args[0]; ++ priv->syscon_shift = args.args[1]; ++ priv->syscon_mask = args.args[2]; ++ ++ host->priv = priv; ++ ++ return 0; ++} ++ ++static const struct dw_mci_drv_data starfive_data = { ++ .common_caps = MMC_CAP_CMD23, ++ .set_ios = dw_mci_starfive_set_ios, ++ .parse_dt = dw_mci_starfive_parse_dt, ++ .execute_tuning = dw_mci_starfive_execute_tuning, ++}; ++ ++static const struct of_device_id dw_mci_starfive_match[] = { ++ { .compatible = "starfive,jh7110-mmc", ++ .data = &starfive_data }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dw_mci_starfive_match); ++ ++static int dw_mci_starfive_probe(struct platform_device *pdev) ++{ ++ return dw_mci_pltfm_register(pdev, &starfive_data); ++} ++ ++static struct platform_driver dw_mci_starfive_driver = { ++ .probe = dw_mci_starfive_probe, ++ .remove = dw_mci_pltfm_remove, ++ .driver = { ++ .name = "dwmmc_starfive", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .of_match_table = dw_mci_starfive_match, ++ }, ++}; ++module_platform_driver(dw_mci_starfive_driver); ++ ++MODULE_DESCRIPTION("StarFive JH7110 Specific DW-MSHC Driver Extension"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:dwmmc_starfive"); diff --git a/target/linux/starfive/patches-6.1/0109-dt-bindings-hwmon-Add-starfive-jh71x0-temp.patch b/target/linux/starfive/patches-6.1/0109-dt-bindings-hwmon-Add-starfive-jh71x0-temp.patch new file mode 100644 index 0000000000..9f6c4128f3 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0109-dt-bindings-hwmon-Add-starfive-jh71x0-temp.patch @@ -0,0 +1,89 @@ +From a0f2b48b5433d2fbcf87e4edf52e5cc26d0c29c8 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Tue, 21 Mar 2023 10:26:43 +0800 +Subject: [PATCH 109/122] dt-bindings: hwmon: Add starfive,jh71x0-temp + +Add bindings for the temperature sensor on the StarFive JH7100 and +JH7110 SoCs. + +Signed-off-by: Emil Renner Berthing +Signed-off-by: Hal Feng +Reviewed-by: Rob Herring +--- + .../bindings/hwmon/starfive,jh71x0-temp.yaml | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml +@@ -0,0 +1,70 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/hwmon/starfive,jh71x0-temp.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH71x0 Temperature Sensor ++ ++maintainers: ++ - Emil Renner Berthing ++ ++description: | ++ StarFive Technology Co. JH71x0 embedded temperature sensor ++ ++properties: ++ compatible: ++ enum: ++ - starfive,jh7100-temp ++ - starfive,jh7110-temp ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ minItems: 2 ++ maxItems: 2 ++ ++ clock-names: ++ items: ++ - const: "sense" ++ - const: "bus" ++ ++ '#thermal-sensor-cells': ++ const: 0 ++ ++ resets: ++ minItems: 2 ++ maxItems: 2 ++ ++ reset-names: ++ items: ++ - const: "sense" ++ - const: "bus" ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - resets ++ - reset-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ ++ temperature-sensor@124a0000 { ++ compatible = "starfive,jh7100-temp"; ++ reg = <0x124a0000 0x10000>; ++ clocks = <&clkgen JH7100_CLK_TEMP_SENSE>, ++ <&clkgen JH7100_CLK_TEMP_APB>; ++ clock-names = "sense", "bus"; ++ #thermal-sensor-cells = <0>; ++ resets = <&rstgen JH7100_RSTN_TEMP_SENSE>, ++ <&rstgen JH7100_RSTN_TEMP_APB>; ++ reset-names = "sense", "bus"; ++ }; diff --git a/target/linux/starfive/patches-6.1/0110-hwmon-sfctemp-Add-StarFive-JH71x0-temperature-sensor.patch b/target/linux/starfive/patches-6.1/0110-hwmon-sfctemp-Add-StarFive-JH71x0-temperature-sensor.patch new file mode 100644 index 0000000000..b52cbd2ba5 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0110-hwmon-sfctemp-Add-StarFive-JH71x0-temperature-sensor.patch @@ -0,0 +1,451 @@ +From 3f68f5d0a8c598a09d26a3908cbbff7312b31487 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Tue, 21 Mar 2023 10:26:44 +0800 +Subject: [PATCH 110/122] hwmon: (sfctemp) Add StarFive JH71x0 temperature + sensor + +Add driver for the StarFive JH71x0 temperature sensor. You +can enable/disable it and read temperature in milli Celcius +through sysfs. + +Signed-off-by: Emil Renner Berthing +Co-developed-by: Samin Guo +Signed-off-by: Samin Guo +Signed-off-by: Hal Feng +--- + Documentation/hwmon/index.rst | 1 + + Documentation/hwmon/sfctemp.rst | 33 ++++ + MAINTAINERS | 8 + + drivers/hwmon/Kconfig | 10 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/sfctemp.c | 331 ++++++++++++++++++++++++++++++++ + 6 files changed, 384 insertions(+) + create mode 100644 Documentation/hwmon/sfctemp.rst + create mode 100644 drivers/hwmon/sfctemp.c + +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -179,6 +179,7 @@ Hardware Monitoring Kernel Drivers + sch5627 + sch5636 + scpi-hwmon ++ sfctemp + sht15 + sht21 + sht3x +--- /dev/null ++++ b/Documentation/hwmon/sfctemp.rst +@@ -0,0 +1,33 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Kernel driver sfctemp ++===================== ++ ++Supported chips: ++ - StarFive JH7100 ++ - StarFive JH7110 ++ ++Authors: ++ - Emil Renner Berthing ++ ++Description ++----------- ++ ++This driver adds support for reading the built-in temperature sensor on the ++JH7100 and JH7110 RISC-V SoCs by StarFive Technology Co. Ltd. ++ ++``sysfs`` interface ++------------------- ++ ++The temperature sensor can be enabled, disabled and queried via the standard ++hwmon interface in sysfs under ``/sys/class/hwmon/hwmonX`` for some value of ++``X``: ++ ++================ ==== ============================================= ++Name Perm Description ++================ ==== ============================================= ++temp1_enable RW Enable or disable temperature sensor. ++ Automatically enabled by the driver, ++ but may be disabled to save power. ++temp1_input RO Temperature reading in milli-degrees Celsius. ++================ ==== ============================================= +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -18679,6 +18679,14 @@ L: netdev@vger.kernel.org + S: Supported + F: drivers/net/ethernet/sfc/ + ++SFCTEMP HWMON DRIVER ++M: Emil Renner Berthing ++L: linux-hwmon@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml ++F: Documentation/hwmon/sfctemp.rst ++F: drivers/hwmon/sfctemp.c ++ + SFF/SFP/SFP+ MODULE SUPPORT + M: Russell King + L: netdev@vger.kernel.org +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1911,6 +1911,16 @@ config SENSORS_STTS751 + This driver can also be built as a module. If so, the module + will be called stts751. + ++config SENSORS_SFCTEMP ++ tristate "Starfive JH71x0 temperature sensor" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ help ++ If you say yes here you get support for temperature sensor ++ on the Starfive JH71x0 SoCs. ++ ++ This driver can also be built as a module. If so, the module ++ will be called sfctemp. ++ + config SENSORS_SMM665 + tristate "Summit Microelectronics SMM665" + depends on I2C +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -179,6 +179,7 @@ obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o + obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o + obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o + obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o ++obj-$(CONFIG_SENSORS_SFCTEMP) += sfctemp.o + obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o + obj-$(CONFIG_SENSORS_SHT15) += sht15.o + obj-$(CONFIG_SENSORS_SHT21) += sht21.o +--- /dev/null ++++ b/drivers/hwmon/sfctemp.c +@@ -0,0 +1,331 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Emil Renner Berthing ++ * Copyright (C) 2021 Samin Guo ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * TempSensor reset. The RSTN can be de-asserted once the analog core has ++ * powered up. Trst(min 100ns) ++ * 0:reset 1:de-assert ++ */ ++#define SFCTEMP_RSTN BIT(0) ++ ++/* ++ * TempSensor analog core power down. The analog core will be powered up ++ * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the ++ * analog core is powered up. ++ * 0:power up 1:power down ++ */ ++#define SFCTEMP_PD BIT(1) ++ ++/* ++ * TempSensor start conversion enable. ++ * 0:disable 1:enable ++ */ ++#define SFCTEMP_RUN BIT(2) ++ ++/* ++ * TempSensor conversion value output. ++ * Temp(C)=DOUT*Y/4094 - K ++ */ ++#define SFCTEMP_DOUT_POS 16 ++#define SFCTEMP_DOUT_MSK GENMASK(27, 16) ++ ++/* DOUT to Celcius conversion constants */ ++#define SFCTEMP_Y1000 237500L ++#define SFCTEMP_Z 4094L ++#define SFCTEMP_K1000 81100L ++ ++struct sfctemp { ++ /* serialize access to hardware register and enabled below */ ++ struct mutex lock; ++ void __iomem *regs; ++ struct clk *clk_sense; ++ struct clk *clk_bus; ++ struct reset_control *rst_sense; ++ struct reset_control *rst_bus; ++ bool enabled; ++}; ++ ++static void sfctemp_power_up(struct sfctemp *sfctemp) ++{ ++ /* make sure we're powered down first */ ++ writel(SFCTEMP_PD, sfctemp->regs); ++ udelay(1); ++ ++ writel(0, sfctemp->regs); ++ /* wait t_pu(50us) + t_rst(100ns) */ ++ usleep_range(60, 200); ++ ++ /* de-assert reset */ ++ writel(SFCTEMP_RSTN, sfctemp->regs); ++ udelay(1); /* wait t_su(500ps) */ ++} ++ ++static void sfctemp_power_down(struct sfctemp *sfctemp) ++{ ++ writel(SFCTEMP_PD, sfctemp->regs); ++} ++ ++static void sfctemp_run(struct sfctemp *sfctemp) ++{ ++ writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs); ++ udelay(1); ++} ++ ++static void sfctemp_stop(struct sfctemp *sfctemp) ++{ ++ writel(SFCTEMP_RSTN, sfctemp->regs); ++} ++ ++static int sfctemp_enable(struct sfctemp *sfctemp) ++{ ++ int ret = 0; ++ ++ mutex_lock(&sfctemp->lock); ++ if (sfctemp->enabled) ++ goto done; ++ ++ ret = clk_prepare_enable(sfctemp->clk_bus); ++ if (ret) ++ goto err; ++ ret = reset_control_deassert(sfctemp->rst_bus); ++ if (ret) ++ goto err_disable_bus; ++ ++ ret = clk_prepare_enable(sfctemp->clk_sense); ++ if (ret) ++ goto err_assert_bus; ++ ret = reset_control_deassert(sfctemp->rst_sense); ++ if (ret) ++ goto err_disable_sense; ++ ++ sfctemp_power_up(sfctemp); ++ sfctemp_run(sfctemp); ++ sfctemp->enabled = true; ++done: ++ mutex_unlock(&sfctemp->lock); ++ return ret; ++ ++err_disable_sense: ++ clk_disable_unprepare(sfctemp->clk_sense); ++err_assert_bus: ++ reset_control_assert(sfctemp->rst_bus); ++err_disable_bus: ++ clk_disable_unprepare(sfctemp->clk_bus); ++err: ++ mutex_unlock(&sfctemp->lock); ++ return ret; ++} ++ ++static int sfctemp_disable(struct sfctemp *sfctemp) ++{ ++ mutex_lock(&sfctemp->lock); ++ if (!sfctemp->enabled) ++ goto done; ++ ++ sfctemp_stop(sfctemp); ++ sfctemp_power_down(sfctemp); ++ reset_control_assert(sfctemp->rst_sense); ++ clk_disable_unprepare(sfctemp->clk_sense); ++ reset_control_assert(sfctemp->rst_bus); ++ clk_disable_unprepare(sfctemp->clk_bus); ++ sfctemp->enabled = false; ++done: ++ mutex_unlock(&sfctemp->lock); ++ return 0; ++} ++ ++static void sfctemp_disable_action(void *data) ++{ ++ sfctemp_disable(data); ++} ++ ++static int sfctemp_convert(struct sfctemp *sfctemp, long *val) ++{ ++ int ret; ++ ++ mutex_lock(&sfctemp->lock); ++ if (!sfctemp->enabled) { ++ ret = -ENODATA; ++ goto out; ++ } ++ ++ /* calculate temperature in milli Celcius */ ++ *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS) ++ * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000; ++ ++ ret = 0; ++out: ++ mutex_unlock(&sfctemp->lock); ++ return ret; ++} ++ ++static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_enable: ++ return 0644; ++ case hwmon_temp_input: ++ return 0444; ++ default: ++ return 0; ++ } ++ default: ++ return 0; ++ } ++} ++ ++static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct sfctemp *sfctemp = dev_get_drvdata(dev); ++ ++ switch (type) { ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_enable: ++ *val = sfctemp->enabled; ++ return 0; ++ case hwmon_temp_input: ++ return sfctemp_convert(sfctemp, val); ++ default: ++ return -EINVAL; ++ } ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct sfctemp *sfctemp = dev_get_drvdata(dev); ++ ++ switch (type) { ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_enable: ++ if (val == 0) ++ return sfctemp_disable(sfctemp); ++ if (val == 1) ++ return sfctemp_enable(sfctemp); ++ return -EINVAL; ++ default: ++ return -EINVAL; ++ } ++ default: ++ return -EINVAL; ++ } ++} ++ ++static const struct hwmon_channel_info *sfctemp_info[] = { ++ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), ++ HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT), ++ NULL ++}; ++ ++static const struct hwmon_ops sfctemp_hwmon_ops = { ++ .is_visible = sfctemp_is_visible, ++ .read = sfctemp_read, ++ .write = sfctemp_write, ++}; ++ ++static const struct hwmon_chip_info sfctemp_chip_info = { ++ .ops = &sfctemp_hwmon_ops, ++ .info = sfctemp_info, ++}; ++ ++static int sfctemp_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device *hwmon_dev; ++ struct sfctemp *sfctemp; ++ int ret; ++ ++ sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL); ++ if (!sfctemp) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, sfctemp); ++ mutex_init(&sfctemp->lock); ++ ++ sfctemp->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(sfctemp->regs)) ++ return PTR_ERR(sfctemp->regs); ++ ++ sfctemp->clk_sense = devm_clk_get(dev, "sense"); ++ if (IS_ERR(sfctemp->clk_sense)) ++ return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense), ++ "error getting sense clock\n"); ++ ++ sfctemp->clk_bus = devm_clk_get(dev, "bus"); ++ if (IS_ERR(sfctemp->clk_bus)) ++ return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus), ++ "error getting bus clock\n"); ++ ++ sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense"); ++ if (IS_ERR(sfctemp->rst_sense)) ++ return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense), ++ "error getting sense reset\n"); ++ ++ sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus"); ++ if (IS_ERR(sfctemp->rst_bus)) ++ return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus), ++ "error getting busreset\n"); ++ ++ ret = reset_control_assert(sfctemp->rst_sense); ++ if (ret) ++ return dev_err_probe(dev, ret, "error asserting sense reset\n"); ++ ++ ret = reset_control_assert(sfctemp->rst_bus); ++ if (ret) ++ return dev_err_probe(dev, ret, "error asserting bus reset\n"); ++ ++ ret = devm_add_action(dev, sfctemp_disable_action, sfctemp); ++ if (ret) ++ return ret; ++ ++ ret = sfctemp_enable(sfctemp); ++ if (ret) ++ return dev_err_probe(dev, ret, "error enabling temperature sensor: %d\n", ret); ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp, ++ &sfctemp_chip_info, NULL); ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static const struct of_device_id sfctemp_of_match[] = { ++ { .compatible = "starfive,jh7100-temp" }, ++ { .compatible = "starfive,jh7110-temp" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, sfctemp_of_match); ++ ++static struct platform_driver sfctemp_driver = { ++ .probe = sfctemp_probe, ++ .driver = { ++ .name = "sfctemp", ++ .of_match_table = sfctemp_of_match, ++ }, ++}; ++module_platform_driver(sfctemp_driver); ++ ++MODULE_AUTHOR("Emil Renner Berthing"); ++MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.1/0111-dt-bindings-dma-snps-dw-axi-dmac-constrain-the-items.patch b/target/linux/starfive/patches-6.1/0111-dt-bindings-dma-snps-dw-axi-dmac-constrain-the-items.patch new file mode 100644 index 0000000000..860c6c0885 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0111-dt-bindings-dma-snps-dw-axi-dmac-constrain-the-items.patch @@ -0,0 +1,62 @@ +From c2f59eeeee68bb66a3db8555474fe94e73b65b02 Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Wed, 22 Mar 2023 17:48:17 +0800 +Subject: [PATCH 111/122] dt-bindings: dma: snps,dw-axi-dmac: constrain the + items of resets for JH7110 dma + +The DMA controller needs two reset items to work properly on JH7110 SoC, +so there is need to constrain the items' value to 2, other platforms +have 1 reset item at most. + +Reviewed-by: Rob Herring +Signed-off-by: Walker Chen +--- + .../bindings/dma/snps,dw-axi-dmac.yaml | 23 ++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml ++++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +@@ -21,6 +21,7 @@ properties: + enum: + - snps,axi-dma-1.01a + - intel,kmb-axi-dma ++ - starfive,jh7110-axi-dma + + reg: + minItems: 1 +@@ -59,7 +60,8 @@ properties: + maximum: 8 + + resets: +- maxItems: 1 ++ minItems: 1 ++ maxItems: 2 + + snps,dma-masters: + description: | +@@ -110,6 +112,25 @@ required: + - snps,priority + - snps,block-size + ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - starfive,jh7110-axi-dma ++then: ++ properties: ++ resets: ++ minItems: 2 ++ items: ++ - description: AXI reset line ++ - description: AHB reset line ++ - description: module reset ++else: ++ properties: ++ resets: ++ maxItems: 1 ++ + additionalProperties: false + + examples: diff --git a/target/linux/starfive/patches-6.1/0112-dmaengine-dw-axi-dmac-Add-support-for-StarFive-JH711.patch b/target/linux/starfive/patches-6.1/0112-dmaengine-dw-axi-dmac-Add-support-for-StarFive-JH711.patch new file mode 100644 index 0000000000..8b15fc213a --- /dev/null +++ b/target/linux/starfive/patches-6.1/0112-dmaengine-dw-axi-dmac-Add-support-for-StarFive-JH711.patch @@ -0,0 +1,122 @@ +From 69ed990fda6795039a2b5b37d8ad5df785f4d97b Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Wed, 22 Mar 2023 17:48:18 +0800 +Subject: [PATCH 112/122] dmaengine: dw-axi-dmac: Add support for StarFive + JH7110 DMA + +Add DMA reset operation in device probe and use different configuration +on CH_CFG registers according to match data. Update all uses of +of_device_is_compatible with of_device_get_match_data. + +Signed-off-by: Walker Chen +Reviewed-by: Emil Renner Berthing +--- + .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 38 ++++++++++++++++--- + drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + + 2 files changed, 34 insertions(+), 5 deletions(-) + +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -21,10 +21,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + +@@ -46,6 +48,10 @@ + DMA_SLAVE_BUSWIDTH_32_BYTES | \ + DMA_SLAVE_BUSWIDTH_64_BYTES) + ++#define AXI_DMA_FLAG_HAS_APB_REGS BIT(0) ++#define AXI_DMA_FLAG_HAS_RESETS BIT(1) ++#define AXI_DMA_FLAG_USE_CFG2 BIT(2) ++ + static inline void + axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val) + { +@@ -86,7 +92,8 @@ static inline void axi_chan_config_write + + cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS | + config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS); +- if (chan->chip->dw->hdata->reg_map_8_channels) { ++ if (chan->chip->dw->hdata->reg_map_8_channels && ++ !chan->chip->dw->hdata->use_cfg2) { + cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS | + config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS | + config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS | +@@ -1367,11 +1374,12 @@ static int parse_device_properties(struc + + static int dw_probe(struct platform_device *pdev) + { +- struct device_node *node = pdev->dev.of_node; + struct axi_dma_chip *chip; + struct resource *mem; + struct dw_axi_dma *dw; + struct dw_axi_dma_hcfg *hdata; ++ struct reset_control *resets; ++ unsigned int flags; + u32 i; + int ret; + +@@ -1400,12 +1408,25 @@ static int dw_probe(struct platform_devi + if (IS_ERR(chip->regs)) + return PTR_ERR(chip->regs); + +- if (of_device_is_compatible(node, "intel,kmb-axi-dma")) { ++ flags = (uintptr_t)of_device_get_match_data(&pdev->dev); ++ if (flags & AXI_DMA_FLAG_HAS_APB_REGS) { + chip->apb_regs = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(chip->apb_regs)) + return PTR_ERR(chip->apb_regs); + } + ++ if (flags & AXI_DMA_FLAG_HAS_RESETS) { ++ resets = devm_reset_control_array_get_exclusive(&pdev->dev); ++ if (IS_ERR(resets)) ++ return PTR_ERR(resets); ++ ++ ret = reset_control_deassert(resets); ++ if (ret) ++ return ret; ++ } ++ ++ chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2); ++ + chip->core_clk = devm_clk_get(chip->dev, "core-clk"); + if (IS_ERR(chip->core_clk)) + return PTR_ERR(chip->core_clk); +@@ -1556,8 +1577,15 @@ static const struct dev_pm_ops dw_axi_dm + }; + + static const struct of_device_id dw_dma_of_id_table[] = { +- { .compatible = "snps,axi-dma-1.01a" }, +- { .compatible = "intel,kmb-axi-dma" }, ++ { ++ .compatible = "snps,axi-dma-1.01a" ++ }, { ++ .compatible = "intel,kmb-axi-dma", ++ .data = (void *)AXI_DMA_FLAG_HAS_APB_REGS, ++ }, { ++ .compatible = "starfive,jh7110-axi-dma", ++ .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), ++ }, + {} + }; + MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +@@ -33,6 +33,7 @@ struct dw_axi_dma_hcfg { + /* Register map for DMAX_NUM_CHANNELS <= 8 */ + bool reg_map_8_channels; + bool restrict_axi_burst_len; ++ bool use_cfg2; + }; + + struct axi_dma_chan { diff --git a/target/linux/starfive/patches-6.1/0113-dmaengine-dw-axi-dmac-Increase-polling-time-to-DMA-t.patch b/target/linux/starfive/patches-6.1/0113-dmaengine-dw-axi-dmac-Increase-polling-time-to-DMA-t.patch new file mode 100644 index 0000000000..903efb43c1 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0113-dmaengine-dw-axi-dmac-Increase-polling-time-to-DMA-t.patch @@ -0,0 +1,29 @@ +From 92c2dc96af79b2f181cc97157ce3ef2be5b48f4c Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Wed, 22 Mar 2023 17:48:19 +0800 +Subject: [PATCH 113/122] dmaengine: dw-axi-dmac: Increase polling time to DMA + transmission completion status + +The bit DMAC_CHEN[0] is automatically cleared by hardware to disable the +channel after the last AMBA transfer of the DMA transfer to the +destination has completed. Software can therefore poll this bit to +determine when this channel is free for a new DMA transfer. +This time requires at least 40 milliseconds on JH7110 SoC, otherwise an +error message 'failed to stop' will be reported. + +Signed-off-by: Walker Chen +--- + 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 +@@ -1147,7 +1147,7 @@ static int dma_chan_terminate_all(struct + axi_chan_disable(chan); + + ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val, +- !(val & chan_active), 1000, 10000); ++ !(val & chan_active), 1000, 50000); + if (ret == -ETIMEDOUT) + dev_warn(dchan2dev(dchan), + "%s failed to stop\n", axi_chan_name(chan)); diff --git a/target/linux/starfive/patches-6.1/0114-RISC-V-Change-suspend_save_csrs-and-suspend_restore_.patch b/target/linux/starfive/patches-6.1/0114-RISC-V-Change-suspend_save_csrs-and-suspend_restore_.patch new file mode 100644 index 0000000000..6c4745462a --- /dev/null +++ b/target/linux/starfive/patches-6.1/0114-RISC-V-Change-suspend_save_csrs-and-suspend_restore_.patch @@ -0,0 +1,50 @@ +From ba1b6ccbf68183b0d9e633ef930c7974144c7b56 Mon Sep 17 00:00:00 2001 +From: Sia Jee Heng +Date: Thu, 30 Mar 2023 14:43:18 +0800 +Subject: [PATCH 114/122] RISC-V: Change suspend_save_csrs and + suspend_restore_csrs to public function + +Currently suspend_save_csrs() and suspend_restore_csrs() functions are +statically defined in the suspend.c. Change the function's attribute +to public so that the functions can be used by hibernation as well. + +Signed-off-by: Sia Jee Heng +Reviewed-by: Ley Foon Tan +Reviewed-by: Mason Huo +Reviewed-by: Conor Dooley +Reviewed-by: Andrew Jones +--- + arch/riscv/include/asm/suspend.h | 3 +++ + arch/riscv/kernel/suspend.c | 4 ++-- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/arch/riscv/include/asm/suspend.h ++++ b/arch/riscv/include/asm/suspend.h +@@ -33,4 +33,7 @@ int cpu_suspend(unsigned long arg, + /* Low-level CPU resume entry function */ + int __cpu_resume_enter(unsigned long hartid, unsigned long context); + ++/* Used to save and restore the CSRs */ ++void suspend_save_csrs(struct suspend_context *context); ++void suspend_restore_csrs(struct suspend_context *context); + #endif +--- a/arch/riscv/kernel/suspend.c ++++ b/arch/riscv/kernel/suspend.c +@@ -8,7 +8,7 @@ + #include + #include + +-static void suspend_save_csrs(struct suspend_context *context) ++void suspend_save_csrs(struct suspend_context *context) + { + context->scratch = csr_read(CSR_SCRATCH); + context->tvec = csr_read(CSR_TVEC); +@@ -29,7 +29,7 @@ static void suspend_save_csrs(struct sus + #endif + } + +-static void suspend_restore_csrs(struct suspend_context *context) ++void suspend_restore_csrs(struct suspend_context *context) + { + csr_write(CSR_SCRATCH, context->scratch); + csr_write(CSR_TVEC, context->tvec); diff --git a/target/linux/starfive/patches-6.1/0115-RISC-V-Factor-out-common-code-of-__cpu_resume_enter.patch b/target/linux/starfive/patches-6.1/0115-RISC-V-Factor-out-common-code-of-__cpu_resume_enter.patch new file mode 100644 index 0000000000..ccdb77b05c --- /dev/null +++ b/target/linux/starfive/patches-6.1/0115-RISC-V-Factor-out-common-code-of-__cpu_resume_enter.patch @@ -0,0 +1,136 @@ +From f0e2b8f9bb240d7391d3eeca55534160fd385ea8 Mon Sep 17 00:00:00 2001 +From: Sia Jee Heng +Date: Thu, 30 Mar 2023 14:43:19 +0800 +Subject: [PATCH 115/122] RISC-V: Factor out common code of + __cpu_resume_enter() + +The cpu_resume() function is very similar for the suspend to disk and +suspend to ram cases. Factor out the common code into suspend_restore_csrs +macro and suspend_restore_regs macro. + +Signed-off-by: Sia Jee Heng +Reviewed-by: Andrew Jones +Reviewed-by: Conor Dooley +--- + arch/riscv/include/asm/assembler.h | 62 ++++++++++++++++++++++++++++++ + arch/riscv/kernel/suspend_entry.S | 34 ++-------------- + 2 files changed, 65 insertions(+), 31 deletions(-) + create mode 100644 arch/riscv/include/asm/assembler.h + +--- /dev/null ++++ b/arch/riscv/include/asm/assembler.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * ++ * Author: Jee Heng Sia ++ */ ++ ++#ifndef __ASSEMBLY__ ++#error "Only include this from assembly code" ++#endif ++ ++#ifndef __ASM_ASSEMBLER_H ++#define __ASM_ASSEMBLER_H ++ ++#include ++#include ++#include ++ ++/* ++ * suspend_restore_csrs - restore CSRs ++ */ ++ .macro suspend_restore_csrs ++ REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0) ++ csrw CSR_EPC, t0 ++ REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0) ++ csrw CSR_STATUS, t0 ++ REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0) ++ csrw CSR_TVAL, t0 ++ REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0) ++ csrw CSR_CAUSE, t0 ++ .endm ++ ++/* ++ * suspend_restore_regs - Restore registers (except A0 and T0-T6) ++ */ ++ .macro suspend_restore_regs ++ REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0) ++ REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0) ++ REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0) ++ REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0) ++ REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0) ++ REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0) ++ REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0) ++ REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0) ++ REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0) ++ REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0) ++ REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0) ++ REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0) ++ REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0) ++ REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0) ++ REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0) ++ REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0) ++ REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0) ++ REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0) ++ REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0) ++ REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0) ++ REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0) ++ REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0) ++ REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) ++ .endm ++ ++#endif /* __ASM_ASSEMBLER_H */ +--- a/arch/riscv/kernel/suspend_entry.S ++++ b/arch/riscv/kernel/suspend_entry.S +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -83,39 +84,10 @@ ENTRY(__cpu_resume_enter) + add a0, a1, zero + + /* Restore CSRs */ +- REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0) +- csrw CSR_EPC, t0 +- REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0) +- csrw CSR_STATUS, t0 +- REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0) +- csrw CSR_TVAL, t0 +- REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0) +- csrw CSR_CAUSE, t0 ++ suspend_restore_csrs + + /* Restore registers (except A0 and T0-T6) */ +- REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0) +- REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0) +- REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0) +- REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0) +- REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0) +- REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0) +- REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0) +- REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0) +- REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0) +- REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0) +- REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0) +- REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0) +- REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0) +- REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0) +- REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0) +- REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0) +- REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0) +- REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0) +- REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0) +- REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0) +- REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0) +- REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0) +- REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) ++ suspend_restore_regs + + /* Return zero value */ + add a0, zero, zero diff --git a/target/linux/starfive/patches-6.1/0116-RISC-V-Add-arch-functions-to-support-hibernation-sus.patch b/target/linux/starfive/patches-6.1/0116-RISC-V-Add-arch-functions-to-support-hibernation-sus.patch new file mode 100644 index 0000000000..eae0559d9c --- /dev/null +++ b/target/linux/starfive/patches-6.1/0116-RISC-V-Add-arch-functions-to-support-hibernation-sus.patch @@ -0,0 +1,673 @@ +From 06f1d699e923c3f09869439cdb603e36302c2611 Mon Sep 17 00:00:00 2001 +From: Sia Jee Heng +Date: Thu, 30 Mar 2023 14:43:21 +0800 +Subject: [PATCH 116/122] RISC-V: Add arch functions to support + hibernation/suspend-to-disk + +Low level Arch functions were created to support hibernation. +swsusp_arch_suspend() relies code from __cpu_suspend_enter() to write +cpu state onto the stack, then calling swsusp_save() to save the memory +image. + +Arch specific hibernation header is implemented and is utilized by the +arch_hibernation_header_restore() and arch_hibernation_header_save() +functions. The arch specific hibernation header consists of satp, hartid, +and the cpu_resume address. The kernel built version is also need to be +saved into the hibernation image header to making sure only the same +kernel is restore when resume. + +swsusp_arch_resume() creates a temporary page table that covering only +the linear map. It copies the restore code to a 'safe' page, then start +to restore the memory image. Once completed, it restores the original +kernel's page table. It then calls into __hibernate_cpu_resume() +to restore the CPU context. Finally, it follows the normal hibernation +path back to the hibernation core. + +To enable hibernation/suspend to disk into RISCV, the below config +need to be enabled: +- CONFIG_HIBERNATION +- CONFIG_ARCH_HIBERNATION_HEADER +- CONFIG_ARCH_HIBERNATION_POSSIBLE + +Signed-off-by: Sia Jee Heng +Reviewed-by: Ley Foon Tan +Reviewed-by: Mason Huo +Reviewed-by: Conor Dooley +Reviewed-by: Andrew Jones +--- + arch/riscv/Kconfig | 8 +- + arch/riscv/include/asm/assembler.h | 20 ++ + arch/riscv/include/asm/suspend.h | 19 ++ + arch/riscv/kernel/Makefile | 1 + + arch/riscv/kernel/asm-offsets.c | 5 + + arch/riscv/kernel/hibernate-asm.S | 77 ++++++ + arch/riscv/kernel/hibernate.c | 427 +++++++++++++++++++++++++++++ + 7 files changed, 556 insertions(+), 1 deletion(-) + create mode 100644 arch/riscv/kernel/hibernate-asm.S + create mode 100644 arch/riscv/kernel/hibernate.c + +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -52,7 +52,7 @@ config RISCV + select CLONE_BACKWARDS + select CLINT_TIMER if !MMU + select COMMON_CLK +- select CPU_PM if CPU_IDLE ++ select CPU_PM if CPU_IDLE || HIBERNATION + select EDAC_SUPPORT + select GENERIC_ARCH_TOPOLOGY + select GENERIC_ATOMIC64 if !64BIT +@@ -715,6 +715,12 @@ menu "Power management options" + + source "kernel/power/Kconfig" + ++config ARCH_HIBERNATION_POSSIBLE ++ def_bool y ++ ++config ARCH_HIBERNATION_HEADER ++ def_bool HIBERNATION ++ + endmenu # "Power management options" + + menu "CPU Power Management" +--- a/arch/riscv/include/asm/assembler.h ++++ b/arch/riscv/include/asm/assembler.h +@@ -59,4 +59,24 @@ + REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) + .endm + ++/* ++ * copy_page - copy 1 page (4KB) of data from source to destination ++ * @a0 - destination ++ * @a1 - source ++ */ ++ .macro copy_page a0, a1 ++ lui a2, 0x1 ++ add a2, a2, a0 ++1 : ++ REG_L t0, 0(a1) ++ REG_L t1, SZREG(a1) ++ ++ REG_S t0, 0(a0) ++ REG_S t1, SZREG(a0) ++ ++ addi a0, a0, 2 * SZREG ++ addi a1, a1, 2 * SZREG ++ bne a2, a0, 1b ++ .endm ++ + #endif /* __ASM_ASSEMBLER_H */ +--- a/arch/riscv/include/asm/suspend.h ++++ b/arch/riscv/include/asm/suspend.h +@@ -21,6 +21,11 @@ struct suspend_context { + #endif + }; + ++/* ++ * Used by hibernation core and cleared during resume sequence ++ */ ++extern int in_suspend; ++ + /* Low-level CPU suspend entry function */ + int __cpu_suspend_enter(struct suspend_context *context); + +@@ -36,4 +41,18 @@ int __cpu_resume_enter(unsigned long har + /* Used to save and restore the CSRs */ + void suspend_save_csrs(struct suspend_context *context); + void suspend_restore_csrs(struct suspend_context *context); ++ ++/* Low-level API to support hibernation */ ++int swsusp_arch_suspend(void); ++int swsusp_arch_resume(void); ++int arch_hibernation_header_save(void *addr, unsigned int max_size); ++int arch_hibernation_header_restore(void *addr); ++int __hibernate_cpu_resume(void); ++ ++/* Used to resume on the CPU we hibernated on */ ++int hibernate_resume_nonboot_cpu_disable(void); ++ ++asmlinkage void hibernate_restore_image(unsigned long resume_satp, unsigned long satp_temp, ++ unsigned long cpu_resume); ++asmlinkage int hibernate_core_restore_code(void); + #endif +--- a/arch/riscv/kernel/Makefile ++++ b/arch/riscv/kernel/Makefile +@@ -65,6 +65,7 @@ obj-$(CONFIG_MODULES) += module.o + obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o + + obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o ++obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o + + obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o + obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o +--- a/arch/riscv/kernel/asm-offsets.c ++++ b/arch/riscv/kernel/asm-offsets.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -116,6 +117,10 @@ void asm_offsets(void) + + OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs); + ++ OFFSET(HIBERN_PBE_ADDR, pbe, address); ++ OFFSET(HIBERN_PBE_ORIG, pbe, orig_address); ++ OFFSET(HIBERN_PBE_NEXT, pbe, next); ++ + OFFSET(KVM_ARCH_GUEST_ZERO, kvm_vcpu_arch, guest_context.zero); + OFFSET(KVM_ARCH_GUEST_RA, kvm_vcpu_arch, guest_context.ra); + OFFSET(KVM_ARCH_GUEST_SP, kvm_vcpu_arch, guest_context.sp); +--- /dev/null ++++ b/arch/riscv/kernel/hibernate-asm.S +@@ -0,0 +1,77 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Hibernation low level support for RISCV. ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * ++ * Author: Jee Heng Sia ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* ++ * int __hibernate_cpu_resume(void) ++ * Switch back to the hibernated image's page table prior to restoring the CPU ++ * context. ++ * ++ * Always returns 0 ++ */ ++ENTRY(__hibernate_cpu_resume) ++ /* switch to hibernated image's page table. */ ++ csrw CSR_SATP, s0 ++ sfence.vma ++ ++ REG_L a0, hibernate_cpu_context ++ ++ suspend_restore_csrs ++ suspend_restore_regs ++ ++ /* Return zero value. */ ++ mv a0, zero ++ ++ ret ++END(__hibernate_cpu_resume) ++ ++/* ++ * Prepare to restore the image. ++ * a0: satp of saved page tables. ++ * a1: satp of temporary page tables. ++ * a2: cpu_resume. ++ */ ++ENTRY(hibernate_restore_image) ++ mv s0, a0 ++ mv s1, a1 ++ mv s2, a2 ++ REG_L s4, restore_pblist ++ REG_L a1, relocated_restore_code ++ ++ jalr a1 ++END(hibernate_restore_image) ++ ++/* ++ * The below code will be executed from a 'safe' page. ++ * It first switches to the temporary page table, then starts to copy the pages ++ * back to the original memory location. Finally, it jumps to __hibernate_cpu_resume() ++ * to restore the CPU context. ++ */ ++ENTRY(hibernate_core_restore_code) ++ /* switch to temp page table. */ ++ csrw satp, s1 ++ sfence.vma ++.Lcopy: ++ /* The below code will restore the hibernated image. */ ++ REG_L a1, HIBERN_PBE_ADDR(s4) ++ REG_L a0, HIBERN_PBE_ORIG(s4) ++ ++ copy_page a0, a1 ++ ++ REG_L s4, HIBERN_PBE_NEXT(s4) ++ bnez s4, .Lcopy ++ ++ jalr s2 ++END(hibernate_core_restore_code) +--- /dev/null ++++ b/arch/riscv/kernel/hibernate.c +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Hibernation support for RISCV ++ * ++ * Copyright (C) 2023 StarFive Technology Co., Ltd. ++ * ++ * Author: Jee Heng Sia ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* The logical cpu number we should resume on, initialised to a non-cpu number. */ ++static int sleep_cpu = -EINVAL; ++ ++/* Pointer to the temporary resume page table. */ ++static pgd_t *resume_pg_dir; ++ ++/* CPU context to be saved. */ ++struct suspend_context *hibernate_cpu_context; ++EXPORT_SYMBOL_GPL(hibernate_cpu_context); ++ ++unsigned long relocated_restore_code; ++EXPORT_SYMBOL_GPL(relocated_restore_code); ++ ++/** ++ * struct arch_hibernate_hdr_invariants - container to store kernel build version. ++ * @uts_version: to save the build number and date so that we do not resume with ++ * a different kernel. ++ */ ++struct arch_hibernate_hdr_invariants { ++ char uts_version[__NEW_UTS_LEN + 1]; ++}; ++ ++/** ++ * struct arch_hibernate_hdr - helper parameters that help us to restore the image. ++ * @invariants: container to store kernel build version. ++ * @hartid: to make sure same boot_cpu executes the hibernate/restore code. ++ * @saved_satp: original page table used by the hibernated image. ++ * @restore_cpu_addr: the kernel's image address to restore the CPU context. ++ */ ++static struct arch_hibernate_hdr { ++ struct arch_hibernate_hdr_invariants invariants; ++ unsigned long hartid; ++ unsigned long saved_satp; ++ unsigned long restore_cpu_addr; ++} resume_hdr; ++ ++static void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i) ++{ ++ memset(i, 0, sizeof(*i)); ++ memcpy(i->uts_version, init_utsname()->version, sizeof(i->uts_version)); ++} ++ ++/* ++ * Check if the given pfn is in the 'nosave' section. ++ */ ++int pfn_is_nosave(unsigned long pfn) ++{ ++ unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin); ++ unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1); ++ ++ return ((pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn)); ++} ++ ++void notrace save_processor_state(void) ++{ ++ WARN_ON(num_online_cpus() != 1); ++} ++ ++void notrace restore_processor_state(void) ++{ ++} ++ ++/* ++ * Helper parameters need to be saved to the hibernation image header. ++ */ ++int arch_hibernation_header_save(void *addr, unsigned int max_size) ++{ ++ struct arch_hibernate_hdr *hdr = addr; ++ ++ if (max_size < sizeof(*hdr)) ++ return -EOVERFLOW; ++ ++ arch_hdr_invariants(&hdr->invariants); ++ ++ hdr->hartid = cpuid_to_hartid_map(sleep_cpu); ++ hdr->saved_satp = csr_read(CSR_SATP); ++ hdr->restore_cpu_addr = (unsigned long)__hibernate_cpu_resume; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(arch_hibernation_header_save); ++ ++/* ++ * Retrieve the helper parameters from the hibernation image header. ++ */ ++int arch_hibernation_header_restore(void *addr) ++{ ++ struct arch_hibernate_hdr_invariants invariants; ++ struct arch_hibernate_hdr *hdr = addr; ++ int ret = 0; ++ ++ arch_hdr_invariants(&invariants); ++ ++ if (memcmp(&hdr->invariants, &invariants, sizeof(invariants))) { ++ pr_crit("Hibernate image not generated by this kernel!\n"); ++ return -EINVAL; ++ } ++ ++ sleep_cpu = riscv_hartid_to_cpuid(hdr->hartid); ++ if (sleep_cpu < 0) { ++ pr_crit("Hibernated on a CPU not known to this kernel!\n"); ++ sleep_cpu = -EINVAL; ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_SMP ++ ret = bringup_hibernate_cpu(sleep_cpu); ++ if (ret) { ++ sleep_cpu = -EINVAL; ++ return ret; ++ } ++#endif ++ resume_hdr = *hdr; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(arch_hibernation_header_restore); ++ ++int swsusp_arch_suspend(void) ++{ ++ int ret = 0; ++ ++ if (__cpu_suspend_enter(hibernate_cpu_context)) { ++ sleep_cpu = smp_processor_id(); ++ suspend_save_csrs(hibernate_cpu_context); ++ ret = swsusp_save(); ++ } else { ++ suspend_restore_csrs(hibernate_cpu_context); ++ flush_tlb_all(); ++ flush_icache_all(); ++ ++ /* ++ * Tell the hibernation core that we've just restored the memory. ++ */ ++ in_suspend = 0; ++ sleep_cpu = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int temp_pgtable_map_pte(pmd_t *dst_pmdp, pmd_t *src_pmdp, unsigned long start, ++ unsigned long end, pgprot_t prot) ++{ ++ pte_t *src_ptep; ++ pte_t *dst_ptep; ++ ++ if (pmd_none(READ_ONCE(*dst_pmdp))) { ++ dst_ptep = (pte_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_ptep) ++ return -ENOMEM; ++ ++ pmd_populate_kernel(NULL, dst_pmdp, dst_ptep); ++ } ++ ++ dst_ptep = pte_offset_kernel(dst_pmdp, start); ++ src_ptep = pte_offset_kernel(src_pmdp, start); ++ ++ do { ++ pte_t pte = READ_ONCE(*src_ptep); ++ ++ if (pte_present(pte)) ++ set_pte(dst_ptep, __pte(pte_val(pte) | pgprot_val(prot))); ++ } while (dst_ptep++, src_ptep++, start += PAGE_SIZE, start < end); ++ ++ return 0; ++} ++ ++static int temp_pgtable_map_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start, ++ unsigned long end, pgprot_t prot) ++{ ++ unsigned long next; ++ unsigned long ret; ++ pmd_t *src_pmdp; ++ pmd_t *dst_pmdp; ++ ++ if (pud_none(READ_ONCE(*dst_pudp))) { ++ dst_pmdp = (pmd_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_pmdp) ++ return -ENOMEM; ++ ++ pud_populate(NULL, dst_pudp, dst_pmdp); ++ } ++ ++ dst_pmdp = pmd_offset(dst_pudp, start); ++ src_pmdp = pmd_offset(src_pudp, start); ++ ++ do { ++ pmd_t pmd = READ_ONCE(*src_pmdp); ++ ++ next = pmd_addr_end(start, end); ++ ++ if (pmd_none(pmd)) ++ continue; ++ ++ if (pmd_leaf(pmd)) { ++ set_pmd(dst_pmdp, __pmd(pmd_val(pmd) | pgprot_val(prot))); ++ } else { ++ ret = temp_pgtable_map_pte(dst_pmdp, src_pmdp, start, next, prot); ++ if (ret) ++ return -ENOMEM; ++ } ++ } while (dst_pmdp++, src_pmdp++, start = next, start != end); ++ ++ return 0; ++} ++ ++static int temp_pgtable_map_pud(p4d_t *dst_p4dp, p4d_t *src_p4dp, unsigned long start, ++ unsigned long end, pgprot_t prot) ++{ ++ unsigned long next; ++ unsigned long ret; ++ pud_t *dst_pudp; ++ pud_t *src_pudp; ++ ++ if (p4d_none(READ_ONCE(*dst_p4dp))) { ++ dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_pudp) ++ return -ENOMEM; ++ ++ p4d_populate(NULL, dst_p4dp, dst_pudp); ++ } ++ ++ dst_pudp = pud_offset(dst_p4dp, start); ++ src_pudp = pud_offset(src_p4dp, start); ++ ++ do { ++ pud_t pud = READ_ONCE(*src_pudp); ++ ++ next = pud_addr_end(start, end); ++ ++ if (pud_none(pud)) ++ continue; ++ ++ if (pud_leaf(pud)) { ++ set_pud(dst_pudp, __pud(pud_val(pud) | pgprot_val(prot))); ++ } else { ++ ret = temp_pgtable_map_pmd(dst_pudp, src_pudp, start, next, prot); ++ if (ret) ++ return -ENOMEM; ++ } ++ } while (dst_pudp++, src_pudp++, start = next, start != end); ++ ++ return 0; ++} ++ ++static int temp_pgtable_map_p4d(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, ++ unsigned long end, pgprot_t prot) ++{ ++ unsigned long next; ++ unsigned long ret; ++ p4d_t *dst_p4dp; ++ p4d_t *src_p4dp; ++ ++ if (pgd_none(READ_ONCE(*dst_pgdp))) { ++ dst_p4dp = (p4d_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_p4dp) ++ return -ENOMEM; ++ ++ pgd_populate(NULL, dst_pgdp, dst_p4dp); ++ } ++ ++ dst_p4dp = p4d_offset(dst_pgdp, start); ++ src_p4dp = p4d_offset(src_pgdp, start); ++ ++ do { ++ p4d_t p4d = READ_ONCE(*src_p4dp); ++ ++ next = p4d_addr_end(start, end); ++ ++ if (p4d_none(p4d)) ++ continue; ++ ++ if (p4d_leaf(p4d)) { ++ set_p4d(dst_p4dp, __p4d(p4d_val(p4d) | pgprot_val(prot))); ++ } else { ++ ret = temp_pgtable_map_pud(dst_p4dp, src_p4dp, start, next, prot); ++ if (ret) ++ return -ENOMEM; ++ } ++ } while (dst_p4dp++, src_p4dp++, start = next, start != end); ++ ++ return 0; ++} ++ ++static int temp_pgtable_mapping(pgd_t *pgdp, unsigned long start, unsigned long end, pgprot_t prot) ++{ ++ pgd_t *dst_pgdp = pgd_offset_pgd(pgdp, start); ++ pgd_t *src_pgdp = pgd_offset_k(start); ++ unsigned long next; ++ unsigned long ret; ++ ++ do { ++ pgd_t pgd = READ_ONCE(*src_pgdp); ++ ++ next = pgd_addr_end(start, end); ++ ++ if (pgd_none(pgd)) ++ continue; ++ ++ if (pgd_leaf(pgd)) { ++ set_pgd(dst_pgdp, __pgd(pgd_val(pgd) | pgprot_val(prot))); ++ } else { ++ ret = temp_pgtable_map_p4d(dst_pgdp, src_pgdp, start, next, prot); ++ if (ret) ++ return -ENOMEM; ++ } ++ } while (dst_pgdp++, src_pgdp++, start = next, start != end); ++ ++ return 0; ++} ++ ++static unsigned long relocate_restore_code(void) ++{ ++ void *page = (void *)get_safe_page(GFP_ATOMIC); ++ ++ if (!page) ++ return -ENOMEM; ++ ++ copy_page(page, hibernate_core_restore_code); ++ ++ /* Make the page containing the relocated code executable. */ ++ set_memory_x((unsigned long)page, 1); ++ ++ return (unsigned long)page; ++} ++ ++int swsusp_arch_resume(void) ++{ ++ unsigned long end = (unsigned long)pfn_to_virt(max_low_pfn); ++ unsigned long start = PAGE_OFFSET; ++ int ret; ++ ++ /* ++ * Memory allocated by get_safe_page() will be dealt with by the hibernation core, ++ * we don't need to free it here. ++ */ ++ resume_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC); ++ if (!resume_pg_dir) ++ return -ENOMEM; ++ ++ /* ++ * Create a temporary page table and map the whole linear region as executable and ++ * writable. ++ */ ++ ret = temp_pgtable_mapping(resume_pg_dir, start, end, __pgprot(_PAGE_WRITE | _PAGE_EXEC)); ++ if (ret) ++ return ret; ++ ++ /* Move the restore code to a new page so that it doesn't get overwritten by itself. */ ++ relocated_restore_code = relocate_restore_code(); ++ if (relocated_restore_code == -ENOMEM) ++ return -ENOMEM; ++ ++ /* ++ * Map the __hibernate_cpu_resume() address to the temporary page table so that the ++ * restore code can jumps to it after finished restore the image. The next execution ++ * code doesn't find itself in a different address space after switching over to the ++ * original page table used by the hibernated image. ++ * The __hibernate_cpu_resume() mapping is unnecessary for RV32 since the kernel and ++ * linear addresses are identical, but different for RV64. To ensure consistency, we ++ * map it for both RV32 and RV64 kernels. ++ * Additionally, we should ensure that the page is writable before restoring the image. ++ */ ++ start = (unsigned long)resume_hdr.restore_cpu_addr; ++ end = start + PAGE_SIZE; ++ ++ ret = temp_pgtable_mapping(resume_pg_dir, start, end, __pgprot(_PAGE_WRITE)); ++ if (ret) ++ return ret; ++ ++ hibernate_restore_image(resume_hdr.saved_satp, (PFN_DOWN(__pa(resume_pg_dir)) | satp_mode), ++ resume_hdr.restore_cpu_addr); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP_SMP ++int hibernate_resume_nonboot_cpu_disable(void) ++{ ++ if (sleep_cpu < 0) { ++ pr_err("Failing to resume from hibernate on an unknown CPU\n"); ++ return -ENODEV; ++ } ++ ++ return freeze_secondary_cpus(sleep_cpu); ++} ++#endif ++ ++static int __init riscv_hibernate_init(void) ++{ ++ hibernate_cpu_context = kzalloc(sizeof(*hibernate_cpu_context), GFP_KERNEL); ++ ++ if (WARN_ON(!hibernate_cpu_context)) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++early_initcall(riscv_hibernate_init); diff --git a/target/linux/starfive/patches-6.1/0117-driver-mfd-axp20x-Add-support-for-AXP15060.patch b/target/linux/starfive/patches-6.1/0117-driver-mfd-axp20x-Add-support-for-AXP15060.patch new file mode 100644 index 0000000000..18ad298065 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0117-driver-mfd-axp20x-Add-support-for-AXP15060.patch @@ -0,0 +1,1014 @@ +From e62161318f2fe3e396fc31c50d210e99bec83021 Mon Sep 17 00:00:00 2001 +From: "ziv.xu" +Date: Fri, 4 Aug 2023 13:53:10 +0800 +Subject: [PATCH 117/122] driver: mfd: axp20x: Add support for AXP15060 + +axp20x add support for AXP15060 + +Signed-off-by: ziv.xu +--- + drivers/mfd/axp20x-i2c.c | 2 + + drivers/mfd/axp20x.c | 373 ++++++++++++++++++++++++++++++++++--- + include/linux/mfd/axp20x.h | 218 +++++++++++++++++++++- + 3 files changed, 557 insertions(+), 36 deletions(-) + +--- a/drivers/mfd/axp20x-i2c.c ++++ b/drivers/mfd/axp20x-i2c.c +@@ -66,6 +66,7 @@ static const struct of_device_id axp20x_ + { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, + { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, + { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, ++ { .compatible = "x-powers,axp15060", .data = (void *)AXP15060_ID }, + { }, + }; + MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); +@@ -79,6 +80,7 @@ static const struct i2c_device_id axp20x + { "axp223", 0 }, + { "axp803", 0 }, + { "axp806", 0 }, ++ { "axp15060", 0 }, + { }, + }; + MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); +--- a/drivers/mfd/axp20x.c ++++ b/drivers/mfd/axp20x.c +@@ -23,7 +23,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +@@ -34,15 +34,18 @@ + + static const char * const axp20x_model_names[] = { + "AXP152", ++ "AXP192", + "AXP202", + "AXP209", + "AXP221", + "AXP223", + "AXP288", ++ "AXP313a", + "AXP803", + "AXP806", + "AXP809", + "AXP813", ++ "AXP15060", + }; + + static const struct regmap_range axp152_writeable_ranges[] = { +@@ -92,6 +95,35 @@ static const struct regmap_access_table + .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), + }; + ++static const struct regmap_range axp192_writeable_ranges[] = { ++ regmap_reg_range(AXP192_DATACACHE(0), AXP192_DATACACHE(5)), ++ regmap_reg_range(AXP192_PWR_OUT_CTRL, AXP192_IRQ5_STATE), ++ regmap_reg_range(AXP20X_DCDC_MODE, AXP192_N_RSTO_CTRL), ++ regmap_reg_range(AXP20X_CC_CTRL, AXP20X_CC_CTRL), ++}; ++ ++static const struct regmap_range axp192_volatile_ranges[] = { ++ regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP192_USB_OTG_STATUS), ++ regmap_reg_range(AXP192_IRQ1_STATE, AXP192_IRQ4_STATE), ++ regmap_reg_range(AXP192_IRQ5_STATE, AXP192_IRQ5_STATE), ++ regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L), ++ regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL), ++ regmap_reg_range(AXP192_GPIO2_0_STATE, AXP192_GPIO2_0_STATE), ++ regmap_reg_range(AXP192_GPIO4_3_STATE, AXP192_GPIO4_3_STATE), ++ regmap_reg_range(AXP192_N_RSTO_CTRL, AXP192_N_RSTO_CTRL), ++ regmap_reg_range(AXP20X_CHRG_CC_31_24, AXP20X_CC_CTRL), ++}; ++ ++static const struct regmap_access_table axp192_writeable_table = { ++ .yes_ranges = axp192_writeable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(axp192_writeable_ranges), ++}; ++ ++static const struct regmap_access_table axp192_volatile_table = { ++ .yes_ranges = axp192_volatile_ranges, ++ .n_yes_ranges = ARRAY_SIZE(axp192_volatile_ranges), ++}; ++ + /* AXP22x ranges are shared with the AXP809, as they cover the same range */ + static const struct regmap_range axp22x_writeable_ranges[] = { + regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), +@@ -119,6 +151,7 @@ static const struct regmap_access_table + + /* AXP288 ranges are shared with the AXP803, as they cover the same range */ + static const struct regmap_range axp288_writeable_ranges[] = { ++ regmap_reg_range(AXP288_POWER_REASON, AXP288_POWER_REASON), + regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), + regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), + }; +@@ -154,6 +187,25 @@ static const struct regmap_range axp806_ + regmap_reg_range(AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT), + }; + ++static const struct regmap_range axp313a_writeable_ranges[] = { ++ regmap_reg_range(AXP313A_ON_INDICATE, AXP313A_IRQ_STATE), ++}; ++ ++static const struct regmap_range axp313a_volatile_ranges[] = { ++ regmap_reg_range(AXP313A_SHUTDOWN_CTRL, AXP313A_SHUTDOWN_CTRL), ++ regmap_reg_range(AXP313A_IRQ_STATE, AXP313A_IRQ_STATE), ++}; ++ ++static const struct regmap_access_table axp313a_writeable_table = { ++ .yes_ranges = axp313a_writeable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(axp313a_writeable_ranges), ++}; ++ ++static const struct regmap_access_table axp313a_volatile_table = { ++ .yes_ranges = axp313a_volatile_ranges, ++ .n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges), ++}; ++ + static const struct regmap_range axp806_volatile_ranges[] = { + regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE), + }; +@@ -168,11 +220,49 @@ static const struct regmap_access_table + .n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges), + }; + ++static const struct regmap_range axp15060_writeable_ranges[] = { ++ regmap_reg_range(AXP15060_PWR_OUT_CTRL1, AXP15060_DCDC_MODE_CTRL2), ++ regmap_reg_range(AXP15060_OUTPUT_MONITOR_DISCHARGE, AXP15060_CPUSLDO_V_CTRL), ++ regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ), ++ regmap_reg_range(AXP15060_PEK_KEY, AXP15060_PEK_KEY), ++ regmap_reg_range(AXP15060_IRQ1_EN, AXP15060_IRQ2_EN), ++ regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE), ++}; ++ ++static const struct regmap_range axp15060_volatile_ranges[] = { ++ regmap_reg_range(AXP15060_STARTUP_SRC, AXP15060_STARTUP_SRC), ++ regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ), ++ regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE), ++}; ++ ++static const struct regmap_access_table axp15060_writeable_table = { ++ .yes_ranges = axp15060_writeable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(axp15060_writeable_ranges), ++}; ++ ++static const struct regmap_access_table axp15060_volatile_table = { ++ .yes_ranges = axp15060_volatile_ranges, ++ .n_yes_ranges = ARRAY_SIZE(axp15060_volatile_ranges), ++}; ++ + static const struct resource axp152_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), + }; + ++static const struct resource axp192_ac_power_supply_resources[] = { ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"), ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"), ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_OVER_V, "ACIN_OVER_V"), ++}; ++ ++static const struct resource axp192_usb_power_supply_resources[] = { ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_VALID, "VBUS_VALID"), ++ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_NOT_VALID, "VBUS_NOT_VALID"), ++}; ++ + static const struct resource axp20x_ac_power_supply_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"), + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"), +@@ -221,6 +311,11 @@ static const struct resource axp288_fuel + DEFINE_RES_IRQ(AXP288_IRQ_WL1), + }; + ++static const struct resource axp313a_pek_resources[] = { ++ DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_RIS_EDGE, "PEK_DBR"), ++ DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_FAL_EDGE, "PEK_DBF"), ++}; ++ + static const struct resource axp803_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_FAL_EDGE, "PEK_DBF"), +@@ -236,6 +331,11 @@ static const struct resource axp809_pek_ + DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_FAL_EDGE, "PEK_DBF"), + }; + ++static const struct resource axp15060_pek_resources[] = { ++ DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_RIS_EDGE, "PEK_DBR"), ++ DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_FAL_EDGE, "PEK_DBF"), ++}; ++ + static const struct regmap_config axp152_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +@@ -245,6 +345,15 @@ static const struct regmap_config axp152 + .cache_type = REGCACHE_RBTREE, + }; + ++static const struct regmap_config axp192_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .wr_table = &axp192_writeable_table, ++ .volatile_table = &axp192_volatile_table, ++ .max_register = AXP20X_CC_CTRL, ++ .cache_type = REGCACHE_RBTREE, ++}; ++ + static const struct regmap_config axp20x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +@@ -272,6 +381,15 @@ static const struct regmap_config axp288 + .cache_type = REGCACHE_RBTREE, + }; + ++static const struct regmap_config axp313a_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .wr_table = &axp313a_writeable_table, ++ .volatile_table = &axp313a_volatile_table, ++ .max_register = AXP313A_IRQ_STATE, ++ .cache_type = REGCACHE_RBTREE, ++}; ++ + static const struct regmap_config axp806_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +@@ -281,6 +399,15 @@ static const struct regmap_config axp806 + .cache_type = REGCACHE_RBTREE, + }; + ++static const struct regmap_config axp15060_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .wr_table = &axp15060_writeable_table, ++ .volatile_table = &axp15060_volatile_table, ++ .max_register = AXP15060_IRQ2_STATE, ++ .cache_type = REGCACHE_RBTREE, ++}; ++ + #define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \ + [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } + +@@ -304,6 +431,42 @@ static const struct regmap_irq axp152_re + INIT_REGMAP_IRQ(AXP152, GPIO0_INPUT, 2, 0), + }; + ++static const struct regmap_irq axp192_regmap_irqs[] = { ++ INIT_REGMAP_IRQ(AXP192, ACIN_OVER_V, 0, 7), ++ INIT_REGMAP_IRQ(AXP192, ACIN_PLUGIN, 0, 6), ++ INIT_REGMAP_IRQ(AXP192, ACIN_REMOVAL, 0, 5), ++ INIT_REGMAP_IRQ(AXP192, VBUS_OVER_V, 0, 4), ++ INIT_REGMAP_IRQ(AXP192, VBUS_PLUGIN, 0, 3), ++ INIT_REGMAP_IRQ(AXP192, VBUS_REMOVAL, 0, 2), ++ INIT_REGMAP_IRQ(AXP192, VBUS_V_LOW, 0, 1), ++ INIT_REGMAP_IRQ(AXP192, BATT_PLUGIN, 1, 7), ++ INIT_REGMAP_IRQ(AXP192, BATT_REMOVAL, 1, 6), ++ INIT_REGMAP_IRQ(AXP192, BATT_ENT_ACT_MODE, 1, 5), ++ INIT_REGMAP_IRQ(AXP192, BATT_EXIT_ACT_MODE, 1, 4), ++ INIT_REGMAP_IRQ(AXP192, CHARG, 1, 3), ++ INIT_REGMAP_IRQ(AXP192, CHARG_DONE, 1, 2), ++ INIT_REGMAP_IRQ(AXP192, BATT_TEMP_HIGH, 1, 1), ++ INIT_REGMAP_IRQ(AXP192, BATT_TEMP_LOW, 1, 0), ++ INIT_REGMAP_IRQ(AXP192, DIE_TEMP_HIGH, 2, 7), ++ INIT_REGMAP_IRQ(AXP192, CHARG_I_LOW, 2, 6), ++ INIT_REGMAP_IRQ(AXP192, DCDC1_V_LONG, 2, 5), ++ INIT_REGMAP_IRQ(AXP192, DCDC2_V_LONG, 2, 4), ++ INIT_REGMAP_IRQ(AXP192, DCDC3_V_LONG, 2, 3), ++ INIT_REGMAP_IRQ(AXP192, PEK_SHORT, 2, 1), ++ INIT_REGMAP_IRQ(AXP192, PEK_LONG, 2, 0), ++ INIT_REGMAP_IRQ(AXP192, N_OE_PWR_ON, 3, 7), ++ INIT_REGMAP_IRQ(AXP192, N_OE_PWR_OFF, 3, 6), ++ INIT_REGMAP_IRQ(AXP192, VBUS_VALID, 3, 5), ++ INIT_REGMAP_IRQ(AXP192, VBUS_NOT_VALID, 3, 4), ++ INIT_REGMAP_IRQ(AXP192, VBUS_SESS_VALID, 3, 3), ++ INIT_REGMAP_IRQ(AXP192, VBUS_SESS_END, 3, 2), ++ INIT_REGMAP_IRQ(AXP192, LOW_PWR_LVL, 3, 0), ++ INIT_REGMAP_IRQ(AXP192, TIMER, 4, 7), ++ INIT_REGMAP_IRQ(AXP192, GPIO2_INPUT, 4, 2), ++ INIT_REGMAP_IRQ(AXP192, GPIO1_INPUT, 4, 1), ++ INIT_REGMAP_IRQ(AXP192, GPIO0_INPUT, 4, 0), ++}; ++ + static const struct regmap_irq axp20x_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7), + INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6), +@@ -415,6 +578,16 @@ static const struct regmap_irq axp288_re + INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1), + }; + ++static const struct regmap_irq axp313a_regmap_irqs[] = { ++ INIT_REGMAP_IRQ(AXP313A, PEK_RIS_EDGE, 0, 7), ++ INIT_REGMAP_IRQ(AXP313A, PEK_FAL_EDGE, 0, 6), ++ INIT_REGMAP_IRQ(AXP313A, PEK_SHORT, 0, 5), ++ INIT_REGMAP_IRQ(AXP313A, PEK_LONG, 0, 4), ++ INIT_REGMAP_IRQ(AXP313A, DCDC3_V_LOW, 0, 3), ++ INIT_REGMAP_IRQ(AXP313A, DCDC2_V_LOW, 0, 2), ++ INIT_REGMAP_IRQ(AXP313A, DIE_TEMP_HIGH, 0, 0), ++}; ++ + static const struct regmap_irq axp803_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP803, ACIN_OVER_V, 0, 7), + INIT_REGMAP_IRQ(AXP803, ACIN_PLUGIN, 0, 6), +@@ -502,24 +675,65 @@ static const struct regmap_irq axp809_re + INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0), + }; + ++static const struct regmap_irq axp15060_regmap_irqs[] = { ++ INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV1, 0, 0), ++ INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV2, 0, 1), ++ INIT_REGMAP_IRQ(AXP15060, DCDC1_V_LOW, 0, 2), ++ INIT_REGMAP_IRQ(AXP15060, DCDC2_V_LOW, 0, 3), ++ INIT_REGMAP_IRQ(AXP15060, DCDC3_V_LOW, 0, 4), ++ INIT_REGMAP_IRQ(AXP15060, DCDC4_V_LOW, 0, 5), ++ INIT_REGMAP_IRQ(AXP15060, DCDC5_V_LOW, 0, 6), ++ INIT_REGMAP_IRQ(AXP15060, DCDC6_V_LOW, 0, 7), ++ INIT_REGMAP_IRQ(AXP15060, PEK_LONG, 1, 0), ++ INIT_REGMAP_IRQ(AXP15060, PEK_SHORT, 1, 1), ++ INIT_REGMAP_IRQ(AXP15060, GPIO1_INPUT, 1, 2), ++ INIT_REGMAP_IRQ(AXP15060, PEK_FAL_EDGE, 1, 3), ++ INIT_REGMAP_IRQ(AXP15060, PEK_RIS_EDGE, 1, 4), ++ INIT_REGMAP_IRQ(AXP15060, GPIO2_INPUT, 1, 5), ++}; ++ + static const struct regmap_irq_chip axp152_regmap_irq_chip = { + .name = "axp152_irq_chip", + .status_base = AXP152_IRQ1_STATE, + .ack_base = AXP152_IRQ1_STATE, +- .mask_base = AXP152_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP152_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp152_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp152_regmap_irqs), + .num_regs = 3, + }; + ++static unsigned int axp192_get_irq_reg(struct regmap_irq_chip_data *data, ++ unsigned int base, int index) ++{ ++ /* linear mapping for IRQ1 to IRQ4 */ ++ if (index < 4) ++ return base + index; ++ ++ /* handle IRQ5 separately */ ++ if (base == AXP192_IRQ1_EN) ++ return AXP192_IRQ5_EN; ++ ++ return AXP192_IRQ5_STATE; ++} ++ ++static const struct regmap_irq_chip axp192_regmap_irq_chip = { ++ .name = "axp192_irq_chip", ++ .status_base = AXP192_IRQ1_STATE, ++ .ack_base = AXP192_IRQ1_STATE, ++ .unmask_base = AXP192_IRQ1_EN, ++ .init_ack_masked = true, ++ .irqs = axp192_regmap_irqs, ++ .num_irqs = ARRAY_SIZE(axp192_regmap_irqs), ++ .num_regs = 5, ++ .get_irq_reg = axp192_get_irq_reg, ++}; ++ + static const struct regmap_irq_chip axp20x_regmap_irq_chip = { + .name = "axp20x_irq_chip", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, +- .mask_base = AXP20X_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP20X_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp20x_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs), +@@ -531,8 +745,7 @@ static const struct regmap_irq_chip axp2 + .name = "axp22x_irq_chip", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, +- .mask_base = AXP20X_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP20X_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp22x_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp22x_regmap_irqs), +@@ -543,8 +756,7 @@ static const struct regmap_irq_chip axp2 + .name = "axp288_irq_chip", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, +- .mask_base = AXP20X_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP20X_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp288_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp288_regmap_irqs), +@@ -552,12 +764,22 @@ static const struct regmap_irq_chip axp2 + + }; + ++static const struct regmap_irq_chip axp313a_regmap_irq_chip = { ++ .name = "axp313a_irq_chip", ++ .status_base = AXP313A_IRQ_STATE, ++ .ack_base = AXP313A_IRQ_STATE, ++ .unmask_base = AXP313A_IRQ_EN, ++ .init_ack_masked = true, ++ .irqs = axp313a_regmap_irqs, ++ .num_irqs = ARRAY_SIZE(axp313a_regmap_irqs), ++ .num_regs = 1, ++}; ++ + static const struct regmap_irq_chip axp803_regmap_irq_chip = { + .name = "axp803", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, +- .mask_base = AXP20X_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP20X_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp803_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp803_regmap_irqs), +@@ -568,8 +790,7 @@ static const struct regmap_irq_chip axp8 + .name = "axp806", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, +- .mask_base = AXP20X_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP20X_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp806_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp806_regmap_irqs), +@@ -580,14 +801,45 @@ static const struct regmap_irq_chip axp8 + .name = "axp809", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, +- .mask_base = AXP20X_IRQ1_EN, +- .mask_invert = true, ++ .unmask_base = AXP20X_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp809_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp809_regmap_irqs), + .num_regs = 5, + }; + ++static const struct regmap_irq_chip axp15060_regmap_irq_chip = { ++ .name = "axp15060", ++ .status_base = AXP15060_IRQ1_STATE, ++ .ack_base = AXP15060_IRQ1_STATE, ++ .unmask_base = AXP15060_IRQ1_EN, ++ .init_ack_masked = true, ++ .irqs = axp15060_regmap_irqs, ++ .num_irqs = ARRAY_SIZE(axp15060_regmap_irqs), ++ .num_regs = 2, ++}; ++ ++static const struct mfd_cell axp192_cells[] = { ++ { ++ .name = "axp192-adc", ++ .of_compatible = "x-powers,axp192-adc", ++ }, { ++ .name = "axp20x-battery-power-supply", ++ .of_compatible = "x-powers,axp192-battery-power-supply", ++ }, { ++ .name = "axp20x-ac-power-supply", ++ .of_compatible = "x-powers,axp202-ac-power-supply", ++ .num_resources = ARRAY_SIZE(axp192_ac_power_supply_resources), ++ .resources = axp192_ac_power_supply_resources, ++ }, { ++ .name = "axp20x-usb-power-supply", ++ .of_compatible = "x-powers,axp192-usb-power-supply", ++ .num_resources = ARRAY_SIZE(axp192_usb_power_supply_resources), ++ .resources = axp192_usb_power_supply_resources, ++ }, ++ { .name = "axp20x-regulator" }, ++}; ++ + static const struct mfd_cell axp20x_cells[] = { + { + .name = "axp20x-gpio", +@@ -683,6 +935,11 @@ static const struct mfd_cell axp152_cell + }, + }; + ++static struct mfd_cell axp313a_cells[] = { ++ MFD_CELL_NAME("axp20x-regulator"), ++ MFD_CELL_RES("axp313a-pek", axp313a_pek_resources), ++}; ++ + static const struct resource axp288_adc_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP288_IRQ_GPADC, "GPADC"), + }; +@@ -832,17 +1089,43 @@ static const struct mfd_cell axp813_cell + }, + }; + +-static struct axp20x_dev *axp20x_pm_power_off; +-static void axp20x_power_off(void) ++static const struct mfd_cell axp15060_cells[] = { ++ { ++ .name = "axp221-pek", ++ .num_resources = ARRAY_SIZE(axp15060_pek_resources), ++ .resources = axp15060_pek_resources, ++ }, { ++ .name = "axp20x-regulator", ++ }, ++}; ++ ++/* For boards that don't have IRQ line connected to SOC. */ ++static const struct mfd_cell axp_regulator_only_cells[] = { ++ { ++ .name = "axp20x-regulator", ++ }, ++}; ++ ++static int axp20x_power_off(struct sys_off_data *data) + { +- if (axp20x_pm_power_off->variant == AXP288_ID) +- return; ++ struct axp20x_dev *axp20x = data->cb_data; ++ unsigned int shutdown_reg; + +- regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, +- AXP20X_OFF); ++ switch (axp20x->variant) { ++ case AXP313A_ID: ++ shutdown_reg = AXP313A_SHUTDOWN_CTRL; ++ break; ++ default: ++ shutdown_reg = AXP20X_OFF_CTRL; ++ break; ++ } ++ ++ regmap_write(axp20x->regmap, shutdown_reg, AXP20X_OFF); + + /* Give capacitors etc. time to drain to avoid kernel panic msg. */ + mdelay(500); ++ ++ return NOTIFY_DONE; + } + + int axp20x_match_device(struct axp20x_dev *axp20x) +@@ -874,6 +1157,12 @@ int axp20x_match_device(struct axp20x_de + axp20x->regmap_cfg = &axp152_regmap_config; + axp20x->regmap_irq_chip = &axp152_regmap_irq_chip; + break; ++ case AXP192_ID: ++ axp20x->nr_cells = ARRAY_SIZE(axp192_cells); ++ axp20x->cells = axp192_cells; ++ axp20x->regmap_cfg = &axp192_regmap_config; ++ axp20x->regmap_irq_chip = &axp192_regmap_irq_chip; ++ break; + case AXP202_ID: + case AXP209_ID: + axp20x->nr_cells = ARRAY_SIZE(axp20x_cells); +@@ -900,6 +1189,12 @@ int axp20x_match_device(struct axp20x_de + axp20x->regmap_irq_chip = &axp288_regmap_irq_chip; + axp20x->irq_flags = IRQF_TRIGGER_LOW; + break; ++ case AXP313A_ID: ++ axp20x->nr_cells = ARRAY_SIZE(axp313a_cells); ++ axp20x->cells = axp313a_cells; ++ axp20x->regmap_cfg = &axp313a_regmap_config; ++ axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip; ++ break; + case AXP803_ID: + axp20x->nr_cells = ARRAY_SIZE(axp803_cells); + axp20x->cells = axp803_cells; +@@ -942,6 +1237,28 @@ int axp20x_match_device(struct axp20x_de + */ + axp20x->regmap_irq_chip = &axp803_regmap_irq_chip; + break; ++ case AXP15060_ID: ++ /* ++ * Don't register the power key part if there is no interrupt ++ * line. ++ * ++ * Since most use cases of AXP PMICs are Allwinner SOCs, board ++ * designers follow Allwinner's reference design and connects ++ * IRQ line to SOC, there's no need for those variants to deal ++ * with cases that IRQ isn't connected. However, AXP15660 is ++ * used by some other vendors' SOCs that didn't connect IRQ ++ * line, we need to deal with this case. ++ */ ++ if (axp20x->irq > 0) { ++ axp20x->nr_cells = ARRAY_SIZE(axp15060_cells); ++ axp20x->cells = axp15060_cells; ++ } else { ++ axp20x->nr_cells = ARRAY_SIZE(axp_regulator_only_cells); ++ axp20x->cells = axp_regulator_only_cells; ++ } ++ axp20x->regmap_cfg = &axp15060_regmap_config; ++ axp20x->regmap_irq_chip = &axp15060_regmap_irq_chip; ++ break; + default: + dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); + return -EINVAL; +@@ -1009,10 +1326,11 @@ int axp20x_device_probe(struct axp20x_de + return ret; + } + +- if (!pm_power_off) { +- axp20x_pm_power_off = axp20x; +- pm_power_off = axp20x_power_off; +- } ++ if (axp20x->variant != AXP288_ID) ++ devm_register_sys_off_handler(axp20x->dev, ++ SYS_OFF_MODE_POWER_OFF, ++ SYS_OFF_PRIO_DEFAULT, ++ axp20x_power_off, axp20x); + + dev_info(axp20x->dev, "AXP20X driver loaded\n"); + +@@ -1022,11 +1340,6 @@ EXPORT_SYMBOL(axp20x_device_probe); + + void axp20x_device_remove(struct axp20x_dev *axp20x) + { +- if (axp20x == axp20x_pm_power_off) { +- axp20x_pm_power_off = NULL; +- pm_power_off = NULL; +- } +- + mfd_remove_devices(axp20x->dev); + regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc); + } +--- a/include/linux/mfd/axp20x.h ++++ b/include/linux/mfd/axp20x.h +@@ -12,18 +12,22 @@ + + enum axp20x_variants { + AXP152_ID = 0, ++ AXP192_ID, + AXP202_ID, + AXP209_ID, + AXP221_ID, + AXP223_ID, + AXP288_ID, ++ AXP313A_ID, + AXP803_ID, + AXP806_ID, + AXP809_ID, + AXP813_ID, ++ AXP15060_ID, + NR_AXP20X_VARIANTS, + }; + ++#define AXP192_DATACACHE(m) (0x06 + (m)) + #define AXP20X_DATACACHE(m) (0x04 + (m)) + + /* Power supply */ +@@ -45,6 +49,13 @@ enum axp20x_variants { + #define AXP152_DCDC_FREQ 0x37 + #define AXP152_DCDC_MODE 0x80 + ++#define AXP192_USB_OTG_STATUS 0x04 ++#define AXP192_PWR_OUT_CTRL 0x12 ++#define AXP192_DCDC2_V_OUT 0x23 ++#define AXP192_DCDC1_V_OUT 0x26 ++#define AXP192_DCDC3_V_OUT 0x27 ++#define AXP192_LDO2_3_V_OUT 0x28 ++ + #define AXP20X_PWR_INPUT_STATUS 0x00 + #define AXP20X_PWR_OP_MODE 0x01 + #define AXP20X_USB_OTG_STATUS 0x02 +@@ -91,6 +102,17 @@ enum axp20x_variants { + #define AXP22X_ALDO3_V_OUT 0x2a + #define AXP22X_CHRG_CTRL3 0x35 + ++#define AXP313A_ON_INDICATE 0x00 ++#define AXP313A_OUTPUT_CONTROL 0x10 ++#define AXP313A_DCDC1_CONRTOL 0x13 ++#define AXP313A_DCDC2_CONRTOL 0x14 ++#define AXP313A_DCDC3_CONRTOL 0x15 ++#define AXP313A_ALDO1_CONRTOL 0x16 ++#define AXP313A_DLDO1_CONRTOL 0x17 ++#define AXP313A_SHUTDOWN_CTRL 0x1a ++#define AXP313A_IRQ_EN 0x20 ++#define AXP313A_IRQ_STATE 0x21 ++ + #define AXP806_STARTUP_SRC 0x00 + #define AXP806_CHIP_ID 0x03 + #define AXP806_PWR_OUT_CTRL1 0x10 +@@ -131,6 +153,39 @@ enum axp20x_variants { + /* Other DCDC regulator control registers are the same as AXP803 */ + #define AXP813_DCDC7_V_OUT 0x26 + ++#define AXP15060_STARTUP_SRC 0x00 ++#define AXP15060_PWR_OUT_CTRL1 0x10 ++#define AXP15060_PWR_OUT_CTRL2 0x11 ++#define AXP15060_PWR_OUT_CTRL3 0x12 ++#define AXP15060_DCDC1_V_CTRL 0x13 ++#define AXP15060_DCDC2_V_CTRL 0x14 ++#define AXP15060_DCDC3_V_CTRL 0x15 ++#define AXP15060_DCDC4_V_CTRL 0x16 ++#define AXP15060_DCDC5_V_CTRL 0x17 ++#define AXP15060_DCDC6_V_CTRL 0x18 ++#define AXP15060_ALDO1_V_CTRL 0x19 ++#define AXP15060_DCDC_MODE_CTRL1 0x1a ++#define AXP15060_DCDC_MODE_CTRL2 0x1b ++#define AXP15060_OUTPUT_MONITOR_DISCHARGE 0x1e ++#define AXP15060_IRQ_PWROK_VOFF 0x1f ++#define AXP15060_ALDO2_V_CTRL 0x20 ++#define AXP15060_ALDO3_V_CTRL 0x21 ++#define AXP15060_ALDO4_V_CTRL 0x22 ++#define AXP15060_ALDO5_V_CTRL 0x23 ++#define AXP15060_BLDO1_V_CTRL 0x24 ++#define AXP15060_BLDO2_V_CTRL 0x25 ++#define AXP15060_BLDO3_V_CTRL 0x26 ++#define AXP15060_BLDO4_V_CTRL 0x27 ++#define AXP15060_BLDO5_V_CTRL 0x28 ++#define AXP15060_CLDO1_V_CTRL 0x29 ++#define AXP15060_CLDO2_V_CTRL 0x2a ++#define AXP15060_CLDO3_V_CTRL 0x2b ++#define AXP15060_CLDO4_V_CTRL 0x2d ++#define AXP15060_CPUSLDO_V_CTRL 0x2e ++#define AXP15060_PWR_WAKEUP_CTRL 0x31 ++#define AXP15060_PWR_DISABLE_DOWN_SEQ 0x32 ++#define AXP15060_PEK_KEY 0x36 ++ + /* Interrupt */ + #define AXP152_IRQ1_EN 0x40 + #define AXP152_IRQ2_EN 0x41 +@@ -139,6 +194,17 @@ enum axp20x_variants { + #define AXP152_IRQ2_STATE 0x49 + #define AXP152_IRQ3_STATE 0x4a + ++#define AXP192_IRQ1_EN 0x40 ++#define AXP192_IRQ2_EN 0x41 ++#define AXP192_IRQ3_EN 0x42 ++#define AXP192_IRQ4_EN 0x43 ++#define AXP192_IRQ1_STATE 0x44 ++#define AXP192_IRQ2_STATE 0x45 ++#define AXP192_IRQ3_STATE 0x46 ++#define AXP192_IRQ4_STATE 0x47 ++#define AXP192_IRQ5_EN 0x4a ++#define AXP192_IRQ5_STATE 0x4d ++ + #define AXP20X_IRQ1_EN 0x40 + #define AXP20X_IRQ2_EN 0x41 + #define AXP20X_IRQ3_EN 0x42 +@@ -152,7 +218,17 @@ enum axp20x_variants { + #define AXP20X_IRQ5_STATE 0x4c + #define AXP20X_IRQ6_STATE 0x4d + ++#define AXP15060_IRQ1_EN 0x40 ++#define AXP15060_IRQ2_EN 0x41 ++#define AXP15060_IRQ1_STATE 0x48 ++#define AXP15060_IRQ2_STATE 0x49 ++ + /* ADC */ ++#define AXP192_GPIO2_V_ADC_H 0x68 ++#define AXP192_GPIO2_V_ADC_L 0x69 ++#define AXP192_GPIO3_V_ADC_H 0x6a ++#define AXP192_GPIO3_V_ADC_L 0x6b ++ + #define AXP20X_ACIN_V_ADC_H 0x56 + #define AXP20X_ACIN_V_ADC_L 0x57 + #define AXP20X_ACIN_I_ADC_H 0x58 +@@ -182,6 +258,8 @@ enum axp20x_variants { + #define AXP20X_IPSOUT_V_HIGH_L 0x7f + + /* Power supply */ ++#define AXP192_GPIO30_IN_RANGE 0x85 ++ + #define AXP20X_DCDC_MODE 0x80 + #define AXP20X_ADC_EN1 0x82 + #define AXP20X_ADC_EN2 0x83 +@@ -210,6 +288,16 @@ enum axp20x_variants { + #define AXP152_PWM1_FREQ_Y 0x9c + #define AXP152_PWM1_DUTY_CYCLE 0x9d + ++#define AXP192_GPIO0_CTRL 0x90 ++#define AXP192_LDO_IO0_V_OUT 0x91 ++#define AXP192_GPIO1_CTRL 0x92 ++#define AXP192_GPIO2_CTRL 0x93 ++#define AXP192_GPIO2_0_STATE 0x94 ++#define AXP192_GPIO4_3_CTRL 0x95 ++#define AXP192_GPIO4_3_STATE 0x96 ++#define AXP192_GPIO2_0_PULL 0x97 ++#define AXP192_N_RSTO_CTRL 0x9e ++ + #define AXP20X_GPIO0_CTRL 0x90 + #define AXP20X_LDO5_V_OUT 0x91 + #define AXP20X_GPIO1_CTRL 0x92 +@@ -222,6 +310,8 @@ enum axp20x_variants { + #define AXP22X_GPIO_STATE 0x94 + #define AXP22X_GPIO_PULL_DOWN 0x95 + ++#define AXP15060_CLDO4_GPIO2_MODESET 0x2c ++ + /* Battery */ + #define AXP20X_CHRG_CC_31_24 0xb0 + #define AXP20X_CHRG_CC_23_16 0xb1 +@@ -288,6 +378,17 @@ enum axp20x_variants { + + /* Regulators IDs */ + enum { ++ AXP192_DCDC1 = 0, ++ AXP192_DCDC2, ++ AXP192_DCDC3, ++ AXP192_LDO1, ++ AXP192_LDO2, ++ AXP192_LDO3, ++ AXP192_LDO_IO0, ++ AXP192_REG_ID_MAX ++}; ++ ++enum { + AXP20X_LDO1 = 0, + AXP20X_LDO2, + AXP20X_LDO3, +@@ -323,6 +424,16 @@ enum { + }; + + enum { ++ AXP313A_DCDC1 = 0, ++ AXP313A_DCDC2, ++ AXP313A_DCDC3, ++ AXP313A_ALDO1, ++ AXP313A_DLDO1, ++ AXP313A_RTC_LDO, ++ AXP313A_REG_ID_MAX, ++}; ++ ++enum { + AXP806_DCDCA = 0, + AXP806_DCDCB, + AXP806_DCDCC, +@@ -419,6 +530,33 @@ enum { + AXP813_REG_ID_MAX, + }; + ++enum { ++ AXP15060_DCDC1 = 0, ++ AXP15060_DCDC2, ++ AXP15060_DCDC3, ++ AXP15060_DCDC4, ++ AXP15060_DCDC5, ++ AXP15060_DCDC6, ++ AXP15060_ALDO1, ++ AXP15060_ALDO2, ++ AXP15060_ALDO3, ++ AXP15060_ALDO4, ++ AXP15060_ALDO5, ++ AXP15060_BLDO1, ++ AXP15060_BLDO2, ++ AXP15060_BLDO3, ++ AXP15060_BLDO4, ++ AXP15060_BLDO5, ++ AXP15060_CLDO1, ++ AXP15060_CLDO2, ++ AXP15060_CLDO3, ++ AXP15060_CLDO4, ++ AXP15060_CPUSLDO, ++ AXP15060_SW, ++ AXP15060_RTC_LDO, ++ AXP15060_REG_ID_MAX, ++}; ++ + /* IRQs */ + enum { + AXP152_IRQ_LDO0IN_CONNECT = 1, +@@ -432,14 +570,51 @@ enum { + AXP152_IRQ_PEK_SHORT, + AXP152_IRQ_PEK_LONG, + AXP152_IRQ_TIMER, +- AXP152_IRQ_PEK_RIS_EDGE, ++ /* out of bit order to make sure the press event is handled first */ + AXP152_IRQ_PEK_FAL_EDGE, ++ AXP152_IRQ_PEK_RIS_EDGE, + AXP152_IRQ_GPIO3_INPUT, + AXP152_IRQ_GPIO2_INPUT, + AXP152_IRQ_GPIO1_INPUT, + AXP152_IRQ_GPIO0_INPUT, + }; + ++enum axp192_irqs { ++ AXP192_IRQ_ACIN_OVER_V = 1, ++ AXP192_IRQ_ACIN_PLUGIN, ++ AXP192_IRQ_ACIN_REMOVAL, ++ AXP192_IRQ_VBUS_OVER_V, ++ AXP192_IRQ_VBUS_PLUGIN, ++ AXP192_IRQ_VBUS_REMOVAL, ++ AXP192_IRQ_VBUS_V_LOW, ++ AXP192_IRQ_BATT_PLUGIN, ++ AXP192_IRQ_BATT_REMOVAL, ++ AXP192_IRQ_BATT_ENT_ACT_MODE, ++ AXP192_IRQ_BATT_EXIT_ACT_MODE, ++ AXP192_IRQ_CHARG, ++ AXP192_IRQ_CHARG_DONE, ++ AXP192_IRQ_BATT_TEMP_HIGH, ++ AXP192_IRQ_BATT_TEMP_LOW, ++ AXP192_IRQ_DIE_TEMP_HIGH, ++ AXP192_IRQ_CHARG_I_LOW, ++ AXP192_IRQ_DCDC1_V_LONG, ++ AXP192_IRQ_DCDC2_V_LONG, ++ AXP192_IRQ_DCDC3_V_LONG, ++ AXP192_IRQ_PEK_SHORT = 22, ++ AXP192_IRQ_PEK_LONG, ++ AXP192_IRQ_N_OE_PWR_ON, ++ AXP192_IRQ_N_OE_PWR_OFF, ++ AXP192_IRQ_VBUS_VALID, ++ AXP192_IRQ_VBUS_NOT_VALID, ++ AXP192_IRQ_VBUS_SESS_VALID, ++ AXP192_IRQ_VBUS_SESS_END, ++ AXP192_IRQ_LOW_PWR_LVL = 31, ++ AXP192_IRQ_TIMER, ++ AXP192_IRQ_GPIO2_INPUT = 37, ++ AXP192_IRQ_GPIO1_INPUT, ++ AXP192_IRQ_GPIO0_INPUT, ++}; ++ + enum { + AXP20X_IRQ_ACIN_OVER_V = 1, + AXP20X_IRQ_ACIN_PLUGIN, +@@ -472,8 +647,9 @@ enum { + AXP20X_IRQ_LOW_PWR_LVL1, + AXP20X_IRQ_LOW_PWR_LVL2, + AXP20X_IRQ_TIMER, +- AXP20X_IRQ_PEK_RIS_EDGE, ++ /* out of bit order to make sure the press event is handled first */ + AXP20X_IRQ_PEK_FAL_EDGE, ++ AXP20X_IRQ_PEK_RIS_EDGE, + AXP20X_IRQ_GPIO3_INPUT, + AXP20X_IRQ_GPIO2_INPUT, + AXP20X_IRQ_GPIO1_INPUT, +@@ -502,8 +678,9 @@ enum axp22x_irqs { + AXP22X_IRQ_LOW_PWR_LVL1, + AXP22X_IRQ_LOW_PWR_LVL2, + AXP22X_IRQ_TIMER, +- AXP22X_IRQ_PEK_RIS_EDGE, ++ /* out of bit order to make sure the press event is handled first */ + AXP22X_IRQ_PEK_FAL_EDGE, ++ AXP22X_IRQ_PEK_RIS_EDGE, + AXP22X_IRQ_GPIO1_INPUT, + AXP22X_IRQ_GPIO0_INPUT, + }; +@@ -545,6 +722,16 @@ enum axp288_irqs { + AXP288_IRQ_BC_USB_CHNG, + }; + ++enum axp313a_irqs { ++ AXP313A_IRQ_DIE_TEMP_HIGH, ++ AXP313A_IRQ_DCDC2_V_LOW = 2, ++ AXP313A_IRQ_DCDC3_V_LOW, ++ AXP313A_IRQ_PEK_LONG, ++ AXP313A_IRQ_PEK_SHORT, ++ AXP313A_IRQ_PEK_FAL_EDGE, ++ AXP313A_IRQ_PEK_RIS_EDGE, ++}; ++ + enum axp803_irqs { + AXP803_IRQ_ACIN_OVER_V = 1, + AXP803_IRQ_ACIN_PLUGIN, +@@ -571,8 +758,9 @@ enum axp803_irqs { + AXP803_IRQ_LOW_PWR_LVL1, + AXP803_IRQ_LOW_PWR_LVL2, + AXP803_IRQ_TIMER, +- AXP803_IRQ_PEK_RIS_EDGE, ++ /* out of bit order to make sure the press event is handled first */ + AXP803_IRQ_PEK_FAL_EDGE, ++ AXP803_IRQ_PEK_RIS_EDGE, + AXP803_IRQ_PEK_SHORT, + AXP803_IRQ_PEK_LONG, + AXP803_IRQ_PEK_OVER_OFF, +@@ -623,8 +811,9 @@ enum axp809_irqs { + AXP809_IRQ_LOW_PWR_LVL1, + AXP809_IRQ_LOW_PWR_LVL2, + AXP809_IRQ_TIMER, +- AXP809_IRQ_PEK_RIS_EDGE, ++ /* out of bit order to make sure the press event is handled first */ + AXP809_IRQ_PEK_FAL_EDGE, ++ AXP809_IRQ_PEK_RIS_EDGE, + AXP809_IRQ_PEK_SHORT, + AXP809_IRQ_PEK_LONG, + AXP809_IRQ_PEK_OVER_OFF, +@@ -632,6 +821,23 @@ enum axp809_irqs { + AXP809_IRQ_GPIO0_INPUT, + }; + ++enum axp15060_irqs { ++ AXP15060_IRQ_DIE_TEMP_HIGH_LV1 = 1, ++ AXP15060_IRQ_DIE_TEMP_HIGH_LV2, ++ AXP15060_IRQ_DCDC1_V_LOW, ++ AXP15060_IRQ_DCDC2_V_LOW, ++ AXP15060_IRQ_DCDC3_V_LOW, ++ AXP15060_IRQ_DCDC4_V_LOW, ++ AXP15060_IRQ_DCDC5_V_LOW, ++ AXP15060_IRQ_DCDC6_V_LOW, ++ AXP15060_IRQ_PEK_LONG, ++ AXP15060_IRQ_PEK_SHORT, ++ AXP15060_IRQ_GPIO1_INPUT, ++ AXP15060_IRQ_PEK_FAL_EDGE, ++ AXP15060_IRQ_PEK_RIS_EDGE, ++ AXP15060_IRQ_GPIO2_INPUT, ++}; ++ + struct axp20x_dev { + struct device *dev; + int irq; +@@ -698,4 +904,4 @@ int axp20x_device_probe(struct axp20x_de + */ + void axp20x_device_remove(struct axp20x_dev *axp20x); + +-#endif /* __LINUX_MFD_AXP20X_H */ ++#endif /* __LINUX_MFD_AXP20X_H */ +\ No newline at end of file diff --git a/target/linux/starfive/patches-6.1/0118-driver-regulator-axp20x-Support-AXP15060-variant.patch b/target/linux/starfive/patches-6.1/0118-driver-regulator-axp20x-Support-AXP15060-variant.patch new file mode 100644 index 0000000000..ccb277b3a0 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0118-driver-regulator-axp20x-Support-AXP15060-variant.patch @@ -0,0 +1,434 @@ +From 1b017f3376a5df4a2cd5a120c16723e777fc9a36 Mon Sep 17 00:00:00 2001 +From: "ziv.xu" +Date: Fri, 4 Aug 2023 13:55:23 +0800 +Subject: [PATCH 118/122] driver: regulator: axp20x: Support AXP15060 variant. + +Add axp15060 variant support to axp20x + +Signed-off-by: ziv.xu +--- + drivers/regulator/axp20x-regulator.c | 291 ++++++++++++++++++++++++++- + 1 file changed, 283 insertions(+), 8 deletions(-) + +--- a/drivers/regulator/axp20x-regulator.c ++++ b/drivers/regulator/axp20x-regulator.c +@@ -134,6 +134,11 @@ + #define AXP22X_PWR_OUT_DLDO4_MASK BIT_MASK(6) + #define AXP22X_PWR_OUT_ALDO3_MASK BIT_MASK(7) + ++#define AXP313A_DCDC1_NUM_VOLTAGES 107 ++#define AXP313A_DCDC23_NUM_VOLTAGES 88 ++#define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0) ++#define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0) ++ + #define AXP803_PWR_OUT_DCDC1_MASK BIT_MASK(0) + #define AXP803_PWR_OUT_DCDC2_MASK BIT_MASK(1) + #define AXP803_PWR_OUT_DCDC3_MASK BIT_MASK(2) +@@ -270,6 +275,74 @@ + + #define AXP813_PWR_OUT_DCDC7_MASK BIT_MASK(6) + ++#define AXP15060_DCDC1_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_DCDC2_V_CTRL_MASK GENMASK(6, 0) ++#define AXP15060_DCDC3_V_CTRL_MASK GENMASK(6, 0) ++#define AXP15060_DCDC4_V_CTRL_MASK GENMASK(6, 0) ++#define AXP15060_DCDC5_V_CTRL_MASK GENMASK(6, 0) ++#define AXP15060_DCDC6_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_ALDO1_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_ALDO2_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_ALDO3_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_ALDO4_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_ALDO5_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_BLDO1_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_BLDO2_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_BLDO3_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_BLDO4_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_BLDO5_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_CLDO1_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_CLDO2_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_CLDO3_V_CTRL_MASK GENMASK(4, 0) ++#define AXP15060_CLDO4_V_CTRL_MASK GENMASK(5, 0) ++#define AXP15060_CPUSLDO_V_CTRL_MASK GENMASK(3, 0) ++ ++#define AXP15060_PWR_OUT_DCDC1_MASK BIT_MASK(0) ++#define AXP15060_PWR_OUT_DCDC2_MASK BIT_MASK(1) ++#define AXP15060_PWR_OUT_DCDC3_MASK BIT_MASK(2) ++#define AXP15060_PWR_OUT_DCDC4_MASK BIT_MASK(3) ++#define AXP15060_PWR_OUT_DCDC5_MASK BIT_MASK(4) ++#define AXP15060_PWR_OUT_DCDC6_MASK BIT_MASK(5) ++#define AXP15060_PWR_OUT_ALDO1_MASK BIT_MASK(0) ++#define AXP15060_PWR_OUT_ALDO2_MASK BIT_MASK(1) ++#define AXP15060_PWR_OUT_ALDO3_MASK BIT_MASK(2) ++#define AXP15060_PWR_OUT_ALDO4_MASK BIT_MASK(3) ++#define AXP15060_PWR_OUT_ALDO5_MASK BIT_MASK(4) ++#define AXP15060_PWR_OUT_BLDO1_MASK BIT_MASK(5) ++#define AXP15060_PWR_OUT_BLDO2_MASK BIT_MASK(6) ++#define AXP15060_PWR_OUT_BLDO3_MASK BIT_MASK(7) ++#define AXP15060_PWR_OUT_BLDO4_MASK BIT_MASK(0) ++#define AXP15060_PWR_OUT_BLDO5_MASK BIT_MASK(1) ++#define AXP15060_PWR_OUT_CLDO1_MASK BIT_MASK(2) ++#define AXP15060_PWR_OUT_CLDO2_MASK BIT_MASK(3) ++#define AXP15060_PWR_OUT_CLDO3_MASK BIT_MASK(4) ++#define AXP15060_PWR_OUT_CLDO4_MASK BIT_MASK(5) ++#define AXP15060_PWR_OUT_CPUSLDO_MASK BIT_MASK(6) ++#define AXP15060_PWR_OUT_SW_MASK BIT_MASK(7) ++ ++#define AXP15060_DCDC23_POLYPHASE_DUAL_MASK BIT_MASK(6) ++#define AXP15060_DCDC46_POLYPHASE_DUAL_MASK BIT_MASK(7) ++ ++#define AXP15060_DCDC234_500mV_START 0x00 ++#define AXP15060_DCDC234_500mV_STEPS 70 ++#define AXP15060_DCDC234_500mV_END \ ++ (AXP15060_DCDC234_500mV_START + AXP15060_DCDC234_500mV_STEPS) ++#define AXP15060_DCDC234_1220mV_START 0x47 ++#define AXP15060_DCDC234_1220mV_STEPS 16 ++#define AXP15060_DCDC234_1220mV_END \ ++ (AXP15060_DCDC234_1220mV_START + AXP15060_DCDC234_1220mV_STEPS) ++#define AXP15060_DCDC234_NUM_VOLTAGES 88 ++ ++#define AXP15060_DCDC5_800mV_START 0x00 ++#define AXP15060_DCDC5_800mV_STEPS 32 ++#define AXP15060_DCDC5_800mV_END \ ++ (AXP15060_DCDC5_800mV_START + AXP15060_DCDC5_800mV_STEPS) ++#define AXP15060_DCDC5_1140mV_START 0x21 ++#define AXP15060_DCDC5_1140mV_STEPS 35 ++#define AXP15060_DCDC5_1140mV_END \ ++ (AXP15060_DCDC5_1140mV_START + AXP15060_DCDC5_1140mV_STEPS) ++#define AXP15060_DCDC5_NUM_VOLTAGES 69 ++ + #define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _enable_val, _disable_val) \ + [_family##_##_id] = { \ +@@ -638,6 +711,48 @@ static const struct regulator_desc axp22 + .ops = &axp20x_ops_sw, + }; + ++static const struct linear_range axp313a_dcdc1_ranges[] = { ++ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), ++ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), ++ REGULATOR_LINEAR_RANGE(1600000, 88, 106, 100000), ++}; ++ ++static const struct linear_range axp313a_dcdc2_ranges[] = { ++ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), ++ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), ++}; ++ ++/* ++ * This is deviating from the datasheet. The values here are taken from the ++ * BSP driver and have been confirmed by measurements. ++ */ ++static const struct linear_range axp313a_dcdc3_ranges[] = { ++ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), ++ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000), ++}; ++ ++static const struct regulator_desc axp313a_regulators[] = { ++ AXP_DESC_RANGES(AXP313A, DCDC1, "dcdc1", "vin1", ++ axp313a_dcdc1_ranges, AXP313A_DCDC1_NUM_VOLTAGES, ++ AXP313A_DCDC1_CONRTOL, AXP313A_DCDC_V_OUT_MASK, ++ AXP313A_OUTPUT_CONTROL, BIT(0)), ++ AXP_DESC_RANGES(AXP313A, DCDC2, "dcdc2", "vin2", ++ axp313a_dcdc2_ranges, AXP313A_DCDC23_NUM_VOLTAGES, ++ AXP313A_DCDC2_CONRTOL, AXP313A_DCDC_V_OUT_MASK, ++ AXP313A_OUTPUT_CONTROL, BIT(1)), ++ AXP_DESC_RANGES(AXP313A, DCDC3, "dcdc3", "vin3", ++ axp313a_dcdc3_ranges, AXP313A_DCDC23_NUM_VOLTAGES, ++ AXP313A_DCDC3_CONRTOL, AXP313A_DCDC_V_OUT_MASK, ++ AXP313A_OUTPUT_CONTROL, BIT(2)), ++ AXP_DESC(AXP313A, ALDO1, "aldo1", "vin1", 500, 3500, 100, ++ AXP313A_ALDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK, ++ AXP313A_OUTPUT_CONTROL, BIT(3)), ++ AXP_DESC(AXP313A, DLDO1, "dldo1", "vin1", 500, 3500, 100, ++ AXP313A_DLDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK, ++ AXP313A_OUTPUT_CONTROL, BIT(4)), ++ AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800), ++}; ++ + /* DCDC ranges shared with AXP813 */ + static const struct linear_range axp803_dcdc234_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, +@@ -1001,6 +1116,104 @@ static const struct regulator_desc axp81 + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK), + }; + ++static const struct linear_range axp15060_dcdc234_ranges[] = { ++ REGULATOR_LINEAR_RANGE(500000, ++ AXP15060_DCDC234_500mV_START, ++ AXP15060_DCDC234_500mV_END, ++ 10000), ++ REGULATOR_LINEAR_RANGE(1220000, ++ AXP15060_DCDC234_1220mV_START, ++ AXP15060_DCDC234_1220mV_END, ++ 20000), ++}; ++ ++static const struct linear_range axp15060_dcdc5_ranges[] = { ++ REGULATOR_LINEAR_RANGE(800000, ++ AXP15060_DCDC5_800mV_START, ++ AXP15060_DCDC5_800mV_END, ++ 10000), ++ REGULATOR_LINEAR_RANGE(1140000, ++ AXP15060_DCDC5_1140mV_START, ++ AXP15060_DCDC5_1140mV_END, ++ 20000), ++}; ++ ++static const struct regulator_desc axp15060_regulators[] = { ++ AXP_DESC(AXP15060, DCDC1, "dcdc1", "vin1", 1500, 3400, 100, ++ AXP15060_DCDC1_V_CTRL, AXP15060_DCDC1_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL1, AXP15060_PWR_OUT_DCDC1_MASK), ++ AXP_DESC_RANGES(AXP15060, DCDC2, "dcdc2", "vin2", ++ axp15060_dcdc234_ranges, AXP15060_DCDC234_NUM_VOLTAGES, ++ AXP15060_DCDC2_V_CTRL, AXP15060_DCDC2_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL1, AXP15060_PWR_OUT_DCDC2_MASK), ++ AXP_DESC_RANGES(AXP15060, DCDC3, "dcdc3", "vin3", ++ axp15060_dcdc234_ranges, AXP15060_DCDC234_NUM_VOLTAGES, ++ AXP15060_DCDC3_V_CTRL, AXP15060_DCDC3_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL1, AXP15060_PWR_OUT_DCDC3_MASK), ++ AXP_DESC_RANGES(AXP15060, DCDC4, "dcdc4", "vin4", ++ axp15060_dcdc234_ranges, AXP15060_DCDC234_NUM_VOLTAGES, ++ AXP15060_DCDC4_V_CTRL, AXP15060_DCDC4_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL1, AXP15060_PWR_OUT_DCDC4_MASK), ++ AXP_DESC_RANGES(AXP15060, DCDC5, "dcdc5", "vin5", ++ axp15060_dcdc5_ranges, AXP15060_DCDC5_NUM_VOLTAGES, ++ AXP15060_DCDC5_V_CTRL, AXP15060_DCDC5_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL1, AXP15060_PWR_OUT_DCDC5_MASK), ++ AXP_DESC(AXP15060, DCDC6, "dcdc6", "vin6", 500, 3400, 100, ++ AXP15060_DCDC6_V_CTRL, AXP15060_DCDC6_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL1, AXP15060_PWR_OUT_DCDC6_MASK), ++ AXP_DESC(AXP15060, ALDO1, "aldo1", "aldoin", 700, 3300, 100, ++ AXP15060_ALDO1_V_CTRL, AXP15060_ALDO1_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_ALDO1_MASK), ++ AXP_DESC(AXP15060, ALDO2, "aldo2", "aldoin", 700, 3300, 100, ++ AXP15060_ALDO2_V_CTRL, AXP15060_ALDO2_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_ALDO2_MASK), ++ AXP_DESC(AXP15060, ALDO3, "aldo3", "aldoin", 700, 3300, 100, ++ AXP15060_ALDO3_V_CTRL, AXP15060_ALDO3_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_ALDO3_MASK), ++ AXP_DESC(AXP15060, ALDO4, "aldo4", "aldoin", 700, 3300, 100, ++ AXP15060_ALDO4_V_CTRL, AXP15060_ALDO4_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_ALDO4_MASK), ++ AXP_DESC(AXP15060, ALDO5, "aldo5", "aldoin", 700, 3300, 100, ++ AXP15060_ALDO5_V_CTRL, AXP15060_ALDO5_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_ALDO5_MASK), ++ AXP_DESC(AXP15060, BLDO1, "bldo1", "bldoin", 700, 3300, 100, ++ AXP15060_BLDO1_V_CTRL, AXP15060_BLDO1_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_BLDO1_MASK), ++ AXP_DESC(AXP15060, BLDO2, "bldo2", "bldoin", 700, 3300, 100, ++ AXP15060_BLDO2_V_CTRL, AXP15060_BLDO2_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_BLDO2_MASK), ++ AXP_DESC(AXP15060, BLDO3, "bldo3", "bldoin", 700, 3300, 100, ++ AXP15060_BLDO3_V_CTRL, AXP15060_BLDO3_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL2, AXP15060_PWR_OUT_BLDO3_MASK), ++ AXP_DESC(AXP15060, BLDO4, "bldo4", "bldoin", 700, 3300, 100, ++ AXP15060_BLDO4_V_CTRL, AXP15060_BLDO4_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_BLDO4_MASK), ++ AXP_DESC(AXP15060, BLDO5, "bldo5", "bldoin", 700, 3300, 100, ++ AXP15060_BLDO5_V_CTRL, AXP15060_BLDO5_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_BLDO5_MASK), ++ AXP_DESC(AXP15060, CLDO1, "cldo1", "cldoin", 700, 3300, 100, ++ AXP15060_CLDO1_V_CTRL, AXP15060_CLDO1_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_CLDO1_MASK), ++ AXP_DESC(AXP15060, CLDO2, "cldo2", "cldoin", 700, 3300, 100, ++ AXP15060_CLDO2_V_CTRL, AXP15060_CLDO2_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_CLDO2_MASK), ++ AXP_DESC(AXP15060, CLDO3, "cldo3", "cldoin", 700, 3300, 100, ++ AXP15060_CLDO3_V_CTRL, AXP15060_CLDO3_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_CLDO3_MASK), ++ AXP_DESC(AXP15060, CLDO4, "cldo4", "cldoin", 700, 4200, 100, ++ AXP15060_CLDO4_V_CTRL, AXP15060_CLDO4_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_CLDO4_MASK), ++ /* Supply comes from DCDC5 */ ++ AXP_DESC(AXP15060, CPUSLDO, "cpusldo", NULL, 700, 1400, 50, ++ AXP15060_CPUSLDO_V_CTRL, AXP15060_CPUSLDO_V_CTRL_MASK, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_CPUSLDO_MASK), ++ /* Supply comes from DCDC1 */ ++ AXP_DESC_SW(AXP15060, SW, "sw", NULL, ++ AXP15060_PWR_OUT_CTRL3, AXP15060_PWR_OUT_SW_MASK), ++ /* Supply comes from ALDO1 */ ++ AXP_DESC_FIXED(AXP15060, RTC_LDO, "rtc-ldo", NULL, 1800), ++}; ++ + static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) + { + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); +@@ -1040,6 +1253,16 @@ static int axp20x_set_dcdc_freq(struct p + def = 3000; + step = 150; + break; ++ case AXP313A_ID: ++ case AXP15060_ID: ++ /* The DCDC PWM frequency seems to be fixed to 3 MHz. */ ++ if (dcdcfreq != 0) { ++ dev_err(&pdev->dev, ++ "DCDC frequency on this PMIC is fixed to 3 MHz.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; + default: + dev_err(&pdev->dev, + "Setting DCDC frequency for unsupported AXP variant\n"); +@@ -1145,6 +1368,15 @@ static int axp20x_set_dcdc_workmode(stru + workmode <<= id - AXP813_DCDC1; + break; + ++ case AXP15060_ID: ++ reg = AXP15060_DCDC_MODE_CTRL2; ++ if (id < AXP15060_DCDC1 || id > AXP15060_DCDC6) ++ return -EINVAL; ++ ++ mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP15060_DCDC1); ++ workmode <<= id - AXP15060_DCDC1; ++ break; ++ + default: + /* should not happen */ + WARN_ON(1); +@@ -1164,7 +1396,7 @@ static bool axp20x_is_polyphase_slave(st + + /* + * Currently in our supported AXP variants, only AXP803, AXP806, +- * and AXP813 have polyphase regulators. ++ * AXP813 and AXP15060 have polyphase regulators. + */ + switch (axp20x->variant) { + case AXP803_ID: +@@ -1196,6 +1428,17 @@ static bool axp20x_is_polyphase_slave(st + } + break; + ++ case AXP15060_ID: ++ regmap_read(axp20x->regmap, AXP15060_DCDC_MODE_CTRL1, ®); ++ ++ switch (id) { ++ case AXP15060_DCDC3: ++ return !!(reg & AXP15060_DCDC23_POLYPHASE_DUAL_MASK); ++ case AXP15060_DCDC6: ++ return !!(reg & AXP15060_DCDC46_POLYPHASE_DUAL_MASK); ++ } ++ break; ++ + default: + return false; + } +@@ -1217,6 +1460,7 @@ static int axp20x_regulator_probe(struct + u32 workmode; + const char *dcdc1_name = axp22x_regulators[AXP22X_DCDC1].name; + const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name; ++ const char *aldo1_name = axp15060_regulators[AXP15060_ALDO1].name; + bool drivevbus = false; + + switch (axp20x->variant) { +@@ -1232,6 +1476,10 @@ static int axp20x_regulator_probe(struct + drivevbus = of_property_read_bool(pdev->dev.parent->of_node, + "x-powers,drive-vbus-en"); + break; ++ case AXP313A_ID: ++ regulators = axp313a_regulators; ++ nregulators = AXP313A_REG_ID_MAX; ++ break; + case AXP803_ID: + regulators = axp803_regulators; + nregulators = AXP803_REG_ID_MAX; +@@ -1252,6 +1500,10 @@ static int axp20x_regulator_probe(struct + drivevbus = of_property_read_bool(pdev->dev.parent->of_node, + "x-powers,drive-vbus-en"); + break; ++ case AXP15060_ID: ++ regulators = axp15060_regulators; ++ nregulators = AXP15060_REG_ID_MAX; ++ break; + default: + dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", + axp20x->variant); +@@ -1278,8 +1530,9 @@ static int axp20x_regulator_probe(struct + continue; + + /* +- * Regulators DC1SW and DC5LDO are connected internally, +- * so we have to handle their supply names separately. ++ * Regulators DC1SW, DC5LDO and RTCLDO on AXP15060 are ++ * connected internally, so we have to handle their supply ++ * names separately. + * + * We always register the regulators in proper sequence, + * so the supply names are correctly read. See the last +@@ -1288,7 +1541,8 @@ static int axp20x_regulator_probe(struct + */ + if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) || + (regulators == axp803_regulators && i == AXP803_DC1SW) || +- (regulators == axp809_regulators && i == AXP809_DC1SW)) { ++ (regulators == axp809_regulators && i == AXP809_DC1SW) || ++ (regulators == axp15060_regulators && i == AXP15060_SW)) { + new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + GFP_KERNEL); + if (!new_desc) +@@ -1300,7 +1554,8 @@ static int axp20x_regulator_probe(struct + } + + if ((regulators == axp22x_regulators && i == AXP22X_DC5LDO) || +- (regulators == axp809_regulators && i == AXP809_DC5LDO)) { ++ (regulators == axp809_regulators && i == AXP809_DC5LDO) || ++ (regulators == axp15060_regulators && i == AXP15060_CPUSLDO)) { + new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + GFP_KERNEL); + if (!new_desc) +@@ -1311,6 +1566,18 @@ static int axp20x_regulator_probe(struct + desc = new_desc; + } + ++ ++ if (regulators == axp15060_regulators && i == AXP15060_RTC_LDO) { ++ new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), ++ GFP_KERNEL); ++ if (!new_desc) ++ return -ENOMEM; ++ ++ *new_desc = regulators[i]; ++ new_desc->supply_name = aldo1_name; ++ desc = new_desc; ++ } ++ + rdev = devm_regulator_register(&pdev->dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register %s\n", +@@ -1329,19 +1596,26 @@ static int axp20x_regulator_probe(struct + } + + /* +- * Save AXP22X DCDC1 / DCDC5 regulator names for later. ++ * Save AXP22X DCDC1 / DCDC5 / AXP15060 ALDO1 regulator names for later. + */ + if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) || +- (regulators == axp809_regulators && i == AXP809_DCDC1)) ++ (regulators == axp809_regulators && i == AXP809_DCDC1) || ++ (regulators == axp15060_regulators && i == AXP15060_DCDC1)) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &dcdc1_name); + + if ((regulators == axp22x_regulators && i == AXP22X_DCDC5) || +- (regulators == axp809_regulators && i == AXP809_DCDC5)) ++ (regulators == axp809_regulators && i == AXP809_DCDC5) || ++ (regulators == axp15060_regulators && i == AXP15060_DCDC5)) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &dcdc5_name); ++ ++ if (regulators == axp15060_regulators && i == AXP15060_ALDO1) ++ of_property_read_string(rdev->dev.of_node, ++ "regulator-name", ++ &aldo1_name); + } + + if (drivevbus) { +@@ -1364,6 +1638,7 @@ static struct platform_driver axp20x_reg + .probe = axp20x_regulator_probe, + .driver = { + .name = "axp20x-regulator", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + }; + diff --git a/target/linux/starfive/patches-6.1/0119-riscv-dts-visionfive2-add-EEPROM-node.patch b/target/linux/starfive/patches-6.1/0119-riscv-dts-visionfive2-add-EEPROM-node.patch new file mode 100644 index 0000000000..8aec7fb7e5 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0119-riscv-dts-visionfive2-add-EEPROM-node.patch @@ -0,0 +1,25 @@ +From 6d91484ec63526def63be4097c28790f25d647b8 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Thu, 10 Aug 2023 23:23:15 +0200 +Subject: [PATCH 119/122] riscv: dts: visionfive2: add EEPROM node + +Signed-off-by: Zoltan HERPAI +--- + .../boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -239,6 +239,12 @@ + pinctrl-0 = <&i2c5_pins>; + status = "okay"; + ++ eeprom@50 { ++ compatible = "atmel,24c04"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ + axp15060: pmic@36 { + compatible = "x-powers,axp15060"; + reg = <0x36>; diff --git a/target/linux/starfive/patches-6.1/0120-riscv-dts-visionfive2-add-mmc-aliases.patch b/target/linux/starfive/patches-6.1/0120-riscv-dts-visionfive2-add-mmc-aliases.patch new file mode 100644 index 0000000000..e8067e1dcb --- /dev/null +++ b/target/linux/starfive/patches-6.1/0120-riscv-dts-visionfive2-add-mmc-aliases.patch @@ -0,0 +1,21 @@ +From aa5fcd525c1a01ca07a6fdb631dbd304e22c9669 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Thu, 10 Aug 2023 23:23:45 +0200 +Subject: [PATCH 120/122] riscv: dts: visionfive2: add mmc aliases + +Signed-off-by: Zoltan HERPAI +--- + arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -13,6 +13,8 @@ + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; ++ mmc0 = &mmc0; ++ mmc1 = &mmc1; + i2c0 = &i2c0; + i2c2 = &i2c2; + i2c5 = &i2c5; diff --git a/target/linux/starfive/patches-6.1/0121-drivers-include-cpufreq-Kconfig-for-riscv.patch b/target/linux/starfive/patches-6.1/0121-drivers-include-cpufreq-Kconfig-for-riscv.patch new file mode 100644 index 0000000000..231a844b41 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0121-drivers-include-cpufreq-Kconfig-for-riscv.patch @@ -0,0 +1,21 @@ +From 22b82c89dac3fadaa8c50760c25be7c78a2782a3 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Thu, 10 Aug 2023 23:42:13 +0200 +Subject: [PATCH] drivers: include cpufreq/Kconfig for riscv + +Signed-off-by: Zoltan HERPAI +--- + drivers/Kconfig | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -237,6 +237,8 @@ source "drivers/most/Kconfig" + + source "drivers/peci/Kconfig" + ++source "drivers/cpufreq/Kconfig" ++ + source "drivers/hte/Kconfig" + + endmenu diff --git a/target/linux/starfive/patches-6.1/0126-clk-starfive-jh7110-sys-Fix-lower-rate-of-CPUfreq-by.patch b/target/linux/starfive/patches-6.1/0126-clk-starfive-jh7110-sys-Fix-lower-rate-of-CPUfreq-by.patch new file mode 100644 index 0000000000..d057797bb2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/0126-clk-starfive-jh7110-sys-Fix-lower-rate-of-CPUfreq-by.patch @@ -0,0 +1,92 @@ +From 8a2d9c6decdbd042b3475d5ab69c1a79f0fd54aa Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Mon, 21 Aug 2023 23:29:15 +0800 +Subject: [PATCH] clk: starfive: jh7110-sys: Fix lower rate of CPUfreq by + setting PLL0 rate to 1.5GHz + +CPUfreq supports 4 cpu frequency loads on 375/500/750/1500MHz. +But now PLL0 rate is 1GHz and the cpu frequency loads become +333/500/500/1000MHz in fact. + +So PLL0 rate should be set to 1.5GHz. Change the parent of cpu_root clock +and the divider of cpu_core before the setting. + +Reviewed-by: Hal Feng +Fixes: e2c510d6d630 ("riscv: dts: starfive: Add cpu scaling for JH7110 SoC") +Signed-off-by: Xingyu Wu +--- + .../clk/starfive/clk-starfive-jh7110-sys.c | 49 ++++++++++++++++++- + 1 file changed, 48 insertions(+), 1 deletion(-) + +--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -389,6 +390,7 @@ static int __init jh7110_syscrg_probe(st + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; ++ struct clk *pllclk; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_SYSCLK_END), +@@ -462,7 +464,52 @@ static int __init jh7110_syscrg_probe(st + if (ret) + return ret; + +- return jh7110_reset_controller_register(priv, "rst-sys", 0); ++ ret = jh7110_reset_controller_register(priv, "rst-sys", 0); ++ if (ret) ++ return ret; ++ ++ /* ++ * Set PLL0 rate to 1.5GHz ++ * In order to not affect the cpu when the PLL0 rate is changing, ++ * we need to switch the parent of cpu_root clock to osc clock first, ++ * and then switch back after setting the PLL0 rate. ++ */ ++ pllclk = clk_get(priv->dev, "pll0_out"); ++ if (!IS_ERR(pllclk)) { ++ struct clk *osc = clk_get(&pdev->dev, "osc"); ++ struct clk *cpu_root = priv->reg[JH7110_SYSCLK_CPU_ROOT].hw.clk; ++ struct clk *cpu_core = priv->reg[JH7110_SYSCLK_CPU_CORE].hw.clk; ++ ++ if (IS_ERR(osc)) { ++ clk_put(pllclk); ++ return PTR_ERR(osc); ++ } ++ ++ /* ++ * CPU need voltage regulation by CPUfreq if set 1.5GHz. ++ * So in this driver, cpu_core need to be set the divider to be 2 first ++ * and will be 750M after setting parent. ++ */ ++ ret = clk_set_rate(cpu_core, clk_get_rate(cpu_core) / 2); ++ if (ret) ++ goto failed_set; ++ ++ ret = clk_set_parent(cpu_root, osc); ++ if (ret) ++ goto failed_set; ++ ++ ret = clk_set_rate(pllclk, 1500000000); ++ if (ret) ++ goto failed_set; ++ ++ ret = clk_set_parent(cpu_root, pllclk); ++ ++failed_set: ++ clk_put(pllclk); ++ clk_put(osc); ++ } ++ ++ return ret; + } + + static const struct of_device_id jh7110_syscrg_match[] = { diff --git a/target/linux/starfive/patches-6.1/1000-net-stmmac-dwmac-starfive-Add-JH7100-support.patch b/target/linux/starfive/patches-6.1/1000-net-stmmac-dwmac-starfive-Add-JH7100-support.patch new file mode 100644 index 0000000000..d009d375ca --- /dev/null +++ b/target/linux/starfive/patches-6.1/1000-net-stmmac-dwmac-starfive-Add-JH7100-support.patch @@ -0,0 +1,63 @@ +From 22885637d0976473b04d4bae191fcf88e28b3df5 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Wed, 29 Sep 2021 20:50:22 +0200 +Subject: [PATCH 1000/1024] net: stmmac: dwmac-starfive: Add JH7100 support + +This adds support for setting the phy interface and delay chains on the +StarFive JH7100 SoC. + +Signed-off-by: Emil Renner Berthing +--- + .../net/ethernet/stmicro/stmmac/dwmac-starfive.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +@@ -17,6 +17,10 @@ + #define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 + #define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U + ++#define JH7100_SYSMAIN_REGISTER28 0x70 ++/* The value below is not a typo, just really bad naming by StarFive ¯\_(ツ)_/¯ */ ++#define JH7100_SYSMAIN_REGISTER49 0xc8 ++ + struct starfive_dwmac { + struct device *dev; + struct clk *clk_tx; +@@ -56,6 +60,7 @@ static int starfive_dwmac_set_mode(struc + struct regmap *regmap; + unsigned int args[2]; + unsigned int mode; ++ u32 gtxclk_dlychain; + int err; + + switch (plat_dat->interface) { +@@ -65,6 +70,7 @@ static int starfive_dwmac_set_mode(struc + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: + mode = STARFIVE_DWMAC_PHY_INFT_RGMII; + break; + +@@ -87,6 +93,12 @@ static int starfive_dwmac_set_mode(struc + if (err) + return dev_err_probe(dwmac->dev, err, "error setting phy mode\n"); + ++ if (!of_property_read_u32(dwmac->dev->of_node, "starfive,gtxclk-dlychain", >xclk_dlychain)) { ++ err = regmap_write(regmap, JH7100_SYSMAIN_REGISTER49, gtxclk_dlychain); ++ if (err) ++ return dev_err_probe(dwmac->dev, err, "error selecting gtxclk delay chain\n"); ++ } ++ + return 0; + } + +@@ -149,6 +161,7 @@ static int starfive_dwmac_probe(struct p + } + + static const struct of_device_id starfive_dwmac_match[] = { ++ { .compatible = "starfive,jh7100-dwmac" }, + { .compatible = "starfive,jh7110-dwmac" }, + { /* sentinel */ } + }; diff --git a/target/linux/starfive/patches-6.1/1001-dt-bindings-mfd-syscon-Add-StarFive-JH7100-sysmain-c.patch b/target/linux/starfive/patches-6.1/1001-dt-bindings-mfd-syscon-Add-StarFive-JH7100-sysmain-c.patch new file mode 100644 index 0000000000..5d46eab3f7 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1001-dt-bindings-mfd-syscon-Add-StarFive-JH7100-sysmain-c.patch @@ -0,0 +1,23 @@ +From a5f12fe4b640281c04a9b8b6ad676df9eeba9aa6 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Wed, 6 Oct 2021 20:42:34 +0200 +Subject: [PATCH 1001/1024] dt-bindings: mfd: syscon: Add StarFive JH7100 + sysmain compatible + +Document StarFive JH7100 SoC compatible for sysmain registers. + +Signed-off-by: Emil Renner Berthing +--- + Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/mfd/syscon.yaml ++++ b/Documentation/devicetree/bindings/mfd/syscon.yaml +@@ -69,6 +69,7 @@ properties: + - samsung,exynos5433-sysreg + - samsung,exynos850-sysreg + - samsung,exynosautov9-sysreg ++ - starfive,jh7100-sysmain + + - const: syscon + diff --git a/target/linux/starfive/patches-6.1/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch b/target/linux/starfive/patches-6.1/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch new file mode 100644 index 0000000000..3a5b8fe593 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch @@ -0,0 +1,25 @@ +From a3e9dc73758c378dd471fb6b1458f39592b020fe Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 14 Oct 2021 20:56:54 +0200 +Subject: [PATCH 1002/1024] 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 +--- + 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 = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data }, + { .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data }, + { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data }, ++ { .compatible = "starfive,jh7100-hsuart", .data = &dw8250_starfive_jh7100_data }, + { .compatible = "starfive,jh7100-uart", .data = &dw8250_starfive_jh7100_data }, + { /* Sentinel */ } + }; diff --git a/target/linux/starfive/patches-6.1/1003-riscv-dts-starfive-Group-tuples-in-interrupt-propert.patch b/target/linux/starfive/patches-6.1/1003-riscv-dts-starfive-Group-tuples-in-interrupt-propert.patch new file mode 100644 index 0000000000..a202950455 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1003-riscv-dts-starfive-Group-tuples-in-interrupt-propert.patch @@ -0,0 +1,40 @@ +From 790e1157753b4dcc9bad4521987fe09aa6657876 Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Thu, 25 Nov 2021 14:21:18 +0100 +Subject: [PATCH 1003/1024] riscv: dts: starfive: Group tuples in interrupt + properties + +To improve human readability and enable automatic validation, the tuples +in the various properties containing interrupt specifiers should be +grouped. + +Fix this by grouping the tuples of "interrupts-extended" properties +using angle brackets. + +Signed-off-by: Geert Uytterhoeven +--- + arch/riscv/boot/dts/starfive/jh7100.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -118,15 +118,15 @@ + clint: clint@2000000 { + compatible = "starfive,jh7100-clint", "sifive,clint0"; + reg = <0x0 0x2000000 0x0 0x10000>; +- interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 +- &cpu1_intc 3 &cpu1_intc 7>; ++ interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>, ++ <&cpu1_intc 3>, <&cpu1_intc 7>; + }; + + plic: interrupt-controller@c000000 { + compatible = "starfive,jh7100-plic", "sifive,plic-1.0.0"; + reg = <0x0 0xc000000 0x0 0x4000000>; +- interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9 +- &cpu1_intc 11 &cpu1_intc 9>; ++ interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>, ++ <&cpu1_intc 11>, <&cpu1_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; diff --git a/target/linux/starfive/patches-6.1/1004-RISC-V-Add-StarFive-JH7100-audio-clock-node.patch b/target/linux/starfive/patches-6.1/1004-RISC-V-Add-StarFive-JH7100-audio-clock-node.patch new file mode 100644 index 0000000000..b57ec9121e --- /dev/null +++ b/target/linux/starfive/patches-6.1/1004-RISC-V-Add-StarFive-JH7100-audio-clock-node.patch @@ -0,0 +1,32 @@ +From 6a9196186f9630006c3db022bcc0bd5796f4fae5 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 17:13:22 +0100 +Subject: [PATCH 1004/1024] RISC-V: 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 +--- + 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 +@@ -133,6 +133,16 @@ + riscv,ndev = <133>; + }; + ++ 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.1/1005-RISC-V-Mark-StarFive-JH7100-as-having-non-coherent-D.patch b/target/linux/starfive/patches-6.1/1005-RISC-V-Mark-StarFive-JH7100-as-having-non-coherent-D.patch new file mode 100644 index 0000000000..11fa1155d6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1005-RISC-V-Mark-StarFive-JH7100-as-having-non-coherent-D.patch @@ -0,0 +1,21 @@ +From a22e1110a6ffcc2cf4b3b598f037879cbd0915d3 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Wed, 31 Aug 2022 22:54:07 +0200 +Subject: [PATCH 1005/1024] RISC-V: Mark StarFive JH7100 as having non-coherent + DMAs + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/jh7100.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -111,6 +111,7 @@ + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; ++ dma-noncoherent; + #address-cells = <2>; + #size-cells = <2>; + ranges; diff --git a/target/linux/starfive/patches-6.1/1006-drivers-tty-serial-8250-update-driver-for-JH7100.patch b/target/linux/starfive/patches-6.1/1006-drivers-tty-serial-8250-update-driver-for-JH7100.patch new file mode 100644 index 0000000000..feb52591b3 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1006-drivers-tty-serial-8250-update-driver-for-JH7100.patch @@ -0,0 +1,28 @@ +From d0c1660c9e88748c9eba81ff3839de54dffba6ad Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Fri, 8 Jan 2021 03:11:04 +0800 +Subject: [PATCH 1006/1024] 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 +@@ -72,8 +72,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.1/1007-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch b/target/linux/starfive/patches-6.1/1007-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch new file mode 100644 index 0000000000..1599e8a2ca --- /dev/null +++ b/target/linux/starfive/patches-6.1/1007-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch @@ -0,0 +1,55 @@ +From 5fdd2623dd3eed156fa1ec65b2096da735bb0cde Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Wed, 17 Nov 2021 14:50:45 +0800 +Subject: [PATCH 1007/1024] dmaengine: dw-axi-dmac: Handle xfer start while + non-idle + +Signed-off-by: Samin Guo +Signed-off-by: Curry Zhang +--- + 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 +@@ -382,11 +382,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); +@@ -1028,6 +1030,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.1/1008-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch b/target/linux/starfive/patches-6.1/1008-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch new file mode 100644 index 0000000000..e01c37fd76 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1008-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch @@ -0,0 +1,64 @@ +From c06352c09ce55999d41036e593293a3aaf0cf70c Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Wed, 17 Nov 2021 14:50:45 +0800 +Subject: [PATCH 1008/1024] dmaengine: dw-axi-dmac: Add StarFive JH7100 support + +Signed-off-by: Samin Guo +Signed-off-by: Emil Renner Berthing +--- + 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 +@@ -677,8 +677,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); +@@ -1508,7 +1513,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); +@@ -1593,6 +1602,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 +@@ -283,7 +283,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.1/1009-pinctrl-starfive-Reset-pinmux-settings.patch b/target/linux/starfive/patches-6.1/1009-pinctrl-starfive-Reset-pinmux-settings.patch new file mode 100644 index 0000000000..d2873ff968 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1009-pinctrl-starfive-Reset-pinmux-settings.patch @@ -0,0 +1,127 @@ +From 89c86fda8cee5b93ce213dcc46b2cf27e5ee3312 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 17 Jul 2021 21:50:38 +0200 +Subject: [PATCH 1009/1024] 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 +--- + .../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 +@@ -200,6 +200,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; +@@ -1222,6 +1226,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; +@@ -1283,6 +1346,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.1/1010-clk-starfive-Add-flags-argument-to-JH71X0__MUX-macro.patch b/target/linux/starfive/patches-6.1/1010-clk-starfive-Add-flags-argument-to-JH71X0__MUX-macro.patch new file mode 100644 index 0000000000..a12be8b979 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1010-clk-starfive-Add-flags-argument-to-JH71X0__MUX-macro.patch @@ -0,0 +1,302 @@ +From f6c0c8639c7424f915f2f2f18cf86b6b97c7d32a Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 25 Mar 2023 22:57:06 +0100 +Subject: [PATCH 1010/1024] clk: starfive: Add flags argument to JH71X0__MUX + macro + +This flag is needed to add the CLK_SET_RATE_PARENT flag on the gmac_tx +clock on the JH7100, which in turn is needed by the dwmac-starfive +driver to set the clock properly for 1000, 100 and 10 Mbps links. + +This change was mostly made using coccinelle: + +@ match @ +expression idx, name, nparents; +@@ + JH71X0__MUX( +-idx, name, nparents, ++idx, name, 0, nparents, + ...) + +Signed-off-by: Emil Renner Berthing +--- + .../clk/starfive/clk-starfive-jh7100-audio.c | 2 +- + drivers/clk/starfive/clk-starfive-jh7100.c | 32 +++++++++---------- + .../clk/starfive/clk-starfive-jh7110-aon.c | 6 ++-- + .../clk/starfive/clk-starfive-jh7110-isp.c | 2 +- + .../clk/starfive/clk-starfive-jh7110-sys.c | 26 +++++++-------- + drivers/clk/starfive/clk-starfive-jh71x0.h | 4 +-- + 6 files changed, 36 insertions(+), 36 deletions(-) + +--- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c +@@ -80,7 +80,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), + JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), + JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), +- JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2, ++ JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 0, 2, + JH7100_AUDCLK_VAD_INTMEM, + JH7100_AUDCLK_AUDIO_12288), + }; +--- a/drivers/clk/starfive/clk-starfive-jh7100.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100.c +@@ -24,48 +24,48 @@ + #define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3) + + static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { +- JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, ++ JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 0, 4, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, ++ JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, ++ JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 0, 4, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, ++ JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, ++ JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT), +- JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, ++ JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, ++ JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, ++ JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 0, 3, + JH7100_CLK_OSC_AUD, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), +- JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, ++ JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), +- JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, ++ JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT), +- JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, ++ JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 0, 3, + JH7100_CLK_OSC_AUD, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), +@@ -76,7 +76,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), + JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), +- JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, ++ JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_OSC_AUD), + JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +@@ -142,7 +142,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), + JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), +- JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, ++ JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 0, 2, + JH7100_CLK_CPU_AXI, + JH7100_CLK_NNEBUS_SRC1), + JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), +@@ -166,7 +166,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), + JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, + JH7100_CLK_USBPHY_ROOTDIV), +- JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, ++ JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_USBPHY_PLLDIV25M), + JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), +@@ -200,12 +200,12 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), +- JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, ++ JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 0, 3, + JH7100_CLK_GMAC_GTX, + JH7100_CLK_GMAC_TX_INV, + JH7100_CLK_GMAC_RMII_TX), + JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), +- JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, ++ JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 0, 2, + JH7100_CLK_GMAC_GR_MII_RX, + JH7100_CLK_GMAC_RMII_RX), + JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), +--- a/drivers/clk/starfive/clk-starfive-jh7110-aon.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c +@@ -26,7 +26,7 @@ + static const struct jh71x0_clk_data jh7110_aonclk_data[] = { + /* source */ + JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC), +- JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 2, ++ JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 0, 2, + JH7110_AONCLK_OSC_DIV4, + JH7110_AONCLK_OSC), + /* gmac0 */ +@@ -39,7 +39,7 @@ static const struct jh71x0_clk_data jh71 + JH7110_AONCLK_GMAC0_GTXCLK, + JH7110_AONCLK_GMAC0_RMII_RTX), + JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX), +- JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 2, ++ JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 0, 2, + JH7110_AONCLK_GMAC0_RGMII_RXIN, + JH7110_AONCLK_GMAC0_RMII_RTX), + JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX), +@@ -48,7 +48,7 @@ static const struct jh71x0_clk_data jh71 + /* rtc */ + JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS), + JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC), +- JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 2, ++ JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 0, 2, + JH7110_AONCLK_RTC_OSC, + JH7110_AONCLK_RTC_INTERNAL), + JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC), +--- a/drivers/clk/starfive/clk-starfive-jh7110-isp.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c +@@ -53,7 +53,7 @@ static const struct jh71x0_clk_data jh71 + JH7110_ISPCLK_MIPI_RX0_PXL), + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF3, "vin_pixel_if3", 0, + JH7110_ISPCLK_MIPI_RX0_PXL), +- JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 2, ++ JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 0, 2, + JH7110_ISPCLK_MIPI_RX0_PXL, + JH7110_ISPCLK_DVP_INV), + /* ispv2_top_wrapper */ +--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +@@ -36,18 +36,18 @@ + + static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { + /* root */ +- JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2, ++ JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 0, 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT), + JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE), +- JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2, ++ JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 0, 2, + JH7110_SYSCLK_PLL2_OUT, + JH7110_SYSCLK_PLL1_OUT), + JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2, + JH7110_SYSCLK_PLL0_OUT, + JH7110_SYSCLK_PLL2_OUT), +- JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2, ++ JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 0, 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT), +@@ -62,7 +62,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT), +- JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2, ++ JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 0, 2, + JH7110_SYSCLK_MCLK_INNER, + JH7110_SYSCLK_MCLK_EXT), + JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER), +@@ -96,7 +96,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4), +- JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4, ++ JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 0, 4, + JH7110_SYSCLK_OSC_DIV2, + JH7110_SYSCLK_PLL1_DIV2, + JH7110_SYSCLK_PLL1_DIV4, +@@ -186,7 +186,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30, + JH7110_SYSCLK_GMAC1_RMII_REFIN), + JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), +- JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2, ++ JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 0, 2, + JH7110_SYSCLK_GMAC1_RGMII_RXIN, + JH7110_SYSCLK_GMAC1_RMII_RTX), + JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX), +@@ -270,11 +270,11 @@ static const struct jh71x0_clk_data jh71 + JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2, + JH7110_SYSCLK_I2STX0_BCLK_MST_INV, + JH7110_SYSCLK_I2STX0_BCLK_MST), +- JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2, ++ JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 0, 2, + JH7110_SYSCLK_I2STX0_BCLK_MST, + JH7110_SYSCLK_I2STX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK), +- JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2, ++ JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 0, 2, + JH7110_SYSCLK_I2STX0_LRCK_MST, + JH7110_SYSCLK_I2STX_LRCK_EXT), + /* i2stx1 */ +@@ -285,11 +285,11 @@ static const struct jh71x0_clk_data jh71 + JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2, + JH7110_SYSCLK_I2STX1_BCLK_MST_INV, + JH7110_SYSCLK_I2STX1_BCLK_MST), +- JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2, ++ JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 0, 2, + JH7110_SYSCLK_I2STX1_BCLK_MST, + JH7110_SYSCLK_I2STX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK), +- JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2, ++ JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 0, 2, + JH7110_SYSCLK_I2STX1_LRCK_MST, + JH7110_SYSCLK_I2STX_LRCK_EXT), + /* i2srx */ +@@ -300,11 +300,11 @@ static const struct jh71x0_clk_data jh71 + JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2, + JH7110_SYSCLK_I2SRX_BCLK_MST_INV, + JH7110_SYSCLK_I2SRX_BCLK_MST), +- JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2, ++ JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 0, 2, + JH7110_SYSCLK_I2SRX_BCLK_MST, + JH7110_SYSCLK_I2SRX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK), +- JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2, ++ JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 0, 2, + JH7110_SYSCLK_I2SRX_LRCK_MST, + JH7110_SYSCLK_I2SRX_LRCK_EXT), + /* pdm */ +@@ -314,7 +314,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK), +- JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2, ++ JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 0, 2, + JH7110_SYSCLK_TDM_INTERNAL, + JH7110_SYSCLK_TDM_EXT), + JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM), +--- a/drivers/clk/starfive/clk-starfive-jh71x0.h ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.h +@@ -61,10 +61,10 @@ struct jh71x0_clk_data { + .parents = { [0] = _parent }, \ + } + +-#define JH71X0__MUX(_idx, _name, _nparents, ...) \ ++#define JH71X0__MUX(_idx, _name, _flags, _nparents, ...) \ + [_idx] = { \ + .name = _name, \ +- .flags = 0, \ ++ .flags = _flags, \ + .max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \ + .parents = { __VA_ARGS__ }, \ + } diff --git a/target/linux/starfive/patches-6.1/1011-clk-starfive-jh7100-Add-CLK_SET_RATE_PARENT-to-gmac_.patch b/target/linux/starfive/patches-6.1/1011-clk-starfive-jh7100-Add-CLK_SET_RATE_PARENT-to-gmac_.patch new file mode 100644 index 0000000000..e5e750820e --- /dev/null +++ b/target/linux/starfive/patches-6.1/1011-clk-starfive-jh7100-Add-CLK_SET_RATE_PARENT-to-gmac_.patch @@ -0,0 +1,25 @@ +From 38d50c243d2d4176b88ad732f4948cca9629251b Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 25 Mar 2023 23:04:31 +0100 +Subject: [PATCH 1011/1024] clk: starfive: jh7100: Add CLK_SET_RATE_PARENT to + gmac_tx + +This is needed by the dwmac-starfive ethernet driver to set the clock +for 1000, 100 and 10 Mbps links properly. + +Signed-off-by: Emil Renner Berthing +--- + drivers/clk/starfive/clk-starfive-jh7100.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/starfive/clk-starfive-jh7100.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100.c +@@ -200,7 +200,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), +- JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 0, 3, ++ JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3, + JH7100_CLK_GMAC_GTX, + JH7100_CLK_GMAC_TX_INV, + JH7100_CLK_GMAC_RMII_TX), diff --git a/target/linux/starfive/patches-6.1/1012-clk-starfive-jh7100-Keep-more-clocks-alive.patch b/target/linux/starfive/patches-6.1/1012-clk-starfive-jh7100-Keep-more-clocks-alive.patch new file mode 100644 index 0000000000..3afdf1d9a6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1012-clk-starfive-jh7100-Keep-more-clocks-alive.patch @@ -0,0 +1,94 @@ +From 3e73731c113fbe6f319403d5e2e64a656fcb17ce Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 14 Oct 2021 20:35:43 +0200 +Subject: [PATCH 1012/1024] clk: starfive: jh7100: Keep more clocks alive + +Signed-off-by: Emil Renner Berthing +--- + drivers/clk/starfive/clk-starfive-jh7100.c | 37 +++++++++++----------- + 1 file changed, 19 insertions(+), 18 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), +@@ -160,11 +160,12 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), + JH71X0_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), +- 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_GATE(JH7100_CLK_USB_AXI, "usb_axi", CLK_IGNORE_UNUSED, JH7100_CLK_USB_BUS), ++ JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", CLK_IGNORE_UNUSED, 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,23 +184,23 @@ 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), + JH71X0_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), + JH71X0__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), +- JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), ++ JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", CLK_IGNORE_UNUSED, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), +- JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), +- JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), +- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), +- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), ++ JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", CLK_IGNORE_UNUSED, 31, JH7100_CLK_GMAC_ROOT_DIV), ++ JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", CLK_IGNORE_UNUSED, 255, JH7100_CLK_GMAC_ROOT_DIV), ++ JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", CLK_IGNORE_UNUSED, 8, JH7100_CLK_GMAC_RMII_REF), ++ JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", CLK_IGNORE_UNUSED, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3, + JH7100_CLK_GMAC_GTX, + JH7100_CLK_GMAC_TX_INV, +@@ -209,8 +210,8 @@ static const struct jh71x0_clk_data jh71 + JH7100_CLK_GMAC_GR_MII_RX, + JH7100_CLK_GMAC_RMII_RX), + JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), +- JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), +- JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), ++ JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", CLK_IGNORE_UNUSED, JH7100_CLK_GMAC_RMII_REF), ++ JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", CLK_IGNORE_UNUSED, 127, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), +@@ -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.1/1013-net-stmmac-use-GFP_DMA32.patch b/target/linux/starfive/patches-6.1/1013-net-stmmac-use-GFP_DMA32.patch new file mode 100644 index 0000000000..a341c96bcf --- /dev/null +++ b/target/linux/starfive/patches-6.1/1013-net-stmmac-use-GFP_DMA32.patch @@ -0,0 +1,30 @@ +From 1889527687432bd63942c86dbebf8686b6515aad Mon Sep 17 00:00:00 2001 +From: Matteo Croce +Date: Fri, 21 May 2021 03:26:38 +0200 +Subject: [PATCH 1013/1024] net: stmmac: use GFP_DMA32 + +Signed-off-by: Matteo Croce +--- + 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 +@@ -1436,7 +1436,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; +@@ -4613,7 +4613,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.1/1014-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch b/target/linux/starfive/patches-6.1/1014-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch new file mode 100644 index 0000000000..86d3b1d839 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1014-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch @@ -0,0 +1,477 @@ +From 919bcebc58044a266e953ac302c8e068e255e2a6 Mon Sep 17 00:00:00 2001 +From: Huan Feng +Date: Fri, 8 Jan 2021 03:35:42 +0800 +Subject: [PATCH 1014/1024] hwrng: Add StarFive JH7100 Random Number Generator + driver + +Signed-off-by: Emil Renner Berthing +--- + 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 +@@ -322,6 +322,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 HW_RANDOM && ARCH_HISI +--- 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_BCM2835) += bcm2835-rng.o + obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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.1/1015-pwm-sifive-ptc-Add-SiFive-PWM-PTC-driver.patch b/target/linux/starfive/patches-6.1/1015-pwm-sifive-ptc-Add-SiFive-PWM-PTC-driver.patch new file mode 100644 index 0000000000..7f47f31fc2 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1015-pwm-sifive-ptc-Add-SiFive-PWM-PTC-driver.patch @@ -0,0 +1,309 @@ +From 8b3a02992094b5995d5a3e0d6d575aa852961c61 Mon Sep 17 00:00:00 2001 +From: Chenjieqin +Date: Fri, 8 Jan 2021 03:56:54 +0800 +Subject: [PATCH 1015/1024] pwm: sifive-ptc: Add SiFive PWM PTC driver + +yiming.li: clear CNTR of PWM after setting period & duty_cycle +Emil: cleanups, clock, reset and div_u64 + +Signed-off-by: Emil Renner Berthing +--- + drivers/pwm/Kconfig | 11 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-sifive-ptc.c | 260 +++++++++++++++++++++++++++++++++++ + 3 files changed, 272 insertions(+) + create mode 100644 drivers/pwm/pwm-sifive-ptc.c + +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -504,6 +504,17 @@ config PWM_SIFIVE + To compile this driver as a module, choose M here: the module + will be called pwm-sifive. + ++config PWM_SIFIVE_PTC ++ tristate "SiFive PWM PTC support" ++ depends on SOC_SIFIVE || SOC_STARFIVE || COMPILE_TEST ++ depends on OF ++ depends on COMMON_CLK ++ help ++ Generic PWM framework driver for SiFive SoCs. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-sifive-ptc. ++ + config PWM_SL28CPLD + tristate "Kontron sl28cpld PWM support" + depends on MFD_SL28CPLD || COMPILE_TEST +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -46,6 +46,7 @@ obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-ren + obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o + obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o + obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o ++obj-$(CONFIG_PWM_SIFIVE_PTC) += pwm-sifive-ptc.o + obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o + obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o + obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o +--- /dev/null ++++ b/drivers/pwm/pwm-sifive-ptc.c +@@ -0,0 +1,260 @@ ++/* ++ * Copyright (C) 2018 SiFive, Inc ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2, as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* max channel of pwm */ ++#define MAX_PWM 8 ++ ++/* PTC Register offsets */ ++#define REG_RPTC_CNTR 0x0 ++#define REG_RPTC_HRC 0x4 ++#define REG_RPTC_LRC 0x8 ++#define REG_RPTC_CTRL 0xC ++ ++/* Bit for PWM clock */ ++#define BIT_PWM_CLOCK_EN 31 ++ ++/* Bit for clock gen soft reset */ ++#define BIT_CLK_GEN_SOFT_RESET 13 ++ ++#define NS_1 1000000000U ++ ++/* Access PTC register (cntr hrc lrc and ctrl), need to replace PWM_BASE_ADDR */ ++#define REG_PTC_BASE_ADDR_SUB(base, N) \ ++ ((base) + (((N) > 3) ? (((N) - 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) ++#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) ++#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) ++#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) ++#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) ++ ++/* pwm ptc device */ ++struct sifive_pwm_ptc_device { ++ struct pwm_chip chip; ++ struct clk *clk; ++ void __iomem *regs; ++}; ++ ++static inline struct sifive_pwm_ptc_device *chip_to_sifive_ptc(struct pwm_chip *c) ++{ ++ return container_of(c, struct sifive_pwm_ptc_device, chip); ++} ++ ++static int sifive_pwm_ptc_get_state(struct pwm_chip *chip, struct pwm_device *dev, ++ struct pwm_state *state) ++{ ++ struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip); ++ u32 data_lrc; ++ u32 data_hrc; ++ u32 pwm_clk_ns = 0; ++ ++ /* get lrc and hrc data from registe */ ++ data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); ++ data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); ++ ++ /* how many ns does apb clock elapse */ ++ pwm_clk_ns = NS_1 / clk_get_rate(pwm->clk); ++ ++ /* pwm period(ns) */ ++ state->period = data_lrc * pwm_clk_ns; ++ ++ /* duty cycle(ns) means high level eclapse ns if it is normal polarity */ ++ state->duty_cycle = data_hrc * pwm_clk_ns; ++ ++ /* polarity, we don't use it now because it is not in dts */ ++ state->polarity = PWM_POLARITY_NORMAL; ++ ++ /* enabled or not */ ++ state->enabled = 1; ++ ++ dev_dbg(pwm->chip.dev, "%s: no:%d\n", __func__, dev->hwpwm); ++ dev_dbg(pwm->chip.dev, "data_hrc:0x%x 0x%x\n", data_hrc, data_lrc); ++ dev_dbg(pwm->chip.dev, "period:%llu\n", state->period); ++ dev_dbg(pwm->chip.dev, "duty_cycle:%llu\n", state->duty_cycle); ++ dev_dbg(pwm->chip.dev, "polarity:%d\n", state->polarity); ++ dev_dbg(pwm->chip.dev, "enabled:%d\n", state->enabled); ++ ++ return 0; ++} ++ ++static int sifive_pwm_ptc_apply(struct pwm_chip *chip, struct pwm_device *dev, ++ const struct pwm_state *state) ++{ ++ struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip); ++ void __iomem *reg_addr; ++ u32 pwm_clk_ns = 0; ++ u32 data_hrc = 0; ++ u32 data_lrc = 0; ++ u32 period_data = 0; ++ u32 duty_data = 0; ++ ++ dev_dbg(pwm->chip.dev, "%s: no:%d\n", __func__, dev->hwpwm); ++ dev_dbg(pwm->chip.dev, "period:%llu\n", state->period); ++ dev_dbg(pwm->chip.dev, "duty_cycle:%llu\n", state->duty_cycle); ++ dev_dbg(pwm->chip.dev, "polarity:%d\n", state->polarity); ++ dev_dbg(pwm->chip.dev, "enabled:%d\n", state->enabled); ++ ++ /* duty_cycle should be less or equal than period */ ++ if (state->duty_cycle > state->period) ++ return -EINVAL; ++ ++ /* calculate pwm real period (ns) */ ++ pwm_clk_ns = NS_1 / clk_get_rate(pwm->clk); ++ ++ dev_dbg(pwm->chip.dev, "pwm_clk_ns:%u\n", pwm_clk_ns); ++ ++ /* calculate period count */ ++ period_data = div_u64(state->period, pwm_clk_ns); ++ ++ if (!state->enabled) ++ /* if disabled, just set duty_data to 0, which means low level always */ ++ duty_data = 0; ++ else ++ /* calculate duty count */ ++ duty_data = div_u64(state->duty_cycle, pwm_clk_ns); ++ ++ dev_dbg(pwm->chip.dev, "period_data:%u, duty_data:%u\n", ++ period_data, duty_data); ++ ++ if (state->polarity == PWM_POLARITY_NORMAL) ++ /* calculate data_hrc */ ++ data_hrc = period_data - duty_data; ++ else ++ /* calculate data_hrc */ ++ data_hrc = duty_data; ++ ++ data_lrc = period_data; ++ ++ /* set hrc */ ++ reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm); ++ dev_dbg(pwm->chip.dev, "%s: reg_addr:%p, data:%u\n", ++ __func__, reg_addr, data_hrc); ++ ++ iowrite32(data_hrc, reg_addr); ++ ++ dev_dbg(pwm->chip.dev, "%s: hrc ok\n", __func__); ++ ++ /* set lrc */ ++ reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm); ++ dev_dbg(pwm->chip.dev, "%s: reg_addr:%p, data:%u\n", ++ __func__, reg_addr, data_lrc); ++ ++ iowrite32(data_lrc, reg_addr); ++ dev_dbg(pwm->chip.dev, "%s: lrc ok\n", __func__); ++ ++ /* Clear REG_RPTC_CNTR after setting period & duty_cycle */ ++ reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm); ++ iowrite32(0, reg_addr); ++ return 0; ++} ++ ++static const struct pwm_ops sifive_pwm_ptc_ops = { ++ .get_state = sifive_pwm_ptc_get_state, ++ .apply = sifive_pwm_ptc_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static void sifive_pwm_ptc_disable_action(void *data) ++{ ++ clk_disable_unprepare(data); ++} ++ ++static int sifive_pwm_ptc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = pdev->dev.of_node; ++ struct sifive_pwm_ptc_device *pwm; ++ struct pwm_chip *chip; ++ struct reset_control *rst; ++ int ret; ++ ++ pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); ++ if (!pwm) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, pwm); ++ ++ chip = &pwm->chip; ++ chip->dev = dev; ++ chip->ops = &sifive_pwm_ptc_ops; ++ ++ /* how many parameters can be transferred to ptc, need to fix */ ++ chip->of_pwm_n_cells = 3; ++ chip->base = -1; ++ ++ /* get pwm channels count, max value is 8 */ ++ ret = of_property_read_u32(node, "starfive,npwm", &chip->npwm); ++ if (ret < 0 || chip->npwm > MAX_PWM) ++ chip->npwm = MAX_PWM; ++ ++ dev_dbg(dev, "%s: npwm:0x%x\n", __func__, chip->npwm); ++ ++ /* get IO base address */ ++ pwm->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pwm->regs)) ++ return dev_err_probe(dev, PTR_ERR(pwm->regs), ++ "Unable to map IO resources\n"); ++ ++ pwm->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pwm->clk)) ++ return dev_err_probe(dev, PTR_ERR(pwm->clk), ++ "Unable to get controller clock\n"); ++ ++ ret = clk_prepare_enable(pwm->clk); ++ if (ret) ++ return dev_err_probe(dev, ret, "Unable to enable clock\n"); ++ ++ ret = devm_add_action_or_reset(dev, sifive_pwm_ptc_disable_action, pwm->clk); ++ if (ret) ++ return ret; ++ ++ rst = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(rst)) ++ return dev_err_probe(dev, PTR_ERR(rst), "Unable to get reset\n"); ++ ++ ret = reset_control_deassert(rst); ++ if (ret) ++ return dev_err_probe(dev, ret, "Unable to deassert reset\n"); ++ ++ /* ++ * after pwmchip_add it will show up as /sys/class/pwm/pwmchip0, ++ * 0 is chip->base, pwm0 can be seen after running echo 0 > export ++ */ ++ ret = devm_pwmchip_add(dev, chip); ++ if (ret) ++ return dev_err_probe(dev, ret, "cannot register PTC: %d\n", ret); ++ ++ dev_dbg(dev, "SiFive PWM PTC chip registered %d PWMs\n", chip->npwm); ++ return 0; ++} ++ ++static const struct of_device_id sifive_pwm_ptc_of_match[] = { ++ { .compatible = "starfive,pwm0" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, sifive_pwm_ptc_of_match); ++ ++static struct platform_driver sifive_pwm_ptc_driver = { ++ .probe = sifive_pwm_ptc_probe, ++ .driver = { ++ .name = "pwm-sifive-ptc", ++ .of_match_table = sifive_pwm_ptc_of_match, ++ }, ++}; ++module_platform_driver(sifive_pwm_ptc_driver); ++ ++MODULE_DESCRIPTION("SiFive PWM PTC driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/starfive/patches-6.1/1016-riscv-Implement-non-coherent-DMA-support-via-SiFive-.patch b/target/linux/starfive/patches-6.1/1016-riscv-Implement-non-coherent-DMA-support-via-SiFive-.patch new file mode 100644 index 0000000000..d8a2befe64 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1016-riscv-Implement-non-coherent-DMA-support-via-SiFive-.patch @@ -0,0 +1,105 @@ +From d30b864417ea3ad1bc4fcf675ea072cb19011930 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 12 Jun 2021 16:48:31 -0700 +Subject: [PATCH 1016/1024] riscv: Implement non-coherent DMA support via + SiFive cache flushing + +This variant is used on the StarFive JH7100 SoC. + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/Kconfig | 6 ++++-- + arch/riscv/mm/dma-noncoherent.c | 37 +++++++++++++++++++++++++++++++-- + 2 files changed, 39 insertions(+), 4 deletions(-) + +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -225,12 +225,14 @@ config LOCKDEP_SUPPORT + def_bool y + + config RISCV_DMA_NONCOHERENT +- bool ++ bool "Support non-coherent DMA" ++ default SOC_STARFIVE + select ARCH_HAS_DMA_PREP_COHERENT ++ select ARCH_HAS_DMA_SET_UNCACHED ++ select ARCH_HAS_DMA_CLEAR_UNCACHED + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SETUP_DMA_OPS +- select DMA_DIRECT_REMAP + + config AS_HAS_INSN + def_bool $(as-instr,.insn r 51$(comma) 0$(comma) 0$(comma) t0$(comma) t0$(comma) zero) +--- a/arch/riscv/mm/dma-noncoherent.c ++++ b/arch/riscv/mm/dma-noncoherent.c +@@ -9,14 +9,21 @@ + #include + #include + #include ++#include + + static bool noncoherent_supported; + + void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, + enum dma_data_direction dir) + { +- void *vaddr = phys_to_virt(paddr); ++ void *vaddr; + ++ if (sifive_ccache_handle_noncoherent()) { ++ sifive_ccache_flush_range(paddr, size); ++ return; ++ } ++ ++ vaddr = phys_to_virt(paddr); + switch (dir) { + case DMA_TO_DEVICE: + ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size); +@@ -35,8 +42,14 @@ void arch_sync_dma_for_device(phys_addr_ + void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, + enum dma_data_direction dir) + { +- void *vaddr = phys_to_virt(paddr); ++ void *vaddr; ++ ++ if (sifive_ccache_handle_noncoherent()) { ++ sifive_ccache_flush_range(paddr, size); ++ return; ++ } + ++ vaddr = phys_to_virt(paddr); + switch (dir) { + case DMA_TO_DEVICE: + break; +@@ -49,10 +62,30 @@ void arch_sync_dma_for_cpu(phys_addr_t p + } + } + ++void *arch_dma_set_uncached(void *addr, size_t size) ++{ ++ if (sifive_ccache_handle_noncoherent()) ++ return sifive_ccache_set_uncached(addr, size); ++ ++ return addr; ++} ++ ++void arch_dma_clear_uncached(void *addr, size_t size) ++{ ++ if (sifive_ccache_handle_noncoherent()) ++ sifive_ccache_clear_uncached(addr, size); ++} ++ + void arch_dma_prep_coherent(struct page *page, size_t size) + { + void *flush_addr = page_address(page); + ++ if (sifive_ccache_handle_noncoherent()) { ++ memset(flush_addr, 0, size); ++ sifive_ccache_flush_range(__pa(flush_addr), size); ++ return; ++ } ++ + ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size); + } + diff --git a/target/linux/starfive/patches-6.1/1017-dt-bindings-riscv-sifive-ccache-Add-uncached-offset-.patch b/target/linux/starfive/patches-6.1/1017-dt-bindings-riscv-sifive-ccache-Add-uncached-offset-.patch new file mode 100644 index 0000000000..7de04411ed --- /dev/null +++ b/target/linux/starfive/patches-6.1/1017-dt-bindings-riscv-sifive-ccache-Add-uncached-offset-.patch @@ -0,0 +1,30 @@ +From 3b83b32e16fa431c76a5da1ac59c268ca2fecbb5 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Sat, 11 Feb 2023 05:18:11 +0200 +Subject: [PATCH 1017/1024] dt-bindings: riscv: sifive-ccache: Add + 'uncached-offset' property + +Add the 'uncached-offset' property to be used for specifying the +uncached memory offset required for handling non-coherent DMA +transactions. + +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20230211031821.976408-3-cristian.ciocaltea@collabora.com +--- + Documentation/devicetree/bindings/riscv/sifive,ccache0.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/Documentation/devicetree/bindings/riscv/sifive,ccache0.yaml ++++ b/Documentation/devicetree/bindings/riscv/sifive,ccache0.yaml +@@ -70,6 +70,11 @@ properties: + + next-level-cache: true + ++ uncached-offset: ++ $ref: /schemas/types.yaml#/definitions/uint64 ++ description: | ++ Uncached memory offset for handling non-coherent DMA transactions. ++ + memory-region: + maxItems: 1 + description: | diff --git a/target/linux/starfive/patches-6.1/1018-soc-sifive-ccache-Add-StarFive-JH71x0-support.patch b/target/linux/starfive/patches-6.1/1018-soc-sifive-ccache-Add-StarFive-JH71x0-support.patch new file mode 100644 index 0000000000..04d1e5aa1e --- /dev/null +++ b/target/linux/starfive/patches-6.1/1018-soc-sifive-ccache-Add-StarFive-JH71x0-support.patch @@ -0,0 +1,77 @@ +From cde57aebfd86b3b062ce0bcf71395d735d05b2f6 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Wed, 6 Apr 2022 00:38:05 +0200 +Subject: [PATCH 1018/1024] soc: sifive: ccache: Add StarFive JH71x0 support + +This adds support for the StarFive JH7100 and JH7110 SoCs which also +feature this SiFive cache controller. + +Unfortunately the interrupt for uncorrected data is broken on the JH7100 +and fires continuously, so add a quirk to not register a handler for it. + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/Kconfig.socs | 1 + + drivers/soc/sifive/Kconfig | 2 +- + drivers/soc/sifive/sifive_ccache.c | 12 +++++++++++- + 3 files changed, 13 insertions(+), 2 deletions(-) + +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -28,6 +28,7 @@ config SOC_STARFIVE + bool "StarFive SoCs" + select PINCTRL + select RESET_CONTROLLER ++ select SIFIVE_CCACHE + select SIFIVE_PLIC + select ARM_AMBA + help +--- a/drivers/soc/sifive/Kconfig ++++ b/drivers/soc/sifive/Kconfig +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + +-if SOC_SIFIVE ++if SOC_SIFIVE || SOC_STARFIVE + + config SIFIVE_CCACHE + bool "Sifive Composable Cache controller" +--- a/drivers/soc/sifive/sifive_ccache.c ++++ b/drivers/soc/sifive/sifive_ccache.c +@@ -106,6 +106,8 @@ static void ccache_config_read(void) + static const struct of_device_id sifive_ccache_ids[] = { + { .compatible = "sifive,fu540-c000-ccache" }, + { .compatible = "sifive,fu740-c000-ccache" }, ++ { .compatible = "starfive,jh7100-ccache", .data = (void *)BIT(DATA_UNCORR) }, ++ { .compatible = "starfive,jh7110-ccache" }, + { .compatible = "sifive,ccache0" }, + { /* end of table */ } + }; +@@ -210,11 +212,15 @@ static int __init sifive_ccache_init(voi + struct device_node *np; + struct resource res; + int i, rc, intr_num; ++ const struct of_device_id *match; ++ unsigned long broken_irqs; + +- np = of_find_matching_node(NULL, sifive_ccache_ids); ++ np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match); + if (!np) + return -ENODEV; + ++ broken_irqs = (uintptr_t)match->data; ++ + if (of_address_to_resource(np, 0, &res)) { + rc = -ENODEV; + goto err_node_put; +@@ -240,6 +246,10 @@ static int __init sifive_ccache_init(voi + + for (i = 0; i < intr_num; i++) { + g_irq[i] = irq_of_parse_and_map(np, i); ++ ++ if (broken_irqs & BIT(i)) ++ continue; ++ + rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc", + NULL); + if (rc) { diff --git a/target/linux/starfive/patches-6.1/1019-soc-sifive-ccache-Add-non-coherent-DMA-handling.patch b/target/linux/starfive/patches-6.1/1019-soc-sifive-ccache-Add-non-coherent-DMA-handling.patch new file mode 100644 index 0000000000..0713739b5f --- /dev/null +++ b/target/linux/starfive/patches-6.1/1019-soc-sifive-ccache-Add-non-coherent-DMA-handling.patch @@ -0,0 +1,159 @@ +From 335c32d2653f2415e042c8ad1ae2a6b33019b96f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 12 Jun 2021 16:48:31 -0700 +Subject: [PATCH 1019/1024] soc: sifive: ccache: Add non-coherent DMA handling + +Add functions to flush the caches and handle non-coherent DMA. + +Signed-off-by: Emil Renner Berthing +--- + drivers/soc/sifive/sifive_ccache.c | 60 +++++++++++++++++++++++++++++- + include/soc/sifive/sifive_ccache.h | 21 +++++++++++ + 2 files changed, 80 insertions(+), 1 deletion(-) + +--- a/drivers/soc/sifive/sifive_ccache.c ++++ b/drivers/soc/sifive/sifive_ccache.c +@@ -8,13 +8,16 @@ + + #define pr_fmt(fmt) "CCACHE: " fmt + ++#include + #include + #include + #include + #include + #include + #include ++#include + #include ++#include + #include + + #define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100 +@@ -39,10 +42,14 @@ + #define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16) + #define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24) + ++#define SIFIVE_CCACHE_FLUSH64 0x200 ++#define SIFIVE_CCACHE_FLUSH32 0x240 ++ + #define SIFIVE_CCACHE_WAYENABLE 0x08 + #define SIFIVE_CCACHE_ECCINJECTERR 0x40 + + #define SIFIVE_CCACHE_MAX_ECCINTR 4 ++#define SIFIVE_CCACHE_LINE_SIZE 64 + + static void __iomem *ccache_base; + static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR]; +@@ -126,6 +133,47 @@ int unregister_sifive_ccache_error_notif + } + EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier); + ++#ifdef CONFIG_RISCV_DMA_NONCOHERENT ++static phys_addr_t uncached_offset; ++DEFINE_STATIC_KEY_FALSE(sifive_ccache_handle_noncoherent_key); ++ ++void sifive_ccache_flush_range(phys_addr_t start, size_t len) ++{ ++ phys_addr_t end = start + len; ++ phys_addr_t line; ++ ++ if (!len) ++ return; ++ ++ mb(); ++ for (line = ALIGN_DOWN(start, SIFIVE_CCACHE_LINE_SIZE); line < end; ++ line += SIFIVE_CCACHE_LINE_SIZE) { ++#ifdef CONFIG_32BIT ++ writel(line >> 4, ccache_base + SIFIVE_CCACHE_FLUSH32); ++#else ++ writeq(line, ccache_base + SIFIVE_CCACHE_FLUSH64); ++#endif ++ mb(); ++ } ++} ++EXPORT_SYMBOL_GPL(sifive_ccache_flush_range); ++ ++void *sifive_ccache_set_uncached(void *addr, size_t size) ++{ ++ phys_addr_t phys_addr = __pa(addr) + uncached_offset; ++ void *mem_base; ++ ++ mem_base = memremap(phys_addr, size, MEMREMAP_WT); ++ if (!mem_base) { ++ pr_err("%s memremap failed for addr %p\n", __func__, addr); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ return mem_base; ++} ++EXPORT_SYMBOL_GPL(sifive_ccache_set_uncached); ++#endif /* CONFIG_RISCV_DMA_NONCOHERENT */ ++ + static int ccache_largest_wayenabled(void) + { + return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF; +@@ -214,6 +262,7 @@ static int __init sifive_ccache_init(voi + int i, rc, intr_num; + const struct of_device_id *match; + unsigned long broken_irqs; ++ u64 __maybe_unused offset; + + np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match); + if (!np) +@@ -259,6 +308,15 @@ static int __init sifive_ccache_init(voi + } + of_node_put(np); + ++#ifdef CONFIG_RISCV_DMA_NONCOHERENT ++ if (!of_property_read_u64(np, "uncached-offset", &offset)) { ++ uncached_offset = offset; ++ static_branch_enable(&sifive_ccache_handle_noncoherent_key); ++ riscv_cbom_block_size = SIFIVE_CCACHE_LINE_SIZE; ++ riscv_noncoherent_supported(); ++ } ++#endif ++ + ccache_config_read(); + + ccache_cache_ops.get_priv_group = ccache_get_priv_group; +@@ -279,4 +337,4 @@ err_node_put: + return rc; + } + +-device_initcall(sifive_ccache_init); ++arch_initcall(sifive_ccache_init); +--- a/include/soc/sifive/sifive_ccache.h ++++ b/include/soc/sifive/sifive_ccache.h +@@ -7,10 +7,31 @@ + #ifndef __SOC_SIFIVE_CCACHE_H + #define __SOC_SIFIVE_CCACHE_H + ++#include ++#include ++ + extern int register_sifive_ccache_error_notifier(struct notifier_block *nb); + extern int unregister_sifive_ccache_error_notifier(struct notifier_block *nb); + + #define SIFIVE_CCACHE_ERR_TYPE_CE 0 + #define SIFIVE_CCACHE_ERR_TYPE_UE 1 + ++DECLARE_STATIC_KEY_FALSE(sifive_ccache_handle_noncoherent_key); ++ ++static inline bool sifive_ccache_handle_noncoherent(void) ++{ ++#ifdef CONFIG_SIFIVE_CCACHE ++ return static_branch_unlikely(&sifive_ccache_handle_noncoherent_key); ++#else ++ return false; ++#endif ++} ++ ++void sifive_ccache_flush_range(phys_addr_t start, size_t len); ++void *sifive_ccache_set_uncached(void *addr, size_t size); ++static inline void sifive_ccache_clear_uncached(void *addr, size_t size) ++{ ++ memunmap(addr); ++} ++ + #endif /* __SOC_SIFIVE_CCACHE_H */ diff --git a/target/linux/starfive/patches-6.1/1020-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch b/target/linux/starfive/patches-6.1/1020-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch new file mode 100644 index 0000000000..7641c559d5 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1020-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch @@ -0,0 +1,48 @@ +From f684a12dac29522c6ce9d504522f75dcf024fc5f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 19:29:25 +0100 +Subject: [PATCH 1020/1024] 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 +--- + .../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.1/1021-dt-bindings-reset-Add-starfive-jh7100-audrst-binding.patch b/target/linux/starfive/patches-6.1/1021-dt-bindings-reset-Add-starfive-jh7100-audrst-binding.patch new file mode 100644 index 0000000000..413833707a --- /dev/null +++ b/target/linux/starfive/patches-6.1/1021-dt-bindings-reset-Add-starfive-jh7100-audrst-binding.patch @@ -0,0 +1,56 @@ +From 9220294c675a111651ff12b2389a81f0935553fd Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Tue, 7 Dec 2021 21:48:51 +0100 +Subject: [PATCH 1021/1024] dt-bindings: reset: Add starfive,jh7100-audrst + bindings + +Add bindings for the audio reset controller on the StarFive JH7100 +RISC-V SoC. + +Signed-off-by: Emil Renner Berthing +--- + .../reset/starfive,jh7100-audrst.yaml | 38 +++++++++++++++++++ + 1 file changed, 38 insertions(+) + create mode 100644 Documentation/devicetree/bindings/reset/starfive,jh7100-audrst.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/reset/starfive,jh7100-audrst.yaml +@@ -0,0 +1,38 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/reset/starfive,jh7100-audrst.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: StarFive JH7100 SoC Audio Reset Controller Device Tree Bindings ++ ++maintainers: ++ - Emil Renner Berthing ++ ++properties: ++ compatible: ++ enum: ++ - starfive,jh7100-audrst ++ ++ reg: ++ maxItems: 1 ++ ++ "#reset-cells": ++ const: 1 ++ ++required: ++ - compatible ++ - reg ++ - "#reset-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ reset-controller@10490000 { ++ compatible = "starfive,jh7100-audrst"; ++ reg = <0x10490000 0x10000>; ++ #reset-cells = <1>; ++ }; ++ ++... diff --git a/target/linux/starfive/patches-6.1/1022-reset-starfive-Add-JH7100-audio-reset-driver.patch b/target/linux/starfive/patches-6.1/1022-reset-starfive-Add-JH7100-audio-reset-driver.patch new file mode 100644 index 0000000000..dc25d354d6 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1022-reset-starfive-Add-JH7100-audio-reset-driver.patch @@ -0,0 +1,144 @@ +From ff806bda9b04bcf73350e319f3efde5cd049b77a Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 19:30:49 +0100 +Subject: [PATCH 1022/1024] 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 +--- + 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 +@@ -19704,7 +19704,7 @@ STARFIVE JH71X0 RESET CONTROLLER DRIVERS + M: Emil Renner Berthing + M: Hal Feng + 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 AUXILIARY_BUS && 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 ++ */ ++ ++#include ++#include ++#include ++ ++#include "reset-starfive-jh71x0.h" ++ ++#include ++ ++/* 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 ++ */ ++ ++#ifndef _RESET_STARFIVE_JH7100_H_ ++#define _RESET_STARFIVE_JH7100_H_ ++ ++#include ++ ++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.1/1023-RISC-V-Add-StarFive-JH7100-audio-reset-node.patch b/target/linux/starfive/patches-6.1/1023-RISC-V-Add-StarFive-JH7100-audio-reset-node.patch new file mode 100644 index 0000000000..0ef6fa485e --- /dev/null +++ b/target/linux/starfive/patches-6.1/1023-RISC-V-Add-StarFive-JH7100-audio-reset-node.patch @@ -0,0 +1,28 @@ +From f7ab709727e845ffdfc428ec2f236d0c1997b153 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 21:33:08 +0100 +Subject: [PATCH 1023/1024] RISC-V: 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 +--- + 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 +@@ -144,6 +144,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.1/1024-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch b/target/linux/starfive/patches-6.1/1024-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch new file mode 100644 index 0000000000..92176679de --- /dev/null +++ b/target/linux/starfive/patches-6.1/1024-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch @@ -0,0 +1,1265 @@ +From 9912cdc9038c40fbcb1f121445519efb55dec046 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sun, 31 Oct 2021 17:15:58 +0100 +Subject: [PATCH 1024/1024] 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 +Huan.Feng +ke.zhu +yiming.li +jack.zhu +Samin Guo +Chenjieqin +bo.li + +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: Emil Renner Berthing +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen L Arnold +Signed-off-by: Drew Fustini +Signed-off-by: Jianlong Huang +Signed-off-by: Jonas Hahnfeld +--- + arch/riscv/boot/dts/starfive/Makefile | 1 + + .../starfive/jh7100-beaglev-starlight-a1.dts | 30 + + .../dts/starfive/jh7100-beaglev-starlight.dts | 16 + + .../boot/dts/starfive/jh7100-common.dtsi | 434 ++++++++++++++ + .../jh7100-starfive-visionfive-v1.dts | 19 + + arch/riscv/boot/dts/starfive/jh7100.dtsi | 561 ++++++++++++++++++ + 6 files changed, 1061 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,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++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,30 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++/dts-v1/; ++#include "jh7100-common.dtsi" ++#include ++ ++/ { ++ 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>; ++}; ++ ++&mdio { ++ phy: ethernet-phy@7 { ++ reg = <7>; ++ }; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts ++++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts +@@ -6,8 +6,24 @@ + + /dts-v1/; + #include "jh7100-common.dtsi" ++#include + + / { + model = "BeagleV Starlight Beta"; + compatible = "beagle,beaglev-starlight-jh7100-r0", "starfive,jh7100"; + }; ++ ++&gmac { ++ snps,reset-gpios = <&gpio 63 GPIO_ACTIVE_LOW>; ++}; ++ ++&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 +@@ -12,7 +12,10 @@ + + / { + aliases { ++ mmc0 = &sdio0; ++ mmc1 = &sdio1; + serial0 = &uart3; ++ serial1 = &uart0; + }; + + chosen { +@@ -39,9 +42,174 @@ + label = "ack"; + }; + }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ size = <0x0 0x28000000>; ++ alignment = <0x0 0x1000>; ++ alloc-ranges = <0x0 0xa0000000 0x0 0x28000000>; ++ linux,cma-default; ++ }; ++ ++ jpu_reserved: framebuffer@c9000000 { ++ reg = <0x0 0xc9000000 0x0 0x4000000>; ++ }; ++ ++ nvdla_reserved: framebuffer@d0000000 { ++ no-map; ++ reg = <0x0 0xd0000000 0x0 0x28000000>; ++ }; ++ ++ vin_reserved: framebuffer@f9000000 { ++ compatible = "shared-dma-pool"; ++ no-map; ++ reg = <0x0 0xf9000000 0x0 0x1000000>; ++ }; ++ ++ sffb_reserved: framebuffer@fb000000 { ++ compatible = "shared-dma-pool"; ++ no-map; ++ reg = <0x0 0xfb000000 0x0 0x2000000>; ++ }; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio 37 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ ++&display { ++ memory-region = <&sffb_reserved>; ++ status = "okay"; ++}; ++ ++&crtc { ++ ddr-format = <4>; //; ++ 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 { ++ starfive,gtxclk-dlychain = <4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac_pins>; ++ phy-mode = "rgmii-txid"; ++ phy-handle = <&phy>; ++ status = "okay"; ++ ++ mdio: mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ }; + }; + + &gpio { ++ gmac_pins: gmac-0 { ++ gtxclk-pins { ++ pins = ; ++ bias-pull-up; ++ drive-strength = <35>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ miitxclk-pins { ++ pins = ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ tx-pins { ++ pins = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ bias-pull-up; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ rxclk-pins { ++ pins = ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <6>; ++ }; ++ rxer-pins { ++ pins = ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ rx-pins { ++ pins = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ + i2c0_pins: i2c0-0 { + i2c-pins { + pinmux = , ++ ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ pwm_pins: pwm-0 { ++ pwm-pins { ++ pinmux = , ++ ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ sdio0_pins: sdio0-0 { ++ clk-pins { ++ pinmux = ; ++ bias-disable; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ sdio-pins { ++ pinmux = , ++ , ++ , ++ , ++ , ++ ; ++ bias-pull-up; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ sdio1_pins: sdio1-0 { ++ clk-pins { ++ pinmux = ; ++ bias-disable; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ sdio-pins { ++ pinmux = , ++ , ++ , ++ , ++ ; ++ bias-pull-up; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ }; ++ ++ spi2_pins: spi2-0 { ++ mosi-pins { ++ pinmux = ; ++ bias-disable; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ miso-pins { ++ pinmux = ; ++ bias-pull-up; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ sck-pins { ++ pinmux = ; ++ bias-disable; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ ss-pins { ++ pinmux = , ++ ; ++ bias-disable; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ }; ++ ++ uart0_pins: uart0-0 { ++ rx-pins { ++ pinmux = , ++ ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ tx-pins { ++ pinmux = , ++ ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ }; ++ + uart3_pins: uart3-0 { + rx-pins { + pinmux = ; ++ ++ port { ++ tda998x_0_input: endpoint { ++ remote-endpoint = <&hdmi_out>; ++ }; ++ }; ++ }; + }; + + &i2c1 { +@@ -154,8 +493,103 @@ + clock-frequency = <27000000>; + }; + ++&ptc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ 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>; ++ cap-sd-highspeed; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio0_pins>; ++ status = "okay"; ++}; ++ ++&sdio1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ bus-width = <4>; ++ cap-sd-highspeed; ++ cap-sdio-irq; ++ cap-power-off-card; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio1_pins>; ++ status = "okay"; ++ ++ wifi@1 { ++ compatible = "brcm,bcm4329-fmac"; ++ reg = <1>; ++ }; ++}; ++ ++&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>; ++ status = "okay"; ++}; ++ + &uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; + status = "okay"; + }; ++ ++&usb3 { ++ dr_mode = "host"; ++ status = "okay"; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts ++++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts +@@ -18,3 +18,22 @@ + priority = <224>; + }; + }; ++ ++&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>; ++ }; ++}; ++ ++&mdio { ++ phy: ethernet-phy@0 { ++ reg = <0>; ++ }; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -6,7 +6,9 @@ + + /dts-v1/; + #include ++#include + #include ++#include + + / { + compatible = "starfive,jh7100"; +@@ -32,7 +34,9 @@ + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv39"; ++ next-level-cache = <&ccache>; + riscv,isa = "rv64imafdc"; ++ starfive,itim = <&itim0>; + tlb-split; + + cpu0_intc: interrupt-controller { +@@ -57,7 +61,9 @@ + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv39"; ++ next-level-cache = <&ccache>; + riscv,isa = "rv64imafdc"; ++ starfive,itim = <&itim1>; + tlb-split; + + cpu1_intc: interrupt-controller { +@@ -108,6 +114,13 @@ + clock-frequency = <0>; + }; + ++ /* gmac device configuration */ ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,wr_osr_lmt = <0xf>; ++ snps,rd_osr_lmt = <0xf>; ++ snps,blen = <256 128 64 32 0 0 0>; ++ }; ++ + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; +@@ -116,6 +129,24 @@ + #size-cells = <2>; + 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>; +@@ -123,6 +154,21 @@ + <&cpu1_intc 3>, <&cpu1_intc 7>; + }; + ++ ccache: cache-controller@2010000 { ++ compatible = "starfive,jh7100-ccache", "cache"; ++ reg = <0x0 0x2010000 0x0 0x1000>, ++ <0x0 0x8000000 0x0 0x2000000>; ++ reg-names = "control", "sideband"; ++ interrupts = <128>, <130>, <131>, <129>; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-sets = <2048>; ++ cache-size = <2097152>; ++ cache-unified; ++ /*next-level-cache = <&L40 &L36>;*/ ++ uncached-offset = <0xf 0x80000000>; ++ }; ++ + plic: interrupt-controller@c000000 { + compatible = "starfive,jh7100-plic", "sifive,plic-1.0.0"; + reg = <0x0 0xc000000 0x0 0x4000000>; +@@ -134,6 +180,177 @@ + riscv,ndev = <133>; + }; + ++ sdio0: mmc@10000000 { ++ compatible = "snps,dw-mshc"; ++ reg = <0x0 0x10000000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_SDIO0_AHB>, ++ <&clkgen JH7100_CLK_SDIO0_CCLKINT_INV>; ++ clock-names = "biu", "ciu"; ++ interrupts = <4>; ++ data-addr = <0>; ++ fifo-depth = <32>; ++ fifo-watermark-aligned; ++ status = "disabled"; ++ }; ++ ++ sdio1: mmc@10010000 { ++ compatible = "snps,dw-mshc"; ++ reg = <0x0 0x10010000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_SDIO1_AHB>, ++ <&clkgen JH7100_CLK_SDIO1_CCLKINT_INV>; ++ clock-names = "biu", "ciu"; ++ interrupts = <5>; ++ data-addr = <0>; ++ fifo-depth = <32>; ++ fifo-watermark-aligned; ++ status = "disabled"; ++ }; ++ ++ gmac: ethernet@10020000 { ++ compatible = "starfive,jh7100-dwmac", "snps,dwmac"; ++ reg = <0x0 0x10020000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_GMAC_ROOT_DIV>, ++ <&clkgen JH7100_CLK_GMAC_AHB>, ++ <&clkgen JH7100_CLK_GMAC_PTP_REF>, ++ <&clkgen JH7100_CLK_GMAC_TX_INV>, ++ <&clkgen JH7100_CLK_GMAC_GTX>; ++ clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "gtx"; ++ resets = <&rstgen JH7100_RSTN_GMAC_AHB>; ++ reset-names = "ahb"; ++ interrupts = <6>, <7>; ++ interrupt-names = "macirq", "eth_wake_irq"; ++ max-frame-size = <9000>; ++ snps,multicast-filter-bins = <0>; ++ snps,perfect-filter-entries = <128>; ++ starfive,syscon = <&sysmain 0x70 0>; ++ rx-fifo-depth = <32768>; ++ tx-fifo-depth = <16384>; ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,fixed-burst; ++ /*snps,force_sf_dma_mode;*/ ++ snps,force_thresh_dma_mode; ++ snps,no-pbl-x8; ++ status = "disabled"; ++ }; ++ ++ 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>; +@@ -150,6 +367,82 @@ + #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>; ++ }; ++ }; ++ }; ++ ++ usb3: usb@104c0000 { ++ compatible = "cdns,usb3"; ++ reg = <0x0 0x104c0000 0x0 0x10000>, // memory area for HOST registers ++ <0x0 0x104d0000 0x0 0x10000>, // memory area for DEVICE registers ++ <0x0 0x104e0000 0x0 0x10000>; // memory area for OTG/DRD registers ++ reg-names = "otg", "xhci", "dev"; ++ interrupts = <44>, <52>, <43>; ++ interrupt-names = "host", "peripheral", "otg"; ++ phy-names = "cdns3,usb3-phy", "cdns3,usb2-phy"; ++ maximum-speed = "super-speed"; ++ status = "disabled"; ++ }; ++ ++ 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>; +@@ -158,12 +451,93 @@ + #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>; + #reset-cells = <1>; + }; + ++ sysmain: syscon@11850000 { ++ compatible = "starfive,jh7100-sysmain", "syscon"; ++ 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>; ++ 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"; ++ }; ++ ++ 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>; +@@ -190,6 +564,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>, +@@ -204,6 +613,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>; //; ++ src-width = <1920>; ++ src-height = <1080>; ++ dst-format = <7>; //; ++ 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>; +@@ -265,5 +754,77 @@ + resets = <&rstgen JH7100_RSTN_WDTIMER_APB>, + <&rstgen JH7100_RSTN_WDT>; + }; ++ ++ ptc: pwm@12490000 { ++ compatible = "starfive,pwm0"; ++ reg = <0x0 0x12490000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_PWM_APB>; ++ resets = <&rstgen JH7100_RSTN_PWM_APB>; ++ #pwm-cells = <3>; ++ sifive,npwm = <8>; ++ status = "disabled"; ++ }; ++ ++ sfctemp: tmon@124a0000 { ++ compatible = "starfive,jh7100-temp"; ++ reg = <0x0 0x124a0000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_TEMP_SENSE>, ++ <&clkgen JH7100_CLK_TEMP_APB>; ++ clock-names = "sense", "bus"; ++ resets = <&rstgen JH7100_RSTN_TEMP_SENSE>, ++ <&rstgen JH7100_RSTN_TEMP_APB>; ++ reset-names = "sense", "bus"; ++ interrupts = <122>; ++ #thermal-sensor-cells = <0>; ++ }; ++ ++ thermal-zones { ++ cpu-thermal { ++ polling-delay-passive = <250>; ++ polling-delay = <15000>; ++ ++ thermal-sensors = <&sfctemp>; ++ ++ cooling-maps { ++ }; ++ ++ trips { ++ cpu_alert0: cpu_alert0 { ++ /* milliCelsius */ ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu_crit { ++ /* milliCelsius */ ++ temperature = <90000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++ ++ 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.1/1025-riscv-dts-visionfive1-enable-QSPI.patch b/target/linux/starfive/patches-6.1/1025-riscv-dts-visionfive1-enable-QSPI.patch new file mode 100644 index 0000000000..7d190a5fc0 --- /dev/null +++ b/target/linux/starfive/patches-6.1/1025-riscv-dts-visionfive1-enable-QSPI.patch @@ -0,0 +1,20 @@ +From 21e0e009b1bffea86890fcbf6e1be4c4121258ef Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Fri, 11 Aug 2023 11:28:27 +0200 +Subject: [PATCH 1025/1025] riscv: dts: visionfive1: enable QSPI + +Signed-off-by: Zoltan HERPAI +--- + .../riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts ++++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts +@@ -37,3 +37,7 @@ + reg = <0>; + }; + }; ++ ++&qspi { ++ status = "okay"; ++};