diff --git a/target/linux/starfive/config-6.12 b/target/linux/starfive/config-6.12 new file mode 100644 index 0000000000..7bb86ecee7 --- /dev/null +++ b/target/linux/starfive/config-6.12 @@ -0,0 +1,641 @@ +CONFIG_64BIT=y +# CONFIG_ACPI is not set +CONFIG_AMBA_PL08X=y +# CONFIG_ARCH_CANAAN is not set +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_DMA_DEFAULT_COHERENT=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y +# CONFIG_ARCH_MICROCHIP is not set +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +# CONFIG_ARCH_RV32I is not set +CONFIG_ARCH_RV64I=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SIFIVE=y +# CONFIG_ARCH_SOPHGO is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_STARFIVE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_ARCH_THEAD is not set +CONFIG_ARCH_WANTS_NO_INSTR=y +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_ARM_AMBA=y +# CONFIG_ARM_MHU_V2 is not set +CONFIG_ASN1=y +CONFIG_AUXILIARY_BUS=y +# CONFIG_AX45MP_L2_CACHE is not set +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y +CONFIG_BUFFER_HEAD=y +# CONFIG_BUILTIN_DTB is not set +CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC=y +CONFIG_CLK_SIFIVE=y +CONFIG_CLK_SIFIVE_PRCI=y +CONFIG_CLK_STARFIVE_JH7100=y +CONFIG_CLK_STARFIVE_JH7100_AUDIO=y +CONFIG_CLK_STARFIVE_JH7110_AON=y +CONFIG_CLK_STARFIVE_JH7110_ISP=y +CONFIG_CLK_STARFIVE_JH7110_PLL=y +CONFIG_CLK_STARFIVE_JH7110_STG=y +CONFIG_CLK_STARFIVE_JH7110_SYS=y +CONFIG_CLK_STARFIVE_JH7110_VOUT=y +CONFIG_CLK_STARFIVE_JH71X0=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CLZ_TAB=y +CONFIG_CMODEL_MEDANY=y +# CONFIG_CMODEL_MEDLOW is not set +CONFIG_COMMON_CLK=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +# CONFIG_COMPAT_32BIT_TIME is not set +CONFIG_CONFIGFS_FS=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_MITIGATIONS=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CRC16=y +CONFIG_CRC7=y +CONFIG_CRC_ITU_T=y +CONFIG_CRYPTO_BLAKE2B=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_DEV_JH7110 is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_ECC=y +CONFIG_CRYPTO_ECDH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS=64 +CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE=32 +CONFIG_CRYPTO_JITTERENTROPY_OSR=1 +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +CONFIG_CRYPTO_LIB_GF128MUL=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LIB_UTILS=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA3=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SM3=y +CONFIG_CRYPTO_SM3_GENERIC=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_USER_API=y +CONFIG_CRYPTO_USER_API_AEAD=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_RNG=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_XXHASH=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_PINCTRL=y +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_RWSEMS=y +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_SG=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WX=y +CONFIG_DECOMPRESS_GZIP=y +# CONFIG_DEVFREQ_GOV_PASSIVE is not set +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_THERMAL is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMADEVICES=y +CONFIG_DMADEVICES_DEBUG=y +CONFIG_DMADEVICES_VDEBUG=y +CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_GLOBAL_POOL=y +CONFIG_DMA_NEED_SYNC=y +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMI=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DTC=y +CONFIG_DT_IDLE_GENPD=y +CONFIG_DT_IDLE_STATES=y +CONFIG_DWMAC_DWC_QOS_ETH=y +# CONFIG_DWMAC_GENERIC is not set +CONFIG_DWMAC_STARFIVE=y +CONFIG_DW_AXI_DMAC=y +CONFIG_E24=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EEPROM_AT24=y +CONFIG_EFI=y +CONFIG_EFIVAR_FS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_COCO_SECRET is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +CONFIG_EFI_DISABLE_RUNTIME=y +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_GENERIC_STUB=y +CONFIG_EFI_PARAMS_FROM_FDT=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_STUB=y +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_ZBOOT is not set +# CONFIG_ERRATA_ANDES is not set +CONFIG_ERRATA_SIFIVE=y +CONFIG_ERRATA_SIFIVE_CIP_1200=y +CONFIG_ERRATA_SIFIVE_CIP_453=y +CONFIG_ERRATA_STARFIVE_JH7100=y +# CONFIG_ERRATA_THEAD is not set +CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_EXT4_FS=y +CONFIG_EXTCON=y +CONFIG_FAILOVER=y +CONFIG_FANOTIFY=y +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-15" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_FAT_FS=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_FONT_SUPPORT=y +CONFIG_FPU=y +CONFIG_FRAME_POINTER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FUNCTION_ALIGNMENT=0 +CONFIG_FWNODE_MDIO=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y +CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_DEVICES=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_ENTRY=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IOREMAP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_IPI_MUX=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PHY_MIPI_DPHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=128 +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_TPS65086=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HOTPLUG_CORE_SYNC=y +CONFIG_HOTPLUG_CORE_SYNC_DEAD=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING=y +CONFIG_HVC_DRIVER=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_JH7110=y +CONFIG_HW_RANDOM_STARFIVE_VIC=y +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IPMS_CAN is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_STACKS=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_JH71XX_PMU=y +CONFIG_JUMP_LABEL=y +CONFIG_KCMP=y +# CONFIG_KERNEL_UNCOMPRESSED is not set +CONFIG_LEGACY_DIRECT_IO=y +CONFIG_LIBFDT=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LSM="" +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MARVELL_PHY=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +CONFIG_MEMTEST=y +CONFIG_MFD_AXP20X=y +CONFIG_MFD_AXP20X_I2C=y +CONFIG_MFD_CORE=y +CONFIG_MFD_SYSCON=y +CONFIG_MFD_TPS65086=y +CONFIG_MICREL_PHY=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DW=y +# CONFIG_MMC_DW_BLUEFIELD is not set +# CONFIG_MMC_DW_EXYNOS is not set +# CONFIG_MMC_DW_HI3798CV200 is not set +# CONFIG_MMC_DW_HI3798MV200 is not set +# CONFIG_MMC_DW_K3 is not set +# CONFIG_MMC_DW_PCI is not set +CONFIG_MMC_DW_PLTFM=y +CONFIG_MMC_DW_STARFIVE=y +CONFIG_MMIOWB=y +CONFIG_MMU_LAZY_TLB_REFCOUNT=y +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MOTORCOMM_PHY=y +CONFIG_MPILIB=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NAMESPACES=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NET_DEVMEM=y +CONFIG_NET_EGRESS=y +CONFIG_NET_FAILOVER=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_INGRESS=y +CONFIG_NET_NS=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SELFTESTS=y +CONFIG_NET_XGRESS=y +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_DEFAULT="iso8859-15" +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NONPORTABLE=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=8 +# CONFIG_NSM is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y +CONFIG_NVMEM_SYSFS=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESOLVE=y +CONFIG_OID_REGISTRY=y +CONFIG_OVERLAY_FS_INDEX=y +CONFIG_OVERLAY_FS_METACOPY=y +CONFIG_OVERLAY_FS_REDIRECT_DIR=y +CONFIG_PADATA=y +CONFIG_PAGE_EXTENSION=y +CONFIG_PAGE_OFFSET=0xff60000000000000 +CONFIG_PAGE_POOL=y +CONFIG_PAGE_REPORTING=y +CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PCI=y +CONFIG_PCIE_CADENCE=y +CONFIG_PCIE_CADENCE_HOST=y +CONFIG_PCIE_CADENCE_PLAT=y +CONFIG_PCIE_CADENCE_PLAT_HOST=y +# CONFIG_PCIE_FU740 is not set +CONFIG_PCIE_PLDA_HOST=y +CONFIG_PCIE_STARFIVE_HOST=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_LABEL=y +CONFIG_PCI_MSI=y +CONFIG_PCS_XPCS=y +CONFIG_PERF_EVENTS=y +CONFIG_PER_VMA_LOCK=y +CONFIG_PGTABLE_HAS_HUGE_LEAVES=y +CONFIG_PGTABLE_LEVELS=5 +CONFIG_PHYLIB=y +CONFIG_PHYLIB_LEDS=y +CONFIG_PHYLINK=y +CONFIG_PHYS_ADDR_T_64BIT=y +# CONFIG_PHYS_RAM_BASE_FIXED is not set +CONFIG_PHY_STARFIVE_JH7110_DPHY_RX=y +# CONFIG_PHY_STARFIVE_JH7110_DPHY_TX is not set +CONFIG_PHY_STARFIVE_JH7110_PCIE=y +CONFIG_PHY_STARFIVE_JH7110_USB=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_STARFIVE_JH7100=y +CONFIG_PINCTRL_STARFIVE_JH7110=y +CONFIG_PINCTRL_STARFIVE_JH7110_AON=y +CONFIG_PINCTRL_STARFIVE_JH7110_SYS=y +CONFIG_PM=y +CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_PM_CLK=y +CONFIG_PM_DEBUG=y +CONFIG_PM_DEVFREQ=y +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_OPP=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +# CONFIG_POWER_RESET_TPS65086 is not set +CONFIG_PPS=y +CONFIG_PREEMPT_COUNT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_CHILDREN=y +CONFIG_PROC_KCORE=y +CONFIG_PTDUMP_CORE=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_PWM=y +CONFIG_PWM_OCORES=y +# CONFIG_PWM_SIFIVE is not set +CONFIG_QUEUED_RWLOCKS=y +CONFIG_RANDSTRUCT_NONE=y +CONFIG_RATIONAL=y +CONFIG_RCU_EQS_DEBUG=y +CONFIG_RD_GZIP=y +CONFIG_REALTEK_PHY=y +# CONFIG_REALTEK_PHY_HWMON is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_IRQ=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_AXP20X=y +CONFIG_REGULATOR_TPS65086=y +# CONFIG_RESET_ATTACK_MITIGATION is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y +CONFIG_RESET_STARFIVE_JH7100=y +CONFIG_RESET_STARFIVE_JH7100_AUDIO=m +CONFIG_RESET_STARFIVE_JH7110=y +CONFIG_RESET_STARFIVE_JH71X0=y +CONFIG_RFS_ACCEL=y +CONFIG_RISCV=y +CONFIG_RISCV_ALTERNATIVE=y +CONFIG_RISCV_APLIC=y +CONFIG_RISCV_APLIC_MSI=y +CONFIG_RISCV_BOOT_SPINWAIT=y +CONFIG_RISCV_DMA_NONCOHERENT=y +# CONFIG_RISCV_EFFICIENT_UNALIGNED_ACCESS is not set +# CONFIG_RISCV_EMULATED_UNALIGNED_ACCESS is not set +CONFIG_RISCV_IMSIC=y +CONFIG_RISCV_IMSIC_PCI=y +CONFIG_RISCV_INTC=y +CONFIG_RISCV_ISA_C=y +CONFIG_RISCV_ISA_FALLBACK=y +CONFIG_RISCV_ISA_SVNAPOT=y +# CONFIG_RISCV_ISA_SVPBMT is not set +# CONFIG_RISCV_ISA_V is not set +# CONFIG_RISCV_ISA_VENDOR_EXT_ANDES is not set +CONFIG_RISCV_ISA_ZAWRS=y +CONFIG_RISCV_ISA_ZBA=y +CONFIG_RISCV_ISA_ZBB=y +CONFIG_RISCV_ISA_ZBC=y +# CONFIG_RISCV_ISA_ZICBOM is not set +CONFIG_RISCV_ISA_ZICBOZ=y +CONFIG_RISCV_MISALIGNED=y +CONFIG_RISCV_NONSTANDARD_CACHE_OPS=y +CONFIG_RISCV_PMU=y +CONFIG_RISCV_PMU_LEGACY=y +CONFIG_RISCV_PMU_SBI=y +CONFIG_RISCV_PROBE_UNALIGNED_ACCESS=y +CONFIG_RISCV_SBI=y +CONFIG_RISCV_SBI_CPUIDLE=y +CONFIG_RISCV_SBI_V01=y +# CONFIG_RISCV_SLOW_UNALIGNED_ACCESS is not set +CONFIG_RISCV_TIMER=y +CONFIG_RISCV_USE_LINKER_RELAXATION=y +CONFIG_RPMSG=y +CONFIG_RPMSG_CHAR=y +# CONFIG_RPMSG_CTRL is not set +CONFIG_RPMSG_NS=y +# CONFIG_RPMSG_TTY is not set +CONFIG_RPMSG_VIRTIO=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_HYM8563=y +CONFIG_RTC_DRV_STARFIVE=y +CONFIG_RTC_I2C_AND_SPI=y +# CONFIG_RUNTIME_KERNEL_TESTING_MENU is not set +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_SCSI=y +CONFIG_SCSI_COMMON=y +CONFIG_SCSI_VIRTIO=y +CONFIG_SENSORS_SFCTEMP=y +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_NR_UARTS=6 +CONFIG_SERIAL_8250_RUNTIME_UARTS=6 +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_SIFIVE=y +CONFIG_SERIAL_SIFIVE_CONSOLE=y +CONFIG_SGL_ALLOC=y +CONFIG_SG_POOL=y +CONFIG_SIFIVE_CCACHE=y +CONFIG_SIFIVE_PLIC=y +CONFIG_SMP=y +# CONFIG_SND_SOC_STARFIVE is not set +CONFIG_SOCK_RX_QUEUE_MAPPING=y +CONFIG_SOC_STARFIVE=y +CONFIG_SOFTIRQ_ON_OWN_STACK=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_SOUND=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_CADENCE_QUADSPI=y +CONFIG_SPI_DYNAMIC=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_PL022=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPLIT_PMD_PTLOCKS=y +CONFIG_SPLIT_PTE_PTLOCKS=y +CONFIG_STARFIVE_JH7110_TIMER=y +CONFIG_STARFIVE_JH8100_INTC=y +CONFIG_STARFIVE_MBOX=y +# CONFIG_STARFIVE_MBOX_TEST is not set +CONFIG_STARFIVE_STARLINK_CACHE=y +# CONFIG_STARFIVE_STARLINK_PMU is not set +CONFIG_STARFIVE_WATCHDOG=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +CONFIG_STMMAC_SELFTESTS=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYNC_FILE=y +CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_SYSFB_SIMPLEFB is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_THREAD_SIZE_ORDER=2 +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TOOLCHAIN_HAS_V=y +CONFIG_TOOLCHAIN_HAS_VECTOR_CRYPTO=y +CONFIG_TOOLCHAIN_HAS_ZBB=y +CONFIG_TOOLCHAIN_HAS_ZBC=y +CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_TTY_PRINTK=y +CONFIG_TTY_PRINTK_LEVEL=6 +CONFIG_TUNE_GENERIC=y +CONFIG_UCS2_STRING=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_USB=y +CONFIG_USB_CDNS3=y +CONFIG_USB_CDNS3_GADGET=y +CONFIG_USB_CDNS3_HOST=y +CONFIG_USB_CDNS3_STARFIVE=y +CONFIG_USB_CDNS_HOST=y +CONFIG_USB_CDNS_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_CONFIGFS=y +# CONFIG_USB_CONFIGFS_ACM is not set +# CONFIG_USB_CONFIGFS_ECM is not set +# CONFIG_USB_CONFIGFS_ECM_SUBSET is not set +# CONFIG_USB_CONFIGFS_EEM is not set +CONFIG_USB_CONFIGFS_F_FS=y +# CONFIG_USB_CONFIGFS_F_HID is not set +# CONFIG_USB_CONFIGFS_F_LB_SS is not set +# CONFIG_USB_CONFIGFS_F_MIDI is not set +# CONFIG_USB_CONFIGFS_F_MIDI2 is not set +# CONFIG_USB_CONFIGFS_F_PRINTER is not set +# CONFIG_USB_CONFIGFS_F_UAC1 is not set +# CONFIG_USB_CONFIGFS_F_UAC1_LEGACY is not set +# CONFIG_USB_CONFIGFS_F_UAC2 is not set +# CONFIG_USB_CONFIGFS_F_UVC is not set +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +# CONFIG_USB_CONFIGFS_NCM is not set +# CONFIG_USB_CONFIGFS_OBEX is not set +# CONFIG_USB_CONFIGFS_RNDIS is not set +# CONFIG_USB_CONFIGFS_SERIAL is not set +CONFIG_USB_F_FS=y +CONFIG_USB_F_MASS_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_PCI=y +CONFIG_USB_ROLE_SWITCH=y +CONFIG_USB_SUPPORT=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USELIB=y +CONFIG_USER_NS=y +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_VFAT_FS=y +CONFIG_VIRTIO=y +CONFIG_VIRTIO_ANCHOR=y +# CONFIG_VIRTIO_BLK is not set +# CONFIG_VIRTIO_DEBUG is not set +# CONFIG_VIRTIO_NET is not set +CONFIG_VMAP_STACK=y +CONFIG_VMCORE_INFO=y +CONFIG_WATCHDOG_CORE=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_WERROR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_XARRAY_MULTI=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA32=y +CONFIG_ZSTD_COMMON=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/target/linux/starfive/patches-6.12/0001-riscv-dts-starfive-Add-full-support-except-VIN-and-V.patch b/target/linux/starfive/patches-6.12/0001-riscv-dts-starfive-Add-full-support-except-VIN-and-V.patch new file mode 100644 index 0000000000..78b6a10ea7 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0001-riscv-dts-starfive-Add-full-support-except-VIN-and-V.patch @@ -0,0 +1,176 @@ +From 5605ebdd7f7033da8f1bcb77cb180ef16235d5c8 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Tue, 11 Apr 2023 16:31:15 +0800 +Subject: [PATCH 01/55] riscv: dts: starfive: Add full support (except VIN and + VOUT) for JH7110 and VisionFive 2 board + +Merge all StarFive dts patches together except VIN and VOUT. + +Signed-off-by: Hal Feng +--- + .../boot/dts/starfive/jh7110-common.dtsi | 2 + + .../jh7110-starfive-visionfive-2.dtsi | 100 ++++++++++++++++++ + arch/riscv/boot/dts/starfive/jh7110.dtsi | 21 ++++ + 3 files changed, 123 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi +@@ -18,6 +18,8 @@ + i2c6 = &i2c6; + mmc0 = &mmc0; + mmc1 = &mmc1; ++ pcie0 = &pcie0; ++ pcie1 = &pcie1; + serial0 = &uart0; + }; + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -29,6 +29,24 @@ + }; + }; + ++&i2srx { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2srx_pins>; ++ status = "okay"; ++}; ++ ++&i2stx0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mclk_ext_pins>; ++ status = "okay"; ++}; ++ ++&i2stx1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2stx1_pins>; ++ status = "okay"; ++}; ++ + &mmc0 { + non-removable; + }; +@@ -40,3 +58,85 @@ + &pcie1 { + status = "okay"; + }; ++ ++&sysgpio { ++ i2srx_pins: i2srx-0 { ++ clk-sd-pins { ++ pinmux = , ++ , ++ , ++ , ++ ; ++ input-enable; ++ }; ++ }; ++ ++ i2stx1_pins: i2stx1-0 { ++ sd-pins { ++ pinmux = ; ++ bias-disable; ++ input-disable; ++ }; ++ }; ++ ++ mclk_ext_pins: mclk-ext-0 { ++ mclk-ext-pins { ++ pinmux = ; ++ input-enable; ++ }; ++ }; ++ ++ tdm_pins: tdm-0 { ++ tx-pins { ++ pinmux = ; ++ bias-pull-up; ++ drive-strength = <2>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pinmux = ; ++ input-enable; ++ }; ++ ++ sync-pins { ++ pinmux = ; ++ input-enable; ++ }; ++ ++ pcmclk-pins { ++ pinmux = ; ++ input-enable; ++ }; ++ }; ++}; ++ ++&tdm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tdm_pins>; ++ status = "okay"; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi +@@ -259,6 +259,7 @@ + clock-output-names = "dvp_clk"; + #clock-cells = <0>; + }; ++ + gmac0_rgmii_rxin: gmac0-rgmii-rxin-clock { + compatible = "fixed-clock"; + clock-output-names = "gmac0_rgmii_rxin"; +@@ -919,6 +920,26 @@ + #gpio-cells = <2>; + }; + ++ timer@13050000 { ++ compatible = "starfive,jh7110-timer"; ++ reg = <0x0 0x13050000 0x0 0x10000>; ++ interrupts = <69>, <70>, <71>, <72>; ++ clocks = <&syscrg JH7110_SYSCLK_TIMER_APB>, ++ <&syscrg JH7110_SYSCLK_TIMER0>, ++ <&syscrg JH7110_SYSCLK_TIMER1>, ++ <&syscrg JH7110_SYSCLK_TIMER2>, ++ <&syscrg JH7110_SYSCLK_TIMER3>; ++ clock-names = "apb", "ch0", "ch1", ++ "ch2", "ch3"; ++ resets = <&syscrg JH7110_SYSRST_TIMER_APB>, ++ <&syscrg JH7110_SYSRST_TIMER0>, ++ <&syscrg JH7110_SYSRST_TIMER1>, ++ <&syscrg JH7110_SYSRST_TIMER2>, ++ <&syscrg JH7110_SYSRST_TIMER3>; ++ reset-names = "apb", "ch0", "ch1", ++ "ch2", "ch3"; ++ }; ++ + watchdog@13070000 { + compatible = "starfive,jh7110-wdt"; + reg = <0x0 0x13070000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.12/0002-clocksource-Add-JH7110-timer-driver.patch b/target/linux/starfive/patches-6.12/0002-clocksource-Add-JH7110-timer-driver.patch new file mode 100644 index 0000000000..1b96bd306f --- /dev/null +++ b/target/linux/starfive/patches-6.12/0002-clocksource-Add-JH7110-timer-driver.patch @@ -0,0 +1,428 @@ +From 9e8b51600e4b0ea28c599303b87f6b1b8585eee4 Mon Sep 17 00:00:00 2001 +From: Xingyu Wu +Date: Thu, 19 Oct 2023 13:35:00 +0800 +Subject: [PATCH 02/55] clocksource: Add JH7110 timer driver + +Add timer driver for the StarFive JH7110 SoC. + +Signed-off-by: Xingyu Wu +--- + drivers/clocksource/Kconfig | 11 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/timer-jh7110.c | 380 +++++++++++++++++++++++++++++ + 3 files changed, 392 insertions(+) + create mode 100644 drivers/clocksource/timer-jh7110.c + +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -653,6 +653,17 @@ config RISCV_TIMER + is accessed via both the SBI and the rdcycle instruction. This is + required for all RISC-V systems. + ++config STARFIVE_JH7110_TIMER ++ bool "Timer for the STARFIVE JH7110 SoC" ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ select TIMER_OF ++ select CLKSRC_MMIO ++ default ARCH_STARFIVE ++ help ++ This enables the timer for StarFive JH7110 SoC. On RISC-V platform, ++ the system has started RISCV_TIMER, but you can also use this timer ++ which can provide four channels to do a lot more things on JH7110 SoC. ++ + config CLINT_TIMER + bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST + depends on GENERIC_SCHED_CLOCK && RISCV +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -81,6 +81,7 @@ obj-$(CONFIG_INGENIC_TIMER) += ingenic- + obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o + obj-$(CONFIG_X86_NUMACHIP) += numachip.o + obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o ++obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o + obj-$(CONFIG_CLINT_TIMER) += timer-clint.o + obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o + obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o +--- /dev/null ++++ b/drivers/clocksource/timer-jh7110.c +@@ -0,0 +1,380 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Starfive JH7110 Timer driver ++ * ++ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. ++ * ++ * Author: ++ * Xingyu Wu ++ * Samin Guo ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ ++#define JH7110_TIMER_CH_LEN 0x40 ++#define JH7110_TIMER_CH_BASE(x) ((x) * JH7110_TIMER_CH_LEN) ++#define JH7110_TIMER_CH_MAX 4 ++ ++#define JH7110_CLOCK_SOURCE_RATING 200 ++#define JH7110_VALID_BITS 32 ++#define JH7110_DELAY_US 0 ++#define JH7110_TIMEOUT_US 10000 ++#define JH7110_CLOCKEVENT_RATING 300 ++#define JH7110_TIMER_MAX_TICKS 0xffffffff ++#define JH7110_TIMER_MIN_TICKS 0xf ++#define JH7110_TIMER_RELOAD_VALUE 0 ++ ++#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt Status for channel0~4 */ ++#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, 1-single run */ ++#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter */ ++#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable register */ ++#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both reload counter */ ++#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */ ++#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear register */ ++#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer interrupt mask register */ ++ ++#define JH7110_TIMER_INT_CLR_ENA BIT(0) ++#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1) ++ ++struct jh7110_clkevt { ++ struct clock_event_device evt; ++ struct clocksource cs; ++ bool cs_is_valid; ++ struct clk *clk; ++ struct reset_control *rst; ++ u32 rate; ++ u32 reload_val; ++ void __iomem *base; ++ char name[sizeof("jh7110-timer.chX")]; ++}; ++ ++struct jh7110_timer_priv { ++ struct clk *pclk; ++ struct reset_control *prst; ++ struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX]; ++}; ++ ++/* 0:continuous-run mode, 1:single-run mode */ ++enum jh7110_timer_mode { ++ JH7110_TIMER_MODE_CONTIN, ++ JH7110_TIMER_MODE_SINGLE, ++}; ++ ++/* Interrupt Mask, 0:Unmask, 1:Mask */ ++enum jh7110_timer_int_mask { ++ JH7110_TIMER_INT_ENA, ++ JH7110_TIMER_INT_DIS, ++}; ++ ++enum jh7110_timer_enable { ++ JH7110_TIMER_DIS, ++ JH7110_TIMER_ENA, ++}; ++ ++static inline struct jh7110_clkevt *to_jh7110_clkevt(struct clock_event_device *evt) ++{ ++ return container_of(evt, struct jh7110_clkevt, evt); ++} ++ ++/* ++ * BIT(0): Read value represent channel int status. ++ * Write 1 to this bit to clear interrupt. Write 0 has no effects. ++ * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written. ++ */ ++static inline int jh7110_timer_int_clear(struct jh7110_clkevt *clkevt) ++{ ++ u32 value; ++ int ret; ++ ++ /* Waiting interrupt can be cleared */ ++ ret = readl_poll_timeout_atomic(clkevt->base + JH7110_TIMER_INT_CLR, value, ++ !(value & JH7110_TIMER_INT_CLR_AVA_MASK), ++ JH7110_DELAY_US, JH7110_TIMEOUT_US); ++ if (!ret) ++ writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + JH7110_TIMER_INT_CLR); ++ ++ return ret; ++} ++ ++static int jh7110_timer_start(struct jh7110_clkevt *clkevt) ++{ ++ int ret; ++ ++ /* Disable and clear interrupt first */ ++ writel(JH7110_TIMER_INT_DIS, clkevt->base + JH7110_TIMER_INT_MASK); ++ ret = jh7110_timer_int_clear(clkevt); ++ if (ret) ++ return ret; ++ ++ writel(JH7110_TIMER_INT_ENA, clkevt->base + JH7110_TIMER_INT_MASK); ++ writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE); ++ ++ return 0; ++} ++ ++static int jh7110_timer_shutdown(struct clock_event_device *evt) ++{ ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ ++ writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); ++ return jh7110_timer_int_clear(clkevt); ++} ++ ++static void jh7110_timer_suspend(struct clock_event_device *evt) ++{ ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ ++ clkevt->reload_val = readl(clkevt->base + JH7110_TIMER_LOAD); ++ jh7110_timer_shutdown(evt); ++} ++ ++static void jh7110_timer_resume(struct clock_event_device *evt) ++{ ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ ++ writel(clkevt->reload_val, clkevt->base + JH7110_TIMER_LOAD); ++ writel(JH7110_TIMER_RELOAD_VALUE, clkevt->base + JH7110_TIMER_RELOAD); ++ jh7110_timer_start(clkevt); ++} ++ ++static int jh7110_timer_tick_resume(struct clock_event_device *evt) ++{ ++ jh7110_timer_resume(evt); ++ ++ return 0; ++} ++ ++/* IRQ handler for the timer */ ++static irqreturn_t jh7110_timer_interrupt(int irq, void *priv) ++{ ++ struct clock_event_device *evt = (struct clock_event_device *)priv; ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ ++ if (jh7110_timer_int_clear(clkevt)) ++ return IRQ_NONE; ++ ++ if (evt->event_handler) ++ evt->event_handler(evt); ++ ++ return IRQ_HANDLED; ++} ++ ++static int jh7110_timer_set_periodic(struct clock_event_device *evt) ++{ ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ u32 periodic = DIV_ROUND_CLOSEST(clkevt->rate, HZ); ++ ++ writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL); ++ writel(periodic, clkevt->base + JH7110_TIMER_LOAD); ++ ++ return jh7110_timer_start(clkevt); ++} ++ ++static int jh7110_timer_set_oneshot(struct clock_event_device *evt) ++{ ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ ++ writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL); ++ writel(JH7110_TIMER_MAX_TICKS, clkevt->base + JH7110_TIMER_LOAD); ++ ++ return jh7110_timer_start(clkevt); ++} ++ ++static int jh7110_timer_set_next_event(unsigned long next, ++ struct clock_event_device *evt) ++{ ++ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt); ++ ++ writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL); ++ writel(next, clkevt->base + JH7110_TIMER_LOAD); ++ ++ return jh7110_timer_start(clkevt); ++} ++ ++static void jh7110_set_clockevent(struct clock_event_device *evt) ++{ ++ evt->features = CLOCK_EVT_FEAT_PERIODIC | ++ CLOCK_EVT_FEAT_ONESHOT | ++ CLOCK_EVT_FEAT_DYNIRQ; ++ evt->set_state_shutdown = jh7110_timer_shutdown; ++ evt->set_state_periodic = jh7110_timer_set_periodic; ++ evt->set_state_oneshot = jh7110_timer_set_oneshot; ++ evt->set_state_oneshot_stopped = jh7110_timer_shutdown; ++ evt->tick_resume = jh7110_timer_tick_resume; ++ evt->set_next_event = jh7110_timer_set_next_event; ++ evt->suspend = jh7110_timer_suspend; ++ evt->resume = jh7110_timer_resume; ++ evt->rating = JH7110_CLOCKEVENT_RATING; ++} ++ ++static u64 jh7110_timer_clocksource_read(struct clocksource *cs) ++{ ++ struct jh7110_clkevt *clkevt = container_of(cs, struct jh7110_clkevt, cs); ++ ++ return (u64)readl(clkevt->base + JH7110_TIMER_VALUE); ++} ++ ++static int jh7110_clocksource_init(struct jh7110_clkevt *clkevt) ++{ ++ int ret; ++ ++ clkevt->cs.name = clkevt->name; ++ clkevt->cs.rating = JH7110_CLOCK_SOURCE_RATING; ++ clkevt->cs.read = jh7110_timer_clocksource_read; ++ clkevt->cs.mask = CLOCKSOURCE_MASK(JH7110_VALID_BITS); ++ clkevt->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; ++ ++ ret = clocksource_register_hz(&clkevt->cs, clkevt->rate); ++ if (ret) ++ return ret; ++ ++ clkevt->cs_is_valid = true; /* clocksource register done */ ++ writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL); ++ writel(JH7110_TIMER_MAX_TICKS, clkevt->base + JH7110_TIMER_LOAD); ++ ++ return jh7110_timer_start(clkevt); ++} ++ ++static void jh7110_clockevents_register(struct jh7110_clkevt *clkevt) ++{ ++ clkevt->rate = clk_get_rate(clkevt->clk); ++ ++ jh7110_set_clockevent(&clkevt->evt); ++ clkevt->evt.name = clkevt->name; ++ clkevt->evt.cpumask = cpu_possible_mask; ++ ++ clockevents_config_and_register(&clkevt->evt, clkevt->rate, ++ JH7110_TIMER_MIN_TICKS, JH7110_TIMER_MAX_TICKS); ++} ++ ++static void jh7110_timer_release(void *data) ++{ ++ struct jh7110_timer_priv *priv = data; ++ int i; ++ ++ for (i = 0; i < JH7110_TIMER_CH_MAX; i++) { ++ /* Disable each channel of timer */ ++ if (priv->clkevt[i].base) ++ writel(JH7110_TIMER_DIS, priv->clkevt[i].base + JH7110_TIMER_ENABLE); ++ ++ /* Avoid no initialization in the loop of the probe */ ++ if (!IS_ERR_OR_NULL(priv->clkevt[i].rst)) ++ reset_control_assert(priv->clkevt[i].rst); ++ ++ if (priv->clkevt[i].cs_is_valid) ++ clocksource_unregister(&priv->clkevt[i].cs); ++ } ++ ++ reset_control_assert(priv->prst); ++} ++ ++static int jh7110_timer_probe(struct platform_device *pdev) ++{ ++ struct jh7110_timer_priv *priv; ++ struct jh7110_clkevt *clkevt; ++ char name[sizeof("chX")]; ++ int ch; ++ int ret; ++ void __iomem *base; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(base), ++ "failed to map registers\n"); ++ ++ priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); ++ if (IS_ERR(priv->prst)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst), ++ "failed to get apb reset\n"); ++ ++ priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb"); ++ if (IS_ERR(priv->pclk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), ++ "failed to get & enable apb clock\n"); ++ ++ ret = reset_control_deassert(priv->prst); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "failed to deassert apb reset\n"); ++ ++ ret = devm_add_action_or_reset(&pdev->dev, jh7110_timer_release, priv); ++ if (ret) ++ return ret; ++ ++ for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) { ++ clkevt = &priv->clkevt[ch]; ++ snprintf(name, sizeof(name), "ch%d", ch); ++ ++ clkevt->base = base + JH7110_TIMER_CH_BASE(ch); ++ /* Ensure timer is disabled */ ++ writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); ++ ++ clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, name); ++ if (IS_ERR(clkevt->rst)) ++ return PTR_ERR(clkevt->rst); ++ ++ clkevt->clk = devm_clk_get_enabled(&pdev->dev, name); ++ if (IS_ERR(clkevt->clk)) ++ return PTR_ERR(clkevt->clk); ++ ++ ret = reset_control_deassert(clkevt->rst); ++ if (ret) ++ return ret; ++ ++ clkevt->evt.irq = platform_get_irq(pdev, ch); ++ if (clkevt->evt.irq < 0) ++ return clkevt->evt.irq; ++ ++ snprintf(clkevt->name, sizeof(clkevt->name), "jh7110-timer.ch%d", ch); ++ jh7110_clockevents_register(clkevt); ++ ++ ret = devm_request_irq(&pdev->dev, clkevt->evt.irq, jh7110_timer_interrupt, ++ IRQF_TIMER | IRQF_IRQPOLL, ++ clkevt->name, &clkevt->evt); ++ if (ret) ++ return ret; ++ ++ ret = jh7110_clocksource_init(clkevt); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id jh7110_timer_match[] = { ++ { .compatible = "starfive,jh7110-timer", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, jh7110_timer_match); ++ ++static struct platform_driver jh7110_timer_driver = { ++ .probe = jh7110_timer_probe, ++ .driver = { ++ .name = "jh7110-timer", ++ .of_match_table = jh7110_timer_match, ++ }, ++}; ++module_platform_driver(jh7110_timer_driver); ++ ++MODULE_AUTHOR("Xingyu Wu "); ++MODULE_DESCRIPTION("StarFive JH7110 timer driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.12/0003-pwm-opencores-Add-PWM-driver-support.patch b/target/linux/starfive/patches-6.12/0003-pwm-opencores-Add-PWM-driver-support.patch new file mode 100644 index 0000000000..0cb700409e --- /dev/null +++ b/target/linux/starfive/patches-6.12/0003-pwm-opencores-Add-PWM-driver-support.patch @@ -0,0 +1,277 @@ +From 4afaa19bcf6eac558a38468417520b65801e0cfd Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Fri, 22 Dec 2023 17:45:46 +0800 +Subject: [PATCH 03/55] pwm: opencores: Add PWM driver support + +Add driver for OpenCores PWM Controller. And add compatibility code +which based on StarFive SoC. + +Co-developed-by: Hal Feng +Signed-off-by: Hal Feng +Signed-off-by: William Qiu +--- + drivers/pwm/Kconfig | 12 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-ocores.c | 230 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 243 insertions(+) + create mode 100644 drivers/pwm/pwm-ocores.c + +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -471,6 +471,18 @@ config PWM_NTXEC + controller found in certain e-book readers designed by the original + design manufacturer Netronix. + ++config PWM_OCORES ++ tristate "OpenCores PWM support" ++ depends on HAS_IOMEM && OF ++ depends on COMMON_CLK ++ depends on ARCH_STARFIVE || COMPILE_TEST ++ help ++ If you say yes to this option, support will be included for the ++ OpenCores PWM. For details see https://opencores.org/projects/ptc. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-ocores. ++ + config PWM_OMAP_DMTIMER + tristate "OMAP Dual-Mode Timer PWM support" + depends on OF +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -42,6 +42,7 @@ obj-$(CONFIG_PWM_MICROCHIP_CORE) += pwm- + obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o + obj-$(CONFIG_PWM_MXS) += pwm-mxs.o + obj-$(CONFIG_PWM_NTXEC) += pwm-ntxec.o ++obj-$(CONFIG_PWM_OCORES) += pwm-ocores.o + obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o + obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o + obj-$(CONFIG_PWM_PXA) += pwm-pxa.o +--- /dev/null ++++ b/drivers/pwm/pwm-ocores.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * OpenCores PWM Driver ++ * ++ * https://opencores.org/projects/ptc ++ * ++ * Copyright (C) 2018-2023 StarFive Technology Co., Ltd. ++ * ++ * Limitations: ++ * - The hardware only do inverted polarity. ++ * - The hardware minimum period / duty_cycle is (1 / pwm_apb clock frequency) ns. ++ * - The hardware maximum period / duty_cycle is (U32_MAX / pwm_apb clock frequency) ns. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* OCPWM_CTRL register bits*/ ++#define REG_OCPWM_EN BIT(0) ++#define REG_OCPWM_ECLK BIT(1) ++#define REG_OCPWM_NEC BIT(2) ++#define REG_OCPWM_OE BIT(3) ++#define REG_OCPWM_SIGNLE BIT(4) ++#define REG_OCPWM_INTE BIT(5) ++#define REG_OCPWM_INT BIT(6) ++#define REG_OCPWM_CNTRRST BIT(7) ++#define REG_OCPWM_CAPTE BIT(8) ++ ++struct ocores_pwm_device { ++ struct clk *clk; ++ struct reset_control *rst; ++ const struct ocores_pwm_data *data; ++ void __iomem *regs; ++ u32 clk_rate; /* PWM APB clock frequency */ ++}; ++ ++struct ocores_pwm_data { ++ void __iomem *(*get_ch_base)(void __iomem *base, unsigned int channel); ++}; ++ ++static inline u32 ocores_readl(struct ocores_pwm_device *ddata, ++ unsigned int channel, ++ unsigned int offset) ++{ ++ void __iomem *base = ddata->data->get_ch_base ? ++ ddata->data->get_ch_base(ddata->regs, channel) : ddata->regs; ++ ++ return readl(base + offset); ++} ++ ++static inline void ocores_writel(struct ocores_pwm_device *ddata, ++ unsigned int channel, ++ unsigned int offset, u32 val) ++{ ++ void __iomem *base = ddata->data->get_ch_base ? ++ ddata->data->get_ch_base(ddata->regs, channel) : ddata->regs; ++ ++ writel(val, base + offset); ++} ++ ++static inline struct ocores_pwm_device *chip_to_ocores(struct pwm_chip *chip) ++{ ++ return pwmchip_get_drvdata(chip); ++} ++ ++static void __iomem *starfive_jh71x0_get_ch_base(void __iomem *base, ++ unsigned int channel) ++{ ++ unsigned int offset = (channel > 3 ? 1 << 15 : 0) + (channel & 3) * 0x10; ++ ++ return base + offset; ++} ++ ++static int ocores_pwm_get_state(struct pwm_chip *chip, ++ struct pwm_device *pwm, ++ struct pwm_state *state) ++{ ++ struct ocores_pwm_device *ddata = chip_to_ocores(chip); ++ u32 period_data, duty_data, ctrl_data; ++ ++ period_data = ocores_readl(ddata, pwm->hwpwm, 0x8); ++ duty_data = ocores_readl(ddata, pwm->hwpwm, 0x4); ++ ctrl_data = ocores_readl(ddata, pwm->hwpwm, 0xC); ++ ++ state->period = DIV_ROUND_UP_ULL((u64)period_data * NSEC_PER_SEC, ddata->clk_rate); ++ state->duty_cycle = DIV_ROUND_UP_ULL((u64)duty_data * NSEC_PER_SEC, ddata->clk_rate); ++ state->polarity = PWM_POLARITY_INVERSED; ++ state->enabled = (ctrl_data & REG_OCPWM_EN) ? true : false; ++ ++ return 0; ++} ++ ++static int ocores_pwm_apply(struct pwm_chip *chip, ++ struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct ocores_pwm_device *ddata = chip_to_ocores(chip); ++ u32 ctrl_data = 0; ++ u64 period_data, duty_data; ++ ++ if (state->polarity != PWM_POLARITY_INVERSED) ++ return -EINVAL; ++ ++ ctrl_data = ocores_readl(ddata, pwm->hwpwm, 0xC); ++ ocores_writel(ddata, pwm->hwpwm, 0xC, 0); ++ ++ period_data = DIV_ROUND_DOWN_ULL(state->period * ddata->clk_rate, NSEC_PER_SEC); ++ if (period_data <= U32_MAX) ++ ocores_writel(ddata, pwm->hwpwm, 0x8, (u32)period_data); ++ else ++ return -EINVAL; ++ ++ duty_data = DIV_ROUND_DOWN_ULL(state->duty_cycle * ddata->clk_rate, NSEC_PER_SEC); ++ if (duty_data <= U32_MAX) ++ ocores_writel(ddata, pwm->hwpwm, 0x4, (u32)duty_data); ++ else ++ return -EINVAL; ++ ++ ocores_writel(ddata, pwm->hwpwm, 0xC, 0); ++ ++ if (state->enabled) { ++ ctrl_data = ocores_readl(ddata, pwm->hwpwm, 0xC); ++ ocores_writel(ddata, pwm->hwpwm, 0xC, ctrl_data | REG_OCPWM_EN | REG_OCPWM_OE); ++ } ++ ++ return 0; ++} ++ ++static const struct pwm_ops ocores_pwm_ops = { ++ .get_state = ocores_pwm_get_state, ++ .apply = ocores_pwm_apply, ++}; ++ ++static const struct ocores_pwm_data jh7100_pwm_data = { ++ .get_ch_base = starfive_jh71x0_get_ch_base, ++}; ++ ++static const struct ocores_pwm_data jh7110_pwm_data = { ++ .get_ch_base = starfive_jh71x0_get_ch_base, ++}; ++ ++static const struct of_device_id ocores_pwm_of_match[] = { ++ { .compatible = "opencores,pwm-v1" }, ++ { .compatible = "starfive,jh7100-pwm", .data = &jh7100_pwm_data}, ++ { .compatible = "starfive,jh7110-pwm", .data = &jh7110_pwm_data}, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ocores_pwm_of_match); ++ ++static void ocores_reset_control_assert(void *data) ++{ ++ reset_control_assert(data); ++} ++ ++static int ocores_pwm_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ocores_pwm_device *ddata; ++ struct pwm_chip *chip; ++ int ret; ++ ++ chip = devm_pwmchip_alloc(dev, 8, sizeof(*ddata)); ++ if (IS_ERR(chip)) ++ return PTR_ERR(chip); ++ ++ chip->ops = &ocores_pwm_ops; ++ ++ ddata = chip_to_ocores(chip); ++ ddata->data = of_device_get_match_data(dev); ++ ++ ddata->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(ddata->regs)) ++ return dev_err_probe(dev, PTR_ERR(ddata->regs), ++ "Unable to map IO resources\n"); ++ ++ ddata->clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(ddata->clk)) ++ return dev_err_probe(dev, PTR_ERR(ddata->clk), ++ "Unable to get pwm's clock\n"); ++ ++ ddata->rst = devm_reset_control_get_optional_exclusive(dev, NULL); ++ if (IS_ERR(ddata->rst)) ++ return dev_err_probe(dev, PTR_ERR(ddata->rst), ++ "Unable to get pwm's reset\n"); ++ ++ reset_control_deassert(ddata->rst); ++ ++ ret = devm_add_action_or_reset(dev, ocores_reset_control_assert, ddata->rst); ++ if (ret) ++ return ret; ++ ++ ddata->clk_rate = clk_get_rate(ddata->clk); ++ if (ddata->clk_rate <= 0) ++ return dev_err_probe(dev, ddata->clk_rate, ++ "Unable to get clock's rate\n"); ++ ++ ret = devm_pwmchip_add(dev, chip); ++ if (ret < 0) ++ return dev_err_probe(dev, ret, "Could not register PWM chip\n"); ++ ++ platform_set_drvdata(pdev, ddata); ++ ++ return ret; ++} ++ ++static struct platform_driver ocores_pwm_driver = { ++ .probe = ocores_pwm_probe, ++ .driver = { ++ .name = "ocores-pwm", ++ .of_match_table = ocores_pwm_of_match, ++ }, ++}; ++module_platform_driver(ocores_pwm_driver); ++ ++MODULE_AUTHOR("Jieqin Chen"); ++MODULE_AUTHOR("Hal Feng "); ++MODULE_DESCRIPTION("OpenCores PWM PTC driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.12/0004-spi-spl022-Get-and-deassert-reset-in-probe.patch b/target/linux/starfive/patches-6.12/0004-spi-spl022-Get-and-deassert-reset-in-probe.patch new file mode 100644 index 0000000000..68b181065e --- /dev/null +++ b/target/linux/starfive/patches-6.12/0004-spi-spl022-Get-and-deassert-reset-in-probe.patch @@ -0,0 +1,60 @@ +From c0d35bd6e76ccabfbbbddc41a0d77ecdfbb4ee31 Mon Sep 17 00:00:00 2001 +From: "ziv.xu" +Date: Sun, 4 Feb 2024 10:35:24 +0800 +Subject: [PATCH 04/55] spi: spl022: Get and deassert reset in probe() + +This fix spi1~6 communication time out. + +Signed-off-by: ziv.xu +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + /* + * This macro is used to define some register default values. +@@ -363,6 +364,7 @@ struct pl022 { + resource_size_t phybase; + void __iomem *virtbase; + struct clk *clk; ++ struct reset_control *rst; + struct spi_controller *host; + struct pl022_ssp_controller *host_info; + struct spi_transfer *cur_transfer; +@@ -1930,6 +1932,19 @@ static int pl022_probe(struct amba_devic + goto err_no_clk; + } + ++ pl022->rst = devm_reset_control_get(&adev->dev, NULL); ++ if (IS_ERR(pl022->rst)) { ++ status = PTR_ERR(pl022->rst); ++ dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n"); ++ goto err_no_rst; ++ } ++ ++ status = reset_control_deassert(pl022->rst); ++ if (status) { ++ dev_err(&adev->dev, "could not deassert SSP/SPI bus reset\n"); ++ goto err_no_rst_de; ++ } ++ + /* Disable SSP */ + writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), + SSP_CR1(pl022->virtbase)); +@@ -1985,6 +2000,8 @@ static int pl022_probe(struct amba_devic + if (platform_info->enable_dma) + pl022_dma_remove(pl022); + err_no_irq: ++ err_no_rst_de: ++ err_no_rst: + err_no_clk: + err_no_ioremap: + amba_release_regions(adev); diff --git a/target/linux/starfive/patches-6.12/0005-i2c-designware-Delete-SMBus-functionalities.patch b/target/linux/starfive/patches-6.12/0005-i2c-designware-Delete-SMBus-functionalities.patch new file mode 100644 index 0000000000..de4a013196 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0005-i2c-designware-Delete-SMBus-functionalities.patch @@ -0,0 +1,33 @@ +From a37f1f4370af69644c512e5e296a10357338c310 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Fri, 12 May 2023 17:33:20 +0800 +Subject: [PATCH 05/55] i2c: designware: Delete SMBus functionalities + +The driver didn't implement the smbus interface, +so replace the SMBus functionalities with +I2C_FUNC_SMBUS_EMUL. + +Signed-off-by: Hal Feng +--- + drivers/i2c/busses/i2c-designware-core.h | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -17,12 +17,10 @@ + #include + #include + +-#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ +- I2C_FUNC_SMBUS_BYTE | \ +- I2C_FUNC_SMBUS_BYTE_DATA | \ +- I2C_FUNC_SMBUS_WORD_DATA | \ +- I2C_FUNC_SMBUS_BLOCK_DATA | \ +- I2C_FUNC_SMBUS_I2C_BLOCK) ++#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL \ ++ & ~I2C_FUNC_SMBUS_QUICK \ ++ & ~I2C_FUNC_SMBUS_PROC_CALL \ ++ & ~I2C_FUNC_SMBUS_PEC)) + + #define DW_IC_CON_MASTER BIT(0) + #define DW_IC_CON_SPEED_STD (1 << 1) diff --git a/target/linux/starfive/patches-6.12/0006-drivers-mtd-gigadevice-add-gd25lq256d-32M-flash-supp.patch b/target/linux/starfive/patches-6.12/0006-drivers-mtd-gigadevice-add-gd25lq256d-32M-flash-supp.patch new file mode 100644 index 0000000000..4ef6b78210 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0006-drivers-mtd-gigadevice-add-gd25lq256d-32M-flash-supp.patch @@ -0,0 +1,29 @@ +From 8850887a7b71b55250be2a15802963d6b32ea8ab Mon Sep 17 00:00:00 2001 +From: Ziv Xu +Date: Fri, 19 Jan 2024 15:22:55 +0800 +Subject: [PATCH 06/55] drivers: mtd: gigadevice: add gd25lq256d 32M flash + support + +add gd25lq256d 32M flash support + +Signed-off-by: Ziv Xu +Signed-off-by: Hal Feng +--- + drivers/mtd/spi-nor/gigadevice.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/mtd/spi-nor/gigadevice.c ++++ b/drivers/mtd/spi-nor/gigadevice.c +@@ -95,6 +95,12 @@ static const struct flash_info gigadevic + .size = SZ_16M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ }, { ++ .id = SNOR_ID(0xc8, 0x60, 0x19), ++ .name = "gd25lq256d", ++ .size = SZ_32M, ++ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_QUAD_PP, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, + }; + diff --git a/target/linux/starfive/patches-6.12/0007-driver-mailbox-Add-mailbox-driver.patch b/target/linux/starfive/patches-6.12/0007-driver-mailbox-Add-mailbox-driver.patch new file mode 100644 index 0000000000..e8a81d12bc --- /dev/null +++ b/target/linux/starfive/patches-6.12/0007-driver-mailbox-Add-mailbox-driver.patch @@ -0,0 +1,804 @@ +From f7db05ea5fffebed6db6693333a6877aa707b16d Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Thu, 8 Jun 2023 00:07:15 -0700 +Subject: [PATCH 07/55] driver: mailbox: Add mailbox driver + +Add mailbox driver. + +Signed-off-by: shanlong.li +Signed-off-by: Hal Feng +--- + drivers/mailbox/Kconfig | 13 + + drivers/mailbox/Makefile | 4 + + drivers/mailbox/starfive_mailbox-test.c | 405 ++++++++++++++++++++++++ + drivers/mailbox/starfive_mailbox.c | 345 ++++++++++++++++++++ + 4 files changed, 767 insertions(+) + create mode 100644 drivers/mailbox/starfive_mailbox-test.c + create mode 100644 drivers/mailbox/starfive_mailbox.c + +--- a/drivers/mailbox/Kconfig ++++ b/drivers/mailbox/Kconfig +@@ -295,4 +295,17 @@ config QCOM_IPCC + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + ++config STARFIVE_MBOX ++ tristate "Platform Starfive Mailbox" ++ depends on OF ++ help ++ Say Y here if you want to build a platform specific variant RISCV ++ controller driver. ++ ++config STARFIVE_MBOX_TEST ++ tristate "Starfive Mailbox Test Client" ++ depends on OF ++ depends on HAS_IOMEM ++ help ++ Test client to help with testing new Controller driver implementations. + endif +--- a/drivers/mailbox/Makefile ++++ b/drivers/mailbox/Makefile +@@ -64,3 +64,7 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox + obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o + + obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o ++ ++obj-$(CONFIG_STARFIVE_MBOX) += starfive_mailbox.o ++ccflags-$(CONFIG_STARFIVE_MBOX) := -Wno-error=missing-prototypes ++obj-$(CONFIG_STARFIVE_MBOX_TEST) += starfive_mailbox-test.o +--- /dev/null ++++ b/drivers/mailbox/starfive_mailbox-test.c +@@ -0,0 +1,405 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (C) 2015 ST Microelectronics ++ * ++ * Author: Lee Jones ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define MBOX_MAX_SIG_LEN 8 ++#define MBOX_MAX_MSG_LEN 16 ++#define MBOX_BYTES_PER_LINE 16 ++#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2) ++#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) ++ ++static bool mbox_data_ready; ++ ++struct mbox_test_device { ++ struct device *dev; ++ void __iomem *tx_mmio; ++ void __iomem *rx_mmio; ++ struct mbox_chan *tx_channel; ++ struct mbox_chan *rx_channel; ++ char *rx_buffer; ++ char *signal; ++ char *message; ++ spinlock_t lock; ++ wait_queue_head_t waitq; ++ struct fasync_struct *async_queue; ++ struct dentry *root_debugfs_dir; ++}; ++ ++static ssize_t mbox_test_signal_write(struct file *filp, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_test_device *tdev = filp->private_data; ++ ++ if (!tdev->tx_channel) { ++ dev_err(tdev->dev, "Channel cannot do Tx\n"); ++ return -EINVAL; ++ } ++ ++ if (count > MBOX_MAX_SIG_LEN) { ++ dev_err(tdev->dev, ++ "Signal length %zd greater than max allowed %d\n", ++ count, MBOX_MAX_SIG_LEN); ++ return -EINVAL; ++ } ++ ++ /* Only allocate memory if we need to */ ++ if (!tdev->signal) { ++ tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL); ++ if (!tdev->signal) ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(tdev->signal, userbuf, count)) { ++ kfree(tdev->signal); ++ tdev->signal = NULL; ++ return -EFAULT; ++ } ++ ++ return count; ++} ++ ++static const struct file_operations mbox_test_signal_ops = { ++ .write = mbox_test_signal_write, ++ .open = simple_open, ++ .llseek = generic_file_llseek, ++}; ++ ++static int mbox_test_message_fasync(int fd, struct file *filp, int on) ++{ ++ struct mbox_test_device *tdev = filp->private_data; ++ ++ return fasync_helper(fd, filp, on, &tdev->async_queue); ++} ++ ++static ssize_t mbox_test_message_write(struct file *filp, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_test_device *tdev = filp->private_data; ++ void *data; ++ int ret; ++ ++ if (!tdev->tx_channel) { ++ dev_err(tdev->dev, "Channel cannot do Tx\n"); ++ return -EINVAL; ++ } ++ ++ if (count > MBOX_MAX_MSG_LEN) { ++ dev_err(tdev->dev, ++ "Message length %zd greater than max allowed %d\n", ++ count, MBOX_MAX_MSG_LEN); ++ return -EINVAL; ++ } ++ ++ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->message) ++ return -ENOMEM; ++ ++ ret = copy_from_user(tdev->message, userbuf, count); ++ if (ret) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (tdev->tx_mmio && tdev->signal) { ++ print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS, ++ tdev->signal, MBOX_MAX_SIG_LEN); ++ ++ data = tdev->signal; ++ } else ++ data = tdev->message; ++ ++ print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS, ++ tdev->message, MBOX_MAX_MSG_LEN); ++ ++ ret = mbox_send_message(tdev->tx_channel, data); ++ mbox_chan_txdone(tdev->tx_channel, ret); ++ if (ret < 0) ++ dev_err(tdev->dev, "Failed to send message via mailbox\n"); ++ ++out: ++ kfree(tdev->signal); ++ kfree(tdev->message); ++ tdev->signal = NULL; ++ ++ return ret < 0 ? ret : count; ++} ++ ++static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) ++{ ++ bool data_ready; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tdev->lock, flags); ++ data_ready = mbox_data_ready; ++ spin_unlock_irqrestore(&tdev->lock, flags); ++ ++ return data_ready; ++} ++ ++static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_test_device *tdev = filp->private_data; ++ unsigned long flags; ++ char *touser, *ptr; ++ int ret; ++ ++ touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL); ++ if (!touser) ++ return -ENOMEM; ++ ++ if (!tdev->rx_channel) { ++ ret = snprintf(touser, 20, "\n"); ++ ret = simple_read_from_buffer(userbuf, count, ppos, ++ touser, ret); ++ goto kfree_err; ++ } ++ ++ do { ++ if (mbox_test_message_data_ready(tdev)) ++ break; ++ ++ if (filp->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ goto waitq_err; ++ } ++ ++ if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ goto waitq_err; ++ } ++ schedule(); ++ ++ } while (1); ++ ++ spin_lock_irqsave(&tdev->lock, flags); ++ ++ ptr = tdev->rx_buffer; ++ ++ mbox_data_ready = false; ++ ++ spin_unlock_irqrestore(&tdev->lock, flags); ++ if (copy_to_user((void __user *)userbuf, ptr, 4)) ++ ret = -EFAULT; ++ ++waitq_err: ++ __set_current_state(TASK_RUNNING); ++kfree_err: ++ kfree(touser); ++ return ret; ++} ++ ++static __poll_t ++mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait) ++{ ++ struct mbox_test_device *tdev = filp->private_data; ++ ++ poll_wait(filp, &tdev->waitq, wait); ++ ++ if (mbox_test_message_data_ready(tdev)) ++ return EPOLLIN | EPOLLRDNORM; ++ return 0; ++} ++ ++static const struct file_operations mbox_test_message_ops = { ++ .write = mbox_test_message_write, ++ .read = mbox_test_message_read, ++ .fasync = mbox_test_message_fasync, ++ .poll = mbox_test_message_poll, ++ .open = simple_open, ++ .llseek = generic_file_llseek, ++}; ++ ++static int mbox_test_add_debugfs(struct platform_device *pdev, ++ struct mbox_test_device *tdev) ++{ ++ if (!debugfs_initialized()) ++ return 0; ++ ++ tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL); ++ if (!tdev->root_debugfs_dir) { ++ dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n"); ++ return -EINVAL; ++ } ++ ++ debugfs_create_file("message", 0600, tdev->root_debugfs_dir, ++ tdev, &mbox_test_message_ops); ++ ++ debugfs_create_file("signal", 0200, tdev->root_debugfs_dir, ++ tdev, &mbox_test_signal_ops); ++ ++ return 0; ++} ++ ++static void mbox_test_receive_message(struct mbox_client *client, void *message) ++{ ++ struct mbox_test_device *tdev = dev_get_drvdata(client->dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tdev->lock, flags); ++ if (tdev->rx_mmio) { ++ memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN); ++ print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS, ++ tdev->rx_buffer, MBOX_MAX_MSG_LEN); ++ } else if (message) { ++ print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS, ++ message, MBOX_MAX_MSG_LEN); ++ memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); ++ } ++ mbox_data_ready = true; ++ spin_unlock_irqrestore(&tdev->lock, flags); ++} ++ ++static void mbox_test_prepare_message(struct mbox_client *client, void *message) ++{ ++ struct mbox_test_device *tdev = dev_get_drvdata(client->dev); ++ ++ if (tdev->tx_mmio) { ++ if (tdev->signal) ++ memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN); ++ else ++ memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN); ++ } ++} ++ ++static struct mbox_chan * ++mbox_test_request_channel(struct platform_device *pdev, const char *name) ++{ ++ struct mbox_client *client; ++ struct mbox_chan *channel; ++ ++ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); ++ if (!client) ++ return ERR_PTR(-ENOMEM); ++ ++ client->dev = &pdev->dev; ++ client->rx_callback = mbox_test_receive_message; ++ client->tx_prepare = mbox_test_prepare_message; ++ client->tx_block = false; ++ client->knows_txdone = false; ++ client->tx_tout = 500; ++ ++ channel = mbox_request_channel_byname(client, name); ++ if (IS_ERR(channel)) { ++ dev_warn(&pdev->dev, "Failed to request %s channel\n", name); ++ return NULL; ++ } ++ ++ return channel; ++} ++ ++static int mbox_test_probe(struct platform_device *pdev) ++{ ++ struct mbox_test_device *tdev; ++ struct resource *res; ++ resource_size_t size; ++ int ret; ++ ++ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); ++ if (!tdev) ++ return -ENOMEM; ++ ++ /* It's okay for MMIO to be NULL */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); ++ if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { ++ /* if reserved area in SRAM, try just ioremap */ ++ size = resource_size(res); ++ tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); ++ } else if (IS_ERR(tdev->tx_mmio)) { ++ tdev->tx_mmio = NULL; ++ } ++ ++ /* If specified, second reg entry is Rx MMIO */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res); ++ if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { ++ size = resource_size(res); ++ tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); ++ } else if (IS_ERR(tdev->rx_mmio)) { ++ tdev->rx_mmio = tdev->tx_mmio; ++ } ++ ++ tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); ++ tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); ++ ++ if (!tdev->tx_channel && !tdev->rx_channel) ++ return -EPROBE_DEFER; ++ ++ /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ ++ if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) ++ tdev->rx_channel = tdev->tx_channel; ++ ++ tdev->dev = &pdev->dev; ++ platform_set_drvdata(pdev, tdev); ++ ++ spin_lock_init(&tdev->lock); ++ ++ if (tdev->rx_channel) { ++ tdev->rx_buffer = devm_kzalloc(&pdev->dev, ++ MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->rx_buffer) ++ return -ENOMEM; ++ } ++ ++ ret = mbox_test_add_debugfs(pdev, tdev); ++ if (ret) ++ return ret; ++ ++ dev_info(&pdev->dev, "Successfully registered\n"); ++ ++ return 0; ++} ++ ++static void mbox_test_remove(struct platform_device *pdev) ++{ ++ struct mbox_test_device *tdev = platform_get_drvdata(pdev); ++ ++ debugfs_remove_recursive(tdev->root_debugfs_dir); ++ ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++} ++ ++static const struct of_device_id mbox_test_match[] = { ++ { .compatible = "starfive,mailbox-test" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mbox_test_match); ++ ++static struct platform_driver mbox_test_driver = { ++ .driver = { ++ .name = "mailbox_test", ++ .of_match_table = mbox_test_match, ++ }, ++ .probe = mbox_test_probe, ++ .remove = mbox_test_remove, ++}; ++module_platform_driver(mbox_test_driver); ++ ++MODULE_DESCRIPTION("Generic Mailbox Testing Facility"); ++MODULE_AUTHOR("Lee Jones ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mailbox.h" ++ ++#define MBOX_CHAN_MAX 4 ++ ++#define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x10)) ++#define MBOX_IRQ_REG 0x00 ++#define MBOX_SET_REG 0x04 ++#define MBOX_CLR_REG 0x08 ++#define MBOX_CMD_REG 0x0c ++#define MBC_PEND_SMRY 0x100 ++ ++typedef enum { ++ MAILBOX_CORE_U7 = 0, ++ MAILBOX_CORE_HIFI4, ++ MAILBOX_CORE_E2, ++ MAILBOX_CORE_RSVD0, ++ MAILBOX_CORE_NUM, ++} mailbox_core_t; ++ ++struct mailbox_irq_name_c{ ++ int id; ++ char name[16]; ++}; ++ ++static const struct mailbox_irq_name_c irq_peer_name[MBOX_CHAN_MAX] = { ++ {MAILBOX_CORE_U7, "u74_core"}, ++ {MAILBOX_CORE_HIFI4, "hifi4_core"}, ++ {MAILBOX_CORE_E2, "e24_core"}, ++ {MAILBOX_CORE_RSVD0, "" }, ++}; ++ ++/** ++ * starfive mailbox channel information ++ * ++ * A channel can be used for TX or RX, it can trigger remote ++ * processor interrupt to notify remote processor and can receive ++ * interrupt if has incoming message. ++ * ++ * @dst_irq: Interrupt vector for remote processor ++ * @core_id: id for remote processor ++ */ ++struct starfive_chan_info { ++ unsigned int dst_irq; ++ mailbox_core_t core_id; ++}; ++ ++/** ++ * starfive mailbox controller data ++ * ++ * Mailbox controller includes 4 channels and can allocate ++ * channel for message transferring. ++ * ++ * @dev: Device to which it is attached ++ * @base: Base address of the register mapping region ++ * @chan: Representation of channels in mailbox controller ++ * @mchan: Representation of channel info ++ * @controller: Representation of a communication channel controller ++ */ ++struct starfive_mbox { ++ struct device *dev; ++ void __iomem *base; ++ struct mbox_chan chan[MBOX_CHAN_MAX]; ++ struct starfive_chan_info mchan[MBOX_CHAN_MAX]; ++ struct mbox_controller controller; ++ struct clk *clk; ++ struct reset_control *rst_rresetn; ++}; ++ ++static struct starfive_mbox *to_starfive_mbox(struct mbox_controller *mbox) ++{ ++ return container_of(mbox, struct starfive_mbox, controller); ++} ++ ++static struct mbox_chan * ++starfive_of_mbox_index_xlate(struct mbox_controller *mbox, ++ const struct of_phandle_args *sp) ++{ ++ struct starfive_mbox *sbox; ++ ++ int ind = sp->args[0]; ++ int core_id = sp->args[1]; ++ ++ if (ind >= mbox->num_chans || core_id >= MAILBOX_CORE_NUM) ++ return ERR_PTR(-EINVAL); ++ ++ sbox = to_starfive_mbox(mbox); ++ ++ sbox->mchan[ind].core_id = core_id; ++ ++ return &mbox->chans[ind]; ++} ++ ++static irqreturn_t starfive_rx_irq_handler(int irq, void *p) ++{ ++ struct mbox_chan *chan = p; ++ unsigned long ch = (unsigned long)chan->con_priv; ++ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); ++ void __iomem *base = MBOX_BASE(mbox, ch); ++ u32 val; ++ ++ val = readl(base + MBOX_CMD_REG); ++ if (!val) ++ return IRQ_NONE; ++ ++ mbox_chan_received_data(chan, (void *)&val); ++ writel(val, base + MBOX_CLR_REG); ++ return IRQ_HANDLED; ++} ++ ++static int starfive_mbox_check_state(struct mbox_chan *chan) ++{ ++ unsigned long ch = (unsigned long)chan->con_priv; ++ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); ++ unsigned long irq_flag = IRQF_SHARED; ++ long ret = 0; ++ ++ pm_runtime_get_sync(mbox->dev); ++ /* MAILBOX should be with IRQF_NO_SUSPEND set */ ++ if (!mbox->dev->pm_domain) ++ irq_flag |= IRQF_NO_SUSPEND; ++ ++ /* Mailbox is idle so directly bail out */ ++ if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) ++ return -EBUSY; ++ ++ if (mbox->mchan[ch].dst_irq > 0) { ++ dev_dbg(mbox->dev, "%s: host IRQ = %d, ch:%ld", __func__, mbox->mchan[ch].dst_irq, ch); ++ ret = devm_request_irq(mbox->dev, mbox->mchan[ch].dst_irq, starfive_rx_irq_handler, ++ irq_flag, irq_peer_name[ch].name, chan); ++ if (ret < 0) ++ dev_err(mbox->dev, "request_irq %d failed\n", mbox->mchan[ch].dst_irq); ++ } ++ ++ return ret; ++} ++ ++static int starfive_mbox_startup(struct mbox_chan *chan) ++{ ++ return starfive_mbox_check_state(chan); ++} ++ ++static void starfive_mbox_shutdown(struct mbox_chan *chan) ++{ ++ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); ++ unsigned long ch = (unsigned long)chan->con_priv; ++ void __iomem *base = MBOX_BASE(mbox, ch); ++ ++ writel(0x0, base + MBOX_IRQ_REG); ++ writel(0x0, base + MBOX_CLR_REG); ++ ++ if (mbox->mchan[ch].dst_irq > 0) ++ devm_free_irq(mbox->dev, mbox->mchan[ch].dst_irq, chan); ++ pm_runtime_put_sync(mbox->dev); ++} ++ ++static int starfive_mbox_send_data(struct mbox_chan *chan, void *msg) ++{ ++ unsigned long ch = (unsigned long)chan->con_priv; ++ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); ++ struct starfive_chan_info *mchan = &mbox->mchan[ch]; ++ void __iomem *base = MBOX_BASE(mbox, ch); ++ u32 *buf = msg; ++ ++ /* Ensure channel is released */ ++ if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) { ++ pr_debug("%s:%d. busy\n", __func__, __LINE__); ++ return -EBUSY; ++ } ++ ++ /* Clear mask for destination interrupt */ ++ writel(BIT(mchan->core_id), base + MBOX_IRQ_REG); ++ ++ /* Fill message data */ ++ writel(*buf, base + MBOX_SET_REG); ++ return 0; ++} ++ ++static struct mbox_chan_ops starfive_mbox_ops = { ++ .startup = starfive_mbox_startup, ++ .send_data = starfive_mbox_send_data, ++ .shutdown = starfive_mbox_shutdown, ++}; ++ ++static const struct of_device_id starfive_mbox_of_match[] = { ++ { .compatible = "starfive,mail_box",}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, starfive_mbox_of_match); ++ ++void starfive_mailbox_init(struct starfive_mbox *mbox) ++{ ++ mbox->clk = devm_clk_get_optional(mbox->dev, "clk_apb"); ++ if (IS_ERR(mbox->clk)) { ++ dev_err(mbox->dev, "failed to get mailbox\n"); ++ return; ++ } ++ ++ mbox->rst_rresetn = devm_reset_control_get_exclusive(mbox->dev, "mbx_rre"); ++ if (IS_ERR(mbox->rst_rresetn)) { ++ dev_err(mbox->dev, "failed to get mailbox reset\n"); ++ return; ++ } ++ ++ clk_prepare_enable(mbox->clk); ++ reset_control_deassert(mbox->rst_rresetn); ++} ++ ++static int starfive_mbox_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct starfive_mbox *mbox; ++ struct mbox_chan *chan; ++ struct resource *res; ++ unsigned long ch; ++ int err; ++ ++ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); ++ if (!mbox) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ mbox->base = devm_ioremap_resource(dev, res); ++ mbox->dev = dev; ++ ++ if (IS_ERR(mbox->base)) ++ return PTR_ERR(mbox->base); ++ ++ starfive_mailbox_init(mbox); ++ ++ mbox->controller.dev = dev; ++ mbox->controller.chans = mbox->chan; ++ mbox->controller.num_chans = MBOX_CHAN_MAX; ++ mbox->controller.ops = &starfive_mbox_ops; ++ mbox->controller.of_xlate = starfive_of_mbox_index_xlate; ++ mbox->controller.txdone_irq = true; ++ mbox->controller.txdone_poll = false; ++ ++ /* Initialize mailbox channel data */ ++ chan = mbox->chan; ++ for (ch = 0; ch < MBOX_CHAN_MAX; ch++) { ++ mbox->mchan[ch].dst_irq = 0; ++ mbox->mchan[ch].core_id = (mailbox_core_t)ch; ++ chan[ch].con_priv = (void *)ch; ++ } ++ mbox->mchan[MAILBOX_CORE_HIFI4].dst_irq = platform_get_irq(pdev, 0); ++ mbox->mchan[MAILBOX_CORE_E2].dst_irq = platform_get_irq(pdev, 1); ++ ++ err = mbox_controller_register(&mbox->controller); ++ if (err) { ++ dev_err(dev, "Failed to register mailbox %d\n", err); ++ return err; ++ } ++ ++ platform_set_drvdata(pdev, mbox); ++ dev_info(dev, "Mailbox enabled\n"); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ ++ return 0; ++} ++ ++static void starfive_mbox_remove(struct platform_device *pdev) ++{ ++ struct starfive_mbox *mbox = platform_get_drvdata(pdev); ++ ++ mbox_controller_unregister(&mbox->controller); ++ devm_clk_put(mbox->dev, mbox->clk); ++ pm_runtime_disable(mbox->dev); ++} ++ ++static int __maybe_unused starfive_mbox_suspend(struct device *dev) ++{ ++ struct starfive_mbox *mbox = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(mbox->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused starfive_mbox_resume(struct device *dev) ++{ ++ struct starfive_mbox *mbox = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_prepare_enable(mbox->clk); ++ if (ret) ++ dev_err(dev, "failed to enable clock\n"); ++ ++ return ret; ++} ++ ++static const struct dev_pm_ops starfive_mbox_pm_ops = { ++ .suspend = starfive_mbox_suspend, ++ .resume = starfive_mbox_resume, ++ SET_RUNTIME_PM_OPS(starfive_mbox_suspend, starfive_mbox_resume, NULL) ++}; ++static struct platform_driver starfive_mbox_driver = { ++ .probe = starfive_mbox_probe, ++ .remove = starfive_mbox_remove, ++ .driver = { ++ .name = "mailbox", ++ .of_match_table = starfive_mbox_of_match, ++ .pm = &starfive_mbox_pm_ops, ++ }, ++}; ++ ++static int __init starfive_mbox_init(void) ++{ ++ return platform_driver_register(&starfive_mbox_driver); ++} ++core_initcall(starfive_mbox_init); ++ ++static void __exit starfive_mbox_exit(void) ++{ ++ platform_driver_unregister(&starfive_mbox_driver); ++} ++module_exit(starfive_mbox_exit); ++ ++MODULE_DESCRIPTION("StarFive Mailbox Controller driver"); ++MODULE_AUTHOR("Shanlong Li "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.12/0008-driver-rtc-Add-StarFive-JH7110-rtc-driver.patch b/target/linux/starfive/patches-6.12/0008-driver-rtc-Add-StarFive-JH7110-rtc-driver.patch new file mode 100644 index 0000000000..c4d4449cad --- /dev/null +++ b/target/linux/starfive/patches-6.12/0008-driver-rtc-Add-StarFive-JH7110-rtc-driver.patch @@ -0,0 +1,787 @@ +From 5969d5b6f7cac455f6f9afc0fe64ac706002e5b5 Mon Sep 17 00:00:00 2001 +From: "ziv.xu" +Date: Fri, 9 Jun 2023 15:31:53 +0800 +Subject: [PATCH 08/55] driver: rtc: Add StarFive JH7110 rtc driver + +Add RTC driver and support for StarFive JH7110 SoC. + +Signed-off-by: ziv.xu +Signed-off-by: Hal Feng +--- + drivers/rtc/Kconfig | 8 + + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-starfive.c | 741 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 750 insertions(+) + create mode 100644 drivers/rtc/rtc-starfive.c + +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1372,6 +1372,14 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_STARFIVE ++ tristate "StarFive 32.768k-RTC" ++ depends on ARCH_STARFIVE ++ depends on OF ++ help ++ If you say Y here you will get support for the RTC found on ++ StarFive SOCS. ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -169,6 +169,7 @@ obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o + obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o + obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o + obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o ++obj-$(CONFIG_RTC_DRV_STARFIVE) += rtc-starfive.o + obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o + obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o + obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o +--- /dev/null ++++ b/drivers/rtc/rtc-starfive.c +@@ -0,0 +1,741 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * RTC driver for the StarFive JH7110 SoC ++ * ++ * Copyright (C) 2021 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Registers */ ++#define SFT_RTC_CFG 0x00 ++#define SFT_RTC_SW_CAL_VALUE 0x04 ++#define SFT_RTC_HW_CAL_CFG 0x08 ++#define SFT_RTC_CMP_CFG 0x0C ++#define SFT_RTC_IRQ_EN 0x10 ++#define SFT_RTC_IRQ_EVEVT 0x14 ++#define SFT_RTC_IRQ_STATUS 0x18 ++#define SFT_RTC_CAL_VALUE 0x24 ++#define SFT_RTC_CFG_TIME 0x28 ++#define SFT_RTC_CFG_DATE 0x2C ++#define SFT_RTC_ACT_TIME 0x34 ++#define SFT_RTC_ACT_DATE 0x38 ++#define SFT_RTC_TIME 0x3C ++#define SFT_RTC_DATE 0x40 ++#define SFT_RTC_TIME_LATCH 0x44 ++#define SFT_RTC_DATE_LATCH 0x48 ++ ++/* RTC_CFG */ ++#define RTC_CFG_ENABLE_SHIFT 0 /* RW: RTC Enable. */ ++#define RTC_CFG_CAL_EN_HW_SHIFT 1 /* RW: Enable of hardware calibretion. */ ++#define RTC_CFG_CAL_SEL_SHIFT 2 /* RW: select the hw/sw calibretion mode.*/ ++#define RTC_CFG_HOUR_MODE_SHIFT 3 /* RW: time hour mode. 24h|12h */ ++ ++/* RTC_SW_CAL_VALUE */ ++#define RTC_SW_CAL_VALUE_MASK GENMASK(15, 0) ++#define RTC_SW_CAL_MAX RTC_SW_CAL_VALUE_MASK ++#define RTC_SW_CAL_MIN 0 ++#define RTC_TICKS_PER_SEC 32768 /* Number of ticks per second */ ++#define RTC_PPB_MULT 1000000000LL /* Multiplier for ppb conversions */ ++ ++/* RTC_HW_CAL_CFG */ ++#define RTC_HW_CAL_REF_SEL_SHIFT 0 ++#define RTC_HW_CAL_FRQ_SEL_SHIFT 1 ++ ++/* IRQ_EN/IRQ_EVEVT/IRQ_STATUS */ ++#define RTC_IRQ_CAL_START BIT(0) ++#define RTC_IRQ_CAL_FINISH BIT(1) ++#define RTC_IRQ_CMP BIT(2) ++#define RTC_IRQ_1SEC BIT(3) ++#define RTC_IRQ_ALAEM BIT(4) ++#define RTC_IRQ_EVT_UPDATE_PSE BIT(31) /* WO: Enable of update time&&date, IRQ_EVEVT only */ ++#define RTC_IRQ_ALL (RTC_IRQ_CAL_START \ ++ | RTC_IRQ_CAL_FINISH \ ++ | RTC_IRQ_CMP \ ++ | RTC_IRQ_1SEC \ ++ | RTC_IRQ_ALAEM) ++ ++/* CAL_VALUE */ ++#define RTC_CAL_VALUE_MASK GENMASK(15, 0) ++ ++/* CFG_TIME/ACT_TIME/RTC_TIME */ ++#define TIME_SEC_MASK GENMASK(6, 0) ++#define TIME_MIN_MASK GENMASK(13, 7) ++#define TIME_HOUR_MASK GENMASK(20, 14) ++ ++/* CFG_DATE/ACT_DATE/RTC_DATE */ ++#define DATE_DAY_MASK GENMASK(5, 0) ++#define DATE_MON_MASK GENMASK(10, 6) ++#define DATE_YEAR_MASK GENMASK(18, 11) ++ ++#define INT_TIMEOUT_US 180 ++ ++enum RTC_HOUR_MODE { ++ RTC_HOUR_MODE_12H = 0, ++ RTC_HOUR_MODE_24H = 1 ++}; ++ ++enum RTC_CAL_MODE { ++ RTC_CAL_MODE_SW = 0, ++ RTC_CAL_MODE_HW = 1 ++}; ++ ++enum RTC_HW_CAL_REF_MODE { ++ RTC_CAL_CLK_REF = 0, ++ RTC_CAL_CLK_MARK = 1 ++}; ++ ++static const unsigned long refclk_list[] = { ++ 1000000, ++ 2000000, ++ 4000000, ++ 5927000, ++ 6000000, ++ 7200000, ++ 8000000, ++ 10250000, ++ 11059200, ++ 12000000, ++ 12288000, ++ 13560000, ++ 16000000, ++ 19200000, ++ 20000000, ++ 22118000, ++ 24000000, ++ 24567000, ++ 25000000, ++ 26000000, ++ 27000000, ++ 30000000, ++ 32000000, ++ 33868800, ++ 36000000, ++ 36860000, ++ 40000000, ++ 44000000, ++ 50000000, ++ 54000000, ++ 28224000, ++ 28000000, ++}; ++ ++struct sft_rtc { ++ struct rtc_device *rtc_dev; ++ struct completion cal_done; ++ struct completion onesec_done; ++ struct clk *pclk; ++ struct clk *cal_clk; ++ struct reset_control *rst_array; ++ int hw_cal_map; ++ void __iomem *regs; ++ int rtc_irq; ++ int ms_pulse_irq; ++ int one_sec_pulse_irq; ++}; ++ ++static inline void sft_rtc_set_enabled(struct sft_rtc *srtc, bool enabled) ++{ ++ u32 val; ++ ++ if (enabled) { ++ val = readl(srtc->regs + SFT_RTC_CFG); ++ val |= BIT(RTC_CFG_ENABLE_SHIFT); ++ writel(val, srtc->regs + SFT_RTC_CFG); ++ } else { ++ val = readl(srtc->regs + SFT_RTC_CFG); ++ val &= ~BIT(RTC_CFG_ENABLE_SHIFT); ++ writel(val, srtc->regs + SFT_RTC_CFG); ++ } ++} ++ ++static inline bool sft_rtc_get_enabled(struct sft_rtc *srtc) ++{ ++ return !!(readl(srtc->regs + SFT_RTC_CFG) & BIT(RTC_CFG_ENABLE_SHIFT)); ++} ++ ++static inline void sft_rtc_set_mode(struct sft_rtc *srtc, enum RTC_HOUR_MODE mode) ++{ ++ u32 val; ++ ++ val = readl(srtc->regs + SFT_RTC_CFG); ++ val |= mode << RTC_CFG_HOUR_MODE_SHIFT; ++ writel(val, srtc->regs + SFT_RTC_CFG); ++} ++ ++static inline int sft_rtc_irq_enable(struct sft_rtc *srtc, u32 irq, bool enable) ++{ ++ u32 val; ++ ++ if (!(irq & RTC_IRQ_ALL)) ++ return -EINVAL; ++ ++ if (enable) { ++ val = readl(srtc->regs + SFT_RTC_IRQ_EN); ++ val |= irq; ++ writel(val, srtc->regs + SFT_RTC_IRQ_EN); ++ } else { ++ val = readl(srtc->regs + SFT_RTC_IRQ_EN); ++ val &= ~irq; ++ writel(val, srtc->regs + SFT_RTC_IRQ_EN); ++ } ++ return 0; ++} ++ ++static inline void ++sft_rtc_set_cal_hw_enable(struct sft_rtc *srtc, bool enable) ++{ ++ u32 val; ++ ++ if (enable) { ++ val = readl(srtc->regs + SFT_RTC_CFG); ++ val |= BIT(RTC_CFG_CAL_EN_HW_SHIFT); ++ writel(val, srtc->regs + SFT_RTC_CFG); ++ } else { ++ val = readl(srtc->regs + SFT_RTC_CFG); ++ val &= ~BIT(RTC_CFG_CAL_EN_HW_SHIFT); ++ writel(val, srtc->regs + SFT_RTC_CFG); ++ } ++} ++ ++static inline void ++sft_rtc_set_cal_mode(struct sft_rtc *srtc, enum RTC_CAL_MODE mode) ++{ ++ u32 val; ++ ++ val = readl(srtc->regs + SFT_RTC_CFG); ++ val |= mode << RTC_CFG_CAL_SEL_SHIFT; ++ writel(val, srtc->regs + SFT_RTC_CFG); ++} ++ ++static int sft_rtc_get_hw_calclk(struct device *dev, unsigned long freq) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(refclk_list); i++) ++ if (refclk_list[i] == freq) ++ return i; ++ ++ dev_err(dev, "refclk: %ldHz do not support.\n", freq); ++ return -EINVAL; ++} ++ ++static inline void sft_rtc_reg2time(struct rtc_time *tm, u32 reg) ++{ ++ tm->tm_hour = bcd2bin(FIELD_GET(TIME_HOUR_MASK, reg)); ++ tm->tm_min = bcd2bin(FIELD_GET(TIME_MIN_MASK, reg)); ++ tm->tm_sec = bcd2bin(FIELD_GET(TIME_SEC_MASK, reg)); ++} ++ ++static inline void sft_rtc_reg2date(struct rtc_time *tm, u32 reg) ++{ ++ tm->tm_year = bcd2bin(FIELD_GET(DATE_YEAR_MASK, reg)) + 100; ++ tm->tm_mon = bcd2bin(FIELD_GET(DATE_MON_MASK, reg)) - 1; ++ tm->tm_mday = bcd2bin(FIELD_GET(DATE_DAY_MASK, reg)); ++} ++ ++static inline u32 sft_rtc_time2reg(struct rtc_time *tm) ++{ ++ return FIELD_PREP(TIME_HOUR_MASK, bin2bcd(tm->tm_hour)) | ++ FIELD_PREP(TIME_MIN_MASK, bin2bcd(tm->tm_min)) | ++ FIELD_PREP(TIME_SEC_MASK, bin2bcd(tm->tm_sec)); ++} ++ ++static inline u32 sft_rtc_date2reg(struct rtc_time *tm) ++{ ++ return FIELD_PREP(DATE_YEAR_MASK, bin2bcd(tm->tm_year - 100)) | ++ FIELD_PREP(DATE_MON_MASK, bin2bcd(tm->tm_mon + 1)) | ++ FIELD_PREP(DATE_DAY_MASK, bin2bcd(tm->tm_mday)); ++} ++ ++static inline void sft_rtc_update_pulse(struct sft_rtc *srtc) ++{ ++ u32 val; ++ ++ val = readl(srtc->regs + SFT_RTC_IRQ_EVEVT); ++ val |= RTC_IRQ_EVT_UPDATE_PSE; ++ writel(val, srtc->regs + SFT_RTC_IRQ_EVEVT); ++} ++ ++static irqreturn_t sft_rtc_irq_handler(int irq, void *data) ++{ ++ struct sft_rtc *srtc = data; ++ struct timerqueue_node *next; ++ u32 irq_flags = 0; ++ u32 irq_mask = 0; ++ u32 val; ++ int ret = 0; ++ ++ val = readl(srtc->regs + SFT_RTC_IRQ_EVEVT); ++ if (val & RTC_IRQ_CAL_START) ++ irq_mask |= RTC_IRQ_CAL_START; ++ ++ if (val & RTC_IRQ_CAL_FINISH) { ++ irq_mask |= RTC_IRQ_CAL_FINISH; ++ complete(&srtc->cal_done); ++ } ++ ++ if (val & RTC_IRQ_CMP) ++ irq_mask |= RTC_IRQ_CMP; ++ ++ if (val & RTC_IRQ_1SEC) { ++ irq_flags |= RTC_PF; ++ irq_mask |= RTC_IRQ_1SEC; ++ complete(&srtc->onesec_done); ++ } ++ ++ if (val & RTC_IRQ_ALAEM) { ++ irq_flags |= RTC_AF; ++ irq_mask |= RTC_IRQ_ALAEM; ++ ++ next = timerqueue_getnext(&srtc->rtc_dev->timerqueue); ++ if (next == &srtc->rtc_dev->aie_timer.node) ++ dev_info(&srtc->rtc_dev->dev, "alarm expires"); ++ } ++ ++ writel(irq_mask, srtc->regs + SFT_RTC_IRQ_EVEVT); ++ ++ /* Wait interrupt flag clear */ ++ ret = readl_poll_timeout_atomic(srtc->regs + SFT_RTC_IRQ_EVEVT, val, ++ (val & irq_mask) == 0, 0, INT_TIMEOUT_US); ++ if (ret) ++ dev_warn(&srtc->rtc_dev->dev, "fail to clear rtc interrupt flag\n"); ++ ++ if (irq_flags) ++ rtc_update_irq(srtc->rtc_dev, 1, irq_flags | RTC_IRQF); ++ ++ return IRQ_HANDLED; ++} ++ ++static int sft_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ u32 val; ++ int irq_1sec_state_start, irq_1sec_state_end; ++ ++ /* If the RTC is disabled, assume the values are invalid */ ++ if (!sft_rtc_get_enabled(srtc)) ++ return -EINVAL; ++ ++ irq_1sec_state_start = ++ (readl(srtc->regs + SFT_RTC_IRQ_STATUS) & RTC_IRQ_1SEC) == 0 ? 0 : 1; ++ ++read_again: ++ val = readl(srtc->regs + SFT_RTC_TIME); ++ sft_rtc_reg2time(tm, val); ++ ++ val = readl(srtc->regs + SFT_RTC_DATE); ++ sft_rtc_reg2date(tm, val); ++ ++ if (irq_1sec_state_start == 0) { ++ irq_1sec_state_end = ++ (readl(srtc->regs + SFT_RTC_IRQ_STATUS) & RTC_IRQ_1SEC) == 0 ? 0 : 1; ++ if (irq_1sec_state_end == 1) { ++ irq_1sec_state_start = 1; ++ goto read_again; ++ } ++ } ++ ++ return 0; ++} ++ ++static int sft_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ u32 val; ++ int ret; ++ ++ val = sft_rtc_time2reg(tm); ++ writel(val, srtc->regs + SFT_RTC_CFG_TIME); ++ ++ val = sft_rtc_date2reg(tm); ++ writel(val, srtc->regs + SFT_RTC_CFG_DATE); ++ ++ /* Update pulse */ ++ sft_rtc_update_pulse(srtc); ++ ++ /* Ensure that data is fully written */ ++ ret = wait_for_completion_interruptible_timeout(&srtc->onesec_done, ++ usecs_to_jiffies(120)); ++ if (ret) { ++ dev_warn(dev, ++ "rtc wait for completion interruptible timeout.\n"); ++ } ++ return 0; ++} ++ ++static int sft_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ ++ return sft_rtc_irq_enable(srtc, RTC_IRQ_ALAEM, enabled); ++} ++ ++static int sft_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ u32 val; ++ ++ val = readl(srtc->regs + SFT_RTC_ACT_TIME); ++ sft_rtc_reg2time(&alarm->time, val); ++ ++ val = readl(srtc->regs + SFT_RTC_ACT_DATE); ++ sft_rtc_reg2date(&alarm->time, val); ++ ++ return 0; ++} ++ ++static int sft_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ u32 val; ++ ++ sft_rtc_alarm_irq_enable(dev, 0); ++ ++ val = sft_rtc_time2reg(&alarm->time); ++ writel(val, srtc->regs + SFT_RTC_ACT_TIME); ++ ++ val = sft_rtc_date2reg(&alarm->time); ++ writel(val, srtc->regs + SFT_RTC_ACT_DATE); ++ ++ sft_rtc_alarm_irq_enable(dev, alarm->enabled); ++ ++ return 0; ++} ++ ++static int sft_rtc_get_offset(struct device *dev, long *offset) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ s64 tmp; ++ u32 val; ++ ++ val = readl(srtc->regs + SFT_RTC_CAL_VALUE) ++ & RTC_SW_CAL_VALUE_MASK; ++ val += 1; ++ /* ++ * the adjust val range is [0x0000-0xffff], ++ * the default val is 0x7fff (32768-1),mapping offset=0 ; ++ */ ++ tmp = (s64)val - RTC_TICKS_PER_SEC; ++ tmp *= RTC_PPB_MULT; ++ tmp = div_s64(tmp, RTC_TICKS_PER_SEC); ++ ++ /* Offset value operates in negative way, so swap sign */ ++ *offset = -tmp; ++ ++ return 0; ++} ++ ++static int sft_rtc_set_offset(struct device *dev, long offset) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ s64 tmp; ++ u32 val; ++ ++ tmp = offset * RTC_TICKS_PER_SEC; ++ tmp = div_s64(tmp, RTC_PPB_MULT); ++ ++ tmp = RTC_TICKS_PER_SEC - tmp; ++ tmp -= 1; ++ if (tmp > RTC_SW_CAL_MAX || tmp < RTC_SW_CAL_MIN) { ++ dev_err(dev, "offset is out of range.\n"); ++ return -EINVAL; ++ } ++ ++ val = tmp & RTC_SW_CAL_VALUE_MASK; ++ /* set software calibration value */ ++ writel(val, srtc->regs + SFT_RTC_SW_CAL_VALUE); ++ ++ /* set CFG_RTC-cal_sel to select calibretion by software. */ ++ sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_SW); ++ ++ return 0; ++} ++ ++static __maybe_unused int ++sft_rtc_hw_adjustment(struct device *dev, unsigned int enable) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ u32 val; ++ ++ if (srtc->hw_cal_map <= 0) { ++ dev_err(dev, "fail to get cal-clock-freq.\n"); ++ return -EFAULT; ++ } ++ ++ if (enable) { ++ sft_rtc_irq_enable(srtc, RTC_IRQ_CAL_FINISH, true); ++ ++ /* Set reference clock frequency value */ ++ val = readl(srtc->regs + SFT_RTC_HW_CAL_CFG); ++ val |= (srtc->hw_cal_map << RTC_HW_CAL_FRQ_SEL_SHIFT); ++ writel(val, srtc->regs + SFT_RTC_HW_CAL_CFG); ++ ++ /* Set CFG_RTC-cal_sel to select calibretion by hardware. */ ++ sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_HW); ++ ++ /* Set CFG_RTC-cal_en_hw to launch hardware calibretion.*/ ++ sft_rtc_set_cal_hw_enable(srtc, true); ++ ++ wait_for_completion_interruptible_timeout(&srtc->cal_done, ++ usecs_to_jiffies(100)); ++ ++ sft_rtc_irq_enable(srtc, RTC_IRQ_CAL_FINISH, false); ++ } else { ++ sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_SW); ++ sft_rtc_set_cal_hw_enable(srtc, false); ++ } ++ ++ return 0; ++} ++ ++static int sft_rtc_get_cal_clk(struct device *dev, struct sft_rtc *srtc) ++{ ++ struct device_node *np = dev->of_node; ++ unsigned long cal_clk_freq; ++ u32 freq; ++ int ret; ++ ++ srtc->cal_clk = devm_clk_get(dev, "cal_clk"); ++ if (IS_ERR(srtc->cal_clk)) ++ return PTR_ERR(srtc->cal_clk); ++ ++ clk_prepare_enable(srtc->cal_clk); ++ ++ cal_clk_freq = clk_get_rate(srtc->cal_clk); ++ if (!cal_clk_freq) { ++ dev_warn(dev, ++ "get rate failed, next try to get from dts.\n"); ++ ret = of_property_read_u32(np, "rtc,cal-clock-freq", &freq); ++ if (!ret) { ++ cal_clk_freq = (u64)freq; ++ } else { ++ dev_err(dev, ++ "Need rtc,cal-clock-freq define in dts.\n"); ++ goto err_disable_cal_clk; ++ } ++ } ++ ++ srtc->hw_cal_map = sft_rtc_get_hw_calclk(dev, cal_clk_freq); ++ if (srtc->hw_cal_map < 0) { ++ ret = srtc->hw_cal_map; ++ goto err_disable_cal_clk; ++ } ++ ++ return 0; ++ ++err_disable_cal_clk: ++ clk_disable_unprepare(srtc->cal_clk); ++ ++ return ret; ++} ++ ++static int sft_rtc_get_irq(struct platform_device *pdev, struct sft_rtc *srtc) ++{ ++ int ret; ++ ++ srtc->rtc_irq = platform_get_irq_byname(pdev, "rtc"); ++ if (srtc->rtc_irq < 0) ++ return -EINVAL; ++ ++ ret = devm_request_irq(&pdev->dev, srtc->rtc_irq, ++ sft_rtc_irq_handler, 0, ++ KBUILD_MODNAME, srtc); ++ if (ret) ++ dev_err(&pdev->dev, "Failed to request interrupt, %d\n", ret); ++ ++ return ret; ++} ++ ++static const struct rtc_class_ops starfive_rtc_ops = { ++ .read_time = sft_rtc_read_time, ++ .set_time = sft_rtc_set_time, ++ .read_alarm = sft_rtc_read_alarm, ++ .set_alarm = sft_rtc_set_alarm, ++ .alarm_irq_enable = sft_rtc_alarm_irq_enable, ++ .set_offset = sft_rtc_set_offset, ++ .read_offset = sft_rtc_get_offset, ++}; ++ ++static int sft_rtc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct sft_rtc *srtc; ++ struct rtc_time tm; ++ struct irq_desc *desc; ++ int ret; ++ ++ srtc = devm_kzalloc(dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(srtc->regs)) ++ return PTR_ERR(srtc->regs); ++ ++ srtc->pclk = devm_clk_get(dev, "pclk"); ++ if (IS_ERR(srtc->pclk)) { ++ ret = PTR_ERR(srtc->pclk); ++ dev_err(dev, ++ "Failed to retrieve the peripheral clock, %d\n", ret); ++ return ret; ++ } ++ ++ srtc->rst_array = devm_reset_control_array_get_exclusive(dev); ++ if (IS_ERR(srtc->rst_array)) { ++ ret = PTR_ERR(srtc->rst_array); ++ dev_err(dev, ++ "Failed to retrieve the rtc reset, %d\n", ret); ++ return ret; ++ } ++ ++ init_completion(&srtc->cal_done); ++ init_completion(&srtc->onesec_done); ++ ++ ret = clk_prepare_enable(srtc->pclk); ++ if (ret) { ++ dev_err(dev, ++ "Failed to enable the peripheral clock, %d\n", ret); ++ return ret; ++ } ++ ++ ret = sft_rtc_get_cal_clk(dev, srtc); ++ if (ret) ++ goto err_disable_pclk; ++ ++ ret = reset_control_deassert(srtc->rst_array); ++ if (ret) { ++ dev_err(dev, ++ "Failed to deassert rtc resets, %d\n", ret); ++ goto err_disable_cal_clk; ++ } ++ ++ ret = sft_rtc_get_irq(pdev, srtc); ++ if (ret) ++ goto err_disable_cal_clk; ++ ++ srtc->rtc_dev = devm_rtc_allocate_device(dev); ++ if (IS_ERR(srtc->rtc_dev)) ++ return PTR_ERR(srtc->rtc_dev); ++ ++ platform_set_drvdata(pdev, srtc); ++ ++ /* The RTC supports 01.01.2001 - 31.12.2099 */ ++ srtc->rtc_dev->range_min = mktime64(2001, 1, 1, 0, 0, 0); ++ srtc->rtc_dev->range_max = mktime64(2099, 12, 31, 23, 59, 59); ++ ++ srtc->rtc_dev->ops = &starfive_rtc_ops; ++ device_init_wakeup(dev, true); ++ ++ desc = irq_to_desc(srtc->rtc_irq); ++ irq_desc_get_chip(desc)->flags = IRQCHIP_SKIP_SET_WAKE; ++ ++ /* Always use 24-hour mode and keep the RTC values */ ++ sft_rtc_set_mode(srtc, RTC_HOUR_MODE_24H); ++ ++ sft_rtc_set_enabled(srtc, true); ++ ++ if (device_property_read_bool(dev, "rtc,hw-adjustment")) ++ sft_rtc_hw_adjustment(dev, true); ++ ++ /* ++ * If rtc time is out of supported range, reset it to the minimum time. ++ * notice that, actual year = 1900 + tm.tm_year ++ * actual month = 1 + tm.tm_mon ++ */ ++ sft_rtc_read_time(dev, &tm); ++ if (tm.tm_year < 101 || tm.tm_year > 199 || tm.tm_mon < 0 || tm.tm_mon > 11 || ++ tm.tm_mday < 1 || tm.tm_mday > 31 || tm.tm_hour < 0 || tm.tm_hour > 23 || ++ tm.tm_min < 0 || tm.tm_min > 59 || tm.tm_sec < 0 || tm.tm_sec > 59) { ++ rtc_time64_to_tm(srtc->rtc_dev->range_min, &tm); ++ sft_rtc_set_time(dev, &tm); ++ } ++ ++ ret = devm_rtc_register_device(srtc->rtc_dev); ++ if (ret) ++ goto err_disable_wakeup; ++ ++ return 0; ++ ++err_disable_wakeup: ++ device_init_wakeup(dev, false); ++ ++err_disable_cal_clk: ++ clk_disable_unprepare(srtc->cal_clk); ++ ++err_disable_pclk: ++ clk_disable_unprepare(srtc->pclk); ++ ++ return ret; ++} ++ ++static void sft_rtc_remove(struct platform_device *pdev) ++{ ++ struct sft_rtc *srtc = platform_get_drvdata(pdev); ++ ++ sft_rtc_alarm_irq_enable(&pdev->dev, 0); ++ device_init_wakeup(&pdev->dev, 0); ++ ++ clk_disable_unprepare(srtc->pclk); ++ clk_disable_unprepare(srtc->cal_clk); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int sft_rtc_suspend(struct device *dev) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(srtc->rtc_irq); ++ ++ return 0; ++} ++ ++static int sft_rtc_resume(struct device *dev) ++{ ++ struct sft_rtc *srtc = dev_get_drvdata(dev); ++ ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(srtc->rtc_irq); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(sft_rtc_pm_ops, sft_rtc_suspend, sft_rtc_resume); ++ ++static const struct of_device_id sft_rtc_of_match[] = { ++ { .compatible = "starfive,jh7110-rtc" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sft_rtc_of_match); ++ ++static struct platform_driver starfive_rtc_driver = { ++ .driver = { ++ .name = "starfive-rtc", ++ .of_match_table = sft_rtc_of_match, ++ .pm = &sft_rtc_pm_ops, ++ }, ++ .probe = sft_rtc_probe, ++ .remove = sft_rtc_remove, ++}; ++module_platform_driver(starfive_rtc_driver); ++ ++MODULE_AUTHOR("Samin Guo "); ++MODULE_AUTHOR("Hal Feng "); ++MODULE_DESCRIPTION("StarFive RTC driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:starfive-rtc"); diff --git a/target/linux/starfive/patches-6.12/0009-uart-8250-Add-dw-auto-flow-ctrl-support.patch b/target/linux/starfive/patches-6.12/0009-uart-8250-Add-dw-auto-flow-ctrl-support.patch new file mode 100644 index 0000000000..92515582c6 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0009-uart-8250-Add-dw-auto-flow-ctrl-support.patch @@ -0,0 +1,98 @@ +From 20c14bbdff9e3be2ddbeffa266f08bae04216e63 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Sun, 25 Jun 2023 09:40:29 +0800 +Subject: [PATCH 09/55] uart: 8250: Add dw auto flow ctrl support + +Add designeware 8250 auto flow ctrl support. Enable +it by add auto-flow-control in dts. + +Signed-off-by: Minda Chen +--- + drivers/tty/serial/8250/8250_core.c | 2 ++ + drivers/tty/serial/8250/8250_dw.c | 3 +++ + drivers/tty/serial/8250/8250_port.c | 14 +++++++++++++- + include/linux/serial_8250.h | 1 + + include/uapi/linux/serial_core.h | 2 ++ + 5 files changed, 21 insertions(+), 1 deletion(-) + +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -810,6 +810,8 @@ int serial8250_register_8250_port(const + uart->dl_read = up->dl_read; + if (up->dl_write) + uart->dl_write = up->dl_write; ++ if (up->probe) ++ uart->probe = up->probe; + + if (uart->port.type != PORT_8250_CIR) { + if (uart_console_registered(&uart->port)) +--- a/drivers/tty/serial/8250/8250_dw.c ++++ b/drivers/tty/serial/8250/8250_dw.c +@@ -594,6 +594,9 @@ static int dw8250_probe(struct platform_ + data->msr_mask_off |= UART_MSR_TERI; + } + ++ if (device_property_read_bool(dev, "auto-flow-control")) ++ up->probe |= UART_PROBE_AFE; ++ + /* If there is separate baudclk, get the rate from it. */ + data->clk = devm_clk_get_optional_enabled(dev, "baudclk"); + if (data->clk == NULL) +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -319,6 +319,14 @@ static const struct serial8250_config ua + .rxtrig_bytes = {1, 8, 16, 30}, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, ++ [PORT_16550A_AFE] = { ++ .name = "16550A_AFE", ++ .fifo_size = 16, ++ .tx_loadsz = 16, ++ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, ++ .rxtrig_bytes = {1, 4, 8, 14}, ++ .flags = UART_CAP_FIFO | UART_CAP_AFE, ++ }, + }; + + /* Uart divisor latch read */ +@@ -1124,6 +1132,11 @@ static void autoconfig_16550a(struct uar + up->port.type = PORT_U6_16550A; + up->capabilities |= UART_CAP_AFE; + } ++ ++ if ((up->port.type == PORT_16550A) && (up->probe & UART_PROBE_AFE)) { ++ up->port.type = PORT_16550A_AFE; ++ up->capabilities |= UART_CAP_AFE; ++ } + } + + /* +@@ -2774,7 +2787,6 @@ serial8250_do_set_termios(struct uart_po + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + } +- + /* + * Update the per-port timeout. + */ +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -141,6 +141,7 @@ struct uart_8250_port { + unsigned char probe; + struct mctrl_gpios *gpios; + #define UART_PROBE_RSA (1 << 0) ++#define UART_PROBE_AFE (1 << 1) + + /* + * Some bits in registers are cleared on a read, so they must +--- a/include/uapi/linux/serial_core.h ++++ b/include/uapi/linux/serial_core.h +@@ -231,6 +231,8 @@ + /* Sunplus UART */ + #define PORT_SUNPLUS 123 + ++#define PORT_16550A_AFE 124 ++ + /* Generic type identifier for ports which type is not important to userspace. */ + #define PORT_GENERIC (-1) + diff --git a/target/linux/starfive/patches-6.12/0010-uart-8250-add-reset-operation-in-runtime-PM.patch b/target/linux/starfive/patches-6.12/0010-uart-8250-add-reset-operation-in-runtime-PM.patch new file mode 100644 index 0000000000..452dfade6d --- /dev/null +++ b/target/linux/starfive/patches-6.12/0010-uart-8250-add-reset-operation-in-runtime-PM.patch @@ -0,0 +1,32 @@ +From ee5aab642d8a99a7a48d9b30f098ca2a97f463c4 Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Wed, 20 Sep 2023 17:19:59 +0800 +Subject: [PATCH 10/55] uart: 8250: add reset operation in runtime PM + +add reset operation in runtime PM + +Signed-off-by: William Qiu +--- + drivers/tty/serial/8250/8250_dw.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/tty/serial/8250/8250_dw.c ++++ b/drivers/tty/serial/8250/8250_dw.c +@@ -712,6 +712,8 @@ static int dw8250_runtime_suspend(struct + { + struct dw8250_data *data = dev_get_drvdata(dev); + ++ reset_control_assert(data->rst); ++ + clk_disable_unprepare(data->clk); + + clk_disable_unprepare(data->pclk); +@@ -734,6 +736,8 @@ static int dw8250_runtime_resume(struct + return ret; + } + ++ reset_control_deassert(data->rst); ++ + return 0; + } + diff --git a/target/linux/starfive/patches-6.12/0011-CAN-starfive-Add-CAN-engine-support.patch b/target/linux/starfive/patches-6.12/0011-CAN-starfive-Add-CAN-engine-support.patch new file mode 100644 index 0000000000..a581e47dd7 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0011-CAN-starfive-Add-CAN-engine-support.patch @@ -0,0 +1,1316 @@ +From 94de8add412dffdfa0389c6ae0f6aaad64d34fcd Mon Sep 17 00:00:00 2001 +From: William Qiu +Date: Thu, 15 Jun 2023 20:15:25 +0800 +Subject: [PATCH 11/55] CAN: starfive - Add CAN engine support + +Adding device probe StarFive CAN module. + +Signed-off-by: William Qiu +Signed-off-by: Hal Feng +--- + drivers/net/can/Kconfig | 5 + + drivers/net/can/Makefile | 2 + + drivers/net/can/ipms_canfd.c | 1273 ++++++++++++++++++++++++++++++++++ + 3 files changed, 1280 insertions(+) + create mode 100644 drivers/net/can/ipms_canfd.c + +--- a/drivers/net/can/Kconfig ++++ b/drivers/net/can/Kconfig +@@ -216,6 +216,11 @@ config CAN_XILINXCAN + Xilinx CAN driver. This driver supports both soft AXI CAN IP and + Zynq CANPS IP. + ++config IPMS_CAN ++ tristate "IPMS CAN" ++ help ++ IPMS CANFD driver. This driver supports IPMS CANFD IP. ++ + source "drivers/net/can/c_can/Kconfig" + source "drivers/net/can/cc770/Kconfig" + source "drivers/net/can/ctucanfd/Kconfig" +--- a/drivers/net/can/Makefile ++++ b/drivers/net/can/Makefile +@@ -33,5 +33,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ + obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o + obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o + obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o ++obj-$(CONFIG_IPMS_CAN) += ipms_canfd.o ++ccflags-$(CONFIG_IPMS_CAN) := -Wno-error=missing-prototypes + + subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG +--- /dev/null ++++ b/drivers/net/can/ipms_canfd.c +@@ -0,0 +1,1273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * StarFive Controller Area Network Host Controller Driver ++ * ++ * Copyright (c) 2022 StarFive Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "ipms_canfd" ++ ++/* CAN registers set */ ++enum canfd_device_reg { ++ CANFD_RUBF_OFFSET = 0x00, /* Receive Buffer Registers 0x00-0x4f */ ++ CANFD_RUBF_ID_OFFSET = 0x00, ++ CANFD_RBUF_CTL_OFFSET = 0x04, ++ CANFD_RBUF_DATA_OFFSET = 0x08, ++ CANFD_TBUF_OFFSET = 0x50, /* Transmit Buffer Registers 0x50-0x97 */ ++ CANFD_TBUF_ID_OFFSET = 0x50, ++ CANFD_TBUF_CTL_OFFSET = 0x54, ++ CANFD_TBUF_DATA_OFFSET = 0x58, ++ CANFD_TTS_OFFSET = 0x98, /* Transmission Time Stamp 0x98-0x9f */ ++ CANFD_CFG_STAT_OFFSET = 0xa0, ++ CANFD_TCMD_OFFSET = 0xa1, ++ CANFD_TCTRL_OFFSET = 0xa2, ++ CANFD_RCTRL_OFFSET = 0xa3, ++ CANFD_RTIE_OFFSET = 0xa4, ++ CANFD_RTIF_OFFSET = 0xa5, ++ CANFD_ERRINT_OFFSET = 0xa6, ++ CANFD_LIMIT_OFFSET = 0xa7, ++ CANFD_S_SEG_1_OFFSET = 0xa8, ++ CANFD_S_SEG_2_OFFSET = 0xa9, ++ CANFD_S_SJW_OFFSET = 0xaa, ++ CANFD_S_PRESC_OFFSET = 0xab, ++ CANFD_F_SEG_1_OFFSET = 0xac, ++ CANFD_F_SEG_2_OFFSET = 0xad, ++ CANFD_F_SJW_OFFSET = 0xae, ++ CANFD_F_PRESC_OFFSET = 0xaf, ++ CANFD_EALCAP_OFFSET = 0xb0, ++ CANFD_RECNT_OFFSET = 0xb2, ++ CANFD_TECNT_OFFSET = 0xb3, ++}; ++ ++enum canfd_reg_bitchange { ++ CAN_FD_SET_RST_MASK = 0x80, /* Set Reset Bit */ ++ CAN_FD_OFF_RST_MASK = 0x7f, /* Reset Off Bit */ ++ CAN_FD_SET_FULLCAN_MASK = 0x10, /* set TTTBM as 1->full TTCAN mode */ ++ CAN_FD_OFF_FULLCAN_MASK = 0xef, /* set TTTBM as 0->separate PTB and STB mode */ ++ CAN_FD_SET_FIFO_MASK = 0x20, /* set TSMODE as 1->FIFO mode */ ++ CAN_FD_OFF_FIFO_MASK = 0xdf, /* set TSMODE as 0->Priority mode */ ++ CAN_FD_SET_TSONE_MASK = 0x04, ++ CAN_FD_OFF_TSONE_MASK = 0xfb, ++ CAN_FD_SET_TSALL_MASK = 0x02, ++ CAN_FD_OFF_TSALL_MASK = 0xfd, ++ CAN_FD_LBMEMOD_MASK = 0x40, /* set loop back mode, external */ ++ CAN_FD_LBMIMOD_MASK = 0x20, /* set loopback internal mode */ ++ CAN_FD_SET_BUSOFF_MASK = 0x01, ++ CAN_FD_OFF_BUSOFF_MASK = 0xfe, ++ CAN_FD_SET_TTSEN_MASK = 0x80, /* set ttsen, tts update enable */ ++ CAN_FD_SET_BRS_MASK = 0x10, /* can fd Bit Rate Switch mask */ ++ CAN_FD_OFF_BRS_MASK = 0xef, ++ CAN_FD_SET_EDL_MASK = 0x20, /* Extended Data Length */ ++ CAN_FD_OFF_EDL_MASK = 0xdf, ++ CAN_FD_SET_DLC_MASK = 0x0f, ++ CAN_FD_SET_TENEXT_MASK = 0x40, ++ CAN_FD_SET_IDE_MASK = 0x80, ++ CAN_FD_OFF_IDE_MASK = 0x7f, ++ CAN_FD_SET_RTR_MASK = 0x40, ++ CAN_FD_OFF_RTR_MASK = 0xbf, ++ CAN_FD_INTR_ALL_MASK = 0xff, /* all interrupts enable mask */ ++ CAN_FD_SET_RIE_MASK = 0x80, ++ CAN_FD_OFF_RIE_MASK = 0x7f, ++ CAN_FD_SET_RFIE_MASK = 0x20, ++ CAN_FD_OFF_RFIE_MASK = 0xdf, ++ CAN_FD_SET_RAFIE_MASK = 0x10, ++ CAN_FD_OFF_RAFIE_MASK = 0xef, ++ CAN_FD_SET_EIE_MASK = 0x02, ++ CAN_FD_OFF_EIE_MASK = 0xfd, ++ CAN_FD_TASCTIVE_MASK = 0x02, ++ CAN_FD_RASCTIVE_MASK = 0x04, ++ CAN_FD_SET_TBSEL_MASK = 0x80, /* message writen in STB */ ++ CAN_FD_OFF_TBSEL_MASK = 0x7f, /* message writen in PTB */ ++ CAN_FD_SET_STBY_MASK = 0x20, ++ CAN_FD_OFF_STBY_MASK = 0xdf, ++ CAN_FD_SET_TPE_MASK = 0x10, /* Transmit primary enable */ ++ CAN_FD_SET_TPA_MASK = 0x08, ++ CAN_FD_SET_SACK_MASK = 0x80, ++ CAN_FD_SET_RREL_MASK = 0x10, ++ CAN_FD_RSTAT_NOT_EMPTY_MASK = 0x03, ++ CAN_FD_SET_RIF_MASK = 0x80, ++ CAN_FD_OFF_RIF_MASK = 0x7f, ++ CAN_FD_SET_RAFIF_MASK = 0x10, ++ CAN_FD_SET_RFIF_MASK = 0x20, ++ CAN_FD_SET_TPIF_MASK = 0x08, /* Transmission Primary Interrupt Flag */ ++ CAN_FD_SET_TSIF_MASK = 0x04, ++ CAN_FD_SET_EIF_MASK = 0x02, ++ CAN_FD_SET_AIF_MASK = 0x01, ++ CAN_FD_SET_EWARN_MASK = 0x80, ++ CAN_FD_SET_EPASS_MASK = 0x40, ++ CAN_FD_SET_EPIE_MASK = 0x20, ++ CAN_FD_SET_EPIF_MASK = 0x10, ++ CAN_FD_SET_ALIE_MASK = 0x08, ++ CAN_FD_SET_ALIF_MASK = 0x04, ++ CAN_FD_SET_BEIE_MASK = 0x02, ++ CAN_FD_SET_BEIF_MASK = 0x01, ++ CAN_FD_OFF_EPIE_MASK = 0xdf, ++ CAN_FD_OFF_BEIE_MASK = 0xfd, ++ CAN_FD_SET_AFWL_MASK = 0x40, ++ CAN_FD_SET_EWL_MASK = 0x0b, ++ CAN_FD_SET_KOER_MASK = 0xe0, ++ CAN_FD_SET_BIT_ERROR_MASK = 0x20, ++ CAN_FD_SET_FORM_ERROR_MASK = 0x40, ++ CAN_FD_SET_STUFF_ERROR_MASK = 0x60, ++ CAN_FD_SET_ACK_ERROR_MASK = 0x80, ++ CAN_FD_SET_CRC_ERROR_MASK = 0xa0, ++ CAN_FD_SET_OTH_ERROR_MASK = 0xc0, ++}; ++ ++/* seg1,seg2,sjw,prescaler all have 8 bits */ ++#define BITS_OF_BITTIMING_REG 8 ++ ++/* in can_bittiming strucure every field has 32 bits---->u32 */ ++#define FBITS_IN_BITTIMING_STR 32 ++#define SEG_1_SHIFT 0 ++#define SEG_2_SHIFT 8 ++#define SJW_SHIFT 16 ++#define PRESC_SHIFT 24 ++ ++/* TTSEN bit used for 32 bit register read or write */ ++#define TTSEN_8_32_SHIFT 24 ++#define RTR_32_8_SHIFT 24 ++ ++/* transmit mode */ ++#define XMIT_FULL 0 ++#define XMIT_SEP_FIFO 1 ++#define XMIT_SEP_PRIO 2 ++#define XMIT_PTB_MODE 3 ++ ++enum IPMS_CAN_TYPE { ++ IPMS_CAN_TYPY_CAN = 0, ++ IPMS_CAN_TYPE_CANFD, ++}; ++ ++struct ipms_canfd_priv { ++ struct can_priv can; ++ struct napi_struct napi; ++ struct device *dev; ++ struct regmap *reg_syscon; ++ void __iomem *reg_base; ++ u32 (*read_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg); ++ void (*write_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg, u32 val); ++ struct clk *can_clk; ++ u32 tx_mode; ++ struct reset_control *resets; ++ struct clk_bulk_data *clks; ++ int nr_clks; ++ u32 can_or_canfd; ++}; ++ ++static struct can_bittiming_const canfd_bittiming_const = { ++ .name = DRIVER_NAME, ++ .tseg1_min = 2, ++ .tseg1_max = 16, ++ .tseg2_min = 2, ++ .tseg2_max = 8, ++ .sjw_max = 4, ++ .brp_min = 1, ++ .brp_max = 512, ++ .brp_inc = 1, ++ ++}; ++ ++static struct can_bittiming_const canfd_data_bittiming_const = { ++ .name = DRIVER_NAME, ++ .tseg1_min = 1, ++ .tseg1_max = 16, ++ .tseg2_min = 2, ++ .tseg2_max = 8, ++ .sjw_max = 8, ++ .brp_min = 1, ++ .brp_max = 512, ++ .brp_inc = 1, ++}; ++ ++static void canfd_write_reg_le(const struct ipms_canfd_priv *priv, ++ enum canfd_device_reg reg, u32 val) ++{ ++ iowrite32(val, priv->reg_base + reg); ++} ++ ++static u32 canfd_read_reg_le(const struct ipms_canfd_priv *priv, ++ enum canfd_device_reg reg) ++{ ++ return ioread32(priv->reg_base + reg); ++} ++ ++static inline unsigned char can_ioread8(const void *addr) ++{ ++ void *addr_down; ++ union val { ++ u8 val_8[4]; ++ u32 val_32; ++ } val; ++ u32 offset = 0; ++ ++ addr_down = (void *)ALIGN_DOWN((unsigned long)addr, 4); ++ offset = addr - addr_down; ++ val.val_32 = ioread32(addr_down); ++ return val.val_8[offset]; ++} ++ ++static inline void can_iowrite8(unsigned char value, void *addr) ++{ ++ void *addr_down; ++ union val { ++ u8 val_8[4]; ++ u32 val_32; ++ } val; ++ u8 offset = 0; ++ ++ addr_down = (void *)ALIGN_DOWN((unsigned long)addr, 4); ++ offset = addr - addr_down; ++ val.val_32 = ioread32(addr_down); ++ val.val_8[offset] = value; ++ iowrite32(val.val_32, addr_down); ++} ++ ++static void canfd_reigister_set_bit(const struct ipms_canfd_priv *priv, ++ enum canfd_device_reg reg, ++ enum canfd_reg_bitchange set_mask) ++{ ++ void *addr_down; ++ union val { ++ u8 val_8[4]; ++ u32 val_32; ++ } val; ++ u8 offset = 0; ++ ++ addr_down = (void *)ALIGN_DOWN((unsigned long)(priv->reg_base + reg), 4); ++ offset = (priv->reg_base + reg) - addr_down; ++ val.val_32 = ioread32(addr_down); ++ val.val_8[offset] |= set_mask; ++ iowrite32(val.val_32, addr_down); ++} ++ ++static void canfd_reigister_off_bit(const struct ipms_canfd_priv *priv, ++ enum canfd_device_reg reg, ++ enum canfd_reg_bitchange set_mask) ++{ ++ void *addr_down; ++ union val { ++ u8 val_8[4]; ++ u32 val_32; ++ } val; ++ u8 offset = 0; ++ ++ addr_down = (void *)ALIGN_DOWN((unsigned long)(priv->reg_base + reg), 4); ++ offset = (priv->reg_base + reg) - addr_down; ++ val.val_32 = ioread32(addr_down); ++ val.val_8[offset] &= set_mask; ++ iowrite32(val.val_32, addr_down); ++} ++ ++static int canfd_device_driver_bittime_configuration(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ struct can_bittiming *bt = &priv->can.bittiming; ++ struct can_bittiming *dbt = &priv->can.data_bittiming; ++ u32 reset_test, bittiming_temp, dat_bittiming; ++ ++ reset_test = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ ++ if (!(reset_test & CAN_FD_SET_RST_MASK)) { ++ netdev_alert(ndev, "Not in reset mode, cannot set bit timing\n"); ++ return -EPERM; ++ } ++ ++ bittiming_temp = ((bt->phase_seg1 + bt->prop_seg + 1 - 2) << SEG_1_SHIFT) | ++ ((bt->phase_seg2 - 1) << SEG_2_SHIFT) | ++ ((bt->sjw - 1) << SJW_SHIFT) | ++ ((bt->brp - 1) << PRESC_SHIFT); ++ ++ /* Check the bittime parameter */ ++ if ((((int)(bt->phase_seg1 + bt->prop_seg + 1) - 2) < 0) || ++ (((int)(bt->phase_seg2) - 1) < 0) || ++ (((int)(bt->sjw) - 1) < 0) || ++ (((int)(bt->brp) - 1) < 0)) ++ return -EINVAL; ++ ++ priv->write_reg(priv, CANFD_S_SEG_1_OFFSET, bittiming_temp); ++ ++ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) { ++ dat_bittiming = ((dbt->phase_seg1 + dbt->prop_seg + 1 - 2) << SEG_1_SHIFT) | ++ ((dbt->phase_seg2 - 1) << SEG_2_SHIFT) | ++ ((dbt->sjw - 1) << SJW_SHIFT) | ++ ((dbt->brp - 1) << PRESC_SHIFT); ++ ++ if ((((int)(dbt->phase_seg1 + dbt->prop_seg + 1) - 2) < 0) || ++ (((int)(dbt->phase_seg2) - 1) < 0) || ++ (((int)(dbt->sjw) - 1) < 0) || ++ (((int)(dbt->brp) - 1) < 0)) ++ return -EINVAL; ++ ++ priv->write_reg(priv, CANFD_F_SEG_1_OFFSET, dat_bittiming); ++ } ++ ++ canfd_reigister_off_bit(priv, CANFD_CFG_STAT_OFFSET, CAN_FD_OFF_RST_MASK); ++ ++ netdev_dbg(ndev, "Slow bit rate: %08x\n", priv->read_reg(priv, CANFD_S_SEG_1_OFFSET)); ++ netdev_dbg(ndev, "Fast bit rate: %08x\n", priv->read_reg(priv, CANFD_F_SEG_1_OFFSET)); ++ ++ return 0; ++} ++ ++int canfd_get_freebuffer(struct ipms_canfd_priv *priv) ++{ ++ /* Get next transmit buffer */ ++ canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_TENEXT_MASK); ++ ++ if (can_ioread8(priv->reg_base + CANFD_TCTRL_OFFSET) & CAN_FD_SET_TENEXT_MASK) ++ return -1; ++ ++ return 0; ++} ++ ++static void canfd_tx_interrupt(struct net_device *ndev, u8 isr) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ ++ /* wait till transmission of the PTB or STB finished */ ++ while (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) { ++ if (isr & CAN_FD_SET_TPIF_MASK) ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_TPIF_MASK); ++ ++ if (isr & CAN_FD_SET_TSIF_MASK) ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_TSIF_MASK); ++ ++ isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET); ++ } ++ netif_wake_queue(ndev); ++} ++ ++static int can_rx(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ struct can_frame *cf; ++ struct sk_buff *skb; ++ u32 can_id; ++ u8 dlc, control, rx_status; ++ ++ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ ++ if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK)) ++ return 0; ++ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET); ++ can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET); ++ dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK; ++ ++ skb = alloc_can_skb(ndev, (struct can_frame **)&cf); ++ if (!skb) { ++ stats->rx_dropped++; ++ return 0; ++ } ++ cf->can_dlc = can_cc_dlc2len(dlc); ++ ++ /* change the CANFD id into socketcan id format */ ++ if (control & CAN_FD_SET_IDE_MASK) { ++ cf->can_id = can_id; ++ cf->can_id |= CAN_EFF_FLAG; ++ } else { ++ cf->can_id = can_id; ++ cf->can_id &= (~CAN_EFF_FLAG); ++ } ++ ++ if (control & CAN_FD_SET_RTR_MASK) ++ cf->can_id |= CAN_RTR_FLAG; ++ ++ if (!(control & CAN_FD_SET_RTR_MASK)) { ++ *((u32 *)(cf->data + 0)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET); ++ *((u32 *)(cf->data + 4)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + 4); ++ } ++ ++ canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK); ++ stats->rx_bytes += can_fd_dlc2len(cf->can_dlc); ++ stats->rx_packets++; ++ netif_receive_skb(skb); ++ ++ return 1; ++} ++ ++static int canfd_rx(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ struct canfd_frame *cf; ++ struct sk_buff *skb; ++ u32 can_id; ++ u8 dlc, control, rx_status; ++ int i; ++ ++ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ ++ if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK)) ++ return 0; ++ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET); ++ can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET); ++ dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK; ++ ++ if (control & CAN_FD_SET_EDL_MASK) ++ /* allocate sk_buffer for canfd frame */ ++ skb = alloc_canfd_skb(ndev, &cf); ++ else ++ /* allocate sk_buffer for can frame */ ++ skb = alloc_can_skb(ndev, (struct can_frame **)&cf); ++ ++ if (!skb) { ++ stats->rx_dropped++; ++ return 0; ++ } ++ ++ /* change the CANFD or CAN2.0 data into socketcan data format */ ++ if (control & CAN_FD_SET_EDL_MASK) ++ cf->len = can_fd_dlc2len(dlc); ++ else ++ cf->len = can_cc_dlc2len(dlc); ++ ++ /* change the CANFD id into socketcan id format */ ++ if (control & CAN_FD_SET_EDL_MASK) { ++ cf->can_id = can_id; ++ if (control & CAN_FD_SET_IDE_MASK) ++ cf->can_id |= CAN_EFF_FLAG; ++ else ++ cf->can_id &= (~CAN_EFF_FLAG); ++ } else { ++ cf->can_id = can_id; ++ if (control & CAN_FD_SET_IDE_MASK) ++ cf->can_id |= CAN_EFF_FLAG; ++ else ++ cf->can_id &= (~CAN_EFF_FLAG); ++ ++ if (control & CAN_FD_SET_RTR_MASK) ++ cf->can_id |= CAN_RTR_FLAG; ++ } ++ ++ /* CANFD frames handed over to SKB */ ++ if (control & CAN_FD_SET_EDL_MASK) { ++ for (i = 0; i < cf->len; i += 4) ++ *((u32 *)(cf->data + i)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + i); ++ } else { ++ /* skb reads the received datas, if the RTR bit not set */ ++ if (!(control & CAN_FD_SET_RTR_MASK)) { ++ *((u32 *)(cf->data + 0)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET); ++ *((u32 *)(cf->data + 4)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + 4); ++ } ++ } ++ ++ canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK); ++ ++ stats->rx_bytes += cf->len; ++ stats->rx_packets++; ++ netif_receive_skb(skb); ++ ++ return 1; ++} ++ ++static int canfd_rx_poll(struct napi_struct *napi, int quota) ++{ ++ struct net_device *ndev = napi->dev; ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ int work_done = 0; ++ u8 rx_status = 0, control = 0; ++ ++ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET); ++ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ ++ /* clear receive interrupt and deal with all the received frames */ ++ while ((rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK) && (work_done < quota)) { ++ (control & CAN_FD_SET_EDL_MASK) ? (work_done += canfd_rx(ndev)) : (work_done += can_rx(ndev)); ++ ++ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET); ++ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ } ++ napi_complete(napi); ++ canfd_reigister_set_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_SET_RIE_MASK); ++ return work_done; ++} ++ ++static void canfd_rxfull_interrupt(struct net_device *ndev, u8 isr) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ ++ if (isr & CAN_FD_SET_RAFIF_MASK) ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RAFIF_MASK); ++ ++ if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, ++ (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)); ++} ++ ++static int set_canfd_xmit_mode(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ ++ switch (priv->tx_mode) { ++ case XMIT_FULL: ++ canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_FULLCAN_MASK); ++ break; ++ case XMIT_SEP_FIFO: ++ canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FULLCAN_MASK); ++ canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_FIFO_MASK); ++ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TBSEL_MASK); ++ break; ++ case XMIT_SEP_PRIO: ++ canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FULLCAN_MASK); ++ canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FIFO_MASK); ++ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TBSEL_MASK); ++ break; ++ case XMIT_PTB_MODE: ++ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_OFF_TBSEL_MASK); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static netdev_tx_t canfd_driver_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ struct canfd_frame *cf = (struct canfd_frame *)skb->data; ++ struct net_device_stats *stats = &ndev->stats; ++ u32 ttsen, id, ctl, addr_off; ++ int i; ++ ++ priv->tx_mode = XMIT_PTB_MODE; ++ ++ if (can_dropped_invalid_skb(ndev, skb)) ++ return NETDEV_TX_OK; ++ ++ switch (priv->tx_mode) { ++ case XMIT_FULL: ++ return NETDEV_TX_BUSY; ++ case XMIT_PTB_MODE: ++ set_canfd_xmit_mode(ndev); ++ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_OFF_STBY_MASK); ++ ++ if (cf->can_id & CAN_EFF_FLAG) { ++ id = (cf->can_id & CAN_EFF_MASK); ++ ttsen = 0 << TTSEN_8_32_SHIFT; ++ id |= ttsen; ++ } else { ++ id = (cf->can_id & CAN_SFF_MASK); ++ ttsen = 0 << TTSEN_8_32_SHIFT; ++ id |= ttsen; ++ } ++ ++ ctl = can_fd_len2dlc(cf->len); ++ ++ /* transmit can fd frame */ ++ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) { ++ if (can_is_canfd_skb(skb)) { ++ if (cf->can_id & CAN_EFF_FLAG) ++ ctl |= CAN_FD_SET_IDE_MASK; ++ else ++ ctl &= CAN_FD_OFF_IDE_MASK; ++ ++ if (cf->flags & CANFD_BRS) ++ ctl |= CAN_FD_SET_BRS_MASK; ++ ++ ctl |= CAN_FD_SET_EDL_MASK; ++ ++ addr_off = CANFD_TBUF_DATA_OFFSET; ++ ++ for (i = 0; i < cf->len; i += 4) { ++ priv->write_reg(priv, addr_off, ++ *((u32 *)(cf->data + i))); ++ addr_off += 4; ++ } ++ } else { ++ ctl &= CAN_FD_OFF_EDL_MASK; ++ ctl &= CAN_FD_OFF_BRS_MASK; ++ ++ if (cf->can_id & CAN_EFF_FLAG) ++ ctl |= CAN_FD_SET_IDE_MASK; ++ else ++ ctl &= CAN_FD_OFF_IDE_MASK; ++ ++ if (cf->can_id & CAN_RTR_FLAG) { ++ ctl |= CAN_FD_SET_RTR_MASK; ++ priv->write_reg(priv, ++ CANFD_TBUF_ID_OFFSET, id); ++ priv->write_reg(priv, ++ CANFD_TBUF_CTL_OFFSET, ctl); ++ } else { ++ ctl &= CAN_FD_OFF_RTR_MASK; ++ addr_off = CANFD_TBUF_DATA_OFFSET; ++ priv->write_reg(priv, addr_off, ++ *((u32 *)(cf->data + 0))); ++ priv->write_reg(priv, addr_off + 4, ++ *((u32 *)(cf->data + 4))); ++ } ++ } ++ priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id); ++ priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl); ++ addr_off = CANFD_TBUF_DATA_OFFSET; ++ } else { ++ ctl &= CAN_FD_OFF_EDL_MASK; ++ ctl &= CAN_FD_OFF_BRS_MASK; ++ ++ if (cf->can_id & CAN_EFF_FLAG) ++ ctl |= CAN_FD_SET_IDE_MASK; ++ else ++ ctl &= CAN_FD_OFF_IDE_MASK; ++ ++ if (cf->can_id & CAN_RTR_FLAG) { ++ ctl |= CAN_FD_SET_RTR_MASK; ++ priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id); ++ priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl); ++ } else { ++ ctl &= CAN_FD_OFF_RTR_MASK; ++ priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id); ++ priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl); ++ addr_off = CANFD_TBUF_DATA_OFFSET; ++ priv->write_reg(priv, addr_off, ++ *((u32 *)(cf->data + 0))); ++ priv->write_reg(priv, addr_off + 4, ++ *((u32 *)(cf->data + 4))); ++ } ++ } ++ canfd_reigister_set_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TPE_MASK); ++ stats->tx_bytes += cf->len; ++ break; ++ default: ++ break; ++ } ++ ++ /*Due to cache blocking, we need call dev_kfree_skb() here to free the socket ++ buffer and return NETDEV_TX_OK */ ++ dev_kfree_skb(skb); ++ ++ return NETDEV_TX_OK; ++} ++ ++static int set_reset_mode(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ u8 ret; ++ ++ ret = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ ret |= CAN_FD_SET_RST_MASK; ++ can_iowrite8(ret, priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ ++ return 0; ++} ++ ++static void canfd_driver_stop(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ int ret; ++ ++ ret = set_reset_mode(ndev); ++ if (ret) ++ netdev_err(ndev, "Mode Resetting Failed!\n"); ++ ++ priv->can.state = CAN_STATE_STOPPED; ++} ++ ++static int canfd_driver_close(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ ++ netif_stop_queue(ndev); ++ napi_disable(&priv->napi); ++ canfd_driver_stop(ndev); ++ ++ free_irq(ndev->irq, ndev); ++ close_candev(ndev); ++ ++ pm_runtime_put(priv->dev); ++ ++ return 0; ++} ++ ++static enum can_state get_of_chip_status(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ u8 can_stat, eir; ++ ++ can_stat = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET); ++ ++ if (can_stat & CAN_FD_SET_BUSOFF_MASK) ++ return CAN_STATE_BUS_OFF; ++ ++ if ((eir & CAN_FD_SET_EPASS_MASK) && ~(can_stat & CAN_FD_SET_BUSOFF_MASK)) ++ return CAN_STATE_ERROR_PASSIVE; ++ ++ if (eir & CAN_FD_SET_EWARN_MASK && ~(eir & CAN_FD_SET_EPASS_MASK)) ++ return CAN_STATE_ERROR_WARNING; ++ ++ if (~(eir & CAN_FD_SET_EPASS_MASK)) ++ return CAN_STATE_ERROR_ACTIVE; ++ ++ return CAN_STATE_ERROR_ACTIVE; ++} ++ ++static void canfd_error_interrupt(struct net_device *ndev, u8 isr, u8 eir) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ struct can_frame *cf; ++ struct sk_buff *skb; ++ u8 koer, recnt = 0, tecnt = 0, can_stat = 0; ++ ++ skb = alloc_can_err_skb(ndev, &cf); ++ ++ koer = can_ioread8(priv->reg_base + CANFD_EALCAP_OFFSET) & CAN_FD_SET_KOER_MASK; ++ recnt = can_ioread8(priv->reg_base + CANFD_RECNT_OFFSET); ++ tecnt = can_ioread8(priv->reg_base + CANFD_TECNT_OFFSET); ++ ++ /*Read can status*/ ++ can_stat = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ ++ /* Bus off --->active error mode */ ++ if ((isr & CAN_FD_SET_EIF_MASK) && priv->can.state == CAN_STATE_BUS_OFF) ++ priv->can.state = get_of_chip_status(ndev); ++ ++ /* State selection */ ++ if (can_stat & CAN_FD_SET_BUSOFF_MASK) { ++ priv->can.state = get_of_chip_status(ndev); ++ priv->can.can_stats.bus_off++; ++ canfd_reigister_set_bit(priv, CANFD_CFG_STAT_OFFSET, CAN_FD_SET_BUSOFF_MASK); ++ can_bus_off(ndev); ++ if (skb) ++ cf->can_id |= CAN_ERR_BUSOFF; ++ ++ } else if ((eir & CAN_FD_SET_EPASS_MASK) && ~(can_stat & CAN_FD_SET_BUSOFF_MASK)) { ++ priv->can.state = get_of_chip_status(ndev); ++ priv->can.can_stats.error_passive++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] |= (recnt > 127) ? CAN_ERR_CRTL_RX_PASSIVE : 0; ++ cf->data[1] |= (tecnt > 127) ? CAN_ERR_CRTL_TX_PASSIVE : 0; ++ cf->data[6] = tecnt; ++ cf->data[7] = recnt; ++ } ++ } else if (eir & CAN_FD_SET_EWARN_MASK && ~(eir & CAN_FD_SET_EPASS_MASK)) { ++ priv->can.state = get_of_chip_status(ndev); ++ priv->can.can_stats.error_warning++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] |= (recnt > 95) ? CAN_ERR_CRTL_RX_WARNING : 0; ++ cf->data[1] |= (tecnt > 95) ? CAN_ERR_CRTL_TX_WARNING : 0; ++ cf->data[6] = tecnt; ++ cf->data[7] = recnt; ++ } ++ } ++ ++ /* Check for in protocol defined error interrupt */ ++ if (eir & CAN_FD_SET_BEIF_MASK) { ++ if (skb) ++ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; ++ ++ /* bit error interrupt */ ++ if (koer == CAN_FD_SET_BIT_ERROR_MASK) { ++ stats->tx_errors++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[2] = CAN_ERR_PROT_BIT; ++ } ++ } ++ /* format error interrupt */ ++ if (koer == CAN_FD_SET_FORM_ERROR_MASK) { ++ stats->rx_errors++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[2] = CAN_ERR_PROT_FORM; ++ } ++ } ++ /* stuffing error interrupt */ ++ if (koer == CAN_FD_SET_STUFF_ERROR_MASK) { ++ stats->rx_errors++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[3] = CAN_ERR_PROT_STUFF; ++ } ++ } ++ /* ack error interrupt */ ++ if (koer == CAN_FD_SET_ACK_ERROR_MASK) { ++ stats->tx_errors++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[2] = CAN_ERR_PROT_LOC_ACK; ++ } ++ } ++ /* crc error interrupt */ ++ if (koer == CAN_FD_SET_CRC_ERROR_MASK) { ++ stats->rx_errors++; ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[2] = CAN_ERR_PROT_LOC_CRC_SEQ; ++ } ++ } ++ priv->can.can_stats.bus_error++; ++ } ++ if (skb) { ++ stats->rx_packets++; ++ stats->rx_bytes += cf->can_dlc; ++ netif_rx(skb); ++ } ++ ++ netdev_dbg(ndev, "Recnt is 0x%02x", can_ioread8(priv->reg_base + CANFD_RECNT_OFFSET)); ++ netdev_dbg(ndev, "Tecnt is 0x%02x", can_ioread8(priv->reg_base + CANFD_TECNT_OFFSET)); ++} ++ ++static irqreturn_t canfd_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *ndev = (struct net_device *)dev_id; ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ u8 isr, eir; ++ u8 isr_handled = 0, eir_handled = 0; ++ ++ /* read the value of interrupt status register */ ++ isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET); ++ ++ /* read the value of error interrupt register */ ++ eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET); ++ ++ /* Check for Tx interrupt and Processing it */ ++ if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) { ++ canfd_tx_interrupt(ndev, isr); ++ isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK); ++ } ++ if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) { ++ canfd_rxfull_interrupt(ndev, isr); ++ isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK); ++ } ++ /* Check Rx interrupt and Processing the receive interrupt routine */ ++ if (isr & CAN_FD_SET_RIF_MASK) { ++ canfd_reigister_off_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_OFF_RIE_MASK); ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RIF_MASK); ++ ++ napi_schedule(&priv->napi); ++ isr_handled |= CAN_FD_SET_RIF_MASK; ++ } ++ if ((isr & CAN_FD_SET_EIF_MASK) | (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK))) { ++ /* reset EPIF and BEIF. Reset EIF */ ++ canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET, ++ eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK)); ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, ++ isr & CAN_FD_SET_EIF_MASK); ++ ++ canfd_error_interrupt(ndev, isr, eir); ++ ++ isr_handled |= CAN_FD_SET_EIF_MASK; ++ eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK); ++ } ++ if ((isr_handled == 0) && (eir_handled == 0)) { ++ netdev_err(ndev, "Unhandled interrupt!\n"); ++ return IRQ_NONE; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int canfd_chip_start(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ int err; ++ u8 ret; ++ ++ err = set_reset_mode(ndev); ++ if (err) { ++ netdev_err(ndev, "Mode Resetting Failed!\n"); ++ return err; ++ } ++ ++ err = canfd_device_driver_bittime_configuration(ndev); ++ if (err) { ++ netdev_err(ndev, "Bittime Setting Failed!\n"); ++ return err; ++ } ++ ++ /* Set Almost Full Warning Limit */ ++ canfd_reigister_set_bit(priv, CANFD_LIMIT_OFFSET, CAN_FD_SET_AFWL_MASK); ++ ++ /* Programmable Error Warning Limit = (EWL+1)*8. Set EWL=11->Error Warning=96 */ ++ canfd_reigister_set_bit(priv, CANFD_LIMIT_OFFSET, CAN_FD_SET_EWL_MASK); ++ ++ /* Interrupts enable */ ++ can_iowrite8(CAN_FD_INTR_ALL_MASK, priv->reg_base + CANFD_RTIE_OFFSET); ++ ++ /* Error Interrupts enable(Error Passive and Bus Error) */ ++ canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET, CAN_FD_SET_EPIE_MASK); ++ ++ ret = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ ++ /* Check whether it is loopback mode or normal mode */ ++ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { ++ ret |= CAN_FD_LBMIMOD_MASK; ++ } else { ++ ret &= ~CAN_FD_LBMEMOD_MASK; ++ ret &= ~CAN_FD_LBMIMOD_MASK; ++ } ++ ++ can_iowrite8(ret, priv->reg_base + CANFD_CFG_STAT_OFFSET); ++ ++ priv->can.state = CAN_STATE_ERROR_ACTIVE; ++ ++ return 0; ++} ++ ++static int canfd_do_set_mode(struct net_device *ndev, enum can_mode mode) ++{ ++ int ret; ++ ++ switch (mode) { ++ case CAN_MODE_START: ++ ret = canfd_chip_start(ndev); ++ if (ret) { ++ netdev_err(ndev, "Could Not Start CAN device !!\n"); ++ return ret; ++ } ++ netif_wake_queue(ndev); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int canfd_driver_open(struct net_device *ndev) ++{ ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ int ret; ++ ++ ret = pm_runtime_get_sync(priv->dev); ++ if (ret < 0) { ++ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", ++ __func__, ret); ++ goto err; ++ } ++ ++ /* Set chip into reset mode */ ++ ret = set_reset_mode(ndev); ++ if (ret) { ++ netdev_err(ndev, "Mode Resetting Failed!\n"); ++ return ret; ++ } ++ ++ /* Common open */ ++ ret = open_candev(ndev); ++ if (ret) ++ return ret; ++ ++ /* Register interrupt handler */ ++ ret = request_irq(ndev->irq, canfd_interrupt, IRQF_SHARED, ndev->name, ndev); ++ if (ret) { ++ netdev_err(ndev, "Request_irq err: %d\n", ret); ++ goto exit_irq; ++ } ++ ++ ret = canfd_chip_start(ndev); ++ if (ret) { ++ netdev_err(ndev, "Could Not Start CAN device !\n"); ++ goto exit_can_start; ++ } ++ ++ napi_enable(&priv->napi); ++ netif_start_queue(ndev); ++ ++ return 0; ++ ++exit_can_start: ++ free_irq(ndev->irq, ndev); ++err: ++ pm_runtime_put(priv->dev); ++exit_irq: ++ close_candev(ndev); ++ return ret; ++} ++ ++static int canfd_control_parse_dt(struct ipms_canfd_priv *priv) ++{ ++ struct of_phandle_args args; ++ u32 syscon_mask, syscon_shift; ++ u32 can_or_canfd; ++ u32 syscon_offset, regval; ++ int ret; ++ ++ ret = of_parse_phandle_with_fixed_args(priv->dev->of_node, ++ "starfive,sys-syscon", 3, 0, &args); ++ if (ret) { ++ dev_err(priv->dev, "Failed to parse starfive,sys-syscon\n"); ++ return -EINVAL; ++ } ++ ++ priv->reg_syscon = syscon_node_to_regmap(args.np); ++ of_node_put(args.np); ++ if (IS_ERR(priv->reg_syscon)) ++ return PTR_ERR(priv->reg_syscon); ++ ++ syscon_offset = args.args[0]; ++ syscon_shift = args.args[1]; ++ syscon_mask = args.args[2]; ++ ++ ret = device_property_read_u32(priv->dev, "syscon,can_or_canfd", &can_or_canfd); ++ if (ret) ++ goto exit_parse; ++ ++ priv->can_or_canfd = can_or_canfd; ++ ++ /* enable can2.0/canfd function */ ++ regval = can_or_canfd << syscon_shift; ++ ret = regmap_update_bits(priv->reg_syscon, syscon_offset, syscon_mask, regval); ++ if (ret) ++ return ret; ++ return 0; ++exit_parse: ++ return ret; ++} ++ ++static const struct net_device_ops canfd_netdev_ops = { ++ .ndo_open = canfd_driver_open, ++ .ndo_stop = canfd_driver_close, ++ .ndo_start_xmit = canfd_driver_start_xmit, ++ .ndo_change_mtu = can_change_mtu, ++}; ++ ++static int canfd_driver_probe(struct platform_device *pdev) ++{ ++ struct net_device *ndev; ++ struct ipms_canfd_priv *priv; ++ void __iomem *addr; ++ int ret; ++ u32 frq; ++ ++ addr = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(addr)) { ++ ret = PTR_ERR(addr); ++ goto exit; ++ } ++ ++ ndev = alloc_candev(sizeof(struct ipms_canfd_priv), 1); ++ if (!ndev) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ priv = netdev_priv(ndev); ++ priv->dev = &pdev->dev; ++ ++ ret = canfd_control_parse_dt(priv); ++ if (ret) ++ goto free_exit; ++ ++ priv->nr_clks = devm_clk_bulk_get_all(priv->dev, &priv->clks); ++ if (priv->nr_clks < 0) { ++ dev_err(priv->dev, "Failed to get can clocks\n"); ++ ret = -ENODEV; ++ goto free_exit; ++ } ++ ++ ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks); ++ if (ret) { ++ dev_err(priv->dev, "Failed to enable clocks\n"); ++ goto free_exit; ++ } ++ ++ priv->resets = devm_reset_control_array_get_exclusive(priv->dev); ++ if (IS_ERR(priv->resets)) { ++ ret = PTR_ERR(priv->resets); ++ dev_err(priv->dev, "Failed to get can resets"); ++ goto clk_exit; ++ } ++ ++ ret = reset_control_deassert(priv->resets); ++ if (ret) ++ goto clk_exit; ++ priv->can.bittiming_const = &canfd_bittiming_const; ++ priv->can.data_bittiming_const = &canfd_data_bittiming_const; ++ priv->can.do_set_mode = canfd_do_set_mode; ++ ++ /* in user space the execution mode can be chosen */ ++ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) ++ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_FD; ++ else ++ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK; ++ priv->reg_base = addr; ++ priv->write_reg = canfd_write_reg_le; ++ priv->read_reg = canfd_read_reg_le; ++ ++ pm_runtime_enable(&pdev->dev); ++ ++ priv->can_clk = devm_clk_get(&pdev->dev, "core_clk"); ++ if (IS_ERR(priv->can_clk)) { ++ dev_err(&pdev->dev, "Device clock not found.\n"); ++ ret = PTR_ERR(priv->can_clk); ++ goto reset_exit; ++ } ++ ++ device_property_read_u32(priv->dev, "frequency", &frq); ++ clk_set_rate(priv->can_clk, frq); ++ ++ priv->can.clock.freq = clk_get_rate(priv->can_clk); ++ ndev->irq = platform_get_irq(pdev, 0); ++ ++ /* we support local echo */ ++ ndev->flags |= IFF_ECHO; ++ ndev->netdev_ops = &canfd_netdev_ops; ++ ++ platform_set_drvdata(pdev, ndev); ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ++ netif_napi_add(ndev, &priv->napi, canfd_rx_poll); ++ ret = register_candev(ndev); ++ if (ret) { ++ dev_err(&pdev->dev, "Fail to register failed (err=%d)\n", ret); ++ goto reset_exit; ++ } ++ ++ dev_dbg(&pdev->dev, "Driver registered: regs=%p, irp=%d, clock=%d\n", ++ priv->reg_base, ndev->irq, priv->can.clock.freq); ++ ++ return 0; ++ ++reset_exit: ++ reset_control_assert(priv->resets); ++clk_exit: ++ clk_bulk_disable_unprepare(priv->nr_clks, priv->clks); ++free_exit: ++ free_candev(ndev); ++exit: ++ return ret; ++} ++ ++static void canfd_driver_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ ++ reset_control_assert(priv->resets); ++ clk_bulk_disable_unprepare(priv->nr_clks, priv->clks); ++ pm_runtime_disable(&pdev->dev); ++ ++ unregister_candev(ndev); ++ netif_napi_del(&priv->napi); ++ free_candev(ndev); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int __maybe_unused canfd_suspend(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ ++ if (netif_running(ndev)) { ++ netif_stop_queue(ndev); ++ netif_device_detach(ndev); ++ canfd_driver_stop(ndev); ++ } ++ ++ return pm_runtime_force_suspend(dev); ++} ++ ++static int __maybe_unused canfd_resume(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(dev, "pm_runtime_force_resume failed on resume\n"); ++ return ret; ++ } ++ ++ if (netif_running(ndev)) { ++ ret = canfd_chip_start(ndev); ++ if (ret) { ++ dev_err(dev, "canfd_chip_start failed on resume\n"); ++ return ret; ++ } ++ ++ netif_device_attach(ndev); ++ netif_start_queue(ndev); ++ } ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int canfd_runtime_suspend(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ ++ reset_control_assert(priv->resets); ++ clk_bulk_disable_unprepare(priv->nr_clks, priv->clks); ++ ++ return 0; ++} ++ ++static int canfd_runtime_resume(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct ipms_canfd_priv *priv = netdev_priv(ndev); ++ int ret; ++ ++ ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks); ++ if (ret) { ++ dev_err(dev, "Failed to prepare_enable clk\n"); ++ return ret; ++ } ++ ++ ret = reset_control_deassert(priv->resets); ++ if (ret) { ++ dev_err(dev, "Failed to deassert reset\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops canfd_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(canfd_suspend, canfd_resume) ++ SET_RUNTIME_PM_OPS(canfd_runtime_suspend, ++ canfd_runtime_resume, NULL) ++}; ++ ++static const struct of_device_id canfd_of_match[] = { ++ { .compatible = "ipms,can" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, canfd_of_match); ++ ++static struct platform_driver can_driver = { ++ .probe = canfd_driver_probe, ++ .remove = canfd_driver_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .pm = &canfd_pm_ops, ++ .of_match_table = canfd_of_match, ++ }, ++}; ++ ++module_platform_driver(can_driver); ++ ++MODULE_DESCRIPTION("ipms can controller driver for StarFive jh7110 SoC"); ++MODULE_AUTHOR("William Qiu +Date: Sat, 12 Oct 2024 17:56:00 +0800 +Subject: [PATCH 12/55] ipms: CAN: Solve CAN packet leakage problem + +Improve RX interrupt trigger mechanism, reduce buffer trigger condition, +and increase polling value to solve the problem of CAN packet leakage. + +Signed-off-by: William Qiu +--- + drivers/net/can/ipms_canfd.c | 108 +++++++++++++++++++---------------- + 1 file changed, 59 insertions(+), 49 deletions(-) + +--- a/drivers/net/can/ipms_canfd.c ++++ b/drivers/net/can/ipms_canfd.c +@@ -5,28 +5,30 @@ + * Copyright (c) 2022 StarFive Technology Co., Ltd. + */ + ++#include ++#include + #include +-#include + #include + #include + #include + #include ++#include + #include ++#include + #include + #include + #include ++#include + #include ++#include ++#include ++#include + #include + #include + #include +-#include +-#include +-#include +-#include +-#include +-#include + + #define DRIVER_NAME "ipms_canfd" ++#define MAX_IRQ 16 + + /* CAN registers set */ + enum canfd_device_reg { +@@ -124,7 +126,7 @@ enum canfd_reg_bitchange { + CAN_FD_SET_BEIF_MASK = 0x01, + CAN_FD_OFF_EPIE_MASK = 0xdf, + CAN_FD_OFF_BEIE_MASK = 0xfd, +- CAN_FD_SET_AFWL_MASK = 0x40, ++ CAN_FD_SET_AFWL_MASK = 0x20, + CAN_FD_SET_EWL_MASK = 0x0b, + CAN_FD_SET_KOER_MASK = 0xe0, + CAN_FD_SET_BIT_ERROR_MASK = 0x20, +@@ -366,12 +368,8 @@ static int can_rx(struct net_device *nde + struct can_frame *cf; + struct sk_buff *skb; + u32 can_id; +- u8 dlc, control, rx_status; +- +- rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ u8 dlc, control; + +- if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK)) +- return 0; + control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET); + can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET); + dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK; +@@ -403,7 +401,7 @@ static int can_rx(struct net_device *nde + canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK); + stats->rx_bytes += can_fd_dlc2len(cf->can_dlc); + stats->rx_packets++; +- netif_receive_skb(skb); ++ netif_rx(skb); + + return 1; + } +@@ -419,9 +417,9 @@ static int canfd_rx(struct net_device *n + int i; + + rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); +- + if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK)) + return 0; ++ + control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET); + can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET); + dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK; +@@ -557,6 +555,8 @@ static netdev_tx_t canfd_driver_start_xm + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + ++ netif_stop_queue(ndev); ++ + switch (priv->tx_mode) { + case XMIT_FULL: + return NETDEV_TX_BUSY; +@@ -837,46 +837,56 @@ static irqreturn_t canfd_interrupt(int i + { + struct net_device *ndev = (struct net_device *)dev_id; + struct ipms_canfd_priv *priv = netdev_priv(ndev); +- u8 isr, eir; ++ u8 isr, eir, rx_status; + u8 isr_handled = 0, eir_handled = 0; ++ int num = 0; + +- /* read the value of interrupt status register */ +- isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET); +- +- /* read the value of error interrupt register */ +- eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET); ++ while (((isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET)) || ++ (eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET))) && ++ num < MAX_IRQ) { ++ num++; ++ ++ /* Check for Tx interrupt and Processing it */ ++ if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) { ++ canfd_tx_interrupt(ndev, isr); ++ isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK); ++ break; ++ } + +- /* Check for Tx interrupt and Processing it */ +- if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) { +- canfd_tx_interrupt(ndev, isr); +- isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK); +- } +- if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) { +- canfd_rxfull_interrupt(ndev, isr); +- isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK); +- } +- /* Check Rx interrupt and Processing the receive interrupt routine */ +- if (isr & CAN_FD_SET_RIF_MASK) { +- canfd_reigister_off_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_OFF_RIE_MASK); +- canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RIF_MASK); +- +- napi_schedule(&priv->napi); +- isr_handled |= CAN_FD_SET_RIF_MASK; +- } +- if ((isr & CAN_FD_SET_EIF_MASK) | (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK))) { +- /* reset EPIF and BEIF. Reset EIF */ +- canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET, +- eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK)); +- canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, +- isr & CAN_FD_SET_EIF_MASK); ++ if (unlikely(isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK))) { ++ canfd_rxfull_interrupt(ndev, isr); ++ isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK); ++ } + +- canfd_error_interrupt(ndev, isr, eir); ++ /* Check Rx interrupt and Processing the receive interrupt routine */ ++ if (isr & CAN_FD_SET_RIF_MASK) { ++ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ while (rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK) { ++ can_rx(ndev); ++ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET); ++ } ++ isr_handled |= CAN_FD_SET_RIF_MASK; ++ } + +- isr_handled |= CAN_FD_SET_EIF_MASK; +- eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK); ++ if (unlikely((isr & CAN_FD_SET_EIF_MASK) | ++ (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK)))) { ++ /* reset EPIF and BEIF. Reset EIF */ ++ canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET, ++ eir & (CAN_FD_SET_EPIF_MASK | ++ CAN_FD_SET_BEIF_MASK)); ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, ++ isr & CAN_FD_SET_EIF_MASK); ++ canfd_error_interrupt(ndev, isr, eir); ++ isr_handled |= CAN_FD_SET_EIF_MASK; ++ eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK); ++ } ++ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, isr); + } +- if ((isr_handled == 0) && (eir_handled == 0)) { +- netdev_err(ndev, "Unhandled interrupt!\n"); ++ ++ if (num == 0) { ++ isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET); ++ eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET); ++ netdev_err(ndev, "Unhandled interrupt!isr:%x,eir:%x\n", isr, eir); + return IRQ_NONE; + } + diff --git a/target/linux/starfive/patches-6.12/0013-drivers-nvme-Add-precheck-and-delay-for-CQE-pending-.patch b/target/linux/starfive/patches-6.12/0013-drivers-nvme-Add-precheck-and-delay-for-CQE-pending-.patch new file mode 100644 index 0000000000..ef84c85305 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0013-drivers-nvme-Add-precheck-and-delay-for-CQE-pending-.patch @@ -0,0 +1,40 @@ +From 63ebc39891f7b292197f653f8f3aa9dfe35135ee Mon Sep 17 00:00:00 2001 +From: "Kevin.xie" +Date: Thu, 24 Nov 2022 16:59:12 +0800 +Subject: [PATCH 13/55] drivers: nvme: Add precheck and delay for CQE pending + status. + +To workaroud the NVMe I/O timeout problem in bootup S10udev case +which caused by the CQE update lantancy. + +Signed-off-by: Kevin.xie +--- + drivers/nvme/host/pci.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include "trace.h" + #include "nvme.h" +@@ -1156,6 +1157,15 @@ static inline int nvme_poll_cq(struct nv + { + int found = 0; + ++ /* ++ * In some cases, such as udev trigger, cqe status may update ++ * a little bit later than MSI, which cause an irq handle missing. ++ * To workaound, here we will prefetch the status first, and wait ++ * 1us if we get nothing. ++ */ ++ if (!nvme_cqe_pending(nvmeq)) ++ udelay(1); ++ + while (nvme_cqe_pending(nvmeq)) { + found++; + /* diff --git a/target/linux/starfive/patches-6.12/0014-riscv-Optimize-memcpy-with-aligned-version.patch b/target/linux/starfive/patches-6.12/0014-riscv-Optimize-memcpy-with-aligned-version.patch new file mode 100644 index 0000000000..6b690ae942 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0014-riscv-Optimize-memcpy-with-aligned-version.patch @@ -0,0 +1,508 @@ +From 16fef31de538ce55e286b630d0b33d872707420d Mon Sep 17 00:00:00 2001 +From: Mason Huo +Date: Tue, 20 Jun 2023 13:37:52 +0800 +Subject: [PATCH 14/55] riscv: Optimize memcpy with aligned version + +Optimizing the 128 byte align case, this will improve the +performance of large block memcpy. + +Here we combine the memcpy of glibc and kernel. + +Signed-off-by: Mason Huo +Signed-off-by: Hal Feng +--- + arch/riscv/lib/Makefile | 3 +- + arch/riscv/lib/{memcpy.S => memcpy_aligned.S} | 37 +-- + arch/riscv/lib/string.c | 266 ++++++++++++++++++ + 3 files changed, 274 insertions(+), 32 deletions(-) + rename arch/riscv/lib/{memcpy.S => memcpy_aligned.S} (65%) + create mode 100644 arch/riscv/lib/string.c + +--- a/arch/riscv/lib/Makefile ++++ b/arch/riscv/lib/Makefile +@@ -1,6 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0-only + lib-y += delay.o +-lib-y += memcpy.o + lib-y += memset.o + lib-y += memmove.o + ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),) +@@ -16,6 +15,8 @@ lib-$(CONFIG_MMU) += uaccess.o + lib-$(CONFIG_64BIT) += tishift.o + lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o + lib-$(CONFIG_RISCV_ISA_ZBC) += crc32.o ++lib-y += string.o ++lib-y += memcpy_aligned.o + + obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o + lib-$(CONFIG_RISCV_ISA_V) += xor.o +--- a/arch/riscv/lib/memcpy.S ++++ /dev/null +@@ -1,110 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Copyright (C) 2013 Regents of the University of California +- */ +- +-#include +-#include +- +-/* void *memcpy(void *, const void *, size_t) */ +-SYM_FUNC_START(__memcpy) +- move t6, a0 /* Preserve return value */ +- +- /* Defer to byte-oriented copy for small sizes */ +- sltiu a3, a2, 128 +- bnez a3, 4f +- /* Use word-oriented copy only if low-order bits match */ +- andi a3, t6, SZREG-1 +- andi a4, a1, SZREG-1 +- bne a3, a4, 4f +- +- beqz a3, 2f /* Skip if already aligned */ +- /* +- * Round to nearest double word-aligned address +- * greater than or equal to start address +- */ +- andi a3, a1, ~(SZREG-1) +- addi a3, a3, SZREG +- /* Handle initial misalignment */ +- sub a4, a3, a1 +-1: +- lb a5, 0(a1) +- addi a1, a1, 1 +- sb a5, 0(t6) +- addi t6, t6, 1 +- bltu a1, a3, 1b +- sub a2, a2, a4 /* Update count */ +- +-2: +- andi a4, a2, ~((16*SZREG)-1) +- beqz a4, 4f +- add a3, a1, a4 +-3: +- REG_L a4, 0(a1) +- REG_L a5, SZREG(a1) +- REG_L a6, 2*SZREG(a1) +- REG_L a7, 3*SZREG(a1) +- REG_L t0, 4*SZREG(a1) +- REG_L t1, 5*SZREG(a1) +- REG_L t2, 6*SZREG(a1) +- REG_L t3, 7*SZREG(a1) +- REG_L t4, 8*SZREG(a1) +- REG_L t5, 9*SZREG(a1) +- REG_S a4, 0(t6) +- REG_S a5, SZREG(t6) +- REG_S a6, 2*SZREG(t6) +- REG_S a7, 3*SZREG(t6) +- REG_S t0, 4*SZREG(t6) +- REG_S t1, 5*SZREG(t6) +- REG_S t2, 6*SZREG(t6) +- REG_S t3, 7*SZREG(t6) +- REG_S t4, 8*SZREG(t6) +- REG_S t5, 9*SZREG(t6) +- REG_L a4, 10*SZREG(a1) +- REG_L a5, 11*SZREG(a1) +- REG_L a6, 12*SZREG(a1) +- REG_L a7, 13*SZREG(a1) +- REG_L t0, 14*SZREG(a1) +- REG_L t1, 15*SZREG(a1) +- addi a1, a1, 16*SZREG +- REG_S a4, 10*SZREG(t6) +- REG_S a5, 11*SZREG(t6) +- REG_S a6, 12*SZREG(t6) +- REG_S a7, 13*SZREG(t6) +- REG_S t0, 14*SZREG(t6) +- REG_S t1, 15*SZREG(t6) +- addi t6, t6, 16*SZREG +- bltu a1, a3, 3b +- andi a2, a2, (16*SZREG)-1 /* Update count */ +- +-4: +- /* Handle trailing misalignment */ +- beqz a2, 6f +- add a3, a1, a2 +- +- /* Use word-oriented copy if co-aligned to word boundary */ +- or a5, a1, t6 +- or a5, a5, a3 +- andi a5, a5, 3 +- bnez a5, 5f +-7: +- lw a4, 0(a1) +- addi a1, a1, 4 +- sw a4, 0(t6) +- addi t6, t6, 4 +- bltu a1, a3, 7b +- +- ret +- +-5: +- lb a4, 0(a1) +- addi a1, a1, 1 +- sb a4, 0(t6) +- addi t6, t6, 1 +- bltu a1, a3, 5b +-6: +- ret +-SYM_FUNC_END(__memcpy) +-SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy) +-SYM_FUNC_ALIAS(__pi_memcpy, __memcpy) +-SYM_FUNC_ALIAS(__pi___memcpy, __memcpy) +--- /dev/null ++++ b/arch/riscv/lib/memcpy_aligned.S +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2013 Regents of the University of California ++ */ ++ ++#include ++#include ++ ++/* void *__memcpy_aligned(void *, const void *, size_t) */ ++SYM_FUNC_START(__memcpy_aligned) ++ move t6, a0 /* Preserve return value */ ++ ++2: ++ andi a4, a2, ~((16*SZREG)-1) ++ beqz a4, 4f ++ add a3, a1, a4 ++3: ++ REG_L a4, 0(a1) ++ REG_L a5, SZREG(a1) ++ REG_L a6, 2*SZREG(a1) ++ REG_L a7, 3*SZREG(a1) ++ REG_L t0, 4*SZREG(a1) ++ REG_L t1, 5*SZREG(a1) ++ REG_L t2, 6*SZREG(a1) ++ REG_L t3, 7*SZREG(a1) ++ REG_L t4, 8*SZREG(a1) ++ REG_L t5, 9*SZREG(a1) ++ REG_S a4, 0(t6) ++ REG_S a5, SZREG(t6) ++ REG_S a6, 2*SZREG(t6) ++ REG_S a7, 3*SZREG(t6) ++ REG_S t0, 4*SZREG(t6) ++ REG_S t1, 5*SZREG(t6) ++ REG_S t2, 6*SZREG(t6) ++ REG_S t3, 7*SZREG(t6) ++ REG_S t4, 8*SZREG(t6) ++ REG_S t5, 9*SZREG(t6) ++ REG_L a4, 10*SZREG(a1) ++ REG_L a5, 11*SZREG(a1) ++ REG_L a6, 12*SZREG(a1) ++ REG_L a7, 13*SZREG(a1) ++ REG_L t0, 14*SZREG(a1) ++ REG_L t1, 15*SZREG(a1) ++ addi a1, a1, 16*SZREG ++ REG_S a4, 10*SZREG(t6) ++ REG_S a5, 11*SZREG(t6) ++ REG_S a6, 12*SZREG(t6) ++ REG_S a7, 13*SZREG(t6) ++ REG_S t0, 14*SZREG(t6) ++ REG_S t1, 15*SZREG(t6) ++ addi t6, t6, 16*SZREG ++ bltu a1, a3, 3b ++ andi a2, a2, (16*SZREG)-1 /* Update count */ ++ ++4: ++ /* Handle trailing misalignment */ ++ beqz a2, 6f ++ add a3, a1, a2 ++ ++ /* Use word-oriented copy if co-aligned to word boundary */ ++ or a5, a1, t6 ++ or a5, a5, a3 ++ andi a5, a5, 3 ++ bnez a5, 5f ++7: ++ lw a4, 0(a1) ++ addi a1, a1, 4 ++ sw a4, 0(t6) ++ addi t6, t6, 4 ++ bltu a1, a3, 7b ++ ++ ret ++ ++5: ++ lb a4, 0(a1) ++ addi a1, a1, 1 ++ sb a4, 0(t6) ++ addi t6, t6, 1 ++ bltu a1, a3, 5b ++6: ++ ret ++SYM_FUNC_END(__memcpy_aligned) ++SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy_aligned) ++SYM_FUNC_ALIAS(__pi_memcpy, __memcpy_aligned) ++SYM_FUNC_ALIAS(__pi___memcpy, __memcpy_aligned) +--- /dev/null ++++ b/arch/riscv/lib/string.c +@@ -0,0 +1,266 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copy memory to memory until the specified number of bytes ++ * has been copied. Overlap is NOT handled correctly. ++ * Copyright (C) 1991-2020 Free Software Foundation, Inc. ++ * This file is part of the GNU C Library. ++ * Contributed by Torbjorn Granlund (tege@sics.se). ++ * ++ * The GNU C Library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * The GNU C Library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with the GNU C Library; if not, see ++ * . ++ * ++ */ ++ ++#define __NO_FORTIFY ++#include ++#include ++ ++#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2))) ++#define OP_T_THRES 16 ++#define op_t unsigned long ++#define OPSIZ (sizeof(op_t)) ++#define OPSIZ_MASK (sizeof(op_t) - 1) ++#define FAST_COPY_THRES (128) ++#define byte unsigned char ++ ++static void _wordcopy_fwd_aligned(long dstp, long srcp, size_t len) ++{ ++ op_t a0, a1; ++ ++ switch (len % 8) { ++ case 2: ++ a0 = ((op_t *) srcp)[0]; ++ srcp -= 6 * OPSIZ; ++ dstp -= 7 * OPSIZ; ++ len += 6; ++ goto do1; ++ case 3: ++ a1 = ((op_t *) srcp)[0]; ++ srcp -= 5 * OPSIZ; ++ dstp -= 6 * OPSIZ; ++ len += 5; ++ goto do2; ++ case 4: ++ a0 = ((op_t *) srcp)[0]; ++ srcp -= 4 * OPSIZ; ++ dstp -= 5 * OPSIZ; ++ len += 4; ++ goto do3; ++ case 5: ++ a1 = ((op_t *) srcp)[0]; ++ srcp -= 3 * OPSIZ; ++ dstp -= 4 * OPSIZ; ++ len += 3; ++ goto do4; ++ case 6: ++ a0 = ((op_t *) srcp)[0]; ++ srcp -= 2 * OPSIZ; ++ dstp -= 3 * OPSIZ; ++ len += 2; ++ goto do5; ++ case 7: ++ a1 = ((op_t *) srcp)[0]; ++ srcp -= 1 * OPSIZ; ++ dstp -= 2 * OPSIZ; ++ len += 1; ++ goto do6; ++ ++ case 0: ++ if (OP_T_THRES <= 3 * OPSIZ && len == 0) ++ return; ++ a0 = ((op_t *) srcp)[0]; ++ srcp -= 0 * OPSIZ; ++ dstp -= 1 * OPSIZ; ++ goto do7; ++ case 1: ++ a1 = ((op_t *) srcp)[0]; ++ srcp -= -1 * OPSIZ; ++ dstp -= 0 * OPSIZ; ++ len -= 1; ++ if (OP_T_THRES <= 3 * OPSIZ && len == 0) ++ goto do0; ++ goto do8; /* No-op. */ ++ } ++ ++ do { ++do8: ++ a0 = ((op_t *) srcp)[0]; ++ ((op_t *) dstp)[0] = a1; ++do7: ++ a1 = ((op_t *) srcp)[1]; ++ ((op_t *) dstp)[1] = a0; ++do6: ++ a0 = ((op_t *) srcp)[2]; ++ ((op_t *) dstp)[2] = a1; ++do5: ++ a1 = ((op_t *) srcp)[3]; ++ ((op_t *) dstp)[3] = a0; ++do4: ++ a0 = ((op_t *) srcp)[4]; ++ ((op_t *) dstp)[4] = a1; ++do3: ++ a1 = ((op_t *) srcp)[5]; ++ ((op_t *) dstp)[5] = a0; ++do2: ++ a0 = ((op_t *) srcp)[6]; ++ ((op_t *) dstp)[6] = a1; ++do1: ++ a1 = ((op_t *) srcp)[7]; ++ ((op_t *) dstp)[7] = a0; ++ ++ srcp += 8 * OPSIZ; ++ dstp += 8 * OPSIZ; ++ len -= 8; ++ } while (len != 0); ++ ++ /* This is the right position for do0. Please don't move ++ * it into the loop. ++ */ ++do0: ++ ((op_t *) dstp)[0] = a1; ++} ++ ++static void _wordcopy_fwd_dest_aligned(long dstp, long srcp, size_t len) ++{ ++ op_t a0, a1, a2, a3; ++ int sh_1, sh_2; ++ ++ /* Calculate how to shift a word read at the memory operation ++ * aligned srcp to make it aligned for copy. ++ */ ++ ++ sh_1 = 8 * (srcp % OPSIZ); ++ sh_2 = 8 * OPSIZ - sh_1; ++ ++ /* Make SRCP aligned by rounding it down to the beginning of the `op_t' ++ * it points in the middle of. ++ */ ++ srcp &= -OPSIZ; ++ ++ switch (len % 4) { ++ case 2: ++ a1 = ((op_t *) srcp)[0]; ++ a2 = ((op_t *) srcp)[1]; ++ srcp -= 1 * OPSIZ; ++ dstp -= 3 * OPSIZ; ++ len += 2; ++ goto do1; ++ case 3: ++ a0 = ((op_t *) srcp)[0]; ++ a1 = ((op_t *) srcp)[1]; ++ srcp -= 0 * OPSIZ; ++ dstp -= 2 * OPSIZ; ++ len += 1; ++ goto do2; ++ case 0: ++ if (OP_T_THRES <= 3 * OPSIZ && len == 0) ++ return; ++ a3 = ((op_t *) srcp)[0]; ++ a0 = ((op_t *) srcp)[1]; ++ srcp -= -1 * OPSIZ; ++ dstp -= 1 * OPSIZ; ++ len += 0; ++ goto do3; ++ case 1: ++ a2 = ((op_t *) srcp)[0]; ++ a3 = ((op_t *) srcp)[1]; ++ srcp -= -2 * OPSIZ; ++ dstp -= 0 * OPSIZ; ++ len -= 1; ++ if (OP_T_THRES <= 3 * OPSIZ && len == 0) ++ goto do0; ++ goto do4; /* No-op. */ ++ } ++ ++ do { ++do4: ++ a0 = ((op_t *) srcp)[0]; ++ ((op_t *) dstp)[0] = MERGE(a2, sh_1, a3, sh_2); ++do3: ++ a1 = ((op_t *) srcp)[1]; ++ ((op_t *) dstp)[1] = MERGE(a3, sh_1, a0, sh_2); ++do2: ++ a2 = ((op_t *) srcp)[2]; ++ ((op_t *) dstp)[2] = MERGE(a0, sh_1, a1, sh_2); ++do1: ++ a3 = ((op_t *) srcp)[3]; ++ ((op_t *) dstp)[3] = MERGE(a1, sh_1, a2, sh_2); ++ ++ srcp += 4 * OPSIZ; ++ dstp += 4 * OPSIZ; ++ len -= 4; ++ } while (len != 0); ++ ++ /* This is the right position for do0. Please don't move ++ * it into the loop. ++ */ ++do0: ++ ((op_t *) dstp)[0] = MERGE(a2, sh_1, a3, sh_2); ++} ++ ++#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \ ++do { \ ++ size_t __nbytes = (nbytes); \ ++ while (__nbytes > 0) { \ ++ byte __x = ((byte *) src_bp)[0]; \ ++ src_bp += 1; \ ++ __nbytes -= 1; \ ++ ((byte *) dst_bp)[0] = __x; \ ++ dst_bp += 1; \ ++ } \ ++} while (0) ++ ++#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \ ++do { \ ++ if (src_bp % OPSIZ == 0) \ ++ _wordcopy_fwd_aligned(dst_bp, src_bp, (nbytes) / OPSIZ); \ ++ else \ ++ _wordcopy_fwd_dest_aligned(dst_bp, src_bp, (nbytes) / OPSIZ); \ ++ src_bp += (nbytes) & -OPSIZ; \ ++ dst_bp += (nbytes) & -OPSIZ; \ ++ (nbytes_left) = (nbytes) % OPSIZ; \ ++} while (0) ++ ++extern void *__memcpy_aligned(void *dest, const void *src, size_t len); ++void *__memcpy(void *dest, const void *src, size_t len) ++{ ++ unsigned long dstp = (long) dest; ++ unsigned long srcp = (long) src; ++ ++ /* If there not too few bytes to copy, use word copy. */ ++ if (len >= OP_T_THRES) { ++ if ((len >= FAST_COPY_THRES) && ((dstp & OPSIZ_MASK) == 0) && ++ ((srcp & OPSIZ_MASK) == 0)) { ++ __memcpy_aligned(dest, src, len); ++ return dest; ++ } ++ /* Copy just a few bytes to make DSTP aligned. */ ++ len -= (-dstp) % OPSIZ; ++ BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ); ++ ++ /* Copy from SRCP to DSTP taking advantage of the known alignment of ++ * DSTP. Number of bytes remaining is put in the third argument, ++ * i.e. in LEN. This number may vary from machine to machine. ++ */ ++ WORD_COPY_FWD(dstp, srcp, len, len); ++ /* Fall out and copy the tail. */ ++ } ++ ++ /* There are just a few bytes to copy. Use byte memory operations. */ ++ BYTE_COPY_FWD(dstp, srcp, len); ++ ++ return dest; ++} ++ ++void *memcpy(void *dest, const void *src, size_t len) __weak __alias(__memcpy); diff --git a/target/linux/starfive/patches-6.12/0015-riscv-purgatory-Change-memcpy-to-the-aligned-version.patch b/target/linux/starfive/patches-6.12/0015-riscv-purgatory-Change-memcpy-to-the-aligned-version.patch new file mode 100644 index 0000000000..090d85ddcc --- /dev/null +++ b/target/linux/starfive/patches-6.12/0015-riscv-purgatory-Change-memcpy-to-the-aligned-version.patch @@ -0,0 +1,36 @@ +From a0eaebc3b3ae079772c1022c47d704c887c375d0 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Sun, 4 Feb 2024 15:27:09 +0800 +Subject: [PATCH 15/55] riscv/purgatory: Change memcpy to the aligned version + +Change memcpy to the aligned version, for purgatory. + +Signed-off-by: Hal Feng +--- + arch/riscv/purgatory/Makefile | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/arch/riscv/purgatory/Makefile ++++ b/arch/riscv/purgatory/Makefile +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + +-purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy.o memset.o ++purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy_aligned.o memcpy.o memset.o + ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),) + purgatory-y += strcmp.o strlen.o strncmp.o + endif +@@ -14,9 +14,12 @@ $(obj)/string.o: $(srctree)/lib/string.c + $(obj)/ctype.o: $(srctree)/lib/ctype.c FORCE + $(call if_changed_rule,cc_o_c) + +-$(obj)/memcpy.o: $(srctree)/arch/riscv/lib/memcpy.S FORCE ++$(obj)/memcpy_aligned.o: $(srctree)/arch/riscv/lib/memcpy_aligned.S FORCE + $(call if_changed_rule,as_o_S) + ++$(obj)/memcpy.o: $(srctree)/arch/riscv/lib/string.c FORCE ++ $(call if_changed_rule,cc_o_c) ++ + $(obj)/memset.o: $(srctree)/arch/riscv/lib/memset.S FORCE + $(call if_changed_rule,as_o_S) + diff --git a/target/linux/starfive/patches-6.12/0016-riscv-Fix-__memcpy_aligned-alias.patch b/target/linux/starfive/patches-6.12/0016-riscv-Fix-__memcpy_aligned-alias.patch new file mode 100644 index 0000000000..ad35ee047f --- /dev/null +++ b/target/linux/starfive/patches-6.12/0016-riscv-Fix-__memcpy_aligned-alias.patch @@ -0,0 +1,22 @@ +From 9b8ac2217743a522f0c4f3e360f089b434fcd04b Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Tue, 21 Jan 2025 11:42:35 +0800 +Subject: [PATCH 16/55] riscv: Fix __memcpy_aligned alias + +Don't set the weak global alias of memcpy_aligned to memcpy. +This affected iperf3 test. + +Signed-off-by: Hal Feng +--- + arch/riscv/lib/memcpy_aligned.S | 1 - + 1 file changed, 1 deletion(-) + +--- a/arch/riscv/lib/memcpy_aligned.S ++++ b/arch/riscv/lib/memcpy_aligned.S +@@ -80,6 +80,5 @@ SYM_FUNC_START(__memcpy_aligned) + 6: + ret + SYM_FUNC_END(__memcpy_aligned) +-SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy_aligned) + SYM_FUNC_ALIAS(__pi_memcpy, __memcpy_aligned) + SYM_FUNC_ALIAS(__pi___memcpy, __memcpy_aligned) diff --git a/target/linux/starfive/patches-6.12/0017-plic-irq-Set-IRQCHIP_EOI_THREADED-in-PREEMPT_RT-case.patch b/target/linux/starfive/patches-6.12/0017-plic-irq-Set-IRQCHIP_EOI_THREADED-in-PREEMPT_RT-case.patch new file mode 100644 index 0000000000..b114c906d4 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0017-plic-irq-Set-IRQCHIP_EOI_THREADED-in-PREEMPT_RT-case.patch @@ -0,0 +1,39 @@ +From 8ea9ae21bde99c2c1832f364f973895e108a4851 Mon Sep 17 00:00:00 2001 +From: Minda Chen +Date: Thu, 18 Jul 2024 17:22:53 +0800 +Subject: [PATCH 17/55] plic: irq: Set IRQCHIP_EOI_THREADED in PREEMPT_RT case + +In ipms can device or other device, interrupt is trigger by level. +in PREEMPT_RT case. irq handle is in thread, If not set +IRQCHIP_EOI_THREADED, device irq in PLIC is cleared first, but +device irq reg is not clear, So the interrupt will be triggered +again, IRQCHIP_EOI_THREADED will clear device PLIC IRQ status +after clear device irq reg. + +Signed-off-by: Minda Chen +--- + drivers/irqchip/irq-sifive-plic.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/irqchip/irq-sifive-plic.c ++++ b/drivers/irqchip/irq-sifive-plic.c +@@ -209,6 +209,9 @@ static struct irq_chip plic_edge_chip = + #endif + .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE | ++#ifdef CONFIG_PREEMPT_RT ++ IRQCHIP_EOI_THREADED | ++#endif + IRQCHIP_AFFINITY_PRE_STARTUP, + }; + +@@ -224,6 +227,9 @@ static struct irq_chip plic_chip = { + #endif + .irq_set_type = plic_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE | ++#ifdef CONFIG_PREEMPT_RT ++ IRQCHIP_EOI_THREADED | ++#endif + IRQCHIP_AFFINITY_PRE_STARTUP, + }; + diff --git a/target/linux/starfive/patches-6.12/0018-driver-e24-add-e24-driver.patch b/target/linux/starfive/patches-6.12/0018-driver-e24-add-e24-driver.patch new file mode 100644 index 0000000000..ca61b4652f --- /dev/null +++ b/target/linux/starfive/patches-6.12/0018-driver-e24-add-e24-driver.patch @@ -0,0 +1,2294 @@ +From b37b26232ebb6c0a61b530f11ccd6eefdf782c04 Mon Sep 17 00:00:00 2001 +From: "shanlong.li" +Date: Fri, 16 Jun 2023 03:02:14 -0700 +Subject: [PATCH 18/55] driver:e24: add e24 driver + +add e24 driver + +Signed-off-by: shanlong.li +--- + drivers/Kconfig | 1 + + drivers/Makefile | 1 + + drivers/e24/Kconfig | 5 + + drivers/e24/Makefile | 12 + + drivers/e24/e24_alloc.c | 241 ++++++ + drivers/e24/e24_alloc.h | 59 ++ + drivers/e24/starfive_e24.c | 1524 +++++++++++++++++++++++++++++++++ + drivers/e24/starfive_e24.h | 159 ++++ + drivers/e24/starfive_e24_hw.c | 134 +++ + drivers/e24/starfive_e24_hw.h | 94 ++ + 10 files changed, 2230 insertions(+) + create mode 100644 drivers/e24/Kconfig + create mode 100644 drivers/e24/Makefile + create mode 100644 drivers/e24/e24_alloc.c + create mode 100644 drivers/e24/e24_alloc.h + create mode 100644 drivers/e24/starfive_e24.c + create mode 100644 drivers/e24/starfive_e24.h + create mode 100644 drivers/e24/starfive_e24_hw.c + create mode 100644 drivers/e24/starfive_e24_hw.h + +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -245,4 +245,5 @@ source "drivers/cdx/Kconfig" + + source "drivers/dpll/Kconfig" + ++source "drivers/e24/Kconfig" + endmenu +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -195,3 +195,4 @@ obj-$(CONFIG_CDX_BUS) += cdx/ + obj-$(CONFIG_DPLL) += dpll/ + + obj-$(CONFIG_S390) += s390/ ++obj-$(CONFIG_E24) += e24/ +--- /dev/null ++++ b/drivers/e24/Kconfig +@@ -0,0 +1,5 @@ ++config E24 ++ tristate "E24 support" ++ default m ++ help ++ This module provides the function of E24 device. +--- /dev/null ++++ b/drivers/e24/Makefile +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# Copyright(c) 1999 - 2018 Intel Corporation. ++# ++# Makefile for the E24 driver ++# ++ccflags-y += -I$(srctree)/drivers/e24 ++#ccflags-y += -DDEBUG ++ccflags-y += -Wunused-variable -Wno-error=missing-prototypes ++ ++obj-$(CONFIG_E24) += e24.o ++ ++e24-y := starfive_e24.o starfive_e24_hw.o e24_alloc.o +--- /dev/null ++++ b/drivers/e24/e24_alloc.c +@@ -0,0 +1,241 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++#include ++#include ++#include "e24_alloc.h" ++ ++struct e24_private_pool { ++ struct e24_allocation_pool pool; ++ struct mutex free_list_lock; ++ phys_addr_t start; ++ u32 size; ++ struct e24_allocation *free_list; ++}; ++ ++static void e24_private_free(struct e24_allocation *e24_allocation) ++{ ++ struct e24_private_pool *pool = container_of(e24_allocation->pool, ++ struct e24_private_pool, ++ pool); ++ struct e24_allocation **pcur; ++ ++ pr_debug("%s: %pap x %d\n", __func__, ++ &e24_allocation->start, e24_allocation->size); ++ ++ mutex_lock(&pool->free_list_lock); ++ ++ for (pcur = &pool->free_list; ; pcur = &(*pcur)->next) { ++ struct e24_allocation *cur = *pcur; ++ ++ if (cur && cur->start + cur->size == e24_allocation->start) { ++ struct e24_allocation *next = cur->next; ++ ++ pr_debug("merging block tail: %pap x 0x%x ->\n", ++ &cur->start, cur->size); ++ cur->size += e24_allocation->size; ++ pr_debug("... -> %pap x 0x%x\n", ++ &cur->start, cur->size); ++ kfree(e24_allocation); ++ ++ if (next && cur->start + cur->size == next->start) { ++ pr_debug("merging with next block: %pap x 0x%x ->\n", ++ &cur->start, cur->size); ++ cur->size += next->size; ++ cur->next = next->next; ++ pr_debug("... -> %pap x 0x%x\n", ++ &cur->start, cur->size); ++ kfree(next); ++ } ++ break; ++ } ++ ++ if (!cur || e24_allocation->start < cur->start) { ++ if (cur && e24_allocation->start + e24_allocation->size == ++ cur->start) { ++ pr_debug("merging block head: %pap x 0x%x ->\n", ++ &cur->start, cur->size); ++ cur->size += e24_allocation->size; ++ cur->start = e24_allocation->start; ++ pr_debug("... -> %pap x 0x%x\n", ++ &cur->start, cur->size); ++ kfree(e24_allocation); ++ } else { ++ pr_debug("inserting new free block\n"); ++ e24_allocation->next = cur; ++ *pcur = e24_allocation; ++ } ++ break; ++ } ++ } ++ ++ mutex_unlock(&pool->free_list_lock); ++} ++ ++static long e24_private_alloc(struct e24_allocation_pool *pool, ++ u32 size, u32 align, ++ struct e24_allocation **alloc) ++{ ++ struct e24_private_pool *ppool = container_of(pool, ++ struct e24_private_pool, ++ pool); ++ struct e24_allocation **pcur; ++ struct e24_allocation *cur = NULL; ++ struct e24_allocation *new; ++ phys_addr_t aligned_start = 0; ++ bool found = false; ++ ++ if (!size || (align & (align - 1))) ++ return -EINVAL; ++ if (!align) ++ align = 1; ++ ++ new = kzalloc(sizeof(struct e24_allocation), GFP_KERNEL); ++ if (!new) ++ return -ENOMEM; ++ ++ align = ALIGN(align, PAGE_SIZE); ++ size = ALIGN(size, PAGE_SIZE); ++ ++ mutex_lock(&ppool->free_list_lock); ++ ++ /* on exit free list is fixed */ ++ for (pcur = &ppool->free_list; *pcur; pcur = &(*pcur)->next) { ++ cur = *pcur; ++ aligned_start = ALIGN(cur->start, align); ++ ++ if (aligned_start >= cur->start && ++ aligned_start - cur->start + size <= cur->size) { ++ if (aligned_start == cur->start) { ++ if (aligned_start + size == cur->start + cur->size) { ++ pr_debug("reusing complete block: %pap x %x\n", ++ &cur->start, cur->size); ++ *pcur = cur->next; ++ } else { ++ pr_debug("cutting block head: %pap x %x ->\n", ++ &cur->start, cur->size); ++ cur->size -= aligned_start + size - cur->start; ++ cur->start = aligned_start + size; ++ pr_debug("... -> %pap x %x\n", ++ &cur->start, cur->size); ++ cur = NULL; ++ } ++ } else { ++ if (aligned_start + size == cur->start + cur->size) { ++ pr_debug("cutting block tail: %pap x %x ->\n", ++ &cur->start, cur->size); ++ cur->size = aligned_start - cur->start; ++ pr_debug("... -> %pap x %x\n", ++ &cur->start, cur->size); ++ cur = NULL; ++ } else { ++ pr_debug("splitting block into two: %pap x %x ->\n", ++ &cur->start, cur->size); ++ new->start = aligned_start + size; ++ new->size = cur->start + ++ cur->size - new->start; ++ ++ cur->size = aligned_start - cur->start; ++ ++ new->next = cur->next; ++ cur->next = new; ++ pr_debug("... -> %pap x %x + %pap x %x\n", ++ &cur->start, cur->size, ++ &new->start, new->size); ++ ++ cur = NULL; ++ new = NULL; ++ } ++ } ++ found = true; ++ break; ++ } else { ++ cur = NULL; ++ } ++ } ++ ++ mutex_unlock(&ppool->free_list_lock); ++ ++ if (!found) { ++ kfree(cur); ++ kfree(new); ++ return -ENOMEM; ++ } ++ ++ if (!cur) { ++ cur = new; ++ new = NULL; ++ } ++ if (!cur) { ++ cur = kzalloc(sizeof(struct e24_allocation), GFP_KERNEL); ++ if (!cur) ++ return -ENOMEM; ++ } ++ ++ kfree(new); ++ pr_debug("returning: %pap x %x\n", &aligned_start, size); ++ cur->start = aligned_start; ++ cur->size = size; ++ cur->pool = pool; ++ atomic_set(&cur->ref, 0); ++ atomic_inc(&cur->ref); ++ *alloc = cur; ++ ++ return 0; ++} ++ ++static void e24_private_free_pool(struct e24_allocation_pool *pool) ++{ ++ struct e24_private_pool *ppool = container_of(pool, ++ struct e24_private_pool, ++ pool); ++ kfree(ppool->free_list); ++ kfree(ppool); ++} ++ ++static phys_addr_t e24_private_offset(const struct e24_allocation *allocation) ++{ ++ struct e24_private_pool *ppool = container_of(allocation->pool, ++ struct e24_private_pool, ++ pool); ++ return allocation->start - ppool->start; ++} ++ ++static const struct e24_allocation_ops e24_private_pool_ops = { ++ .alloc = e24_private_alloc, ++ .free = e24_private_free, ++ .free_pool = e24_private_free_pool, ++ .offset = e24_private_offset, ++}; ++ ++long e24_init_private_pool(struct e24_allocation_pool **ppool, ++ phys_addr_t start, u32 size) ++{ ++ struct e24_private_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL); ++ struct e24_allocation *allocation = kmalloc(sizeof(*allocation), ++ GFP_KERNEL); ++ ++ if (!pool || !allocation) { ++ kfree(pool); ++ kfree(allocation); ++ return -ENOMEM; ++ } ++ ++ *allocation = (struct e24_allocation){ ++ .pool = &pool->pool, ++ .start = start, ++ .size = size, ++ }; ++ *pool = (struct e24_private_pool){ ++ .pool = { ++ .ops = &e24_private_pool_ops, ++ }, ++ .start = start, ++ .size = size, ++ .free_list = allocation, ++ }; ++ mutex_init(&pool->free_list_lock); ++ *ppool = &pool->pool; ++ return 0; ++} +--- /dev/null ++++ b/drivers/e24/e24_alloc.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef E24_ALLOC_H ++#define E24_ALLOC_H ++ ++struct e24_allocation_pool; ++struct e24_allocation; ++ ++struct e24_allocation_ops { ++ long (*alloc)(struct e24_allocation_pool *allocation_pool, ++ u32 size, u32 align, struct e24_allocation **alloc); ++ void (*free)(struct e24_allocation *allocation); ++ void (*free_pool)(struct e24_allocation_pool *allocation_pool); ++ phys_addr_t (*offset)(const struct e24_allocation *allocation); ++}; ++ ++struct e24_allocation_pool { ++ const struct e24_allocation_ops *ops; ++}; ++ ++struct e24_allocation { ++ struct e24_allocation_pool *pool; ++ struct e24_allocation *next; ++ phys_addr_t start; ++ u32 size; ++ atomic_t ref; ++}; ++ ++static inline void e24_free_pool(struct e24_allocation_pool *allocation_pool) ++{ ++ allocation_pool->ops->free_pool(allocation_pool); ++} ++ ++static inline void e24_free(struct e24_allocation *allocation) ++{ ++ return allocation->pool->ops->free(allocation); ++} ++ ++static inline long e24_allocate(struct e24_allocation_pool *allocation_pool, ++ u32 size, u32 align, ++ struct e24_allocation **alloc) ++{ ++ return allocation_pool->ops->alloc(allocation_pool, ++ size, align, alloc); ++} ++ ++static inline void e24_allocation_put(struct e24_allocation *e24_allocation) ++{ ++ if (atomic_dec_and_test(&e24_allocation->ref)) ++ e24_allocation->pool->ops->free(e24_allocation); ++} ++ ++static inline phys_addr_t e24_allocation_offset(const struct e24_allocation *allocation) ++{ ++ return allocation->pool->ops->offset(allocation); ++} ++ ++long e24_init_private_pool(struct e24_allocation_pool **ppool, phys_addr_t start, u32 size); ++ ++#endif +--- /dev/null ++++ b/drivers/e24/starfive_e24.c +@@ -0,0 +1,1522 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * e24 driver for StarFive JH7110 SoC ++ * ++ * Copyright (c) 2021 StarFive Technology Co., Ltd. ++ * Author: Shanlong Li ++ */ ++#include ++#include ++#include ++#include ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) ++#include ++#else ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "e24_alloc.h" ++#include "starfive_e24.h" ++#include "starfive_e24_hw.h" ++ ++#define EMBOX_MAX_MSG_LEN 4 ++ ++static DEFINE_IDA(e24_nodeid); ++ ++struct e24_dsp_cmd { ++ __u32 flags; ++ __u32 in_data_size; ++ __u32 out_data_size; ++ union { ++ __u32 in_data_addr; ++ __u8 in_data[E24_DSP_CMD_INLINE_DATA_SIZE]; ++ }; ++ union { ++ __u32 out_data_addr; ++ __u8 out_data[E24_DSP_CMD_INLINE_DATA_SIZE]; ++ }; ++}; ++ ++struct e24_ioctl_user { ++ u32 flags; ++ u32 in_data_size; ++ u32 out_data_size; ++ u64 in_data_addr; ++ u64 out_data_addr; ++}; ++ ++struct e24_ioctl_request { ++ struct e24_ioctl_user ioctl_data; ++ phys_addr_t in_data_phys; ++ phys_addr_t out_data_phys; ++ struct e24_mapping *buffer_mapping; ++ ++ union { ++ struct e24_mapping in_data_mapping; ++ u8 in_data[E24_DSP_CMD_INLINE_DATA_SIZE]; ++ }; ++ union { ++ struct e24_mapping out_data_mapping; ++ u8 out_data[E24_DSP_CMD_INLINE_DATA_SIZE]; ++ }; ++}; ++ ++static int firmware_command_timeout = 10; ++ ++static inline void e24_comm_read(volatile void __iomem *addr, void *p, ++ size_t sz) ++{ ++ size_t sz32 = sz & ~3; ++ u32 v; ++ ++ while (sz32) { ++ v = __raw_readl(addr); ++ memcpy(p, &v, sizeof(v)); ++ p += 4; ++ addr += 4; ++ sz32 -= 4; ++ } ++ sz &= 3; ++ if (sz) { ++ v = __raw_readl(addr); ++ memcpy(p, &v, sz); ++ } ++} ++ ++static inline void e24_comm_write(volatile void __iomem *addr, const void *p, ++ size_t sz) ++{ ++ size_t sz32 = sz & ~3; ++ u32 v; ++ ++ while (sz32) { ++ memcpy(&v, p, sizeof(v)); ++ __raw_writel(v, addr); ++ p += 4; ++ addr += 4; ++ sz32 -= 4; ++ } ++ sz &= 3; ++ if (sz) { ++ v = 0; ++ memcpy(&v, p, sz); ++ __raw_writel(v, addr); ++ } ++} ++ ++static bool e24_cacheable(struct e24_device *e24_dat, unsigned long pfn, ++ unsigned long n_pages) ++{ ++ if (e24_dat->hw_ops->cacheable) { ++ return e24_dat->hw_ops->cacheable(e24_dat->hw_arg, pfn, n_pages); ++ } else { ++ unsigned long i; ++ ++ for (i = 0; i < n_pages; ++i) ++ if (!pfn_valid(pfn + i)) ++ return false; ++ return true; ++ } ++} ++ ++static int e24_compare_address_sort(const void *a, const void *b) ++{ ++ const struct e24_address_map_entry *pa = a; ++ const struct e24_address_map_entry *pb = b; ++ ++ if (pa->src_addr < pb->src_addr && ++ pb->src_addr - pa->src_addr >= pa->size) ++ return -1; ++ if (pa->src_addr > pb->src_addr && ++ pa->src_addr - pb->src_addr >= pb->size) ++ return 1; ++ ++ return 0; ++} ++ ++static int e24_compare_address_search(const void *a, const void *b) ++{ ++ const phys_addr_t *pa = a; ++ ++ return e24_compare_address(*pa, b); ++} ++ ++struct e24_address_map_entry * ++e24_get_address_mapping(const struct e24_address_map *map, phys_addr_t addr) ++{ ++ return bsearch(&addr, map->entry, map->n, sizeof(*map->entry), ++ e24_compare_address_search); ++} ++ ++u32 e24_translate_to_dsp(const struct e24_address_map *map, phys_addr_t addr) ++{ ++#ifdef E24_MEM_MAP ++ return addr; ++#else ++ struct e24_address_map_entry *entry = e24_get_address_mapping(map, addr); ++ ++ if (!entry) ++ return E24_NO_TRANSLATION; ++ return entry->dst_addr + addr - entry->src_addr; ++#endif ++} ++ ++static int e24_dma_direction(unsigned int flags) ++{ ++ static const enum dma_data_direction e24_dma_direction[] = { ++ [0] = DMA_NONE, ++ [E24_FLAG_READ] = DMA_TO_DEVICE, ++ [E24_FLAG_WRITE] = DMA_FROM_DEVICE, ++ [E24_FLAG_READ_WRITE] = DMA_BIDIRECTIONAL, ++ }; ++ return e24_dma_direction[flags & E24_FLAG_READ_WRITE]; ++} ++ ++static void e24_dma_sync_for_cpu(struct e24_device *e24_dat, ++ unsigned long virt, ++ phys_addr_t phys, ++ unsigned long size, ++ unsigned long flags) ++{ ++ if (e24_dat->hw_ops->dma_sync_for_cpu) ++ e24_dat->hw_ops->dma_sync_for_cpu(e24_dat->hw_arg, ++ (void *)virt, phys, size, ++ flags); ++ else ++ dma_sync_single_for_cpu(e24_dat->dev, phys_to_dma(e24_dat->dev, phys), size, ++ e24_dma_direction(flags)); ++} ++ ++static void starfive_mbox_receive_message(struct mbox_client *client, void *message) ++{ ++ struct e24_device *e24_dat = dev_get_drvdata(client->dev); ++ ++ complete(&e24_dat->tx_channel->tx_complete); ++} ++ ++static struct mbox_chan * ++starfive_mbox_request_channel(struct device *dev, const char *name) ++{ ++ struct mbox_client *client; ++ struct mbox_chan *channel; ++ ++ client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL); ++ if (!client) ++ return ERR_PTR(-ENOMEM); ++ ++ client->dev = dev; ++ client->rx_callback = starfive_mbox_receive_message; ++ client->tx_prepare = NULL; ++ client->tx_done = NULL; ++ client->tx_block = true; ++ client->knows_txdone = false; ++ client->tx_tout = 3000; ++ ++ channel = mbox_request_channel_byname(client, name); ++ if (IS_ERR(channel)) { ++ dev_warn(dev, "Failed to request %s channel\n", name); ++ return NULL; ++ } ++ ++ return channel; ++} ++ ++static void e24_vm_open(struct vm_area_struct *vma) ++{ ++ struct e24_allocation *cur = vma->vm_private_data; ++ ++ atomic_inc(&cur->ref); ++} ++ ++static void e24_vm_close(struct vm_area_struct *vma) ++{ ++ e24_allocation_put(vma->vm_private_data); ++} ++ ++static const struct vm_operations_struct e24_vm_ops = { ++ .open = e24_vm_open, ++ .close = e24_vm_close, ++}; ++ ++static long e24_synchronize(struct e24_device *dev) ++{ ++ ++ struct e24_comm *queue = dev->queue; ++ struct e24_dsp_cmd __iomem *cmd = queue->comm; ++ u32 flags; ++ unsigned long deadline = jiffies + 10 * HZ; ++ ++ do { ++ flags = __raw_readl(&cmd->flags); ++ /* memory barrier */ ++ rmb(); ++ if (flags == 0x104) ++ return 0; ++ ++ schedule(); ++ } while (time_before(jiffies, deadline)); ++ ++ return -1; ++} ++ ++static int e24_open(struct inode *inode, struct file *filp) ++{ ++ struct e24_device *e24_dev = container_of(filp->private_data, ++ struct e24_device, miscdev); ++ int rc = 0; ++ ++ rc = pm_runtime_get_sync(e24_dev->dev); ++ if (rc < 0) ++ return rc; ++ ++ spin_lock_init(&e24_dev->busy_list_lock); ++ filp->private_data = e24_dev; ++ mdelay(1); ++ ++ return 0; ++} ++ ++int e24_release(struct inode *inode, struct file *filp) ++{ ++ struct e24_device *e24_dev = (struct e24_device *)filp->private_data; ++ int rc = 0; ++ ++ rc = pm_runtime_put_sync(e24_dev->dev); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static ssize_t mbox_e24_message_write(struct file *filp, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct e24_device *edev = filp->private_data; ++ void *data; ++ int ret; ++ ++ if (!edev->tx_channel) { ++ dev_err(edev->dev, "Channel cannot do Tx\n"); ++ return -EINVAL; ++ } ++ ++ if (count > EMBOX_MAX_MSG_LEN) { ++ dev_err(edev->dev, ++ "Message length %zd greater than max allowed %d\n", ++ count, EMBOX_MAX_MSG_LEN); ++ return -EINVAL; ++ } ++ ++ edev->message = kzalloc(EMBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!edev->message) ++ return -ENOMEM; ++ ++ ret = copy_from_user(edev->message, userbuf, count); ++ if (ret) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS, ++ edev->message, EMBOX_MAX_MSG_LEN); ++ data = edev->message; ++ pr_debug("%s:%d, %d\n", __func__, __LINE__, *((int *)data)); ++ ret = mbox_send_message(edev->tx_channel, data); ++ ++ if (ret < 0 || !edev->tx_channel->active_req) ++ dev_err(edev->dev, "Failed to send message via mailbox:%d\n", ret); ++ ++out: ++ kfree(edev->message); ++ edev->tx_channel->active_req = NULL; ++ ++ return ret < 0 ? ret : count; ++} ++ ++static long _e24_copy_user_phys(struct e24_device *edev, ++ unsigned long vaddr, unsigned long size, ++ phys_addr_t paddr, unsigned long flags, ++ bool to_phys) ++{ ++ void __iomem *p = ioremap(paddr, size); ++ unsigned long rc; ++ ++ if (!p) { ++ dev_err(edev->dev, ++ "couldn't ioremap %pap x 0x%08x\n", ++ &paddr, (u32)size); ++ return -EINVAL; ++ } ++ if (to_phys) ++ rc = raw_copy_from_user(__io_virt(p), ++ (void __user *)vaddr, size); ++ else ++ rc = copy_to_user((void __user *)vaddr, ++ __io_virt(p), size); ++ iounmap(p); ++ if (rc) ++ return -EFAULT; ++ return 0; ++} ++ ++static long e24_copy_user_to_phys(struct e24_device *edev, ++ unsigned long vaddr, unsigned long size, ++ phys_addr_t paddr, unsigned long flags) ++{ ++ return _e24_copy_user_phys(edev, vaddr, size, paddr, flags, true); ++} ++ ++static long e24_copy_user_from_phys(struct e24_device *edev, ++ unsigned long vaddr, unsigned long size, ++ phys_addr_t paddr, unsigned long flags) ++{ ++ return _e24_copy_user_phys(edev, vaddr, size, paddr, flags, false); ++} ++ ++static long e24_copy_virt_to_phys(struct e24_device *edev, ++ unsigned long flags, ++ unsigned long vaddr, unsigned long size, ++ phys_addr_t *paddr, ++ struct e24_alien_mapping *mapping) ++{ ++ phys_addr_t phys; ++ unsigned long align = clamp(vaddr & -vaddr, 16ul, PAGE_SIZE); ++ unsigned long offset = vaddr & (align - 1); ++ struct e24_allocation *allocation; ++ long rc; ++ ++ rc = e24_allocate(edev->pool, ++ size + align, align, &allocation); ++ if (rc < 0) ++ return rc; ++ ++ phys = (allocation->start & -align) | offset; ++ if (phys < allocation->start) ++ phys += align; ++ ++ if (flags & E24_FLAG_READ) { ++ if (e24_copy_user_to_phys(edev, vaddr, ++ size, phys, flags)) { ++ e24_allocation_put(allocation); ++ return -EFAULT; ++ } ++ } ++ ++ *paddr = phys; ++ *mapping = (struct e24_alien_mapping){ ++ .vaddr = vaddr, ++ .size = size, ++ .paddr = *paddr, ++ .allocation = allocation, ++ .type = ALIEN_COPY, ++ }; ++ pr_debug("%s: copying to pa: %pap\n", __func__, paddr); ++ ++ return 0; ++} ++ ++static long e24_writeback_alien_mapping(struct e24_device *edev, ++ struct e24_alien_mapping *alien_mapping, ++ unsigned long flags) ++{ ++ struct page *page; ++ size_t nr_pages; ++ size_t i; ++ long ret = 0; ++ ++ switch (alien_mapping->type) { ++ case ALIEN_GUP: ++ e24_dma_sync_for_cpu(edev, ++ alien_mapping->vaddr, ++ alien_mapping->paddr, ++ alien_mapping->size, ++ flags); ++ pr_debug("%s: dirtying alien GUP @va = %p, pa = %pap\n", ++ __func__, (void __user *)alien_mapping->vaddr, ++ &alien_mapping->paddr); ++ page = pfn_to_page(__phys_to_pfn(alien_mapping->paddr)); ++ nr_pages = PFN_UP(alien_mapping->vaddr + alien_mapping->size) - ++ PFN_DOWN(alien_mapping->vaddr); ++ for (i = 0; i < nr_pages; ++i) ++ SetPageDirty(page + i); ++ break; ++ ++ case ALIEN_COPY: ++ pr_debug("%s: synchronizing alien copy @pa = %pap back to %p\n", ++ __func__, &alien_mapping->paddr, ++ (void __user *)alien_mapping->vaddr); ++ if (e24_copy_user_from_phys(edev, ++ alien_mapping->vaddr, ++ alien_mapping->size, ++ alien_mapping->paddr, ++ flags)) ++ ret = -EINVAL; ++ break; ++ ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static bool vma_needs_cache_ops(struct vm_area_struct *vma) ++{ ++ pgprot_t prot = vma->vm_page_prot; ++ ++ return pgprot_val(prot) != pgprot_val(pgprot_noncached(prot)) && ++ pgprot_val(prot) != pgprot_val(pgprot_writecombine(prot)); ++} ++ ++static void e24_alien_mapping_destroy(struct e24_alien_mapping *alien_mapping) ++{ ++ switch (alien_mapping->type) { ++ case ALIEN_COPY: ++ e24_allocation_put(alien_mapping->allocation); ++ break; ++ default: ++ break; ++ } ++} ++ ++static long __e24_unshare_block(struct file *filp, struct e24_mapping *mapping, ++ unsigned long flags) ++{ ++ long ret = 0; ++ struct e24_device *edev = filp->private_data; ++ ++ switch (mapping->type & ~E24_MAPPING_KERNEL) { ++ case E24_MAPPING_NATIVE: ++ if (flags & E24_FLAG_WRITE) { ++ e24_dma_sync_for_cpu(edev, ++ mapping->native.vaddr, ++ mapping->native.m_allocation->start, ++ mapping->native.m_allocation->size, ++ flags); ++ } ++ e24_allocation_put(mapping->native.m_allocation); ++ break; ++ ++ case E24_MAPPING_ALIEN: ++ if (flags & E24_FLAG_WRITE) { ++ ret = e24_writeback_alien_mapping(edev, ++ &mapping->alien_mapping, ++ flags); ++ } ++ e24_alien_mapping_destroy(&mapping->alien_mapping); ++ break; ++ ++ case E24_MAPPING_KERNEL: ++ break; ++ ++ default: ++ break; ++ } ++ ++ mapping->type = E24_MAPPING_NONE; ++ ++ return ret; ++} ++ ++static long __e24_share_block(struct file *filp, ++ unsigned long virt, unsigned long size, ++ unsigned long flags, phys_addr_t *paddr, ++ struct e24_mapping *mapping) ++{ ++ phys_addr_t phys = ~0ul; ++ struct e24_device *edev = filp->private_data; ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma = find_vma(mm, virt); ++ bool do_cache = true; ++ long rc = -EINVAL; ++ ++ if (!vma) { ++ pr_debug("%s: no vma for vaddr/size = 0x%08lx/0x%08lx\n", ++ __func__, virt, size); ++ return -EINVAL; ++ } ++ ++ if (virt + size < virt || vma->vm_start > virt) ++ return -EINVAL; ++ ++ if (vma && (vma->vm_file == filp)) { ++ struct e24_device *vm_file = vma->vm_file->private_data; ++ struct e24_allocation *e24_user_allocation = vma->vm_private_data; ++ ++ phys = vm_file->shared_mem + (vma->vm_pgoff << PAGE_SHIFT) + ++ virt - vma->vm_start; ++ pr_debug("%s: E24 allocation at 0x%08lx, paddr: %pap\n", ++ __func__, virt, &phys); ++ ++ rc = 0; ++ mapping->type = E24_MAPPING_NATIVE; ++ mapping->native.m_allocation = e24_user_allocation; ++ mapping->native.vaddr = virt; ++ atomic_inc(&e24_user_allocation->ref); ++ do_cache = vma_needs_cache_ops(vma); ++ } ++ if (rc < 0) { ++ struct e24_alien_mapping *alien_mapping = ++ &mapping->alien_mapping; ++ ++ /* Otherwise this is alien allocation. */ ++ pr_debug("%s: non-E24 allocation at 0x%08lx\n", ++ __func__, virt); ++ ++ rc = e24_copy_virt_to_phys(edev, flags, ++ virt, size, &phys, ++ alien_mapping); ++ ++ if (rc < 0) { ++ pr_debug("%s: couldn't map virt to phys\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ phys = alien_mapping->paddr + ++ virt - alien_mapping->vaddr; ++ ++ mapping->type = E24_MAPPING_ALIEN; ++ } ++ ++ *paddr = phys; ++ pr_debug("%s: mapping = %p, mapping->type = %d\n", ++ __func__, mapping, mapping->type); ++ ++ return 0; ++} ++ ++ ++static void e24_unmap_request_nowb(struct file *filp, struct e24_ioctl_request *rq) ++{ ++ if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) ++ __e24_unshare_block(filp, &rq->in_data_mapping, 0); ++ if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) ++ __e24_unshare_block(filp, &rq->out_data_mapping, 0); ++} ++ ++static long e24_unmap_request(struct file *filp, struct e24_ioctl_request *rq) ++{ ++ long ret = 0; ++ ++ if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) ++ __e24_unshare_block(filp, &rq->in_data_mapping, E24_FLAG_READ); ++ ++ if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) { ++ ret = __e24_unshare_block(filp, &rq->out_data_mapping, ++ E24_FLAG_WRITE); ++ if (ret < 0) ++ pr_debug("%s: out_data could not be unshared\n", __func__); ++ ++ } else { ++ if (copy_to_user((void __user *)(unsigned long)rq->ioctl_data.out_data_addr, ++ rq->out_data, ++ rq->ioctl_data.out_data_size)) { ++ pr_debug("%s: out_data could not be copied\n", __func__); ++ ret = -EFAULT; ++ } ++ } ++ ++ return ret; ++} ++ ++static bool e24_cmd_complete(struct e24_comm *share_com) ++{ ++ struct e24_dsp_cmd __iomem *cmd = share_com->comm; ++ u32 flags = __raw_readl(&cmd->flags); ++ ++ rmb(); ++ return (flags & (E24_CMD_FLAG_REQUEST_VALID | ++ E24_CMD_FLAG_RESPONSE_VALID)) == ++ (E24_CMD_FLAG_REQUEST_VALID | ++ E24_CMD_FLAG_RESPONSE_VALID); ++} ++ ++static long e24_complete_poll(struct e24_device *edev, struct e24_comm *comm, ++ bool (*cmd_complete)(struct e24_comm *p), struct e24_ioctl_request *rq) ++{ ++ unsigned long deadline = jiffies + firmware_command_timeout * HZ; ++ ++ do { ++ if (cmd_complete(comm)) { ++ pr_debug("%s: poll complete.\n", __func__); ++ return 0; ++ } ++ schedule(); ++ } while (time_before(jiffies, deadline)); ++ ++ pr_debug("%s: poll complete cmd timeout.\n", __func__); ++ ++ return -EBUSY; ++} ++ ++static long e24_map_request(struct file *filp, struct e24_ioctl_request *rq, struct mm_struct *mm) ++{ ++ long ret = 0; ++ ++ mmap_read_lock(mm); ++ if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) { ++ ret = __e24_share_block(filp, rq->ioctl_data.in_data_addr, ++ rq->ioctl_data.in_data_size, ++ E24_FLAG_READ, &rq->in_data_phys, ++ &rq->in_data_mapping); ++ if (ret < 0) { ++ pr_debug("%s: in_data could not be shared\n", __func__); ++ goto share_err; ++ } ++ } else { ++ if (copy_from_user(rq->in_data, ++ (void __user *)(unsigned long)rq->ioctl_data.in_data_addr, ++ rq->ioctl_data.in_data_size)) { ++ pr_debug("%s: in_data could not be copied\n", ++ __func__); ++ ret = -EFAULT; ++ goto share_err; ++ } ++ } ++ ++ if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) { ++ ret = __e24_share_block(filp, rq->ioctl_data.out_data_addr, ++ rq->ioctl_data.out_data_size, ++ E24_FLAG_WRITE, &rq->out_data_phys, ++ &rq->out_data_mapping); ++ if (ret < 0) { ++ pr_debug("%s: out_data could not be shared\n", ++ __func__); ++ goto share_err; ++ } ++ } ++share_err: ++ mmap_read_unlock(mm); ++ if (ret < 0) ++ e24_unmap_request_nowb(filp, rq); ++ return ret; ++ ++} ++ ++static void e24_fill_hw_request(struct e24_dsp_cmd __iomem *cmd, ++ struct e24_ioctl_request *rq, ++ const struct e24_address_map *map) ++{ ++ __raw_writel(rq->ioctl_data.in_data_size, &cmd->in_data_size); ++ __raw_writel(rq->ioctl_data.out_data_size, &cmd->out_data_size); ++ ++ if (rq->ioctl_data.in_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) ++ __raw_writel(e24_translate_to_dsp(map, rq->in_data_phys), ++ &cmd->in_data_addr); ++ else ++ e24_comm_write(&cmd->in_data, rq->in_data, ++ rq->ioctl_data.in_data_size); ++ ++ if (rq->ioctl_data.out_data_size > E24_DSP_CMD_INLINE_DATA_SIZE) ++ __raw_writel(e24_translate_to_dsp(map, rq->out_data_phys), ++ &cmd->out_data_addr); ++ ++ wmb(); ++ /* update flags */ ++ __raw_writel(rq->ioctl_data.flags, &cmd->flags); ++} ++ ++static long e24_complete_hw_request(struct e24_dsp_cmd __iomem *cmd, ++ struct e24_ioctl_request *rq) ++{ ++ u32 flags = __raw_readl(&cmd->flags); ++ ++ if (rq->ioctl_data.out_data_size <= E24_DSP_CMD_INLINE_DATA_SIZE) ++ e24_comm_read(&cmd->out_data, rq->out_data, ++ rq->ioctl_data.out_data_size); ++ ++ __raw_writel(0, &cmd->flags); ++ ++ return (flags & E24_QUEUE_VALID_FLAGS) ? -ENXIO : 0; ++} ++ ++static long e24_ioctl_submit_task(struct file *filp, ++ struct e24_ioctl_user __user *msg) ++{ ++ struct e24_device *edev = filp->private_data; ++ struct e24_comm *queue = edev->queue; ++ struct e24_ioctl_request rq_data, *vrq = &rq_data; ++ void *data = &edev->mbox_data; ++ int ret = -ENOMEM; ++ int irq_mode = edev->irq_mode; ++ ++ if (copy_from_user(&vrq->ioctl_data, msg, sizeof(*msg))) ++ return -EFAULT; ++ ++ if (vrq->ioctl_data.flags & ~E24_QUEUE_VALID_FLAGS) { ++ dev_dbg(edev->dev, "%s: invalid flags 0x%08x\n", ++ __func__, vrq->ioctl_data.flags); ++ return -EINVAL; ++ } ++ ++ ret = e24_map_request(filp, vrq, current->mm); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&queue->lock); ++ e24_fill_hw_request(queue->comm, vrq, &edev->address_map); ++ ++ if (irq_mode) { ++ ret = mbox_send_message(edev->tx_channel, data); ++ mbox_chan_txdone(edev->tx_channel, ret); ++ } else { ++ ret = e24_complete_poll(edev, queue, e24_cmd_complete, vrq); ++ } ++ ++ ret = e24_complete_hw_request(queue->comm, vrq); ++ mutex_unlock(&queue->lock); ++ ++ if (ret == 0) ++ ret = e24_unmap_request(filp, vrq); ++ ++ return ret; ++} ++ ++static long e24_ioctl_get_channel(struct file *filp, ++ void __user *msg) ++{ ++ struct e24_device *edev = filp->private_data; ++ ++ if (edev->tx_channel == NULL) ++ edev->tx_channel = starfive_mbox_request_channel(edev->dev, "tx"); ++ if (edev->rx_channel == NULL) ++ edev->rx_channel = starfive_mbox_request_channel(edev->dev, "rx"); ++ ++ return 0; ++} ++ ++static long e24_ioctl_free_channel(struct file *filp, ++ void __user *msg) ++{ ++ struct e24_device *edev = filp->private_data; ++ ++ if (edev->rx_channel) ++ mbox_free_channel(edev->rx_channel); ++ if (edev->tx_channel) ++ mbox_free_channel(edev->tx_channel); ++ ++ edev->rx_channel = NULL; ++ edev->tx_channel = NULL; ++ return 0; ++} ++ ++static void e24_allocation_queue(struct e24_device *edev, ++ struct e24_allocation *e24_pool_allocation) ++{ ++ spin_lock(&edev->busy_list_lock); ++ ++ e24_pool_allocation->next = edev->busy_list; ++ edev->busy_list = e24_pool_allocation; ++ ++ spin_unlock(&edev->busy_list_lock); ++} ++ ++static struct e24_allocation *e24_allocation_dequeue(struct e24_device *edev, ++ phys_addr_t paddr, u32 size) ++{ ++ struct e24_allocation **pcur; ++ struct e24_allocation *cur; ++ ++ spin_lock(&edev->busy_list_lock); ++ ++ for (pcur = &edev->busy_list; (cur = *pcur); pcur = &((*pcur)->next)) { ++ pr_debug("%s: %pap / %pap x %d\n", __func__, &paddr, &cur->start, cur->size); ++ if (paddr >= cur->start && paddr + size - cur->start <= cur->size) { ++ *pcur = cur->next; ++ break; ++ } ++ } ++ ++ spin_unlock(&edev->busy_list_lock); ++ return cur; ++} ++ ++static int e24_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ int err; ++ struct e24_device *edev = filp->private_data; ++ unsigned long pfn = vma->vm_pgoff + PFN_DOWN(edev->shared_mem); ++ struct e24_allocation *e24_user_allocation; ++ ++ e24_user_allocation = e24_allocation_dequeue(filp->private_data, ++ pfn << PAGE_SHIFT, ++ vma->vm_end - vma->vm_start); ++ if (e24_user_allocation) { ++ pgprot_t prot = vma->vm_page_prot; ++ ++ if (!e24_cacheable(edev, pfn, ++ PFN_DOWN(vma->vm_end - vma->vm_start))) { ++ prot = pgprot_writecombine(prot); ++ vma->vm_page_prot = prot; ++ } ++ ++ err = remap_pfn_range(vma, vma->vm_start, pfn, ++ vma->vm_end - vma->vm_start, ++ prot); ++ ++ vma->vm_private_data = e24_user_allocation; ++ vma->vm_ops = &e24_vm_ops; ++ } else { ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static long e24_ioctl_free(struct file *filp, ++ struct e24_ioctl_alloc __user *p) ++{ ++ struct mm_struct *mm = current->mm; ++ struct e24_ioctl_alloc user_ioctl_alloc; ++ struct vm_area_struct *vma; ++ unsigned long start; ++ ++ if (copy_from_user(&user_ioctl_alloc, p, sizeof(*p))) ++ return -EFAULT; ++ ++ start = user_ioctl_alloc.addr; ++ pr_debug("%s: virt_addr = 0x%08lx\n", __func__, start); ++ ++ mmap_read_lock(mm); ++ vma = find_vma(mm, start); ++ ++ if (vma && vma->vm_file == filp && ++ vma->vm_start <= start && start < vma->vm_end) { ++ size_t size; ++ ++ start = vma->vm_start; ++ size = vma->vm_end - vma->vm_start; ++ mmap_read_unlock(mm); ++ pr_debug("%s: 0x%lx x %zu\n", __func__, start, size); ++ return vm_munmap(start, size); ++ } ++ pr_debug("%s: no vma/bad vma for vaddr = 0x%08lx\n", __func__, start); ++ mmap_read_unlock(mm); ++ ++ return -EINVAL; ++} ++ ++static long e24_ioctl_alloc(struct file *filp, ++ struct e24_ioctl_alloc __user *p) ++{ ++ struct e24_device *edev = filp->private_data; ++ struct e24_allocation *e24_pool_allocation; ++ unsigned long vaddr; ++ struct e24_ioctl_alloc user_ioctl_alloc; ++ long err; ++ ++ if (copy_from_user(&user_ioctl_alloc, p, sizeof(*p))) ++ return -EFAULT; ++ ++ pr_debug("%s: size = %d, align = %x\n", __func__, ++ user_ioctl_alloc.size, user_ioctl_alloc.align); ++ ++ err = e24_allocate(edev->pool, ++ user_ioctl_alloc.size, ++ user_ioctl_alloc.align, ++ &e24_pool_allocation); ++ if (err) ++ return err; ++ ++ e24_allocation_queue(edev, e24_pool_allocation); ++ ++ vaddr = vm_mmap(filp, 0, e24_pool_allocation->size, ++ PROT_READ | PROT_WRITE, MAP_SHARED, ++ e24_allocation_offset(e24_pool_allocation)); ++ ++ user_ioctl_alloc.addr = vaddr; ++ ++ if (copy_to_user(p, &user_ioctl_alloc, sizeof(*p))) { ++ vm_munmap(vaddr, user_ioctl_alloc.size); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static long e24_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long retval; ++ ++ switch (cmd) { ++ case E24_IOCTL_SEND: ++ retval = e24_ioctl_submit_task(filp, (struct e24_ioctl_user *)arg); ++ break; ++ case E24_IOCTL_GET_CHANNEL: ++ retval = e24_ioctl_get_channel(filp, NULL); ++ break; ++ case E24_IOCTL_FREE_CHANNEL: ++ retval = e24_ioctl_free_channel(filp, NULL); ++ break; ++ case E24_IOCTL_ALLOC: ++ retval = e24_ioctl_alloc(filp, (struct e24_ioctl_alloc __user *)arg); ++ break; ++ case E24_IOCTL_FREE: ++ retval = e24_ioctl_free(filp, (struct e24_ioctl_alloc __user *)arg); ++ break; ++ default: ++ retval = -EINVAL; ++ break; ++ } ++ return retval; ++} ++ ++static const struct file_operations e24_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = e24_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = e24_ioctl, ++#endif ++ .open = e24_open, ++ .release = e24_release, ++ .write = mbox_e24_message_write, ++ .mmap = e24_mmap, ++}; ++ ++void mailbox_task(struct platform_device *pdev) ++{ ++ struct e24_device *e24_dev = platform_get_drvdata(pdev); ++ ++ e24_dev->tx_channel = starfive_mbox_request_channel(e24_dev->dev, "tx"); ++ e24_dev->rx_channel = starfive_mbox_request_channel(e24_dev->dev, "rx"); ++ pr_debug("%s:%d.%#llx\n", __func__, __LINE__, (u64)e24_dev->rx_channel); ++} ++ ++static long e24_init_mem_pool(struct platform_device *pdev, struct e24_device *devs) ++{ ++ struct resource *mem; ++ ++ mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecmd"); ++ if (!mem) ++ return -ENODEV; ++ ++ devs->comm_phys = mem->start; ++ devs->comm = devm_ioremap(&pdev->dev, mem->start, mem->end - mem->start); ++ mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "espace"); ++ if (!mem) ++ return -ENODEV; ++ ++ devs->shared_mem = mem->start; ++ devs->shared_size = resource_size(mem); ++ pr_debug("%s:%d.%llx,%llx\n", __func__, __LINE__, devs->comm_phys, devs->shared_mem); ++ return e24_init_private_pool(&devs->pool, devs->shared_mem, devs->shared_size); ++} ++ ++static int e24_init_address_map(struct device *dev, ++ struct e24_address_map *map) ++{ ++#if IS_ENABLED(CONFIG_OF) ++ struct device_node *pnode = dev->of_node; ++ struct device_node *node; ++ int rlen, off; ++ const __be32 *ranges = of_get_property(pnode, "ranges", &rlen); ++ int na, pna, ns; ++ int i; ++ ++ if (!ranges) { ++ dev_dbg(dev, "%s: no 'ranges' property in the device tree, no translation at that level\n", ++ __func__); ++ goto empty; ++ } ++ ++ node = of_get_next_child(pnode, NULL); ++ if (!node) { ++ dev_warn(dev, "%s: no child node found in the device tree, no translation at that level\n", ++ __func__); ++ goto empty; ++ } ++ ++ na = of_n_addr_cells(node); ++ ns = of_n_size_cells(node); ++ pna = of_n_addr_cells(pnode); ++ ++ rlen /= 4; ++ map->n = rlen / (na + pna + ns); ++ map->entry = kmalloc_array(map->n, sizeof(*map->entry), GFP_KERNEL); ++ if (!map->entry) ++ return -ENOMEM; ++ ++ dev_dbg(dev, ++ "%s: na = %d, pna = %d, ns = %d, rlen = %d cells, n = %d\n", ++ __func__, na, pna, ns, rlen, map->n); ++ ++ for (off = 0, i = 0; off < rlen; off += na + pna + ns, ++i) { ++ map->entry[i].src_addr = of_translate_address(node, ++ ranges + off); ++ map->entry[i].dst_addr = of_read_number(ranges + off, na); ++ map->entry[i].size = of_read_number(ranges + off + na + pna, ns); ++ dev_dbg(dev, ++ " src_addr = 0x%llx, dst_addr = 0x%lx, size = 0x%lx\n", ++ (unsigned long long)map->entry[i].src_addr, ++ (unsigned long)map->entry[i].dst_addr, ++ (unsigned long)map->entry[i].size); ++ } ++ sort(map->entry, map->n, sizeof(*map->entry), e24_compare_address_sort, NULL); ++ ++ of_node_put(node); ++ return 0; ++ ++empty: ++#endif ++ map->n = 1; ++ map->entry = kmalloc(sizeof(*map->entry), GFP_KERNEL); ++ map->entry->src_addr = 0; ++ map->entry->dst_addr = 0; ++ map->entry->size = ~0u; ++ return -ENOMEM; ++} ++ ++typedef long e24_init_function(struct platform_device *pdev); ++ ++static inline void e24_init(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->init) ++ e24_hw->hw_ops->init(e24_hw->hw_arg); ++} ++ ++static inline void e24_release_e24(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->reset) ++ e24_hw->hw_ops->release(e24_hw->hw_arg); ++} ++ ++static inline void e24_halt_e24(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->halt) ++ e24_hw->hw_ops->halt(e24_hw->hw_arg); ++} ++ ++static inline int e24_enable_e24(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->enable) ++ return e24_hw->hw_ops->enable(e24_hw->hw_arg); ++ else ++ return -EINVAL; ++} ++ ++static inline void e24_reset_e24(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->reset) ++ e24_hw->hw_ops->reset(e24_hw->hw_arg); ++} ++ ++static inline void e24_disable_e24(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->disable) ++ e24_hw->hw_ops->disable(e24_hw->hw_arg); ++} ++ ++static inline void e24_sendirq_e24(struct e24_device *e24_hw) ++{ ++ if (e24_hw->hw_ops->send_irq) ++ e24_hw->hw_ops->send_irq(e24_hw->hw_arg); ++} ++ ++irqreturn_t e24_irq_handler(int irq, struct e24_device *e24_hw) ++{ ++ dev_dbg(e24_hw->dev, "%s\n", __func__); ++ complete(&e24_hw->completion); ++ ++ return IRQ_HANDLED; ++} ++EXPORT_SYMBOL(e24_irq_handler); ++ ++static phys_addr_t e24_translate_to_cpu(struct e24_device *mail, Elf32_Phdr *phdr) ++{ ++ phys_addr_t res; ++ __be32 addr = cpu_to_be32((u32)phdr->p_paddr); ++ struct device_node *node = ++ of_get_next_child(mail->dev->of_node, NULL); ++ ++ if (!node) ++ node = mail->dev->of_node; ++ ++ res = of_translate_address(node, &addr); ++ ++ if (node != mail->dev->of_node) ++ of_node_put(node); ++ return res; ++} ++ ++static int e24_load_segment_to_sysmem(struct e24_device *e24, Elf32_Phdr *phdr) ++{ ++ phys_addr_t pa = e24_translate_to_cpu(e24, phdr); ++ struct page *page = pfn_to_page(__phys_to_pfn(pa)); ++ size_t page_offs = pa & ~PAGE_MASK; ++ size_t offs; ++ ++ for (offs = 0; offs < phdr->p_memsz; ++page) { ++ void *p = kmap(page); ++ size_t sz; ++ ++ if (!p) ++ return -ENOMEM; ++ ++ page_offs &= ~PAGE_MASK; ++ sz = PAGE_SIZE - page_offs; ++ ++ if (offs < phdr->p_filesz) { ++ size_t copy_sz = sz; ++ ++ if (phdr->p_filesz - offs < copy_sz) ++ copy_sz = phdr->p_filesz - offs; ++ ++ copy_sz = ALIGN(copy_sz, 4); ++ memcpy(p + page_offs, ++ (void *)e24->firmware->data + ++ phdr->p_offset + offs, ++ copy_sz); ++ page_offs += copy_sz; ++ offs += copy_sz; ++ sz -= copy_sz; ++ } ++ ++ if (offs < phdr->p_memsz && sz) { ++ if (phdr->p_memsz - offs < sz) ++ sz = phdr->p_memsz - offs; ++ ++ sz = ALIGN(sz, 4); ++ memset(p + page_offs, 0, sz); ++ page_offs += sz; ++ offs += sz; ++ } ++ kunmap(page); ++ } ++ dma_sync_single_for_device(e24->dev, pa, phdr->p_memsz, DMA_TO_DEVICE); ++ return 0; ++} ++ ++static int e24_load_segment_to_iomem(struct e24_device *e24, Elf32_Phdr *phdr) ++{ ++ phys_addr_t pa = e24_translate_to_cpu(e24, phdr); ++ void __iomem *p = ioremap(pa, phdr->p_memsz); ++ ++ if (!p) { ++ dev_err(e24->dev, "couldn't ioremap %pap x 0x%08x\n", ++ &pa, (u32)phdr->p_memsz); ++ return -EINVAL; ++ } ++ if (e24->hw_ops->memcpy_tohw) ++ e24->hw_ops->memcpy_tohw(p, (void *)e24->firmware->data + ++ phdr->p_offset, phdr->p_filesz); ++ else ++ memcpy_toio(p, (void *)e24->firmware->data + phdr->p_offset, ++ ALIGN(phdr->p_filesz, 4)); ++ ++ if (e24->hw_ops->memset_hw) ++ e24->hw_ops->memset_hw(p + phdr->p_filesz, 0, ++ phdr->p_memsz - phdr->p_filesz); ++ else ++ memset_io(p + ALIGN(phdr->p_filesz, 4), 0, ++ ALIGN(phdr->p_memsz - ALIGN(phdr->p_filesz, 4), 4)); ++ ++ iounmap(p); ++ return 0; ++} ++ ++static int e24_load_firmware(struct e24_device *e24_dev) ++{ ++ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)e24_dev->firmware->data; ++ u32 *dai = (u32 *)e24_dev->firmware->data; ++ int i; ++ ++ pr_debug("elf size:%ld,%x,%x\n", e24_dev->firmware->size, dai[0], dai[1]); ++ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { ++ dev_err(e24_dev->dev, "bad firmware ELF magic\n"); ++ return -EINVAL; ++ } ++ ++ if (ehdr->e_type != ET_EXEC) { ++ dev_err(e24_dev->dev, "bad firmware ELF type\n"); ++ return -EINVAL; ++ } ++ ++ if (ehdr->e_machine != EM_RISCV) { ++ dev_err(e24_dev->dev, "bad firmware ELF machine\n"); ++ return -EINVAL; ++ } ++ ++ if (ehdr->e_phoff >= e24_dev->firmware->size || ++ ehdr->e_phoff + ++ ehdr->e_phentsize * ehdr->e_phnum > e24_dev->firmware->size) { ++ dev_err(e24_dev->dev, "bad firmware ELF PHDR information\n"); ++ return -EINVAL; ++ } ++ ++ for (i = ehdr->e_phnum; i >= 0 ; i--) { ++ Elf32_Phdr *phdr = (void *)e24_dev->firmware->data + ++ ehdr->e_phoff + i * ehdr->e_phentsize; ++ phys_addr_t pa; ++ int rc; ++ ++ /* Only load non-empty loadable segments, R/W/X */ ++ if (!(phdr->p_type == PT_LOAD && ++ (phdr->p_flags & (PF_X | PF_R | PF_W)) && ++ phdr->p_memsz > 0)) ++ continue; ++ ++ if (phdr->p_offset >= e24_dev->firmware->size || ++ phdr->p_offset + phdr->p_filesz > e24_dev->firmware->size) { ++ dev_err(e24_dev->dev, "bad firmware ELF program header entry %d\n", i); ++ return -EINVAL; ++ } ++ ++ pa = e24_translate_to_cpu(e24_dev, phdr); ++ if (pa == (phys_addr_t)OF_BAD_ADDR) { ++ dev_err(e24_dev->dev, ++ "device address 0x%08x could not be mapped to host physical address", ++ (u32)phdr->p_paddr); ++ return -EINVAL; ++ } ++ dev_dbg(e24_dev->dev, "loading segment %d (device 0x%08x) to physical %pap\n", ++ i, (u32)phdr->p_paddr, &pa); ++ ++ if (pfn_valid(__phys_to_pfn(pa))) ++ rc = e24_load_segment_to_sysmem(e24_dev, phdr); ++ else ++ rc = e24_load_segment_to_iomem(e24_dev, phdr); ++ ++ if (rc < 0) ++ return rc; ++ } ++ return 0; ++} ++ ++static int e24_boot_firmware(struct device *dev) ++{ ++ int ret; ++ struct e24_device *e24_dev = dev_get_drvdata(dev); ++ ++ if (e24_dev->firmware_name) { ++ ret = request_firmware(&e24_dev->firmware, e24_dev->firmware_name, e24_dev->dev); ++ ++ if (ret < 0) ++ return ret; ++ ++ ret = e24_load_firmware(e24_dev); ++ if (ret < 0) { ++ release_firmware(e24_dev->firmware); ++ return ret; ++ } ++ ++ } ++ ++ release_firmware(e24_dev->firmware); ++ ret = e24_enable_e24(e24_dev); ++ if (ret < 0) ++ return ret; ++ ++ e24_reset_e24(e24_dev); ++ e24_release_e24(e24_dev); ++ e24_synchronize(e24_dev); ++ ++ return ret; ++} ++ ++int e24_runtime_suspend(struct device *dev) ++{ ++ struct e24_device *e24_dev = dev_get_drvdata(dev); ++ ++ e24_halt_e24(e24_dev); ++ e24_disable_e24(e24_dev); ++ ++ return 0; ++} ++ ++long e24_init_v0(struct platform_device *pdev) ++{ ++ long ret = -EINVAL; ++ int nodeid, i; ++ struct e24_hw_arg *hw_arg; ++ struct e24_device *e24_dev; ++ char nodename[sizeof("eboot") + 2 * sizeof(int)]; ++ ++ e24_dev = devm_kzalloc(&pdev->dev, sizeof(*e24_dev), GFP_KERNEL); ++ if (e24_dev == NULL) { ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ hw_arg = devm_kzalloc(&pdev->dev, sizeof(*hw_arg), GFP_KERNEL); ++ if (hw_arg == NULL) ++ return ret; ++ ++ platform_set_drvdata(pdev, e24_dev); ++ e24_dev->dev = &pdev->dev; ++ e24_dev->hw_arg = hw_arg; ++ e24_dev->hw_ops = e24_get_hw_ops(); ++ e24_dev->nodeid = -1; ++ hw_arg->e24 = e24_dev; ++ ++ ret = e24_init_mem_pool(pdev, e24_dev); ++ if (ret < 0) ++ goto err; ++ ++ ret = e24_init_address_map(e24_dev->dev, &e24_dev->address_map); ++ if (ret < 0) ++ goto err_free_pool; ++ ++ e24_dev->n_queues = 1; ++ e24_dev->queue = devm_kmalloc(&pdev->dev, ++ e24_dev->n_queues * sizeof(*e24_dev->queue), ++ GFP_KERNEL); ++ if (e24_dev->queue == NULL) ++ goto err_free_map; ++ ++ for (i = 0; i < e24_dev->n_queues; i++) { ++ mutex_init(&e24_dev->queue[i].lock); ++ e24_dev->queue[i].comm = e24_dev->comm + E24_CMD_STRIDE * i; ++ } ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "irq-mode", ++ &hw_arg->irq_mode); ++ e24_dev->irq_mode = hw_arg->irq_mode; ++ if (hw_arg->irq_mode == 0) ++ dev_info(&pdev->dev, "using polling mode on the device side\n"); ++ ++ e24_dev->mbox_data = e24_translate_to_dsp(&e24_dev->address_map, e24_dev->comm_phys); ++ ret = device_property_read_string(e24_dev->dev, "firmware-name", ++ &e24_dev->firmware_name); ++ if (ret == -EINVAL || ret == -ENODATA) { ++ dev_dbg(e24_dev->dev, ++ "no firmware-name property, not loading firmware"); ++ } else if (ret < 0) { ++ dev_err(e24_dev->dev, "invalid firmware name (%ld)", ret); ++ goto err_free_map; ++ } ++ ++ e24_init(e24_dev); ++ pm_runtime_set_active(e24_dev->dev); ++ pm_runtime_enable(e24_dev->dev); ++ if (!pm_runtime_enabled(e24_dev->dev)) { ++ ret = e24_boot_firmware(e24_dev->dev); ++ if (ret) ++ goto err_pm_disable; ++ } ++ nodeid = ida_simple_get(&e24_nodeid, 0, 0, GFP_KERNEL); ++ if (nodeid < 0) { ++ ret = nodeid; ++ goto err_pm_disable; ++ } ++ ++ e24_dev->nodeid = nodeid; ++ sprintf(nodename, "eboot%u", nodeid); ++ ++ e24_dev->miscdev = (struct miscdevice){ ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = devm_kstrdup(&pdev->dev, nodename, GFP_KERNEL), ++ .nodename = devm_kstrdup(&pdev->dev, nodename, GFP_KERNEL), ++ .fops = &e24_fops, ++ }; ++ ++ ret = misc_register(&e24_dev->miscdev); ++ if (ret < 0) ++ goto err_free_id; ++ ++ return PTR_ERR(e24_dev); ++err_free_id: ++ ida_simple_remove(&e24_nodeid, nodeid); ++ ++err_pm_disable: ++ pm_runtime_disable(e24_dev->dev); ++err_free_map: ++ kfree(e24_dev->address_map.entry); ++err_free_pool: ++ e24_free_pool(e24_dev->pool); ++err: ++ dev_err(&pdev->dev, "%s: ret = %ld\n", __func__, ret); ++ return ret; ++} ++ ++static const struct of_device_id e24_of_match[] = { ++ { ++ .compatible = "starfive,e24", ++ .data = e24_init_v0, ++ }, ++ { ++ }, ++}; ++MODULE_DEVICE_TABLE(of, e24_of_match); ++ ++int e24_deinit(struct platform_device *pdev) ++{ ++ struct e24_device *e24_dev = platform_get_drvdata(pdev); ++ ++ pm_runtime_disable(&pdev->dev); ++ if (!pm_runtime_status_suspended(e24_dev->dev)) ++ e24_runtime_suspend(e24_dev->dev); ++ ++ misc_deregister(&e24_dev->miscdev); ++ e24_free_pool(e24_dev->pool); ++ kfree(e24_dev->address_map.entry); ++ ida_simple_remove(&e24_nodeid, e24_dev->nodeid); ++ ++ if (e24_dev->rx_channel) ++ mbox_free_channel(e24_dev->rx_channel); ++ if (e24_dev->tx_channel) ++ mbox_free_channel(e24_dev->tx_channel); ++ return 0; ++} ++ ++static int e24_probe(struct platform_device *pdev) ++{ ++ long ret = -EINVAL; ++ const e24_init_function *init; ++ ++ init = of_device_get_match_data(&pdev->dev); ++ ret = init(pdev); ++ ++ return IS_ERR_VALUE(ret) ? ret : 0; ++} ++ ++static void e24_remove(struct platform_device *pdev) ++{ ++ e24_deinit(pdev); ++} ++ ++static const struct dev_pm_ops e24_runtime_pm_ops = { ++ SET_RUNTIME_PM_OPS(e24_runtime_suspend, ++ e24_boot_firmware, NULL) ++}; ++ ++static struct platform_driver e24_driver = { ++ .probe = e24_probe, ++ .remove = e24_remove, ++ .driver = { ++ .name = "e24_boot", ++ .of_match_table = of_match_ptr(e24_of_match), ++ .pm = &e24_runtime_pm_ops, ++ }, ++}; ++ ++module_platform_driver(e24_driver); ++ ++MODULE_DESCRIPTION("StarFive e24 driver"); ++MODULE_AUTHOR("Shanlong Li "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/e24/starfive_e24.h +@@ -0,0 +1,159 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __STARFIVE_E24_H__ ++#define __STARFIVE_E24_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define E24_IOCTL_MAGIC 'e' ++#define E24_IOCTL_SEND _IO(E24_IOCTL_MAGIC, 1) ++#define E24_IOCTL_RECV _IO(E24_IOCTL_MAGIC, 2) ++#define E24_IOCTL_GET_CHANNEL _IO(E24_IOCTL_MAGIC, 3) ++#define E24_IOCTL_FREE_CHANNEL _IO(E24_IOCTL_MAGIC, 4) ++#define E24_IOCTL_ALLOC _IO(E24_IOCTL_MAGIC, 5) ++#define E24_IOCTL_FREE _IO(E24_IOCTL_MAGIC, 6) ++ ++#define E24_DSP_CMD_INLINE_DATA_SIZE 16 ++#define E24_NO_TRANSLATION ((u32)~0ul) ++#define E24_CMD_STRIDE 256 ++ ++#define E24_MEM_MAP ++enum e24_irq_mode { ++ MAIL_IRQ_NONE, ++ MAIL_IRQ_LEVEL, ++ MAIL_IRQ_MAX ++}; ++ ++enum { ++ E24_FLAG_READ = 0x1, ++ E24_FLAG_WRITE = 0x2, ++ E24_FLAG_READ_WRITE = 0x3, ++}; ++ ++enum { ++ E24_QUEUE_FLAG_VALID = 0x4, ++ E24_QUEUE_FLAG_PRIO = 0xff00, ++ E24_QUEUE_FLAG_PRIO_SHIFT = 8, ++ ++ E24_QUEUE_VALID_FLAGS = ++ E24_QUEUE_FLAG_VALID | ++ E24_QUEUE_FLAG_PRIO, ++}; ++ ++enum { ++ E24_CMD_FLAG_REQUEST_VALID = 0x00000001, ++ E24_CMD_FLAG_RESPONSE_VALID = 0x00000002, ++ E24_CMD_FLAG_REQUEST_NSID = 0x00000004, ++ E24_CMD_FLAG_RESPONSE_DELIVERY_FAIL = 0x00000008, ++}; ++ ++struct e24_address_map_entry { ++ phys_addr_t src_addr; ++ u32 dst_addr; ++ u32 size; ++}; ++ ++struct e24_address_map { ++ unsigned int n; ++ struct e24_address_map_entry *entry; ++}; ++ ++struct e24_alien_mapping { ++ unsigned long vaddr; ++ unsigned long size; ++ phys_addr_t paddr; ++ void *allocation; ++ enum { ++ ALIEN_GUP, ++ ALIEN_PFN_MAP, ++ ALIEN_COPY, ++ } type; ++}; ++ ++struct e24_mapping { ++ enum { ++ E24_MAPPING_NONE, ++ E24_MAPPING_NATIVE, ++ E24_MAPPING_ALIEN, ++ E24_MAPPING_KERNEL = 0x4, ++ } type; ++ union { ++ struct { ++ struct e24_allocation *m_allocation; ++ unsigned long vaddr; ++ } native; ++ struct e24_alien_mapping alien_mapping; ++ }; ++}; ++ ++struct e24_ioctl_alloc { ++ u32 size; ++ u32 align; ++ u64 addr; ++}; ++ ++struct e24_comm { ++ struct mutex lock; ++ void __iomem *comm; ++ struct completion completion; ++ u32 priority; ++}; ++ ++struct e24_device { ++ struct device *dev; ++ const char *firmware_name; ++ const struct firmware *firmware; ++ struct miscdevice miscdev; ++ const struct e24_hw_ops *hw_ops; ++ void *hw_arg; ++ int irq_mode; ++ ++ u32 n_queues; ++ struct completion completion; ++ struct e24_address_map address_map; ++ struct e24_comm *queue; ++ void __iomem *comm; ++ phys_addr_t comm_phys; ++ phys_addr_t shared_mem; ++ phys_addr_t shared_size; ++ ++ u32 mbox_data; ++ int nodeid; ++ spinlock_t busy_list_lock; ++ ++ struct mbox_chan *tx_channel; ++ struct mbox_chan *rx_channel; ++ void *rx_buffer; ++ void *message; ++ struct e24_allocation_pool *pool; ++ struct e24_allocation *busy_list; ++}; ++ ++struct e24_hw_arg { ++ struct e24_device *e24; ++ phys_addr_t regs_phys; ++ struct clk *clk_rtc; ++ struct clk *clk_core; ++ struct clk *clk_dbg; ++ struct reset_control *rst_core; ++ struct regmap *reg_syscon; ++ enum e24_irq_mode irq_mode; ++}; ++ ++static inline int e24_compare_address(phys_addr_t addr, ++ const struct e24_address_map_entry *entry) ++{ ++ if (addr < entry->src_addr) ++ return -1; ++ if (addr - entry->src_addr < entry->size) ++ return 0; ++ return 1; ++} ++ ++irqreturn_t e24_irq_handler(int irq, struct e24_device *e24_hw); ++ ++#endif +--- /dev/null ++++ b/drivers/e24/starfive_e24_hw.c +@@ -0,0 +1,134 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "starfive_e24.h" ++#include "starfive_e24_hw.h" ++ ++#define RET_E24_VECTOR_ADDR 0x6CE00000 ++ ++static void halt(void *hw_arg) ++{ ++ struct e24_hw_arg *mail_arg = hw_arg; ++ ++ reset_control_assert(mail_arg->rst_core); ++ pr_debug("e24 halt.\n"); ++} ++ ++static void release(void *hw_arg) ++{ ++ struct e24_hw_arg *mail_arg = hw_arg; ++ ++ reset_control_deassert(mail_arg->rst_core); ++ pr_debug("e24 begin run.\n"); ++} ++ ++static void reset(void *hw_arg) ++{ ++ struct e24_hw_arg *mail_arg = hw_arg; ++ ++ regmap_update_bits(mail_arg->reg_syscon, 0x24, 0xFFFFFFFF, RET_E24_VECTOR_ADDR); ++ pr_debug("e24 reset vector.\n"); ++} ++ ++static void disable(void *hw_arg) ++{ ++ struct e24_hw_arg *mail_arg = hw_arg; ++ ++ clk_disable_unprepare(mail_arg->clk_core); ++ clk_disable_unprepare(mail_arg->clk_dbg); ++ clk_disable_unprepare(mail_arg->clk_rtc); ++ ++ pr_debug("e24 disable ...\n"); ++ ++} ++ ++static int enable(void *hw_arg) ++{ ++ struct e24_hw_arg *mail_arg = hw_arg; ++ int ret = 0; ++ ++ ret = clk_prepare_enable(mail_arg->clk_core); ++ if (ret) ++ return -EAGAIN; ++ ++ ret = clk_prepare_enable(mail_arg->clk_dbg); ++ if (ret) { ++ clk_disable_unprepare(mail_arg->clk_core); ++ return -EAGAIN; ++ } ++ ++ ret = clk_prepare_enable(mail_arg->clk_rtc); ++ if (ret) { ++ clk_disable_unprepare(mail_arg->clk_core); ++ clk_disable_unprepare(mail_arg->clk_dbg); ++ return -EAGAIN; ++ } ++ ++ pr_debug("e24_enable clk ...\n"); ++ return 0; ++} ++ ++ ++static int init(void *hw_arg) ++{ ++ struct e24_hw_arg *mail_arg = hw_arg; ++ ++ mail_arg->reg_syscon = syscon_regmap_lookup_by_phandle( ++ mail_arg->e24->dev->of_node, ++ "starfive,stg-syscon"); ++ if (IS_ERR(mail_arg->reg_syscon)) { ++ dev_err(mail_arg->e24->dev, "No starfive,stg-syscon\n"); ++ return PTR_ERR(mail_arg->reg_syscon); ++ } ++ ++ mail_arg->clk_core = devm_clk_get_optional(mail_arg->e24->dev, "clk_core"); ++ if (IS_ERR(mail_arg->clk_core)) { ++ dev_err(mail_arg->e24->dev, "failed to get e24 clk core\n"); ++ return -ENOMEM; ++ } ++ ++ mail_arg->clk_dbg = devm_clk_get_optional(mail_arg->e24->dev, "clk_dbg"); ++ if (IS_ERR(mail_arg->clk_dbg)) { ++ dev_err(mail_arg->e24->dev, "failed to get e24 clk dbg\n"); ++ return -ENOMEM; ++ } ++ ++ mail_arg->clk_rtc = devm_clk_get_optional(mail_arg->e24->dev, "clk_rtc"); ++ if (IS_ERR(mail_arg->clk_rtc)) { ++ dev_err(mail_arg->e24->dev, "failed to get e24 clk rtc\n"); ++ return -ENOMEM; ++ } ++ ++ mail_arg->rst_core = devm_reset_control_get_exclusive(mail_arg->e24->dev, "e24_core"); ++ if (IS_ERR(mail_arg->rst_core)) { ++ dev_err(mail_arg->e24->dev, "failed to get e24 reset\n"); ++ return -ENOMEM; ++ } ++ ++ enable(hw_arg); ++ ++ return 0; ++} ++ ++static struct e24_hw_ops e24_hw_ops = { ++ .init = init, ++ .enable = enable, ++ .reset = reset, ++ .halt = halt, ++ .release = release, ++ .disable = disable, ++}; ++ ++struct e24_hw_ops *e24_get_hw_ops(void) ++{ ++ return &e24_hw_ops; ++} +--- /dev/null ++++ b/drivers/e24/starfive_e24_hw.h +@@ -0,0 +1,94 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __STARFIVE_E24_HW_H__ ++#define __STARFIVE_E24_HW_H__ ++/* ++ * Hardware-specific operation entry points. ++ */ ++struct e24_hw_ops { ++ /* ++ * Gets the clock for E24. ++ */ ++ int (*init)(void *hw_arg); ++ /* ++ * Enable power/clock, but keep the core stalled. ++ */ ++ int (*enable)(void *hw_arg); ++ /* ++ * Diable power/clock. ++ */ ++ void (*disable)(void *hw_arg); ++ /* ++ * Reset the core. ++ */ ++ void (*reset)(void *hw_arg); ++ /* ++ * Unstall the core. ++ */ ++ void (*release)(void *hw_arg); ++ /* ++ * Stall the core. ++ */ ++ void (*halt)(void *hw_arg); ++ ++ /* Get HW-specific data to pass to the DSP on synchronization ++ * ++ * param hw_arg: opaque parameter passed to DSP at initialization ++ * param sz: return size of sync data here ++ * return a buffer allocated with kmalloc that the caller will free ++ */ ++ void *(*get_hw_sync_data)(void *hw_arg, size_t *sz); ++ ++ /* ++ * Send IRQ to the core. ++ */ ++ void (*send_irq)(void *hw_arg); ++ ++ /* ++ * Check whether region of physical memory may be handled by ++ * dma_sync_* operations ++ * ++ * \param hw_arg: opaque parameter passed to DSP at initialization ++ * time ++ */ ++ bool (*cacheable)(void *hw_arg, unsigned long pfn, unsigned long n_pages); ++ /* ++ * Synchronize region of memory for DSP access. ++ * ++ * \param hw_arg: opaque parameter passed to DSP at initialization ++ * time ++ */ ++ void (*dma_sync_for_device)(void *hw_arg, ++ void *vaddr, phys_addr_t paddr, ++ unsigned long sz, unsigned int flags); ++ /* ++ * Synchronize region of memory for host access. ++ * ++ * \param hw_arg: opaque parameter passed to DSP at initialization ++ * time ++ */ ++ void (*dma_sync_for_cpu)(void *hw_arg, ++ void *vaddr, phys_addr_t paddr, ++ unsigned long sz, unsigned int flags); ++ ++ /* ++ * memcpy data/code to device-specific memory. ++ */ ++ void (*memcpy_tohw)(void __iomem *dst, const void *src, size_t sz); ++ /* ++ * memset device-specific memory. ++ */ ++ void (*memset_hw)(void __iomem *dst, int c, size_t sz); ++ ++ /* ++ * Check DSP status. ++ * ++ * \param hw_arg: opaque parameter passed to DSP at initialization ++ * time ++ * \return whether the core has crashed and needs to be restarted ++ */ ++ bool (*panic_check)(void *hw_arg); ++}; ++ ++long e24_init_hw(struct platform_device *pdev, void *hw_arg); ++struct e24_hw_ops *e24_get_hw_ops(void); ++#endif diff --git a/target/linux/starfive/patches-6.12/0019-net-stmmac-Extend-waiting-time-of-dma-reset.patch b/target/linux/starfive/patches-6.12/0019-net-stmmac-Extend-waiting-time-of-dma-reset.patch new file mode 100644 index 0000000000..3814cfbb6b --- /dev/null +++ b/target/linux/starfive/patches-6.12/0019-net-stmmac-Extend-waiting-time-of-dma-reset.patch @@ -0,0 +1,23 @@ +From 0eaf04ef4963db173428da176f52320754b0574c Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Thu, 10 Oct 2024 11:05:20 +0800 +Subject: [PATCH 19/55] net: stmmac: Extend waiting time of dma reset + +Fix dma reset failure happening when disabling network. + +Signed-off-by: Hal Feng +--- + drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +@@ -23,7 +23,7 @@ int dwmac4_dma_reset(void __iomem *ioadd + + return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, + !(value & DMA_BUS_MODE_SFT_RESET), +- 10000, 1000000); ++ 10000, 3000000); + } + + void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr, diff --git a/target/linux/starfive/patches-6.12/0020-spi-pl022-starfive-Add-platform-bus-register-to-adap.patch b/target/linux/starfive/patches-6.12/0020-spi-pl022-starfive-Add-platform-bus-register-to-adap.patch new file mode 100644 index 0000000000..6c0f51eaa9 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0020-spi-pl022-starfive-Add-platform-bus-register-to-adap.patch @@ -0,0 +1,235 @@ +From 714c99f993097e5c16822e73ba0a7945b86a20ea Mon Sep 17 00:00:00 2001 +From: "xingyu.wu" +Date: Tue, 28 Jun 2022 22:48:15 +0800 +Subject: [PATCH 20/55] spi-pl022:starfive:Add platform bus register to adapt + overlay + +Add platform bus register to adapt dtbo overlay. + +Signed-off-by: Xingyu Wu +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 143 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 137 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + /* + * This macro is used to define some register default values. +@@ -1841,7 +1842,10 @@ pl022_platform_data_dt_get(struct device + return NULL; + } + +- pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); ++ if (strncmp(dev->bus->name, "platform", strlen("platform"))) ++ pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); ++ else ++ pd = kzalloc(sizeof(struct pl022_ssp_controller), GFP_KERNEL); + if (!pd) + return NULL; + +@@ -1861,6 +1865,14 @@ static int pl022_probe(struct amba_devic + struct spi_controller *host; + struct pl022 *pl022 = NULL; /*Data for this driver */ + int status = 0; ++ int platform_flag = 0; ++ ++ if (strncmp(dev->bus->name, "platform", strlen("platform"))) ++ platform_flag = 0; ++ else ++ platform_flag = 1; ++ dev_dbg(&adev->dev, "bus name:%s platform flag:%d", ++ dev->bus->name, platform_flag); + + dev_info(&adev->dev, + "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); +@@ -1916,7 +1928,11 @@ static int pl022_probe(struct amba_devic + goto err_no_ioregion; + + pl022->phybase = adev->res.start; +- pl022->virtbase = devm_ioremap(dev, adev->res.start, ++ if (platform_flag) ++ pl022->virtbase = ioremap(adev->res.start, ++ resource_size(&adev->res)); ++ else ++ pl022->virtbase = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (pl022->virtbase == NULL) { + status = -ENOMEM; +@@ -1925,14 +1941,28 @@ static int pl022_probe(struct amba_devic + dev_info(&adev->dev, "mapped registers from %pa to %p\n", + &adev->res.start, pl022->virtbase); + +- pl022->clk = devm_clk_get_enabled(&adev->dev, NULL); ++ if (platform_flag) ++ pl022->clk = clk_get(&adev->dev, NULL); ++ else ++ pl022->clk = devm_clk_get_enabled(&adev->dev, NULL); + if (IS_ERR(pl022->clk)) { + status = PTR_ERR(pl022->clk); + dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); + goto err_no_clk; + } + +- pl022->rst = devm_reset_control_get(&adev->dev, NULL); ++ if (platform_flag) { ++ status = clk_prepare_enable(pl022->clk); ++ if (status) { ++ dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); ++ goto err_no_clk_en; ++ } ++ } ++ ++ if (platform_flag) ++ pl022->rst = reset_control_get_exclusive(&adev->dev, NULL); ++ else ++ pl022->rst = devm_reset_control_get(&adev->dev, NULL); + if (IS_ERR(pl022->rst)) { + status = PTR_ERR(pl022->rst); + dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n"); +@@ -1950,7 +1980,11 @@ static int pl022_probe(struct amba_devic + SSP_CR1(pl022->virtbase)); + load_ssp_default_config(pl022); + +- status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, ++ if (platform_flag) ++ status = request_irq(adev->irq[0], pl022_interrupt_handler, ++ 0, "pl022", pl022); ++ else ++ status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, + 0, "pl022", pl022); + if (status < 0) { + dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); +@@ -1975,7 +2009,10 @@ static int pl022_probe(struct amba_devic + + /* Register with the SPI framework */ + amba_set_drvdata(adev, pl022); +- status = devm_spi_register_controller(&adev->dev, host); ++ if (platform_flag) ++ status = spi_register_controller(host); ++ else ++ status = devm_spi_register_controller(&adev->dev, host); + if (status != 0) { + dev_err_probe(&adev->dev, status, + "problem registering spi host\n"); +@@ -2000,13 +2037,24 @@ static int pl022_probe(struct amba_devic + if (platform_info->enable_dma) + pl022_dma_remove(pl022); + err_no_irq: ++ if (platform_flag) ++ free_irq(adev->irq[0], pl022); ++ reset_control_assert(pl022->rst); + err_no_rst_de: ++ if (platform_flag) ++ reset_control_put(pl022->rst); + err_no_rst: ++ if (platform_flag) ++ clk_put(pl022->clk); + err_no_clk: ++ if (platform_flag) ++ iounmap(pl022->virtbase); + err_no_ioremap: + amba_release_regions(adev); + err_no_ioregion: + spi_controller_put(host); ++ if (platform_flag) ++ kfree(platform_info); + return status; + } + +@@ -2205,6 +2253,89 @@ static void __exit pl022_exit(void) + } + module_exit(pl022_exit); + ++/* ++ * Register PL022 in platform bus to accommodate overlay use. ++ * Because overlay only trigger response from the platform bus ++ * not amba bus. ++ */ ++static int starfive_of_pl022_probe(struct platform_device *pdev) ++{ ++ int ret; ++ const struct amba_id id = { ++ .id = 0x00041022, ++ .mask = 0x000fffff, ++ .data = &vendor_arm ++ }; ++ struct amba_device *pcdev; ++ struct device *dev = &pdev->dev; ++ ++ pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); ++ if (!pcdev) ++ return -ENOMEM; ++ ++ pcdev->dev = pdev->dev; ++ pcdev->periphid = id.id; ++ pcdev->res = *(pdev->resource); ++ ++ pcdev->irq[0] = platform_get_irq(pdev, 0); ++ if (pcdev->irq[0] < 0) { ++ dev_err(dev, "failed to get irq\n"); ++ ret = -EINVAL; ++ } ++ ++ ret = pl022_probe(pcdev, &id); ++ ++ return ret; ++} ++ ++static void starfive_of_pl022_remove(struct platform_device *pdev) ++{ ++ u32 size; ++ int irq; ++ struct pl022 *pl022 = dev_get_drvdata(&pdev->dev); ++ ++ if (!pl022) ++ return; ++ ++ pm_runtime_get_noresume(&pdev->dev); ++ ++ load_ssp_default_config(pl022); ++ if (pl022->host_info->enable_dma) ++ pl022_dma_remove(pl022); ++ ++ irq = platform_get_irq(pdev, 0); ++ free_irq(irq, pl022); ++ reset_control_assert(pl022->rst); ++ reset_control_put(pl022->rst); ++ clk_disable_unprepare(pl022->clk); ++ clk_put(pl022->clk); ++ iounmap(pl022->virtbase); ++ kfree(pl022->host_info); ++ ++ size = resource_size(pdev->resource); ++ release_mem_region(pdev->resource->start, size); ++} ++ ++static const struct of_device_id starfive_of_pl022_match[] = { ++ { .compatible = "starfive,jh7110-spi-pl022" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, starfive_of_pl022_match); ++ ++static struct platform_driver starfive_of_pl022_driver = { ++ .driver = { ++ .name = "starfive-spi-pl022", ++ .of_match_table = starfive_of_pl022_match, ++ .pm = &pl022_dev_pm_ops, ++ }, ++ .probe = starfive_of_pl022_probe, ++ .remove = starfive_of_pl022_remove, ++}; ++ ++module_platform_driver(starfive_of_pl022_driver); ++/* platform register end */ ++ ++MODULE_AUTHOR("xingyu.wu "); + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("PL022 SSP Controller Driver"); + MODULE_LICENSE("GPL"); diff --git a/target/linux/starfive/patches-6.12/0021-spi-pl022-starfive-Avoid-power-device-error-when-CON.patch b/target/linux/starfive/patches-6.12/0021-spi-pl022-starfive-Avoid-power-device-error-when-CON.patch new file mode 100644 index 0000000000..a2ec87131c --- /dev/null +++ b/target/linux/starfive/patches-6.12/0021-spi-pl022-starfive-Avoid-power-device-error-when-CON.patch @@ -0,0 +1,92 @@ +From 8063cc5e813c3a5f86a4f17e3681cda3dbebcb1a Mon Sep 17 00:00:00 2001 +From: "xingyu.wu" +Date: Tue, 19 Jul 2022 14:49:20 +0800 +Subject: [PATCH 21/55] spi:pl022-starfive:Avoid power device error when + CONFIG_PM enable + +It would be error when CONFIG_PM enable and use overlay by of-platform to register. + +Add some power manager operation in platform probe function. + +Signed-off-by: Xingyu Wu +Signed-off-by: Ziv Xu +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 36 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 34 insertions(+), 2 deletions(-) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -35,6 +35,8 @@ + #include + #include + #include ++#include ++#include + + /* + * This macro is used to define some register default values. +@@ -2019,7 +2021,8 @@ static int pl022_probe(struct amba_devic + goto err_spi_register; + } + dev_dbg(dev, "probe succeeded\n"); +- ++ if (!platform_flag) ++ platform_info->autosuspend_delay = 100; + /* let runtime pm put suspend */ + if (platform_info->autosuspend_delay > 0) { + dev_info(&adev->dev, +@@ -2029,7 +2032,10 @@ static int pl022_probe(struct amba_devic + platform_info->autosuspend_delay); + pm_runtime_use_autosuspend(dev); + } +- pm_runtime_put(dev); ++ if (platform_flag) ++ clk_disable_unprepare(pl022->clk); ++ else ++ pm_runtime_put(dev); + + return 0; + +@@ -2283,8 +2289,33 @@ static int starfive_of_pl022_probe(struc + ret = -EINVAL; + } + ++ ret = of_clk_set_defaults(dev->of_node, false); ++ if (ret < 0) ++ goto err_probe; ++ ++ ret = dev_pm_domain_attach(dev, true); ++ if (ret) ++ goto err_probe; ++ + ret = pl022_probe(pcdev, &id); + ++ struct pl022 *pl022 = amba_get_drvdata(pcdev); ++ ++ pl022->host->dev.parent = &pdev->dev; ++ platform_set_drvdata(pdev, pl022); ++ ++ pm_runtime_enable(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(&pdev->dev, 100); ++ pm_runtime_use_autosuspend(&pdev->dev); ++ ++ if (ret) { ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_put_noidle(dev); ++ dev_pm_domain_detach(dev, true); ++ } ++ ++err_probe: + return ret; + } + +@@ -2314,6 +2345,7 @@ static void starfive_of_pl022_remove(str + + size = resource_size(pdev->resource); + release_mem_region(pdev->resource->start, size); ++ pm_runtime_disable(&pdev->dev); + } + + static const struct of_device_id starfive_of_pl022_match[] = { diff --git a/target/linux/starfive/patches-6.12/0022-spi-pl022-starfive-fix-the-problem-of-spi-overlay-re.patch b/target/linux/starfive/patches-6.12/0022-spi-pl022-starfive-fix-the-problem-of-spi-overlay-re.patch new file mode 100644 index 0000000000..15b84adeef --- /dev/null +++ b/target/linux/starfive/patches-6.12/0022-spi-pl022-starfive-fix-the-problem-of-spi-overlay-re.patch @@ -0,0 +1,396 @@ +From 7a98fafdc544b85694db5d99cdf933a4640058f9 Mon Sep 17 00:00:00 2001 +From: "ziv.xu" +Date: Wed, 23 Nov 2022 14:53:58 +0800 +Subject: [PATCH 22/55] spi-pl022-starfive:fix the problem of spi overlay + reload + +fix the problem of spi overlay reload + +Signed-off-by: ziv.xu +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 266 ++++++++++++++++++++++++++-------------- + 1 file changed, 177 insertions(+), 89 deletions(-) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -1859,6 +1859,163 @@ pl022_platform_data_dt_get(struct device + return pd; + } + ++static int pl022_platform_probe(struct platform_device *pdev, const struct amba_id *id) ++{ ++ struct device *dev = &pdev->dev; ++ struct spi_controller *host; ++ struct pl022_ssp_controller *platform_info; ++ struct amba_device *adev; ++ struct pl022 *pl022 = NULL; ++ struct resource *res; ++ int status = 0; ++ int irq; ++ ++ dev_info(dev, ++ "ARM PL022 driver for StarFive SoC platform, device ID: 0x%08x\n", ++ id->id); ++ ++ adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); ++ adev->dev = pdev->dev; ++ platform_info = pl022_platform_data_dt_get(dev); ++ if (!platform_info) { ++ dev_err(dev, "probe: no platform data defined\n"); ++ return -ENODEV; ++ } ++ /* Allocate host with space for data */ ++ host = spi_alloc_host(dev, sizeof(struct pl022)); ++ if (host == NULL) { ++ dev_err(dev, "probe - cannot alloc SPI host\n"); ++ return -ENOMEM; ++ } ++ ++ pl022 = spi_controller_get_devdata(host); ++ pl022->host = host; ++ pl022->host_info = platform_info; ++ pl022->adev = adev; ++ pl022->vendor = id->data; ++ pl022->host->dev.parent = &pdev->dev; ++ /* ++ * Bus Number Which has been Assigned to this SSP controller ++ * on this board ++ */ ++ host->bus_num = platform_info->bus_id; ++ host->cleanup = pl022_cleanup; ++ host->setup = pl022_setup; ++ /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/ ++ host->auto_runtime_pm = true; ++ host->transfer_one = pl022_transfer_one; ++ host->set_cs = pl022_cs_control; ++ host->handle_err = pl022_handle_err; ++ host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; ++ host->rt = platform_info->rt; ++ host->dev.of_node = dev->of_node; ++ host->use_gpio_descriptors = true; ++ ++ /* ++ * Supports mode 0-3, loopback, and active low CS. Transfers are ++ * always MS bit first on the original pl022. ++ */ ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; ++ if (pl022->vendor->extended_cr) ++ host->mode_bits |= SPI_LSB_FIRST; ++ ++ dev_dbg(dev, "BUSNO: %d\n", host->bus_num); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pl022->phybase = res->start; ++ pl022->virtbase = devm_ioremap_resource(dev, res); ++ if (pl022->virtbase == NULL) { ++ status = -ENOMEM; ++ goto err_no_ioremap; ++ } ++ dev_info(dev, "mapped registers from %llx to %llx\n", ++ pdev->resource->start, pdev->resource->end); ++ ++ pl022->clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(pl022->clk)) { ++ status = PTR_ERR(pl022->clk); ++ dev_err(dev, "could not retrieve SSP/SPI bus clock\n"); ++ goto err_no_clk; ++ } ++ ++ pl022->rst = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(pl022->rst)) { ++ status = PTR_ERR(pl022->rst); ++ dev_err(dev, "could not retrieve SSP/SPI bus reset\n"); ++ goto err_no_rst; ++ } ++ ++ status = reset_control_deassert(pl022->rst); ++ if (status) { ++ dev_err(dev, "could not deassert SSP/SPI bus reset\n"); ++ goto err_no_rst_de; ++ } ++ ++ /* Disable SSP */ ++ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), ++ SSP_CR1(pl022->virtbase)); ++ load_ssp_default_config(pl022); ++ ++ /* Obtain IRQ line. */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ status = -ENXIO; ++ goto err_no_irq; ++ } ++ status = devm_request_irq(dev, irq, pl022_interrupt_handler, ++ 0, "pl022", pl022); ++ if (status < 0) { ++ dev_err(dev, "probe - cannot get IRQ (%d)\n", status); ++ goto err_no_irq; ++ } ++ ++ /* Get DMA channels, try autoconfiguration first */ ++ status = pl022_dma_autoprobe(pl022); ++ if (status == -EPROBE_DEFER) { ++ dev_dbg(dev, "deferring probe to get DMA channel\n"); ++ goto err_no_irq; ++ } ++ ++ /* dma is not used unless configured in the device tree */ ++ platform_info->enable_dma = 0; ++ ++ /* If that failed, use channels from platform_info */ ++ if (status == 0) ++ platform_info->enable_dma = 1; ++ else if (platform_info->enable_dma) { ++ status = pl022_dma_probe(pl022); ++ if (status != 0) ++ platform_info->enable_dma = 0; ++ } ++ ++ /* Register with the SPI framework */ ++ dev_set_drvdata(dev, pl022); ++ ++ status = devm_spi_register_controller(dev, host); ++ if (status != 0) { ++ dev_err(dev, ++ "probe - problem registering spi host\n"); ++ goto err_spi_register; ++ } ++ dev_dbg(dev, "probe succeeded\n"); ++ ++ clk_disable_unprepare(pl022->clk); ++ ++ return 0; ++ err_spi_register: ++ if (platform_info->enable_dma) ++ pl022_dma_remove(pl022); ++ err_no_irq: ++ reset_control_assert(pl022->rst); ++ err_no_rst_de: ++ err_no_rst: ++ err_no_clk: ++ err_no_ioremap: ++ release_mem_region(pdev->resource->start, resource_size(pdev->resource)); ++ spi_controller_put(host); ++ return status; ++} ++ + static int pl022_probe(struct amba_device *adev, const struct amba_id *id) + { + struct device *dev = &adev->dev; +@@ -1867,14 +2024,6 @@ static int pl022_probe(struct amba_devic + struct spi_controller *host; + struct pl022 *pl022 = NULL; /*Data for this driver */ + int status = 0; +- int platform_flag = 0; +- +- if (strncmp(dev->bus->name, "platform", strlen("platform"))) +- platform_flag = 0; +- else +- platform_flag = 1; +- dev_dbg(&adev->dev, "bus name:%s platform flag:%d", +- dev->bus->name, platform_flag); + + dev_info(&adev->dev, + "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); +@@ -1930,11 +2079,7 @@ static int pl022_probe(struct amba_devic + goto err_no_ioregion; + + pl022->phybase = adev->res.start; +- if (platform_flag) +- pl022->virtbase = ioremap(adev->res.start, +- resource_size(&adev->res)); +- else +- pl022->virtbase = devm_ioremap(dev, adev->res.start, ++ pl022->virtbase = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (pl022->virtbase == NULL) { + status = -ENOMEM; +@@ -1943,28 +2088,14 @@ static int pl022_probe(struct amba_devic + dev_info(&adev->dev, "mapped registers from %pa to %p\n", + &adev->res.start, pl022->virtbase); + +- if (platform_flag) +- pl022->clk = clk_get(&adev->dev, NULL); +- else +- pl022->clk = devm_clk_get_enabled(&adev->dev, NULL); ++ pl022->clk = devm_clk_get_enabled(&adev->dev, NULL); + if (IS_ERR(pl022->clk)) { + status = PTR_ERR(pl022->clk); + dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); + goto err_no_clk; + } + +- if (platform_flag) { +- status = clk_prepare_enable(pl022->clk); +- if (status) { +- dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); +- goto err_no_clk_en; +- } +- } +- +- if (platform_flag) +- pl022->rst = reset_control_get_exclusive(&adev->dev, NULL); +- else +- pl022->rst = devm_reset_control_get(&adev->dev, NULL); ++ pl022->rst = devm_reset_control_get(&adev->dev, NULL); + if (IS_ERR(pl022->rst)) { + status = PTR_ERR(pl022->rst); + dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n"); +@@ -1982,11 +2113,7 @@ static int pl022_probe(struct amba_devic + SSP_CR1(pl022->virtbase)); + load_ssp_default_config(pl022); + +- if (platform_flag) +- status = request_irq(adev->irq[0], pl022_interrupt_handler, +- 0, "pl022", pl022); +- else +- status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, ++ status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, + 0, "pl022", pl022); + if (status < 0) { + dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); +@@ -2011,18 +2138,16 @@ static int pl022_probe(struct amba_devic + + /* Register with the SPI framework */ + amba_set_drvdata(adev, pl022); +- if (platform_flag) +- status = spi_register_controller(host); +- else +- status = devm_spi_register_controller(&adev->dev, host); ++ ++ status = devm_spi_register_controller(&adev->dev, host); + if (status != 0) { + dev_err_probe(&adev->dev, status, + "problem registering spi host\n"); + goto err_spi_register; + } + dev_dbg(dev, "probe succeeded\n"); +- if (!platform_flag) +- platform_info->autosuspend_delay = 100; ++ ++ platform_info->autosuspend_delay = 100; + /* let runtime pm put suspend */ + if (platform_info->autosuspend_delay > 0) { + dev_info(&adev->dev, +@@ -2032,10 +2157,8 @@ static int pl022_probe(struct amba_devic + platform_info->autosuspend_delay); + pm_runtime_use_autosuspend(dev); + } +- if (platform_flag) +- clk_disable_unprepare(pl022->clk); +- else +- pm_runtime_put(dev); ++ ++ pm_runtime_put(dev); + + return 0; + +@@ -2043,24 +2166,15 @@ static int pl022_probe(struct amba_devic + if (platform_info->enable_dma) + pl022_dma_remove(pl022); + err_no_irq: +- if (platform_flag) +- free_irq(adev->irq[0], pl022); + reset_control_assert(pl022->rst); + err_no_rst_de: +- if (platform_flag) +- reset_control_put(pl022->rst); + err_no_rst: +- if (platform_flag) +- clk_put(pl022->clk); + err_no_clk: +- if (platform_flag) +- iounmap(pl022->virtbase); + err_no_ioremap: + amba_release_regions(adev); + err_no_ioregion: + spi_controller_put(host); +- if (platform_flag) +- kfree(platform_info); ++ + return status; + } + +@@ -2272,23 +2386,8 @@ static int starfive_of_pl022_probe(struc + .mask = 0x000fffff, + .data = &vendor_arm + }; +- struct amba_device *pcdev; + struct device *dev = &pdev->dev; + +- pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); +- if (!pcdev) +- return -ENOMEM; +- +- pcdev->dev = pdev->dev; +- pcdev->periphid = id.id; +- pcdev->res = *(pdev->resource); +- +- pcdev->irq[0] = platform_get_irq(pdev, 0); +- if (pcdev->irq[0] < 0) { +- dev_err(dev, "failed to get irq\n"); +- ret = -EINVAL; +- } +- + ret = of_clk_set_defaults(dev->of_node, false); + if (ret < 0) + goto err_probe; +@@ -2297,16 +2396,11 @@ static int starfive_of_pl022_probe(struc + if (ret) + goto err_probe; + +- ret = pl022_probe(pcdev, &id); +- +- struct pl022 *pl022 = amba_get_drvdata(pcdev); +- +- pl022->host->dev.parent = &pdev->dev; +- platform_set_drvdata(pdev, pl022); ++ ret = pl022_platform_probe(pdev, &id); + +- pm_runtime_enable(&pdev->dev); +- pm_runtime_set_autosuspend_delay(&pdev->dev, 100); +- pm_runtime_use_autosuspend(&pdev->dev); ++ pm_runtime_enable(dev); ++ pm_runtime_set_autosuspend_delay(dev, 100); ++ pm_runtime_use_autosuspend(dev); + + if (ret) { + pm_runtime_disable(dev); +@@ -2321,31 +2415,25 @@ err_probe: + + static void starfive_of_pl022_remove(struct platform_device *pdev) + { +- u32 size; +- int irq; + struct pl022 *pl022 = dev_get_drvdata(&pdev->dev); + + if (!pl022) + return; + ++ pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + + load_ssp_default_config(pl022); + if (pl022->host_info->enable_dma) + pl022_dma_remove(pl022); + +- irq = platform_get_irq(pdev, 0); +- free_irq(irq, pl022); +- reset_control_assert(pl022->rst); +- reset_control_put(pl022->rst); + clk_disable_unprepare(pl022->clk); +- clk_put(pl022->clk); +- iounmap(pl022->virtbase); +- kfree(pl022->host_info); + +- size = resource_size(pdev->resource); +- release_mem_region(pdev->resource->start, size); ++ pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ dev_pm_domain_detach(&pdev->dev, true); + } + + static const struct of_device_id starfive_of_pl022_match[] = { diff --git a/target/linux/starfive/patches-6.12/0023-spi-pl022-starfive-Enable-spi-to-be-compiled-into-mo.patch b/target/linux/starfive/patches-6.12/0023-spi-pl022-starfive-Enable-spi-to-be-compiled-into-mo.patch new file mode 100644 index 0000000000..661a2ea9aa --- /dev/null +++ b/target/linux/starfive/patches-6.12/0023-spi-pl022-starfive-Enable-spi-to-be-compiled-into-mo.patch @@ -0,0 +1,38 @@ +From 4ed44e07a80ef61932b1b5012fc7f8a5a7767e41 Mon Sep 17 00:00:00 2001 +From: "ziv.xu" +Date: Wed, 18 Jan 2023 15:50:47 +0800 +Subject: [PATCH 23/55] spi-pl022-starfive:Enable spi to be compiled into + modules + +Enable spi to be compiled into modules + +Signed-off-by: ziv.xu +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -2365,7 +2365,11 @@ static int __init pl022_init(void) + { + return amba_driver_register(&pl022_driver); + } ++#if !IS_MODULE(CONFIG_SPI_PL022) + subsys_initcall(pl022_init); ++#else ++module_init(pl022_init); ++#endif + + static void __exit pl022_exit(void) + { +@@ -2452,7 +2456,9 @@ static struct platform_driver starfive_o + .remove = starfive_of_pl022_remove, + }; + ++#if !IS_MODULE(CONFIG_SPI_PL022) + module_platform_driver(starfive_of_pl022_driver); ++#endif + /* platform register end */ + + MODULE_AUTHOR("xingyu.wu "); diff --git a/target/linux/starfive/patches-6.12/0024-spi-pl022-Prompt-warning-when-frequency-does-not-sup.patch b/target/linux/starfive/patches-6.12/0024-spi-pl022-Prompt-warning-when-frequency-does-not-sup.patch new file mode 100644 index 0000000000..b455e920e9 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0024-spi-pl022-Prompt-warning-when-frequency-does-not-sup.patch @@ -0,0 +1,26 @@ +From 1944de0e9d9c23f071ec1a75177ea7adbb87ba26 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Thu, 6 Jun 2024 11:01:58 +0800 +Subject: [PATCH 24/55] spi: pl022: Prompt warning when frequency does not + support + +Prompt warning when the frequency does not support. + +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -1556,6 +1556,10 @@ static int calculate_effective_freq(stru + WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate \n", + freq); + ++ if (best_freq != freq) ++ dev_warn(&pl022->adev->dev, ++ "Requested frequency: %d Hz is unsupported,select by default %d Hz\n", ++ freq, best_freq); + clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF); + clk_freq->scr = (u8) (best_scr & 0xFF); + dev_dbg(&pl022->adev->dev, diff --git a/target/linux/starfive/patches-6.12/0025-spi-pl022-Fix-spi-overlay-falut.patch b/target/linux/starfive/patches-6.12/0025-spi-pl022-Fix-spi-overlay-falut.patch new file mode 100644 index 0000000000..4d0f276230 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0025-spi-pl022-Fix-spi-overlay-falut.patch @@ -0,0 +1,33 @@ +From 1b818a33e3cd20250b72306946789d09d2c7b2c8 Mon Sep 17 00:00:00 2001 +From: Hal Feng +Date: Sun, 26 Jan 2025 16:56:05 +0800 +Subject: [PATCH 25/55] spi: pl022: Fix spi overlay falut + +set_cs() should not be set for spi controller when using overlay. +clk_disable_unprepare() is not needed after using +devm_clk_get_enabled() to get and enable clocks. + +Signed-off-by: Hal Feng +--- + drivers/spi/spi-pl022.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -1908,7 +1908,6 @@ static int pl022_platform_probe(struct p + /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/ + host->auto_runtime_pm = true; + host->transfer_one = pl022_transfer_one; +- host->set_cs = pl022_cs_control; + host->handle_err = pl022_handle_err; + host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; + host->rt = platform_info->rt; +@@ -2435,8 +2434,6 @@ static void starfive_of_pl022_remove(str + if (pl022->host_info->enable_dma) + pl022_dma_remove(pl022); + +- clk_disable_unprepare(pl022->clk); +- + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); diff --git a/target/linux/starfive/patches-6.12/0026-RISC-V-Added-generic-pmu-events-mapfile.patch b/target/linux/starfive/patches-6.12/0026-RISC-V-Added-generic-pmu-events-mapfile.patch new file mode 100644 index 0000000000..ec6fab5bc2 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0026-RISC-V-Added-generic-pmu-events-mapfile.patch @@ -0,0 +1,42 @@ +From 7e21305a33876bb56294389d5ecd6f497800e2fb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?= + +Date: Tue, 16 Nov 2021 15:48:11 +0000 +Subject: [PATCH 26/55] RISC-V: Added generic pmu-events mapfile +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The pmu-events now supports custom events for RISC-V, plus the cycle, +time and instret events were defined. + +Signed-off-by: João Mário Domingos +--- + .../pmu-events/arch/riscv/riscv-generic.json | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + create mode 100644 tools/perf/pmu-events/arch/riscv/riscv-generic.json + +--- /dev/null ++++ b/tools/perf/pmu-events/arch/riscv/riscv-generic.json +@@ -0,0 +1,20 @@ ++[ ++ { ++ "PublicDescription": "CPU Cycles", ++ "EventCode": "0x00", ++ "EventName": "riscv_cycles", ++ "BriefDescription": "CPU cycles RISC-V generic counter" ++ }, ++ { ++ "PublicDescription": "CPU Time", ++ "EventCode": "0x01", ++ "EventName": "riscv_time", ++ "BriefDescription": "CPU time RISC-V generic counter" ++ }, ++ { ++ "PublicDescription": "CPU Instructions", ++ "EventCode": "0x02", ++ "EventName": "riscv_instret", ++ "BriefDescription": "CPU retired instructions RISC-V generic counter" ++ } ++] +\ No newline at end of file diff --git a/target/linux/starfive/patches-6.12/0027-RISC-V-Create-unique-identification-for-SoC-PMU.patch b/target/linux/starfive/patches-6.12/0027-RISC-V-Create-unique-identification-for-SoC-PMU.patch new file mode 100644 index 0000000000..b18e10f2ac --- /dev/null +++ b/target/linux/starfive/patches-6.12/0027-RISC-V-Create-unique-identification-for-SoC-PMU.patch @@ -0,0 +1,93 @@ +From f0b0e5392bd7bce16c86d4ed3fc66394db16eb7d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?= + +Date: Tue, 16 Nov 2021 15:48:09 +0000 +Subject: [PATCH 27/55] RISC-V: Create unique identification for SoC PMU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The SBI PMU platform driver did not provide any identification for +perf events matching. This patch introduces a new sysfs file inside the +platform device (soc:pmu/id) for pmu identification. + +The identification is a 64-bit value generated as: +[63-32]: mvendorid; +[31]: marchid[MSB]; +[30-16]: marchid[15-0]; +[15-0]: mimpid[15MSBs]; + +The CSRs are detailed in the RISC-V privileged spec [1]. +The marchid is split in MSB + 15LSBs, due to the MSB being used for +open-source architecture identification. + +[1] https://github.com/riscv/riscv-isa-manual + +Signed-off-by: João Mário Domingos +--- + drivers/perf/riscv_pmu_sbi.c | 47 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +--- a/drivers/perf/riscv_pmu_sbi.c ++++ b/drivers/perf/riscv_pmu_sbi.c +@@ -1326,6 +1326,46 @@ static struct ctl_table sbi_pmu_sysctl_t + }, + }; + ++static uint64_t pmu_sbi_get_pmu_id(void) ++{ ++ union sbi_pmu_id { ++ uint64_t value; ++ struct { ++ uint16_t imp:16; ++ uint16_t arch:16; ++ uint32_t vendor:32; ++ }; ++ } pmuid; ++ ++ pmuid.value = 0; ++ pmuid.vendor = (uint32_t) sbi_get_mvendorid(); ++ pmuid.arch = (sbi_get_marchid() >> (63 - 15) & (1 << 15)) | (sbi_get_marchid() & 0x7FFF); ++ pmuid.imp = (sbi_get_mimpid() >> 16); ++ ++ return pmuid.value; ++} ++ ++static ssize_t pmu_sbi_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int len; ++ ++ len = sprintf(buf, "0x%llx\n", pmu_sbi_get_pmu_id()); ++ if (len <= 0) ++ dev_err(dev, "mydrv: Invalid sprintf len: %dn", len); ++ ++ return len; ++} ++ ++static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, pmu_sbi_id_show, 0); ++ ++static struct attribute *pmu_sbi_attrs[] = { ++ &dev_attr_id.attr, ++ NULL ++}; ++ ++ATTRIBUTE_GROUPS(pmu_sbi); ++ + static int pmu_sbi_device_probe(struct platform_device *pdev) + { + struct riscv_pmu *pmu = NULL; +@@ -1375,6 +1415,13 @@ static int pmu_sbi_device_probe(struct p + pmu->event_unmapped = pmu_sbi_event_unmapped; + pmu->csr_index = pmu_sbi_csr_index; + ++ ret = sysfs_create_group(&pdev->dev.kobj, &pmu_sbi_group); ++ if (ret) { ++ dev_err(&pdev->dev, "sysfs creation failed\n"); ++ return ret; ++ } ++ pdev->dev.groups = pmu_sbi_groups; ++ + ret = riscv_pm_pmu_register(pmu); + if (ret) + goto out_unregister; diff --git a/target/linux/starfive/patches-6.12/0028-RISC-V-Support-CPUID-for-risc-v-in-perf.patch b/target/linux/starfive/patches-6.12/0028-RISC-V-Support-CPUID-for-risc-v-in-perf.patch new file mode 100644 index 0000000000..6b5132636a --- /dev/null +++ b/target/linux/starfive/patches-6.12/0028-RISC-V-Support-CPUID-for-risc-v-in-perf.patch @@ -0,0 +1,55 @@ +From 81ab7f42a1153d6d93b3d429ae0c779e97b0d3d6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?= + +Date: Tue, 16 Nov 2021 15:48:10 +0000 +Subject: [PATCH 28/55] RISC-V: Support CPUID for risc-v in perf +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch creates the header.c file for the risc-v architecture and introduces support for +PMU identification through sysfs. +It is now possible to configure pmu-events in risc-v. + +Depends on patch [1], that introduces the id sysfs file. + +Signed-off-by: João Mário Domingos +Signed-off-by: minda.chen +--- + drivers/perf/riscv_pmu.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/perf/riscv_pmu.c ++++ b/drivers/perf/riscv_pmu.c +@@ -18,6 +18,23 @@ + + #include + ++PMU_FORMAT_ATTR(event, "config:0-63"); ++ ++static struct attribute *riscv_arch_formats_attr[] = { ++ &format_attr_event.attr, ++ NULL, ++}; ++ ++static struct attribute_group riscv_pmu_format_group = { ++ .name = "format", ++ .attrs = riscv_arch_formats_attr, ++}; ++ ++static const struct attribute_group *riscv_pmu_attr_groups[] = { ++ &riscv_pmu_format_group, ++ NULL, ++}; ++ + static bool riscv_perf_user_access(struct perf_event *event) + { + return ((event->attr.type == PERF_TYPE_HARDWARE) || +@@ -407,6 +424,7 @@ struct riscv_pmu *riscv_pmu_alloc(void) + cpuc->snapshot_addr = NULL; + } + pmu->pmu = (struct pmu) { ++ .attr_groups = riscv_pmu_attr_groups, + .event_init = riscv_pmu_event_init, + .event_mapped = riscv_pmu_event_mapped, + .event_unmapped = riscv_pmu_event_unmapped, diff --git a/target/linux/starfive/patches-6.12/0029-dmaengine-dw-axi-dmac-Drop-unused-print-message.patch b/target/linux/starfive/patches-6.12/0029-dmaengine-dw-axi-dmac-Drop-unused-print-message.patch new file mode 100644 index 0000000000..0b5d770329 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0029-dmaengine-dw-axi-dmac-Drop-unused-print-message.patch @@ -0,0 +1,24 @@ +From 1664fcade482724f09a4e0cf25018b6ccebaed84 Mon Sep 17 00:00:00 2001 +From: Walker Chen +Date: Mon, 12 Jun 2023 21:21:45 +0800 +Subject: [PATCH 29/55] dmaengine: dw-axi-dmac: Drop unused print message + +Removed printing information which is not related to StarFive +platform. + +Signed-off-by: Walker Chen +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -569,7 +569,7 @@ static void dw_axi_dma_set_hw_channel(st + unsigned long reg_value, val; + + if (!chip->apb_regs) { +- dev_err(chip->dev, "apb_regs not initialized\n"); ++ dev_dbg(chip->dev, "apb_regs not initialized\n"); + return; + } + diff --git a/target/linux/starfive/patches-6.12/0030-riscv-dts-starfive-vf2-add-reserved-memory-for-E24.patch b/target/linux/starfive/patches-6.12/0030-riscv-dts-starfive-vf2-add-reserved-memory-for-E24.patch new file mode 100644 index 0000000000..dcc3dc1920 --- /dev/null +++ b/target/linux/starfive/patches-6.12/0030-riscv-dts-starfive-vf2-add-reserved-memory-for-E24.patch @@ -0,0 +1,32 @@ +From 8339ccc47af05298612b7f01b8609f9081e9b081 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Sat, 31 May 2025 13:59:30 +0000 +Subject: [PATCH 30/55] riscv: dts: starfive: vf2: add reserved-memory for E24 + +E24 is an rv32 RISC-V core in the JH7110 package. As the driver is now +available for it, add reserved memory as required. + +Signed-off-by: Zoltan HERPAI +--- + .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -11,6 +11,16 @@ + aliases { + ethernet1 = &gmac1; + }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ e24_mem: e24@c0000000 { ++ reg = <0x0 0x6ce00000 0x0 0x1600000>; ++ }; ++ }; + }; + + &gmac1 { diff --git a/target/linux/starfive/patches-6.12/1000-riscv-dts-starfive-Add-JH7100-high-speed-UARTs.patch b/target/linux/starfive/patches-6.12/1000-riscv-dts-starfive-Add-JH7100-high-speed-UARTs.patch new file mode 100644 index 0000000000..57133a268c --- /dev/null +++ b/target/linux/starfive/patches-6.12/1000-riscv-dts-starfive-Add-JH7100-high-speed-UARTs.patch @@ -0,0 +1,49 @@ +From 907f68f5000522e3c78e9a5dca194f52f2ac54d3 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sun, 31 Oct 2021 17:15:58 +0100 +Subject: [PATCH 1000/1021] riscv: dts: starfive: Add JH7100 high speed UARTs + +Add missing device tree nodes for UART0 and UART1 on the StarFive JH7100 +SoC. UART0 is used for Bluetooth on the BeagleV Starlight and StarFive +VisionFive V1 boards. + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/jh7100.dtsi | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -258,6 +258,32 @@ + reg = <0x0 0x11850000 0x0 0x10000>; + }; + ++ uart0: serial@11870000 { ++ compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart"; ++ reg = <0x0 0x11870000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_UART0_CORE>, ++ <&clkgen JH7100_CLK_UART0_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&rstgen JH7100_RSTN_UART0_APB>; ++ interrupts = <92>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@11880000 { ++ compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart"; ++ reg = <0x0 0x11880000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_UART1_CORE>, ++ <&clkgen JH7100_CLK_UART1_APB>; ++ clock-names = "baudclk", "apb_pclk"; ++ resets = <&rstgen JH7100_RSTN_UART1_APB>; ++ interrupts = <93>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ + i2c0: i2c@118b0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x118b0000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.12/1001-riscv-dts-starfive-Enable-Bluetooth-on-JH7100-boards.patch b/target/linux/starfive/patches-6.12/1001-riscv-dts-starfive-Enable-Bluetooth-on-JH7100-boards.patch new file mode 100644 index 0000000000..b2c3e5189f --- /dev/null +++ b/target/linux/starfive/patches-6.12/1001-riscv-dts-starfive-Enable-Bluetooth-on-JH7100-boards.patch @@ -0,0 +1,79 @@ +From 920915a0d5495b1185391cceb92f9d5b26a875e4 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Mon, 13 Sep 2021 01:18:01 +0200 +Subject: [PATCH 1001/1021] riscv: dts: starfive: Enable Bluetooth on JH7100 + boards + +Add pinctrl and UART nodes for the Broadcom Wifi/Bluetooth module on the +BeagleV Starlight and StarFive VisionFive V1 boards. + +Signed-off-by: Emil Renner Berthing +--- + .../boot/dts/starfive/jh7100-common.dtsi | 49 +++++++++++++++++++ + 1 file changed, 49 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi +@@ -289,6 +289,41 @@ + }; + }; + ++ uart0_pins: uart0-0 { ++ rx-pins { ++ pinmux = ; ++ bias-pull-up; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ tx-pins { ++ pinmux = ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ cts-pins { ++ pinmux = ; ++ bias-pull-down; ++ drive-strength = <14>; ++ input-enable; ++ input-schmitt-enable; ++ }; ++ rts-pins { ++ pinmux = ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ }; ++ }; ++ + uart3_pins: uart3-0 { + rx-pins { + pinmux = ; ++ uart-has-rtscts; ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "brcm,bcm4330-bt"; ++ max-speed = <4000000>; ++ device-wakeup-gpios = <&gpio 38 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio 35 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ + &uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; diff --git a/target/linux/starfive/patches-6.12/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch b/target/linux/starfive/patches-6.12/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch new file mode 100644 index 0000000000..db83fe9ba7 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1002-serial-8250_dw-Add-starfive-jh7100-hsuart-compatible.patch @@ -0,0 +1,25 @@ +From 48358693ffb4bc661996d14adcd3942a318cdb79 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 14 Oct 2021 20:56:54 +0200 +Subject: [PATCH 1002/1021] serial: 8250_dw: Add starfive,jh7100-hsuart + compatible + +This adds a compatible for the high speed UARTs on the StarFive JH7100 +RISC-V SoC. Just like the regular uarts we also need to keep the input +clocks at their default rate and rely only on the divisor in the UART. + +Signed-off-by: Emil Renner Berthing +--- + drivers/tty/serial/8250/8250_dw.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/tty/serial/8250/8250_dw.c ++++ b/drivers/tty/serial/8250/8250_dw.c +@@ -777,6 +777,7 @@ static const struct of_device_id dw8250_ + { .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data }, + { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data }, + { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data }, ++ { .compatible = "starfive,jh7100-hsuart", .data = &dw8250_skip_set_rate_data }, + { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data }, + { /* Sentinel */ } + }; diff --git a/target/linux/starfive/patches-6.12/1003-drivers-tty-serial-8250-update-driver-for-JH7100.patch b/target/linux/starfive/patches-6.12/1003-drivers-tty-serial-8250-update-driver-for-JH7100.patch new file mode 100644 index 0000000000..6d41247359 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1003-drivers-tty-serial-8250-update-driver-for-JH7100.patch @@ -0,0 +1,28 @@ +From bb3c832bd58bd2bca5f7f99bd19a0fe6ad3cf1a4 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Fri, 8 Jan 2021 03:11:04 +0800 +Subject: [PATCH 1003/1021] drivers/tty/serial/8250: update driver for JH7100 + +--- + drivers/tty/serial/8250/8250_port.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -68,8 +68,16 @@ static const struct serial8250_config ua + }, + [PORT_16550] = { + .name = "16550", ++#ifdef CONFIG_SOC_STARFIVE ++ .fifo_size = 16, ++ .tx_loadsz = 16, ++ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, ++ .rxtrig_bytes = {1, 4, 8, 14}, ++ .flags = UART_CAP_FIFO, ++#else + .fifo_size = 1, + .tx_loadsz = 1, ++#endif + }, + [PORT_16550A] = { + .name = "16550A", diff --git a/target/linux/starfive/patches-6.12/1004-power-reset-tps65086-Allow-building-as-a-module.patch b/target/linux/starfive/patches-6.12/1004-power-reset-tps65086-Allow-building-as-a-module.patch new file mode 100644 index 0000000000..b8dd18fff8 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1004-power-reset-tps65086-Allow-building-as-a-module.patch @@ -0,0 +1,29 @@ +From 995a9b41dd4e29d02ec549170f917b301d8a6d36 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sun, 3 Jul 2022 21:01:11 +0200 +Subject: [PATCH 1004/1021] power: reset: tps65086: Allow building as a module + +Signed-off-by: Emil Renner Berthing +--- + drivers/power/reset/Kconfig | 2 +- + drivers/power/reset/tps65086-restart.c | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -217,7 +217,7 @@ config POWER_RESET_ST + Reset support for STMicroelectronics boards. + + config POWER_RESET_TPS65086 +- bool "TPS65086 restart driver" ++ tristate "TPS65086 restart driver" + depends on MFD_TPS65086 + help + This driver adds support for resetting the TPS65086 PMIC on restart. +--- a/drivers/power/reset/tps65086-restart.c ++++ b/drivers/power/reset/tps65086-restart.c +@@ -57,3 +57,4 @@ module_platform_driver(tps65086_restart_ + + MODULE_AUTHOR("Emil Renner Berthing "); + MODULE_DESCRIPTION("TPS65086 restart driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/starfive/patches-6.12/1005-riscv-dts-starfive-Add-StarFive-JH7100-audio-clock-n.patch b/target/linux/starfive/patches-6.12/1005-riscv-dts-starfive-Add-StarFive-JH7100-audio-clock-n.patch new file mode 100644 index 0000000000..2f7ed82f53 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1005-riscv-dts-starfive-Add-StarFive-JH7100-audio-clock-n.patch @@ -0,0 +1,33 @@ +From bedd1e49a138fc532712ae3e889af17a0dbc9417 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 17:13:22 +0100 +Subject: [PATCH 1005/1021] riscv: dts: starfive: Add StarFive JH7100 audio + clock node + +Add device tree node for the audio clocks on the StarFive JH7100 RISC-V +SoC. + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/jh7100.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -239,6 +239,16 @@ + }; + }; + ++ audclk: clock-controller@10480000 { ++ compatible = "starfive,jh7100-audclk"; ++ reg = <0x0 0x10480000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_AUDIO_SRC>, ++ <&clkgen JH7100_CLK_AUDIO_12288>, ++ <&clkgen JH7100_CLK_DOM7AHB_BUS>; ++ clock-names = "audio_src", "audio_12288", "dom7ahb_bus"; ++ #clock-cells = <1>; ++ }; ++ + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x0 0x11800000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.12/1006-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch b/target/linux/starfive/patches-6.12/1006-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch new file mode 100644 index 0000000000..7739a7d914 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1006-dt-bindings-reset-Add-StarFive-JH7100-audio-reset-de.patch @@ -0,0 +1,48 @@ +From 052732a9fb44ab63e522a9b2949d64e2d2f2d4fc Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 19:29:25 +0100 +Subject: [PATCH 1006/1021] dt-bindings: reset: Add StarFive JH7100 audio reset + definitions + +Add all resets for the StarFive JH7100 audio reset controller. + +Signed-off-by: Emil Renner Berthing +--- + .../dt-bindings/reset/starfive-jh7100-audio.h | 31 +++++++++++++++++++ + 1 file changed, 31 insertions(+) + create mode 100644 include/dt-bindings/reset/starfive-jh7100-audio.h + +--- /dev/null ++++ b/include/dt-bindings/reset/starfive-jh7100-audio.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++#ifndef __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__ ++#define __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__ ++ ++#define JH7100_AUDRSTN_APB_BUS 0 ++#define JH7100_AUDRSTN_I2SADC_APB 1 ++#define JH7100_AUDRSTN_I2SADC_SRST 2 ++#define JH7100_AUDRSTN_PDM_APB 3 ++#define JH7100_AUDRSTN_I2SVAD_APB 4 ++#define JH7100_AUDRSTN_I2SVAD_SRST 5 ++#define JH7100_AUDRSTN_SPDIF_APB 6 ++#define JH7100_AUDRSTN_PWMDAC_APB 7 ++#define JH7100_AUDRSTN_I2SDAC_APB 8 ++#define JH7100_AUDRSTN_I2SDAC_SRST 9 ++#define JH7100_AUDRSTN_I2S1_APB 10 ++#define JH7100_AUDRSTN_I2S1_SRST 11 ++#define JH7100_AUDRSTN_I2SDAC16K_APB 12 ++#define JH7100_AUDRSTN_I2SDAC16K_SRST 13 ++#define JH7100_AUDRSTN_DMA1P_AHB 14 ++#define JH7100_AUDRSTN_USB_APB 15 ++#define JH7100_AUDRST_USB_AXI 16 ++#define JH7100_AUDRST_USB_PWRUP_RST_N 17 ++#define JH7100_AUDRST_USB_PONRST 18 ++ ++#define JH7100_AUDRSTN_END 19 ++ ++#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__ */ diff --git a/target/linux/starfive/patches-6.12/1007-reset-starfive-Add-JH7100-audio-reset-driver.patch b/target/linux/starfive/patches-6.12/1007-reset-starfive-Add-JH7100-audio-reset-driver.patch new file mode 100644 index 0000000000..5954e5807e --- /dev/null +++ b/target/linux/starfive/patches-6.12/1007-reset-starfive-Add-JH7100-audio-reset-driver.patch @@ -0,0 +1,144 @@ +From 2828a23364ab4a55af817b7ab370e6fc225f025d Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 19:30:49 +0100 +Subject: [PATCH 1007/1021] reset: starfive: Add JH7100 audio reset driver + +The audio resets are almost identical to the system resets, there are +just fewer of them. So factor out and export a generic probe function, +so most of the reset controller implementation can be shared. + +Signed-off-by: Emil Renner Berthing +--- + MAINTAINERS | 2 +- + drivers/reset/starfive/Kconfig | 7 ++ + drivers/reset/starfive/Makefile | 2 + + .../starfive/reset-starfive-jh7100-audio.c | 66 +++++++++++++++++++ + .../reset/starfive/reset-starfive-jh7100.h | 16 +++++ + 5 files changed, 92 insertions(+), 1 deletion(-) + create mode 100644 drivers/reset/starfive/reset-starfive-jh7100-audio.c + create mode 100644 drivers/reset/starfive/reset-starfive-jh7100.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -22078,7 +22078,7 @@ STARFIVE JH71X0 RESET CONTROLLER DRIVERS + M: Emil Renner Berthing + 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 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.12/1008-riscv-dts-starfive-Add-StarFive-JH7100-audio-reset-n.patch b/target/linux/starfive/patches-6.12/1008-riscv-dts-starfive-Add-StarFive-JH7100-audio-reset-n.patch new file mode 100644 index 0000000000..0c93f88ca3 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1008-riscv-dts-starfive-Add-StarFive-JH7100-audio-reset-n.patch @@ -0,0 +1,29 @@ +From a806acd4f507764123838c9620d4e581585f2099 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 20 Nov 2021 21:33:08 +0100 +Subject: [PATCH 1008/1021] riscv: dts: starfive: Add StarFive JH7100 audio + reset node + +Add device tree node for the audio resets on the StarFive JH7100 RISC-V +SoC. + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/jh7100.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -249,6 +249,12 @@ + #clock-cells = <1>; + }; + ++ audrst: reset-controller@10490000 { ++ compatible = "starfive,jh7100-audrst"; ++ reg = <0x0 0x10490000 0x0 0x10000>; ++ #reset-cells = <1>; ++ }; ++ + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x0 0x11800000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.12/1009-clk-starfive-jh7100-Keep-more-clocks-alive.patch b/target/linux/starfive/patches-6.12/1009-clk-starfive-jh7100-Keep-more-clocks-alive.patch new file mode 100644 index 0000000000..4f527ec460 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1009-clk-starfive-jh7100-Keep-more-clocks-alive.patch @@ -0,0 +1,61 @@ +From 174c73330839bad688b9fb2e9b6b9a2e5d74021f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 14 Oct 2021 20:35:43 +0200 +Subject: [PATCH 1009/1021] clk: starfive: jh7100: Keep more clocks alive + +Signed-off-by: Emil Renner Berthing +--- + drivers/clk/starfive/clk-starfive-jh7100.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +--- a/drivers/clk/starfive/clk-starfive-jh7100.c ++++ b/drivers/clk/starfive/clk-starfive-jh7100.c +@@ -94,9 +94,9 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT), +- JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS), +- JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS), +- JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DLA_BUS), ++ JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DLA_BUS), ++ JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", CLK_IGNORE_UNUSED, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT), + JH71X0_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC), +@@ -163,8 +163,9 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS), + JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS), + JH71X0__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT), +- JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), +- JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, ++ JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", CLK_IGNORE_UNUSED, 8, ++ JH7100_CLK_USBPHY_ROOTDIV), ++ JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", CLK_IGNORE_UNUSED, 32, + JH7100_CLK_USBPHY_ROOTDIV), + JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2, + JH7100_CLK_OSC_SYS, +@@ -183,11 +184,11 @@ static const struct jh71x0_clk_data jh71 + JH71X0__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS), + JH71X0_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS), +- JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT), ++ JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", CLK_IGNORE_UNUSED, 4, JH7100_CLK_VOUT_ROOT), + JH71X0__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT), + JH71X0__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC), +- JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS), +- JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS), ++ JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DISP_BUS), ++ JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DISP_BUS), + JH71X0_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC), + JH71X0__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT), +@@ -223,7 +224,7 @@ static const struct jh71x0_clk_data jh71 + JH71X0_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB), +- JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS), ++ JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", CLK_IGNORE_UNUSED, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC), diff --git a/target/linux/starfive/patches-6.12/1010-pinctrl-starfive-Reset-pinmux-settings.patch b/target/linux/starfive/patches-6.12/1010-pinctrl-starfive-Reset-pinmux-settings.patch new file mode 100644 index 0000000000..bf1c2d80f3 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1010-pinctrl-starfive-Reset-pinmux-settings.patch @@ -0,0 +1,127 @@ +From f3e66db46e8c849e154042c35bfa22fedc03c3df Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 17 Jul 2021 21:50:38 +0200 +Subject: [PATCH 1010/1021] pinctrl: starfive: Reset pinmux settings + +Current u-boot doesn't seem to take into account that some GPIOs are +configured as inputs/outputs of certain peripherals on power-up. This +means it ends up configuring some GPIOs as inputs to more than one +peripheral which the documentation explicitly says is illegal. Similarly +it also ends up configuring more than one GPIO as output of the same +peripheral. While not explicitly mentioned by the documentation this +also seems like a bad idea. + +The easiest way to remedy this mess is to just disconnect all GPIOs from +peripherals and have our pinmux configuration set everything up +properly. This, however, means that we'd disconnect the serial console +from its pins for a while, so add a device tree property to keep +certain GPIOs from being reset. + +Signed-off-by: Emil Renner Berthing +--- + .../pinctrl/starfive,jh7100-pinctrl.yaml | 4 ++ + .../starfive/pinctrl-starfive-jh7100.c | 66 +++++++++++++++++++ + 2 files changed, 70 insertions(+) + +--- a/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml ++++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml +@@ -88,6 +88,10 @@ properties: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3, 4, 5, 6] + ++ starfive,keep-gpiomux: ++ description: Keep pinmux for these GPIOs from being reset at boot. ++ $ref: /schemas/types.yaml#/definitions/uint32-array ++ + required: + - compatible + - reg +--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c ++++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c +@@ -203,6 +203,10 @@ static u16 starfive_drive_strength_from_ + return (clamp(i, 14U, 63U) - 14) / 7; + } + ++static bool keepmux; ++module_param(keepmux, bool, 0644); ++MODULE_PARM_DESC(keepmux, "Keep pinmux settings from previous boot stage"); ++ + struct starfive_pinctrl { + struct gpio_chip gc; + struct pinctrl_gpio_range gpios; +@@ -1210,6 +1214,65 @@ static void starfive_disable_clock(void + clk_disable_unprepare(data); + } + ++#define GPI_END (GPI_USB_OVER_CURRENT + 1) ++static void starfive_pinmux_reset(struct starfive_pinctrl *sfp) ++{ ++ static const DECLARE_BITMAP(defaults, GPI_END) = { ++ BIT_MASK(GPI_I2C0_PAD_SCK_IN) | ++ BIT_MASK(GPI_I2C0_PAD_SDA_IN) | ++ BIT_MASK(GPI_I2C1_PAD_SCK_IN) | ++ BIT_MASK(GPI_I2C1_PAD_SDA_IN) | ++ BIT_MASK(GPI_I2C2_PAD_SCK_IN) | ++ BIT_MASK(GPI_I2C2_PAD_SDA_IN) | ++ BIT_MASK(GPI_I2C3_PAD_SCK_IN) | ++ BIT_MASK(GPI_I2C3_PAD_SDA_IN) | ++ BIT_MASK(GPI_SDIO0_PAD_CARD_DETECT_N) | ++ ++ BIT_MASK(GPI_SDIO1_PAD_CARD_DETECT_N) | ++ BIT_MASK(GPI_SPI0_PAD_SS_IN_N) | ++ BIT_MASK(GPI_SPI1_PAD_SS_IN_N) | ++ BIT_MASK(GPI_SPI2_PAD_SS_IN_N) | ++ BIT_MASK(GPI_SPI2AHB_PAD_SS_N) | ++ BIT_MASK(GPI_SPI3_PAD_SS_IN_N), ++ ++ BIT_MASK(GPI_UART0_PAD_SIN) | ++ BIT_MASK(GPI_UART1_PAD_SIN) | ++ BIT_MASK(GPI_UART2_PAD_SIN) | ++ BIT_MASK(GPI_UART3_PAD_SIN) | ++ BIT_MASK(GPI_USB_OVER_CURRENT) ++ }; ++ DECLARE_BITMAP(keep, NR_GPIOS) = {}; ++ struct device_node *np = sfp->gc.parent->of_node; ++ int len = of_property_count_u32_elems(np, "starfive,keep-gpiomux"); ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ u32 gpio; ++ ++ of_property_read_u32_index(np, "starfive,keep-gpiomux", i, &gpio); ++ if (gpio < NR_GPIOS) ++ set_bit(gpio, keep); ++ } ++ ++ for (i = 0; i < NR_GPIOS; i++) { ++ if (test_bit(i, keep)) ++ continue; ++ ++ writel_relaxed(GPO_DISABLE, sfp->base + GPON_DOEN_CFG + 8 * i); ++ writel_relaxed(GPO_LOW, sfp->base + GPON_DOUT_CFG + 8 * i); ++ } ++ ++ for (i = 0; i < GPI_END; i++) { ++ void __iomem *reg = sfp->base + GPI_CFG_OFFSET + 4 * i; ++ u32 din = readl_relaxed(reg); ++ ++ if (din >= 2 && din < (NR_GPIOS + 2) && test_bit(din - 2, keep)) ++ continue; ++ ++ writel_relaxed(test_bit(i, defaults), reg); ++ } ++} ++ + static int starfive_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -1271,6 +1334,9 @@ static int starfive_probe(struct platfor + writel(value, sfp->padctl + IO_PADSHARE_SEL); + } + ++ if (!keepmux) ++ starfive_pinmux_reset(sfp); ++ + value = readl(sfp->padctl + IO_PADSHARE_SEL); + switch (value) { + case 0: diff --git a/target/linux/starfive/patches-6.12/1011-net-stmmac-use-GFP_DMA32.patch b/target/linux/starfive/patches-6.12/1011-net-stmmac-use-GFP_DMA32.patch new file mode 100644 index 0000000000..7ddad83585 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1011-net-stmmac-use-GFP_DMA32.patch @@ -0,0 +1,30 @@ +From 690e2d40fe645e86dcd0ac265038426676473e19 Mon Sep 17 00:00:00 2001 +From: Matteo Croce +Date: Fri, 21 May 2021 03:26:38 +0200 +Subject: [PATCH 1011/1021] 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 +@@ -1460,7 +1460,7 @@ static int stmmac_init_rx_buffers(struct + { + struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; +- gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN); ++ gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32); + + if (priv->dma_cap.host_dma_width <= 32) + gfp |= GFP_DMA32; +@@ -4756,7 +4756,7 @@ static inline void stmmac_rx_refill(stru + struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int dirty = stmmac_rx_dirty(priv, queue); + unsigned int entry = rx_q->dirty_rx; +- gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN); ++ gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32); + + if (priv->dma_cap.host_dma_width <= 32) + gfp |= GFP_DMA32; diff --git a/target/linux/starfive/patches-6.12/1012-dt-bindings-dma-dw-axi-dmac-Increase-DMA-channel-lim.patch b/target/linux/starfive/patches-6.12/1012-dt-bindings-dma-dw-axi-dmac-Increase-DMA-channel-lim.patch new file mode 100644 index 0000000000..047fb94251 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1012-dt-bindings-dma-dw-axi-dmac-Increase-DMA-channel-lim.patch @@ -0,0 +1,45 @@ +From e941dae591d8cd24f6758ecded9cc9741082e76d Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Thu, 27 May 2021 20:13:43 +0200 +Subject: [PATCH 1012/1021] dt-bindings: dma: dw-axi-dmac: Increase DMA channel + limit to 16 + +The first DMAC instance in the StarFive JH7100 SoC supports 16 DMA +channels. + +FIXME Given there are more changes to the driver than just increasing + DMAC_MAX_CHANNELS, we probably need a new compatible value, too. + +Signed-off-by: Geert Uytterhoeven +--- + Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml ++++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +@@ -57,7 +57,7 @@ properties: + + dma-channels: + minimum: 1 +- maximum: 8 ++ maximum: 16 + + resets: + minItems: 1 +@@ -81,14 +81,14 @@ properties: + Channel priority specifier associated with the DMA channels. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 +- maxItems: 8 ++ maxItems: 16 + + snps,block-size: + description: | + Channel block size specifier associated with the DMA channels. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 +- maxItems: 8 ++ maxItems: 16 + + snps,axi-max-burst-len: + description: | diff --git a/target/linux/starfive/patches-6.12/1013-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch b/target/linux/starfive/patches-6.12/1013-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch new file mode 100644 index 0000000000..a4a84ee82c --- /dev/null +++ b/target/linux/starfive/patches-6.12/1013-dmaengine-dw-axi-dmac-Handle-xfer-start-while-non-id.patch @@ -0,0 +1,55 @@ +From 38bf6380d873ebf247dde54a1b93dcfbf3ea19f6 Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Wed, 17 Nov 2021 14:50:45 +0800 +Subject: [PATCH 1013/1021] dmaengine: dw-axi-dmac: Handle xfer start while + non-idle + +Signed-off-by: Samin Guo +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 +@@ -428,11 +428,13 @@ static void axi_chan_block_xfer_start(st + u32 irq_mask; + u8 lms = 0; /* Select AXI0 master for LLI fetching */ + ++ chan->is_err = false; + if (unlikely(axi_chan_is_hw_enable(chan))) { + dev_err(chan2dev(chan), "%s is non-idle!\n", + axi_chan_name(chan)); + +- return; ++ axi_chan_disable(chan); ++ chan->is_err = true; + } + + axi_dma_enable(chan->chip); +@@ -1074,6 +1076,14 @@ static noinline void axi_chan_handle_err + axi_chan_name(chan)); + goto out; + } ++ if (chan->is_err) { ++ struct axi_dma_desc *desc = vd_to_axi_desc(vd); ++ ++ axi_chan_block_xfer_start(chan, desc); ++ chan->is_err = false; ++ goto out; ++ } ++ + /* Remove the completed descriptor from issued list */ + list_del(&vd->node); + +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +@@ -50,6 +50,7 @@ struct axi_dma_chan { + struct dma_slave_config config; + enum dma_transfer_direction direction; + bool cyclic; ++ bool is_err; + /* these other elements are all protected by vc.lock */ + bool is_paused; + }; diff --git a/target/linux/starfive/patches-6.12/1014-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch b/target/linux/starfive/patches-6.12/1014-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch new file mode 100644 index 0000000000..426f3c0916 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1014-dmaengine-dw-axi-dmac-Add-StarFive-JH7100-support.patch @@ -0,0 +1,64 @@ +From 43048e7698e0a2c0870112168ed138de4aa937cc Mon Sep 17 00:00:00 2001 +From: Samin Guo +Date: Wed, 17 Nov 2021 14:50:45 +0800 +Subject: [PATCH 1014/1021] dmaengine: dw-axi-dmac: Add StarFive JH7100 support + +Signed-off-by: Samin Guo +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 +@@ -723,8 +723,13 @@ static int dw_axi_dma_set_hw_desc(struct + + hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1); + ++#ifdef CONFIG_SOC_STARFIVE ++ ctllo |= DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_DST_MSIZE_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_SRC_MSIZE_POS; ++#else + ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | + DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS; ++#endif + hw_desc->lli->ctl_lo = cpu_to_le32(ctllo); + + set_desc_src_master(hw_desc); +@@ -1589,7 +1594,11 @@ static int dw_probe(struct platform_devi + * Therefore, set constraint to 1024 * 4. + */ + dw->dma.dev->dma_parms = &dw->dma_parms; ++#ifdef CONFIG_SOC_STARFIVE ++ dma_set_max_seg_size(&pdev->dev, DMAC_MAX_BLK_SIZE); ++#else + dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE); ++#endif + platform_set_drvdata(pdev, chip); + + pm_runtime_enable(chip->dev); +@@ -1674,6 +1683,9 @@ static const struct of_device_id dw_dma_ + .compatible = "intel,kmb-axi-dma", + .data = (void *)AXI_DMA_FLAG_HAS_APB_REGS, + }, { ++ .compatible = "starfive,jh7100-axi-dma", ++ .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), ++ }, { + .compatible = "starfive,jh7110-axi-dma", + .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), + }, { +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +@@ -288,7 +288,11 @@ enum { + #define CH_CTL_L_SRC_MAST BIT(0) + + /* CH_CFG_H */ ++#ifdef CONFIG_SOC_STARFIVE ++#define CH_CFG_H_PRIORITY_POS 15 ++#else + #define CH_CFG_H_PRIORITY_POS 17 ++#endif + #define CH_CFG_H_DST_PER_POS 12 + #define CH_CFG_H_SRC_PER_POS 7 + #define CH_CFG_H_HS_SEL_DST_POS 4 diff --git a/target/linux/starfive/patches-6.12/1015-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch b/target/linux/starfive/patches-6.12/1015-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch new file mode 100644 index 0000000000..549f7f8646 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1015-hwrng-Add-StarFive-JH7100-Random-Number-Generator-dr.patch @@ -0,0 +1,477 @@ +From 4a5a14f6cce89d12efa90dd8e2a82e36df2ee179 Mon Sep 17 00:00:00 2001 +From: Huan Feng +Date: Fri, 8 Jan 2021 03:35:42 +0800 +Subject: [PATCH 1015/1021] hwrng: Add StarFive JH7100 Random Number Generator + driver + +Signed-off-by: Emil Renner Berthing +--- + drivers/char/hw_random/Kconfig | 13 ++ + drivers/char/hw_random/Makefile | 1 + + drivers/char/hw_random/starfive-vic-rng.c | 256 ++++++++++++++++++++++ + drivers/char/hw_random/starfive-vic-rng.h | 167 ++++++++++++++ + 4 files changed, 437 insertions(+) + create mode 100644 drivers/char/hw_random/starfive-vic-rng.c + create mode 100644 drivers/char/hw_random/starfive-vic-rng.h + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -323,6 +323,19 @@ config HW_RANDOM_POWERNV + + If unsure, say Y. + ++config HW_RANDOM_STARFIVE_VIC ++ tristate "Starfive VIC Random Number Generator support" ++ depends on HW_RANDOM && (SOC_STARFIVE || COMPILE_TEST) ++ default SOC_STARFIVE ++ help ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Starfive VIC SoC. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called starfive-vic-rng. ++ ++ If unsure, say Y. ++ + config HW_RANDOM_HISI + tristate "Hisilicon Random Number Generator support" + depends on ARCH_HISI || COMPILE_TEST +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon + obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o + obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o + obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o ++obj-$(CONFIG_HW_RANDOM_STARFIVE_VIC) += starfive-vic-rng.o + obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o + obj-$(CONFIG_HW_RANDOM_HISTB) += histb-rng.o + obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o +--- /dev/null ++++ b/drivers/char/hw_random/starfive-vic-rng.c +@@ -0,0 +1,256 @@ ++/* ++ ****************************************************************************** ++ * @file starfive-vic-rng.c ++ * @author StarFive Technology ++ * @version V1.0 ++ * @date 08/13/2020 ++ * @brief ++ ****************************************************************************** ++ * @copy ++ * ++ * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS ++ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE ++ * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY ++ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING ++ * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE ++ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. ++ * ++ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. ++ */ ++#include ++#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.12/1016-usb-cdns3-starfive-Simplify-mode-init.patch b/target/linux/starfive/patches-6.12/1016-usb-cdns3-starfive-Simplify-mode-init.patch new file mode 100644 index 0000000000..fabb8fb1d9 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1016-usb-cdns3-starfive-Simplify-mode-init.patch @@ -0,0 +1,119 @@ +From d3bef81bd427caf4cbf7ecef64f0268a6ac8ce52 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 22 Jul 2023 15:59:02 +0200 +Subject: [PATCH 1016/1021] usb: cdns3: starfive: Simplify mode init + +The syscon regmap and offset to the USB mode register is only used at +probe time, so there is no need to store it in the device data. Just get +the regmap pointer in the cdns_mode_init() function where it is needed. +Also this function never uses the platform device, so just pass the +device pointer directly. + +Signed-off-by: Emil Renner Berthing +--- + drivers/usb/cdns3/cdns3-starfive.c | 51 ++++++++++++------------------ + 1 file changed, 21 insertions(+), 30 deletions(-) + +--- a/drivers/usb/cdns3/cdns3-starfive.c ++++ b/drivers/usb/cdns3/cdns3-starfive.c +@@ -34,46 +34,45 @@ + + struct cdns_starfive { + struct device *dev; +- struct regmap *stg_syscon; + struct reset_control *resets; + struct clk_bulk_data *clks; + int num_clks; +- u32 stg_usb_mode; + }; + +-static void cdns_mode_init(struct platform_device *pdev, +- struct cdns_starfive *data) ++static int cdns_mode_init(struct device *dev, struct cdns_starfive *data) + { ++ struct regmap *syscon; ++ unsigned int usb_mode; + enum usb_dr_mode mode; + +- regmap_update_bits(data->stg_syscon, data->stg_usb_mode, ++ syscon = syscon_regmap_lookup_by_phandle_args(dev->of_node, ++ "starfive,stg-syscon", 1, &usb_mode); ++ if (IS_ERR(syscon)) ++ return dev_err_probe(dev, PTR_ERR(syscon), ++ "Failed to parse starfive,stg-syscon\n"); ++ ++ regmap_update_bits(syscon, usb_mode, + USB_MISC_CFG_MASK, + USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE); + + /* dr mode setting */ +- mode = usb_get_dr_mode(&pdev->dev); ++ mode = usb_get_dr_mode(dev); + + switch (mode) { + case USB_DR_MODE_HOST: +- regmap_update_bits(data->stg_syscon, +- data->stg_usb_mode, +- USB_STRAP_MASK, +- USB_STRAP_HOST); +- regmap_update_bits(data->stg_syscon, +- data->stg_usb_mode, +- USB_SUSPENDM_MASK, +- USB_SUSPENDM_HOST); ++ regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_HOST); ++ regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, USB_SUSPENDM_HOST); + break; + + case USB_DR_MODE_PERIPHERAL: +- regmap_update_bits(data->stg_syscon, data->stg_usb_mode, +- USB_STRAP_MASK, USB_STRAP_DEVICE); +- regmap_update_bits(data->stg_syscon, data->stg_usb_mode, +- USB_SUSPENDM_MASK, 0); ++ regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_DEVICE); ++ regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, 0); + break; + default: + break; + } ++ ++ return 0; + } + + static int cdns_clk_rst_init(struct cdns_starfive *data) +@@ -108,7 +107,6 @@ static int cdns_starfive_probe(struct pl + { + struct device *dev = &pdev->dev; + struct cdns_starfive *data; +- unsigned int args; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); +@@ -117,16 +115,6 @@ static int cdns_starfive_probe(struct pl + + data->dev = dev; + +- data->stg_syscon = +- syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, +- "starfive,stg-syscon", 1, &args); +- +- if (IS_ERR(data->stg_syscon)) +- return dev_err_probe(dev, PTR_ERR(data->stg_syscon), +- "Failed to parse starfive,stg-syscon\n"); +- +- data->stg_usb_mode = args; +- + data->num_clks = devm_clk_bulk_get_all(data->dev, &data->clks); + if (data->num_clks < 0) + return dev_err_probe(data->dev, -ENODEV, +@@ -137,7 +125,10 @@ static int cdns_starfive_probe(struct pl + return dev_err_probe(data->dev, PTR_ERR(data->resets), + "Failed to get resets"); + +- cdns_mode_init(pdev, data); ++ ret = cdns_mode_init(dev, data); ++ if (ret) ++ return ret; ++ + ret = cdns_clk_rst_init(data); + if (ret) + return ret; diff --git a/target/linux/starfive/patches-6.12/1017-usb-cdns3-starfive-Don-t-store-device-backpointer.patch b/target/linux/starfive/patches-6.12/1017-usb-cdns3-starfive-Don-t-store-device-backpointer.patch new file mode 100644 index 0000000000..e2868122db --- /dev/null +++ b/target/linux/starfive/patches-6.12/1017-usb-cdns3-starfive-Don-t-store-device-backpointer.patch @@ -0,0 +1,126 @@ +From 38b62b73015e3c843ff05400cd972683a7f3af04 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 22 Jul 2023 16:18:24 +0200 +Subject: [PATCH 1017/1021] usb: cdns3: starfive: Don't store device + backpointer + +Signed-off-by: Emil Renner Berthing +--- + drivers/usb/cdns3/cdns3-starfive.c | 37 ++++++++++++------------------ + 1 file changed, 15 insertions(+), 22 deletions(-) + +--- a/drivers/usb/cdns3/cdns3-starfive.c ++++ b/drivers/usb/cdns3/cdns3-starfive.c +@@ -33,7 +33,6 @@ + #define USB_REFCLK_MODE BIT(23) + + struct cdns_starfive { +- struct device *dev; + struct reset_control *resets; + struct clk_bulk_data *clks; + int num_clks; +@@ -49,7 +48,7 @@ static int cdns_mode_init(struct device + "starfive,stg-syscon", 1, &usb_mode); + if (IS_ERR(syscon)) + return dev_err_probe(dev, PTR_ERR(syscon), +- "Failed to parse starfive,stg-syscon\n"); ++ "failed to parse starfive,stg-syscon\n"); + + regmap_update_bits(syscon, usb_mode, + USB_MISC_CFG_MASK, +@@ -75,18 +74,17 @@ static int cdns_mode_init(struct device + return 0; + } + +-static int cdns_clk_rst_init(struct cdns_starfive *data) ++static int cdns_clk_rst_init(struct device *dev, struct cdns_starfive *data) + { + int ret; + + ret = clk_bulk_prepare_enable(data->num_clks, data->clks); + if (ret) +- return dev_err_probe(data->dev, ret, +- "failed to enable clocks\n"); ++ return dev_err_probe(dev, ret, "failed to enable clocks\n"); + + ret = reset_control_deassert(data->resets); + if (ret) { +- dev_err(data->dev, "failed to reset clocks\n"); ++ dev_err(dev, "failed to reset clocks\n"); + goto err_clk_init; + } + +@@ -97,7 +95,7 @@ err_clk_init: + return ret; + } + +-static void cdns_clk_rst_deinit(struct cdns_starfive *data) ++static void cdns_clk_rst_deinit(struct device *dev, struct cdns_starfive *data) + { + reset_control_assert(data->resets); + clk_bulk_disable_unprepare(data->num_clks, data->clks); +@@ -113,31 +111,26 @@ static int cdns_starfive_probe(struct pl + if (!data) + return -ENOMEM; + +- data->dev = dev; +- +- data->num_clks = devm_clk_bulk_get_all(data->dev, &data->clks); ++ data->num_clks = devm_clk_bulk_get_all(dev, &data->clks); + if (data->num_clks < 0) +- return dev_err_probe(data->dev, -ENODEV, +- "Failed to get clocks\n"); ++ return dev_err_probe(dev, -ENODEV, "failed to get clocks\n"); + +- data->resets = devm_reset_control_array_get_exclusive(data->dev); ++ data->resets = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(data->resets)) +- return dev_err_probe(data->dev, PTR_ERR(data->resets), +- "Failed to get resets"); ++ return dev_err_probe(dev, PTR_ERR(data->resets), "failed to get resets\n"); + + ret = cdns_mode_init(dev, data); + if (ret) + return ret; + +- ret = cdns_clk_rst_init(data); ++ ret = cdns_clk_rst_init(dev, data); + if (ret) + return ret; + + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) { +- dev_err(dev, "Failed to create children\n"); +- cdns_clk_rst_deinit(data); +- return ret; ++ cdns_clk_rst_deinit(dev, data); ++ return dev_err_probe(dev, ret, "failed to create children\n"); + } + + device_set_wakeup_capable(dev, true); +@@ -167,7 +160,7 @@ static void cdns_starfive_remove(struct + + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +- cdns_clk_rst_deinit(data); ++ cdns_clk_rst_deinit(dev, data); + platform_set_drvdata(pdev, NULL); + } + +@@ -193,14 +186,14 @@ static int cdns_starfive_resume(struct d + { + struct cdns_starfive *data = dev_get_drvdata(dev); + +- return cdns_clk_rst_init(data); ++ return cdns_clk_rst_init(dev, data); + } + + static int cdns_starfive_suspend(struct device *dev) + { + struct cdns_starfive *data = dev_get_drvdata(dev); + +- cdns_clk_rst_deinit(data); ++ cdns_clk_rst_deinit(dev, data); + + return 0; + } diff --git a/target/linux/starfive/patches-6.12/1018-usb-cdns3-starfive-Add-StarFive-JH7100-support.patch b/target/linux/starfive/patches-6.12/1018-usb-cdns3-starfive-Add-StarFive-JH7100-support.patch new file mode 100644 index 0000000000..496a0de769 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1018-usb-cdns3-starfive-Add-StarFive-JH7100-support.patch @@ -0,0 +1,113 @@ +From eae127ccbe02ba20e4eb86081268205f7f40b8fc Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 22 Jul 2023 16:21:04 +0200 +Subject: [PATCH 1018/1021] usb: cdns3: starfive: Add StarFive JH7100 support + +Signed-off-by: Emil Renner Berthing +--- + drivers/usb/cdns3/cdns3-starfive.c | 46 ++++++++++++++++++------------ + 1 file changed, 28 insertions(+), 18 deletions(-) + +--- a/drivers/usb/cdns3/cdns3-starfive.c ++++ b/drivers/usb/cdns3/cdns3-starfive.c +@@ -20,17 +20,17 @@ + #include + #include "core.h" + +-#define USB_STRAP_HOST BIT(17) +-#define USB_STRAP_DEVICE BIT(18) +-#define USB_STRAP_MASK GENMASK(18, 16) +- +-#define USB_SUSPENDM_HOST BIT(19) +-#define USB_SUSPENDM_MASK BIT(19) +- +-#define USB_MISC_CFG_MASK GENMASK(23, 20) +-#define USB_SUSPENDM_BYPS BIT(20) +-#define USB_PLL_EN BIT(22) +-#define USB_REFCLK_MODE BIT(23) ++#define JH7110_STRAP_HOST BIT(17) ++#define JH7110_STRAP_DEVICE BIT(18) ++#define JH7110_STRAP_MASK GENMASK(18, 16) ++ ++#define JH7110_SUSPENDM_HOST BIT(19) ++#define JH7110_SUSPENDM_MASK BIT(19) ++ ++#define JH7110_MISC_CFG_MASK GENMASK(23, 20) ++#define JH7110_SUSPENDM_BYPS BIT(20) ++#define JH7110_PLL_EN BIT(22) ++#define JH7110_REFCLK_MODE BIT(23) + + struct cdns_starfive { + struct reset_control *resets; +@@ -38,7 +38,14 @@ struct cdns_starfive { + int num_clks; + }; + +-static int cdns_mode_init(struct device *dev, struct cdns_starfive *data) ++typedef int (cdns_starfive_mode_init_t)(struct device *dev, struct cdns_starfive *data); ++ ++static int cdns_jh7100_mode_init(struct device *dev, struct cdns_starfive *data) ++{ ++ return 0; ++} ++ ++static int cdns_jh7110_mode_init(struct device *dev, struct cdns_starfive *data) + { + struct regmap *syscon; + unsigned int usb_mode; +@@ -51,21 +58,21 @@ static int cdns_mode_init(struct device + "failed to parse starfive,stg-syscon\n"); + + regmap_update_bits(syscon, usb_mode, +- USB_MISC_CFG_MASK, +- USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE); ++ JH7110_MISC_CFG_MASK, ++ JH7110_SUSPENDM_BYPS | JH7110_PLL_EN | JH7110_REFCLK_MODE); + + /* dr mode setting */ + mode = usb_get_dr_mode(dev); + + switch (mode) { + case USB_DR_MODE_HOST: +- regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_HOST); +- regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, USB_SUSPENDM_HOST); ++ regmap_update_bits(syscon, usb_mode, JH7110_STRAP_MASK, JH7110_STRAP_HOST); ++ regmap_update_bits(syscon, usb_mode, JH7110_SUSPENDM_MASK, JH7110_SUSPENDM_HOST); + break; + + case USB_DR_MODE_PERIPHERAL: +- regmap_update_bits(syscon, usb_mode, USB_STRAP_MASK, USB_STRAP_DEVICE); +- regmap_update_bits(syscon, usb_mode, USB_SUSPENDM_MASK, 0); ++ regmap_update_bits(syscon, usb_mode, JH7110_STRAP_MASK, JH7110_STRAP_DEVICE); ++ regmap_update_bits(syscon, usb_mode, JH7110_SUSPENDM_MASK, 0); + break; + default: + break; +@@ -105,6 +112,7 @@ static int cdns_starfive_probe(struct pl + { + struct device *dev = &pdev->dev; + struct cdns_starfive *data; ++ cdns_starfive_mode_init_t *mode_init; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); +@@ -119,7 +127,8 @@ static int cdns_starfive_probe(struct pl + if (IS_ERR(data->resets)) + return dev_err_probe(dev, PTR_ERR(data->resets), "failed to get resets\n"); + +- ret = cdns_mode_init(dev, data); ++ mode_init = device_get_match_data(dev); ++ ret = mode_init(dev, data); + if (ret) + return ret; + +@@ -207,7 +216,8 @@ static const struct dev_pm_ops cdns_star + }; + + static const struct of_device_id cdns_starfive_of_match[] = { +- { .compatible = "starfive,jh7110-usb", }, ++ { .compatible = "starfive,jh7100-usb", .data = cdns_jh7100_mode_init }, ++ { .compatible = "starfive,jh7110-usb", .data = cdns_jh7110_mode_init }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, cdns_starfive_of_match); diff --git a/target/linux/starfive/patches-6.12/1019-riscv-dts-starfive-Add-JH7100-USB-node.patch b/target/linux/starfive/patches-6.12/1019-riscv-dts-starfive-Add-JH7100-USB-node.patch new file mode 100644 index 0000000000..15e88bbd51 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1019-riscv-dts-starfive-Add-JH7100-USB-node.patch @@ -0,0 +1,60 @@ +From e73da6a4dc3f127d45e26d68ee051199c1fc2bb9 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 22 Jul 2023 16:36:17 +0200 +Subject: [PATCH 1019/1021] riscv: dts: starfive: Add JH7100 USB node + +Add the device tree node for the USB 3.0 peripheral on the +StarFive JH7100 SoC. + +Signed-off-by: Emil Renner Berthing +--- + .../boot/dts/starfive/jh7100-common.dtsi | 5 ++++ + arch/riscv/boot/dts/starfive/jh7100.dtsi | 26 +++++++++++++++++++ + 2 files changed, 31 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi +@@ -447,3 +447,8 @@ + pinctrl-0 = <&uart3_pins>; + status = "okay"; + }; ++ ++&usb3 { ++ dr_mode = "host"; ++ status = "okay"; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -255,6 +255,32 @@ + #reset-cells = <1>; + }; + ++ usb3: usb@104c0000 { ++ compatible = "starfive,jh7100-usb"; ++ ranges = <0x0 0x0 0x104c0000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ clocks = <&audclk JH7100_AUDCLK_USB_LPM>, ++ <&audclk JH7100_AUDCLK_USB_STB>, ++ <&clkgen JH7100_CLK_USB_AXI>, ++ <&clkgen JH7100_CLK_USBNOC_AXI>; ++ clock-names = "lpm", "stb", "axi", "nocaxi"; ++ resets = <&rstgen JH7100_RSTN_USB_AXI>, ++ <&rstgen JH7100_RSTN_USBNOC_AXI>; ++ reset-names = "axi", "nocaxi"; ++ status = "disabled"; ++ ++ usb_cdns3: usb@0 { ++ compatible = "cdns,usb3"; ++ reg = <0x00000 0x10000>, ++ <0x10000 0x10000>, ++ <0x20000 0x10000>; ++ reg-names = "otg", "xhci", "dev"; ++ interrupts = <44>, <52>, <43>; ++ interrupt-names = "host", "peripheral", "otg"; ++ }; ++ }; ++ + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x0 0x11800000 0x0 0x10000>; diff --git a/target/linux/starfive/patches-6.12/1020-usb-cdns3-starfive-Initialize-JH7100-host-mode.patch b/target/linux/starfive/patches-6.12/1020-usb-cdns3-starfive-Initialize-JH7100-host-mode.patch new file mode 100644 index 0000000000..03afdf2c68 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1020-usb-cdns3-starfive-Initialize-JH7100-host-mode.patch @@ -0,0 +1,103 @@ +From 8deff65d2d7ffea00231ec592d956aebf7de0852 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sat, 22 Jul 2023 18:50:49 +0200 +Subject: [PATCH 1020/1021] usb: cdns3: starfive: Initialize JH7100 host mode + +These settings are directly copied from StarFive's port of u-boot +for the JH7100: + + /* config strap */ + _SET_SYSCON_REG_SCFG_usb0_mode_strap(0x2); + _SET_SYSCON_REG_SCFG_usb7_PLL_EN(0x1); + _SET_SYSCON_REG_SCFG_usb7_U3_EQ_EN(0x1); + _SET_SYSCON_REG_SCFG_usb7_U3_SSRX_SEL(0x1); + _SET_SYSCON_REG_SCFG_usb7_U3_SSTX_SEL(0x1); + _SET_SYSCON_REG_SCFG_usb3_utmi_iddig(0x1); + +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/jh7100.dtsi | 6 ++++ + drivers/usb/cdns3/cdns3-starfive.c | 43 ++++++++++++++++++++++++ + 2 files changed, 49 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -255,6 +255,11 @@ + #reset-cells = <1>; + }; + ++ sysaudio: syscon@104a0000 { ++ compatible = "starfive,jh7100-sysaudio", "syscon"; ++ reg = <0x0 0x104a0000 0x0 0x10000>; ++ }; ++ + usb3: usb@104c0000 { + compatible = "starfive,jh7100-usb"; + ranges = <0x0 0x0 0x104c0000 0x100000>; +@@ -268,6 +273,7 @@ + resets = <&rstgen JH7100_RSTN_USB_AXI>, + <&rstgen JH7100_RSTN_USBNOC_AXI>; + reset-names = "axi", "nocaxi"; ++ starfive,syscon = <&sysaudio>; + status = "disabled"; + + usb_cdns3: usb@0 { +--- a/drivers/usb/cdns3/cdns3-starfive.c ++++ b/drivers/usb/cdns3/cdns3-starfive.c +@@ -20,6 +20,19 @@ + #include + #include "core.h" + ++#define JH7100_USB0 0x20 ++#define JH7100_USB0_MODE_STRAP_MASK GENMASK(2, 0) ++#define JH7100_USB0_MODE_STRAP_HOST 2 ++ ++#define JH7100_USB3 0x2c ++#define JH7100_USB3_UTMI_IDDIG BIT(21) ++ ++#define JH7100_USB7 0x3c ++#define JH7100_USB7_SSRX_SEL BIT(18) ++#define JH7100_USB7_SSTX_SEL BIT(19) ++#define JH7100_USB7_PLL_EN BIT(23) ++#define JH7100_USB7_EQ_EN BIT(25) ++ + #define JH7110_STRAP_HOST BIT(17) + #define JH7110_STRAP_DEVICE BIT(18) + #define JH7110_STRAP_MASK GENMASK(18, 16) +@@ -42,6 +55,36 @@ typedef int (cdns_starfive_mode_init_t)( + + static int cdns_jh7100_mode_init(struct device *dev, struct cdns_starfive *data) + { ++ struct regmap *syscon; ++ enum usb_dr_mode mode; ++ ++ syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "starfive,syscon"); ++ if (IS_ERR(syscon)) ++ return dev_err_probe(dev, PTR_ERR(syscon), ++ "failed to get starfive,syscon\n"); ++ ++ /* dr mode setting */ ++ mode = usb_get_dr_mode(dev); ++ ++ switch (mode) { ++ case USB_DR_MODE_HOST: ++ regmap_update_bits(syscon, JH7100_USB0, ++ JH7100_USB0_MODE_STRAP_MASK, JH7100_USB0_MODE_STRAP_HOST); ++ regmap_update_bits(syscon, JH7100_USB7, ++ JH7100_USB7_PLL_EN, JH7100_USB7_PLL_EN); ++ regmap_update_bits(syscon, JH7100_USB7, ++ JH7100_USB7_EQ_EN, JH7100_USB7_EQ_EN); ++ regmap_update_bits(syscon, JH7100_USB7, ++ JH7100_USB7_SSRX_SEL, JH7100_USB7_SSRX_SEL); ++ regmap_update_bits(syscon, JH7100_USB7, ++ JH7100_USB7_SSTX_SEL, JH7100_USB7_SSTX_SEL); ++ regmap_update_bits(syscon, JH7100_USB3, ++ JH7100_USB3_UTMI_IDDIG, JH7100_USB3_UTMI_IDDIG); ++ break; ++ default: ++ break; ++ } ++ + return 0; + } + diff --git a/target/linux/starfive/patches-6.12/1021-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch b/target/linux/starfive/patches-6.12/1021-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch new file mode 100644 index 0000000000..211dc75997 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1021-riscv-dts-Add-full-JH7100-Starlight-and-VisionFive-s.patch @@ -0,0 +1,848 @@ +From a861bf8cf26216da57b4886ecf48222e01e4fba9 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Sun, 31 Oct 2021 17:15:58 +0100 +Subject: [PATCH 1021/1021] riscv: dts: Add full JH7100, Starlight and + VisionFive support + +Based on the device tree in https://github.com/starfive-tech/u-boot/ +with contributions from: +yanhong.wang +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: Geert Uytterhoeven +Signed-off-by: Stephen L Arnold +Signed-off-by: Drew Fustini +Signed-off-by: Jianlong Huang +Signed-off-by: Jonas Hahnfeld +Signed-off-by: Emil Renner Berthing +--- + arch/riscv/boot/dts/starfive/Makefile | 2 + + .../starfive/jh7100-beaglev-starlight-a1.dts | 24 ++ + .../dts/starfive/jh7100-beaglev-starlight.dts | 6 + + .../boot/dts/starfive/jh7100-common.dtsi | 177 ++++++++ + .../jh7100-starfive-visionfive-v1.dts | 13 + + arch/riscv/boot/dts/starfive/jh7100.dtsi | 389 ++++++++++++++++++ + 6 files changed, 611 insertions(+) + create mode 100644 arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts + +--- a/arch/riscv/boot/dts/starfive/Makefile ++++ b/arch/riscv/boot/dts/starfive/Makefile +@@ -1,10 +1,12 @@ + # SPDX-License-Identifier: GPL-2.0 + # Enables support for device-tree overlays ++DTC_FLAGS_jh7100-beaglev-starlight-a1 := -@ + DTC_FLAGS_jh7100-beaglev-starlight := -@ + DTC_FLAGS_jh7100-starfive-visionfive-v1 := -@ + DTC_FLAGS_jh7110-starfive-visionfive-2-v1.2a := -@ + DTC_FLAGS_jh7110-starfive-visionfive-2-v1.3b := -@ + ++dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight-a1.dtb + dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb + dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb + +--- /dev/null ++++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts +@@ -0,0 +1,24 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2021 Emil Renner Berthing ++ */ ++ ++/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>; ++}; +--- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts ++++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts +@@ -6,6 +6,7 @@ + + /dts-v1/; + #include "jh7100-common.dtsi" ++#include + + / { + model = "BeagleV Starlight Beta"; +@@ -16,6 +17,11 @@ + phy-handle = <&phy>; + }; + ++&gpio { ++ /* don't reset gpio mux for serial console on uart3 */ ++ starfive,keep-gpiomux = <13 14>; ++}; ++ + &mdio { + phy: ethernet-phy@7 { + reg = <7>; +--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi +@@ -15,6 +15,7 @@ + mmc0 = &sdio0; + mmc1 = &sdio1; + serial0 = &uart3; ++ serial1 = &uart0; + }; + + chosen { +@@ -47,11 +48,41 @@ + #size-cells = <2>; + ranges; + ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ alloc-ranges = <0x0 0xa0000000 0x0 0x28000000>; ++ size = <0x0 0x28000000>; ++ alignment = <0x0 0x1000>; ++ reusable; ++ linux,cma-default; ++ }; ++ ++ jpu_reserved: framebuffer@c9000000 { ++ reg = <0x0 0xc9000000 0x0 0x4000000>; ++ }; ++ ++ nvdla_reserved: framebuffer@d0000000 { ++ reg = <0x0 0xd0000000 0x0 0x28000000>; ++ no-map; ++ }; ++ ++ vin_reserved: framebuffer@f9000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x0 0xf9000000 0x0 0x1000000>; ++ no-map; ++ }; ++ + dma-reserved@fa000000 { + reg = <0x0 0xfa000000 0x0 0x1000000>; + no-map; + }; + ++ sffb_reserved: framebuffer@fb000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x0 0xfb000000 0x0 0x2000000>; ++ no-map; ++ }; ++ + linux,dma@107a000000 { + compatible = "shared-dma-pool"; + reg = <0x10 0x7a000000 0x0 0x1000000>; +@@ -72,6 +103,44 @@ + }; + }; + ++&display { ++ memory-region = <&sffb_reserved>; ++ status = "okay"; ++}; ++ ++&crtc { ++ ddr-format = <4>; //; ++ status = "okay"; ++ ++ port: port@0 { ++ reg = <0>; ++ ++ crtc_0_out: endpoint { ++ remote-endpoint = <&hdmi_input0>; ++ }; ++ }; ++}; ++ ++&encoder { ++ encoder-type = <2>; // 2-TMDS, 3-LVDS, 6-DSI, 8-DPI ++ status = "okay"; ++ ++ ports { ++ port@0 { ++ hdmi_out: endpoint { ++ remote-endpoint = <&tda998x_0_input>; ++ }; ++ }; ++ ++ port@1 { ++ hdmi_input0: endpoint { ++ remote-endpoint = <&crtc_0_out>; ++ }; ++ }; ++ ++ }; ++}; ++ + &gmac { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_pins>; +@@ -199,6 +268,20 @@ + }; + }; + ++ pwmdac_pins: pwmdac-0 { ++ pwmdac-pins { ++ pinmux = , ++ ; ++ bias-disable; ++ drive-strength = <35>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ + pwm_pins: pwm-0 { + pwm-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 = ; ++ ++ port { ++ tda998x_0_input: endpoint { ++ remote-endpoint = <&hdmi_out>; ++ }; ++ }; ++ }; + }; + + &i2c1 { +@@ -400,6 +527,44 @@ + status = "okay"; + }; + ++&pwmdac { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwmdac_pins>; ++ status = "okay"; ++}; ++ ++&qspi { ++ nor_flash: nor-flash@0 { ++ compatible = "spi-flash"; ++ reg = <0>; ++ spi-max-frequency = <31250000>; ++ page-size = <256>; ++ block-size = <16>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <1>; ++ cdns,tsd2d-ns = <1>; ++ cdns,tchsh-ns = <1>; ++ cdns,tslch-ns = <1>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <1>; ++ }; ++ ++ nand_flash: nand-flash@1 { ++ compatible = "spi-flash-nand"; ++ reg = <1>; ++ spi-max-frequency = <31250000>; ++ page-size = <2048>; ++ block-size = <17>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <1>; ++ cdns,tsd2d-ns = <1>; ++ cdns,tchsh-ns = <1>; ++ cdns,tslch-ns = <1>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <1>; ++ }; ++}; ++ + &sdio0 { + broken-cd; + bus-width = <4>; +@@ -428,6 +593,18 @@ + }; + }; + ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_pins>; ++ status = "okay"; ++ ++ spi_dev0: spi@0 { ++ compatible = "rohm,dh2228fv"; ++ spi-max-frequency = <10000000>; ++ reg = <0>; ++ }; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +--- a/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts ++++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts +@@ -22,6 +22,19 @@ + phy-handle = <&phy>; + }; + ++&gpio { ++ /* don't reset gpio mux for serial console and reset gpio */ ++ starfive,keep-gpiomux = <13 14 63>; ++}; ++ ++&i2c0 { ++ eeprom@50 { ++ compatible = "atmel,24c04"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++}; ++ + /* + * The board uses a Motorcomm YT8521 PHY supporting RGMII-ID, but requires + * manual adjustment of the RX internal delay to work properly. The default +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -6,7 +6,9 @@ + + /dts-v1/; + #include ++#include + #include ++#include + + / { + compatible = "starfive,jh7100"; +@@ -37,6 +39,7 @@ + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; ++ starfive,itim = <&itim0>; + tlb-split; + + cpu0_intc: interrupt-controller { +@@ -66,6 +69,7 @@ + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; ++ starfive,itim = <&itim1>; + tlb-split; + + cpu1_intc: interrupt-controller { +@@ -153,6 +157,24 @@ + dma-noncoherent; + ranges; + ++ dtim: dtim@1000000 { ++ compatible = "starfive,dtim0"; ++ reg = <0x0 0x1000000 0x0 0x2000>; ++ reg-names = "mem"; ++ }; ++ ++ itim0: itim@1808000 { ++ compatible = "starfive,itim0"; ++ reg = <0x0 0x1808000 0x0 0x8000>; ++ reg-names = "mem"; ++ }; ++ ++ itim1: itim@1820000 { ++ compatible = "starfive,itim0"; ++ reg = <0x0 0x1820000 0x0 0x8000>; ++ reg-names = "mem"; ++ }; ++ + clint: clint@2000000 { + compatible = "starfive,jh7100-clint", "sifive,clint0"; + reg = <0x0 0x2000000 0x0 0x10000>; +@@ -239,6 +261,124 @@ + }; + }; + ++ dma2p: dma-controller@100b0000 { ++ compatible = "starfive,jh7100-axi-dma"; ++ reg = <0x0 0x100b0000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_SGDMA2P_AXI>, ++ <&clkgen JH7100_CLK_SGDMA2P_AHB>; ++ clock-names = "core-clk", "cfgr-clk"; ++ resets = <&rstgen JH7100_RSTN_SGDMA2P_AXI>, ++ <&rstgen JH7100_RSTN_SGDMA2P_AHB>; ++ reset-names = "axi", "ahb"; ++ interrupts = <2>; ++ #dma-cells = <1>; ++ dma-channels = <4>; ++ snps,dma-masters = <1>; ++ snps,data-width = <4>; ++ snps,block-size = <4096 4096 4096 4096>; ++ snps,priority = <0 1 2 3>; ++ snps,axi-max-burst-len = <128>; ++ dma-coherent; ++ }; ++ ++ crypto: crypto@100d0000 { ++ compatible = "starfive,vic-sec"; ++ reg = <0x0 0x100d0000 0x0 0x20000>, ++ <0x0 0x11800234 0x0 0xc>; ++ reg-names = "secmem", "secclk"; ++ clocks = <&clkgen JH7100_CLK_SEC_AHB>; ++ interrupts = <31>; ++ }; ++ ++ i2sadc0: i2sadc0@10400000 { ++ compatible = "snps,designware-i2sadc0"; ++ reg = <0x0 0x10400000 0x0 0x1000>; ++ clocks = <&clkgen JH7100_CLK_APB1_BUS>; ++ clock-names = "i2sclk"; ++ interrupt-parent = <&plic>; ++ #sound-dai-cells = <0>; ++ dmas = <&dma2p 28>; ++ dma-names = "rx"; ++ }; ++ ++ i2svad: i2svad@10420000 { ++ compatible = "starfive,sf-i2svad"; ++ reg = <0x0 0x10420000 0x0 0x1000> ; ++ clocks = <&audclk JH7100_AUDCLK_I2SVAD_APB>; ++ clock-names = "i2svad_apb"; ++ resets = <&audrst JH7100_AUDRSTN_I2SVAD_APB>, ++ <&audrst JH7100_AUDRSTN_I2SVAD_SRST>; ++ reset-names = "apb_i2svad", "i2svad_srst"; ++ interrupts = <60>, <61>; ++ interrupt-names = "spintr", "slintr"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ pwmdac: pwmdac@10440000 { ++ compatible = "starfive,pwmdac"; ++ reg = <0x0 0x10440000 0x0 0x1000>; ++ clocks = <&clkgen JH7100_CLK_AUDIO_ROOT>, ++ <&clkgen JH7100_CLK_AUDIO_SRC>, ++ <&clkgen JH7100_CLK_AUDIO_12288>, ++ <&audclk JH7100_AUDCLK_DMA1P_AHB>, ++ <&audclk JH7100_AUDCLK_PWMDAC_APB>, ++ <&audclk JH7100_AUDCLK_DAC_MCLK>; ++ clock-names = "audio_root", ++ "audio_src", ++ "audio_12288", ++ "dma1p_ahb", ++ "pwmdac_apb", ++ "dac_mclk"; ++ resets = <&audrst JH7100_AUDRSTN_APB_BUS>, ++ <&audrst JH7100_AUDRSTN_DMA1P_AHB>, ++ <&audrst JH7100_AUDRSTN_PWMDAC_APB>; ++ reset-names = "apb_bus", "dma1p_ahb", "apb_pwmdac"; ++ dmas = <&dma2p 23>; ++ dma-names = "tx"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ i2sdac0: i2sdac0@10450000 { ++ compatible = "snps,designware-i2sdac0"; ++ reg = <0x0 0x10450000 0x0 0x1000>; ++ clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>, ++ <&audclk JH7100_AUDCLK_I2SDAC_BCLK>, ++ <&audclk JH7100_AUDCLK_I2SDAC_LRCLK>, ++ <&audclk JH7100_AUDCLK_I2SDAC_APB>; ++ clock-names = "dac_mclk", "i2sdac0_bclk", "i2sdac0_lrclk", "i2sdac_apb"; ++ resets = <&audrst JH7100_AUDRSTN_I2SDAC_APB>, ++ <&audrst JH7100_AUDRSTN_I2SDAC_SRST>; ++ reset-names = "apb_i2sdac", "i2sdac_srst"; ++ #sound-dai-cells = <0>; ++ dmas = <&dma2p 30>; ++ dma-names = "tx"; ++ }; ++ ++ i2sdac1: i2sdac1@10460000 { ++ compatible = "snps,designware-i2sdac1"; ++ reg = <0x0 0x10460000 0x0 0x1000>; ++ clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>, ++ <&audclk JH7100_AUDCLK_I2S1_BCLK>, ++ <&audclk JH7100_AUDCLK_I2S1_LRCLK>, ++ <&audclk JH7100_AUDCLK_I2S1_APB>; ++ clock-names = "dac_mclk", "i2sdac1_bclk", "i2sdac1_lrclk", "i2s1_apb"; ++ resets = <&audrst JH7100_AUDRSTN_I2S1_APB>, ++ <&audrst JH7100_AUDRSTN_I2S1_SRST>; ++ #sound-dai-cells = <0>; ++ dmas = <&dma2p 31>; ++ dma-names = "tx"; ++ }; ++ ++ i2sdac16k: i2sdac16k@10470000 { ++ compatible = "snps,designware-i2sdac16k"; ++ reg = <0x0 0x10470000 0x0 0x1000>; ++ clocks = <&clkgen JH7100_CLK_APB1_BUS>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&dma2p 29>; ++ dma-names = "tx"; ++ }; ++ + audclk: clock-controller@10480000 { + compatible = "starfive,jh7100-audclk"; + reg = <0x0 0x10480000 0x0 0x10000>; +@@ -255,6 +395,50 @@ + #reset-cells = <1>; + }; + ++ spdif_transmitter: spdif-transmitter { ++ compatible = "linux,spdif-dit"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ spdif_receiver: spdif-receiver { ++ compatible = "linux,spdif-dir"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ pwmdac_codec: pwmdac-transmitter { ++ compatible = "linux,pwmdac-dit"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ dmic_codec: dmic { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ sound: snd-card { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "Starfive-Multi-Sound-Card"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* pwmdac */ ++ simple-audio-card,dai-link@0 { ++ reg = <0>; ++ status = "okay"; ++ format = "left_j"; ++ bitclock-master = <&sndcpu0>; ++ frame-master = <&sndcpu0>; ++ ++ sndcpu0: cpu { ++ sound-dai = <&pwmdac>; ++ }; ++ ++ codec { ++ sound-dai = <&pwmdac_codec>; ++ }; ++ }; ++ }; ++ + sysaudio: syscon@104a0000 { + compatible = "starfive,jh7100-sysaudio", "syscon"; + reg = <0x0 0x104a0000 0x0 0x10000>; +@@ -287,6 +471,25 @@ + }; + }; + ++ dma1p: dma-controller@10500000 { ++ compatible = "starfive,jh7100-axi-dma"; ++ reg = <0x0 0x10500000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_SGDMA1P_AXI>, ++ <&clkgen JH7100_CLK_SGDMA1P_BUS>; ++ clock-names = "core-clk", "cfgr-clk"; ++ resets = <&rstgen JH7100_RSTN_DMA1P_AXI>, ++ <&rstgen JH7100_RSTN_SGDMA1P_AXI>; ++ reset-names = "axi", "ahb"; ++ interrupts = <1>; ++ #dma-cells = <1>; ++ dma-channels = <16>; ++ snps,dma-masters = <1>; ++ snps,data-width = <3>; ++ snps,block-size = <4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096>; ++ snps,priority = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>; ++ snps,axi-max-burst-len = <64>; ++ }; ++ + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x0 0x11800000 0x0 0x10000>; +@@ -295,6 +498,13 @@ + #clock-cells = <1>; + }; + ++ otp: otp@11810000 { ++ compatible = "starfive,fu740-otp"; ++ reg = <0x0 0x11810000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_OTP_APB>; ++ fuse-count = <0x200>; ++ }; ++ + rstgen: reset-controller@11840000 { + compatible = "starfive,jh7100-reset"; + reg = <0x0 0x11840000 0x0 0x10000>; +@@ -306,6 +516,21 @@ + reg = <0x0 0x11850000 0x0 0x10000>; + }; + ++ qspi: spi@11860000 { ++ compatible = "cdns,qspi-nor"; ++ reg = <0x0 0x11860000 0x0 0x10000>, ++ <0x0 0x20000000 0x0 0x20000000>; ++ clocks = <&clkgen JH7100_CLK_QSPI_AHB>; ++ interrupts = <3>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ cdns,fifo-depth = <256>; ++ cdns,fifo-width = <4>; ++ cdns,trigger-address = <0x0>; ++ spi-max-frequency = <250000000>; ++ status = "disabled"; ++ }; ++ + uart0: serial@11870000 { + compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart"; + reg = <0x0 0x11870000 0x0 0x10000>; +@@ -332,6 +557,34 @@ + status = "disabled"; + }; + ++ spi0: spi@11890000 { ++ compatible = "snps,dw-apb-ssi"; ++ reg = <0x0 0x11890000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_SPI0_CORE>, ++ <&clkgen JH7100_CLK_SPI0_APB>; ++ clock-names = "ssi_clk", "pclk"; ++ resets = <&rstgen JH7100_RSTN_SPI0_APB>; ++ reset-names = "spi"; ++ interrupts = <94>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi1: spi@118a0000 { ++ compatible = "snps,dw-apb-ssi"; ++ reg = <0x0 0x118a0000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_SPI1_CORE>, ++ <&clkgen JH7100_CLK_SPI1_APB>; ++ clock-names = "ssi_clk", "pclk"; ++ resets = <&rstgen JH7100_RSTN_SPI1_APB>; ++ reset-names = "spi"; ++ interrupts = <95>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + i2c0: i2c@118b0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x118b0000 0x0 0x10000>; +@@ -358,6 +611,41 @@ + status = "disabled"; + }; + ++ trng: trng@118d0000 { ++ compatible = "starfive,vic-rng"; ++ reg = <0x0 0x118d0000 0x0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_TRNG_APB>; ++ interrupts = <98>; ++ }; ++ ++ vpu_enc: vpu_enc@118e0000 { ++ compatible = "cm,cm521-vpu"; ++ reg = <0x0 0x118e0000 0x0 0x4000>; ++ reg-names = "control"; ++ clocks = <&clkgen JH7100_CLK_VP6_CORE>; ++ clock-names = "vcodec"; ++ interrupts = <26>; ++ }; ++ ++ vpu_dec: vpu_dec@118f0000 { ++ compatible = "c&m,cm511-vpu"; ++ reg = <0 0x118f0000 0 0x10000>; ++ clocks = <&clkgen JH7100_CLK_VP6_CORE>; ++ clock-names = "vcodec"; ++ interrupts = <23>; ++ //memory-region = <&vpu_reserved>; ++ }; ++ ++ jpu: coadj12@11900000 { ++ compatible = "cm,codaj12-jpu-1"; ++ reg = <0x0 0x11900000 0x0 0x300>; ++ reg-names = "control"; ++ clocks = <&clkgen JH7100_CLK_JPEG_APB>; ++ clock-names = "jpege"; ++ interrupts = <24>; ++ memory-region = <&jpu_reserved>; ++ }; ++ + gpio: pinctrl@11910000 { + compatible = "starfive,jh7100-pinctrl"; + reg = <0x0 0x11910000 0x0 0x10000>, +@@ -372,6 +660,86 @@ + #interrupt-cells = <2>; + }; + ++ nvdla@11940000 { ++ compatible = "nvidia,nvdla_os_initial"; ++ interrupts = <22>; ++ memory-region = <&nvdla_reserved>; ++ reg = <0x0 0x11940000 0x0 0x40000>; ++ status = "okay"; ++ }; ++ ++ display: display-subsystem { ++ compatible = "starfive,display-subsystem"; ++ dma-coherent; ++ status = "disabled"; ++ }; ++ ++ encoder: display-encoder { ++ compatible = "starfive,display-encoder"; ++ status = "disabled"; ++ }; ++ ++ crtc: crtc@12000000 { ++ compatible = "starfive,jh7100-crtc"; ++ reg = <0x0 0x12000000 0x0 0x10000>, ++ <0x0 0x12040000 0x0 0x10000>, ++ <0x0 0x12080000 0x0 0x10000>, ++ <0x0 0x120c0000 0x0 0x10000>, ++ <0x0 0x12240000 0x0 0x10000>, ++ <0x0 0x12250000 0x0 0x10000>, ++ <0x0 0x12260000 0x0 0x10000>; ++ reg-names = "lcdc", "vpp0", "vpp1", "vpp2", "clk", "rst", "sys"; ++ clocks = <&clkgen JH7100_CLK_DISP_AXI>, <&clkgen JH7100_CLK_VOUT_SRC>; ++ clock-names = "disp_axi", "vout_src"; ++ resets = <&rstgen JH7100_RSTN_DISP_AXI>, <&rstgen JH7100_RSTN_VOUT_SRC>; ++ reset-names = "disp_axi", "vout_src"; ++ interrupts = <101>, <103>; ++ interrupt-names = "lcdc_irq", "vpp1_irq"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ pp1 { ++ pp-id = <1>; ++ fifo-out; ++ //sys-bus-out; ++ src-format = <11>; //; ++ 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>; +@@ -454,5 +822,26 @@ + reset-names = "sense", "bus"; + #thermal-sensor-cells = <0>; + }; ++ ++ xrp@f0000000 { ++ compatible = "cdns,xrp"; ++ reg = <0x0 0xf0000000 0x0 0x01ffffff>, ++ <0x10 0x72000000 0x0 0x00001000>, ++ <0x10 0x72001000 0x0 0x00fff000>, ++ <0x0 0x124b0000 0x0 0x00010000>; ++ clocks = <&clkgen JH7100_CLK_VP6_CORE>; ++ interrupts = <27>, <28>; ++ firmware-name = "vp6_elf"; ++ dsp-irq = <19 20>; ++ dsp-irq-src = <0x20 0x21>; ++ intc-irq-mode = <1>; ++ intc-irq = <0 1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x40000000 0x0 0x40000000 0x01000000>, ++ <0xb0000000 0x10 0x70000000 0x3000000>; ++ dsp@0 { ++ }; ++ }; + }; + }; diff --git a/target/linux/starfive/patches-6.12/1022-riscv-dts-starfive-vf1-add-LED-aliases-and-stop-hear.patch b/target/linux/starfive/patches-6.12/1022-riscv-dts-starfive-vf1-add-LED-aliases-and-stop-hear.patch new file mode 100644 index 0000000000..354a4815aa --- /dev/null +++ b/target/linux/starfive/patches-6.12/1022-riscv-dts-starfive-vf1-add-LED-aliases-and-stop-hear.patch @@ -0,0 +1,38 @@ +From ec25d5b3e4ac00b76dce3593b54062ee7826cbbd Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Sat, 31 May 2025 22:17:21 +0000 +Subject: [PATCH 1022/1022] riscv: dts: starfive: vf1: add LED aliases and stop + heartbeat + +Signed-off-by: Zoltan HERPAI +--- + arch/riscv/boot/dts/starfive/jh7100-common.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi +@@ -16,6 +16,10 @@ + mmc1 = &sdio1; + serial0 = &uart3; + serial1 = &uart0; ++ led-boot = &led_ack; ++ led-failsafe = &led_ack; ++ led-running = &led_ack; ++ led-upgrade = &led_ack; + }; + + chosen { +@@ -34,11 +38,11 @@ + leds { + compatible = "gpio-leds"; + +- led-ack { ++ led_ack: led-ack { + gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; + color = ; + function = LED_FUNCTION_HEARTBEAT; +- linux,default-trigger = "heartbeat"; ++ default-state = "on"; + label = "ack"; + }; + }; diff --git a/target/linux/starfive/patches-6.12/1023-riscv-dts-starfive-visionfive2-add-SYSLED-support.patch b/target/linux/starfive/patches-6.12/1023-riscv-dts-starfive-visionfive2-add-SYSLED-support.patch new file mode 100644 index 0000000000..c5898470c3 --- /dev/null +++ b/target/linux/starfive/patches-6.12/1023-riscv-dts-starfive-visionfive2-add-SYSLED-support.patch @@ -0,0 +1,34 @@ +From 3a92ee5a97f030bdb1e88272a5d277ecb76836d6 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Sun, 1 Jun 2025 14:03:30 +0000 +Subject: [PATCH 7/8] riscv: dts: starfive: visionfive2: add SYSLED support + +A SYS LED is available at aongpio-3. Add standard heartbeat +support for it. + +Signed-off-by: Zoltan HERPAI +--- + .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -21,6 +21,18 @@ + reg = <0x0 0x6ce00000 0x0 0x1600000>; + }; + }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led-ack { ++ gpios = <&aongpio 3 GPIO_ACTIVE_HIGH>; ++ color = ; ++ function = LED_FUNCTION_HEARTBEAT; ++ linux,default-trigger = "heartbeat"; ++ label = "ack"; ++ }; ++ }; + }; + + &gmac1 { diff --git a/target/linux/starfive/patches-6.12/1024-riscv-dts-starfive-visionfive2-add-LED-aliases-and-s.patch b/target/linux/starfive/patches-6.12/1024-riscv-dts-starfive-visionfive2-add-LED-aliases-and-s.patch new file mode 100644 index 0000000000..cbb6c7ebda --- /dev/null +++ b/target/linux/starfive/patches-6.12/1024-riscv-dts-starfive-visionfive2-add-LED-aliases-and-s.patch @@ -0,0 +1,43 @@ +From d930d3d22dcca6946dbdc822d7b8681f0d6372e5 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Sun, 1 Jun 2025 14:06:04 +0000 +Subject: [PATCH 8/8] riscv: dts: starfive: visionfive2: add LED aliases and + stop heartbeat + +Signed-off-by: Zoltan HERPAI +--- + .../boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -6,10 +6,15 @@ + + /dts-v1/; + #include "jh7110-common.dtsi" ++#include + + / { + aliases { + ethernet1 = &gmac1; ++ led-boot = &led_ack; ++ led-failsafe = &led_ack; ++ led-running = &led_ack; ++ led-upgrade = &led_ack; + }; + + reserved-memory { +@@ -25,11 +30,11 @@ + leds { + compatible = "gpio-leds"; + +- led-ack { ++ led_ack: led-ack { + gpios = <&aongpio 3 GPIO_ACTIVE_HIGH>; + color = ; + function = LED_FUNCTION_HEARTBEAT; +- linux,default-trigger = "heartbeat"; ++ default-state = "on"; + label = "ack"; + }; + }; diff --git a/target/linux/starfive/patches-6.12/1025-riscv-dts-starfive-visionfive2-add-dma-pool-entry.patch b/target/linux/starfive/patches-6.12/1025-riscv-dts-starfive-visionfive2-add-dma-pool-entry.patch new file mode 100644 index 0000000000..437266cc6d --- /dev/null +++ b/target/linux/starfive/patches-6.12/1025-riscv-dts-starfive-visionfive2-add-dma-pool-entry.patch @@ -0,0 +1,31 @@ +From 928a660ec1124853d2dae074e74ec7b20fe9bac2 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Sun, 1 Jun 2025 16:02:38 +0000 +Subject: [PATCH] riscv: dts: starfive: visionfive2: add dma pool entry + +In the VF2 SDK there is a reserved memory for a shared dma pool, which is +also updated by the SDK bootloader. Add this node here as well. + +Signed-off-by: Zoltan HERPAI +--- + .../boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -25,6 +25,15 @@ + e24_mem: e24@c0000000 { + reg = <0x0 0x6ce00000 0x0 0x1600000>; + }; ++ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ size = <0x0 0x20000000>; ++ alignment = <0x0 0x1000>; ++ alloc-ranges = <0x0 0x70000000 0x0 0x20000000>; ++ linux,cma-default; ++ }; + }; + + leds {